or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-processing.mdhttp-processing.mdindex.mdlisteners-events.mdsecurity-filtering.mdservlet-lifecycle.mdsession-cookies.md

async-processing.mddocs/

0

# Asynchronous Processing and I/O

1

2

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.

3

4

## AsyncContext Interface

5

6

```java { .api }

7

/**

8

* Interface representing the execution context for an asynchronous operation

9

* that was initiated on a ServletRequest.

10

*/

11

public interface AsyncContext {

12

13

// Request attribute constants for async context information

14

public static final String ASYNC_REQUEST_URI = "javax.servlet.async.request_uri";

15

public static final String ASYNC_CONTEXT_PATH = "javax.servlet.async.context_path";

16

public static final String ASYNC_MAPPING = "javax.servlet.async.mapping";

17

public static final String ASYNC_PATH_INFO = "javax.servlet.async.path_info";

18

public static final String ASYNC_SERVLET_PATH = "javax.servlet.async.servlet_path";

19

public static final String ASYNC_QUERY_STRING = "javax.servlet.async.query_string";

20

21

/**

22

* Get the original ServletRequest that was used to initialize this AsyncContext.

23

*/

24

ServletRequest getRequest();

25

26

/**

27

* Get the original ServletResponse that was used to initialize this AsyncContext.

28

*/

29

ServletResponse getResponse();

30

31

/**

32

* Check if this AsyncContext was initialized with the original or wrapped

33

* ServletRequest and ServletResponse objects.

34

*/

35

boolean hasOriginalRequestAndResponse();

36

37

/**

38

* Dispatch the request and response to the container for processing.

39

* Uses the original request URI.

40

*/

41

void dispatch();

42

43

/**

44

* Dispatch the request and response to the specified path.

45

*/

46

void dispatch(String path);

47

48

/**

49

* Dispatch the request and response to the specified context and path.

50

*/

51

void dispatch(ServletContext context, String path);

52

53

/**

54

* Complete the asynchronous operation and close the response.

55

*/

56

void complete();

57

58

/**

59

* Start a new thread to process the asynchronous operation.

60

*/

61

void start(Runnable run);

62

63

/**

64

* Add an AsyncListener to receive notifications about async events.

65

*/

66

void addListener(AsyncListener listener);

67

68

/**

69

* Add an AsyncListener with associated request and response objects.

70

*/

71

void addListener(AsyncListener listener, ServletRequest servletRequest,

72

ServletResponse servletResponse);

73

74

/**

75

* Create and return an AsyncListener instance.

76

*/

77

<T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException;

78

79

/**

80

* Set the timeout for this asynchronous operation in milliseconds.

81

*/

82

void setTimeout(long timeout);

83

84

/**

85

* Get the timeout for this asynchronous operation in milliseconds.

86

*/

87

long getTimeout();

88

}

89

```

90

91

## AsyncListener Interface

92

93

```java { .api }

94

/**

95

* Listener interface for receiving notifications about asynchronous operations.

96

*/

97

public interface AsyncListener extends EventListener {

98

99

/**

100

* Called when an asynchronous operation has completed.

101

*/

102

void onComplete(AsyncEvent event) throws IOException;

103

104

/**

105

* Called when an asynchronous operation has timed out.

106

*/

107

void onTimeout(AsyncEvent event) throws IOException;

108

109

/**

110

* Called when an asynchronous operation has failed or encountered an error.

111

*/

112

void onError(AsyncEvent event) throws IOException;

113

114

/**

115

* Called when a new asynchronous operation is started.

116

*/

117

void onStartAsync(AsyncEvent event) throws IOException;

118

}

119

```

120

121

## AsyncEvent Class

122

123

