CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-eclipse-jetty--jetty-servlet

Eclipse Jetty servlet container providing comprehensive servlet, filter, and listener integration with lifecycle management and dynamic registration support.

Pending
Overview
Eval results
Files

filter-handling.mddocs/

Filter Handling

Filter handling in Eclipse Jetty provides comprehensive request/response filtering capabilities with support for different dispatcher types, URL pattern matching, and lifecycle management through the FilterHolder and FilterMapping classes.

FilterHolder

The FilterHolder manages individual filter instances, their configuration, and lifecycle.

public class FilterHolder extends Holder<Filter> {
    // Constructors
    public FilterHolder();
    public FilterHolder(Source source);
    public FilterHolder(Class<? extends Filter> filter);
    public FilterHolder(Filter filter);
    
    // Filter instance management
    public void setFilter(Filter filter);
    public Filter getFilter();
    
    // Lifecycle management
    public void doStart();
    public void initialize();
    public void doStop();
    public void destroyInstance(Object instance);
    
    // Registration access
    public FilterRegistration.Dynamic getRegistration();
    
    // String representation
    public String toString();
}

FilterMapping

The FilterMapping class defines how filters are applied to requests based on URL patterns, servlet names, and dispatcher types.

public class FilterMapping implements Dumpable {
    // Dispatcher type constants
    public static final int DEFAULT = 0;
    public static final int REQUEST = 1;
    public static final int FORWARD = 2;
    public static final int INCLUDE = 4;
    public static final int ERROR = 8;
    public static final int ASYNC = 16;
    public static final int ALL = 31;
    
    // Constructor
    public FilterMapping();
    
    // Filter identification
    public String getFilterName();
    public void setFilterName(String filterName);
    
    // URL pattern mapping
    public String[] getPathSpecs();
    public void setPathSpecs(String[] pathSpecs);
    public void setPathSpec(String pathSpec);
    
    // Servlet name mapping
    public String[] getServletNames();
    public void setServletNames(String[] servletNames);
    public void setServletName(String servletName);
    
    // Dispatcher type configuration
    public EnumSet<DispatcherType> getDispatcherTypes();
    public void setDispatcherTypes(EnumSet<DispatcherType> dispatcherTypes);
    public void setDispatches(int dispatches);
    public int getDispatches();
    
    // Mapping properties
    public boolean isDefaultMapping();
    public boolean isMatchAfter();
    public void setMatchAfter(boolean matchAfter);
    
    // Utility methods
    public String toString();
    public void dump(Appendable out, String indent);
}

Usage Examples

Basic Filter Registration

import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ServletHandler;
import jakarta.servlet.Filter;
import jakarta.servlet.DispatcherType;
import java.util.EnumSet;

// Create servlet handler
ServletHandler handler = new ServletHandler();

// Method 1: Add filter with mapping in one call
FilterHolder holder1 = handler.addFilterWithMapping(
    LoggingFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));

// Method 2: Add filter and mapping separately
FilterHolder holder2 = new FilterHolder("authFilter", AuthenticationFilter.class);
handler.addFilter(holder2);

FilterMapping mapping = new FilterMapping();
mapping.setFilterName("authFilter");
mapping.setPathSpec("/secure/*");
mapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD));
handler.addFilterMapping(mapping);

// Method 3: Using class name string
FilterHolder holder3 = handler.addFilterWithMapping(
    "com.example.CacheFilter", "/api/*", EnumSet.of(DispatcherType.REQUEST));

Filter Configuration and Initialization

import org.eclipse.jetty.servlet.FilterHolder;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;

// Create and configure filter holder
FilterHolder filterHolder = new FilterHolder("compressionFilter", CompressionFilter.class);

// Set initialization parameters
filterHolder.setInitParameter("threshold", "1024");
filterHolder.setInitParameter("mimeTypes", "text/html,text/css,application/javascript");
filterHolder.setInitParameter("enabled", "true");

// Set display name for management
filterHolder.setDisplayName("Content Compression Filter");

// Enable async support
filterHolder.setAsyncSupported(true);

// Add to handler with specific mapping
handler.addFilter(filterHolder);

// Create detailed mapping
FilterMapping mapping = new FilterMapping();
mapping.setFilterName("compressionFilter");
mapping.setPathSpecs(new String[]{"*.html", "*.css", "*.js", "/api/*"});
mapping.setDispatcherTypes(EnumSet.of(
    DispatcherType.REQUEST,
    DispatcherType.ASYNC
));
handler.addFilterMapping(mapping);

Dispatcher Type Configuration

import jakarta.servlet.DispatcherType;
import java.util.EnumSet;

