CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-javax-servlet--javax-servlet-api

Java Servlet API specification defining core interfaces and classes for web application development

Pending
Overview
Eval results
Files

async-processing.mddocs/

Asynchronous Processing and I/O

The Java Servlet API provides comprehensive support for asynchronous request processing and non-blocking I/O operations. This enables scalable web applications that can handle many concurrent connections efficiently without blocking threads.

AsyncContext Interface

/**
 * Interface representing the execution context for an asynchronous operation
 * that was initiated on a ServletRequest.
 */
public interface AsyncContext {
    
    // Request attribute constants for async context information
    public static final String ASYNC_REQUEST_URI = "javax.servlet.async.request_uri";
    public static final String ASYNC_CONTEXT_PATH = "javax.servlet.async.context_path";
    public static final String ASYNC_MAPPING = "javax.servlet.async.mapping";
    public static final String ASYNC_PATH_INFO = "javax.servlet.async.path_info";
    public static final String ASYNC_SERVLET_PATH = "javax.servlet.async.servlet_path";
    public static final String ASYNC_QUERY_STRING = "javax.servlet.async.query_string";
    
    /**
     * Get the original ServletRequest that was used to initialize this AsyncContext.
     */
    ServletRequest getRequest();
    
    /**
     * Get the original ServletResponse that was used to initialize this AsyncContext.
     */
    ServletResponse getResponse();
    
    /**
     * Check if this AsyncContext was initialized with the original or wrapped
     * ServletRequest and ServletResponse objects.
     */
    boolean hasOriginalRequestAndResponse();
    
    /**
     * Dispatch the request and response to the container for processing.
     * Uses the original request URI.
     */
    void dispatch();
    
    /**
     * Dispatch the request and response to the specified path.
     */
    void dispatch(String path);
    
    /**
     * Dispatch the request and response to the specified context and path.
     */
    void dispatch(ServletContext context, String path);
    
    /**
     * Complete the asynchronous operation and close the response.
     */
    void complete();
    
    /**
     * Start a new thread to process the asynchronous operation.
     */
    void start(Runnable run);
    
    /**
     * Add an AsyncListener to receive notifications about async events.
     */
    void addListener(AsyncListener listener);
    
    /**
     * Add an AsyncListener with associated request and response objects.
     */
    void addListener(AsyncListener listener, ServletRequest servletRequest, 
                    ServletResponse servletResponse);
    
    /**
     * Create and return an AsyncListener instance.
     */
    <T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException;
    
    /**
     * Set the timeout for this asynchronous operation in milliseconds.
     */
    void setTimeout(long timeout);
    
    /**
     * Get the timeout for this asynchronous operation in milliseconds.
     */
    long getTimeout();
}

AsyncListener Interface

/**
 * Listener interface for receiving notifications about asynchronous operations.
 */
public interface AsyncListener extends EventListener {
    
    /**
     * Called when an asynchronous operation has completed.
     */
    void onComplete(AsyncEvent event) throws IOException;
    
    /**
     * Called when an asynchronous operation has timed out.
     */
    void onTimeout(AsyncEvent event) throws IOException;
    
    /**
     * Called when an asynchronous operation has failed or encountered an error.
     */
    void onError(AsyncEvent event) throws IOException;
    
    /**
     * Called when a new asynchronous operation is started.
     */
    void onStartAsync(AsyncEvent event) throws IOException;
}

AsyncEvent Class

/**
 * Event class representing an asynchronous operation event.
 */
public class AsyncEvent {
    
    private AsyncContext asyncContext;
    private ServletRequest suppliedRequest;
    private ServletResponse suppliedResponse;
    private Throwable throwable;
    
    /**
     * Create an AsyncEvent with the specified AsyncContext.
     */
    public AsyncEvent(AsyncContext context) {
        this(context, null, null, null);
    }
    