```java { .api }

124

/**

125

* Event class representing an asynchronous operation event.

126

*/

127

public class AsyncEvent {

128

129

private AsyncContext asyncContext;

130

private ServletRequest suppliedRequest;

131

private ServletResponse suppliedResponse;

132

private Throwable throwable;

133

134

/**

135

* Create an AsyncEvent with the specified AsyncContext.

136

*/

137

public AsyncEvent(AsyncContext context) {

138

this(context, null, null, null);

139

}

140

141

/**

142

* Create an AsyncEvent with AsyncContext and associated request/response.

143

*/

144

public AsyncEvent(AsyncContext context, ServletRequest suppliedRequest,

145

ServletResponse suppliedResponse) {

146

this(context, suppliedRequest, suppliedResponse, null);

147

}

148

149

/**

150

* Create an AsyncEvent with AsyncContext and throwable.

151

*/

152

public AsyncEvent(AsyncContext context, Throwable throwable) {

153

this(context, null, null, throwable);

154

}

155

156

/**

157

* Create an AsyncEvent with all parameters.

158

*/

159

public AsyncEvent(AsyncContext context, ServletRequest suppliedRequest,

160

ServletResponse suppliedResponse, Throwable throwable) {

161

this.asyncContext = context;

162

this.suppliedRequest = suppliedRequest;

163

this.suppliedResponse = suppliedResponse;

164

this.throwable = throwable;

165

}

166

167

/**

168

* Get the AsyncContext associated with this event.

169

*/

170

public AsyncContext getAsyncContext() {

171

return asyncContext;

172

}

173

174

/**

175

* Get the ServletRequest supplied when the AsyncContext was created.

176

*/

177

public ServletRequest getSuppliedRequest() {

178

return suppliedRequest;

179

}

180

181

/**

182

* Get the ServletResponse supplied when the AsyncContext was created.

183

*/

184

public ServletResponse getSuppliedResponse() {

185

return suppliedResponse;

186

}

187

188

/**

189

* Get the throwable that caused the async operation to fail.

190

*/

191

public Throwable getThrowable() {

192

return throwable;

193

}

194

}

195

```

196

197

## Non-Blocking I/O Interfaces

198

199

### ReadListener Interface

200

201

```java { .api }

202

/**

203

* Listener interface for non-blocking read operations on ServletInputStream.

204

*/

205

public interface ReadListener extends EventListener {

206

207

/**

208

* Called when data is available to be read from the input stream.

209

* This method should read all available data.

210

*/

211

void onDataAvailable() throws IOException;

212

213

/**

214

* Called when all data has been read from the input stream.

215

*/

216

void onAllDataRead() throws IOException;

217

218

/**

219

* Called when an error occurs during a non-blocking read operation.

220

*/

221

void onError(Throwable t);

222

}

223

```

224

225

### WriteListener Interface

226

227

```java { .api }

228

/**

229

* Listener interface for non-blocking write operations on ServletOutputStream.

230

*/

231

public interface WriteListener extends EventListener {

232

233

/**

234

* Called when it's possible to write data to the output stream.

235

* This method should write all pending data.

236

*/

237

void onWritePossible() throws IOException;

238

239

/**

240

* Called when an error occurs during a non-blocking write operation.

241

*/

242

void onError(Throwable t);

243

}

244

```

245

246

## Enhanced ServletInputStream

247

248

```java { .api }

249

/**

250

* Enhanced ServletInputStream with non-blocking I/O support.

251

*/

252

public abstract class ServletInputStream extends InputStream {

253

254

/**

255

* Read a line from the input stream into a byte array.

256

* Legacy method from earlier servlet versions.

257

*/

258

public int readLine(byte[] b, int off, int len) throws IOException {

259

if (len <= 0) {

260

return 0;

261

}

262

int count = 0, c;

263

264

while ((c = read()) != -1) {

265

b[off++] = (byte) c;

266

count++;

267

if (c == '\n' || count == len) {

268

break;

269

}

270

}

271

return count > 0 ? count : -1;

272

}

273

274

/**

275

* Check if all data has been read from the input stream.

276

*/

277

public abstract boolean isFinished();

278

279

/**

280

* Check if data can be read from the input stream without blocking.

281

*/

282

public abstract boolean isReady();

283

284

/**

285

* Set a ReadListener for non-blocking I/O operations.

286

* The container will invoke the listener when data becomes available.

287

*/

288

public abstract void setReadListener(ReadListener readListener);

289

}

290

```