// Security filter for all request types
FilterHolder securityFilter = new FilterHolder("security", SecurityFilter.class);
FilterMapping securityMapping = new FilterMapping();
securityMapping.setFilterName("security");
securityMapping.setPathSpec("/secure/*");
securityMapping.setDispatcherTypes(EnumSet.of(
    DispatcherType.REQUEST,   // Normal requests
    DispatcherType.FORWARD,   // RequestDispatcher.forward()
    DispatcherType.INCLUDE,   // RequestDispatcher.include()  
    DispatcherType.ERROR,     // Error page requests
    DispatcherType.ASYNC      // Async requests
));

// Logging filter for requests only
FilterHolder loggingFilter = new FilterHolder("logging", LoggingFilter.class);
FilterMapping loggingMapping = new FilterMapping();
loggingMapping.setFilterName("logging");
loggingMapping.setPathSpec("/*");
loggingMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));

// Cache filter for requests and forwards
FilterHolder cacheFilter = new FilterHolder("cache", CacheFilter.class);
FilterMapping cacheMapping = new FilterMapping();
cacheMapping.setFilterName("cache");
cacheMapping.setPathSpec("/static/*");
cacheMapping.setDispatcherTypes(EnumSet.of(
    DispatcherType.REQUEST,
    DispatcherType.FORWARD
));

// Add filters to handler
handler.addFilter(securityFilter);
handler.addFilterMapping(securityMapping);
handler.addFilter(loggingFilter);
handler.addFilterMapping(loggingMapping);
handler.addFilter(cacheFilter);
handler.addFilterMapping(cacheMapping);

Multiple Path Patterns

// Filter that handles multiple URL patterns
FilterHolder multiPatternFilter = new FilterHolder("multiPattern", MultiPatternFilter.class);

FilterMapping multiMapping = new FilterMapping();
multiMapping.setFilterName("multiPattern");
multiMapping.setPathSpecs(new String[]{
    "/api/v1/*",        // API version 1
    "/api/v2/*",        // API version 2  
    "*.json",           // All JSON requests
    "/admin/*",         // Admin interface
    "/reports/*"        // Reports section
});
multiMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));

handler.addFilter(multiPatternFilter);
handler.addFilterMapping(multiMapping);

Servlet Name Mapping

// Filter that applies to specific servlets by name
FilterHolder servletSpecificFilter = new FilterHolder("servletFilter", ServletSpecificFilter.class);

FilterMapping servletMapping = new FilterMapping();
servletMapping.setFilterName("servletFilter");
servletMapping.setServletNames(new String[]{
    "dataServlet",      // Apply to data servlet
    "reportServlet",    // Apply to report servlet
    "adminServlet"      // Apply to admin servlet
});
servletMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));

handler.addFilter(servletSpecificFilter);
handler.addFilterMapping(servletMapping);

// Can also set single servlet name
FilterMapping singleServletMapping = new FilterMapping();
singleServletMapping.setFilterName("servletFilter");
singleServletMapping.setServletName("criticalServlet");

Filter Ordering and Chain Management

import org.eclipse.jetty.servlet.ServletHandler;

// Create handler with filter chain configuration
ServletHandler handler = new ServletHandler();

// Enable filter chain caching for performance
handler.setFilterChainsCached(true);
handler.setMaxFilterChainsCacheSize(1000);

// Security filter - should run first
FilterHolder securityFilter = new FilterHolder("security", SecurityFilter.class);
FilterMapping securityMapping = new FilterMapping();
securityMapping.setFilterName("security");
securityMapping.setPathSpec("/*");
securityMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));

// Logging filter - should run after security
FilterHolder loggingFilter = new FilterHolder("logging", LoggingFilter.class);
FilterMapping loggingMapping = new FilterMapping();
loggingMapping.setFilterName("logging");
loggingMapping.setPathSpec("/*");
loggingMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));

// Compression filter - should run last  
FilterHolder compressionFilter = new FilterHolder("compression", CompressionFilter.class);
FilterMapping compressionMapping = new FilterMapping();
compressionMapping.setFilterName("compression");
compressionMapping.setPathSpec("/*");
compressionMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));

// Add filters in order (security -> logging -> compression)
handler.addFilter(securityFilter);
handler.addFilterMapping(securityMapping);

handler.addFilter(loggingFilter);
handler.addFilterMapping(loggingMapping);

handler.addFilter(compressionFilter);
handler.addFilterMapping(compressionMapping);

// Alternative: Use prepend to insert at beginning of chain
FilterMapping emergencyMapping = new FilterMapping();
emergencyMapping.setFilterName("emergency");
emergencyMapping.setPathSpec("/emergency/*");
handler.prependFilterMapping(emergencyMapping);

Advanced Filter Mapping