    /**
     * Create an AsyncEvent with AsyncContext and associated request/response.
     */
    public AsyncEvent(AsyncContext context, ServletRequest suppliedRequest, 
                     ServletResponse suppliedResponse) {
        this(context, suppliedRequest, suppliedResponse, null);
    }
    
    /**
     * Create an AsyncEvent with AsyncContext and throwable.
     */
    public AsyncEvent(AsyncContext context, Throwable throwable) {
        this(context, null, null, throwable);
    }
    
    /**
     * Create an AsyncEvent with all parameters.
     */
    public AsyncEvent(AsyncContext context, ServletRequest suppliedRequest, 
                     ServletResponse suppliedResponse, Throwable throwable) {
        this.asyncContext = context;
        this.suppliedRequest = suppliedRequest;
        this.suppliedResponse = suppliedResponse;
        this.throwable = throwable;
    }
    
    /**
     * Get the AsyncContext associated with this event.
     */
    public AsyncContext getAsyncContext() {
        return asyncContext;
    }
    
    /**
     * Get the ServletRequest supplied when the AsyncContext was created.
     */
    public ServletRequest getSuppliedRequest() {
        return suppliedRequest;
    }
    
    /**
     * Get the ServletResponse supplied when the AsyncContext was created.
     */
    public ServletResponse getSuppliedResponse() {
        return suppliedResponse;
    }
    
    /**
     * Get the throwable that caused the async operation to fail.
     */
    public Throwable getThrowable() {
        return throwable;
    }
}

Non-Blocking I/O Interfaces

ReadListener Interface

/**
 * Listener interface for non-blocking read operations on ServletInputStream.
 */
public interface ReadListener extends EventListener {
    
    /**
     * Called when data is available to be read from the input stream.
     * This method should read all available data.
     */
    void onDataAvailable() throws IOException;
    
    /**
     * Called when all data has been read from the input stream.
     */
    void onAllDataRead() throws IOException;
    
    /**
     * Called when an error occurs during a non-blocking read operation.
     */
    void onError(Throwable t);
}

WriteListener Interface

/**
 * Listener interface for non-blocking write operations on ServletOutputStream.
 */
public interface WriteListener extends EventListener {
    
    /**
     * Called when it's possible to write data to the output stream.
     * This method should write all pending data.
     */
    void onWritePossible() throws IOException;
    
    /**
     * Called when an error occurs during a non-blocking write operation.
     */
    void onError(Throwable t);
}

Enhanced ServletInputStream

/**
 * Enhanced ServletInputStream with non-blocking I/O support.
 */
public abstract class ServletInputStream extends InputStream {
    
    /**
     * Read a line from the input stream into a byte array.
     * Legacy method from earlier servlet versions.
     */
    public int readLine(byte[] b, int off, int len) throws IOException {
        if (len <= 0) {
            return 0;
        }
        int count = 0, c;
        
        while ((c = read()) != -1) {
            b[off++] = (byte) c;
            count++;
            if (c == '\n' || count == len) {
                break;
            }
        }
        return count > 0 ? count : -1;
    }
    
    /**
     * Check if all data has been read from the input stream.
     */
    public abstract boolean isFinished();
    
    /**
     * Check if data can be read from the input stream without blocking.
     */
    public abstract boolean isReady();
    
    /**
     * Set a ReadListener for non-blocking I/O operations.
     * The container will invoke the listener when data becomes available.
     */
    public abstract void setReadListener(ReadListener readListener);
}

Enhanced ServletOutputStream

/**
 * Enhanced ServletOutputStream with non-blocking I/O support.
 */
public abstract class ServletOutputStream extends OutputStream {
    
    /**
     * Write a string to the output stream.
     */
    public void print(String s) throws IOException {
        if (s == null) s = "null";
        int len = s.length();
        byte[] out = new byte[len];
        for (int i = 0; i < len; i++) {
            out[i] = (byte) s.charAt(i);
        }
        write(out, 0, len);
    }
    