291

292

## Enhanced ServletOutputStream

293

294

```java { .api }

295

/**

296

* Enhanced ServletOutputStream with non-blocking I/O support.

297

*/

298

public abstract class ServletOutputStream extends OutputStream {

299

300

/**

301

* Write a string to the output stream.

302

*/

303

public void print(String s) throws IOException {

304

if (s == null) s = "null";

305

int len = s.length();

306

byte[] out = new byte[len];

307

for (int i = 0; i < len; i++) {

308

out[i] = (byte) s.charAt(i);

309

}

310

write(out, 0, len);

311

}

312

313

/**

314

* Write a boolean value to the output stream.

315

*/

316

public void print(boolean b) throws IOException {

317

print(b ? "true" : "false");

318

}

319

320

/**

321

* Write a character to the output stream.

322

*/

323

public void print(char c) throws IOException {

324

print(String.valueOf(c));

325

}

326

327

/**

328

* Write an integer to the output stream.

329

*/

330

public void print(int i) throws IOException {

331

print(String.valueOf(i));

332

}

333

334

/**

335

* Write a long value to the output stream.

336

*/

337

public void print(long l) throws IOException {

338

print(String.valueOf(l));

339

}

340

341

/**

342

* Write a float value to the output stream.

343

*/

344

public void print(float f) throws IOException {

345

print(String.valueOf(f));

346

}

347

348

/**

349

* Write a double value to the output stream.

350

*/

351

public void print(double d) throws IOException {

352

print(String.valueOf(d));

353

}

354

355

/**

356

* Write a line separator to the output stream.

357

*/

358

public void println() throws IOException {

359

print("\r\n");

360

}

361

362

/**

363

* Write a string followed by a line separator.

364

*/

365

public void println(String s) throws IOException {

366

print(s);

367

println();

368

}

369

370

/**

371

* Write a boolean followed by a line separator.

372

*/

373

public void println(boolean b) throws IOException {

374

print(b);

375

println();

376

}

377

378

/**

379

* Write a character followed by a line separator.

380

*/

381

public void println(char c) throws IOException {

382

print(c);

383

println();

384

}

385

386

/**

387

* Write an integer followed by a line separator.

388

*/

389

public void println(int i) throws IOException {

390

print(i);

391

println();

392

}

393

394

/**

395

* Write a long followed by a line separator.

396

*/

397

public void println(long l) throws IOException {

398

print(l);

399

println();

400

}

401

402

/**

403

* Write a float followed by a line separator.

404

*/

405

public void println(float f) throws IOException {

406

print(f);

407

println();

408

}

409

410

/**

411

* Write a double followed by a line separator.

412

*/

413

public void println(double d) throws IOException {

414

print(d);

415

println();

416

}

417

418

/**

419

* Check if data can be written to the output stream without blocking.

420

*/

421

public abstract boolean isReady();

422

423

/**

424

* Set a WriteListener for non-blocking I/O operations.

425

* The container will invoke the listener when writing becomes possible.

426

*/

427

public abstract void setWriteListener(WriteListener writeListener);

428

}

429

```

430

431

## Asynchronous Processing Examples

432

433

### Basic Async Servlet

434

435

