CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-atmosphere--atmosphere-runtime

The Atmosphere Framework runtime providing comprehensive support for building real-time, event-driven web applications with transparent transport protocol support including WebSockets, Server Sent Events, Long-Polling, HTTP Streaming, and JSONP.

Pending
Overview
Eval results
Files

interceptors.mddocs/

Interceptor System

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.

Capabilities

AtmosphereInterceptor Interface

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

/**
 * Request/response interception and modification
 */
public interface AtmosphereInterceptor {
    /**
     * Intercept incoming AtmosphereResource before processing
     * @param resource AtmosphereResource to intercept
     * @return Action indicating how to proceed
     */
    public Action intercept(AtmosphereResource resource);
    
    /**
     * Post-process AtmosphereResource after main processing
     * @param resource AtmosphereResource after processing
     */
    public void postInspect(AtmosphereResource resource);
    
    /**
     * Configure interceptor with AtmosphereConfig
     * @param config AtmosphereConfig instance
     */
    public void configure(AtmosphereConfig config);
    
    /**
     * Get execution priority (lower numbers execute first)
     * @return priority value
     */
    public int priority();
    
    /**
     * Destroy interceptor and cleanup resources
     */
    public void destroy();
    
    /**
     * Get supported protocols for this interceptor
     * @return list of supported protocol names
     */
    public List<String> supportedProtocols();
}

/**
 * Action result from interceptor processing
 */
public enum Action {
    CONTINUE,  // Continue processing with next interceptor
    SUSPEND,   // Suspend processing at this point
    RESUME,    // Resume processing
    CANCELLED, // Cancel request processing
    SKIP_ATMOSPHEREHANDLER, // Skip AtmosphereHandler execution
    CREATED    // Resource was created by interceptor
}

Usage Examples:

@AtmosphereInterceptorService
public class LoggingInterceptor implements AtmosphereInterceptor {
    
    @Override
    public Action intercept(AtmosphereResource resource) {
        AtmosphereRequest request = resource.getRequest();
        
        System.out.println("Intercepting request: " + 
                          request.getMethod() + " " + request.getPathInfo());
        
        // Log request headers
        Enumeration<String> headers = request.getHeaderNames();
        while (headers.hasMoreElements()) {
            String headerName = headers.nextElement();
            System.out.println("Header: " + headerName + " = " + 
                             request.getHeader(headerName));
        }
        
        return Action.CONTINUE;
    }
    
    @Override
    public void postInspect(AtmosphereResource resource) {
        System.out.println("Post-processing request for: " + 
                          resource.getRequest().getPathInfo());
    }
    
    @Override
    public int priority() {
        return 1000; // Low priority, execute after security interceptors
    }
}

Built-in Interceptors

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

/**
 * Handle Cross-Origin Resource Sharing (CORS)
 */
public class CorsInterceptor implements AtmosphereInterceptor {
    /**
     * Set allowed origins for CORS
     * @param origins comma-separated list of allowed origins
     * @return this interceptor
     */
    public CorsInterceptor setAllowedOrigins(String origins);
    
    /**
     * Set allowed HTTP methods
     * @param methods comma-separated list of allowed methods
     * @return this interceptor
     */
    public CorsInterceptor setAllowedMethods(String methods);
    
    /**
     * Set allowed headers
     * @param headers comma-separated list of allowed headers
     * @return this interceptor
     */
    public CorsInterceptor setAllowedHeaders(String headers);
    
    /**
     * Enable credentials support
     * @param allowCredentials true to allow credentials
     * @return this interceptor
     */
    public CorsInterceptor setAllowCredentials(boolean allowCredentials);
}

/**
 * Implement heartbeat mechanism for connection monitoring
 */
public class HeartbeatInterceptor implements AtmosphereInterceptor {
    /**
     * Set heartbeat interval
     * @param interval heartbeat interval in milliseconds
     * @return this interceptor
     */
    public HeartbeatInterceptor setHeartbeatInterval(long interval);
    
    /**
     * Set client heartbeat data
     * @param heartbeatData data to send for heartbeat
     * @return this interceptor
     */
    public HeartbeatInterceptor setHeartbeatData(String heartbeatData);
}

/**
 * Server-Sent Events protocol support
 */
public class SSEAtmosphereInterceptor implements AtmosphereInterceptor {
    /**
     * Set whether to pad SSE messages
     * @param padding true to enable padding
     * @return this interceptor
     */
    public SSEAtmosphereInterceptor setPadding(boolean padding);
}

/**
 * JSONP protocol support for cross-domain requests
 */
public class JSONPAtmosphereInterceptor implements AtmosphereInterceptor {
    /**
     * Set JSONP callback parameter name
     * @param callbackName parameter name for callback
     * @return this interceptor
     */
    public JSONPAtmosphereInterceptor setCallbackName(String callbackName);
}

