View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.http.nio.protocol;
29  
30  import java.io.IOException;
31  import java.util.concurrent.Future;
32  
33  import org.apache.http.ConnectionReuseStrategy;
34  import org.apache.http.HttpException;
35  import org.apache.http.HttpHost;
36  import org.apache.http.HttpRequest;
37  import org.apache.http.HttpResponse;
38  import org.apache.http.concurrent.BasicFuture;
39  import org.apache.http.concurrent.FutureCallback;
40  import org.apache.http.nio.ContentDecoder;
41  import org.apache.http.nio.ContentEncoder;
42  import org.apache.http.nio.IOControl;
43  import org.apache.http.params.DefaultedHttpParams;
44  import org.apache.http.params.HttpParams;
45  import org.apache.http.protocol.HttpContext;
46  import org.apache.http.protocol.HttpProcessor;
47  
48  /**
49   * Basic implementation of {@link HttpAsyncRequestExecutionHandler} that executes
50   * a single HTTP request / response exchange.
51   *
52   * @param <T> the result type of request execution.
53   * @since 4.2
54   */
55  public class BasicAsyncRequestExecutionHandler<T> implements HttpAsyncRequestExecutionHandler<T> {
56  
57      private final HttpAsyncRequestProducer requestProducer;
58      private final HttpAsyncResponseConsumer<T> responseConsumer;
59      private final BasicFuture<T> future;
60      private final HttpContext localContext;
61      private final HttpProcessor httppocessor;
62      private final ConnectionReuseStrategy reuseStrategy;
63      private final HttpParams params;
64  
65      private volatile boolean requestSent;
66  
67      public BasicAsyncRequestExecutionHandler(
68              final HttpAsyncRequestProducer requestProducer,
69              final HttpAsyncResponseConsumer<T> responseConsumer,
70              final FutureCallback<T> callback,
71              final HttpContext localContext,
72              final HttpProcessor httppocessor,
73              final ConnectionReuseStrategy reuseStrategy,
74              final HttpParams params) {
75          super();
76          if (requestProducer == null) {
77              throw new IllegalArgumentException("Request producer may not be null");
78          }
79          if (responseConsumer == null) {
80              throw new IllegalArgumentException("Response consumer may not be null");
81          }
82          if (localContext == null) {
83              throw new IllegalArgumentException("HTTP context may not be null");
84          }
85          if (httppocessor == null) {
86              throw new IllegalArgumentException("HTTP processor may not be null");
87          }
88          if (reuseStrategy == null) {
89              throw new IllegalArgumentException("Connection reuse strategy may not be null");
90          }
91          if (params == null) {
92              throw new IllegalArgumentException("HTTP parameters may not be null");
93          }
94          this.requestProducer = requestProducer;
95          this.responseConsumer = responseConsumer;
96          this.future = new BasicFuture<T>(callback);
97          this.localContext = localContext;
98          this.httppocessor = httppocessor;
99          this.reuseStrategy = reuseStrategy;
100         this.params = params;
101     }
102 
103     public BasicAsyncRequestExecutionHandler(
104             final HttpAsyncRequestProducer requestProducer,
105             final HttpAsyncResponseConsumer<T> responseConsumer,
106             final HttpContext localContext,
107             final HttpProcessor httppocessor,
108             final ConnectionReuseStrategy reuseStrategy,
109             final HttpParams params) {
110         this(requestProducer, responseConsumer, null, localContext, httppocessor, reuseStrategy, params);
111     }
112 
113     public Future<T> getFuture() {
114         return this.future;
115     }
116 
117     private void releaseResources() {
118         try {
119             this.responseConsumer.close();
120         } catch (IOException ex) {
121         }
122         try {
123             this.requestProducer.close();
124         } catch (IOException ex) {
125         }
126     }
127 
128     public void close() throws IOException {
129         releaseResources();
130         if (!this.future.isDone()) {
131             this.future.cancel();
132         }
133     }
134 
135     public HttpHost getTarget() {
136         return this.requestProducer.getTarget();
137     }
138 
139     public HttpRequest generateRequest() throws IOException, HttpException {
140         HttpRequest request = this.requestProducer.generateRequest();
141         request.setParams(new DefaultedHttpParams(request.getParams(), this.params));
142         return request;
143     }
144 
145     public void produceContent(
146             final ContentEncoder encoder, final IOControl ioctrl) throws IOException {
147         this.requestProducer.produceContent(encoder, ioctrl);
148     }
149 
150     public void requestCompleted(final HttpContext context) {
151         this.requestProducer.requestCompleted(context);
152         this.requestSent = true;
153     }
154 
155     public boolean isRepeatable() {
156         return false;
157     }
158 
159     public void resetRequest() {
160     }
161 
162     public void responseReceived(final HttpResponse response) throws IOException, HttpException {
163         response.setParams(new DefaultedHttpParams(response.getParams(), this.params));
164         this.responseConsumer.responseReceived(response);
165     }
166 
167     public void consumeContent(
168             final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
169         this.responseConsumer.consumeContent(decoder, ioctrl);
170     }
171 
172     public void failed(final Exception ex) {
173         try {
174             if (!this.requestSent) {
175                 this.requestProducer.failed(ex);
176             }
177             this.responseConsumer.failed(ex);
178         } finally {
179             try {
180                 this.future.failed(ex);
181             } finally {
182                 releaseResources();
183             }
184         }
185     }
186 
187     public boolean cancel() {
188         try {
189             boolean cancelled = this.responseConsumer.cancel();
190             this.future.cancel();
191             releaseResources();
192             return cancelled;
193         } catch (RuntimeException ex) {
194             failed(ex);
195             throw ex;
196         }
197     }
198 
199     public void responseCompleted(final HttpContext context) {
200         try {
201             this.responseConsumer.responseCompleted(context);
202             T result = this.responseConsumer.getResult();
203             Exception ex = this.responseConsumer.getException();
204             if (ex == null) {
205                 this.future.completed(result);
206             } else {
207                 this.future.failed(ex);
208             }
209             releaseResources();
210         } catch (RuntimeException ex) {
211             failed(ex);
212             throw ex;
213         }
214     }
215 
216     public T getResult() {
217         return this.responseConsumer.getResult();
218     }
219 
220     public Exception getException() {
221         return this.responseConsumer.getException();
222     }
223 
224     public HttpContext getContext() {
225         return this.localContext;
226     }
227 
228     public HttpProcessor getHttpProcessor() {
229         return this.httppocessor;
230     }
231 
232     public ConnectionReuseStrategy getConnectionReuseStrategy() {
233         return this.reuseStrategy;
234     }
235 
236     public boolean isDone() {
237         return this.responseConsumer.isDone();
238     }
239 
240 }