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 2008/02/24 20:16:33 UTC

svn commit: r630660 - in /httpcomponents/httpcore/branches/limewire_contrib/module-nio/src: main/java/org/apache/http/nio/protocol/ test/java/org/apache/http/nio/protocol/

Author: olegk
Date: Sun Feb 24 11:16:27 2008
New Revision: 630660

URL: http://svn.apache.org/viewvc?rev=630660&view=rev
Log:
HTTPCORE-148: 

* Improved asynchronous client side HTTP protocol handler

Contributed by Sam Berlin <sberlin at gmail.com>
Reviewed by Oleg Kalnichevski

Added:
    httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AbstractNHttpClientHandler.java   (with props)
    httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpClientHandler.java   (with props)
    httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestExecutionHandler.java   (with props)
Modified:
    httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpClientHandlerBase.java
    httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/test/java/org/apache/http/nio/protocol/TestAsyncNHttpHandlers.java

Added: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AbstractNHttpClientHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AbstractNHttpClientHandler.java?rev=630660&view=auto
==============================================================================
--- httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AbstractNHttpClientHandler.java (added)
+++ httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AbstractNHttpClientHandler.java Sun Feb 24 11:16:27 2008
@@ -0,0 +1,75 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ * 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.nio.NHttpClientConnection;
+import org.apache.http.nio.NHttpClientHandler;
+import org.apache.http.nio.util.ByteBufferAllocator;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpProcessor;
+
+public abstract class AbstractNHttpClientHandler extends NHttpHandlerBase
+                                             implements NHttpClientHandler {
+
+    public AbstractNHttpClientHandler(
+            final HttpProcessor httpProcessor,
+            final ConnectionReuseStrategy connStrategy,
+            final ByteBufferAllocator allocator,
+            final HttpParams params) {
+        super(httpProcessor, connStrategy, allocator, params);
+    }
+
+    public void closed(final NHttpClientConnection conn) {
+        if (this.eventListener != null) {
+            this.eventListener.connectionClosed(conn);
+        }
+    }
+
+    public void exception(final NHttpClientConnection conn, final HttpException ex) {
+        closeConnection(conn, ex);
+        if (this.eventListener != null) {
+            this.eventListener.fatalProtocolException(ex, conn);
+        }
+    }
+
+    public void exception(final NHttpClientConnection conn, final IOException ex) {
+        shutdownConnection(conn, ex);
+        if (this.eventListener != null) {
+            this.eventListener.fatalIOException(ex, conn);
+        }
+    }
+
+}

