Apache HttpComponents Client fluent API providing a simplified interface for HTTP operations
—
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.
Create Async instances using the static factory method:
public static Async newInstance();import org.apache.http.client.fluent.Async;
Async async = Async.newInstance();Configure the Async instance with custom executors:
public Async use(Executor executor);
public Async use(java.util.concurrent.Executor concurrentExec);import org.apache.http.client.fluent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
// Use custom HTTP executor for authentication/cookies
Executor httpExecutor = Executor.newInstance()
.auth("api.example.com", "username", "password");
// Use custom thread pool for concurrent execution
ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
Async async = Async.newInstance()
.use(httpExecutor) // HTTP context management
.use(threadPool); // Thread executionExecute requests asynchronously with various response handling options:
public <T> Future<T> execute(Request request, ResponseHandler<T> handler);
public <T> Future<T> execute(Request request, ResponseHandler<T> handler, FutureCallback<T> callback);
public Future<Content> execute(Request request);
public Future<Content> execute(Request request, FutureCallback<Content> callback);Execute requests returning Future objects:
import org.apache.http.client.fluent.Request;
import org.apache.http.client.fluent.Content;
import java.util.concurrent.Future;
Async async = Async.newInstance();
// Simple async execution returning Content
Future<Content> future = async.execute(Request.Get("https://api.example.com/data"));
// Block and get result
Content content = future.get();
String response = content.asString();
// Non-blocking check
if (future.isDone()) {
Content result = future.get();
}Use custom ResponseHandler for specific response processing:
import org.apache.http.client.ResponseHandler;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import java.util.concurrent.Future;
// Custom handler to extract status code
ResponseHandler<Integer> statusHandler = new ResponseHandler<Integer>() {
@Override
public Integer handleResponse(HttpResponse response) {
return response.getStatusLine().getStatusCode();
}
};
// Execute with custom handler
Future<Integer> statusFuture = async.execute(
Request.Get("https://api.example.com/check"),
statusHandler
);
Integer statusCode = statusFuture.get();
System.out.println("Status: " + statusCode);Use callbacks for asynchronous result processing:
import org.apache.http.concurrent.FutureCallback;
import java.util.concurrent.Future;
// Callback for Content results
FutureCallback<Content> contentCallback = new FutureCallback<Content>() {
@Override
public void completed(Content result) {
System.out.println("Request completed: " + result.asString());
}
@Override
public void failed(Exception ex) {
System.err.println("Request failed: " + ex.getMessage());
}
@Override
public void cancelled() {
System.out.println("Request cancelled");
}
};
// Execute with callback
Future<Content> future = async.execute(
Request.Get("https://api.example.com/data"),
contentCallback
);
// Continue with other work while request executes in background
doOtherWork();
// Optionally wait for completion
future.get();Execute multiple requests concurrently:
import java.util.concurrent.Future;
import java.util.List;
import java.util.ArrayList;
Async async = Async.newInstance();
List<Future<Content>> futures = new ArrayList<>();
// Start multiple async requests
futures.add(async.execute(Request.Get("https://api.example.com/data1")));
futures.add(async.execute(Request.Get("https://api.example.com/data2")));
futures.add(async.execute(Request.Get("https://api.example.com/data3")));
// Process results as they complete
for (Future<Content> future : futures) {
Content content = future.get(); // Blocks until this specific request completes
System.out.println("Response: " + content.asString());
}The returned Future objects support standard Future interface operations:
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
Future<Content> future = async.execute(Request.Get("https://slow-api.example.com/data"));
// Check if completed
boolean done = future.isDone();
// Cancel if not started or interrupt if running
boolean cancelled = future.cancel(true);
// Get with timeout
try {
Content content = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.err.println("Request timed out");
future.cancel(true);
}Async operations can fail in various ways:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
Future<Content> future = async.execute(Request.Get("https://api.example.com/data"));
try {
Content content = future.get();
String response = content.asString();
} catch (ExecutionException e) {
// Unwrap the actual exception
Throwable cause = e.getCause();
if (cause instanceof IOException) {
System.err.println("I/O error: " + cause.getMessage());
} else if (cause instanceof ClientProtocolException) {
System.err.println("Protocol error: " + cause.getMessage());
} else {
System.err.println("Unexpected error: " + cause.getMessage());
}
} catch (InterruptedException e) {
System.err.println("Request interrupted: " + e.getMessage());
Thread.currentThread().interrupt();
}Combine Async with Executor for authenticated requests:
import org.apache.http.client.fluent.Executor;
// Create authenticated executor
Executor authenticatedExecutor = Executor.newInstance()
.auth("api.example.com", "username", "password");
// Use with async
Async async = Async.newInstance()
.use(authenticatedExecutor);
// All async requests will be authenticated
Future<Content> future = async.execute(Request.Get("https://api.example.com/private-data"));Use a managed thread pool for better resource control:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
ExecutorService threadPool = Executors.newFixedThreadPool(5);
Async async = Async.newInstance()
.use(threadPool);
// Execute multiple requests using the managed thread pool
List<Future<Content>> futures = new ArrayList<>();
for (int i = 0; i < 10; i++) {
futures.add(async.execute(Request.Get("https://api.example.com/data/" + i)));
}
// Process results
for (Future<Content> future : futures) {
Content content = future.get();
System.out.println("Response: " + content.asString());
}
// Clean up
threadPool.shutdown();Track progress of multiple async operations:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
Async async = Async.newInstance();
AtomicInteger completed = new AtomicInteger(0);
AtomicInteger total = new AtomicInteger(5);
FutureCallback<Content> progressCallback = new FutureCallback<Content>() {
@Override
public void completed(Content result) {
int count = completed.incrementAndGet();
System.out.println("Progress: " + count + "/" + total.get());
}
@Override
public void failed(Exception ex) {
System.err.println("Request failed: " + ex.getMessage());
completed.incrementAndGet(); // Count failures too
}
@Override
public void cancelled() {
System.out.println("Request cancelled");
completed.incrementAndGet(); // Count cancellations too
}
};
// Start requests with progress tracking
for (int i = 0; i < total.get(); i++) {
async.execute(Request.Get("https://api.example.com/data/" + i), progressCallback);
}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.
future.get()import org.apache.http.client.fluent.*;
import org.apache.http.concurrent.FutureCallback;
import java.util.concurrent.*;
import java.util.List;
import java.util.ArrayList;
public class AsyncExample {
public static void main(String[] args) {
// Custom thread pool
ExecutorService threadPool = Executors.newFixedThreadPool(3);
// Authenticated HTTP executor
Executor httpExecutor = Executor.newInstance()
.auth("api.example.com", "username", "password");
// Async with custom configuration
Async async = Async.newInstance()
.use(httpExecutor)
.use(threadPool);
try {
// Multiple concurrent requests
List<Future<Content>> futures = new ArrayList<>();
futures.add(async.execute(Request.Get("https://api.example.com/users")));
futures.add(async.execute(Request.Get("https://api.example.com/orders")));
futures.add(async.execute(Request.Get("https://api.example.com/products")));
// Process results with timeout
for (Future<Content> future : futures) {
try {
Content content = future.get(10, TimeUnit.SECONDS);
System.out.println("Response length: " + content.asBytes().length);
} catch (TimeoutException e) {
System.err.println("Request timed out");
future.cancel(true);
} catch (ExecutionException e) {
System.err.println("Request failed: " + e.getCause().getMessage());
}
}
} catch (InterruptedException e) {
System.err.println("Interrupted: " + e.getMessage());
Thread.currentThread().interrupt();
} finally {
// Clean up resources
threadPool.shutdown();
Executor.closeIdleConnections();
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-apache-httpcomponents--fluent-hc