/**
 * Set appropriate cache headers for responses
 */
public class CacheHeadersInterceptor implements AtmosphereInterceptor {
    /**
     * Set cache control directives
     * @param cacheControl cache control header value
     * @return this interceptor
     */
    public CacheHeadersInterceptor setCacheControl(String cacheControl);
}

/**
 * Handle idle resource cleanup
 */
public class IdleResourceInterceptor implements AtmosphereInterceptor {
    /**
     * Set idle timeout for resources
     * @param idleTimeout timeout in milliseconds
     * @return this interceptor
     */
    public IdleResourceInterceptor setIdleTimeout(long idleTimeout);
}

/**
 * Manage AtmosphereResource lifecycle events
 */
public class AtmosphereResourceLifecycleInterceptor implements AtmosphereInterceptor {
    /**
     * Enable lifecycle event broadcasting
     * @param broadcastLifecycleEvents true to broadcast events
     * @return this interceptor
     */
    public AtmosphereResourceLifecycleInterceptor setBroadcastLifecycleEvents(boolean broadcastLifecycleEvents);
}

/**
 * Handle client disconnection events
 */
public class OnDisconnectInterceptor implements AtmosphereInterceptor {
    /**
     * Set disconnection message
     * @param disconnectMessage message to send on disconnect
     * @return this interceptor
     */
    public OnDisconnectInterceptor setDisconnectMessage(String disconnectMessage);
}

Usage Examples:

// Configure CORS interceptor
CorsInterceptor corsInterceptor = new CorsInterceptor()
    .setAllowedOrigins("http://localhost:3000,https://myapp.com")
    .setAllowedMethods("GET,POST,PUT,DELETE")
    .setAllowedHeaders("Content-Type,Authorization")
    .setAllowCredentials(true);

// Configure heartbeat interceptor
HeartbeatInterceptor heartbeatInterceptor = new HeartbeatInterceptor()
    .setHeartbeatInterval(30000) // 30 seconds
    .setHeartbeatData("ping");

// Configure SSE interceptor
SSEAtmosphereInterceptor sseInterceptor = new SSEAtmosphereInterceptor()
    .setPadding(true);

// Add interceptors to framework
AtmosphereFramework framework = new AtmosphereFramework();
framework.intercept(corsInterceptor)
         .intercept(heartbeatInterceptor)
         .intercept(sseInterceptor);

Custom Interceptor Development

Base classes and utilities for developing custom interceptors.

/**
 * Adapter implementation providing default interceptor behavior
 */
public class AtmosphereInterceptorAdapter implements AtmosphereInterceptor {
    /**
     * Default intercept implementation (CONTINUE)
     * @param resource AtmosphereResource
     * @return Action.CONTINUE
     */
    public Action intercept(AtmosphereResource resource) {
        return Action.CONTINUE;
    }
    
    /**
     * Default post-inspect implementation (no-op)
     * @param resource AtmosphereResource
     */
    public void postInspect(AtmosphereResource resource) {
        // Default: do nothing
    }
    
    /**
     * Default priority (medium priority)
     * @return 1000
     */
    public int priority() {
        return 1000;
    }
    
    /**
     * Default configuration (no-op)
     * @param config AtmosphereConfig
     */
    public void configure(AtmosphereConfig config) {
        // Default: do nothing
    }
    
    /**
     * Default destroy (no-op)
     */
    public void destroy() {
        // Default: do nothing
    }
}

Usage Examples:

// Authentication interceptor
@AtmosphereInterceptorService
public class AuthenticationInterceptor extends AtmosphereInterceptorAdapter {
    
    @Override
    public Action intercept(AtmosphereResource resource) {
        AtmosphereRequest request = resource.getRequest();
        
        // Check for authentication token
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            // Send 401 Unauthorized
            try {
                resource.getResponse().setStatus(401);
                resource.getResponse().getWriter().write("Unauthorized");
                resource.getResponse().flushBuffer();
                return Action.CANCELLED;
            } catch (IOException e) {
                return Action.CANCELLED;
            }
        }
        
        // Validate token
        String token = authHeader.substring(7);
        if (!isValidToken(token)) {
            try {
                resource.getResponse().setStatus(403);
                resource.getResponse().getWriter().write("Invalid token");
                resource.getResponse().flushBuffer();
                return Action.CANCELLED; 
            } catch (IOException e) {
                return Action.CANCELLED;
            }
        }
        
        // Add user info to request attributes
        User user = getUserFromToken(token);
        request.setAttribute("user", user);
        
        return Action.CONTINUE;
    }
    
    @Override
    public int priority() {
        return 100; // High priority - execute early
    }
    
    private boolean isValidToken(String token) {
        // Token validation logic
        return token != null && token.length() > 10;
    }
    
    private User getUserFromToken(String token) {
        // Extract user from token
        return new User("user123", "John Doe");
    }
}

