Author: markt
Date: Sat May 14 22:14:55 2011
New Revision: 1103243
URL: http://svn.apache.org/viewvc?rev=1103243&view=rev
Log:
Initial AJP-NIO implementation.
Docs to follow once more testing has been completed.
Added:
tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java
- copied, changed from r1102964,
tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java
tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java
- copied, changed from r1102964,
tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java
Copied: tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java (from
r1102964, tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java)
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java?p2=tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java&p1=tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java&r1=1102964&r2=1103243&rev=1103243&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java Sat May 14
22:14:55 2011
@@ -17,11 +17,11 @@
package org.apache.coyote.ajp;
+import java.io.EOFException;
import java.io.IOException;
-import java.io.InputStream;
import java.io.InterruptedIOException;
-import java.io.OutputStream;
-import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.channels.Selector;
import java.util.concurrent.Executor;
import org.apache.coyote.ActionCode;
@@ -36,29 +36,23 @@ import org.apache.tomcat.util.buf.ByteCh
import org.apache.tomcat.util.buf.HexUtils;
import org.apache.tomcat.util.http.HttpMessages;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
-import org.apache.tomcat.util.net.JIoEndpoint;
+import org.apache.tomcat.util.net.NioChannel;
+import org.apache.tomcat.util.net.NioEndpoint;
+import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment;
+import org.apache.tomcat.util.net.NioSelectorPool;
import org.apache.tomcat.util.net.SocketStatus;
-import org.apache.tomcat.util.net.SocketWrapper;
/**
- * Processes AJP requests.
- *
- * @author Remy Maucherat
- * @author Henri Gomez
- * @author Dan Milstein
- * @author Keith Wannamaker
- * @author Kevin Seguin
- * @author Costin Manolache
- * @author Bill Barker
+ * Processes AJP requests using NIO.
*/
-public class AjpProcessor extends AbstractAjpProcessor {
+public class AjpNioProcessor extends AbstractAjpProcessor {
/**
* Logger.
*/
- private static final Log log = LogFactory.getLog(AjpProcessor.class);
+ private static final Log log = LogFactory.getLog(AjpNioProcessor.class);
@Override
protected Log getLog() {
return log;
@@ -67,7 +61,7 @@ public class AjpProcessor extends Abstra
// ----------------------------------------------------------- Constructors
- public AjpProcessor(int packetSize, JIoEndpoint endpoint) {
+ public AjpNioProcessor(int packetSize, NioEndpoint endpoint) {
this.endpoint = endpoint;
@@ -79,6 +73,8 @@ public class AjpProcessor extends Abstra
response.setOutputBuffer(new SocketOutputBuffer());
request.setResponse(response);
+ pool = endpoint.getSelectorPool();
+
this.packetSize = packetSize;
requestHeaderMessage = new AjpMessage(packetSize);
responseHeaderMessage = new AjpMessage(packetSize);
@@ -110,21 +106,24 @@ public class AjpProcessor extends Abstra
/**
* Socket associated with the current connection.
*/
- protected SocketWrapper<Socket> socket;
+ protected NioChannel socket;
+ protected NioSelectorPool pool;
+
+
/**
- * Input stream.
+ * Input buffer.
*/
- protected InputStream input;
-
+ protected ByteBuffer readBuffer;
+ protected int readBufferEnd;
/**
- * Output stream.
+ * Output buffer.
*/
- protected OutputStream output;
-
+ protected ByteBuffer writeBuffer;
+
/**
* Direct buffer used for sending right away a get body message.
*/
@@ -189,16 +188,6 @@ public class AjpProcessor extends Abstra
// ------------------------------------------------------------- Properties
- /**
- * The number of milliseconds Tomcat will wait for a subsequent request
- * before closing the connection. The default is the same as for
- * Apache HTTP Server (15 000 milliseconds).
- */
- protected int keepAliveTimeout = -1;
- public int getKeepAliveTimeout() { return keepAliveTimeout; }
- public void setKeepAliveTimeout(int timeout) { keepAliveTimeout = timeout;
}
-
-
// --------------------------------------------------------- Public Methods
@@ -208,18 +197,23 @@ public class AjpProcessor extends Abstra
*
* @throws IOException error during an I/O operation
*/
- public SocketState process(SocketWrapper<Socket> socket)
+ public SocketState process(NioChannel socket)
throws IOException {
RequestInfo rp = request.getRequestProcessor();
rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
// Setting up the socket
this.socket = socket;
- input = socket.getSocket().getInputStream();
- output = socket.getSocket().getOutputStream();
+ readBuffer = socket.getBufHandler().getReadBuffer();
+ readBufferEnd = 0;
+ readBuffer.clear();
+ writeBuffer = socket.getBufHandler().getWriteBuffer();
+ writeBuffer.clear();
+
int soTimeout = -1;
+ final KeyAttachment ka = (KeyAttachment)socket.getAttachment(false);
if (keepAliveTimeout > 0) {
- soTimeout = socket.getSocket().getSoTimeout();
+ ka.setTimeout(soTimeout);
}
// Error flag
@@ -231,7 +225,7 @@ public class AjpProcessor extends Abstra
try {
// Set keep alive timeout if enabled
if (keepAliveTimeout > 0) {
- socket.getSocket().setSoTimeout(keepAliveTimeout);
+ ka.setTimeout(keepAliveTimeout);
}
// Get first message of the request
if (!readMessage(requestHeaderMessage)) {
@@ -241,14 +235,14 @@ public class AjpProcessor extends Abstra
}
// Set back timeout if keep alive timeout is enabled
if (keepAliveTimeout > 0) {
- socket.getSocket().setSoTimeout(soTimeout);
+ ka.setTimeout(soTimeout);
}
// Check message type, process right away and break if
// not regular request processing
int type = requestHeaderMessage.getByte();
if (type == Constants.JK_AJP13_CPING_REQUEST) {
try {
- output.write(pongMessageArray);
+ output(pongMessageArray, 0, pongMessageArray.length);
} catch (IOException e) {
error = true;
}
@@ -343,13 +337,23 @@ public class AjpProcessor extends Abstra
if (isAsync() && !error && !endpoint.isPaused()) {
return SocketState.LONG;
} else {
- input = null;
- output = null;
+ readBuffer = null;
+ writeBuffer = null;
return SocketState.CLOSED;
}
}
+
+ @Override
+ public void recycle() {
+ if (readBuffer != null) {
+ readBuffer.clear();
+ }
+ readBufferEnd = 0;
+ super.recycle();
+ }
+
public SocketState asyncDispatch(SocketStatus status) {
RequestInfo rp = request.getRequestProcessor();
@@ -373,8 +377,8 @@ public class AjpProcessor extends Abstra
if (error) {
response.setStatus(500);
request.updateCounters();
- input = null;
- output = null;
+ readBuffer = null;
+ writeBuffer = null;
return SocketState.CLOSED;
} else {
return SocketState.LONG;
@@ -384,8 +388,8 @@ public class AjpProcessor extends Abstra
response.setStatus(500);
}
request.updateCounters();
- input = null;
- output = null;
+ readBuffer = null;
+ writeBuffer = null;
return SocketState.CLOSED;
}
@@ -413,18 +417,20 @@ public class AjpProcessor extends Abstra
if (actionCode == ActionCode.ASYNC_COMPLETE) {
if (asyncStateMachine.asyncComplete()) {
- ((JIoEndpoint)endpoint).processSocketAsync(this.socket,
- SocketStatus.OPEN);
+ ((NioEndpoint)endpoint).processSocket(this.socket,
+ SocketStatus.OPEN, false);
}
} else if (actionCode == ActionCode.ASYNC_SETTIMEOUT) {
if (param == null) return;
long timeout = ((Long)param).longValue();
- // if we are not piggy backing on a worker thread, set the timeout
- socket.setTimeout(timeout);
+ final KeyAttachment ka =
(KeyAttachment)socket.getAttachment(false);
+ if (keepAliveTimeout > 0) {
+ ka.setTimeout(timeout);
+ }
} else if (actionCode == ActionCode.ASYNC_DISPATCH) {
if (asyncStateMachine.asyncDispatch()) {
- ((JIoEndpoint)endpoint).processSocketAsync(this.socket,
- SocketStatus.OPEN);
+ ((NioEndpoint)endpoint).processSocket(this.socket,
+ SocketStatus.OPEN, true);
}
}
}
@@ -435,7 +441,28 @@ public class AjpProcessor extends Abstra
@Override
protected void output(byte[] src, int offset, int length)
throws IOException {
- output.write(src, offset, length);
+ ByteBuffer writeBuffer = socket.getBufHandler() .getWriteBuffer();
+
+ writeBuffer.put(src, offset, length);
+
+ writeBuffer.flip();
+
+ NioEndpoint.KeyAttachment att =
(NioEndpoint.KeyAttachment)socket.getAttachment(false);
+ if ( att == null ) throw new IOException("Key must be cancelled");
+ long writeTimeout = att.getTimeout();
+ Selector selector = null;
+ try {
+ selector = pool.get();
+ } catch ( IOException x ) {
+ //ignore
+ }
+ try {
+ pool.write(writeBuffer, socket, selector, writeTimeout, true,
+ null);
+ }finally {
+ if ( selector != null ) pool.put(selector);
+ }
+ writeBuffer.clear();
}
/**
@@ -460,8 +487,7 @@ public class AjpProcessor extends Abstra
finished = true;
// Add the end message
- output.write(endMessageArray);
-
+ output(endMessageArray, 0, endMessageArray.length);
}
@@ -469,22 +495,55 @@ public class AjpProcessor extends Abstra
* Read at least the specified amount of bytes, and place them
* in the input buffer.
*/
- protected boolean read(byte[] buf, int pos, int n)
+ protected void read(byte[] buf, int pos, int n)
throws IOException {
- int read = 0;
+ int read = readBufferEnd - pos;
int res = 0;
while (read < n) {
- res = input.read(buf, read + pos, n - read);
+ res = readSocket(buf, read + pos, true);
if (res > 0) {
read += res;
} else {
throw new IOException(sm.getString("ajpprotocol.failedread"));
}
}
-
- return true;
+ readBufferEnd += read;
+ }
+ private int readSocket(byte[] buf, int pos, boolean block) throws
IOException {
+ int nRead = 0;
+ socket.getBufHandler().getReadBuffer().clear();
+ if ( block ) {
+ Selector selector = null;
+ try {
+ selector = pool.get();
+ } catch ( IOException x ) {
+ // Ignore
+ }
+ try {
+ NioEndpoint.KeyAttachment att =
(NioEndpoint.KeyAttachment)socket.getAttachment(false);
+ if ( att == null ) throw new IOException("Key must be
cancelled.");
+ nRead =
pool.read(socket.getBufHandler().getReadBuffer(),socket,selector,att.getTimeout());
+ } catch ( EOFException eof ) {
+ nRead = -1;
+ } finally {
+ if ( selector != null ) pool.put(selector);
+ }
+ } else {
+ nRead = socket.read(socket.getBufHandler().getReadBuffer());
+ }
+ if (nRead > 0) {
+ socket.getBufHandler().getReadBuffer().flip();
+ socket.getBufHandler().getReadBuffer().limit(nRead);
+ socket.getBufHandler().getReadBuffer().get(buf, pos, nRead);
+ return nRead;
+ } else if (nRead == -1) {
+ //return false;
+ throw new EOFException(sm.getString("iib.eof.error"));
+ } else {
+ return 0;
+ }
}
@@ -536,7 +595,7 @@ public class AjpProcessor extends Abstra
}
// Request more data immediately
- output.write(getBodyMessageArray);
+ output(getBodyMessageArray, 0, getBodyMessageArray.length);
boolean moreData = receive();
if( !moreData ) {
@@ -593,7 +652,7 @@ public class AjpProcessor extends Abstra
protected void flush(boolean explicit) throws IOException {
if (explicit && !finished) {
// Send the flush message
- output.write(flushMessageArray);
+ output(flushMessageArray, 0, flushMessageArray.length);
}
}
@@ -639,7 +698,7 @@ public class AjpProcessor extends Abstra
responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
responseHeaderMessage.appendBytes(chunk.getBytes(),
chunk.getOffset() + off, thisTime);
responseHeaderMessage.end();
- output.write(responseHeaderMessage.getBuffer(), 0,
responseHeaderMessage.getLen());
+ output(responseHeaderMessage.getBuffer(), 0,
responseHeaderMessage.getLen());
off += thisTime;
}
Copied: tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java (from
r1102964, tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java)
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java?p2=tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java&p1=tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java&r1=1102964&r2=1103243&rev=1103243&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java Sat May 14
22:14:55 2011
@@ -17,6 +17,8 @@
package org.apache.coyote.ajp;
+import java.nio.channels.SocketChannel;
+import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
@@ -31,24 +33,22 @@ import org.apache.juli.logging.LogFactor
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.modeler.Registry;
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.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;
/**
* Abstract the protocol implementation, including threading, etc.
* Processor is single threaded and specific to stream-based protocols,
* will not fit Jk protocols like JNI.
- *
- * @author Remy Maucherat
- * @author Costin Manolache
*/
-public class AjpAprProtocol extends AbstractAjpProtocol {
+public class AjpNioProtocol extends AbstractAjpProtocol {
- private static final Log log = LogFactory.getLog(AjpAprProtocol.class);
+ private static final Log log = LogFactory.getLog(AjpNioProtocol.class);
@Override
protected Log getLog() { return log; }
@@ -63,14 +63,15 @@ public class AjpAprProtocol extends Abst
// ------------------------------------------------------------ Constructor
- public AjpAprProtocol() {
- endpoint = new AprEndpoint();
+ public AjpNioProtocol() {
+ endpoint = new NioEndpoint();
cHandler = new AjpConnectionHandler(this);
- ((AprEndpoint) endpoint).setHandler(cHandler);
+ ((NioEndpoint) endpoint).setHandler(cHandler);
setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
- setUseSendfile(Constants.DEFAULT_USE_SENDFILE);
+ // AJP does not use Send File
+ ((NioEndpoint) endpoint).setUseSendfile(false);
}
@@ -86,24 +87,15 @@ public class AjpAprProtocol extends Abst
// --------------------------------------------------------- Public Methods
- public boolean getUseSendfile() { return endpoint.getUseSendfile(); }
- public void setUseSendfile(@SuppressWarnings("unused") boolean
useSendfile) {
- /* No sendfile for AJP */
- }
-
- public int getPollTime() { return ((AprEndpoint)endpoint).getPollTime(); }
- public void setPollTime(int pollTime) {
((AprEndpoint)endpoint).setPollTime(pollTime); }
-
- // pollerSize is now a synonym for maxConnections
- public void setPollerSize(int pollerSize) {
endpoint.setMaxConnections(pollerSize); }
- public int getPollerSize() { return endpoint.getMaxConnections(); }
+ // AJP does not use Send File.
+ public boolean getUseSendfile() { return false; }
// ----------------------------------------------------- JMX related
methods
@Override
protected String getNamePrefix() {
- return ("ajp-apr");
+ return ("ajp-nio");
}
@@ -112,19 +104,19 @@ public class AjpAprProtocol extends Abst
protected static class AjpConnectionHandler implements Handler {
- protected AjpAprProtocol proto;
+ protected AjpNioProtocol proto;
protected AtomicLong registerCount = new AtomicLong(0);
protected RequestGroupInfo global = new RequestGroupInfo();
- protected ConcurrentHashMap<SocketWrapper<Long>, AjpAprProcessor>
connections =
- new ConcurrentHashMap<SocketWrapper<Long>, AjpAprProcessor>();
+ protected ConcurrentHashMap<NioChannel, AjpNioProcessor> connections =
+ new ConcurrentHashMap<NioChannel, AjpNioProcessor>();
- protected ConcurrentLinkedQueue<AjpAprProcessor> recycledProcessors =
- new ConcurrentLinkedQueue<AjpAprProcessor>() {
+ protected ConcurrentLinkedQueue<AjpNioProcessor> recycledProcessors =
+ new ConcurrentLinkedQueue<AjpNioProcessor>() {
private static final long serialVersionUID = 1L;
protected AtomicInteger size = new AtomicInteger(0);
@Override
- public boolean offer(AjpAprProcessor processor) {
+ public boolean offer(AjpNioProcessor processor) {
boolean offer = (proto.processorCache == -1) ? true :
(size.get() < proto.processorCache);
//avoid over growing our cache or add after we have stopped
boolean result = false;
@@ -139,8 +131,8 @@ public class AjpAprProtocol extends Abst
}
@Override
- public AjpAprProcessor poll() {
- AjpAprProcessor result = super.poll();
+ public AjpNioProcessor poll() {
+ AjpNioProcessor result = super.poll();
if ( result != null ) {
size.decrementAndGet();
}
@@ -149,7 +141,7 @@ public class AjpAprProtocol extends Abst
@Override
public void clear() {
- AjpAprProcessor next = poll();
+ AjpNioProcessor next = poll();
while ( next != null ) {
unregister(next);
next = poll();
@@ -159,7 +151,7 @@ public class AjpAprProtocol extends Abst
}
};
- public AjpConnectionHandler(AjpAprProtocol proto) {
+ public AjpConnectionHandler(AjpNioProtocol proto) {
this.proto = proto;
}
@@ -173,15 +165,62 @@ public class AjpAprProtocol extends Abst
recycledProcessors.clear();
}
+ @Override
+ public SSLImplementation getSslImplementation() {
+ // AJP does not support SSL
+ return null;
+ }
+
+ @Override
+ public void release(SocketChannel socket) {
+ if (log.isDebugEnabled())
+ log.debug("Iterating through our connections to release a
socket channel:"+socket);
+ boolean released = false;
+ Iterator<java.util.Map.Entry<NioChannel, AjpNioProcessor>> it =
connections.entrySet().iterator();
+ while (it.hasNext()) {
+ java.util.Map.Entry<NioChannel, AjpNioProcessor> entry =
it.next();
+ if (entry.getKey().getIOChannel()==socket) {
+ it.remove();
+ AjpNioProcessor result = entry.getValue();
+ result.recycle();
+ unregister(result);
+ released = true;
+ break;
+ }
+ }
+ if (log.isDebugEnabled())
+ log.debug("Done iterating through our connections to release a
socket channel:"+socket +" released:"+released);
+ }
+
+ /**
+ * Use this only if the processor is not available, otherwise use
+ * {@link #release(NioChannel, Http11NioProcessor).
+ */
+ @Override
+ public void release(NioChannel socket) {
+ AjpNioProcessor processor = connections.remove(socket);
+ if (processor != null) {
+ processor.recycle();
+ recycledProcessors.offer(processor);
+ }
+ }
+
+
+ public void release(NioChannel socket, AjpNioProcessor processor) {
+ connections.remove(socket);
+ processor.recycle();
+ recycledProcessors.offer(processor);
+ }
+
// FIXME: Support for this could be added in AJP as well
@Override
- public SocketState event(SocketWrapper<Long> socket, SocketStatus
status) {
+ public SocketState event(NioChannel socket, SocketStatus status) {
return SocketState.CLOSED;
}
@Override
- public SocketState process(SocketWrapper<Long> socket) {
- AjpAprProcessor processor = recycledProcessors.poll();
+ public SocketState process(NioChannel socket) {
+ AjpNioProcessor processor = recycledProcessors.poll();
try {
if (processor == null) {
processor = createProcessor();
@@ -196,7 +235,9 @@ public class AjpAprProtocol extends Abst
// Need to make socket available for next processing cycle
// but no need for the poller
connections.put(socket, processor);
- socket.setAsync(true);
+ NioEndpoint.KeyAttachment att =
+
(NioEndpoint.KeyAttachment)socket.getAttachment(false);
+ att.setAsync(true);
} else {
processor.recycle();
recycledProcessors.offer(processor);
@@ -227,46 +268,8 @@ public class AjpAprProtocol extends Abst
return SocketState.CLOSED;
}
- @Override
- public SocketState asyncDispatch(SocketWrapper<Long> socket,
SocketStatus status) {
-
- AjpAprProcessor processor = connections.get(socket);
-
- SocketState state = SocketState.CLOSED;
- if (processor != null) {
- // Call the appropriate event
- try {
- state = processor.asyncDispatch(socket, status);
- }
- // Future developers: if you discover any other
- // rare-but-nonfatal exceptions, catch them here, and log as
- // debug.
- 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.
- AjpAprProtocol.log.error
- (sm.getString("ajpprotocol.proto.error"), e);
- } finally {
- if (state == SocketState.LONG && processor.isAsync()) {
- state = processor.asyncPostProcess();
- }
- if (state != SocketState.LONG && state !=
SocketState.ASYNC_END) {
- connections.remove(socket);
- processor.recycle();
- recycledProcessors.offer(processor);
- if (state == SocketState.OPEN) {
-
((AprEndpoint)proto.endpoint).getPoller().add(socket.getSocket().longValue());
- }
- }
- }
- }
- return state;
- }
-
- protected AjpAprProcessor createProcessor() {
- AjpAprProcessor processor = new AjpAprProcessor(proto.packetSize,
(AprEndpoint)proto.endpoint);
+ protected AjpNioProcessor createProcessor() {
+ AjpNioProcessor processor = new AjpNioProcessor(proto.packetSize,
(NioEndpoint)proto.endpoint);
processor.setAdapter(proto.adapter);
processor.setTomcatAuthentication(proto.tomcatAuthentication);
processor.setRequiredSecret(proto.requiredSecret);
@@ -275,7 +278,7 @@ public class AjpAprProtocol extends Abst
return processor;
}
- protected void register(AjpAprProcessor processor) {
+ protected void register(AjpNioProcessor processor) {
if (proto.getDomain() != null) {
synchronized (this) {
try {
@@ -297,7 +300,7 @@ public class AjpAprProtocol extends Abst
}
}
- protected void unregister(AjpAprProcessor processor) {
+ protected void unregister(AjpNioProcessor processor) {
if (proto.getDomain() != null) {
synchronized (this) {
try {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]