```java { .api }

436

/**

437

* Basic asynchronous servlet example

438

*/

439

@WebServlet(value = "/async-basic", asyncSupported = true)

440

public class BasicAsyncServlet extends HttpServlet {

441

442

private ExecutorService executor = Executors.newCachedThreadPool();

443

444

@Override

445

protected void doGet(HttpServletRequest request, HttpServletResponse response)

446

throws ServletException, IOException {

447

448

// Start asynchronous processing

449

AsyncContext asyncContext = request.startAsync();

450

451

// Set timeout (30 seconds)

452

asyncContext.setTimeout(30000);

453

454

// Add async listener for event handling

455

asyncContext.addListener(new AsyncListener() {

456

@Override

457

public void onComplete(AsyncEvent event) throws IOException {

458

System.out.println("Async operation completed");

459

}

460

461

@Override

462

public void onTimeout(AsyncEvent event) throws IOException {

463

System.out.println("Async operation timed out");

464

AsyncContext ctx = event.getAsyncContext();

465

try {

466

ServletResponse resp = ctx.getResponse();

467

resp.setContentType("text/plain");

468

resp.getWriter().write("Request timed out");

469

} finally {

470

ctx.complete();

471

}

472

}

473

474

@Override

475

public void onError(AsyncEvent event) throws IOException {

476

System.out.println("Async operation failed: " + event.getThrowable());

477

event.getAsyncContext().complete();

478

}

479

480

@Override

481

public void onStartAsync(AsyncEvent event) throws IOException {

482

System.out.println("Async operation started");

483

}

484

});

485

486

// Start async work using AsyncContext.start()

487

asyncContext.start(new Runnable() {

488

@Override

489

public void run() {

490

try {

491

// Simulate long-running operation

492

Thread.sleep(5000);

493

494

// Generate response

495

ServletResponse resp = asyncContext.getResponse();

496

resp.setContentType("text/plain;charset=UTF-8");

497

PrintWriter writer = resp.getWriter();

498

writer.write("Async operation completed at " + new Date());

499

writer.flush();

500

501

} catch (Exception e) {

502

throw new RuntimeException(e);

503

} finally {

504

asyncContext.complete();

505

}

506

}

507

});

508

}

509

510

@Override

511

public void destroy() {

512

executor.shutdown();

513

try {

514

if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {

515

executor.shutdownNow();

516

}

517

} catch (InterruptedException e) {

518

executor.shutdownNow();

519

}

520

}

521

}

522

```

523

524

### Advanced Async Processing with Thread Pool

525

526

