CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-eclipse-jetty--jetty-client

Eclipse Jetty HTTP Client - A lightweight, asynchronous HTTP client library that supports HTTP/1.1, HTTP/2, WebSocket, and various authentication mechanisms, proxy configurations, and connection pooling strategies.

Pending
Overview
Eval results
Files

response-processing.mddocs/

Response Processing

The response processing capability provides comprehensive response handling including status codes, headers, content processing, and streaming capabilities with multiple listener patterns for both synchronous and asynchronous response handling.

Response Interface

The core interface for accessing HTTP response information.

public interface Response {
    // Request association
    Request getRequest();
    
    // Status information
    HttpVersion getVersion();
    int getStatus();
    String getReason();
    
    // Headers and trailers
    HttpFields getHeaders();
    HttpFields getTrailers();
    
    // Listener interfaces for event-driven processing
    interface Listener extends EventListener {
        default void onBegin(Response response) {}
        default void onHeader(Response response, HttpField field) {}
        default void onHeaders(Response response) {}
        default void onContent(Response response, ByteBuffer content) {}
        default void onSuccess(Response response) {}
        default void onFailure(Response response, Throwable failure) {}
        default void onComplete(Result result) {}
    }
    
    interface CompleteListener extends Listener {
        void onComplete(Result result);
    }
    
    interface BeginListener extends EventListener {
        void onBegin(Response response);
    }
    
    interface HeaderListener extends EventListener {
        void onHeader(Response response, HttpField field);
    }
    
    interface HeadersListener extends EventListener {
        void onHeaders(Response response);
    }
    
    interface ContentListener extends EventListener {
        void onContent(Response response, ByteBuffer content);
    }
    
    interface DemandedContentListener extends EventListener {
        void onContent(Response response, LongConsumer demand, ByteBuffer content);
    }
    
    interface SuccessListener extends EventListener {
        void onSuccess(Response response);
    }
    
    interface FailureListener extends EventListener {
        void onFailure(Response response, Throwable failure);
    }
}

ContentResponse Interface

Extended response interface that provides access to buffered response content.

public interface ContentResponse extends Response {
    // Content access
    String getMediaType();
    String getEncoding();
    byte[] getContent();
    String getContentAsString();
    String getContentAsString(String encoding);
    
    // Factory method
    static ContentResponse from(Response response, byte[] content, String mediaType, String encoding);
}

Basic Response Access

Synchronous Response Handling

ContentResponse response = client.GET("https://api.example.com/users");

// Status information
int status = response.getStatus();
String reason = response.getReason();
HttpVersion version = response.getVersion();

System.out.println("Status: " + status + " " + reason);
System.out.println("HTTP Version: " + version);

// Content access
byte[] contentBytes = response.getContent();
String contentString = response.getContentAsString();
String mediaType = response.getMediaType();
String encoding = response.getEncoding();

System.out.println("Content Type: " + mediaType);
System.out.println("Content Length: " + contentBytes.length);
System.out.println("Content: " + contentString);

Response Headers

ContentResponse response = client.GET("https://api.example.com/data");

HttpFields headers = response.getHeaders();

// Access specific headers
String contentType = headers.get("Content-Type");
String serverHeader = headers.get("Server");
String cacheControl = headers.get("Cache-Control");

// Iterate through all headers
for (HttpField field : headers) {
    System.out.println(field.getName() + ": " + field.getValue());
}

// Check for header existence
if (headers.contains("X-Rate-Limit-Remaining")) {
    String rateLimit = headers.get("X-Rate-Limit-Remaining");
    System.out.println("Remaining requests: " + rateLimit);
}

Asynchronous Response Processing

Using Response Listeners

Process responses as they arrive without blocking:

client.newRequest("https://api.example.com/stream")
    .send(new Response.Listener() {
        @Override
        public void onBegin(Response response) {
            System.out.println("Response begun: " + response.getStatus());
        }
        
        @Override
        public void onHeaders(Response response) {
            HttpFields headers = response.getHeaders();
            String contentType = headers.get("Content-Type");
            System.out.println("Content-Type: " + contentType);
        }
        
        @Override
        public void onContent(Response response, ByteBuffer content) {
            // Process content as it arrives
            byte[] bytes = new byte[content.remaining()];
            content.get(bytes);
            System.out.println("Received chunk: " + bytes.length + " bytes");
        }
        
        @Override
        public void onSuccess(Response response) {
            System.out.println("Response completed successfully");
        }
        
        @Override
        public void onFailure(Response response, Throwable failure) {
            System.err.println("Response failed: " + failure.getMessage());
        }
    });