    /**
     * Write a boolean value to the output stream.
     */
    public void print(boolean b) throws IOException {
        print(b ? "true" : "false");
    }
    
    /**
     * Write a character to the output stream.
     */
    public void print(char c) throws IOException {
        print(String.valueOf(c));
    }
    
    /**
     * Write an integer to the output stream.
     */
    public void print(int i) throws IOException {
        print(String.valueOf(i));
    }
    
    /**
     * Write a long value to the output stream.
     */
    public void print(long l) throws IOException {
        print(String.valueOf(l));
    }
    
    /**
     * Write a float value to the output stream.
     */
    public void print(float f) throws IOException {
        print(String.valueOf(f));
    }
    
    /**
     * Write a double value to the output stream.
     */
    public void print(double d) throws IOException {
        print(String.valueOf(d));
    }
    
    /**
     * Write a line separator to the output stream.
     */
    public void println() throws IOException {
        print("\r\n");
    }
    
    /**
     * Write a string followed by a line separator.
     */
    public void println(String s) throws IOException {
        print(s);
        println();
    }
    
    /**
     * Write a boolean followed by a line separator.
     */
    public void println(boolean b) throws IOException {
        print(b);
        println();
    }
    
    /**
     * Write a character followed by a line separator.
     */
    public void println(char c) throws IOException {
        print(c);
        println();
    }
    
    /**
     * Write an integer followed by a line separator.
     */
    public void println(int i) throws IOException {
        print(i);
        println();
    }
    
    /**
     * Write a long followed by a line separator.
     */
    public void println(long l) throws IOException {
        print(l);
        println();
    }
    
    /**
     * Write a float followed by a line separator.
     */
    public void println(float f) throws IOException {
        print(f);
        println();
    }
    
    /**
     * Write a double followed by a line separator.
     */
    public void println(double d) throws IOException {
        print(d);
        println();
    }
    
    /**
     * Check if data can be written to the output stream without blocking.
     */
    public abstract boolean isReady();
    
    /**
     * Set a WriteListener for non-blocking I/O operations.
     * The container will invoke the listener when writing becomes possible.
     */
    public abstract void setWriteListener(WriteListener writeListener);
}

Asynchronous Processing Examples

Basic Async Servlet

/**
 * Basic asynchronous servlet example
 */
@WebServlet(value = "/async-basic", asyncSupported = true)
public class BasicAsyncServlet extends HttpServlet {
    
    private ExecutorService executor = Executors.newCachedThreadPool();
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        // Start asynchronous processing
        AsyncContext asyncContext = request.startAsync();
        
        // Set timeout (30 seconds)
        asyncContext.setTimeout(30000);
        
        // Add async listener for event handling
        asyncContext.addListener(new AsyncListener() {
            @Override
            public void onComplete(AsyncEvent event) throws IOException {
                System.out.println("Async operation completed");
            }
            
            @Override
            public void onTimeout(AsyncEvent event) throws IOException {
                System.out.println("Async operation timed out");
                AsyncContext ctx = event.getAsyncContext();
                try {
                    ServletResponse resp = ctx.getResponse();
                    resp.setContentType("text/plain");
                    resp.getWriter().write("Request timed out");
                } finally {
                    ctx.complete();
                }
            }
            
            @Override
            public void onError(AsyncEvent event) throws IOException {
                System.out.println("Async operation failed: " + event.getThrowable());
                event.getAsyncContext().complete();
            }
            
            @Override
            public void onStartAsync(AsyncEvent event) throws IOException {
                System.out.println("Async operation started");
            }
        });
        
        // Start async work using AsyncContext.start()
        asyncContext.start(new Runnable() {
            @Override
            public void run() {
                try {
                    // Simulate long-running operation
                    Thread.sleep(5000);
                    
                    // Generate response
                    ServletResponse resp = asyncContext.getResponse();
                    resp.setContentType("text/plain;charset=UTF-8");
                    PrintWriter writer = resp.getWriter();
                    writer.write("Async operation completed at " + new Date());
                    writer.flush();
                    
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    asyncContext.complete();
                }
            }
        });
    }
    
    @Override
    public void destroy() {
        executor.shutdown();
        try {
            if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
    }
}

