You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2011/07/08 19:19:19 UTC
svn commit: r1144390 - in /tomcat/trunk/java/org/apache/coyote/ajp:
AbstractAjpProcessor.java AbstractAjpProtocol.java AjpAprProcessor.java
AjpAprProtocol.java AjpNioProcessor.java AjpNioProtocol.java
AjpProcessor.java AjpProtocol.java
Author: markt
Date: Fri Jul 8 17:19:19 2011
New Revision: 1144390
URL: http://svn.apache.org/viewvc?rev=1144390&view=rev
Log:
Pull up Handler.process for the Ajp Connectors.
Note that this is an intermediate step. The aim is to pull this up to AbstractProtocol
Modified:
tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProtocol.java
tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java
tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java
tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java
tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java
tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java
tomcat/trunk/java/org/apache/coyote/ajp/AjpProtocol.java
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java?rev=1144390&r1=1144389&r2=1144390&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java Fri Jul 8 17:19:19 2011
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.coyote.ajp;
import java.io.ByteArrayInputStream;
@@ -43,12 +42,13 @@ import org.apache.tomcat.util.net.Abstra
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SocketStatus;
+import org.apache.tomcat.util.net.SocketWrapper;
import org.apache.tomcat.util.res.StringManager;
/**
* Base class for AJP Processor implementations.
*/
-public abstract class AbstractAjpProcessor extends AbstractProcessor {
+public abstract class AbstractAjpProcessor<S> extends AbstractProcessor {
protected abstract Log getLog();
@@ -454,6 +454,9 @@ public abstract class AbstractAjpProcess
protected abstract void finish() throws IOException;
+ public abstract SocketState process(SocketWrapper<S> socket)
+ throws IOException;
+
public SocketState asyncDispatch(SocketStatus status) {
RequestInfo rp = request.getRequestProcessor();
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProtocol.java?rev=1144390&r1=1144389&r2=1144390&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProtocol.java Fri Jul 8 17:19:19 2011
@@ -16,7 +16,12 @@
*/
package org.apache.coyote.ajp;
+import java.util.concurrent.ConcurrentHashMap;
+
import org.apache.coyote.AbstractProtocol;
+import org.apache.tomcat.util.ExceptionUtils;
+import org.apache.tomcat.util.net.SocketStatus;
+import org.apache.tomcat.util.net.SocketWrapper;
import org.apache.tomcat.util.res.StringManager;
public abstract class AbstractAjpProtocol extends AbstractProtocol {
@@ -70,4 +75,87 @@ public abstract class AbstractAjpProtoco
this.packetSize = packetSize;
}
}
+
+ protected abstract static class AbstractAjpConnectionHandler<S,P extends AbstractAjpProcessor<S>>
+ extends AbstractConnectionHandler {
+
+ protected ConcurrentHashMap<SocketWrapper<S>,P> connections =
+ new ConcurrentHashMap<SocketWrapper<S>,P>();
+
+ protected RecycledProcessors<P> recycledProcessors =
+ new RecycledProcessors<P>(this);
+
+ @Override
+ public void recycle() {
+ recycledProcessors.clear();
+ }
+
+ public SocketState process(SocketWrapper<S> socket,
+ SocketStatus status) {
+ P processor = connections.remove(socket);
+
+ socket.setAsync(false);
+
+ try {
+ if (processor == null) {
+ processor = recycledProcessors.poll();
+ }
+ if (processor == null) {
+ processor = createProcessor();
+ }
+
+ SocketState state = SocketState.CLOSED;
+ do {
+ if (processor.isAsync() || state == SocketState.ASYNC_END) {
+ state = processor.asyncDispatch(status);
+ } else {
+ state = processor.process(socket);
+ }
+
+ if (state != SocketState.CLOSED && processor.isAsync()) {
+ state = processor.asyncPostProcess();
+ }
+ } while (state == SocketState.ASYNC_END);
+
+ if (state == SocketState.LONG) {
+ // In the middle of processing a request/response. Keep the
+ // socket associated with the processor.
+ connections.put(socket, processor);
+ socket.setAsync(true);
+ } else if (state == SocketState.OPEN){
+ // In keep-alive but between requests. OK to recycle
+ // processor. Continue to poll for the next request.
+ release(socket, processor, false, true);
+ } else {
+ // Connection closed. OK to recycle the processor.
+ release(socket, processor, true, false);
+ }
+ return state;
+ } catch(java.net.SocketException e) {
+ // SocketExceptions are normal
+ getLog().debug(sm.getString(
+ "ajpprotocol.proto.socketexception.debug"), e);
+ } catch (java.io.IOException e) {
+ // IOExceptions are normal
+ getLog().debug(sm.getString(
+ "ajpprotocol.proto.ioexception.debug"), e);
+ }
+ // Future developers: if you discover any other
+ // rare-but-nonfatal exceptions, catch them here, and log as
+ // above.
+ catch (Throwable e) {
+ ExceptionUtils.handleThrowable(e);
+ // any other exception or error is odd. Here we log it
+ // with "ERROR" level, so it will show up even on
+ // less-than-verbose logs.
+ getLog().error(sm.getString("ajpprotocol.proto.error"), e);
+ }
+ release(socket, processor, true, false);
+ return SocketState.CLOSED;
+ }
+
+ protected abstract P createProcessor();
+ protected abstract void release(SocketWrapper<S> socket, P processor,
+ boolean socketClosing, boolean addToPoller);
+ }
}
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java?rev=1144390&r1=1144389&r2=1144390&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java Fri Jul 8 17:19:19 2011
@@ -47,7 +47,7 @@ import org.apache.tomcat.util.net.Socket
* @author Costin Manolache
* @author Bill Barker
*/
-public class AjpAprProcessor extends AbstractAjpProcessor {
+public class AjpAprProcessor extends AbstractAjpProcessor<Long> {
/**
@@ -106,6 +106,7 @@ public class AjpAprProcessor extends Abs
*
* @throws IOException error during an I/O operation
*/
+ @Override
public SocketState process(SocketWrapper<Long> socket)
throws IOException {
RequestInfo rp = request.getRequestProcessor();
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java?rev=1144390&r1=1144389&r2=1144390&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java Fri Jul 8 17:19:19 2011
@@ -14,19 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.coyote.ajp;
-import java.util.concurrent.ConcurrentHashMap;
-
import org.apache.coyote.AbstractProtocol;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.net.AprEndpoint;
import org.apache.tomcat.util.net.AprEndpoint.Handler;
-import org.apache.tomcat.util.net.SocketStatus;
import org.apache.tomcat.util.net.SocketWrapper;
@@ -100,16 +95,11 @@ public class AjpAprProtocol extends Abst
protected static class AjpConnectionHandler
- extends AbstractConnectionHandler implements Handler {
+ extends AbstractAjpConnectionHandler<Long,AjpAprProcessor>
+ implements Handler {
protected AjpAprProtocol proto;
- protected ConcurrentHashMap<SocketWrapper<Long>, AjpAprProcessor> connections =
- new ConcurrentHashMap<SocketWrapper<Long>, AjpAprProcessor>();
-
- protected RecycledProcessors<AjpAprProcessor> recycledProcessors =
- new RecycledProcessors<AjpAprProcessor>(this);
-
public AjpConnectionHandler(AjpAprProtocol proto) {
this.proto = proto;
}
@@ -124,15 +114,11 @@ public class AjpAprProtocol extends Abst
return log;
}
- @Override
- public void recycle() {
- recycledProcessors.clear();
- }
-
/**
* Expected to be used by the handler once the processor is no longer
* required.
*/
+ @Override
public void release(SocketWrapper<Long> socket,
AjpAprProcessor processor, boolean isSocketClosing,
boolean addToPoller) {
@@ -146,70 +132,6 @@ public class AjpAprProtocol extends Abst
@Override
- public SocketState process(SocketWrapper<Long> socket,
- SocketStatus status) {
- AjpAprProcessor processor = connections.remove(socket);
-
- socket.setAsync(false);
-
- try {
- if (processor == null) {
- processor = recycledProcessors.poll();
- }
- if (processor == null) {
- processor = createProcessor();
- }
-
- SocketState state = SocketState.CLOSED;
- do {
- if (processor.isAsync() || state == SocketState.ASYNC_END) {
- state = processor.asyncDispatch(status);
- } else {
- state = processor.process(socket);
- }
-
- if (state != SocketState.CLOSED && processor.isAsync()) {
- state = processor.asyncPostProcess();
- }
- } while (state == SocketState.ASYNC_END);
-
- if (state == SocketState.LONG) {
- // Need to make socket available for next processing cycle
- // but no need for the poller
- connections.put(socket, processor);
- socket.setAsync(true);
- } else if (state == SocketState.OPEN){
- // In keep-alive but between requests. OK to recycle
- // processor. Continue to poll for the next request.
- release(socket, processor, false, true);
- } else {
- // Connection closed. OK to recycle the processor.
- release(socket, processor, true, false);
- }
- return state;
- } catch(java.net.SocketException e) {
- // SocketExceptions are normal
- log.debug(sm.getString(
- "ajpprotocol.proto.socketexception.debug"), e);
- } catch (java.io.IOException e) {
- // IOExceptions are normal
- log.debug(sm.getString(
- "ajpprotocol.proto.ioexception.debug"), e);
- }
- // Future developers: if you discover any other
- // rare-but-nonfatal exceptions, catch them here, and log as
- // above.
- catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
- // any other exception or error is odd. Here we log it
- // with "ERROR" level, so it will show up even on
- // less-than-verbose logs.
- log.error(sm.getString("ajpprotocol.proto.error"), e);
- }
- release(socket, processor, true, false);
- return SocketState.CLOSED;
- }
-
protected AjpAprProcessor createProcessor() {
AjpAprProcessor processor = new AjpAprProcessor(proto.packetSize, (AprEndpoint)proto.endpoint);
processor.setAdapter(proto.adapter);
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java?rev=1144390&r1=1144389&r2=1144390&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java Fri Jul 8 17:19:19 2011
@@ -42,7 +42,7 @@ import org.apache.tomcat.util.net.Socket
/**
* Processes AJP requests using NIO.
*/
-public class AjpNioProcessor extends AbstractAjpProcessor {
+public class AjpNioProcessor extends AbstractAjpProcessor<NioChannel> {
/**
@@ -91,6 +91,7 @@ public class AjpNioProcessor extends Abs
*
* @throws IOException error during an I/O operation
*/
+ @Override
public SocketState process(SocketWrapper<NioChannel> socket)
throws IOException {
RequestInfo rp = request.getRequestProcessor();
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java?rev=1144390&r1=1144389&r2=1144390&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java Fri Jul 8 17:19:19 2011
@@ -14,23 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.coyote.ajp;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
-import java.util.concurrent.ConcurrentHashMap;
import org.apache.coyote.AbstractProtocol;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.net.NioChannel;
import org.apache.tomcat.util.net.NioEndpoint;
import org.apache.tomcat.util.net.NioEndpoint.Handler;
import org.apache.tomcat.util.net.SSLImplementation;
-import org.apache.tomcat.util.net.SocketStatus;
import org.apache.tomcat.util.net.SocketWrapper;
@@ -90,16 +86,11 @@ public class AjpNioProtocol extends Abst
protected static class AjpConnectionHandler
- extends AbstractConnectionHandler implements Handler {
+ extends AbstractAjpConnectionHandler<NioChannel, AjpNioProcessor>
+ implements Handler {
protected AjpNioProtocol proto;
- protected ConcurrentHashMap<SocketWrapper<NioChannel>, AjpNioProcessor> connections =
- new ConcurrentHashMap<SocketWrapper<NioChannel>, AjpNioProcessor>();
-
- protected RecycledProcessors<AjpNioProcessor> recycledProcessors =
- new RecycledProcessors<AjpNioProcessor>(this);
-
public AjpConnectionHandler(AjpNioProtocol proto) {
this.proto = proto;
}
@@ -115,11 +106,6 @@ public class AjpNioProtocol extends Abst
}
@Override
- public void recycle() {
- recycledProcessors.clear();
- }
-
- @Override
public SSLImplementation getSslImplementation() {
// AJP does not support SSL
return null;
@@ -167,6 +153,7 @@ public class AjpNioProtocol extends Abst
* Expected to be used by the handler once the processor is no longer
* required.
*/
+ @Override
public void release(SocketWrapper<NioChannel> socket,
AjpNioProcessor processor, boolean isSocketClosing,
boolean addToPoller) {
@@ -179,70 +166,6 @@ public class AjpNioProtocol extends Abst
@Override
- public SocketState process(SocketWrapper<NioChannel> socket,
- SocketStatus status) {
- AjpNioProcessor processor = connections.remove(socket);
-
- socket.setAsync(false); //no longer check for timeout
-
- try {
- if (processor == null) {
- processor = recycledProcessors.poll();
- }
- if (processor == null) {
- processor = createProcessor();
- }
-
- SocketState state = SocketState.CLOSED;
- do {
- if (processor.isAsync() || state == SocketState.ASYNC_END) {
- state = processor.asyncDispatch(status);
- } else {
- state = processor.process(socket);
- }
-
- if (state != SocketState.CLOSED && processor.isAsync()) {
- state = processor.asyncPostProcess();
- }
- } while (state == SocketState.ASYNC_END);
-
- if (state == SocketState.LONG) {
- // In the middle of processing a request/response. Keep the
- // socket associated with the processor.
- connections.put(socket, processor);
- socket.setAsync(true);
- } else if (state == SocketState.OPEN){
- // In keep-alive but between requests. OK to recycle
- // processor. Continue to poll for the next request.
- release(socket, processor, false, true);
- } else {
- // Connection closed. OK to recycle the processor.
- release(socket, processor, true, false);
- }
- return state;
- } catch(java.net.SocketException e) {
- // SocketExceptions are normal
- log.debug(sm.getString(
- "ajpprotocol.proto.socketexception.debug"), e);
- } catch (java.io.IOException e) {
- // IOExceptions are normal
- log.debug(sm.getString(
- "ajpprotocol.proto.ioexception.debug"), e);
- }
- // Future developers: if you discover any other
- // rare-but-nonfatal exceptions, catch them here, and log as
- // above.
- catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
- // any other exception or error is odd. Here we log it
- // with "ERROR" level, so it will show up even on
- // less-than-verbose logs.
- log.error(sm.getString("ajpprotocol.proto.error"), e);
- }
- release(socket, processor, true, false);
- return SocketState.CLOSED;
- }
-
protected AjpNioProcessor createProcessor() {
AjpNioProcessor processor = new AjpNioProcessor(proto.packetSize, (NioEndpoint)proto.endpoint);
processor.setAdapter(proto.adapter);
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java?rev=1144390&r1=1144389&r2=1144390&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java Fri Jul 8 17:19:19 2011
@@ -47,7 +47,7 @@ import org.apache.tomcat.util.net.Socket
* @author Costin Manolache
* @author Bill Barker
*/
-public class AjpProcessor extends AbstractAjpProcessor {
+public class AjpProcessor extends AbstractAjpProcessor<Socket> {
/**
@@ -100,6 +100,7 @@ public class AjpProcessor extends Abstra
*
* @throws IOException error during an I/O operation
*/
+ @Override
public SocketState process(SocketWrapper<Socket> socket)
throws IOException {
RequestInfo rp = request.getRequestProcessor();
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpProtocol.java?rev=1144390&r1=1144389&r2=1144390&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpProtocol.java Fri Jul 8 17:19:19 2011
@@ -14,21 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.coyote.ajp;
import java.net.Socket;
-import java.util.concurrent.ConcurrentHashMap;
import org.apache.coyote.AbstractProtocol;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.net.JIoEndpoint;
import org.apache.tomcat.util.net.JIoEndpoint.Handler;
import org.apache.tomcat.util.net.SSLImplementation;
-import org.apache.tomcat.util.net.SocketStatus;
import org.apache.tomcat.util.net.SocketWrapper;
@@ -89,16 +85,11 @@ public class AjpProtocol extends Abstrac
protected static class AjpConnectionHandler
- extends AbstractConnectionHandler implements Handler {
+ extends AbstractAjpConnectionHandler<Socket,AjpProcessor>
+ implements Handler {
protected AjpProtocol proto;
- protected ConcurrentHashMap<SocketWrapper<Socket>, AjpProcessor> connections =
- new ConcurrentHashMap<SocketWrapper<Socket>, AjpProcessor>();
-
- protected RecycledProcessors<AjpProcessor> recycledProcessors =
- new RecycledProcessors<AjpProcessor>(this);
-
public AjpConnectionHandler(AjpProtocol proto) {
this.proto = proto;
}
@@ -119,11 +110,6 @@ public class AjpProtocol extends Abstrac
return null;
}
- @Override
- public void recycle() {
- recycledProcessors.clear();
- }
-
/**
* Expected to be used by the handler once the processor is no longer
* required.
@@ -133,6 +119,7 @@ public class AjpProtocol extends Abstrac
* @param isSocketClosing
* @param addToPoller Ignored for BIO
*/
+ @Override
public void release(SocketWrapper<Socket> socket,
AjpProcessor processor, boolean isSocketClosing,
boolean addToPoller) {
@@ -142,70 +129,6 @@ public class AjpProtocol extends Abstrac
@Override
- public SocketState process(SocketWrapper<Socket> socket,
- SocketStatus status) {
- AjpProcessor processor = connections.remove(socket);
-
- socket.setAsync(false);
-
- try {
- if (processor == null) {
- processor = recycledProcessors.poll();
- }
- if (processor == null) {
- processor = createProcessor();
- }
-
- SocketState state = SocketState.CLOSED;
- do {
- if (processor.isAsync() || state == SocketState.ASYNC_END) {
- state = processor.asyncDispatch(status);
- } else {
- state = processor.process(socket);
- }
-
- if (state != SocketState.CLOSED && processor.isAsync()) {
- state = processor.asyncPostProcess();
- }
- } while (state == SocketState.ASYNC_END);
-
- if (state == SocketState.LONG) {
- // In the middle of processing a request/response. Keep the
- // socket associated with the processor.
- connections.put(socket, processor);
- socket.setAsync(true);
- } else if (state == SocketState.OPEN){
- // In keep-alive but between requests. OK to recycle
- // processor. Continue to poll for the next request.
- release(socket, processor, false, true);
- } else {
- // Connection closed. OK to recycle the processor.
- release(socket, processor, true, false);
- }
- return state;
- } catch(java.net.SocketException e) {
- // SocketExceptions are normal
- log.debug(sm.getString(
- "ajpprotocol.proto.socketexception.debug"), e);
- } catch (java.io.IOException e) {
- // IOExceptions are normal
- log.debug(sm.getString(
- "ajpprotocol.proto.ioexception.debug"), e);
- }
- // Future developers: if you discover any other
- // rare-but-nonfatal exceptions, catch them here, and log as
- // above.
- catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
- // any other exception or error is odd. Here we log it
- // with "ERROR" level, so it will show up even on
- // less-than-verbose logs.
- log.error(sm.getString("ajpprotocol.proto.error"), e);
- }
- release(socket, processor, true, false);
- return SocketState.CLOSED;
- }
-
protected AjpProcessor createProcessor() {
AjpProcessor processor = new AjpProcessor(proto.packetSize, (JIoEndpoint)proto.endpoint);
processor.setAdapter(proto.adapter);
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org