or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotations.mdbroadcasting.mdcaching.mdcore-framework.mdindex.mdinterceptors.mdwebsocket.md

interceptors.mddocs/

0

# Interceptor System

1

2

Request/response processing pipeline with built-in interceptors for CORS, heartbeat, protocol handling, and custom processing logic. Interceptors provide a flexible way to process and modify requests and responses.

3

4

## Capabilities

5

6

### AtmosphereInterceptor Interface

7

8

Core interface for intercepting and processing Atmosphere requests with priority-based execution order.

9

10

```java { .api }

11

/**

12

* Request/response interception and modification

13

*/

14

public interface AtmosphereInterceptor {

15

/**

16

* Intercept incoming AtmosphereResource before processing

17

* @param resource AtmosphereResource to intercept

18

* @return Action indicating how to proceed

19

*/

20

public Action intercept(AtmosphereResource resource);

21

22

/**

23

* Post-process AtmosphereResource after main processing

24

* @param resource AtmosphereResource after processing

25

*/

26

public void postInspect(AtmosphereResource resource);

27

28

/**

29

* Configure interceptor with AtmosphereConfig

30

* @param config AtmosphereConfig instance

31

*/

32

public void configure(AtmosphereConfig config);

33

34

/**

35

* Get execution priority (lower numbers execute first)

36

* @return priority value

37

*/

38

public int priority();

39

40

/**

41

* Destroy interceptor and cleanup resources

42

*/

43

public void destroy();

44

45

/**

46

* Get supported protocols for this interceptor

47

* @return list of supported protocol names

48

*/

49

public List<String> supportedProtocols();

50

}

51

52

/**

53

* Action result from interceptor processing

54

*/

55

public enum Action {

56

CONTINUE, // Continue processing with next interceptor

57

SUSPEND, // Suspend processing at this point

58

RESUME, // Resume processing

59

CANCELLED, // Cancel request processing

60

SKIP_ATMOSPHEREHANDLER, // Skip AtmosphereHandler execution

61

CREATED // Resource was created by interceptor

62

}

63

```

64

65

**Usage Examples:**

66

67

```java

68

@AtmosphereInterceptorService

69

public class LoggingInterceptor implements AtmosphereInterceptor {

70

71

@Override

72

public Action intercept(AtmosphereResource resource) {

73

AtmosphereRequest request = resource.getRequest();

74

75

System.out.println("Intercepting request: " +

76

request.getMethod() + " " + request.getPathInfo());

77

78

// Log request headers

79

Enumeration<String> headers = request.getHeaderNames();

80

while (headers.hasMoreElements()) {

81

String headerName = headers.nextElement();

82

System.out.println("Header: " + headerName + " = " +

83

request.getHeader(headerName));

84

}

85

86

return Action.CONTINUE;

87

}

88

89

@Override

90

public void postInspect(AtmosphereResource resource) {

91

System.out.println("Post-processing request for: " +

92

resource.getRequest().getPathInfo());

93

}

94

95

@Override

96

public int priority() {

97

return 1000; // Low priority, execute after security interceptors

98

}

99

}

100

```

101

102

### Built-in Interceptors

103

104

Pre-built interceptors for common cross-cutting concerns and protocol handling.

105

106