Advanced Async Processing with Thread Pool

/**
 * Advanced asynchronous servlet with custom thread pool and error handling
 */
@WebServlet(value = "/async-advanced", asyncSupported = true)
public class AdvancedAsyncServlet extends HttpServlet {
    
    private ExecutorService executor;
    private ScheduledExecutorService scheduler;
    
    @Override
    public void init() throws ServletException {
        // Create custom thread pools
        executor = Executors.newFixedThreadPool(10, r -> {
            Thread t = new Thread(r, "AsyncProcessor-" + System.currentTimeMillis());
            t.setDaemon(true);
            return t;
        });
        
        scheduler = Executors.newScheduledThreadPool(2, r -> {
            Thread t = new Thread(r, "AsyncScheduler-" + System.currentTimeMillis());
            t.setDaemon(true);
            return t;
        });
    }
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        String operation = request.getParameter("operation");
        String delayParam = request.getParameter("delay");
        
        int delay = 1000; // Default 1 second
        if (delayParam != null) {
            try {
                delay = Integer.parseInt(delayParam);
            } catch (NumberFormatException e) {
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid delay parameter");
                return;
            }
        }
        
        AsyncContext asyncContext = request.startAsync(request, response);
        asyncContext.setTimeout(60000); // 60 second timeout
        
        // Add comprehensive async listener
        asyncContext.addListener(new ComprehensiveAsyncListener());
        