// Create complex filter with conditional matching
FilterHolder conditionalFilter = new FilterHolder("conditional", ConditionalFilter.class);
conditionalFilter.setInitParameter("enabledHours", "09:00-17:00");
conditionalFilter.setInitParameter("enabledDays", "MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY");

FilterMapping conditionalMapping = new FilterMapping();
conditionalMapping.setFilterName("conditional");
conditionalMapping.setPathSpec("/business/*");
conditionalMapping.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));

// Set to match after servlet matching (rare use case)
conditionalMapping.setMatchAfter(true);

handler.addFilter(conditionalFilter);
handler.addFilterMapping(conditionalMapping);

// Check if mapping is default mapping
if (conditionalMapping.isDefaultMapping()) {
    System.out.println("This is a default mapping");
}

// Check match after setting
if (conditionalMapping.isMatchAfter()) {
    System.out.println("Filter matches after servlet matching");
}

Filter Lifecycle Management

public class LifecycleAwareFilter implements Filter {
    private FilterConfig config;
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.config = filterConfig;
        System.out.println("Filter initialized: " + filterConfig.getFilterName());
        
        // Access initialization parameters
        Enumeration<String> paramNames = filterConfig.getInitParameterNames();
        while (paramNames.hasMoreElements()) {
            String name = paramNames.nextElement();
            String value = filterConfig.getInitParameter(name);
            System.out.println("  " + name + " = " + value);
        }
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        // Pre-processing
        long startTime = System.currentTimeMillis();
        
        try {
            // Continue filter chain
            chain.doFilter(request, response);
        } finally {
            // Post-processing
            long duration = System.currentTimeMillis() - startTime;
            System.out.println("Request processed in " + duration + "ms");
        }
    }
    
    @Override
    public void destroy() {
        System.out.println("Filter destroyed: " + config.getFilterName());
        config = null;
    }
}

// Configure lifecycle-aware filter
FilterHolder lifecycleFilter = new FilterHolder("lifecycle", LifecycleAwareFilter.class);
lifecycleFilter.setInitParameter("debug", "true");

// Start filter (calls init())
try {
    lifecycleFilter.start();
} catch (Exception e) {
    System.err.println("Failed to start filter: " + e.getMessage());
}

// Stop filter (calls destroy())
try {
    lifecycleFilter.stop();  
} catch (Exception e) {
    System.err.println("Failed to stop filter: " + e.getMessage());
}

Filter Registration and Dynamic Management

import jakarta.servlet.FilterRegistration;

// Create filter holder and get dynamic registration
FilterHolder dynamicFilter = new FilterHolder("dynamic", DynamicFilter.class);
handler.addFilter(dynamicFilter);

// Access filter registration for dynamic configuration
FilterRegistration.Dynamic registration = dynamicFilter.getRegistration();

if (registration != null) {
    // Set initialization parameters dynamically
    registration.setInitParameter("runtime.config", "dynamic-value");
    
    // Set async support
    registration.setAsyncSupported(true);
    
    // Add URL patterns dynamically
    registration.addMappingForUrlPatterns(
        EnumSet.of(DispatcherType.REQUEST), 
        true,  // isMatchAfter
        "/dynamic/*", "*.dyn"
    );
    
    // Add servlet name mappings
    registration.addMappingForServletNames(
        EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD),
        true,  // isMatchAfter  
        "dynamicServlet", "testServlet"
    );
}

Error Handling in Filters

public class ErrorHandlingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                        FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (ServletException | IOException e) {
            // Log error
            System.err.println("Error in filter chain: " + e.getMessage());
            
            // Set error attributes for error page
            request.setAttribute("jakarta.servlet.error.exception", e);
            request.setAttribute("jakarta.servlet.error.exception_type", e.getClass());
            request.setAttribute("jakarta.servlet.error.message", e.getMessage());
            
            // Forward to error page or re-throw
            if (response instanceof HttpServletResponse) {
                ((HttpServletResponse) response).sendError(500, "Internal Server Error");
            } else {
                throw e;
            }
        }
    }
}

// Configure error handling filter to run on ERROR dispatch type
FilterHolder errorFilter = new FilterHolder("errorHandler", ErrorHandlingFilter.class);
FilterMapping errorMapping = new FilterMapping();
errorMapping.setFilterName("errorHandler");
errorMapping.setPathSpec("/*");
errorMapping.setDispatcherTypes(EnumSet.of(
    DispatcherType.REQUEST,
    DispatcherType.ERROR
));

handler.addFilter(errorFilter);
handler.addFilterMapping(errorMapping);

Install with Tessl CLI

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

docs

error-handling.md

filter-handling.md

index.md

listeners.md

monitoring.md

servlet-context.md

servlet-handling.md

testing.md

tile.json