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.hc.client5.http.impl.classic;
28
29 import java.io.Closeable;
30 import java.io.IOException;
31 import java.util.concurrent.ExecutorService;
32 import java.util.concurrent.FutureTask;
33 import java.util.concurrent.atomic.AtomicBoolean;
34
35 import org.apache.hc.client5.http.classic.HttpClient;
36 import org.apache.hc.core5.annotation.Contract;
37 import org.apache.hc.core5.annotation.ThreadingBehavior;
38 import org.apache.hc.core5.concurrent.FutureCallback;
39 import org.apache.hc.core5.http.ClassicHttpRequest;
40 import org.apache.hc.core5.http.io.HttpClientResponseHandler;
41 import org.apache.hc.core5.http.protocol.HttpContext;
42
43 /**
44 * This class schedules message execution execution and processing
45 * as {@link FutureTask}s with the provided {@link ExecutorService}.
46 */
47 @Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
48 public class FutureRequestExecutionService implements Closeable {
49
50 private final HttpClient httpclient;
51 private final ExecutorService executorService;
52 private final FutureRequestExecutionMetricsureRequestExecutionMetrics.html#FutureRequestExecutionMetrics">FutureRequestExecutionMetrics metrics = new FutureRequestExecutionMetrics();
53 private final AtomicBoolean closed = new AtomicBoolean(false);
54
55 /**
56 * Create a new FutureRequestExecutionService.
57 *
58 * @param httpclient
59 * you should tune your httpclient instance to match your needs. You should
60 * align the max number of connections in the pool and the number of threads
61 * in the executor; it doesn't make sense to have more threads than connections
62 * and if you have less connections than threads, the threads will just end up
63 * blocking on getting a connection from the pool.
64 * @param executorService
65 * any executorService will do here. E.g.
66 * {@link java.util.concurrent.Executors#newFixedThreadPool(int)}
67 */
68 public FutureRequestExecutionService(
69 final HttpClient httpclient,
70 final ExecutorService executorService) {
71 this.httpclient = httpclient;
72 this.executorService = executorService;
73 }
74
75 /**
76 * Schedule a request for execution.
77 *
78 * @param <T>
79 *
80 * @param request
81 * request to execute
82 * @param HttpClientResponseHandler
83 * handler that will process the response.
84 * @return HttpAsyncClientFutureTask for the scheduled request.
85 */
86 public <T> FutureTask<T> execute(
87 final ClassicHttpRequest request,
88 final HttpContext context,
89 final HttpClientResponseHandler<T> HttpClientResponseHandler) {
90 return execute(request, context, HttpClientResponseHandler, null);
91 }
92
93 /**
94 * Schedule a request for execution.
95 *
96 * @param <T>
97 *
98 * @param request
99 * request to execute
100 * @param context
101 * optional context; use null if not needed.
102 * @param HttpClientResponseHandler
103 * handler that will process the response.
104 * @param callback
105 * callback handler that will be called when the request is scheduled,
106 * started, completed, failed, or cancelled.
107 * @return HttpAsyncClientFutureTask for the scheduled request.
108 */
109 public <T> FutureTask<T> execute(
110 final ClassicHttpRequest request,
111 final HttpContext context,
112 final HttpClientResponseHandler<T> HttpClientResponseHandler,
113 final FutureCallback<T> callback) {
114 if(closed.get()) {
115 throw new IllegalStateException("Close has been called on this httpclient instance.");
116 }
117 metrics.getScheduledConnections().incrementAndGet();
118 final HttpRequestTaskCallable<T> callable = new HttpRequestTaskCallable<>(
119 httpclient, request, context, HttpClientResponseHandler, callback, metrics);
120 final HttpRequestFutureTask<T> httpRequestFutureTask = new HttpRequestFutureTask<>(
121 request, callable);
122 executorService.execute(httpRequestFutureTask);
123
124 return httpRequestFutureTask;
125 }
126
127 /**
128 * @return metrics gathered for this instance.
129 * @see FutureRequestExecutionMetrics
130 */
131 public FutureRequestExecutionMetrics metrics() {
132 return metrics;
133 }
134
135 @Override
136 public void close() throws IOException {
137 closed.set(true);
138 executorService.shutdownNow();
139 if (httpclient instanceof Closeable) {
140 ((Closeable) httpclient).close();
141 }
142 }
143 }