        // Submit async task based on operation type
        switch (operation != null ? operation : "default") {
            case "immediate":
                handleImmediateResponse(asyncContext);
                break;
            case "delayed":
                handleDelayedResponse(asyncContext, delay);
                break;
            case "stream":
                handleStreamingResponse(asyncContext);
                break;
            case "error":
                handleErrorResponse(asyncContext);
                break;
            default:
                handleDefaultResponse(asyncContext, delay);
        }
    }
    
    private void handleImmediateResponse(AsyncContext asyncContext) {
        executor.submit(() -> {
            try {
                ServletResponse response = asyncContext.getResponse();
                response.setContentType("application/json;charset=UTF-8");
                
                PrintWriter writer = response.getWriter();
                writer.write("{");
                writer.write("\"status\":\"success\",");
                writer.write("\"message\":\"Immediate response\",");
                writer.write("\"timestamp\":\"" + Instant.now() + "\"");
                writer.write("}");
                writer.flush();
                
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                asyncContext.complete();
            }
        });
    }
    
    private void handleDelayedResponse(AsyncContext asyncContext, int delay) {
        scheduler.schedule(() -> {
            try {
                ServletResponse response = asyncContext.getResponse();
                response.setContentType("application/json;charset=UTF-8");
                
                PrintWriter writer = response.getWriter();
                writer.write("{");
                writer.write("\"status\":\"success\",");
                writer.write("\"message\":\"Delayed response after " + delay + "ms\",");
                writer.write("\"timestamp\":\"" + Instant.now() + "\"");
                writer.write("}");
                writer.flush();
                
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                asyncContext.complete();
            }
        }, delay, TimeUnit.MILLISECONDS);
    }
    
    private void handleStreamingResponse(AsyncContext asyncContext) {
        executor.submit(() -> {
            try {
                ServletResponse response = asyncContext.getResponse();
                response.setContentType("text/plain;charset=UTF-8");
                
                PrintWriter writer = response.getWriter();
                
                // Send chunked response
                for (int i = 1; i <= 10; i++) {
                    writer.println("Chunk " + i + " sent at " + Instant.now());
                    writer.flush();
                    
                    Thread.sleep(500); // Delay between chunks
                }
                
                writer.println("Streaming completed");
                writer.flush();
                
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                asyncContext.complete();
            }
        });
    }
    
    private void handleErrorResponse(AsyncContext asyncContext) {
        executor.submit(() -> {
            try {
                // Simulate processing delay
                Thread.sleep(1000);
                
                // Intentionally throw an error
                throw new RuntimeException("Simulated async error");
                
            } catch (Exception e) {
                try {
                    ServletResponse response = asyncContext.getResponse();
                    response.setContentType("application/json;charset=UTF-8");
                    
                    if (!response.isCommitted()) {
                        PrintWriter writer = response.getWriter();
                        writer.write("{");
                        writer.write("\"status\":\"error\",");
                        writer.write("\"message\":\"" + e.getMessage() + "\",");
                        writer.write("\"timestamp\":\"" + Instant.now() + "\"");
                        writer.write("}");
                        writer.flush();
                    }
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                } finally {
                    asyncContext.complete();
                }
            }
        });
    }
    
    private void handleDefaultResponse(AsyncContext asyncContext, int delay) {
        CompletableFuture
            .supplyAsync(() -> {
                try {
                    Thread.sleep(delay);
                    return "Processing completed after " + delay + "ms";
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }, executor)
            .whenComplete((result, throwable) -> {
                try {
                    ServletResponse response = asyncContext.getResponse();
                    response.setContentType("application/json;charset=UTF-8");
                    
                    PrintWriter writer = response.getWriter();
                    if (throwable == null) {
                        writer.write("{");
                        writer.write("\"status\":\"success\",");
                        writer.write("\"message\":\"" + result + "\",");
                        writer.write("\"timestamp\":\"" + Instant.now() + "\"");
                        writer.write("}");
                    } else {
                        writer.write("{");
                        writer.write("\"status\":\"error\",");
                        writer.write("\"message\":\"" + throwable.getMessage() + "\",");
                        writer.write("\"timestamp\":\"" + Instant.now() + "\"");
                        writer.write("}");
                    }
                    writer.flush();
                    
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    asyncContext.complete();
                }
            });
    }
    
    private class ComprehensiveAsyncListener implements AsyncListener {
        @Override
        public void onComplete(AsyncEvent event) throws IOException {
            System.out.println("Async request completed successfully");
        }
        
        @Override
        public void onTimeout(AsyncEvent event) throws IOException {
            System.out.println("Async request timed out");
            
            AsyncContext ctx = event.getAsyncContext();
            try {
                ServletResponse response = ctx.getResponse();
                if (!response.isCommitted()) {
                    response.setContentType("application/json;charset=UTF-8");
                    PrintWriter writer = response.getWriter();
                    writer.write("{");
                    writer.write("\"status\":\"timeout\",");
                    writer.write("\"message\":\"Request processing timed out\",");
                    writer.write("\"timestamp\":\"" + Instant.now() + "\"");
                    writer.write("}");
                    writer.flush();
                }
            } finally {
                ctx.complete();
            }
        }
        
        @Override
        public void onError(AsyncEvent event) throws IOException {
            Throwable throwable = event.getThrowable();
            System.out.println("Async request failed: " + throwable.getMessage());
            
            AsyncContext ctx = event.getAsyncContext();
            try {
                ServletResponse response = ctx.getResponse();
                if (!response.isCommitted()) {
                    response.setContentType("application/json;charset=UTF-8");
                    PrintWriter writer = response.getWriter();
                    writer.write("{");
                    writer.write("\"status\":\"error\",");
                    writer.write("\"message\":\"" + throwable.getMessage() + "\",");
                    writer.write("\"timestamp\":\"" + Instant.now() + "\"");
                    writer.write("}");
                    writer.flush();
                }
            } finally {
                ctx.complete();
            }
        }
        
        @Override
        public void onStartAsync(AsyncEvent event) throws IOException {
            System.out.println("Async request started");
        }
    }
    
    @Override
    public void destroy() {
        executor.shutdown();
        scheduler.shutdown();
        try {
            if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
            if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                scheduler.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            scheduler.shutdownNow();
        }
    }
}