```java { .api }

527

/**

528

* Advanced asynchronous servlet with custom thread pool and error handling

529

*/

530

@WebServlet(value = "/async-advanced", asyncSupported = true)

531

public class AdvancedAsyncServlet extends HttpServlet {

532

533

private ExecutorService executor;

534

private ScheduledExecutorService scheduler;

535

536

@Override

537

public void init() throws ServletException {

538

// Create custom thread pools

539

executor = Executors.newFixedThreadPool(10, r -> {

540

Thread t = new Thread(r, "AsyncProcessor-" + System.currentTimeMillis());

541

t.setDaemon(true);

542

return t;

543

});

544

545

scheduler = Executors.newScheduledThreadPool(2, r -> {

546

Thread t = new Thread(r, "AsyncScheduler-" + System.currentTimeMillis());

547

t.setDaemon(true);

548

return t;

549

});

550

}

551

552

@Override

553

protected void doPost(HttpServletRequest request, HttpServletResponse response)

554

throws ServletException, IOException {

555

556

String operation = request.getParameter("operation");

557

String delayParam = request.getParameter("delay");

558

559

int delay = 1000; // Default 1 second

560

if (delayParam != null) {

561

try {

562

delay = Integer.parseInt(delayParam);

563

} catch (NumberFormatException e) {

564

response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid delay parameter");

565

return;

566

}

567

}

568

569

AsyncContext asyncContext = request.startAsync(request, response);

570

asyncContext.setTimeout(60000); // 60 second timeout

571

572

// Add comprehensive async listener

573

asyncContext.addListener(new ComprehensiveAsyncListener());

574

575

// Submit async task based on operation type

576

switch (operation != null ? operation : "default") {

577

case "immediate":

578

handleImmediateResponse(asyncContext);

579

break;

580

case "delayed":

581

handleDelayedResponse(asyncContext, delay);

582

break;

583

case "stream":

584

handleStreamingResponse(asyncContext);

585

break;

586

case "error":

587

handleErrorResponse(asyncContext);

588

break;

589

default:

590

handleDefaultResponse(asyncContext, delay);

591

}

592

}

593

594

private void handleImmediateResponse(AsyncContext asyncContext) {

595

executor.submit(() -> {

596

try {

597

ServletResponse response = asyncContext.getResponse();

598

response.setContentType("application/json;charset=UTF-8");

599

600

PrintWriter writer = response.getWriter();

601

writer.write("{");

602

writer.write("\"status\":\"success\",");

603

writer.write("\"message\":\"Immediate response\",");

604

writer.write("\"timestamp\":\"" + Instant.now() + "\"");

605

writer.write("}");

606

writer.flush();

607

608

} catch (IOException e) {

609

throw new RuntimeException(e);

610

} finally {

611

asyncContext.complete();

612

}

613

});

614

}

615

616

private void handleDelayedResponse(AsyncContext asyncContext, int delay) {

617

scheduler.schedule(() -> {

618

try {

619

ServletResponse response = asyncContext.getResponse();

620

response.setContentType("application/json;charset=UTF-8");

621

622

PrintWriter writer = response.getWriter();

623

writer.write("{");

624

writer.write("\"status\":\"success\",");

625

writer.write("\"message\":\"Delayed response after " + delay + "ms\",");

626

writer.write("\"timestamp\":\"" + Instant.now() + "\"");

627

writer.write("}");

628

writer.flush();

629

630

} catch (IOException e) {

631

throw new RuntimeException(e);

632

} finally {

633

asyncContext.complete();

634

}

635

}, delay, TimeUnit.MILLISECONDS);

636

}

637

638

private void handleStreamingResponse(AsyncContext asyncContext) {

639

executor.submit(() -> {

640

try {

641

ServletResponse response = asyncContext.getResponse();

642

response.setContentType("text/plain;charset=UTF-8");

643

644

PrintWriter writer = response.getWriter();

645

646

// Send chunked response

647

for (int i = 1; i <= 10; i++) {

648

writer.println("Chunk " + i + " sent at " + Instant.now());

649

writer.flush();

650

651

Thread.sleep(500); // Delay between chunks

652

}

653

654

writer.println("Streaming completed");

655

writer.flush();

656

657

} catch (Exception e) {

658

throw new RuntimeException(e);

659

} finally {

660

asyncContext.complete();

661

}

662

});

663

}

664

665

private void handleErrorResponse(AsyncContext asyncContext) {

666

executor.submit(() -> {

667

try {

668

// Simulate processing delay

669

Thread.sleep(1000);

670

671

// Intentionally throw an error

672

throw new RuntimeException("Simulated async error");

673

674

} catch (Exception e) {

675

try {

676

ServletResponse response = asyncContext.getResponse();

677

response.setContentType("application/json;charset=UTF-8");

678

679

if (!response.isCommitted()) {

680

PrintWriter writer = response.getWriter();

681

writer.write("{");

682

writer.write("\"status\":\"error\",");

683

writer.write("\"message\":\"" + e.getMessage() + "\",");

684

writer.write("\"timestamp\":\"" + Instant.now() + "\"");

685

writer.write("}");

686

writer.flush();

687

}

688

} catch (IOException ioException) {

689

ioException.printStackTrace();

690

} finally {

691

asyncContext.complete();

692

}

693

}

694

});

695

}

696

697

private void handleDefaultResponse(AsyncContext asyncContext, int delay) {

698

CompletableFuture

699

.supplyAsync(() -> {

700

try {

701

Thread.sleep(delay);

702

return "Processing completed after " + delay + "ms";

703

} catch (InterruptedException e) {

704

throw new RuntimeException(e);

705

}

706

}, executor)

707

.whenComplete((result, throwable) -> {

708

try {

709

ServletResponse response = asyncContext.getResponse();

710

response.setContentType("application/json;charset=UTF-8");

711

712

PrintWriter writer = response.getWriter();

713

if (throwable == null) {

714

writer.write("{");

715

writer.write("\"status\":\"success\",");

716

writer.write("\"message\":\"" + result + "\",");

717

writer.write("\"timestamp\":\"" + Instant.now() + "\"");

718

writer.write("}");

719

} else {

720

writer.write("{");

721

writer.write("\"status\":\"error\",");

722

writer.write("\"message\":\"" + throwable.getMessage() + "\",");

723

writer.write("\"timestamp\":\"" + Instant.now() + "\"");

724

writer.write("}");

725

}

726

writer.flush();

727

728

} catch (IOException e) {

729

e.printStackTrace();

730

} finally {

731

asyncContext.complete();

732

}

733

});

734

}

735

736

private class ComprehensiveAsyncListener implements AsyncListener {

737

@Override

738

public void onComplete(AsyncEvent event) throws IOException {

739

System.out.println("Async request completed successfully");

740

}

741

742

@Override

743

public void onTimeout(AsyncEvent event) throws IOException {

744

System.out.println("Async request timed out");

745

746

AsyncContext ctx = event.getAsyncContext();

747

try {

748

ServletResponse response = ctx.getResponse();

749

if (!response.isCommitted()) {

750

response.setContentType("application/json;charset=UTF-8");

751

PrintWriter writer = response.getWriter();

752

writer.write("{");

753

writer.write("\"status\":\"timeout\",");

754

writer.write("\"message\":\"Request processing timed out\",");

755

writer.write("\"timestamp\":\"" + Instant.now() + "\"");

756

writer.write("}");

757

writer.flush();

758

}

759

} finally {

760

ctx.complete();

761

}

762

}

763

764

@Override

765

public void onError(AsyncEvent event) throws IOException {

766

Throwable throwable = event.getThrowable();

767

System.out.println("Async request failed: " + throwable.getMessage());

768

769

AsyncContext ctx = event.getAsyncContext();

770

try {

771

ServletResponse response = ctx.getResponse();

772

if (!response.isCommitted()) {

773

response.setContentType("application/json;charset=UTF-8");

774

PrintWriter writer = response.getWriter();

775

writer.write("{");

776

writer.write("\"status\":\"error\",");

777

writer.write("\"message\":\"" + throwable.getMessage() + "\",");

778

writer.write("\"timestamp\":\"" + Instant.now() + "\"");

779

writer.write("}");

780

writer.flush();

781

}

782

} finally {

783

ctx.complete();

784

}

785

}

786

787

@Override

788

public void onStartAsync(AsyncEvent event) throws IOException {

789

System.out.println("Async request started");

790

}

791

}

792

793

@Override

794

public void destroy() {

795

executor.shutdown();

796

scheduler.shutdown();

797

try {

798

if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {

799

executor.shutdownNow();

800

}

801

if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {

802

scheduler.shutdownNow();

803

}

804

} catch (InterruptedException e) {

805

executor.shutdownNow();

806

scheduler.shutdownNow();

807

}

808

}

809

}

810

```

