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  package org.apache.http.impl.client;
28  
29  import java.io.IOException;
30  import java.util.LinkedList;
31  import java.util.Queue;
32  import java.util.concurrent.CancellationException;
33  import java.util.concurrent.CountDownLatch;
34  import java.util.concurrent.ExecutionException;
35  import java.util.concurrent.ExecutorService;
36  import java.util.concurrent.Executors;
37  import java.util.concurrent.Future;
38  import java.util.concurrent.TimeUnit;
39  import java.util.concurrent.TimeoutException;
40  import java.util.concurrent.atomic.AtomicBoolean;
41  
42  import org.apache.http.HttpException;
43  import org.apache.http.HttpRequest;
44  import org.apache.http.HttpResponse;
45  import org.apache.http.client.ClientProtocolException;
46  import org.apache.http.client.HttpClient;
47  import org.apache.http.client.ResponseHandler;
48  import org.apache.http.client.methods.HttpGet;
49  import org.apache.http.client.protocol.HttpClientContext;
50  import org.apache.http.concurrent.FutureCallback;
51  import org.apache.http.impl.bootstrap.HttpServer;
52  import org.apache.http.impl.bootstrap.ServerBootstrap;
53  import org.apache.http.protocol.HttpContext;
54  import org.apache.http.protocol.HttpRequestHandler;
55  import org.junit.After;
56  import org.junit.Assert;
57  import org.junit.Before;
58  import org.junit.Test;
59  
60  @SuppressWarnings("boxing") // test code
61  public class TestFutureRequestExecutionService {
62  
63      private HttpServer localServer;
64      private String uri;
65      private FutureRequestExecutionService httpAsyncClientWithFuture;
66  
67      private final AtomicBoolean blocked = new AtomicBoolean(false);
68  
69      @Before
70      public void before() throws Exception {
71              this.localServer = ServerBootstrap.bootstrap()
72                      .registerHandler("/wait", new HttpRequestHandler() {
73  
74                  @Override
75                  public void handle(
76                          final HttpRequest request, final HttpResponse response,
77                          final HttpContext context) throws HttpException, IOException {
78                      try {
79                          while(blocked.get()) {
80                              Thread.sleep(10);
81                          }
82                      } catch (final InterruptedException e) {
83                          throw new IllegalStateException(e);
84                      }
85                      response.setStatusCode(200);
86                  }
87              }).create();
88  
89              this.localServer.start();
90              uri = "http://localhost:" + this.localServer.getLocalPort() + "/wait";
91              final HttpClient httpClient = HttpClientBuilder.create()
92                      .setMaxConnPerRoute(5)
93                      .build();
94              final ExecutorService executorService = Executors.newFixedThreadPool(5);
95              httpAsyncClientWithFuture = new FutureRequestExecutionService(httpClient, executorService);
96      }
97  
98      @After
99      public void after() throws Exception {
100         blocked.set(false); // any remaining requests should unblock
101         this.localServer.stop();
102         httpAsyncClientWithFuture.close();
103     }
104 
105     @Test
106     public void shouldExecuteSingleCall() throws InterruptedException, ExecutionException {
107         final HttpRequestFutureTask<Boolean> task = httpAsyncClientWithFuture.execute(
108             new HttpGet(uri), HttpClientContext.create(), new OkidokiHandler());
109         Assert.assertTrue("request should have returned OK", task.get().booleanValue());
110     }
111 
112     @Test(expected=CancellationException.class)
113     public void shouldCancel() throws InterruptedException, ExecutionException {
114         final HttpRequestFutureTask<Boolean> task = httpAsyncClientWithFuture.execute(
115             new HttpGet(uri), HttpClientContext.create(), new OkidokiHandler());
116         task.cancel(true);
117         task.get();
118     }
119 
120     @Test(expected=TimeoutException.class)
121     public void shouldTimeout() throws InterruptedException, ExecutionException, TimeoutException {
122         blocked.set(true);
123         final HttpRequestFutureTask<Boolean> task = httpAsyncClientWithFuture.execute(
124             new HttpGet(uri), HttpClientContext.create(), new OkidokiHandler());
125         task.get(10, TimeUnit.MILLISECONDS);
126     }
127 
128     @Test
129     public void shouldExecuteMultipleCalls() throws Exception {
130         final int reqNo = 100;
131         final Queue<Future<Boolean>> tasks = new LinkedList<Future<Boolean>>();
132         for(int i = 0; i < reqNo; i++) {
133             final Future<Boolean> task = httpAsyncClientWithFuture.execute(
134                     new HttpGet(uri), HttpClientContext.create(), new OkidokiHandler());
135             tasks.add(task);
136         }
137         for (final Future<Boolean> task : tasks) {
138             final Boolean b = task.get();
139             Assert.assertNotNull(b);
140             Assert.assertTrue("request should have returned OK", b.booleanValue());
141         }
142     }
143 
144     @Test
145     public void shouldExecuteMultipleCallsAndCallback() throws Exception {
146         final int reqNo = 100;
147         final Queue<Future<Boolean>> tasks = new LinkedList<Future<Boolean>>();
148         final CountDownLatch latch = new CountDownLatch(reqNo);
149         for(int i = 0; i < reqNo; i++) {
150             final Future<Boolean> task = httpAsyncClientWithFuture.execute(
151                     new HttpGet(uri), HttpClientContext.create(),
152                     new OkidokiHandler(), new CountingCallback(latch));
153             tasks.add(task);
154         }
155         Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
156         for (final Future<Boolean> task : tasks) {
157             final Boolean b = task.get();
158             Assert.assertNotNull(b);
159             Assert.assertTrue("request should have returned OK", b.booleanValue());
160         }
161     }
162 
163     private final class CountingCallback implements FutureCallback<Boolean> {
164 
165         private final CountDownLatch latch;
166 
167         CountingCallback(final CountDownLatch latch) {
168             super();
169             this.latch = latch;
170         }
171 
172         @Override
173         public void failed(final Exception ex) {
174             latch.countDown();
175         }
176 
177         @Override
178         public void completed(final Boolean result) {
179             latch.countDown();
180         }
181 
182         @Override
183         public void cancelled() {
184             latch.countDown();
185         }
186     }
187 
188 
189     private final class OkidokiHandler implements ResponseHandler<Boolean> {
190         @Override
191         public Boolean handleResponse(
192                 final HttpResponse response) throws ClientProtocolException, IOException {
193             return response.getStatusLine().getStatusCode() == 200;
194         }
195     }
196 
197 }