Propchange: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AbstractNHttpClientHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AbstractNHttpClientHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AbstractNHttpClientHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpClientHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpClientHandler.java?rev=630660&view=auto
==============================================================================
--- httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpClientHandler.java (added)
+++ httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpClientHandler.java Sun Feb 24 11:16:27 2008
@@ -0,0 +1,448 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ * 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.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.nio.ContentDecoder;
+import org.apache.http.nio.ContentEncoder;
+import org.apache.http.nio.NHttpClientConnection;
+import org.apache.http.nio.entity.ConsumingNHttpEntity;
+import org.apache.http.nio.entity.ConsumingNHttpEntityTemplate;
+import org.apache.http.nio.entity.ProducingNHttpEntity;
+import org.apache.http.nio.entity.SkipContentListener;
+import org.apache.http.nio.util.ByteBufferAllocator;
+import org.apache.http.nio.util.HeapByteBufferAllocator;
+import org.apache.http.params.CoreProtocolPNames;
+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;
+
+/**
+ * HTTP client handler implementation that asynchronously reads & writes out the
+ * content of messages.
+ *
+ * @see ConsumingNHttpEntity
+ * @see ProducingNHttpEntity
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:sberlin at gmail.com">Sam Berlin</a>
+ *
+ */
+public class AsyncNHttpClientHandler extends AbstractNHttpClientHandler {
+
+    protected NHttpRequestExecutionHandler execHandler;
+
+    public AsyncNHttpClientHandler(
+            final HttpProcessor httpProcessor,
+            final NHttpRequestExecutionHandler execHandler,
+            final ConnectionReuseStrategy connStrategy,
+            final ByteBufferAllocator allocator,
+            final HttpParams params) {
+        super(httpProcessor, connStrategy, allocator, params);
+        if (execHandler == null) {
+            throw new IllegalArgumentException("HTTP request execution handler may not be null.");
+        }
+        this.execHandler = execHandler;
+    }
+
+    public AsyncNHttpClientHandler(
+            final HttpProcessor httpProcessor,
+            final NHttpRequestExecutionHandler execHandler,
+            final ConnectionReuseStrategy connStrategy,
+            final HttpParams params) {
+        this(httpProcessor, execHandler, connStrategy,
+                new HeapByteBufferAllocator(), params);
+    }
+
+    public void connected(final NHttpClientConnection conn, final Object attachment) {
+        HttpContext context = conn.getContext();
+
+        initialize(conn, attachment);
+
+        ClientConnState connState = new ClientConnState();
+        context.setAttribute(CONN_STATE, connState);
+
+        if (this.eventListener != null) {
+            this.eventListener.connectionOpen(conn);
+        }
+
+        requestReady(conn);
+    }
+
+    @Override
+    public void closed(final NHttpClientConnection conn) {
+        HttpContext context = conn.getContext();
+
+        ClientConnState connState = (ClientConnState) context.getAttribute(CONN_STATE);
+        connState.reset();
+
+        this.execHandler.finalizeContext(context);
+
+        if (this.eventListener != null) {
+            this.eventListener.connectionClosed(conn);
+        }
+    }
+
+    public void requestReady(final NHttpClientConnection conn) {
+        HttpContext context = conn.getContext();
+
+        ClientConnState connState = (ClientConnState) context.getAttribute(CONN_STATE);
+        if (connState.getOutputState() != ClientConnState.READY) {
+            return;
+        }
+
+        try {
+
+            HttpRequest request = this.execHandler.submitRequest(context);
+            if (request == null) {
+                return;
+            }
+
+            request.setParams(
+                    new DefaultedHttpParams(request.getParams(), this.params));
+
+            context.setAttribute(ExecutionContext.HTTP_REQUEST, request);
+            this.httpProcessor.process(request, context);
+            connState.setRequest(request);
+            conn.submitRequest(request);
+            connState.setOutputState(ClientConnState.REQUEST_SENT);
+
+            if (request instanceof HttpEntityEnclosingRequest) {
+                HttpEntityEnclosingRequest entityReq = (HttpEntityEnclosingRequest)request;
+                ProducingNHttpEntity entity = (ProducingNHttpEntity)entityReq.getEntity();
+                connState.setProducingEntity(entity);
+
+                if (entityReq.expectContinue()) {
+                    int timeout = conn.getSocketTimeout();
+                    connState.setTimeout(timeout);
+                    timeout = this.params.getIntParameter(
+                            CoreProtocolPNames.WAIT_FOR_CONTINUE, 3000);
+                    conn.setSocketTimeout(timeout);
+                    connState.setOutputState(ClientConnState.EXPECT_CONTINUE);
+                }
+            }
+
+        } catch (IOException ex) {
+            shutdownConnection(conn, ex);
+            if (this.eventListener != null) {
+                this.eventListener.fatalIOException(ex, conn);
+            }
+        } catch (HttpException ex) {
+            closeConnection(conn, ex);
+            if (this.eventListener != null) {
+                this.eventListener.fatalProtocolException(ex, conn);
+            }
+        }
+    }
+
+    public void inputReady(final NHttpClientConnection conn, final ContentDecoder decoder) {
+        HttpContext context = conn.getContext();
+
+        ClientConnState connState = (ClientConnState) context.getAttribute(CONN_STATE);
+
+        ConsumingNHttpEntity consumingEntity = connState.getConsumingEntity();
+
+        try {
+            consumingEntity.consumeContent(decoder, conn);
+            if (decoder.isCompleted()) {
+                processResponse(conn, connState);
+            }
+
+        } catch (IOException ex) {
+            shutdownConnection(conn, ex);
+            if (this.eventListener != null) {
+                this.eventListener.fatalIOException(ex, conn);
+            }
+        } catch (HttpException ex) {
+            closeConnection(conn, ex);
+            if (this.eventListener != null) {
+                this.eventListener.fatalProtocolException(ex, conn);
+            }
+        }
+    }
+
+    public void outputReady(final NHttpClientConnection conn, final ContentEncoder encoder) {
+        HttpContext context = conn.getContext();
+        ClientConnState connState = (ClientConnState) context.getAttribute(CONN_STATE);
+
+        try {
+            if (connState.getOutputState() == ClientConnState.EXPECT_CONTINUE) {
+                conn.suspendOutput();
+                return;
+            }
+
+            ProducingNHttpEntity entity = connState.getProducingEntity();
+
+            entity.produceContent(encoder, conn);
+        } catch (IOException ex) {
+            shutdownConnection(conn, ex);
+            if (this.eventListener != null) {
+                this.eventListener.fatalIOException(ex, conn);
+            }
+        }
+    }
+
+    public void responseReceived(final NHttpClientConnection conn) {
+        HttpContext context = conn.getContext();
+        ClientConnState connState = (ClientConnState) context.getAttribute(CONN_STATE);
+
+        HttpResponse response = conn.getHttpResponse();
+        response.setParams(
+                new DefaultedHttpParams(response.getParams(), this.params));
+
+        HttpRequest request = connState.getRequest();
+        try {
+
+            int statusCode = response.getStatusLine().getStatusCode();
+            if (statusCode < HttpStatus.SC_OK) {
+                // 1xx intermediate response
+                if (statusCode == HttpStatus.SC_CONTINUE
+                        && connState.getOutputState() == ClientConnState.EXPECT_CONTINUE) {
+                    continueRequest(conn, connState);
+                }
+                return;
+            } else {
+                connState.setResponse(response);
+
+                if (connState.getOutputState() == ClientConnState.EXPECT_CONTINUE) {
+                    cancelRequest(conn, connState);
+                }
+            }
+            if (!canResponseHaveBody(request, response)) {
+                conn.resetInput();
+                response.setEntity(null);
+                processResponse(conn, connState);
+            } else {
+                HttpEntity entity = response.getEntity();
+                if (entity != null) {
+                    ConsumingNHttpEntity consumingEntity = this.execHandler.responseEntity(
+                            response, context);
+                    if (consumingEntity == null) {
+                        consumingEntity = new ConsumingNHttpEntityTemplate(
+                                entity, new SkipContentListener(this.allocator));
+                    }
+                    response.setEntity(consumingEntity);
+                    connState.setConsumingEntity(consumingEntity);
+                }
+            }
+
+
+        } catch (IOException ex) {
+            shutdownConnection(conn, ex);
+            if (this.eventListener != null) {
+                this.eventListener.fatalIOException(ex, conn);
+            }
+        } catch (HttpException ex) {
+            closeConnection(conn, ex);
+            if (this.eventListener != null) {
+                this.eventListener.fatalProtocolException(ex, conn);
+            }
+        }
+    }
+
+    public void timeout(final NHttpClientConnection conn) {
+        HttpContext context = conn.getContext();
+        ClientConnState connState = (ClientConnState) context.getAttribute(CONN_STATE);
+
+        try {
+
+            if (connState.getOutputState() == ClientConnState.EXPECT_CONTINUE) {
+                continueRequest(conn, connState);
+                return;
+            }
+
+        } catch (IOException ex) {
+            shutdownConnection(conn, ex);
+            if (this.eventListener != null) {
+                this.eventListener.fatalIOException(ex, conn);
+            }
+        }
+
+        handleTimeout(conn);
+    }
+
+    private void initialize(
+            final NHttpClientConnection conn,
+            final Object attachment) {
+        HttpContext context = conn.getContext();
+
+        context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
+        this.execHandler.initalizeContext(context, attachment);
+    }
+
+    private void continueRequest(
+            final NHttpClientConnection conn,
+            final ClientConnState connState) throws IOException {
+
+        int timeout = connState.getTimeout();
+        conn.setSocketTimeout(timeout);
+
+        conn.requestOutput();
+        connState.setOutputState(ClientConnState.REQUEST_SENT);
+    }
+
+    private void cancelRequest(
+            final NHttpClientConnection conn,
+            final ClientConnState connState) throws IOException {
+
+        int timeout = connState.getTimeout();
+        conn.setSocketTimeout(timeout);
+
+        conn.resetOutput();
+        connState.resetOutput();
+    }
+
+    private void processResponse(
+            final NHttpClientConnection conn,
+            final ClientConnState connState) throws IOException, HttpException {
+
+        HttpContext context = conn.getContext();
+        HttpResponse response = connState.getResponse();
+
+        context.setAttribute(ExecutionContext.HTTP_RESPONSE, response);
+
+        this.httpProcessor.process(response, context);
+
+        this.execHandler.handleResponse(response, context);
+
+        if (!this.connStrategy.keepAlive(response, context)) {
+            conn.close();
+        } else {
+            // Ready for another request
+            connState.resetInput();
+            connState.resetOutput();
+            conn.requestOutput();
+        }
+    }
+
+    protected static class ClientConnState {
+
+        public static final int READY                      = 0;
+        public static final int REQUEST_SENT               = 1;
+        public static final int EXPECT_CONTINUE            = 2;
+        public static final int REQUEST_BODY_STREAM        = 4;
+        public static final int REQUEST_BODY_DONE          = 8;
+        public static final int RESPONSE_RECEIVED          = 16;
+        public static final int RESPONSE_BODY_STREAM       = 32;
+        public static final int RESPONSE_BODY_DONE         = 64;
+
+        private int outputState;
+
+        private HttpRequest request;
+        private HttpResponse response;
+        private ConsumingNHttpEntity consumingEntity;
+        private ProducingNHttpEntity producingEntity;
+
+        private int timeout;
+
+        public void setConsumingEntity(final ConsumingNHttpEntity consumingEntity) {
+            this.consumingEntity = consumingEntity;
+        }
+
+        public void setProducingEntity(final ProducingNHttpEntity producingEntity) {
+            this.producingEntity = producingEntity;
+        }
+
+        public ProducingNHttpEntity getProducingEntity() {
+            return producingEntity;
+        }
+
+        public ConsumingNHttpEntity getConsumingEntity() {
+            return consumingEntity;
+        }
+
+        public int getOutputState() {
+            return this.outputState;
+        }
+
+        public void setOutputState(int outputState) {
+            this.outputState = outputState;
+        }
+
+        public HttpRequest getRequest() {
+            return this.request;
+        }
+
+        public void setRequest(final HttpRequest request) {
+            this.request = request;
+        }
+
+        public HttpResponse getResponse() {
+            return this.response;
+        }
+
+        public void setResponse(final HttpResponse response) {
+            this.response = response;
+        }
+
+        public int getTimeout() {
+            return this.timeout;
+        }
+
+        public void setTimeout(int timeout) {
+            this.timeout = timeout;
+        }
+
+        public void resetInput() {
+            this.response = null;
+            if (this.consumingEntity != null) {
+                this.consumingEntity.finish();
+                this.consumingEntity = null;
+            }
+        }
+
+        public void resetOutput() {
+            this.request = null;
+            if (this.producingEntity != null) {
+                this.producingEntity.finish();
+                this.producingEntity = null;
+            }
+            this.outputState = READY;
+        }
+
+        public void reset() {
+            resetInput();
+            resetOutput();
+        }
+    }
+
+}

