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