// Rate limiting interceptor
@AtmosphereInterceptorService
public class RateLimitInterceptor extends AtmosphereInterceptorAdapter {
    private final Map<String, TokenBucket> clientBuckets = new ConcurrentHashMap<>();
    private final int maxRequestsPerMinute = 60;
    
    @Override
    public Action intercept(AtmosphereResource resource) {
        String clientIp = resource.getRequest().getRemoteAddr();
        
        // Get or create token bucket for client
        TokenBucket bucket = clientBuckets.computeIfAbsent(clientIp, 
            k -> new TokenBucket(maxRequestsPerMinute, 1, TimeUnit.MINUTES));
        
        // Check if request is allowed
        if (!bucket.tryConsume()) {
            try {
                resource.getResponse().setStatus(429); // Too Many Requests
                resource.getResponse().setHeader("Retry-After", "60");
                resource.getResponse().getWriter().write("Rate limit exceeded");
                resource.getResponse().flushBuffer();
                return Action.CANCELLED;
            } catch (IOException e) {
                return Action.CANCELLED;
            }
        }
        
        return Action.CONTINUE;
    }
    
    @Override
    public int priority() {
        return 200; // Execute after authentication but before main processing
    }
}

// Request transformation interceptor
@AtmosphereInterceptorService
public class RequestTransformInterceptor extends AtmosphereInterceptorAdapter {
    
    @Override
    public Action intercept(AtmosphereResource resource) {
        AtmosphereRequest request = resource.getRequest();
        
        // Transform specific paths
        String pathInfo = request.getPathInfo();
        if (pathInfo != null && pathInfo.startsWith("/legacy/")) {
            // Rewrite legacy paths to new format
            String newPath = pathInfo.replace("/legacy/", "/api/v2/");
            
            // Create new request with transformed path
            AtmosphereRequest.Builder builder = new AtmosphereRequest.Builder();
            builder.request(request).pathInfo(newPath);
            
            // Replace request in resource
            resource.setRequest(builder.build());
        }
        
        // Add custom headers
        resource.getResponse().setHeader("X-Processed-By", "Atmosphere");
        resource.getResponse().setHeader("X-Request-Id", UUID.randomUUID().toString());
        
        return Action.CONTINUE;
    }
    
    @Override
    public void postInspect(AtmosphereResource resource) {
        // Add processing time header
        long processingTime = System.currentTimeMillis() - 
            (Long) resource.getRequest().getAttribute("startTime");
        resource.getResponse().setHeader("X-Processing-Time", String.valueOf(processingTime));
    }
    
    @Override
    public int priority() {
        return 500; // Medium priority
    }
}

Interceptor Chain Management

Utilities for managing and configuring interceptor execution chains.

/**
 * Interceptor chain configuration and management
 */
public class InterceptorManager {
    /**
     * Add interceptor to global chain
     * @param interceptor AtmosphereInterceptor to add
     */
    public void addInterceptor(AtmosphereInterceptor interceptor);
    
    /**
     * Remove interceptor from chain
     * @param interceptor AtmosphereInterceptor to remove
     */
    public void removeInterceptor(AtmosphereInterceptor interceptor);
    
    /**
     * Get all registered interceptors ordered by priority
     * @return List of interceptors in execution order
     */
    public List<AtmosphereInterceptor> getInterceptors();
    
    /**
     * Clear all interceptors
     */
    public void clearInterceptors();
}

Async I/O Interceptors

Special interceptors for handling asynchronous I/O operations.

/**
 * Intercept async I/O operations
 */
public interface AsyncIOInterceptor {
    /**
     * Intercept before payload is written
     * @param resource AtmosphereResource
     * @param data payload being written
     * @param offset write offset
     * @param length write length
     * @return modified payload or original data
     */
    public byte[] prePayload(AtmosphereResource resource, byte[] data, int offset, int length);
    
    /**
     * Intercept after payload is written
     * @param resource AtmosphereResource  
     * @param data payload that was written
     * @param offset write offset
     * @param length write length
     */
    public void postPayload(AtmosphereResource resource, byte[] data, int offset, int length);
    
    /**
     * Configure async I/O interceptor
     * @param config AtmosphereConfig
     */
    public void configure(AtmosphereConfig config);
}

/**
 * Adapter for AsyncIOInterceptor with default implementations
 */
public class AsyncIOInterceptorAdapter implements AsyncIOInterceptor {
    /**
     * Default pre-payload processing (return original data)
     */
    public byte[] prePayload(AtmosphereResource resource, byte[] data, int offset, int length) {
        return data;
    }
    
    /**
     * Default post-payload processing (no-op)
     */
    public void postPayload(AtmosphereResource resource, byte[] data, int offset, int length) {
        // Default: do nothing
    }
}

