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
28 package org.apache.hc.client5.http.examples;
29
30 import java.io.IOException;
31 import java.nio.ByteBuffer;
32 import java.nio.charset.StandardCharsets;
33 import java.util.concurrent.Future;
34 import java.util.concurrent.atomic.AtomicLong;
35
36 import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
37 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
38 import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
39 import org.apache.hc.client5.http.impl.ChainElement;
40 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
41 import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
42 import org.apache.hc.core5.concurrent.FutureCallback;
43 import org.apache.hc.core5.http.ContentType;
44 import org.apache.hc.core5.http.EntityDetails;
45 import org.apache.hc.core5.http.Header;
46 import org.apache.hc.core5.http.HttpException;
47 import org.apache.hc.core5.http.HttpRequest;
48 import org.apache.hc.core5.http.HttpRequestInterceptor;
49 import org.apache.hc.core5.http.HttpResponse;
50 import org.apache.hc.core5.http.HttpStatus;
51 import org.apache.hc.core5.http.impl.BasicEntityDetails;
52 import org.apache.hc.core5.http.message.BasicHttpResponse;
53 import org.apache.hc.core5.http.message.StatusLine;
54 import org.apache.hc.core5.http.nio.AsyncDataConsumer;
55 import org.apache.hc.core5.http.protocol.HttpContext;
56 import org.apache.hc.core5.io.CloseMode;
57 import org.apache.hc.core5.reactor.IOReactorConfig;
58 import org.apache.hc.core5.util.Timeout;
59
60
61
62
63
64 public class AsyncClientInterceptors {
65
66 public static void main(final String[] args) throws Exception {
67
68 final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
69 .setSoTimeout(Timeout.ofSeconds(5))
70 .build();
71
72 final CloseableHttpAsyncClient client = HttpAsyncClients.custom()
73 .setIOReactorConfig(ioReactorConfig)
74
75
76
77 .addRequestInterceptorFirst(new HttpRequestInterceptor() {
78
79 private final AtomicLong count = new AtomicLong(0);
80
81 @Override
82 public void process(
83 final HttpRequest request,
84 final EntityDetails entity,
85 final HttpContext context) throws HttpException, IOException {
86 request.setHeader("request-id", Long.toString(count.incrementAndGet()));
87 }
88 })
89
90
91
92 .addExecInterceptorAfter(ChainElement.PROTOCOL.name(), "custom", (request, requestEntityProducer, scope, chain, asyncExecCallback) -> {
93 final Header idHeader = request.getFirstHeader("request-id");
94 if (idHeader != null && "13".equalsIgnoreCase(idHeader.getValue())) {
95 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_NOT_FOUND, "Oppsie");
96 final ByteBuffer content = ByteBuffer.wrap("bad luck".getBytes(StandardCharsets.US_ASCII));
97 final AsyncDataConsumer asyncDataConsumer = asyncExecCallback.handleResponse(
98 response,
99 new BasicEntityDetails(content.remaining(), ContentType.TEXT_PLAIN));
100 asyncDataConsumer.consume(content);
101 asyncDataConsumer.streamEnd(null);
102 } else {
103 chain.proceed(request, requestEntityProducer, scope, asyncExecCallback);
104 }
105 })
106
107 .build();
108
109 client.start();
110
111 final String requestUri = "http://httpbin.org/get";
112 for (int i = 0; i < 20; i++) {
113 final SimpleHttpRequest request = SimpleRequestBuilder.get(requestUri).build();
114 System.out.println("Executing request " + request);
115 final Future<SimpleHttpResponse> future = client.execute(
116 request,
117 new FutureCallback<SimpleHttpResponse>() {
118
119 @Override
120 public void completed(final SimpleHttpResponse response) {
121 System.out.println(request + "->" + new StatusLine(response));
122 System.out.println(response.getBody());
123 }
124
125 @Override
126 public void failed(final Exception ex) {
127 System.out.println(request + "->" + ex);
128 }
129
130 @Override
131 public void cancelled() {
132 System.out.println(request + " cancelled");
133 }
134
135 });
136 future.get();
137 }
138
139 System.out.println("Shutting down");
140 client.close(CloseMode.GRACEFUL);
141 }
142
143 }
144