Using Complete Listener

Simplified listener for complete response handling:

client.newRequest("https://api.example.com/data")
    .send(result -> {
        if (result.isSucceeded()) {
            Response response = result.getResponse();
            System.out.println("Success: " + response.getStatus());
            
            // Access request that generated this response
            Request request = result.getRequest();
            System.out.println("Original URL: " + request.getURI());
        } else {
            Throwable failure = result.getFailure();
            System.err.println("Request failed: " + failure.getMessage());
        }
    });

Specialized Response Listeners

BufferingResponseListener

Automatically buffers response content in memory:

public class BufferingResponseListener extends Response.Listener.Adapter {
    public BufferingResponseListener();
    public BufferingResponseListener(int maxLength);
    
    public byte[] getContent();
    public String getContentAsString();
    public String getContentAsString(String encoding);
    public String getMediaType();
    public String getEncoding();
}
BufferingResponseListener listener = new BufferingResponseListener();

client.newRequest("https://api.example.com/data")
    .send(listener);

// Wait for completion and access buffered content
Response response = listener.get(5, TimeUnit.SECONDS);
byte[] content = listener.getContent();
String contentString = listener.getContentAsString();

InputStreamResponseListener

Provides InputStream access to response content:

public class InputStreamResponseListener extends Response.Listener.Adapter {
    public InputStreamResponseListener();
    
    public InputStream getInputStream();
    public Response get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException, ExecutionException;
}
InputStreamResponseListener listener = new InputStreamResponseListener();

client.newRequest("https://api.example.com/large-file")
    .send(listener);

// Get the InputStream to read content
try (InputStream inputStream = listener.getInputStream()) {
    // Process stream as data arrives
    byte[] buffer = new byte[8192];
    int bytesRead;
    while ((bytesRead = inputStream.read(buffer)) != -1) {
        // Process buffer content
        processData(buffer, 0, bytesRead);
    }
}

PathResponseListener

Saves response content directly to a file:

public class PathResponseListener extends Response.Listener.Adapter {
    public PathResponseListener(Path file);
    public PathResponseListener(Path file, boolean overwrite);
    
    public Path getPath();
}
Path downloadPath = Paths.get("/tmp/downloaded-file.zip");
PathResponseListener listener = new PathResponseListener(downloadPath, true);

client.newRequest("https://api.example.com/download/file.zip")
    .send(listener);

// Wait for download completion
Response response = listener.get(30, TimeUnit.SECONDS);
if (response.getStatus() == 200) {
    System.out.println("File downloaded to: " + downloadPath);
}

FutureResponseListener

CompletableFuture-based response handling:

public class FutureResponseListener extends BufferingResponseListener implements Future<ContentResponse> {
    public FutureResponseListener(Request request);
    public FutureResponseListener(Request request, int maxLength);
}
Request request = client.newRequest("https://api.example.com/data");
FutureResponseListener listener = new FutureResponseListener(request);

request.send(listener);

// Use as Future
ContentResponse response = listener.get(10, TimeUnit.SECONDS);
String content = response.getContentAsString();

Result Interface

The Result interface provides access to the complete request/response cycle:

public interface Result {
    Request getRequest();
    Response getResponse();
    Throwable getRequestFailure();
    Throwable getResponseFailure();
    boolean isSucceeded();
    boolean isFailed();
}

Result Processing

client.newRequest("https://api.example.com/data")
    .send(result -> {
        Request request = result.getRequest();
        System.out.println("Request URL: " + request.getURI());
        
        if (result.isSucceeded()) {
            Response response = result.getResponse();
            System.out.println("Response status: " + response.getStatus());
        } else {
            // Check for request vs response failures
            Throwable requestFailure = result.getRequestFailure();
            Throwable responseFailure = result.getResponseFailure();
            
            if (requestFailure != null) {
                System.err.println("Request failed: " + requestFailure.getMessage());
            }
            if (responseFailure != null) {
                System.err.println("Response failed: " + responseFailure.getMessage());
            }
        }
    });

Status Code Handling

Common Status Code Patterns

ContentResponse response = client.GET("https://api.example.com/resource");