```java { .api }

107

/**

108

* Handle Cross-Origin Resource Sharing (CORS)

109

*/

110

public class CorsInterceptor implements AtmosphereInterceptor {

111

/**

112

* Set allowed origins for CORS

113

* @param origins comma-separated list of allowed origins

114

* @return this interceptor

115

*/

116

public CorsInterceptor setAllowedOrigins(String origins);

117

118

/**

119

* Set allowed HTTP methods

120

* @param methods comma-separated list of allowed methods

121

* @return this interceptor

122

*/

123

public CorsInterceptor setAllowedMethods(String methods);

124

125

/**

126

* Set allowed headers

127

* @param headers comma-separated list of allowed headers

128

* @return this interceptor

129

*/

130

public CorsInterceptor setAllowedHeaders(String headers);

131

132

/**

133

* Enable credentials support

134

* @param allowCredentials true to allow credentials

135

* @return this interceptor

136

*/

137

public CorsInterceptor setAllowCredentials(boolean allowCredentials);

138

}

139

140

/**

141

* Implement heartbeat mechanism for connection monitoring

142

*/

143

public class HeartbeatInterceptor implements AtmosphereInterceptor {

144

/**

145

* Set heartbeat interval

146

* @param interval heartbeat interval in milliseconds

147

* @return this interceptor

148

*/

149

public HeartbeatInterceptor setHeartbeatInterval(long interval);

150

151

/**

152

* Set client heartbeat data

153

* @param heartbeatData data to send for heartbeat

154

* @return this interceptor

155

*/

156

public HeartbeatInterceptor setHeartbeatData(String heartbeatData);

157

}

158

159

/**

160

* Server-Sent Events protocol support

161

*/

162

public class SSEAtmosphereInterceptor implements AtmosphereInterceptor {

163

/**

164

* Set whether to pad SSE messages

165

* @param padding true to enable padding

166

* @return this interceptor

167

*/

168

public SSEAtmosphereInterceptor setPadding(boolean padding);

169

}

170

171

/**

172

* JSONP protocol support for cross-domain requests

173

*/

174

public class JSONPAtmosphereInterceptor implements AtmosphereInterceptor {

175

/**

176

* Set JSONP callback parameter name

177

* @param callbackName parameter name for callback

178

* @return this interceptor

179

*/

180

public JSONPAtmosphereInterceptor setCallbackName(String callbackName);

181

}

182

183

/**

184

* Set appropriate cache headers for responses

185

*/

186

public class CacheHeadersInterceptor implements AtmosphereInterceptor {

187

/**

188

* Set cache control directives

189

* @param cacheControl cache control header value

190

* @return this interceptor

191

*/

192

public CacheHeadersInterceptor setCacheControl(String cacheControl);

193

}

194

195

/**

196

* Handle idle resource cleanup

197

*/

198

public class IdleResourceInterceptor implements AtmosphereInterceptor {

199

/**

200

* Set idle timeout for resources

201

* @param idleTimeout timeout in milliseconds

202

* @return this interceptor

203

*/

204

public IdleResourceInterceptor setIdleTimeout(long idleTimeout);

205

}

206

207

/**

208

* Manage AtmosphereResource lifecycle events

209

*/

210

public class AtmosphereResourceLifecycleInterceptor implements AtmosphereInterceptor {

211

/**

212

* Enable lifecycle event broadcasting

213

* @param broadcastLifecycleEvents true to broadcast events

214

* @return this interceptor

215

*/

216

public AtmosphereResourceLifecycleInterceptor setBroadcastLifecycleEvents(boolean broadcastLifecycleEvents);

217

}

218

219

/**

220

* Handle client disconnection events

221

*/

222

public class OnDisconnectInterceptor implements AtmosphereInterceptor {

223

/**

224

* Set disconnection message

225

* @param disconnectMessage message to send on disconnect

226

* @return this interceptor

227

*/

228

public OnDisconnectInterceptor setDisconnectMessage(String disconnectMessage);

229

}

230

```

231

232

**Usage Examples:**

233

234

```java

235

// Configure CORS interceptor

236

CorsInterceptor corsInterceptor = new CorsInterceptor()

237

.setAllowedOrigins("http://localhost:3000,https://myapp.com")

238

.setAllowedMethods("GET,POST,PUT,DELETE")

239

.setAllowedHeaders("Content-Type,Authorization")

240

.setAllowCredentials(true);

241

242

// Configure heartbeat interceptor

243

HeartbeatInterceptor heartbeatInterceptor = new HeartbeatInterceptor()

244

.setHeartbeatInterval(30000) // 30 seconds

245

.setHeartbeatData("ping");

246

247

// Configure SSE interceptor

248

SSEAtmosphereInterceptor sseInterceptor = new SSEAtmosphereInterceptor()

249

.setPadding(true);

250

251

// Add interceptors to framework

252

AtmosphereFramework framework = new AtmosphereFramework();

253

framework.intercept(corsInterceptor)

254

.intercept(heartbeatInterceptor)

255

.intercept(sseInterceptor);

256

```

257

258

### Custom Interceptor Development

259

260

Base classes and utilities for developing custom interceptors.

261

262

