You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2011/09/01 14:32:58 UTC

svn commit: r1164047 - /httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/

Author: olegk
Date: Thu Sep  1 12:32:57 2011
New Revision: 1164047

URL: http://svn.apache.org/viewvc?rev=1164047&view=rev
Log:
Complete rewrite of core async HTTP protocol handlers (client side protocol handler)

Added:
    httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandler.java   (with props)
    httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandlerImpl.java   (with props)
    httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java   (contents, props changed)
      - copied, changed from r1164041, httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/NHttpClientProtocolHandler.java
    httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/MessageState.java   (contents, props changed)
      - copied, changed from r1164042, httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/MessageState.java
Modified:
    httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/AbstractAsyncRequestConsumer.java
    httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/AbstractAsyncResponseConsumer.java
    httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncRequestConsumer.java
    httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncResponseConsumer.java
    httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/NullRequestConsumer.java

Modified: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/AbstractAsyncRequestConsumer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/AbstractAsyncRequestConsumer.java?rev=1164047&r1=1164046&r2=1164047&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/AbstractAsyncRequestConsumer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/AbstractAsyncRequestConsumer.java Thu Sep  1 12:32:57 2011
@@ -96,4 +96,8 @@ public abstract class AbstractAsyncReque
         return this.result;
     }
 
+    public boolean isDone() {
+        return this.completed;
+    }
+
 }

Modified: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/AbstractAsyncResponseConsumer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/AbstractAsyncResponseConsumer.java?rev=1164047&r1=1164046&r2=1164047&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/AbstractAsyncResponseConsumer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/AbstractAsyncResponseConsumer.java Thu Sep  1 12:32:57 2011
@@ -114,4 +114,8 @@ public abstract class AbstractAsyncRespo
         return this.result;
     }
 
+    public boolean isDone() {
+        return this.completed;
+    }
+
 }

