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.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   * This example demonstrates how to insert custom request interceptor and an execution interceptor
62   * to the request execution chain.
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                  // Add a simple request ID to each outgoing request
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                  // Simulate a 404 response for some requests without passing the message down to the backend
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