```java { .api }

263

/**

264

* Adapter implementation providing default interceptor behavior

265

*/

266

public class AtmosphereInterceptorAdapter implements AtmosphereInterceptor {

267

/**

268

* Default intercept implementation (CONTINUE)

269

* @param resource AtmosphereResource

270

* @return Action.CONTINUE

271

*/

272

public Action intercept(AtmosphereResource resource) {

273

return Action.CONTINUE;

274

}

275

276

/**

277

* Default post-inspect implementation (no-op)

278

* @param resource AtmosphereResource

279

*/

280

public void postInspect(AtmosphereResource resource) {

281

// Default: do nothing

282

}

283

284

/**

285

* Default priority (medium priority)

286

* @return 1000

287

*/

288

public int priority() {

289

return 1000;

290

}

291

292

/**

293

* Default configuration (no-op)

294

* @param config AtmosphereConfig

295

*/

296

public void configure(AtmosphereConfig config) {

297

// Default: do nothing

298

}

299

300

/**

301

* Default destroy (no-op)

302

*/

303

public void destroy() {

304

// Default: do nothing

305

}

306

}

307

```

308

309

**Usage Examples:**

310

311

```java

312

// Authentication interceptor

313

@AtmosphereInterceptorService

314

public class AuthenticationInterceptor extends AtmosphereInterceptorAdapter {

315

316

@Override

317

public Action intercept(AtmosphereResource resource) {

318

AtmosphereRequest request = resource.getRequest();

319

320

// Check for authentication token

321

String authHeader = request.getHeader("Authorization");

322

if (authHeader == null || !authHeader.startsWith("Bearer ")) {

323

// Send 401 Unauthorized

324

try {

325

resource.getResponse().setStatus(401);

326

resource.getResponse().getWriter().write("Unauthorized");

327

resource.getResponse().flushBuffer();

328

return Action.CANCELLED;

329

} catch (IOException e) {

330

return Action.CANCELLED;

331

}

332

}

333

334

// Validate token

335

String token = authHeader.substring(7);

336

if (!isValidToken(token)) {

337

try {

338

resource.getResponse().setStatus(403);

339

resource.getResponse().getWriter().write("Invalid token");

340

resource.getResponse().flushBuffer();

341

return Action.CANCELLED;

342

} catch (IOException e) {

343

return Action.CANCELLED;

344

}

345

}

346

347

// Add user info to request attributes

348

User user = getUserFromToken(token);

349

request.setAttribute("user", user);

350

351

return Action.CONTINUE;

352

}

353

354

@Override

355

public int priority() {

356

return 100; // High priority - execute early

357

}

358

359

private boolean isValidToken(String token) {

360

// Token validation logic

361

return token != null && token.length() > 10;

362

}

363

364

private User getUserFromToken(String token) {

365

// Extract user from token

366

return new User("user123", "John Doe");

367

}

368

}

369

370

// Rate limiting interceptor

371

@AtmosphereInterceptorService

372

public class RateLimitInterceptor extends AtmosphereInterceptorAdapter {

373

private final Map<String, TokenBucket> clientBuckets = new ConcurrentHashMap<>();

374

private final int maxRequestsPerMinute = 60;

375

376

@Override

377

public Action intercept(AtmosphereResource resource) {

378

String clientIp = resource.getRequest().getRemoteAddr();

379

380

// Get or create token bucket for client

381

TokenBucket bucket = clientBuckets.computeIfAbsent(clientIp,

382

k -> new TokenBucket(maxRequestsPerMinute, 1, TimeUnit.MINUTES));

383

384

// Check if request is allowed

385

if (!bucket.tryConsume()) {

386

try {

387

resource.getResponse().setStatus(429); // Too Many Requests

388

resource.getResponse().setHeader("Retry-After", "60");

389

resource.getResponse().getWriter().write("Rate limit exceeded");

390

resource.getResponse().flushBuffer();

391

return Action.CANCELLED;

392

} catch (IOException e) {

393

return Action.CANCELLED;

394

}

395

}

396

397

return Action.CONTINUE;

398

}

399

400

@Override

401

public int priority() {

402

return 200; // Execute after authentication but before main processing

403

}

404

}

405

406

// Request transformation interceptor

407

@AtmosphereInterceptorService

408

public class RequestTransformInterceptor extends AtmosphereInterceptorAdapter {

409

410

@Override

411

public Action intercept(AtmosphereResource resource) {

412

AtmosphereRequest request = resource.getRequest();

413

414

// Transform specific paths

415

String pathInfo = request.getPathInfo();

416

if (pathInfo != null && pathInfo.startsWith("/legacy/")) {

417

// Rewrite legacy paths to new format

418

String newPath = pathInfo.replace("/legacy/", "/api/v2/");

419

420

// Create new request with transformed path

421

AtmosphereRequest.Builder builder = new AtmosphereRequest.Builder();

422

builder.request(request).pathInfo(newPath);

423

424

// Replace request in resource

425

resource.setRequest(builder.build());

426

}

427

428

// Add custom headers

429

resource.getResponse().setHeader("X-Processed-By", "Atmosphere");

430

resource.getResponse().setHeader("X-Request-Id", UUID.randomUUID().toString());

431

432

return Action.CONTINUE;

433

}

434

435

@Override

436

public void postInspect(AtmosphereResource resource) {

437

// Add processing time header

438

long processingTime = System.currentTimeMillis() -

439

(Long) resource.getRequest().getAttribute("startTime");

440

resource.getResponse().setHeader("X-Processing-Time", String.valueOf(processingTime));

441

}

442

443

@Override

444

public int priority() {

445

return 500; // Medium priority

446

}

447

}

448

```