Non-Blocking I/O Examples

Non-Blocking Read Example

/**
 * Servlet demonstrating non-blocking input stream reading
 */
@WebServlet(value = "/non-blocking-read", asyncSupported = true)
public class NonBlockingReadServlet extends HttpServlet {
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        AsyncContext asyncContext = request.startAsync();
        asyncContext.setTimeout(30000);
        
        ServletInputStream inputStream = request.getInputStream();
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        
        inputStream.setReadListener(new ReadListener() {
            @Override
            public void onDataAvailable() throws IOException {
                // Read all available data
                byte[] data = new byte[1024];
                int bytesRead;
                
                while (inputStream.isReady() && (bytesRead = inputStream.read(data)) != -1) {
                    buffer.write(data, 0, bytesRead);
                }
            }
            
            @Override
            public void onAllDataRead() throws IOException {
                try {
                    // Process the complete request data
                    String requestData = buffer.toString("UTF-8");
                    String processedData = processData(requestData);
                    
                    // Send response
                    ServletResponse resp = asyncContext.getResponse();
                    resp.setContentType("application/json;charset=UTF-8");
                    
                    PrintWriter writer = resp.getWriter();
                    writer.write("{");
                    writer.write("\"status\":\"success\",");
                    writer.write("\"originalSize\":" + requestData.length() + ",");
                    writer.write("\"processedData\":\"" + processedData + "\",");
                    writer.write("\"timestamp\":\"" + Instant.now() + "\"");
                    writer.write("}");
                    writer.flush();
                    
                } finally {
                    asyncContext.complete();
                }
            }
            
            @Override
            public void onError(Throwable t) {
                System.err.println("Error reading request data: " + t.getMessage());
                try {
                    ServletResponse resp = asyncContext.getResponse();
                    if (!resp.isCommitted()) {
                        resp.setContentType("application/json;charset=UTF-8");
                        PrintWriter writer = resp.getWriter();
                        writer.write("{");
                        writer.write("\"status\":\"error\",");
                        writer.write("\"message\":\"" + t.getMessage() + "\"");
                        writer.write("}");
                        writer.flush();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    asyncContext.complete();
                }
            }
        });
    }
    
    private String processData(String data) {
        // Simulate data processing
        return data.toUpperCase().replaceAll("\\s+", "_");
    }
}

Non-Blocking Write Example

/**
 * Servlet demonstrating non-blocking output stream writing
 */
@WebServlet(value = "/non-blocking-write", asyncSupported = true)
public class NonBlockingWriteServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        AsyncContext asyncContext = request.startAsync();
        asyncContext.setTimeout(60000);
        
        response.setContentType("text/plain;charset=UTF-8");
        ServletOutputStream outputStream = response.getOutputStream();
        
        // Generate large amount of data to write
        Queue<String> dataQueue = generateLargeDataSet();
        
        outputStream.setWriteListener(new WriteListener() {
            @Override
            public void onWritePossible() throws IOException {
                // Write data while the output stream is ready
                while (outputStream.isReady() && !dataQueue.isEmpty()) {
                    String data = dataQueue.poll();
                    outputStream.print(data);
                    outputStream.println(); // Add line separator
                }
                
                // Check if all data has been written
                if (dataQueue.isEmpty()) {
                    outputStream.println("=== End of Data ===");
                    asyncContext.complete();
                }
            }
            
            @Override
            public void onError(Throwable t) {
                System.err.println("Error writing response data: " + t.getMessage());
                asyncContext.complete();
            }
        });
    }
    
    private Queue<String> generateLargeDataSet() {
        Queue<String> data = new LinkedList<>();
        
        // Generate 1000 lines of sample data
        for (int i = 1; i <= 1000; i++) {
            data.offer("Line " + i + ": This is sample data generated at " + 
                      Instant.now() + " with some additional content to make it longer.");
        }
        
        return data;
    }
}