811

812

## Non-Blocking I/O Examples

813

814

### Non-Blocking Read Example

815

816

```java { .api }

817

/**

818

* Servlet demonstrating non-blocking input stream reading

819

*/

820

@WebServlet(value = "/non-blocking-read", asyncSupported = true)

821

public class NonBlockingReadServlet extends HttpServlet {

822

823

@Override

824

protected void doPost(HttpServletRequest request, HttpServletResponse response)

825

throws ServletException, IOException {

826

827

AsyncContext asyncContext = request.startAsync();

828

asyncContext.setTimeout(30000);

829

830

ServletInputStream inputStream = request.getInputStream();

831

ByteArrayOutputStream buffer = new ByteArrayOutputStream();

832

833

inputStream.setReadListener(new ReadListener() {

834

@Override

835

public void onDataAvailable() throws IOException {

836

// Read all available data

837

byte[] data = new byte[1024];

838

int bytesRead;

839

840

while (inputStream.isReady() && (bytesRead = inputStream.read(data)) != -1) {

841

buffer.write(data, 0, bytesRead);

842

}

843

}

844

845

@Override

846

public void onAllDataRead() throws IOException {

847

try {

848

// Process the complete request data

849

String requestData = buffer.toString("UTF-8");

850

String processedData = processData(requestData);

851

852

// Send response

853

ServletResponse resp = asyncContext.getResponse();

854

resp.setContentType("application/json;charset=UTF-8");

855

856

PrintWriter writer = resp.getWriter();

857

writer.write("{");

858

writer.write("\"status\":\"success\",");

859

writer.write("\"originalSize\":" + requestData.length() + ",");

860

writer.write("\"processedData\":\"" + processedData + "\",");

861

writer.write("\"timestamp\":\"" + Instant.now() + "\"");

862

writer.write("}");

863

writer.flush();

864

865

} finally {

866

asyncContext.complete();

867

}

868

}

869

870

@Override

871

public void onError(Throwable t) {

872

System.err.println("Error reading request data: " + t.getMessage());

873

try {

874

ServletResponse resp = asyncContext.getResponse();

875

if (!resp.isCommitted()) {

876

resp.setContentType("application/json;charset=UTF-8");

877

PrintWriter writer = resp.getWriter();

878

writer.write("{");

879

writer.write("\"status\":\"error\",");

880

writer.write("\"message\":\"" + t.getMessage() + "\"");

881

writer.write("}");

882

writer.flush();

883

}

884

} catch (IOException e) {

885

e.printStackTrace();

886

} finally {

887

asyncContext.complete();

888

}

889

}

890

});

891

}

892

893

private String processData(String data) {

894

// Simulate data processing

895

return data.toUpperCase().replaceAll("\\s+", "_");

896

}

897

}

898

```

