1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.restlet.ext.httpclient4;
20
21 import java.io.FilterInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.net.URI;
26 import java.net.URISyntaxException;
27 import java.nio.channels.ReadableByteChannel;
28 import java.nio.channels.WritableByteChannel;
29 import java.util.logging.Level;
30 import org.apache.http.Header;
31 import org.apache.http.HttpResponse;
32 import org.apache.http.client.methods.HttpDelete;
33 import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
34 import org.apache.http.client.methods.HttpGet;
35 import org.apache.http.client.methods.HttpHead;
36 import org.apache.http.client.methods.HttpOptions;
37 import org.apache.http.client.methods.HttpPost;
38 import org.apache.http.client.methods.HttpPut;
39 import org.apache.http.client.methods.HttpTrace;
40 import org.apache.http.client.methods.HttpUriRequest;
41 import org.apache.http.entity.AbstractHttpEntity;
42 import org.apache.http.message.BasicHeader;
43 import org.apache.http.util.EntityUtils;
44 import org.restlet.Request;
45 import org.restlet.Response;
46 import org.restlet.Uniform;
47 import org.restlet.data.Method;
48 import org.restlet.data.Protocol;
49 import org.restlet.data.Status;
50 import org.restlet.engine.adapter.ClientCall;
51 import org.restlet.engine.header.HeaderConstants;
52 import org.restlet.representation.Representation;
53 import org.restlet.util.Series;
54
55
56
57
58
59
60 public class HttpMethodCall extends ClientCall {
61
62
63
64
65 private volatile HttpDOIClientHelper clientHelper;
66
67
68
69
70 private volatile HttpUriRequest httpRequest;
71
72
73
74
75 private volatile HttpResponse httpResponse;
76
77
78
79
80 private volatile boolean responseHeadersAdded;
81
82
83
84
85
86
87
88
89
90
91
92 public HttpMethodCall(final HttpDOIClientHelper helper, final String method,
93 final String requestUri, boolean hasEntity) throws IOException {
94 super(helper, method, requestUri);
95 this.clientHelper = helper;
96
97 if (requestUri.startsWith("http")) {
98 if (method.equalsIgnoreCase(Method.GET.getName())) {
99 this.httpRequest = new HttpGet(requestUri);
100 } else if (method.equalsIgnoreCase(Method.POST.getName())) {
101 this.httpRequest = new HttpPost(requestUri);
102 } else if (method.equalsIgnoreCase(Method.PUT.getName())) {
103 this.httpRequest = new HttpPut(requestUri);
104 } else if (method.equalsIgnoreCase(Method.HEAD.getName())) {
105 this.httpRequest = new HttpHead(requestUri);
106 } else if (method.equalsIgnoreCase(Method.DELETE.getName())) {
107 this.httpRequest = new HttpDelete(requestUri);
108 if (hasEntity) {
109 getLogger()
110 .warning(
111 "The current DELETE request provides an entity that may be not "
112 + "supported by the Apache HTTP Client library. If you "
113 + "face such issues, you can still move to another HTTP"
114 + " client connector.");
115 }
116 } else if (method.equalsIgnoreCase(Method.OPTIONS.getName())) {
117 this.httpRequest = new HttpOptions(requestUri);
118 } else if (method.equalsIgnoreCase(Method.TRACE.getName())) {
119 this.httpRequest = new HttpTrace(requestUri);
120 } else {
121 this.httpRequest = new HttpEntityEnclosingRequestBase() {
122
123
124
125
126 @Override
127 public String getMethod() {
128 return method;
129 }
130
131
132
133
134 @Override
135 public URI getURI() {
136 URI uri;
137 try {
138 uri = new URI(requestUri);
139 } catch (URISyntaxException e) {
140 getLogger().log(Level.WARNING,
141 "Invalid URI syntax", e);
142 uri = null;
143 }
144 return uri;
145 }
146 };
147 }
148
149 this.responseHeadersAdded = false;
150 setConfidential(this.httpRequest.getURI().getScheme()
151 .equalsIgnoreCase(Protocol.HTTPS.getSchemeName()));
152 } else {
153 throw new IllegalArgumentException(
154 "Only HTTP or HTTPS resource URIs are allowed here");
155 }
156 }
157
158
159
160
161
162
163 public HttpUriRequest getHttpRequest() {
164 return this.httpRequest;
165 }
166
167
168
169
170
171
172 public HttpResponse getHttpResponse() {
173 return this.httpResponse;
174 }
175
176
177
178
179 @Override
180 public String getReasonPhrase() {
181 final String reasonPhrase;
182 if ((getHttpResponse() != null)
183 && (getHttpResponse().getStatusLine() != null)) {
184 reasonPhrase = getHttpResponse().getStatusLine().getReasonPhrase();
185 } else {
186 reasonPhrase = null;
187 }
188 return reasonPhrase;
189 }
190
191
192
193
194
195
196 @Override
197 public WritableByteChannel getRequestEntityChannel() {
198 return null;
199 }
200
201
202
203
204
205
206 @Override
207 public OutputStream getRequestEntityStream() {
208 return null;
209 }
210
211
212
213
214
215
216 @Override
217 public OutputStream getRequestHeadStream() {
218 return null;
219 }
220
221
222
223
224
225
226 @Override
227 public ReadableByteChannel getResponseEntityChannel(final long size) {
228 return null;
229 }
230
231
232
233
234 @Override
235 public InputStream getResponseEntityStream(final long size) {
236 InputStream result = null;
237
238 try {
239
240
241
242 final InputStream responseStream = (getHttpResponse() == null) ? null
243 : (getHttpResponse().getEntity() == null) ? null
244 : getHttpResponse().getEntity().getContent();
245 if (responseStream != null) {
246 result = new FilterInputStream(responseStream) {
247 @Override
248 public void close() throws IOException {
249 super.close();
250 EntityUtils.consume(getHttpResponse().getEntity());
251 }
252 };
253 }
254 } catch (IOException ioe) {
255 this.clientHelper
256 .getLogger()
257 .log(Level.WARNING,
258 "An error occurred during the communication with the remote HTTP server.",
259 ioe);
260 }
261
262 return result;
263 }
264
265
266
267
268 @Override
269 public Series<org.restlet.data.Header> getResponseHeaders() {
270 final Series<org.restlet.data.Header> result = super.getResponseHeaders();
271
272 if (!this.responseHeadersAdded) {
273 if ((getHttpResponse() != null)
274 && (getHttpResponse().getAllHeaders() != null)) {
275 for (Header header : getHttpResponse().getAllHeaders()) {
276 result.add(header.getName(), header.getValue());
277 }
278 }
279
280 this.responseHeadersAdded = true;
281 }
282
283 return result;
284 }
285
286
287
288
289 @Override
290 public String getServerAddress() {
291 return getHttpRequest().getURI().getHost();
292 }
293
294
295
296
297 @Override
298 public int getStatusCode() {
299 final int statusCode;
300 if (getHttpResponse() != null
301 && getHttpResponse().getStatusLine() != null) {
302 statusCode = getHttpResponse().getStatusLine().getStatusCode();
303 } else {
304 statusCode = Status.CONNECTOR_ERROR_COMMUNICATION.getCode();
305 }
306 return statusCode;
307 }
308
309
310
311
312 @Override
313 public Status sendRequest(final Request request) {
314 Status result;
315
316 try {
317 final Representation entity = request.getEntity();
318
319
320 for (final org.restlet.data.Header header : getRequestHeaders()) {
321 if (!header.getName().equals(
322 HeaderConstants.HEADER_CONTENT_LENGTH)) {
323 getHttpRequest().addHeader(header.getName(),
324 header.getValue());
325 }
326 }
327
328
329 if ((entity != null)
330 && (getHttpRequest() instanceof HttpEntityEnclosingRequestBase)) {
331 final HttpEntityEnclosingRequestBase eem = (HttpEntityEnclosingRequestBase) getHttpRequest();
332 eem.setEntity(new AbstractHttpEntity() {
333
334
335
336 @Override
337 public InputStream getContent() throws IOException,
338 IllegalStateException {
339 return entity.getStream();
340 }
341
342
343
344
345 @Override
346 public long getContentLength() {
347 return entity.getSize();
348 }
349
350
351
352
353 @Override
354 public Header getContentType() {
355 return new BasicHeader(
356 HeaderConstants.HEADER_CONTENT_TYPE, (entity
357 .getMediaType() != null) ? entity
358 .getMediaType().toString() : null);
359 }
360
361
362
363
364 @Override
365 public boolean isRepeatable() {
366 return !entity.isTransient();
367 }
368
369
370
371
372 @Override
373 public boolean isStreaming() {
374 return (entity.getSize() == Representation.UNKNOWN_SIZE);
375 }
376
377
378
379
380 @Override
381 public void writeTo(final OutputStream os) throws IOException {
382 entity.write(os);
383 os.flush();
384 }
385 });
386 }
387
388
389 this.httpResponse = this.clientHelper.getHttpClient().execute(
390 getHttpRequest());
391
392
393
394 result = new Status(getStatusCode(), getReasonPhrase());
395 } catch (IOException ioe) {
396 this.clientHelper
397 .getLogger()
398 .log(Level.WARNING,
399 "An error occurred during the communication with the remote HTTP server.",
400 ioe);
401 result = new Status(Status.CONNECTOR_ERROR_COMMUNICATION, ioe);
402
403
404 getHttpRequest().abort();
405 }
406
407 return result;
408 }
409
410
411
412
413 @Override
414 public void sendRequest(final Request request, final Response response, final Uniform callback)
415 throws Exception {
416 sendRequest(request);
417
418 if (request.getOnSent() != null) {
419 request.getOnSent().handle(request, response);
420 }
421
422 if (callback != null) {
423
424 callback.handle(request, response);
425 }
426 }
427
428 }