Propchange: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpClientHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpClientHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpClientHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpClientHandlerBase.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpClientHandlerBase.java?rev=630660&r1=630659&r2=630660&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpClientHandlerBase.java (original)
+++ httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpClientHandlerBase.java Sun Feb 24 11:16:27 2008
@@ -36,18 +36,16 @@
 import org.apache.http.ConnectionReuseStrategy;
 import org.apache.http.HttpException;
 import org.apache.http.nio.NHttpClientConnection;
-import org.apache.http.nio.NHttpClientHandler;
 import org.apache.http.nio.util.ByteBufferAllocator;
 import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HttpProcessor;
 
-public abstract class NHttpClientHandlerBase extends NHttpHandlerBase 
-                                             implements NHttpClientHandler {
+public abstract class NHttpClientHandlerBase extends AbstractNHttpClientHandler {
 
     protected HttpRequestExecutionHandler execHandler;
-    
+
     public NHttpClientHandlerBase(
-            final HttpProcessor httpProcessor, 
+            final HttpProcessor httpProcessor,
             final HttpRequestExecutionHandler execHandler,
             final ConnectionReuseStrategy connStrategy,
             final ByteBufferAllocator allocator,
@@ -58,7 +56,7 @@
         }
         this.execHandler = execHandler;
     }
-    
+
     public void closed(final NHttpClientConnection conn) {
         if (this.eventListener != null) {
             this.eventListener.connectionClosed(conn);
@@ -78,5 +76,5 @@
             this.eventListener.fatalIOException(ex, conn);
         }
     }
-    
+
 }

