0
# Asynchronous Operations
1
2
The Async class provides asynchronous execution of HTTP requests using Future-based patterns with optional callback support. Requests are executed in background threads while allowing the main thread to continue processing.
3
4
## Async Instance Creation
5
6
Create Async instances using the static factory method:
7
8
```java { .api }
9
public static Async newInstance();
10
```
11
12
### Usage Examples
13
14
```java
15
import org.apache.http.client.fluent.Async;
16
17
Async async = Async.newInstance();
18
```
19
20
## Configuration
21
22
Configure the Async instance with custom executors:
23
24
```java { .api }
25
public Async use(Executor executor);
26
public Async use(java.util.concurrent.Executor concurrentExec);
27
```
28
29
### Usage Examples
30
31
```java
32
import org.apache.http.client.fluent.Executor;
33
import java.util.concurrent.Executors;
34
import java.util.concurrent.ThreadPoolExecutor;
35
36
// Use custom HTTP executor for authentication/cookies
37
Executor httpExecutor = Executor.newInstance()
38
.auth("api.example.com", "username", "password");
39
40
// Use custom thread pool for concurrent execution
41
ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
42
43
Async async = Async.newInstance()
44
.use(httpExecutor) // HTTP context management
45
.use(threadPool); // Thread execution
46
```
47
48
## Asynchronous Execution Methods
49
50
Execute requests asynchronously with various response handling options:
51
52
```java { .api }
53
public <T> Future<T> execute(Request request, ResponseHandler<T> handler);
54
public <T> Future<T> execute(Request request, ResponseHandler<T> handler, FutureCallback<T> callback);
55
public Future<Content> execute(Request request);
56
public Future<Content> execute(Request request, FutureCallback<Content> callback);
57
```
58
59
### Basic Async Execution
60
61
Execute requests returning Future objects:
62
63
```java
64
import org.apache.http.client.fluent.Request;
65
import org.apache.http.client.fluent.Content;
66
import java.util.concurrent.Future;
67
68
Async async = Async.newInstance();
69
70
// Simple async execution returning Content
71
Future<Content> future = async.execute(Request.Get("https://api.example.com/data"));
72
73
// Block and get result
74
Content content = future.get();
75
String response = content.asString();
76
77
// Non-blocking check
78
if (future.isDone()) {
79
Content result = future.get();
80
}
81
```
82
83
### Custom Response Handlers
84
85
Use custom ResponseHandler for specific response processing:
86
87
```java
88
import org.apache.http.client.ResponseHandler;
89
import org.apache.http.HttpResponse;
90
import org.apache.http.util.EntityUtils;
91
import java.util.concurrent.Future;
92
93
// Custom handler to extract status code
94
ResponseHandler<Integer> statusHandler = new ResponseHandler<Integer>() {
95
@Override
96
public Integer handleResponse(HttpResponse response) {
97
return response.getStatusLine().getStatusCode();
98
}
99
};
100
101
// Execute with custom handler
102
Future<Integer> statusFuture = async.execute(
103
Request.Get("https://api.example.com/check"),
104
statusHandler
105
);
106
107
Integer statusCode = statusFuture.get();
108
System.out.println("Status: " + statusCode);
109
```
110
111
### Callback-based Execution
112
113
Use callbacks for asynchronous result processing:
114
115
```java
116
import org.apache.http.concurrent.FutureCallback;
117
import java.util.concurrent.Future;
118
119
// Callback for Content results
120
FutureCallback<Content> contentCallback = new FutureCallback<Content>() {
121
@Override
122
public void completed(Content result) {
123
System.out.println("Request completed: " + result.asString());
124
}
125
126
@Override
127
public void failed(Exception ex) {
128
System.err.println("Request failed: " + ex.getMessage());
129
}
130
131
@Override
132
public void cancelled() {
133
System.out.println("Request cancelled");
134
}
135
};
136
137
// Execute with callback
138
Future<Content> future = async.execute(
139
Request.Get("https://api.example.com/data"),
140
contentCallback
141
);
142
143
// Continue with other work while request executes in background
144
doOtherWork();
145
146
// Optionally wait for completion
147
future.get();
148
```
149
150
### Multiple Concurrent Requests
151
152
Execute multiple requests concurrently:
153
154
```java
155
import java.util.concurrent.Future;
156
import java.util.List;
157
import java.util.ArrayList;
158
159
Async async = Async.newInstance();
160
List<Future<Content>> futures = new ArrayList<>();
161
162
// Start multiple async requests
163
futures.add(async.execute(Request.Get("https://api.example.com/data1")));
164
futures.add(async.execute(Request.Get("https://api.example.com/data2")));
165
futures.add(async.execute(Request.Get("https://api.example.com/data3")));
166
167
// Process results as they complete
168
for (Future<Content> future : futures) {
169
Content content = future.get(); // Blocks until this specific request completes
170
System.out.println("Response: " + content.asString());
171
}
172
```
173
174
## Future Operations
175
176
The returned Future objects support standard Future interface operations:
177
178
```java
179
import java.util.concurrent.Future;
180
import java.util.concurrent.TimeUnit;
181
import java.util.concurrent.TimeoutException;
182
183
Future<Content> future = async.execute(Request.Get("https://slow-api.example.com/data"));
184
185
// Check if completed
186
boolean done = future.isDone();
187
188
// Cancel if not started or interrupt if running
189
boolean cancelled = future.cancel(true);
190
191
// Get with timeout
192
try {
193
Content content = future.get(5, TimeUnit.SECONDS);
194
} catch (TimeoutException e) {
195
System.err.println("Request timed out");
196
future.cancel(true);
197
}
198
```
199
200
## Error Handling
201
202
Async operations can fail in various ways:
203
204
```java
205
import java.util.concurrent.ExecutionException;
206
import java.util.concurrent.Future;
207
208
Future<Content> future = async.execute(Request.Get("https://api.example.com/data"));
209
210
try {
211
Content content = future.get();
212
String response = content.asString();
213
} catch (ExecutionException e) {
214
// Unwrap the actual exception
215
Throwable cause = e.getCause();
216
if (cause instanceof IOException) {
217
System.err.println("I/O error: " + cause.getMessage());
218
} else if (cause instanceof ClientProtocolException) {
219
System.err.println("Protocol error: " + cause.getMessage());
220
} else {
221
System.err.println("Unexpected error: " + cause.getMessage());
222
}
223
} catch (InterruptedException e) {
224
System.err.println("Request interrupted: " + e.getMessage());
225
Thread.currentThread().interrupt();
226
}
227
```
228
229
## Advanced Patterns
230
231
### Async with Authentication
232
233
Combine Async with Executor for authenticated requests:
234
235
```java
236
import org.apache.http.client.fluent.Executor;
237
238
// Create authenticated executor
239
Executor authenticatedExecutor = Executor.newInstance()
240
.auth("api.example.com", "username", "password");
241
242
// Use with async
243
Async async = Async.newInstance()
244
.use(authenticatedExecutor);
245
246
// All async requests will be authenticated
247
Future<Content> future = async.execute(Request.Get("https://api.example.com/private-data"));
248
```
249
250
### Async with Custom Thread Pool
251
252
Use a managed thread pool for better resource control:
253
254
```java
255
import java.util.concurrent.ExecutorService;
256
import java.util.concurrent.Executors;
257
258
ExecutorService threadPool = Executors.newFixedThreadPool(5);
259
260
Async async = Async.newInstance()
261
.use(threadPool);
262
263
// Execute multiple requests using the managed thread pool
264
List<Future<Content>> futures = new ArrayList<>();
265
for (int i = 0; i < 10; i++) {
266
futures.add(async.execute(Request.Get("https://api.example.com/data/" + i)));
267
}
268
269
// Process results
270
for (Future<Content> future : futures) {
271
Content content = future.get();
272
System.out.println("Response: " + content.asString());
273
}
274
275
// Clean up
276
threadPool.shutdown();
277
```
278
279
### Async with Progress Tracking
280
281
Track progress of multiple async operations:
282
283
```java
284
import java.util.concurrent.CompletableFuture;
285
import java.util.concurrent.atomic.AtomicInteger;
286
287
Async async = Async.newInstance();
288
AtomicInteger completed = new AtomicInteger(0);
289
AtomicInteger total = new AtomicInteger(5);
290
291
FutureCallback<Content> progressCallback = new FutureCallback<Content>() {
292
@Override
293
public void completed(Content result) {
294
int count = completed.incrementAndGet();
295
System.out.println("Progress: " + count + "/" + total.get());
296
}
297
298
@Override
299
public void failed(Exception ex) {
300
System.err.println("Request failed: " + ex.getMessage());
301
completed.incrementAndGet(); // Count failures too
302
}
303
304
@Override
305
public void cancelled() {
306
System.out.println("Request cancelled");
307
completed.incrementAndGet(); // Count cancellations too
308
}
309
};
310
311
// Start requests with progress tracking
312
for (int i = 0; i < total.get(); i++) {
313
async.execute(Request.Get("https://api.example.com/data/" + i), progressCallback);
314
}
315
```
316
317
## Thread Safety
318
319
The Async class is **thread-safe** and can be used concurrently from multiple threads. However, each execution creates a new background thread or uses the configured thread pool.
320
321
## Best Practices
322
323
1. **Reuse Async instances**: Create once and reuse for multiple requests
324
2. **Configure thread pools**: Use custom ExecutorService for better resource management
325
3. **Handle timeouts**: Always use timeout when calling `future.get()`
326
4. **Combine with Executor**: Use Executor for authentication/session management
327
5. **Process failures**: Always handle ExecutionException in Future.get()
328
6. **Clean up resources**: Shutdown custom thread pools when done
329
330
## Complete Example
331
332
```java
333
import org.apache.http.client.fluent.*;
334
import org.apache.http.concurrent.FutureCallback;
335
import java.util.concurrent.*;
336
import java.util.List;
337
import java.util.ArrayList;
338
339
public class AsyncExample {
340
public static void main(String[] args) {
341
// Custom thread pool
342
ExecutorService threadPool = Executors.newFixedThreadPool(3);
343
344
// Authenticated HTTP executor
345
Executor httpExecutor = Executor.newInstance()
346
.auth("api.example.com", "username", "password");
347
348
// Async with custom configuration
349
Async async = Async.newInstance()
350
.use(httpExecutor)
351
.use(threadPool);
352
353
try {
354
// Multiple concurrent requests
355
List<Future<Content>> futures = new ArrayList<>();
356
357
futures.add(async.execute(Request.Get("https://api.example.com/users")));
358
futures.add(async.execute(Request.Get("https://api.example.com/orders")));
359
futures.add(async.execute(Request.Get("https://api.example.com/products")));
360
361
// Process results with timeout
362
for (Future<Content> future : futures) {
363
try {
364
Content content = future.get(10, TimeUnit.SECONDS);
365
System.out.println("Response length: " + content.asBytes().length);
366
} catch (TimeoutException e) {
367
System.err.println("Request timed out");
368
future.cancel(true);
369
} catch (ExecutionException e) {
370
System.err.println("Request failed: " + e.getCause().getMessage());
371
}
372
}
373
374
} catch (InterruptedException e) {
375
System.err.println("Interrupted: " + e.getMessage());
376
Thread.currentThread().interrupt();
377
} finally {
378
// Clean up resources
379
threadPool.shutdown();
380
Executor.closeIdleConnections();
381
}
382
}
383
}
384
```