0
# Filter Handling
1
2
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.
3
4
## FilterHolder
5
6
The `FilterHolder` manages individual filter instances, their configuration, and lifecycle.
7
8
```java { .api }
9
public class FilterHolder extends Holder<Filter> {
10
// Constructors
11
public FilterHolder();
12
public FilterHolder(Source source);
13
public FilterHolder(Class<? extends Filter> filter);
14
public FilterHolder(Filter filter);
15
16
// Filter instance management
17
public void setFilter(Filter filter);
18
public Filter getFilter();
19
20
// Lifecycle management
21
public void doStart();
22
public void initialize();
23
public void doStop();
24
public void destroyInstance(Object instance);
25
26
// Registration access
27
public FilterRegistration.Dynamic getRegistration();
28
29
// String representation
30
public String toString();
31
}
32
```
33
34
## FilterMapping
35
36
The `FilterMapping` class defines how filters are applied to requests based on URL patterns, servlet names, and dispatcher types.
37
38
```java { .api }
39
public class FilterMapping implements Dumpable {
40
// Dispatcher type constants
41
public static final int DEFAULT = 0;
42
public static final int REQUEST = 1;
43
public static final int FORWARD = 2;
44
public static final int INCLUDE = 4;
45
public static final int ERROR = 8;
46
public static final int ASYNC = 16;
47
public static final int ALL = 31;
48
49
// Constructor
50
public FilterMapping();
51
52
// Filter identification
53
public String getFilterName();
54
public void setFilterName(String filterName);
55
56
// URL pattern mapping
57
public String[] getPathSpecs();
58
public void setPathSpecs(String[] pathSpecs);
59
public void setPathSpec(String pathSpec);
60
61
// Servlet name mapping
62
public String[] getServletNames();
63
public void setServletNames(String[] servletNames);
64
public void setServletName(String servletName);
65
66
// Dispatcher type configuration
67
public EnumSet<DispatcherType> getDispatcherTypes();
68
public void setDispatcherTypes(EnumSet<DispatcherType> dispatcherTypes);
69
public void setDispatches(int dispatches);
70
public int getDispatches();
71
72
// Mapping properties
73
public boolean isDefaultMapping();
74
public boolean isMatchAfter();
75
public void setMatchAfter(boolean matchAfter);
76
77
// Utility methods
78
public String toString();
79
public void dump(Appendable out, String indent);
80
}
81
```
82
83
## Usage Examples
84
85
### Basic Filter Registration
86
87
```java
88
import org.eclipse.jetty.servlet.FilterHolder;
89
import org.eclipse.jetty.servlet.FilterMapping;
90
import org.eclipse.jetty.servlet.ServletHandler;
91
import jakarta.servlet.Filter;
92
import jakarta.servlet.DispatcherType;
93
import java.util.EnumSet;
94
95
// Create servlet handler
96
ServletHandler handler = new ServletHandler();
97
98
// Method 1: Add filter with mapping in one call
99
FilterHolder holder1 = handler.addFilterWithMapping(
100
LoggingFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
101
102
// Method 2: Add filter and mapping separately
103
FilterHolder holder2 = new FilterHolder("authFilter", AuthenticationFilter.class);
104
handler.addFilter(holder2);
105
106
FilterMapping mapping = new FilterMapping();
107
mapping.setFilterName("authFilter");
108
mapping.setPathSpec("/secure/*");
109
mapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD));
110
handler.addFilterMapping(mapping);
111
112
// Method 3: Using class name string
113
FilterHolder holder3 = handler.addFilterWithMapping(
114
"com.example.CacheFilter", "/api/*", EnumSet.of(DispatcherType.REQUEST));
115
```
116
117
### Filter Configuration and Initialization
118
119
```java
120
import org.eclipse.jetty.servlet.FilterHolder;
121
import jakarta.servlet.Filter;
122
import jakarta.servlet.FilterConfig;
123
import jakarta.servlet.ServletException;
124
125
// Create and configure filter holder
126
FilterHolder filterHolder = new FilterHolder("compressionFilter", CompressionFilter.class);
127
128
// Set initialization parameters
129
filterHolder.setInitParameter("threshold", "1024");
130
filterHolder.setInitParameter("mimeTypes", "text/html,text/css,application/javascript");
131
filterHolder.setInitParameter("enabled", "true");
132
133
// Set display name for management
134
filterHolder.setDisplayName("Content Compression Filter");
135
136
// Enable async support
137
filterHolder.setAsyncSupported(true);
138
139
// Add to handler with specific mapping
140
handler.addFilter(filterHolder);
141
142
// Create detailed mapping
143
FilterMapping mapping = new FilterMapping();
144
mapping.setFilterName("compressionFilter");
145
mapping.setPathSpecs(new String[]{"*.html", "*.css", "*.js", "/api/*"});
146
mapping.setDispatcherTypes(EnumSet.of(
147
DispatcherType.REQUEST,
148
DispatcherType.ASYNC
149
));
150
handler.addFilterMapping(mapping);
151
```
152
153
### Dispatcher Type Configuration
154
155
```java
156
import jakarta.servlet.DispatcherType;
157
import java.util.EnumSet;
158
159
// Security filter for all request types
160
FilterHolder securityFilter = new FilterHolder("security", SecurityFilter.class);
161
FilterMapping securityMapping = new FilterMapping();
162
securityMapping.setFilterName("security");
163
securityMapping.setPathSpec("/secure/*");
164
securityMapping.setDispatcherTypes(EnumSet.of(
165
DispatcherType.REQUEST, // Normal requests
166
DispatcherType.FORWARD, // RequestDispatcher.forward()
167
DispatcherType.INCLUDE, // RequestDispatcher.include()
168
DispatcherType.ERROR, // Error page requests
169
DispatcherType.ASYNC // Async requests
170
));
171
172
// Logging filter for requests only
173
FilterHolder loggingFilter = new FilterHolder("logging", LoggingFilter.class);
174
FilterMapping loggingMapping = new FilterMapping();
175
loggingMapping.setFilterName("logging");
176
loggingMapping.setPathSpec("/*");
177
loggingMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));
178
179
// Cache filter for requests and forwards
180
FilterHolder cacheFilter = new FilterHolder("cache", CacheFilter.class);
181
FilterMapping cacheMapping = new FilterMapping();
182
cacheMapping.setFilterName("cache");
183
cacheMapping.setPathSpec("/static/*");
184
cacheMapping.setDispatcherTypes(EnumSet.of(
185
DispatcherType.REQUEST,
186
DispatcherType.FORWARD
187
));
188
189
// Add filters to handler
190
handler.addFilter(securityFilter);
191
handler.addFilterMapping(securityMapping);
192
handler.addFilter(loggingFilter);
193
handler.addFilterMapping(loggingMapping);
194
handler.addFilter(cacheFilter);
195
handler.addFilterMapping(cacheMapping);
196
```
197
198
### Multiple Path Patterns
199
200
```java
201
// Filter that handles multiple URL patterns
202
FilterHolder multiPatternFilter = new FilterHolder("multiPattern", MultiPatternFilter.class);
203
204
FilterMapping multiMapping = new FilterMapping();
205
multiMapping.setFilterName("multiPattern");
206
multiMapping.setPathSpecs(new String[]{
207
"/api/v1/*", // API version 1
208
"/api/v2/*", // API version 2
209
"*.json", // All JSON requests
210
"/admin/*", // Admin interface
211
"/reports/*" // Reports section
212
});
213
multiMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));
214
215
handler.addFilter(multiPatternFilter);
216
handler.addFilterMapping(multiMapping);
217
```
218
219
### Servlet Name Mapping
220
221
```java
222
// Filter that applies to specific servlets by name
223
FilterHolder servletSpecificFilter = new FilterHolder("servletFilter", ServletSpecificFilter.class);
224
225
FilterMapping servletMapping = new FilterMapping();
226
servletMapping.setFilterName("servletFilter");
227
servletMapping.setServletNames(new String[]{
228
"dataServlet", // Apply to data servlet
229
"reportServlet", // Apply to report servlet
230
"adminServlet" // Apply to admin servlet
231
});
232
servletMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));
233
234
handler.addFilter(servletSpecificFilter);
235
handler.addFilterMapping(servletMapping);
236
237
// Can also set single servlet name
238
FilterMapping singleServletMapping = new FilterMapping();
239
singleServletMapping.setFilterName("servletFilter");
240
singleServletMapping.setServletName("criticalServlet");
241
```
242
243
### Filter Ordering and Chain Management
244
245
```java
246
import org.eclipse.jetty.servlet.ServletHandler;
247
248
// Create handler with filter chain configuration
249
ServletHandler handler = new ServletHandler();
250
251
// Enable filter chain caching for performance
252
handler.setFilterChainsCached(true);
253
handler.setMaxFilterChainsCacheSize(1000);
254
255
// Security filter - should run first
256
FilterHolder securityFilter = new FilterHolder("security", SecurityFilter.class);
257
FilterMapping securityMapping = new FilterMapping();
258
securityMapping.setFilterName("security");
259
securityMapping.setPathSpec("/*");
260
securityMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));
261
262
// Logging filter - should run after security
263
FilterHolder loggingFilter = new FilterHolder("logging", LoggingFilter.class);
264
FilterMapping loggingMapping = new FilterMapping();
265
loggingMapping.setFilterName("logging");
266
loggingMapping.setPathSpec("/*");
267
loggingMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));
268
269
// Compression filter - should run last
270
FilterHolder compressionFilter = new FilterHolder("compression", CompressionFilter.class);
271
FilterMapping compressionMapping = new FilterMapping();
272
compressionMapping.setFilterName("compression");
273
compressionMapping.setPathSpec("/*");
274
compressionMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));
275
276
// Add filters in order (security -> logging -> compression)
277
handler.addFilter(securityFilter);
278
handler.addFilterMapping(securityMapping);
279
280
handler.addFilter(loggingFilter);
281
handler.addFilterMapping(loggingMapping);
282
283
handler.addFilter(compressionFilter);
284
handler.addFilterMapping(compressionMapping);
285
286
// Alternative: Use prepend to insert at beginning of chain
287
FilterMapping emergencyMapping = new FilterMapping();
288
emergencyMapping.setFilterName("emergency");
289
emergencyMapping.setPathSpec("/emergency/*");
290
handler.prependFilterMapping(emergencyMapping);
291
```
292
293
### Advanced Filter Mapping
294
295
```java
296
// Create complex filter with conditional matching
297
FilterHolder conditionalFilter = new FilterHolder("conditional", ConditionalFilter.class);
298
conditionalFilter.setInitParameter("enabledHours", "09:00-17:00");
299
conditionalFilter.setInitParameter("enabledDays", "MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY");
300
301
FilterMapping conditionalMapping = new FilterMapping();
302
conditionalMapping.setFilterName("conditional");
303
conditionalMapping.setPathSpec("/business/*");
304
conditionalMapping.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
305
306
// Set to match after servlet matching (rare use case)
307
conditionalMapping.setMatchAfter(true);
308
309
handler.addFilter(conditionalFilter);
310
handler.addFilterMapping(conditionalMapping);
311
312
// Check if mapping is default mapping
313
if (conditionalMapping.isDefaultMapping()) {
314
System.out.println("This is a default mapping");
315
}
316
317
// Check match after setting
318
if (conditionalMapping.isMatchAfter()) {
319
System.out.println("Filter matches after servlet matching");
320
}
321
```
322
323
### Filter Lifecycle Management
324
325
```java
326
public class LifecycleAwareFilter implements Filter {
327
private FilterConfig config;
328
329
@Override
330
public void init(FilterConfig filterConfig) throws ServletException {
331
this.config = filterConfig;
332
System.out.println("Filter initialized: " + filterConfig.getFilterName());
333
334
// Access initialization parameters
335
Enumeration<String> paramNames = filterConfig.getInitParameterNames();
336
while (paramNames.hasMoreElements()) {
337
String name = paramNames.nextElement();
338
String value = filterConfig.getInitParameter(name);
339
System.out.println(" " + name + " = " + value);
340
}
341
}
342
343
@Override
344
public void doFilter(ServletRequest request, ServletResponse response,
345
FilterChain chain) throws IOException, ServletException {
346
// Pre-processing
347
long startTime = System.currentTimeMillis();
348
349
try {
350
// Continue filter chain
351
chain.doFilter(request, response);
352
} finally {
353
// Post-processing
354
long duration = System.currentTimeMillis() - startTime;
355
System.out.println("Request processed in " + duration + "ms");
356
}
357
}
358
359
@Override
360
public void destroy() {
361
System.out.println("Filter destroyed: " + config.getFilterName());
362
config = null;
363
}
364
}
365
366
// Configure lifecycle-aware filter
367
FilterHolder lifecycleFilter = new FilterHolder("lifecycle", LifecycleAwareFilter.class);
368
lifecycleFilter.setInitParameter("debug", "true");
369
370
// Start filter (calls init())
371
try {
372
lifecycleFilter.start();
373
} catch (Exception e) {
374
System.err.println("Failed to start filter: " + e.getMessage());
375
}
376
377
// Stop filter (calls destroy())
378
try {
379
lifecycleFilter.stop();
380
} catch (Exception e) {
381
System.err.println("Failed to stop filter: " + e.getMessage());
382
}
383
```
384
385
### Filter Registration and Dynamic Management
386
387
```java
388
import jakarta.servlet.FilterRegistration;
389
390
// Create filter holder and get dynamic registration
391
FilterHolder dynamicFilter = new FilterHolder("dynamic", DynamicFilter.class);
392
handler.addFilter(dynamicFilter);
393
394
// Access filter registration for dynamic configuration
395
FilterRegistration.Dynamic registration = dynamicFilter.getRegistration();
396
397
if (registration != null) {
398
// Set initialization parameters dynamically
399
registration.setInitParameter("runtime.config", "dynamic-value");
400
401
// Set async support
402
registration.setAsyncSupported(true);
403
404
// Add URL patterns dynamically
405
registration.addMappingForUrlPatterns(
406
EnumSet.of(DispatcherType.REQUEST),
407
true, // isMatchAfter
408
"/dynamic/*", "*.dyn"
409
);
410
411
// Add servlet name mappings
412
registration.addMappingForServletNames(
413
EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD),
414
true, // isMatchAfter
415
"dynamicServlet", "testServlet"
416
);
417
}
418
```
419
420
### Error Handling in Filters
421
422
```java
423
public class ErrorHandlingFilter implements Filter {
424
@Override
425
public void doFilter(ServletRequest request, ServletResponse response,
426
FilterChain chain) throws IOException, ServletException {
427
try {
428
chain.doFilter(request, response);
429
} catch (ServletException | IOException e) {
430
// Log error
431
System.err.println("Error in filter chain: " + e.getMessage());
432
433
// Set error attributes for error page
434
request.setAttribute("jakarta.servlet.error.exception", e);
435
request.setAttribute("jakarta.servlet.error.exception_type", e.getClass());
436
request.setAttribute("jakarta.servlet.error.message", e.getMessage());
437
438
// Forward to error page or re-throw
439
if (response instanceof HttpServletResponse) {
440
((HttpServletResponse) response).sendError(500, "Internal Server Error");
441
} else {
442
throw e;
443
}
444
}
445
}
446
}
447
448
// Configure error handling filter to run on ERROR dispatch type
449
FilterHolder errorFilter = new FilterHolder("errorHandler", ErrorHandlingFilter.class);
450
FilterMapping errorMapping = new FilterMapping();
451
errorMapping.setFilterName("errorHandler");
452
errorMapping.setPathSpec("/*");
453
errorMapping.setDispatcherTypes(EnumSet.of(
454
DispatcherType.REQUEST,
455
DispatcherType.ERROR
456
));
457
458
handler.addFilter(errorFilter);
459
handler.addFilterMapping(errorMapping);
460
```