Author: jfrederic.clere(a)jboss.com
Date: 2007-11-01 13:03:01 -0400 (Thu, 01 Nov 2007)
New Revision: 334
Added:
sandbox/tomcat/tomcat6/oldjk.patch
Modified:
sandbox/tomcat/tomcat6/README
Log:
Add the remove of the jk code.
Modified: sandbox/tomcat/tomcat6/README
===================================================================
--- sandbox/tomcat/tomcat6/README 2007-11-01 16:27:49 UTC (rev 333)
+++ sandbox/tomcat/tomcat6/README 2007-11-01 17:03:01 UTC (rev 334)
@@ -1,3 +1,4 @@
patch.build.patch: Arrange build.
cluster.patch: remove cluster and documentation.
nio.patch: remove nio and documentation.
+oldjk.patch: remove the old jk code.
Added: sandbox/tomcat/tomcat6/oldjk.patch
===================================================================
--- sandbox/tomcat/tomcat6/oldjk.patch (rev 0)
+++ sandbox/tomcat/tomcat6/oldjk.patch 2007-11-01 17:03:01 UTC (rev 334)
@@ -0,0 +1,11271 @@
+Index: java/org/apache/jk/apr/AprImpl.java
+===================================================================
+--- java/org/apache/jk/apr/AprImpl.java (revision 590752)
++++ java/org/apache/jk/apr/AprImpl.java (working copy)
+@@ -1,317 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.juli.logging.Log log=
+- org.apache.juli.logging.LogFactory.getLog( AprImpl.class );
+-}
+Index: java/org/apache/jk/apr/TomcatStarter.java
+===================================================================
+--- java/org/apache/jk/apr/TomcatStarter.java (revision 590752)
++++ java/org/apache/jk/apr/TomcatStarter.java (working copy)
+@@ -1,94 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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);
+- }
+- }
+-}
+Index: java/org/apache/jk/mbeans-descriptors.xml
+===================================================================
+--- java/org/apache/jk/mbeans-descriptors.xml (revision 590752)
++++ java/org/apache/jk/mbeans-descriptors.xml (working copy)
+@@ -1,557 +0,0 @@
+-<?xml version="1.0"?>
+-<!--
+- Licensed to the Apache Software Foundation (ASF) under one or more
+- contributor license agreements. See the NOTICE file distributed with
+- this work for additional information regarding copyright ownership.
+- The ASF licenses this file to You under the Apache License, Version 2.0
+- (the "License"); you may not use this file except in compliance with
+- the License. You may obtain a copy of the License at
+-
+-
http://www.apache.org/licenses/LICENSE-2.0
+-
+- Unless required by applicable law or agreed to in writing, software
+- distributed under the License is distributed on an "AS IS" BASIS,
+- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- See the License for the specific language governing permissions and
+- limitations under the License.
+--->
+-<!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>
+Index: java/org/apache/jk/config/BaseJkConfig.java
+===================================================================
+--- java/org/apache/jk/config/BaseJkConfig.java (revision 590752)
++++ java/org/apache/jk/config/BaseJkConfig.java (working copy)
+@@ -1,516 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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><ContextManager></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$
+- */
+-public class BaseJkConfig implements LifecycleListener {
+- private static org.apache.juli.logging.Log log =
+- org.apache.juli.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;
+- }
+-}
+Index: java/org/apache/jk/config/WebXml2Jk.java
+===================================================================
+--- java/org/apache/jk/config/WebXml2Jk.java (revision 590752)
++++ java/org/apache/jk/config/WebXml2Jk.java (working copy)
+@@ -1,452 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.juli.logging.Log log=
+- org.apache.juli.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;
+- }
+-
+-}
+Index: java/org/apache/jk/config/NSConfig.java
+===================================================================
+--- java/org/apache/jk/config/NSConfig.java (revision 590752)
++++ java/org/apache/jk/config/NSConfig.java (working copy)
+@@ -1,329 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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><ContextManager></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.juli.logging.Log log =
+- org.apache.juli.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;
+- }
+-
+-}
+Index: java/org/apache/jk/config/ApacheConfig.java
+===================================================================
+--- java/org/apache/jk/config/ApacheConfig.java (revision 590752)
++++ java/org/apache/jk/config/ApacheConfig.java (working copy)
+@@ -1,574 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.juli.logging.Log log =
+- org.apache.juli.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;
+- }
+-
+-}
+Index: java/org/apache/jk/config/GeneratorApache2.java
+===================================================================
+--- java/org/apache/jk/config/GeneratorApache2.java (revision 590752)
++++ java/org/apache/jk/config/GeneratorApache2.java (working copy)
+@@ -1,194 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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>");
+- }
+- }
+-}
+Index: java/org/apache/jk/config/IISConfig.java
+===================================================================
+--- java/org/apache/jk/config/IISConfig.java (revision 590752)
++++ java/org/apache/jk/config/IISConfig.java (working copy)
+@@ -1,306 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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><ContextManager></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.juli.logging.Log log =
+- org.apache.juli.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();
+- }
+-
+-}
+Index: java/org/apache/jk/config/GeneratorJk1.java
+===================================================================
+--- java/org/apache/jk/config/GeneratorJk1.java (revision 590752)
++++ java/org/apache/jk/config/GeneratorJk1.java (working copy)
+@@ -1,113 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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);
+- }
+- }
+-}
+Index: java/org/apache/jk/config/GeneratorJk2.java
+===================================================================
+--- java/org/apache/jk/config/GeneratorJk2.java (revision 590752)
++++ java/org/apache/jk/config/GeneratorJk2.java (working copy)
+@@ -1,144 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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");
+- }
+- }
+-}
+Index: java/org/apache/jk/server/JkCoyoteHandler.java
+===================================================================
+--- java/org/apache/jk/server/JkCoyoteHandler.java (revision 590752)
++++ java/org/apache/jk/server/JkCoyoteHandler.java (working copy)
+@@ -1,218 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.jk.server;
+-
+-import java.io.IOException;
+-import java.util.Iterator;
+-
+-import javax.management.MBeanServer;
+-import javax.management.ObjectName;
+-
+-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.core.JkHandler;
+-import org.apache.jk.core.Msg;
+-import org.apache.jk.core.MsgContext;
+-import org.apache.tomcat.util.modeler.Registry;
+-
+-/** 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.juli.logging.Log log
+- = org.apache.juli.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);
+- }
+-}
+Index: java/org/apache/jk/server/JkMain.java
+===================================================================
+--- java/org/apache/jk/server/JkMain.java (revision 590752)
++++ java/org/apache/jk/server/JkMain.java (working copy)
+@@ -1,695 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.jk.core.JkHandler;
+-import org.apache.jk.core.WorkerEnv;
+-import org.apache.tomcat.util.IntrospectionUtils;
+-import org.apache.tomcat.util.modeler.Registry;
+-
+-/** 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 stopping " +
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.juli.logging.Log log=
+- org.apache.juli.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();
+- }
+- }
+- }
+-
+-
+-}
+Index: java/org/apache/jk/common/JkInputStream.java
+===================================================================
+--- java/org/apache/jk/common/JkInputStream.java (revision 590752)
++++ java/org/apache/jk/common/JkInputStream.java (working copy)
+@@ -1,327 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.juli.logging.Log log=
+- org.apache.juli.logging.LogFactory.getLog( JkInputStream.class );
+-
+- private Msg bodyMsg;
+- private Msg outputMsg;
+- 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, int bsize) {
+- mc = context;
+- bodyMsg = new MsgAjp(bsize);
+- outputMsg = new MsgAjp(bsize);
+- }
+- /**
+- * @deprecated
+- */
+- public JkInputStream(MsgContext context) {
+- this(context, 8*1024);
+- }
+-
+- // -------------------- 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);
+- }
+- long contentLength = res.getContentLengthLong();
+- if( contentLength >= 0 ) {
+- headers.setValue("Content-Length").setLong(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());
+- }
+-
+-
+-}
+Index: java/org/apache/jk/common/AjpConstants.java
+===================================================================
+--- java/org/apache/jk/common/AjpConstants.java (revision 590752)
++++ java/org/apache/jk/common/AjpConstants.java (working copy)
+@@ -1,193 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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;
+-
+-}
+Index: java/org/apache/jk/common/ChannelJni.java
+===================================================================
+--- java/org/apache/jk/common/ChannelJni.java (revision 590752)
++++ java/org/apache/jk/common/ChannelJni.java (working copy)
+@@ -1,192 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.juli.logging.Log log=
+- org.apache.juli.logging.LogFactory.getLog( ChannelJni.class );
+-
+-}
+Index: java/org/apache/jk/common/JkMX.java
+===================================================================
+--- java/org/apache/jk/common/JkMX.java (revision 590752)
++++ java/org/apache/jk/common/JkMX.java (working copy)
+@@ -1,395 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.juli.logging.Log log=
+- org.apache.juli.logging.LogFactory.getLog( JkMX.class );
+-
+-
+-}
+-
+Index: java/org/apache/jk/common/ChannelUn.java
+===================================================================
+--- java/org/apache/jk/common/ChannelUn.java (revision 590752)
++++ java/org/apache/jk/common/ChannelUn.java (working copy)
+@@ -1,395 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.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.modeler.Registry;
+-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.juli.logging.Log log=
+- org.apache.juli.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);
+- }
+-}
+Index: java/org/apache/jk/common/JniHandler.java
+===================================================================
+--- java/org/apache/jk/common/JniHandler.java (revision 590752)
++++ java/org/apache/jk/common/JniHandler.java (working copy)
+@@ -1,318 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.jk.common;
+-
+-import java.io.IOException;
+-
+-import javax.management.ObjectName;
+-
+-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;
+-import org.apache.tomcat.util.modeler.Registry;
+-
+-
+-/**
+- * 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.juli.logging.Log log=
+- org.apache.juli.logging.LogFactory.getLog( JniHandler.class );
+-}
+Index: java/org/apache/jk/common/ChannelShm.java
+===================================================================
+--- java/org/apache/jk/common/ChannelShm.java (revision 590752)
++++ java/org/apache/jk/common/ChannelShm.java (working copy)
+@@ -1,33 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.jk.common;
+-
+-import org.apache.jk.core.JkHandler;
+-
+-
+-
+-/** Channel using shm.
+- *
+- * @author Costin Manolache
+- */
+-public class ChannelShm extends JkHandler {
+-
+- // Not implemented yet.
+-
+-
+-}
+Index: java/org/apache/jk/common/ChannelSocket.java
+===================================================================
+--- java/org/apache/jk/common/ChannelSocket.java (revision 590752)
++++ java/org/apache/jk/common/ChannelSocket.java (working copy)
+@@ -1,895 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.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.modeler.Registry;
+-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.juli.logging.Log log =
+- org.apache.juli.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(packetSize);
+- 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;
+- }
+- }
+-
+-}
+-
+Index: java/org/apache/jk/common/MsgAjp.java
+===================================================================
+--- java/org/apache/jk/common/MsgAjp.java (revision 590752)
++++ java/org/apache/jk/common/MsgAjp.java (working copy)
+@@ -1,354 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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(a)apache.org]
+- * @author Dan Milstein [danmil(a)shore.net]
+- * @author Keith Wannamaker [Keith(a)Wannamaker.org]
+- * @author Kevin Seguin
+- * @author Costin Manolache
+- */
+-public class MsgAjp extends Msg {
+- private static org.apache.juli.logging.Log log=
+- org.apache.juli.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();
+- int length = bc.getLength();
+- appendInt( length );
+- cpBytes(bytes, start, length);
+- 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 );
+- mb.getCharChunk().recycle();
+- 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 );
+- }
+-
+-}
+Index: java/org/apache/jk/common/WorkerDummy.java
+===================================================================
+--- java/org/apache/jk/common/WorkerDummy.java (revision 590752)
++++ java/org/apache/jk/common/WorkerDummy.java (working copy)
+@@ -1,91 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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;
+-}
+-
+Index: java/org/apache/jk/common/HandlerRequest.java
+===================================================================
+--- java/org/apache/jk/common/HandlerRequest.java (revision 590752)
++++ java/org/apache/jk/common/HandlerRequest.java (working copy)
+@@ -1,669 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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(a)apache.org]
+- * @author Dan Milstein [danmil(a)shore.net]
+- * @author Keith Wannamaker [Keith(a)Wannamaker.org]
+- * @author Costin Manolache
+- */
+-public class HandlerRequest extends JkHandler
+-{
+- private static org.apache.juli.logging.Log log=
+- org.apache.juli.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
+- long cl=req.getContentLengthLong();
+- 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
+- long cl = vMB.getLong();
+- if(cl < Integer.MAX_VALUE)
+- req.setContentLength( (int)cl );
+- } 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);
+-
+- }
+-
+- }
+-
+-}
+Index: java/org/apache/jk/common/ChannelNioSocket.java
+===================================================================
+--- java/org/apache/jk/common/ChannelNioSocket.java (revision 590752)
++++ java/org/apache/jk/common/ChannelNioSocket.java (working copy)
+@@ -1,1199 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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 java.net.SocketTimeoutException;
+-
+-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.tomcat.util.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.juli.logging.Log log =
+- org.apache.juli.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()) {
+- SocketInputStream sis = (SocketInputStream)ep.getNote(isNote);
+- sis.closeIt();
+- 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.isAcceptable()) {
+- acceptConnections();
+- } else {
+- SocketConnection sc =
(SocketConnection)sk.attachment();
+- sc.process(sk);
+- }
+- 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) {
+- closeIt();
+- return false;
+- } else if(nr == 0) {
+- if(!nioIsBroken) {
+- dataAvailable = (buffer.remaining() <= 0);
+- }
+- }
+- }
+- return true;
+- }
+-
+- synchronized void closeIt() {
+- isClosed = true;
+- if(blocking)
+- notify();
+- }
+-
+- 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;
+- }
+- } else if(!isClosed) {
+- throw new SocketTimeoutException("Read request timed out");
+- }
+- }
+- }
+-
+- 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;
+- }
+- }
+-
+-}
+-
+Index: java/org/apache/jk/common/Shm.java
+===================================================================
+--- java/org/apache/jk/common/Shm.java (revision 590752)
++++ java/org/apache/jk/common/Shm.java (working copy)
+@@ -1,331 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.juli.logging.Log log=
+- org.apache.juli.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();
+- }
+- }
+-}
+Index: java/org/apache/jk/common/Shm14.java
+===================================================================
+--- java/org/apache/jk/common/Shm14.java (revision 590752)
++++ java/org/apache/jk/common/Shm14.java (working copy)
+@@ -1,97 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.juli.logging.Log log=
+- org.apache.juli.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();
+- }
+- }
+-
+-}
+Index: java/org/apache/jk/common/HandlerDispatch.java
+===================================================================
+--- java/org/apache/jk/common/HandlerDispatch.java (revision 590752)
++++ java/org/apache/jk/common/HandlerDispatch.java (working copy)
+@@ -1,101 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.juli.logging.Log log=
+- org.apache.juli.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 );
+- }
+-
+- }
+Index: java/org/apache/jk/core/JkHandler.java
+===================================================================
+--- java/org/apache/jk/core/JkHandler.java (revision 590752)
++++ java/org/apache/jk/core/JkHandler.java (working copy)
+@@ -1,201 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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.tomcat.util.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(8*1024);
+- }
+-
+- public MsgContext createMsgContext(int bsize) {
+- return new MsgContext(bsize);
+- }
+-
+- 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 {
+- }
+-
+-}
+Index: java/org/apache/jk/core/WorkerEnv.java
+===================================================================
+--- java/org/apache/jk/core/WorkerEnv.java (revision 590752)
++++ java/org/apache/jk/core/WorkerEnv.java (working copy)
+@@ -1,145 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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(a)apache.org]
+- * @author Dan Milstein [danmil(a)shore.net]
+- * @author Keith Wannamaker [Keith(a)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;
+- }
+-
+-}
+Index: java/org/apache/jk/core/Msg.java
+===================================================================
+--- java/org/apache/jk/core/Msg.java (revision 590752)
++++ java/org/apache/jk/core/Msg.java (working copy)
+@@ -1,154 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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(a)apache.org]
+- * @author Dan Milstein [danmil(a)shore.net]
+- * @author Keith Wannamaker [Keith(a)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 );
+- }
+-
+-
+-}
+Index: java/org/apache/jk/core/MsgContext.java
+===================================================================
+--- java/org/apache/jk/core/MsgContext.java (revision 590752)
++++ java/org/apache/jk/core/MsgContext.java (working copy)
+@@ -1,393 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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(a)apache.org]
+- * @author Dan Milstein [danmil(a)shore.net]
+- * @author Keith Wannamaker [Keith(a)Wannamaker.org]
+- * @author Kevin Seguin
+- * @author Costin Manolache
+- */
+-public class MsgContext implements ActionHook {
+- private static org.apache.juli.logging.Log log =
+- org.apache.juli.logging.LogFactory.getLog(MsgContext.class);
+- private static org.apache.juli.logging.Log logTime=
+- org.apache.juli.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;
+- 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(int bsize) {
+- try {
+- c2b = new C2BConverter("iso-8859-1");
+- } catch(IOException iex) {
+- log.warn("Can't happen", iex);
+- }
+- jkIS = new JkInputStream(this, bsize);
+- }
+- /**
+- * @deprecated
+- */
+- public MsgContext() {
+- this(8*1024);
+- }
+-
+- 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 " );
+- Response res = (Response)param;
+- if(!res.isCommitted()) {
+- action(ActionCode.ACTION_COMMIT, res);
+- }
+- try {
+- source.flush( null, this );
+- } catch(IOException iex) {
+- // This is logged elsewhere, so debug only here
+- log.debug("Error during flush",iex);
+- 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;
+- req.setContentLength(bc.getLength());
+- jkIS.setReplay(bc);
+- }
+- }
+-
+-
+- 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();
+- }
+-}
+Index: java/org/apache/jk/core/JkChannel.java
+===================================================================
+--- java/org/apache/jk/core/JkChannel.java (revision 590752)
++++ java/org/apache/jk/core/JkChannel.java (working copy)
+@@ -1,77 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.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();
+-
+-}
+Index: java/org/apache/jk/core/package.html
+===================================================================
+--- java/org/apache/jk/core/package.html (revision 590752)
++++ java/org/apache/jk/core/package.html (working copy)
+@@ -1,32 +0,0 @@
+-<!--
+- Licensed to the Apache Software Foundation (ASF) under one or more
+- contributor license agreements. See the NOTICE file distributed with
+- this work for additional information regarding copyright ownership.
+- The ASF licenses this file to You under the Apache License, Version 2.0
+- (the "License"); you may not use this file except in compliance with
+- the License. You may obtain a copy of the License at
+-
+-
http://www.apache.org/licenses/LICENSE-2.0
+-
+- Unless required by applicable law or agreed to in writing, software
+- distributed under the License is distributed on an "AS IS" BASIS,
+- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- See the License for the specific language governing permissions and
+- limitations under the License.
+--->
+-<!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>