File Upload with Non-Blocking I/O

/**
 * Servlet for handling file uploads with non-blocking I/O
 */
@WebServlet(value = "/upload-async", asyncSupported = true)
@MultipartConfig(
    location = "/tmp",
    fileSizeThreshold = 1024 * 1024,    // 1 MB
    maxFileSize = 1024 * 1024 * 50,     // 50 MB
    maxRequestSize = 1024 * 1024 * 100  // 100 MB
)
public class AsyncFileUploadServlet extends HttpServlet {
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        AsyncContext asyncContext = request.startAsync();
        asyncContext.setTimeout(300000); // 5 minutes for large uploads
        
        // Process multipart request asynchronously
        CompletableFuture.runAsync(() -> {
            try {
                Collection<Part> parts = request.getParts();
                List<String> uploadedFiles = new ArrayList<>();
                
                for (Part part : parts) {
                    if (part.getName().equals("file") && part.getSize() > 0) {
                        String fileName = getSubmittedFileName(part);
                        String uploadPath = saveFileAsync(part, fileName);
                        uploadedFiles.add(fileName + " (" + part.getSize() + " bytes)");
                    }
                }
                
                // Send success response
                ServletResponse resp = asyncContext.getResponse();
                resp.setContentType("application/json;charset=UTF-8");
                
                PrintWriter writer = resp.getWriter();
                writer.write("{");
                writer.write("\"status\":\"success\",");
                writer.write("\"filesUploaded\":" + uploadedFiles.size() + ",");
                writer.write("\"files\":[");
                for (int i = 0; i < uploadedFiles.size(); i++) {
                    if (i > 0) writer.write(",");
                    writer.write("\"" + uploadedFiles.get(i) + "\"");
                }
                writer.write("],");
                writer.write("\"timestamp\":\"" + Instant.now() + "\"");
                writer.write("}");
                writer.flush();
                
            } catch (Exception e) {
                try {
                    ServletResponse resp = asyncContext.getResponse();
                    if (!resp.isCommitted()) {
                        resp.setContentType("application/json;charset=UTF-8");
                        PrintWriter writer = resp.getWriter();
                        writer.write("{");
                        writer.write("\"status\":\"error\",");
                        writer.write("\"message\":\"" + e.getMessage() + "\"");
                        writer.write("}");
                        writer.flush();
                    }
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            } finally {
                asyncContext.complete();
            }
        });
    }
    
    private String saveFileAsync(Part part, String fileName) throws IOException {
        String uploadDir = getServletContext().getRealPath("/uploads");
        Files.createDirectories(Paths.get(uploadDir));
        
        String filePath = uploadDir + File.separator + 
                         System.currentTimeMillis() + "_" + fileName;
        
        // Save file using NIO for better performance
        try (InputStream input = part.getInputStream()) {
            Files.copy(input, Paths.get(filePath), StandardCopyOption.REPLACE_EXISTING);
        }
        
        return filePath;
    }
    
    private String getSubmittedFileName(Part part) {
        String contentDisposition = part.getHeader("Content-Disposition");
        if (contentDisposition != null) {
            String[] elements = contentDisposition.split(";");
            for (String element : elements) {
                if (element.trim().startsWith("filename")) {
                    return element.substring(element.indexOf('=') + 1)
                                 .trim().replace("\"", "");
                }
            }
        }
        return "unknown_" + System.currentTimeMillis();
    }
}

This comprehensive coverage of asynchronous processing and non-blocking I/O provides all the tools needed for building scalable, high-performance servlet applications that can handle many concurrent connections efficiently.

Install with Tessl CLI

npx tessl i tessl/maven-javax-servlet--javax-servlet-api

docs

async-processing.md

http-processing.md

index.md

listeners-events.md

security-filtering.md

servlet-lifecycle.md

session-cookies.md

tile.json