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 @Override
122 public void start() throws HttpException, IOException {
123 final HttpHost target = this.requestProducer.getTarget();
124 final HttpRequest original = this.requestProducer.generateRequest();
125
126 if (original instanceof HttpExecutionAware) {
127 ((HttpExecutionAware) original).setCancellable(this);
128 }
129 this.exec.prepare(target, original, this.state, this);
130 requestConnection();
131 }
132
133 @Override
134 public HttpRequest generateRequest() throws IOException, HttpException {
135 return this.exec.generateRequest(this.state, this);
136 }
137
138 @Override
139 public void produceContent(
140 final ContentEncoder encoder, final IOControl ioControl) throws IOException {
141 this.exec.produceContent(this.state, encoder, ioControl);
142 }
143
144 @Override
145 public void requestCompleted() {
146 this.exec.requestCompleted(this.state, this);
147 }
148
149 @Override
150 public void responseReceived(
151 final HttpResponse response) throws IOException, HttpException {
152 this.exec.responseReceived(response, this.state, this);
153 }
154
155 @Override
156 public void consumeContent(
157 final ContentDecoder decoder, final IOControl ioControl) throws IOException {
158 this.exec.consumeContent(this.state, decoder, ioControl);
159 if (!decoder.isCompleted() && this.responseConsumer.isDone()) {
160 markConnectionNonReusable();
161 try {
162 markCompleted();
163 releaseConnection();
164 this.resultFuture.cancel();
165 } finally {
166 close();
167 }
168 }
169 }
170
171 @Override
172 public void responseCompleted() throws IOException, HttpException {
173 this.exec.responseCompleted(this.state, this);
174
175 if (this.state.getFinalResponse() != null || this.resultFuture.isDone()) {
176 try {
177 markCompleted();
178 releaseConnection();
179 final T result = this.responseConsumer.getResult();
180 final Exception ex = this.responseConsumer.getException();
181 if (ex == null) {
182 this.resultFuture.completed(result);
183 } else {
184 this.resultFuture.failed(ex);
185 }
186 } finally {
187 close();
188 }
189 } else {
190 NHttpClientConnection localConn = getConnection();
191 if (localConn != null && !localConn.isOpen()) {
192 releaseConnection();
193 localConn = null;
194 }
195 if (localConn != null) {
196 localConn.requestOutput();
197 } else {
198 requestConnection();
199 }
200 }
201 }
202
203 @Override
204 public void inputTerminated() {
205 if (!isCompleted()) {
206 requestConnection();
207 } else {
208 close();
209 }
210 }
211
212 public void abortConnection() {
213 discardConnection();
214 }
215
216 }