Added: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestExecutionHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestExecutionHandler.java?rev=630660&view=auto
==============================================================================
--- httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestExecutionHandler.java (added)
+++ httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestExecutionHandler.java Sun Feb 24 11:16:27 2008
@@ -0,0 +1,130 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ * 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.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.nio.entity.ConsumingNHttpEntity;
+import org.apache.http.nio.entity.ProducingNHttpEntity;
+import org.apache.http.nio.reactor.ConnectingIOReactor;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * HTTP request execution handler can be used by client-side protocol handlers
+ * to trigger the submission of a new HTTP request and the processing of an HTTP
+ * response. When a new response entity is available for consumption,
+ * {@link #responseEntity(HttpRequest, HttpResponse, HttpContext)} is called.
+ * After the {@link ConsumingNHttpEntity} consumes the response body,
+ * {@link #handleResponse(HttpResponse, HttpContext)} is notified that the
+ * response is fully read.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ */
+public interface NHttpRequestExecutionHandler {
+
+    /**
+     * Triggered when a new connection has been established and the
+     * HTTP context needs to be initialized.
+     *
+     * <p>The attachment object is the same object which was passed
+     * to the connecting I/O reactor when the connection request was
+     * made. The attachment may optionally contain some state information
+     * required in order to correctly initalize the HTTP context.
+     *
+     * @see ConnectingIOReactor#connect
+     *
+     * @param context the actual HTTP context
+     * @param attachment the object passed to the connecting I/O reactor
+     *   upon the request for a new connection.
+     */
+    void initalizeContext(HttpContext context, Object attachment);
+
+    /**
+     * Triggered when the underlying connection is ready to send a new
+     * HTTP request to the target host. This method may return
+     * <code>null</null> if the client is not yet ready to send a
+     * request. In this case the connection will remain open and
+     * can be activated at a later point.
+     * <p>
+     * If the request has an entity, the entity <b>must</b> be an
+     * instance of {@link ProducingNHttpEntity}.
+     *
+     * @param context the actual HTTP context
+     * @return an HTTP request to be sent or <code>null</null> if no
+     *   request needs to be sent
+     */
+    HttpRequest submitRequest(HttpContext context);
+
+    /**
+     * Triggered when a response is received with an entity. This method should
+     * return a {@link ConsumingNHttpEntity} that will be used to consume the
+     * entity. <code>null</code> is a valid response value, and will indicate
+     * that the entity should be silently ignored.
+     * <p>
+     * After the entity is fully consumed,
+     * {@link NHttpRequestExecutionHandler#handleResponse(HttpResponse, HttpContext)}
+     * is called to notify a full response & entity are ready to be processed.
+     *
+     * @param response
+     *            The response containing the existing entity.
+     * @param context
+     *            the actual HTTP context
+     * @return An entity that will asynchronously consume the response's content
+     *         body.
+     */
+    ConsumingNHttpEntity responseEntity(HttpResponse response, HttpContext context)
+        throws IOException;
+
+    /**
+     * Triggered when an HTTP response is ready to be processed.
+     *
+     * @param response
+     *            the HTTP response to be processed
+     * @param context
+     *            the actual HTTP context
+     */
+    void handleResponse(HttpResponse response, HttpContext context)
+        throws IOException;
+
+    /**
+     * Triggered when the connection is terminated. This event can be used
+     * to release objects stored in the context or perform some other kind
+     * of cleanup.
+     *
+     * @param context the actual HTTP context
+     */
+    void finalizeContext(HttpContext context);
+
+}

Propchange: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestExecutionHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestExecutionHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestExecutionHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/test/java/org/apache/http/nio/protocol/TestAsyncNHttpHandlers.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/test/java/org/apache/http/nio/protocol/TestAsyncNHttpHandlers.java?rev=630660&r1=630659&r2=630660&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/test/java/org/apache/http/nio/protocol/TestAsyncNHttpHandlers.java (original)
+++ httpcomponents/httpcore/branches/limewire_contrib/module-nio/src/test/java/org/apache/http/nio/protocol/TestAsyncNHttpHandlers.java Sun Feb 24 11:16:27 2008
@@ -50,7 +50,6 @@
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
 import org.apache.http.HttpVersion;
-import org.apache.http.entity.ByteArrayEntity;
 import org.apache.http.impl.DefaultConnectionReuseStrategy;
 import org.apache.http.impl.DefaultHttpResponseFactory;
 import org.apache.http.message.BasicHttpEntityEnclosingRequest;
@@ -202,7 +201,7 @@
     }
 
     private NHttpClientHandler createHttpClientHandler(
-            final HttpRequestExecutionHandler requestExecutionHandler) {
+            final NHttpRequestExecutionHandler requestExecutionHandler) {
         BasicHttpProcessor httpproc = new BasicHttpProcessor();
         httpproc.addInterceptor(new RequestContent());
         httpproc.addInterceptor(new RequestTargetHost());
@@ -210,7 +209,7 @@
         httpproc.addInterceptor(new RequestUserAgent());
         httpproc.addInterceptor(new RequestExpectContinue());
 
-        BufferingHttpClientHandler clientHandler = new BufferingHttpClientHandler(
+        AsyncNHttpClientHandler clientHandler = new AsyncNHttpClientHandler(
                 httpproc,
                 requestExecutionHandler,
                 new DefaultConnectionReuseStrategy(),
@@ -240,13 +239,15 @@
         NHttpRequestHandler requestHandler = new SimpleNHttpRequestHandler() {
 
             public ConsumingNHttpEntity entityRequest(
-                    HttpEntityEnclosingRequest request, HttpContext context) {
+                    final HttpEntityEnclosingRequest request,
+                    final HttpContext context) {
                 return null;
             }
 
             public void handle(
-                    HttpRequest request, HttpResponse response, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpRequest request,
+                    final HttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
                 String s = request.getRequestLine().getUri();
                 URI uri;
                 try {
@@ -262,7 +263,7 @@
 
         };
 
-        HttpRequestExecutionHandler requestExecutionHandler = new HttpRequestExecutionHandler() {
+        NHttpRequestExecutionHandler requestExecutionHandler = new NHttpRequestExecutionHandler() {
 
             public void initalizeContext(final HttpContext context, final Object attachment) {
                 context.setAttribute("LIST", (ByteSequence) attachment);
@@ -283,6 +284,13 @@
                 return get;
             }
 
+            public ConsumingNHttpEntity responseEntity(
+                    final HttpResponse response,
+                    final HttpContext context) throws IOException {
+                return new BufferingNHttpEntity(response.getEntity(),
+                        new HeapByteBufferAllocator());
+            }
+
             public void handleResponse(final HttpResponse response, final HttpContext context) {
                 NHttpConnection conn = (NHttpConnection) context.getAttribute(
                         ExecutionContext.HTTP_CONNECTION);
@@ -373,16 +381,17 @@
         NHttpRequestHandler requestHandler = new SimpleNHttpRequestHandler() {
 
             public ConsumingNHttpEntity entityRequest(
-                    HttpEntityEnclosingRequest request, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpEntityEnclosingRequest request,
+                    final HttpContext context) throws HttpException, IOException {
                 return new BufferingNHttpEntity(
                         request.getEntity(),
                         new HeapByteBufferAllocator());
             }
 
             public void handle(
-                    HttpRequest request, HttpResponse response, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpRequest request,
+                    final HttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
                 if (request instanceof HttpEntityEnclosingRequest) {
                     HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
                     byte[] b = EntityUtils.toByteArray(entity);
@@ -394,7 +403,7 @@
             }
         };
 
-        HttpRequestExecutionHandler requestExecutionHandler = new HttpRequestExecutionHandler() {
+        NHttpRequestExecutionHandler requestExecutionHandler = new NHttpRequestExecutionHandler() {
 
             public void initalizeContext(final HttpContext context, final Object attachment) {
                 context.setAttribute("LIST", (ByteSequence) attachment);
@@ -405,6 +414,13 @@
             public void finalizeContext(final HttpContext context) {
             }
 
+            public ConsumingNHttpEntity responseEntity(
+                    final HttpResponse response,
+                    final HttpContext context) throws IOException {
+                return new BufferingNHttpEntity(response.getEntity(),
+                        new HeapByteBufferAllocator());
+            }
+
             public HttpRequest submitRequest(final HttpContext context) {
                 int i = ((Integer) context.getAttribute("REQ-COUNT")).intValue();
                 BasicHttpEntityEnclosingRequest post = null;
@@ -412,7 +428,7 @@
                     post = new BasicHttpEntityEnclosingRequest("POST", "/?" + i);
 
                     byte[] data = requestData.getBytes(i);
-                    ByteArrayEntity outgoing = new ByteArrayEntity(data);
+                    NByteArrayEntity outgoing = new NByteArrayEntity(data);
                     post.setEntity(outgoing);
 
                     context.setAttribute("REQ-COUNT", new Integer(i + 1));
@@ -510,16 +526,17 @@
         NHttpRequestHandler requestHandler = new SimpleNHttpRequestHandler() {
 
             public ConsumingNHttpEntity entityRequest(
-                    HttpEntityEnclosingRequest request, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpEntityEnclosingRequest request,
+                    final HttpContext context) throws HttpException, IOException {
                 return new BufferingNHttpEntity(
                         request.getEntity(),
                         new HeapByteBufferAllocator());
             }
 
             public void handle(
-                    HttpRequest request, HttpResponse response, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpRequest request,
+                    final HttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
                 if (request instanceof HttpEntityEnclosingRequest) {
                     HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
                     byte[] b = EntityUtils.toByteArray(entity);
@@ -533,7 +550,7 @@
             }
         };
 
-        HttpRequestExecutionHandler requestExecutionHandler = new HttpRequestExecutionHandler() {
+        NHttpRequestExecutionHandler requestExecutionHandler = new NHttpRequestExecutionHandler() {
 
             public void initalizeContext(final HttpContext context, final Object attachment) {
                 context.setAttribute("LIST", (ByteSequence) attachment);
@@ -544,13 +561,20 @@
             public void finalizeContext(final HttpContext context) {
             }
 
+            public ConsumingNHttpEntity responseEntity(
+                    final HttpResponse response,
+                    final HttpContext context) throws IOException {
+                return new BufferingNHttpEntity(response.getEntity(),
+                        new HeapByteBufferAllocator());
+            }
+
             public HttpRequest submitRequest(final HttpContext context) {
                 int i = ((Integer) context.getAttribute("REQ-COUNT")).intValue();
                 BasicHttpEntityEnclosingRequest post = null;
                 if (i < reqNo) {
                     post = new BasicHttpEntityEnclosingRequest("POST", "/?" + i);
                     byte[] data = requestData.getBytes(i);
-                    ByteArrayEntity outgoing = new ByteArrayEntity(data);
+                    NByteArrayEntity outgoing = new NByteArrayEntity(data);
                     outgoing.setChunked(true);
                     post.setEntity(outgoing);
 
@@ -652,16 +676,17 @@
         NHttpRequestHandler requestHandler = new SimpleNHttpRequestHandler() {
 
             public ConsumingNHttpEntity entityRequest(
-                    HttpEntityEnclosingRequest request, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpEntityEnclosingRequest request,
+                    final HttpContext context) throws HttpException, IOException {
                 return new BufferingNHttpEntity(
                         request.getEntity(),
                         new HeapByteBufferAllocator());
             }
 
             public void handle(
-                    HttpRequest request, HttpResponse response, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpRequest request,
+                    final HttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
                 if (request instanceof HttpEntityEnclosingRequest) {
                     HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
                     byte[] b = EntityUtils.toByteArray(entity);
@@ -679,7 +704,7 @@
         this.client.getParams().setParameter(
                 CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_0);
 
-        HttpRequestExecutionHandler requestExecutionHandler = new HttpRequestExecutionHandler() {
+        NHttpRequestExecutionHandler requestExecutionHandler = new NHttpRequestExecutionHandler() {
 
             public void initalizeContext(final HttpContext context, final Object attachment) {
                 context.setAttribute("LIST", (ByteSequence) attachment);
@@ -690,13 +715,20 @@
             public void finalizeContext(final HttpContext context) {
             }
 
+            public ConsumingNHttpEntity responseEntity(
+                    final HttpResponse response,
+                    final HttpContext context) throws IOException {
+                return new BufferingNHttpEntity(response.getEntity(),
+                        new HeapByteBufferAllocator());
+            }
+
             public HttpRequest submitRequest(final HttpContext context) {
                 int i = ((Integer) context.getAttribute("REQ-COUNT")).intValue();
                 BasicHttpEntityEnclosingRequest post = null;
                 if (i < reqNo) {
                     post = new BasicHttpEntityEnclosingRequest("POST", "/?" + i);
                     byte[] data = requestData.getBytes(i);
-                    ByteArrayEntity outgoing = new ByteArrayEntity(data);
+                    NByteArrayEntity outgoing = new NByteArrayEntity(data);
                     post.setEntity(outgoing);
 
                     context.setAttribute("REQ-COUNT", new Integer(i + 1));
@@ -794,16 +826,17 @@
         NHttpRequestHandler requestHandler = new SimpleNHttpRequestHandler() {
 
             public ConsumingNHttpEntity entityRequest(
-                    HttpEntityEnclosingRequest request, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpEntityEnclosingRequest request,
+                    final HttpContext context) throws HttpException, IOException {
                 return new BufferingNHttpEntity(
                         request.getEntity(),
                         new HeapByteBufferAllocator());
             }
 
             public void handle(
-                    HttpRequest request, HttpResponse response, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpRequest request,
+                    final HttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
                 if (request instanceof HttpEntityEnclosingRequest) {
                     HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
                     byte[] b = EntityUtils.toByteArray(entity);
@@ -820,7 +853,7 @@
         // Activate 'expect: continue' handshake
         this.client.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, true);
 
-        HttpRequestExecutionHandler requestExecutionHandler = new HttpRequestExecutionHandler() {
+        NHttpRequestExecutionHandler requestExecutionHandler = new NHttpRequestExecutionHandler() {
 
             public void initalizeContext(final HttpContext context, final Object attachment) {
                 context.setAttribute("LIST", (ByteSequence) attachment);
@@ -831,13 +864,20 @@
             public void finalizeContext(final HttpContext context) {
             }
 
+            public ConsumingNHttpEntity responseEntity(
+                    final HttpResponse response,
+                    final HttpContext context) throws IOException {
+                return new BufferingNHttpEntity(response.getEntity(),
+                        new HeapByteBufferAllocator());
+            }
+
             public HttpRequest submitRequest(final HttpContext context) {
                 int i = ((Integer) context.getAttribute("REQ-COUNT")).intValue();
                 BasicHttpEntityEnclosingRequest post = null;
                 if (i < reqNo) {
                     post = new BasicHttpEntityEnclosingRequest("POST", "/?" + i);
                     byte[] data = requestData.getBytes(i);
-                    ByteArrayEntity outgoing = new ByteArrayEntity(data);
+                    NByteArrayEntity outgoing = new NByteArrayEntity(data);
                     outgoing.setChunked(true);
                     post.setEntity(outgoing);
 
@@ -929,16 +969,17 @@
         NHttpRequestHandler requestHandler = new SimpleNHttpRequestHandler() {
 
             public ConsumingNHttpEntity entityRequest(
-                    HttpEntityEnclosingRequest request, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpEntityEnclosingRequest request,
+                    final HttpContext context) throws HttpException, IOException {
                 return new BufferingNHttpEntity(
                         request.getEntity(),
                         new HeapByteBufferAllocator());
             }
 
             public void handle(
-                    HttpRequest request, HttpResponse response, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpRequest request,
+                    final HttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
                 NStringEntity outgoing = new NStringEntity("No content");
                 response.setEntity(outgoing);
             }
@@ -973,7 +1014,7 @@
         // Activate 'expect: continue' handshake
         this.client.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, true);
 
-        HttpRequestExecutionHandler requestExecutionHandler = new HttpRequestExecutionHandler() {
+        NHttpRequestExecutionHandler requestExecutionHandler = new NHttpRequestExecutionHandler() {
 
             public void initalizeContext(final HttpContext context, final Object attachment) {
                 context.setAttribute("LIST", (ResponseSequence) attachment);
@@ -984,13 +1025,20 @@
             public void finalizeContext(final HttpContext context) {
             }
 
+            public ConsumingNHttpEntity responseEntity(
+                    final HttpResponse response,
+                    final HttpContext context) throws IOException {
+                return new BufferingNHttpEntity(response.getEntity(),
+                        new HeapByteBufferAllocator());
+            }
+
             public HttpRequest submitRequest(final HttpContext context) {
                 int i = ((Integer) context.getAttribute("REQ-COUNT")).intValue();
                 BasicHttpEntityEnclosingRequest post = null;
                 if (i < reqNo) {
                     post = new BasicHttpEntityEnclosingRequest("POST", "/");
                     post.addHeader("Secret", Integer.toString(i));
-                    ByteArrayEntity outgoing = new ByteArrayEntity(
+                    NByteArrayEntity outgoing = new NByteArrayEntity(
                             EncodingUtils.getAsciiBytes("No content"));
                     post.setEntity(outgoing);
 
@@ -1011,7 +1059,7 @@
                 HttpEntity entity = response.getEntity();
                 if (entity != null) {
                     try {
-                        entity.consumeContent();
+                        EntityUtils.toByteArray(entity);
                     } catch (IOException ex) {
                         requestCount.abort();
                         return;
@@ -1087,16 +1135,17 @@
         NHttpRequestHandler requestHandler = new SimpleNHttpRequestHandler() {
 
             public ConsumingNHttpEntity entityRequest(
-                    HttpEntityEnclosingRequest request, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpEntityEnclosingRequest request,
+                    final HttpContext context) throws HttpException, IOException {
                 return new BufferingNHttpEntity(
                         request.getEntity(),
                         new HeapByteBufferAllocator());
             }
 
             public void handle(
-                    HttpRequest request, HttpResponse response, HttpContext context)
-                    throws HttpException, IOException {
+                    final HttpRequest request,
+                    final HttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
                 String s = request.getRequestLine().getUri();
                 URI uri;
                 try {
@@ -1112,7 +1161,7 @@
 
         };
 
-        HttpRequestExecutionHandler requestExecutionHandler = new HttpRequestExecutionHandler() {
+        NHttpRequestExecutionHandler requestExecutionHandler = new NHttpRequestExecutionHandler() {
 
             public void initalizeContext(final HttpContext context, final Object attachment) {
                 context.setAttribute("LIST", (ResponseSequence) attachment);
@@ -1121,6 +1170,13 @@
             }
 
             public void finalizeContext(final HttpContext context) {
+            }
+
+            public ConsumingNHttpEntity responseEntity(
+                    final HttpResponse response,
+                    final HttpContext context) throws IOException {
+                return new BufferingNHttpEntity(response.getEntity(),
+                        new HeapByteBufferAllocator());
             }
 
             public HttpRequest submitRequest(final HttpContext context) {