449

450

### Interceptor Chain Management

451

452

Utilities for managing and configuring interceptor execution chains.

453

454

```java { .api }

455

/**

456

* Interceptor chain configuration and management

457

*/

458

public class InterceptorManager {

459

/**

460

* Add interceptor to global chain

461

* @param interceptor AtmosphereInterceptor to add

462

*/

463

public void addInterceptor(AtmosphereInterceptor interceptor);

464

465

/**

466

* Remove interceptor from chain

467

* @param interceptor AtmosphereInterceptor to remove

468

*/

469

public void removeInterceptor(AtmosphereInterceptor interceptor);

470

471

/**

472

* Get all registered interceptors ordered by priority

473

* @return List of interceptors in execution order

474

*/

475

public List<AtmosphereInterceptor> getInterceptors();

476

477

/**

478

* Clear all interceptors

479

*/

480

public void clearInterceptors();

481

}

482

```

483

484

### Async I/O Interceptors

485

486

Special interceptors for handling asynchronous I/O operations.

487

488

```java { .api }

489

/**

490

* Intercept async I/O operations

491

*/

492

public interface AsyncIOInterceptor {

493

/**

494

* Intercept before payload is written

495

* @param resource AtmosphereResource

496

* @param data payload being written

497

* @param offset write offset

498

* @param length write length

499

* @return modified payload or original data

500

*/

501

public byte[] prePayload(AtmosphereResource resource, byte[] data, int offset, int length);

502

503

/**

504

* Intercept after payload is written

505

* @param resource AtmosphereResource

506

* @param data payload that was written

507

* @param offset write offset

508

* @param length write length

509

*/

510

public void postPayload(AtmosphereResource resource, byte[] data, int offset, int length);

511

512

/**

513

* Configure async I/O interceptor

514

* @param config AtmosphereConfig

515

*/

516

public void configure(AtmosphereConfig config);

517

}

518

519

/**

520

* Adapter for AsyncIOInterceptor with default implementations

521

*/

522

public class AsyncIOInterceptorAdapter implements AsyncIOInterceptor {

523

/**

524

* Default pre-payload processing (return original data)

525

*/

526

public byte[] prePayload(AtmosphereResource resource, byte[] data, int offset, int length) {

527

return data;

528

}

529

530

/**

531

* Default post-payload processing (no-op)

532

*/

533

public void postPayload(AtmosphereResource resource, byte[] data, int offset, int length) {

534

// Default: do nothing

535

}

536

}

537

```

538

539

**Usage Examples:**

540

541

```java

542

// Compression interceptor for async I/O

543

public class CompressionAsyncIOInterceptor extends AsyncIOInterceptorAdapter {

544

545

@Override

546

public byte[] prePayload(AtmosphereResource resource, byte[] data, int offset, int length) {

547

// Check if client supports compression

548

String acceptEncoding = resource.getRequest().getHeader("Accept-Encoding");

549

if (acceptEncoding != null && acceptEncoding.contains("gzip")) {

550

551

try {

552

// Compress data using GZIP

553

ByteArrayOutputStream baos = new ByteArrayOutputStream();

554

try (GZIPOutputStream gzipOut = new GZIPOutputStream(baos)) {

555

gzipOut.write(data, offset, length);

556

}

557

558

// Set compression headers

559

resource.getResponse().setHeader("Content-Encoding", "gzip");

560

resource.getResponse().setHeader("Vary", "Accept-Encoding");

561

562

byte[] compressed = baos.toByteArray();

563

System.out.println("Compressed " + length + " bytes to " + compressed.length + " bytes");

564

565

return compressed;

566

567

} catch (IOException e) {

568

System.err.println("Compression failed: " + e.getMessage());

569

return data; // Return original data on error

570

}

571

}

572

573

return data; // No compression

574

}

575

576

@Override

577

public void postPayload(AtmosphereResource resource, byte[] data, int offset, int length) {

578

// Log compression statistics

579

String contentEncoding = resource.getResponse().getHeader("Content-Encoding");

580

if ("gzip".equals(contentEncoding)) {

581

System.out.println("Sent compressed payload: " + length + " bytes");

582

}

583

}

584

}

585

```