899

900

### Non-Blocking Write Example

901

902

```java { .api }

903

/**

904

* Servlet demonstrating non-blocking output stream writing

905

*/

906

@WebServlet(value = "/non-blocking-write", asyncSupported = true)

907

public class NonBlockingWriteServlet extends HttpServlet {

908

909

@Override

910

protected void doGet(HttpServletRequest request, HttpServletResponse response)

911

throws ServletException, IOException {

912

913

AsyncContext asyncContext = request.startAsync();

914

asyncContext.setTimeout(60000);

915

916

response.setContentType("text/plain;charset=UTF-8");

917

ServletOutputStream outputStream = response.getOutputStream();

918

919

// Generate large amount of data to write

920

Queue<String> dataQueue = generateLargeDataSet();

921

922

outputStream.setWriteListener(new WriteListener() {

923

@Override

924

public void onWritePossible() throws IOException {

925

// Write data while the output stream is ready

926

while (outputStream.isReady() && !dataQueue.isEmpty()) {

927

String data = dataQueue.poll();

928

outputStream.print(data);

929

outputStream.println(); // Add line separator

930

}

931

932

// Check if all data has been written

933

if (dataQueue.isEmpty()) {

934

outputStream.println("=== End of Data ===");

935

asyncContext.complete();

936

}

937

}

938

939

@Override

940

public void onError(Throwable t) {

941

System.err.println("Error writing response data: " + t.getMessage());

942

asyncContext.complete();

943

}

944

});

945

}

946

947

private Queue<String> generateLargeDataSet() {

948

Queue<String> data = new LinkedList<>();

949

950

// Generate 1000 lines of sample data

951

for (int i = 1; i <= 1000; i++) {

952

data.offer("Line " + i + ": This is sample data generated at " +

953

Instant.now() + " with some additional content to make it longer.");

954

}

955

956

return data;

957

}

958

}

959

```

960

961

### File Upload with Non-Blocking I/O

962

963