Added: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandler.java?rev=1164047&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandler.java (added)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandler.java Thu Sep  1 12:32:57 2011
@@ -0,0 +1,42 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.nio.protocol;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * @since 4.2
+ */
+public interface HttpAsyncClientExchangeHandler<T> extends HttpAsyncRequestProducer, HttpAsyncResponseConsumer<T> {
+
+    HttpContext getContext();
+
+    ConnectionReuseStrategy getConnectionReuseStrategy();
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandlerImpl.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandlerImpl.java?rev=1164047&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandlerImpl.java (added)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandlerImpl.java Thu Sep  1 12:32:57 2011
@@ -0,0 +1,178 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.nio.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.nio.ContentDecoder;
+import org.apache.http.nio.ContentEncoder;
+import org.apache.http.nio.IOControl;
+import org.apache.http.nio.NHttpClientConnection;
+import org.apache.http.params.DefaultedHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpProcessor;
+
+class HttpAsyncClientExchangeHandlerImpl<T> implements HttpAsyncClientExchangeHandler<T> {
+
+    private final HttpAsyncRequestProducer requestProducer;
+    private final HttpAsyncResponseConsumer<T> responseConsumer;
+    private final HttpContext localContext;
+    private final HttpProcessor httppocessor;
+    private final NHttpClientConnection conn;
+    private final ConnectionReuseStrategy reuseStrategy;
+    private final HttpParams params;
+
+    public HttpAsyncClientExchangeHandlerImpl(
+            final HttpAsyncRequestProducer requestProducer,
+            final HttpAsyncResponseConsumer<T> responseConsumer,
+            final HttpContext localContext,
+            final HttpProcessor httppocessor,
+            final NHttpClientConnection conn,
+            final ConnectionReuseStrategy reuseStrategy,
+            final HttpParams params) {
+        super();
+        if (requestProducer == null) {
+            throw new IllegalArgumentException("Request producer may not be null");
+        }
+        if (responseConsumer == null) {
+            throw new IllegalArgumentException("Response consumer may not be null");
+        }
+        if (localContext == null) {
+            throw new IllegalArgumentException("HTTP context may not be null");
+        }
+        if (httppocessor == null) {
+            throw new IllegalArgumentException("HTTP processor may not be null");
+        }
+        if (conn == null) {
+            throw new IllegalArgumentException("HTTP connection may not be null");
+        }
+        if (reuseStrategy == null) {
+            throw new IllegalArgumentException("Connection reuse strategy may not be null");
+        }
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        this.requestProducer = requestProducer;
+        this.responseConsumer = responseConsumer;
+        this.localContext = localContext;
+        this.httppocessor = httppocessor;
+        this.conn = conn;
+        this.reuseStrategy = reuseStrategy;
+        this.params = params;
+    }
+
+    public void close() throws IOException {
+        this.responseConsumer.close();
+        this.requestProducer.close();
+    }
+
+    public HttpHost getTarget() {
+        return this.requestProducer.getTarget();
+    }
+
+    public HttpRequest generateRequest() throws IOException, HttpException {
+        HttpHost target = this.requestProducer.getTarget();
+        HttpRequest request = this.requestProducer.generateRequest();
+        request.setParams(new DefaultedHttpParams(request.getParams(), this.params));
+
+        this.localContext.setAttribute(ExecutionContext.HTTP_REQUEST, request);
+        this.localContext.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
+        this.localContext.setAttribute(ExecutionContext.HTTP_CONNECTION, this.conn);
+
+        this.httppocessor.process(request, this.localContext);
+
+        return request;
+    }
+
+    public void produceContent(
+            final ContentEncoder encoder, final IOControl ioctrl) throws IOException {
+        this.requestProducer.produceContent(encoder, ioctrl);
+        if (encoder.isCompleted()) {
+            this.requestProducer.close();
+        }
+    }
+
+    public boolean isRepeatable() {
+        return false;
+    }
+
+    public void resetRequest() {
+    }
+
+    public void responseReceived(final HttpResponse response) throws IOException, HttpException {
+        response.setParams(new DefaultedHttpParams(response.getParams(), this.params));
+        this.localContext.setAttribute(ExecutionContext.HTTP_RESPONSE, response);
+        this.httppocessor.process(response, this.localContext);
+        this.responseConsumer.responseReceived(response);
+    }
+
+    public void consumeContent(
+            final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
+        this.responseConsumer.consumeContent(decoder, ioctrl);
+    }
+
+    public void responseCompleted(final HttpContext context) {
+        this.responseConsumer.responseCompleted(context);
+    }
+
+    public void failed(final Exception ex) {
+        this.responseConsumer.failed(ex);
+    }
+
+    public void cancel() {
+        this.responseConsumer.cancel();
+    }
+
+    public T getResult() {
+        return this.responseConsumer.getResult();
+    }
+
+    public Exception getException() {
+        return this.responseConsumer.getException();
+    }
+
+    public HttpContext getContext() {
+        return this.localContext;
+    }
+
+    public ConnectionReuseStrategy getConnectionReuseStrategy() {
+        return this.reuseStrategy;
+    }
+
+    public boolean isDone() {
+        return this.responseConsumer.isDone();
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandlerImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandlerImpl.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientExchangeHandlerImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Copied: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java (from r1164041, httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/NHttpClientProtocolHandler.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java?p2=httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java&p1=httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/NHttpClientProtocolHandler.java&r1=1164041&r2=1164047&rev=1164047&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/NHttpClientProtocolHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java Thu Sep  1 12:32:57 2011
@@ -25,14 +25,13 @@
  *
  */
 
-package org.apache.http.impl.nio.client;
+package org.apache.http.nio.protocol;
 
 import java.io.IOException;
 import java.net.ProtocolException;
 import java.net.SocketTimeoutException;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.apache.http.ConnectionReuseStrategy;
 import org.apache.http.HttpEntityEnclosingRequest;
 import org.apache.http.HttpException;
 import org.apache.http.HttpRequest;
@@ -43,76 +42,39 @@ import org.apache.http.nio.ContentEncode
 import org.apache.http.nio.NHttpClientConnection;
 import org.apache.http.nio.NHttpClientHandler;
 import org.apache.http.nio.NHttpConnection;
-import org.apache.http.nio.client.HttpAsyncExchangeHandler;
 import org.apache.http.params.CoreProtocolPNames;
 import org.apache.http.protocol.HttpContext;
 
 /**
- * Fully asynchronous HTTP client side protocol handler that implements the
- * essential requirements of the HTTP protocol for the server side message
- * processing as described by RFC 2616. It is capable of executing HTTP requests
- * with nearly constant memory footprint. Only HTTP message heads are stored in
- * memory, while content of message bodies is streamed directly from the entity
- * to the underlying channel (and vice versa) using {@link ConsumingNHttpEntity}
- * and {@link ProducingNHttpEntity} interfaces.
+ * @since 4.2
  */
-class NHttpClientProtocolHandler implements NHttpClientHandler {
-
-    private final Log log = LogFactory.getLog(getClass());
+public class HttpAsyncClientProtocolHandler implements NHttpClientHandler {
 
+    public static final String HTTP_HANDLER = "http.nio.exchange-handler";
     private static final String HTTP_EXCHNAGE = "http.nio.exchange";
 
-    public NHttpClientProtocolHandler() {
+    public HttpAsyncClientProtocolHandler() {
         super();
     }
 
-    private void closeConnection(final NHttpClientConnection conn) {
-        try {
-            conn.close();
-        } catch (IOException ex) {
-            try {
-                conn.shutdown();
-            } catch (IOException ignore) {
-                this.log.debug("I/O error terminating connection: " + ex.getMessage(), ex);
-            }
-        }
-    }
-
-    protected void shutdownConnection(final NHttpClientConnection conn) {
-        try {
-            conn.shutdown();
-        } catch (IOException ex) {
-            this.log.debug("I/O error terminating connection: " + ex.getMessage(), ex);
-        }
-    }
-
     public void connected(final NHttpClientConnection conn, final Object attachment) {
         HttpExchange httpexchange = new HttpExchange();
         HttpContext context = conn.getContext();
-        if (this.log.isDebugEnabled()) {
-            this.log.debug(conn + ": Connected");
-        }
         context.setAttribute(HTTP_EXCHNAGE, httpexchange);
         requestReady(conn);
     }
 
     public void closed(final NHttpClientConnection conn) {
-        HttpContext context = conn.getContext();
-        HttpAsyncExchangeHandler<?> handler = getHandler(context);
-        if (this.log.isDebugEnabled()) {
-            this.log.debug(conn + ": Disconnected");
-        }
+        HttpExchange httpexchange = getHttpExchange(conn);
+        HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
         if (handler != null) {
             handler.cancel();
         }
     }
 
     public void exception(final NHttpClientConnection conn, final HttpException ex) {
-        HttpContext context = conn.getContext();
-        HttpAsyncExchangeHandler<?> handler = getHandler(context);
-        if (this.log.isErrorEnabled()) {
-            this.log.error(conn + " HTTP protocol exception: " + ex.getMessage(), ex);
-        }
+        HttpExchange httpexchange = getHttpExchange(conn);
+        HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
         if (handler != null) {
             handler.failed(ex);
         }
@@ -120,11 +82,8 @@ class NHttpClientProtocolHandler impleme
     }
 
     public void exception(final NHttpClientConnection conn, final IOException ex) {
-        HttpContext context = conn.getContext();
-        HttpAsyncExchangeHandler<?> handler = getHandler(context);
-        if (this.log.isErrorEnabled()) {
-            this.log.error(conn + " I/O error: " + ex.getMessage(), ex);
-        }
+        HttpExchange httpexchange = getHttpExchange(conn);
+        HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
         if (handler != null) {
             handler.failed(ex);
         }
@@ -132,19 +91,17 @@ class NHttpClientProtocolHandler impleme
     }
 
     public void requestReady(final NHttpClientConnection conn) {
-        HttpContext context = conn.getContext();
-        HttpExchange httpexchange = getHttpExchange(context);
-        HttpAsyncExchangeHandler<?> handler = getHandler(context);
-        if (this.log.isDebugEnabled()) {
-            this.log.debug(conn + " Request ready");
-        }
+        HttpExchange httpexchange = getHttpExchange(conn);
         if (httpexchange.getRequestState() != MessageState.READY) {
             return;
         }
+        HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
+        if (handler == null) {
+            handler = (HttpAsyncClientExchangeHandler<?>) conn.getContext().removeAttribute(
+                    HTTP_HANDLER);
+            httpexchange.setHandler(handler);
+        }
         if (handler == null || handler.isDone()) {
-            if (this.log.isDebugEnabled()) {
-                this.log.debug(conn + " No request submitted");
-            }
             return;
         }
         try {
@@ -172,80 +129,62 @@ class NHttpClientProtocolHandler impleme
             } else {
                 httpexchange.setRequestState(MessageState.COMPLETED);
             }
-        } catch (IOException ex) {
-            if (this.log.isDebugEnabled()) {
-                this.log.debug(conn + " I/O error: " + ex.getMessage(), ex);
-            }
+        } catch (RuntimeException ex) {
             shutdownConnection(conn);
             handler.failed(ex);
-        } catch (HttpException ex) {
-            if (this.log.isDebugEnabled()) {
-                this.log.debug(conn + " HTTP protocol exception: " + ex.getMessage(), ex);
-            }
-            closeConnection(conn);
+            throw ex;
+        } catch (Exception ex) {
+            shutdownConnection(conn);
             handler.failed(ex);
+            onException(ex);
         }
     }
 
     public void inputReady(final NHttpClientConnection conn, final ContentDecoder decoder) {
-        HttpContext context = conn.getContext();
-        HttpExchange httpexchange = getHttpExchange(context);
-        HttpAsyncExchangeHandler<?> handler = getHandler(context);
-        if (this.log.isDebugEnabled()) {
-            this.log.debug(conn + " Input ready");
-        }
+        HttpExchange httpexchange = getHttpExchange(conn);
+        HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
         try {
             handler.consumeContent(decoder, conn);
-            if (this.log.isDebugEnabled()) {
-                this.log.debug(conn + " Content decoder " + decoder);
-            }
             if (decoder.isCompleted()) {
                 processResponse(conn, httpexchange, handler);
             }
-        } catch (IOException ex) {
-            if (this.log.isDebugEnabled()) {
-                this.log.debug("I/O error: " + ex.getMessage(), ex);
-            }
+        } catch (RuntimeException ex) {
+            shutdownConnection(conn);
+            handler.failed(ex);
+            throw ex;
+        } catch (Exception ex) {
             shutdownConnection(conn);
             handler.failed(ex);
+            onException(ex);
         }
     }
 
     public void outputReady(final NHttpClientConnection conn, final ContentEncoder encoder) {
-        HttpContext context = conn.getContext();
-        HttpExchange httpexchange = getHttpExchange(context);
-        HttpAsyncExchangeHandler<?> handler = getHandler(context);
-        if (this.log.isDebugEnabled()) {
-            this.log.debug(conn + " Output ready");
-        }
+        HttpExchange httpexchange = getHttpExchange(conn);
+        HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
         try {
             if (httpexchange.getRequestState() == MessageState.ACK) {
                 conn.suspendOutput();
                 return;
             }
             handler.produceContent(encoder, conn);
-            if (this.log.isDebugEnabled()) {
-                this.log.debug(conn + " Content encoder " + encoder);
-            }
             if (encoder.isCompleted()) {
                 httpexchange.setRequestState(MessageState.COMPLETED);
             }
-        } catch (IOException ex) {
-            if (this.log.isDebugEnabled()) {
-                this.log.debug(conn + " I/O error: " + ex.getMessage(), ex);
-            }
+        } catch (RuntimeException ex) {
+            shutdownConnection(conn);
+            handler.failed(ex);
+            throw ex;
+        } catch (Exception ex) {
             shutdownConnection(conn);
             handler.failed(ex);
+            onException(ex);
         }
     }
 
     public void responseReceived(final NHttpClientConnection conn) {
-        HttpContext context = conn.getContext();
-        HttpExchange httpexchange = getHttpExchange(context);
-        HttpAsyncExchangeHandler<?> handler = getHandler(context);
-        if (this.log.isDebugEnabled()) {
-            this.log.debug(conn + " Response received");
-        }
+        HttpExchange httpexchange = getHttpExchange(conn);
+        HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
         try {
             HttpResponse response = conn.getHttpResponse();
             HttpRequest request = httpexchange.getRequest();
@@ -285,27 +224,23 @@ class NHttpClientProtocolHandler impleme
                 conn.resetInput();
                 processResponse(conn, httpexchange, handler);
             }
-        } catch (IOException ex) {
-            if (this.log.isDebugEnabled()) {
-                this.log.debug("I/O error: " + ex.getMessage(), ex);
-            }
+        } catch (RuntimeException ex) {
             shutdownConnection(conn);
             handler.failed(ex);
-        } catch (HttpException ex) {
-            if (this.log.isDebugEnabled()) {
-                this.log.debug("HTTP protocol exception: " + ex.getMessage(), ex);
-            }
-            closeConnection(conn);
+            throw ex;
+        } catch (Exception ex) {
+            shutdownConnection(conn);
             handler.failed(ex);
+            onException(ex);
         }
     }
 
     public void timeout(final NHttpClientConnection conn) {
-        HttpContext context = conn.getContext();
-        HttpExchange httpexchange = getHttpExchange(context);
-        HttpAsyncExchangeHandler<?> handler = getHandler(context);
-        if (this.log.isDebugEnabled()) {
-            this.log.debug(conn + " Timeout");
+        HttpExchange httpexchange = getHttpExchange(conn);
+        HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
+        if (handler == null) {
+            shutdownConnection(conn);
+            return;
         }
         try {
             if (httpexchange.getRequestState() == MessageState.ACK) {
@@ -326,49 +261,66 @@ class NHttpClientProtocolHandler impleme
                     conn.shutdown();
                 }
             }
-        } catch (IOException ex) {
-            if (this.log.isDebugEnabled()) {
-                this.log.debug("I/O error: " + ex.getMessage(), ex);
-            }
+        } catch (RuntimeException ex) {
             shutdownConnection(conn);
             handler.failed(ex);
+            throw ex;
+        } catch (Exception ex) {
+            shutdownConnection(conn);
+            handler.failed(ex);
+            onException(ex);
         }
     }
 
-    private HttpExchange getHttpExchange(final HttpContext context) {
-        return (HttpExchange) context.getAttribute(HTTP_EXCHNAGE);
+    protected void onException(final Exception ex) {
     }
 
-    private HttpAsyncExchangeHandler<?> getHandler(final HttpContext context) {
-        return (HttpAsyncExchangeHandler<?>) context.getAttribute(
-                DefaultAsyncRequestDirector.HTTP_EXCHANGE_HANDLER);
+    private void closeConnection(final NHttpConnection conn) {
+        try {
+            conn.close();
+        } catch (IOException ex) {
+            try {
+                conn.shutdown();
+            } catch (IOException ex2) {
+                onException(ex2);
+            }
+        }
+    }
+
+    private void shutdownConnection(final NHttpConnection conn) {
+        try {
+            conn.shutdown();
+        } catch (IOException ex) {
+            onException(ex);
+        }
+    }
+
+    private HttpExchange getHttpExchange(final NHttpConnection conn) {
+        return (HttpExchange) conn.getContext().getAttribute(HTTP_EXCHNAGE);
     }
 
     private void processResponse(
             final NHttpClientConnection conn,
             final HttpExchange httpexchange,
-            final HttpAsyncExchangeHandler<?> handler) throws IOException {
+            final HttpAsyncClientExchangeHandler<?> handler) throws IOException {
         if (!httpexchange.isValid()) {
             conn.close();
         }
+        HttpContext context = handler.getContext();
         HttpRequest request = httpexchange.getRequest();
         HttpResponse response = httpexchange.getResponse();
 
         String method = request.getRequestLine().getMethod();
         int status = response.getStatusLine().getStatusCode();
         if (method.equalsIgnoreCase("CONNECT") && status == HttpStatus.SC_OK) {
-            this.log.debug("CONNECT method succeeded");
             conn.resetInput();
         } else {
-            if (!handler.keepAlive(response)) {
-                this.log.debug("Connection cannot be kept alive");
+            ConnectionReuseStrategy connReuseStrategy = handler.getConnectionReuseStrategy();
+            if (!connReuseStrategy.keepAlive(response, context)) {
                 conn.close();
             }
         }
-        if (this.log.isDebugEnabled()) {
-            this.log.debug(conn + " Response processed");
-        }
-        handler.responseCompleted();
+        handler.responseCompleted(context);
         httpexchange.reset();
     }
 
@@ -389,4 +341,117 @@ class NHttpClientProtocolHandler impleme
             && status != HttpStatus.SC_RESET_CONTENT;
     }
 
+    class HttpExchange {
+
+        private volatile HttpAsyncClientExchangeHandler<?> handler;
+        private volatile MessageState requestState;
+        private volatile MessageState responseState;
+        private volatile HttpRequest request;
+        private volatile HttpResponse response;
+        private volatile boolean valid;
+        private volatile int timeout;
+
+        HttpExchange() {
+            super();
+            this.valid = true;
+            this.requestState = MessageState.READY;
+            this.responseState = MessageState.READY;
+        }
+
+        public HttpAsyncClientExchangeHandler<?> getHandler() {
+            return this.handler;
+        }
+
+        public void setHandler(final HttpAsyncClientExchangeHandler<?> handler) {
+            if (this.handler != null) {
+                throw new IllegalStateException("Handler already set");
+            }
+            this.handler = handler;
+        }
+
+        public MessageState getRequestState() {
+            return this.requestState;
+        }
+
+        public void setRequestState(final MessageState state) {
+            this.requestState = state;
+        }
+
+        public MessageState getResponseState() {
+            return this.responseState;
+        }
+
+        public void setResponseState(final MessageState state) {
+            this.responseState = state;
+        }
+
+        public HttpRequest getRequest() {
+            return this.request;
+        }
+
+        public void setRequest(final HttpRequest request) {
+            if (this.request != null) {
+                throw new IllegalStateException("Request already set");
+            }
+            this.request = request;
+        }
+
+        public HttpResponse getResponse() {
+            return this.response;
+        }
+
+        public void setResponse(final HttpResponse response) {
+            if (this.request != null) {
+                throw new IllegalStateException("Response already set");
+            }
+            this.response = response;
+        }
+
+        public int getTimeout() {
+            return this.timeout;
+        }
+
+        public void setTimeout(int timeout) {
+            this.timeout = timeout;
+        }
+
+        public void reset() {
+            this.responseState = MessageState.READY;
+            this.requestState = MessageState.READY;
+            this.handler = null;
+            this.response = null;
+            this.request = null;
+        }
+
+        public boolean isValid() {
+            return this.valid;
+        }
+
+        public void invalidate() {
+            this.valid = false;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder buf = new StringBuilder();
+            buf.append("request state: ");
+            buf.append(this.requestState);
+            buf.append("; request: ");
+            if (this.request != null) {
+                buf.append(this.request.getRequestLine());
+            }
+            buf.append("; response state: ");
+            buf.append(this.responseState);
+            buf.append("; response: ");
+            if (this.response != null) {
+                buf.append(this.response.getStatusLine());
+            }
+            buf.append("; valid: ");
+            buf.append(this.valid);
+            buf.append(";");
+            return buf.toString();
+        }
+
+    }
+
 }

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java
------------------------------------------------------------------------------
--- svn:mergeinfo (added)
+++ svn:mergeinfo Thu Sep  1 12:32:57 2011
@@ -0,0 +1 @@
+/httpcomponents/httpasyncclient/branches/conn-mgmt-redesign/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/NHttpClientProtocolHandler.java:1155312-1159070

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncRequestConsumer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncRequestConsumer.java?rev=1164047&r1=1164046&r2=1164047&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncRequestConsumer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncRequestConsumer.java Thu Sep  1 12:32:57 2011
@@ -49,4 +49,6 @@ public interface HttpAsyncRequestConsume
 
     T getResult();
 
+    boolean isDone();
+
 }

Modified: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncResponseConsumer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncResponseConsumer.java?rev=1164047&r1=1164046&r2=1164047&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncResponseConsumer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncResponseConsumer.java Thu Sep  1 12:32:57 2011
@@ -54,4 +54,6 @@ public interface HttpAsyncResponseConsum
 
     Exception getException();
 
+    boolean isDone();
+
 }

Copied: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/MessageState.java (from r1164042, httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/MessageState.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/MessageState.java?p2=httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/MessageState.java&p1=httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/MessageState.java&r1=1164042&r2=1164047&rev=1164047&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/MessageState.java (original)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/MessageState.java Thu Sep  1 12:32:57 2011
@@ -24,7 +24,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.http.impl.nio.client;
+package org.apache.http.nio.protocol;
 
 enum MessageState {
 

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/MessageState.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/MessageState.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/MessageState.java
------------------------------------------------------------------------------
--- svn:mergeinfo (added)
+++ svn:mergeinfo Thu Sep  1 12:32:57 2011
@@ -0,0 +1 @@
+/httpcomponents/httpasyncclient/branches/conn-mgmt-redesign/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/MessageState.java:1155312-1159070

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/MessageState.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/NullRequestConsumer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/NullRequestConsumer.java?rev=1164047&r1=1164046&r2=1164047&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/NullRequestConsumer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/NullRequestConsumer.java Thu Sep  1 12:32:57 2011
@@ -38,6 +38,7 @@ import org.apache.http.protocol.HttpCont
 class NullRequestConsumer implements HttpAsyncRequestConsumer<Object> {
 
     private final ByteBuffer buffer;
+    private volatile boolean completed;
 
     NullRequestConsumer() {
         super();
@@ -57,13 +58,15 @@ class NullRequestConsumer implements Htt
     }
 
     public void requestCompleted(final HttpContext context) {
+        this.completed = true;
     }
 
     public void failed(final Exception ex) {
+        this.completed = true;
     }
 
     public Object getResult() {
-        return Boolean.TRUE;
+        return this.completed;
     }
 
     public Exception getException() {
@@ -71,6 +74,11 @@ class NullRequestConsumer implements Htt
     }
 
     public void close() throws IOException {
+        this.completed = true;
+    }
+
+    public boolean isDone() {
+        return this.completed;
     }
 
 }
\ No newline at end of file