switch (response.getStatus()) {
    case 200:
        // OK - process successful response
        String content = response.getContentAsString();
        break;
        
    case 201:
        // Created - resource created successfully
        String location = response.getHeaders().get("Location");
        break;
        
    case 204:
        // No Content - successful operation with no response body
        break;
        
    case 301:
    case 302:
        // Redirects - typically handled automatically by client
        String location = response.getHeaders().get("Location");
        break;
        
    case 400:
        // Bad Request - client error
        String errorDetails = response.getContentAsString();
        throw new IllegalArgumentException("Bad request: " + errorDetails);
        
    case 401:
        // Unauthorized - authentication required
        throw new SecurityException("Authentication required");
        
    case 403:
        // Forbidden - access denied
        throw new SecurityException("Access forbidden");
        
    case 404:
        // Not Found - resource doesn't exist
        throw new IllegalArgumentException("Resource not found");
        
    case 429:
        // Too Many Requests - rate limiting
        String retryAfter = response.getHeaders().get("Retry-After");
        throw new RuntimeException("Rate limited. Retry after: " + retryAfter);
        
    case 500:
        // Internal Server Error
        throw new RuntimeException("Server error: " + response.getReason());
        
    default:
        if (response.getStatus() >= 400) {
            throw new RuntimeException("HTTP error: " + response.getStatus() + " " + response.getReason());
        }
}

Status Code Categories

ContentResponse response = client.GET("https://api.example.com/data");
int status = response.getStatus();

if (status >= 200 && status < 300) {
    // Success responses
    handleSuccess(response);
} else if (status >= 300 && status < 400) {
    // Redirection responses (usually handled automatically)
    handleRedirect(response);
} else if (status >= 400 && status < 500) {
    // Client error responses
    handleClientError(response);
} else if (status >= 500) {
    // Server error responses
    handleServerError(response);
}

Advanced Response Processing

Content Type Processing

ContentResponse response = client.GET("https://api.example.com/data");

String contentType = response.getMediaType();
String encoding = response.getEncoding();

if ("application/json".equals(contentType)) {
    String json = response.getContentAsString();
    // Parse JSON content
} else if ("application/xml".equals(contentType)) {
    String xml = response.getContentAsString();
    // Parse XML content
} else if (contentType != null && contentType.startsWith("text/")) {
    String text = response.getContentAsString(encoding);
    // Process text content
} else {
    byte[] binaryData = response.getContent();
    // Process binary content
}

Large Response Streaming

client.newRequest("https://api.example.com/large-dataset")
    .send(new Response.Listener() {
        private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        
        @Override
        public void onContent(Response response, ByteBuffer content) {
            // Stream content to avoid memory issues
            byte[] bytes = new byte[content.remaining()];
            content.get(bytes);
            
            try {
                buffer.write(bytes);
                
                // Process buffer when it reaches a certain size
                if (buffer.size() > 64 * 1024) { // 64KB chunks
                    processChunk(buffer.toByteArray());
                    buffer.reset();
                }
            } catch (IOException e) {
                throw new RuntimeException("Failed to process content", e);
            }
        }
        
        @Override
        public void onSuccess(Response response) {
            // Process any remaining content
            if (buffer.size() > 0) {
                processChunk(buffer.toByteArray());
            }
        }
    });

Response Validation

public class ValidatingResponseListener extends Response.Listener.Adapter {
    @Override
    public void onHeaders(Response response) {
        // Validate response headers
        HttpFields headers = response.getHeaders();
        
        String contentType = headers.get("Content-Type");
        if (contentType == null || !contentType.startsWith("application/json")) {
            throw new IllegalStateException("Expected JSON response, got: " + contentType);
        }
        
        String contentLength = headers.get("Content-Length");
        if (contentLength != null) {
            long length = Long.parseLong(contentLength);
            if (length > MAX_RESPONSE_SIZE) {
                throw new IllegalStateException("Response too large: " + length);
            }
        }
    }
    
    @Override
    public void onSuccess(Response response) {
        if (response.getStatus() != 200) {
            throw new IllegalStateException("Expected 200 OK, got: " + response.getStatus());
        }
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-eclipse-jetty--jetty-client

docs

authentication.md

connection-pooling.md

content-management.md

http-operations.md

index.md

proxy-configuration.md

request-configuration.md

response-processing.md

tile.json