1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.http.impl.nio.client;
28
29 import java.io.IOException;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.http.ConnectionReuseStrategy;
33 import org.apache.http.HttpException;
34 import org.apache.http.HttpHost;
35 import org.apache.http.HttpRequest;
36 import org.apache.http.HttpResponse;
37 import org.apache.http.client.methods.HttpExecutionAware;
38 import org.apache.http.client.protocol.HttpClientContext;
39 import org.apache.http.concurrent.BasicFuture;
40 import org.apache.http.conn.ConnectionKeepAliveStrategy;
41 import org.apache.http.nio.ContentDecoder;
42 import org.apache.http.nio.ContentEncoder;
43 import org.apache.http.nio.IOControl;
44 import org.apache.http.nio.NHttpClientConnection;
45 import org.apache.http.nio.conn.NHttpClientConnectionManager;
46 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
47 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
48
49
50
51
52
53
54
55 class DefaultClientExchangeHandlerImpl<T> extends AbstractClientExchangeHandler {
56
57 private final HttpAsyncRequestProducer requestProducer;
58 private final HttpAsyncResponseConsumer<T> responseConsumer;
59 private final BasicFuture<T> resultFuture;
60 private final InternalClientExec exec;
61 private final InternalState state;
62
63 public DefaultClientExchangeHandlerImpl(
64 final Log log,
65 final HttpAsyncRequestProducer requestProducer,
66 final HttpAsyncResponseConsumer<T> responseConsumer,
67 final HttpClientContext localContext,
68 final BasicFuture<T> resultFuture,
69 final NHttpClientConnectionManager connmgr,
70 final ConnectionReuseStrategy connReuseStrategy,
71 final ConnectionKeepAliveStrategy keepaliveStrategy,
72 final InternalClientExec exec) {
73 super(log, localContext, connmgr, connReuseStrategy, keepaliveStrategy);
74 this.requestProducer = requestProducer;
75 this.responseConsumer = responseConsumer;
76 this.resultFuture = resultFuture;
77 this.exec = exec;
78 this.state = new InternalState(getId(), requestProducer, responseConsumer, localContext);
79 }
80
81 @Override
82 void releaseResources() {
83 try {
84 this.requestProducer.close();
85 } catch (final IOException ex) {
86 this.log.debug("I/O error closing request producer", ex);
87 }
88 try {
89 this.responseConsumer.close();
90 } catch (final IOException ex) {
91 this.log.debug("I/O error closing response consumer", ex);
92 }
93 }
94
95 @Override
96 void executionFailed(final Exception ex) {
97 try {
98 this.requestProducer.failed(ex);
99 this.responseConsumer.failed(ex);
100 } finally {
101 this.resultFuture.failed(ex);
102 }
103 }
104
105 @Override
106 boolean executionCancelled() {
107 final boolean cancelled = this.responseConsumer.cancel();
108
109 final T result = this.responseConsumer.getResult();
110 final Exception ex = this.responseConsumer.getException();
111 if (ex != null) {
112 this.resultFuture.failed(ex);
113 } else if (result != null) {
114 this.resultFuture.completed(result);
115 } else {
116 this.resultFuture.cancel();
117 }
118 return cancelled;
119 }
120
121 public void start() throws HttpException, IOException {
122 final HttpHost target = this.requestProducer.getTarget();
123 final HttpRequest original = this.requestProducer.generateRequest();
124
125 if (original instanceof HttpExecutionAware) {
126 ((HttpExecutionAware) original).setCancellable(this);
127 }
128 this.exec.prepare(target, original, this.state, this);
129 requestConnection();
130 }
131
132 @Override
133 public HttpRequest generateRequest() throws IOException, HttpException {
134 return this.exec.generateRequest(this.state, this);
135 }
136
137 @Override
138 public void produceContent(
139 final ContentEncoder encoder, final IOControl ioctrl) throws IOException {
140 this.exec.produceContent(this.state, encoder, ioctrl);
141 }
142
143 @Override
144 public void requestCompleted() {
145 this.exec.requestCompleted(this.state, this);
146 }
147
148 @Override
149 public void responseReceived(
150 final HttpResponse response) throws IOException, HttpException {
151 this.exec.responseReceived(response, this.state, this);
152 }
153
154 @Override
155 public void consumeContent(
156 final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
157 this.exec.consumeContent(this.state, decoder, ioctrl);
158 if (!decoder.isCompleted() && this.responseConsumer.isDone()) {
159 markConnectionNonReusable();
160 try {
161 markCompleted();
162 releaseConnection();
163 this.resultFuture.cancel();
164 } finally {
165 close();
166 }
167 }
168 }
169
170 @Override
171 public void responseCompleted() throws IOException, HttpException {
172 this.exec.responseCompleted(this.state, this);
173
174 if (this.state.getFinalResponse() != null || this.resultFuture.isDone()) {
175 try {
176 markCompleted();
177 releaseConnection();
178 final T result = this.responseConsumer.getResult();
179 final Exception ex = this.responseConsumer.getException();
180 if (ex == null) {
181 this.resultFuture.completed(result);
182 } else {
183 this.resultFuture.failed(ex);
184 }
185 } finally {
186 close();
187 }
188 } else {
189 NHttpClientConnection localConn = getConnection();
190 if (localConn != null && !localConn.isOpen()) {
191 releaseConnection();
192 localConn = null;
193 }
194 if (localConn != null) {
195 localConn.requestOutput();
196 } else {
197 requestConnection();
198 }
199 }
200 }
201
202 @Override
203 public void inputTerminated() {
204 if (!isCompleted()) {
205 requestConnection();
206 } else {
207 close();
208 }
209 }
210
211 public void abortConnection() {
212 discardConnection();
213 }
214
215 }