586

587

### Complete Interceptor Example

588

589

Comprehensive example showing multiple interceptors working together in a real application.

590

591

```java

592

// Security interceptor chain

593

@AtmosphereInterceptorService

594

public class SecurityInterceptorChain extends AtmosphereInterceptorAdapter {

595

private final AuthenticationService authService;

596

private final AuditService auditService;

597

598

public SecurityInterceptorChain() {

599

this.authService = new AuthenticationService();

600

this.auditService = new AuditService();

601

}

602

603

@Override

604

public Action intercept(AtmosphereResource resource) {

605

AtmosphereRequest request = resource.getRequest();

606

String path = request.getPathInfo();

607

608

// Skip authentication for public endpoints

609

if (isPublicEndpoint(path)) {

610

return Action.CONTINUE;

611

}

612

613

// Authenticate request

614

String authResult = authenticateRequest(request);

615

if (authResult == null) {

616

sendUnauthorizedResponse(resource);

617

return Action.CANCELLED;

618

}

619

620

// Check authorization

621

if (!isAuthorized(authResult, path, request.getMethod())) {

622

sendForbiddenResponse(resource);

623

return Action.CANCELLED;

624

}

625

626

// Add security context to request

627

request.setAttribute("securityContext", createSecurityContext(authResult));

628

629

// Audit the request

630

auditService.logAccess(authResult, path, request.getMethod(),

631

request.getRemoteAddr());

632

633

return Action.CONTINUE;

634

}

635

636

@Override

637

public void postInspect(AtmosphereResource resource) {

638

// Audit the response

639

AtmosphereRequest request = resource.getRequest();

640

SecurityContext context = (SecurityContext) request.getAttribute("securityContext");

641

642

if (context != null) {

643

int statusCode = resource.getResponse().getStatus();

644

auditService.logResponse(context.getUserId(), request.getPathInfo(),

645

statusCode, System.currentTimeMillis());

646

}

647

}

648

649

@Override

650

public int priority() {

651

return 50; // Very high priority - execute first

652

}

653

654

private boolean isPublicEndpoint(String path) {

655

return path != null && (path.startsWith("/public/") ||

656

path.equals("/health") ||

657

path.equals("/status"));

658

}

659

660

private String authenticateRequest(AtmosphereRequest request) {

661

String authHeader = request.getHeader("Authorization");

662

if (authHeader != null && authHeader.startsWith("Bearer ")) {

663

String token = authHeader.substring(7);

664

return authService.validateToken(token);

665

}

666

return null;

667

}

668

669

private boolean isAuthorized(String userId, String path, String method) {

670

return authService.checkPermission(userId, path, method);

671

}

672

673

private void sendUnauthorizedResponse(AtmosphereResource resource) {

674

try {

675

resource.getResponse().setStatus(401);

676

resource.getResponse().setContentType("application/json");

677

resource.getResponse().getWriter()

678

.write("{\"error\":\"Unauthorized\",\"code\":401}");

679

resource.getResponse().flushBuffer();

680

} catch (IOException e) {

681

// Log error

682

}

683

}

684

685

private void sendForbiddenResponse(AtmosphereResource resource) {

686

try {

687

resource.getResponse().setStatus(403);

688

resource.getResponse().setContentType("application/json");

689

resource.getResponse().getWriter()

690

.write("{\"error\":\"Forbidden\",\"code\":403}");

691

resource.getResponse().flushBuffer();

692

} catch (IOException e) {

693

// Log error

694

}

695

}

696

697

private SecurityContext createSecurityContext(String userId) {

698

return new SecurityContext(userId, authService.getUserRoles(userId));

699

}

700

}

701

```