```java { .api }

964

/**

965

* Servlet for handling file uploads with non-blocking I/O

966

*/

967

@WebServlet(value = "/upload-async", asyncSupported = true)

968

@MultipartConfig(

969

location = "/tmp",

970

fileSizeThreshold = 1024 * 1024, // 1 MB

971

maxFileSize = 1024 * 1024 * 50, // 50 MB

972

maxRequestSize = 1024 * 1024 * 100 // 100 MB

973

)

974

public class AsyncFileUploadServlet extends HttpServlet {

975

976

@Override

977

protected void doPost(HttpServletRequest request, HttpServletResponse response)

978

throws ServletException, IOException {

979

980

AsyncContext asyncContext = request.startAsync();

981

asyncContext.setTimeout(300000); // 5 minutes for large uploads

982

983

// Process multipart request asynchronously

984

CompletableFuture.runAsync(() -> {

985

try {

986

Collection<Part> parts = request.getParts();

987

List<String> uploadedFiles = new ArrayList<>();

988

989

for (Part part : parts) {

990

if (part.getName().equals("file") && part.getSize() > 0) {

991

String fileName = getSubmittedFileName(part);

992

String uploadPath = saveFileAsync(part, fileName);

993

uploadedFiles.add(fileName + " (" + part.getSize() + " bytes)");

994

}

995

}

996

997

// Send success response

998

ServletResponse resp = asyncContext.getResponse();

999

resp.setContentType("application/json;charset=UTF-8");

1000

1001

PrintWriter writer = resp.getWriter();

1002

writer.write("{");

1003

writer.write("\"status\":\"success\",");

1004

writer.write("\"filesUploaded\":" + uploadedFiles.size() + ",");

1005

writer.write("\"files\":[");

1006

for (int i = 0; i < uploadedFiles.size(); i++) {

1007

if (i > 0) writer.write(",");

1008

writer.write("\"" + uploadedFiles.get(i) + "\"");

1009

}

1010

writer.write("],");

1011

writer.write("\"timestamp\":\"" + Instant.now() + "\"");

1012

writer.write("}");

1013

writer.flush();

1014

1015

} catch (Exception e) {

1016

try {

1017

ServletResponse resp = asyncContext.getResponse();

1018

if (!resp.isCommitted()) {

1019

resp.setContentType("application/json;charset=UTF-8");

1020

PrintWriter writer = resp.getWriter();

1021

writer.write("{");

1022

writer.write("\"status\":\"error\",");

1023

writer.write("\"message\":\"" + e.getMessage() + "\"");

1024

writer.write("}");

1025

writer.flush();

1026

}

1027

} catch (IOException ioException) {

1028

ioException.printStackTrace();

1029

}

1030

} finally {

1031

asyncContext.complete();

1032

}

1033

});

1034

}

1035

1036

private String saveFileAsync(Part part, String fileName) throws IOException {

1037

String uploadDir = getServletContext().getRealPath("/uploads");

1038

Files.createDirectories(Paths.get(uploadDir));

1039

1040

String filePath = uploadDir + File.separator +

1041

System.currentTimeMillis() + "_" + fileName;

1042

1043

// Save file using NIO for better performance

1044

try (InputStream input = part.getInputStream()) {

1045

Files.copy(input, Paths.get(filePath), StandardCopyOption.REPLACE_EXISTING);

1046

}

1047

1048

return filePath;

1049

}

1050

1051

private String getSubmittedFileName(Part part) {

1052

String contentDisposition = part.getHeader("Content-Disposition");

1053

if (contentDisposition != null) {

1054

String[] elements = contentDisposition.split(";");

1055

for (String element : elements) {

1056

if (element.trim().startsWith("filename")) {

1057

return element.substring(element.indexOf('=') + 1)

1058

.trim().replace("\"", "");

1059

}

1060

}

1061

}

1062

return "unknown_" + System.currentTimeMillis();

1063

}

1064

}

1065

```

1066

1067

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.