Usage Examples:

// Compression interceptor for async I/O
public class CompressionAsyncIOInterceptor extends AsyncIOInterceptorAdapter {
    
    @Override
    public byte[] prePayload(AtmosphereResource resource, byte[] data, int offset, int length) {
        // Check if client supports compression
        String acceptEncoding = resource.getRequest().getHeader("Accept-Encoding");
        if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
            
            try {
                // Compress data using GZIP
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                try (GZIPOutputStream gzipOut = new GZIPOutputStream(baos)) {
                    gzipOut.write(data, offset, length);
                }
                
                // Set compression headers
                resource.getResponse().setHeader("Content-Encoding", "gzip");
                resource.getResponse().setHeader("Vary", "Accept-Encoding");
                
                byte[] compressed = baos.toByteArray();
                System.out.println("Compressed " + length + " bytes to " + compressed.length + " bytes");
                
                return compressed;
                
            } catch (IOException e) {
                System.err.println("Compression failed: " + e.getMessage());
                return data; // Return original data on error
            }
        }
        
        return data; // No compression
    }
    
    @Override
    public void postPayload(AtmosphereResource resource, byte[] data, int offset, int length) {
        // Log compression statistics
        String contentEncoding = resource.getResponse().getHeader("Content-Encoding");
        if ("gzip".equals(contentEncoding)) {
            System.out.println("Sent compressed payload: " + length + " bytes");
        }
    }
}

Complete Interceptor Example

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

// Security interceptor chain
@AtmosphereInterceptorService
public class SecurityInterceptorChain extends AtmosphereInterceptorAdapter {
    private final AuthenticationService authService;
    private final AuditService auditService;
    
    public SecurityInterceptorChain() {
        this.authService = new AuthenticationService();
        this.auditService = new AuditService();
    }
    
    @Override
    public Action intercept(AtmosphereResource resource) {
        AtmosphereRequest request = resource.getRequest();
        String path = request.getPathInfo();
        
        // Skip authentication for public endpoints
        if (isPublicEndpoint(path)) {
            return Action.CONTINUE;
        }
        
        // Authenticate request
        String authResult = authenticateRequest(request);
        if (authResult == null) {
            sendUnauthorizedResponse(resource);
            return Action.CANCELLED;
        }
        
        // Check authorization
        if (!isAuthorized(authResult, path, request.getMethod())) {
            sendForbiddenResponse(resource);
            return Action.CANCELLED;
        }
        
        // Add security context to request
        request.setAttribute("securityContext", createSecurityContext(authResult));
        
        // Audit the request
        auditService.logAccess(authResult, path, request.getMethod(), 
                             request.getRemoteAddr());
        
        return Action.CONTINUE;
    }
    
    @Override
    public void postInspect(AtmosphereResource resource) {
        // Audit the response
        AtmosphereRequest request = resource.getRequest();
        SecurityContext context = (SecurityContext) request.getAttribute("securityContext");
        
        if (context != null) {
            int statusCode = resource.getResponse().getStatus();
            auditService.logResponse(context.getUserId(), request.getPathInfo(), 
                                   statusCode, System.currentTimeMillis());
        }
    }
    
    @Override
    public int priority() {
        return 50; // Very high priority - execute first
    }
    
    private boolean isPublicEndpoint(String path) {
        return path != null && (path.startsWith("/public/") || 
                               path.equals("/health") || 
                               path.equals("/status"));
    }
    
    private String authenticateRequest(AtmosphereRequest request) {
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            return authService.validateToken(token);
        }
        return null;
    }
    
    private boolean isAuthorized(String userId, String path, String method) {
        return authService.checkPermission(userId, path, method);
    }
    
    private void sendUnauthorizedResponse(AtmosphereResource resource) {
        try {
            resource.getResponse().setStatus(401);
            resource.getResponse().setContentType("application/json");
            resource.getResponse().getWriter()
                   .write("{\"error\":\"Unauthorized\",\"code\":401}");
            resource.getResponse().flushBuffer();
        } catch (IOException e) {
            // Log error
        }
    }
    
    private void sendForbiddenResponse(AtmosphereResource resource) {
        try {
            resource.getResponse().setStatus(403);
            resource.getResponse().setContentType("application/json");
            resource.getResponse().getWriter()
                   .write("{\"error\":\"Forbidden\",\"code\":403}");
            resource.getResponse().flushBuffer();
        } catch (IOException e) {
            // Log error
        }
    }
    
    private SecurityContext createSecurityContext(String userId) {
        return new SecurityContext(userId, authService.getUserRoles(userId));
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-atmosphere--atmosphere-runtime

docs

annotations.md

broadcasting.md

caching.md

core-framework.md

index.md

interceptors.md

websocket.md

tile.json