0
# Server Container
1
2
The server container APIs provide server-side processing capabilities including request/response filtering, asynchronous processing, resource management, and dynamic configuration. These APIs enable cross-cutting concerns like authentication, logging, caching, and custom request processing.
3
4
## Core Imports
5
6
```java
7
import javax.ws.rs.container.ContainerRequestContext;
8
import javax.ws.rs.container.ContainerResponseContext;
9
import javax.ws.rs.container.ContainerRequestFilter;
10
import javax.ws.rs.container.ContainerResponseFilter;
11
import javax.ws.rs.container.DynamicFeature;
12
import javax.ws.rs.core.FeatureContext;
13
import javax.ws.rs.container.PreMatching;
14
import javax.ws.rs.container.Suspended;
15
16
import javax.ws.rs.container.AsyncResponse;
17
import javax.ws.rs.container.CompletionCallback;
18
import javax.ws.rs.container.ConnectionCallback;
19
import javax.ws.rs.container.TimeoutHandler;
20
21
import javax.ws.rs.container.ResourceContext;
22
import javax.ws.rs.container.ResourceInfo;
23
24
import javax.ws.rs.core.Response;
25
import javax.ws.rs.ext.Provider;
26
27
import java.io.IOException;
28
import java.util.concurrent.TimeUnit;
29
```
30
31
## Request and Response Context
32
33
### ContainerRequestContext Interface
34
35
Provides access to request processing information on the server side.
36
37
```java { .api }
38
public interface ContainerRequestContext {
39
40
Object getProperty(String name);
41
Collection<String> getPropertyNames();
42
void setProperty(String name, Object object);
43
void removeProperty(String name);
44
45
UriInfo getUriInfo();
46
void setRequestUri(URI requestUri);
47
void setRequestUri(URI baseUri, URI requestUri);
48
49
Request getRequest();
50
String getMethod();
51
void setMethod(String method);
52
53
MultivaluedMap<String, String> getHeaders();
54
String getHeaderString(String name);
55
56
Date getDate();
57
Locale getLanguage();
58
int getLength();
59
MediaType getMediaType();
60
List<MediaType> getAcceptableMediaTypes();
61
List<Locale> getAcceptableLanguages();
62
63
Map<String, Cookie> getCookies();
64
65
boolean hasEntity();
66
InputStream getEntityStream();
67
void setEntityStream(InputStream input);
68
69
SecurityContext getSecurityContext();
70
void setSecurityContext(SecurityContext context);
71
72
void abortWith(Response response);
73
}
74
```
75
76
### ContainerResponseContext Interface
77
78
Provides access to response processing information on the server side.
79
80
```java { .api }
81
public interface ContainerResponseContext {
82
83
int getStatus();
84
void setStatus(int code);
85
StatusType getStatusInfo();
86
void setStatusInfo(StatusType statusInfo);
87
88
MultivaluedMap<String, Object> getHeaders();
89
MultivaluedMap<String, String> getStringHeaders();
90
String getHeaderString(String name);
91
92
Set<String> getAllowedMethods();
93
94
Date getDate();
95
Date getLastModified();
96
URI getLocation();
97
Set<Link> getLinks();
98
boolean hasLink(String relation);
99
Link getLink(String relation);
100
Link.Builder getLinkBuilder(String relation);
101
102
boolean hasEntity();
103
Object getEntity();
104
Class<?> getEntityClass();
105
Type getEntityType();
106
void setEntity(Object entity);
107
void setEntity(Object entity, Annotation[] annotations, MediaType mediaType);
108
109
Annotation[] getEntityAnnotations();
110
MediaType getMediaType();
111
112
OutputStream getEntityStream();
113
void setEntityStream(OutputStream outputStream);
114
}
115
```
116
117
## Request and Response Filters
118
119
### ContainerRequestFilter Interface
120
121
Filters incoming server requests.
122
123
```java { .api }
124
@Provider
125
public interface ContainerRequestFilter {
126
127
void filter(ContainerRequestContext requestContext) throws IOException;
128
}
129
```
130
131
### ContainerResponseFilter Interface
132
133
Filters outgoing server responses.
134
135
```java { .api }
136
@Provider
137
public interface ContainerResponseFilter {
138
139
void filter(ContainerRequestContext requestContext,
140
ContainerResponseContext responseContext) throws IOException;
141
}
142
```
143
144
**Filter Implementation Examples:**
145
146
```java
147
// Authentication filter
148
@Provider
149
@Priority(Priorities.AUTHENTICATION)
150
public class AuthenticationFilter implements ContainerRequestFilter {
151
152
@Override
153
public void filter(ContainerRequestContext requestContext) throws IOException {
154
String authorization = requestContext.getHeaderString("Authorization");
155
156
if (authorization == null || !authorization.startsWith("Bearer ")) {
157
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
158
.entity("Authentication required")
159
.build());
160
return;
161
}
162
163
String token = authorization.substring("Bearer ".length());
164
if (!isValidToken(token)) {
165
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
166
.entity("Invalid token")
167
.build());
168
}
169
}
170
171
private boolean isValidToken(String token) {
172
// Token validation logic
173
return tokenService.validate(token);
174
}
175
}
176
177
// Logging filter
178
@Provider
179
public class LoggingFilter implements ContainerRequestFilter, ContainerResponseFilter {
180
181
@Override
182
public void filter(ContainerRequestContext requestContext) throws IOException {
183
System.out.println("Request: " + requestContext.getMethod() + " " +
184
requestContext.getUriInfo().getRequestUri());
185
186
// Store request timestamp
187
requestContext.setProperty("request.timestamp", System.currentTimeMillis());
188
}
189
190
@Override
191
public void filter(ContainerRequestContext requestContext,
192
ContainerResponseContext responseContext) throws IOException {
193
Long startTime = (Long) requestContext.getProperty("request.timestamp");
194
long duration = System.currentTimeMillis() - startTime;
195
196
System.out.println("Response: " + responseContext.getStatus() +
197
" (took " + duration + "ms)");
198
}
199
}
200
201
// CORS filter
202
@Provider
203
@PreMatching
204
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
205
206
@Override
207
public void filter(ContainerRequestContext requestContext) throws IOException {
208
if ("OPTIONS".equals(requestContext.getMethod())) {
209
requestContext.abortWith(Response.ok().build());
210
}
211
}
212
213
@Override
214
public void filter(ContainerRequestContext requestContext,
215
ContainerResponseContext responseContext) throws IOException {
216
responseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
217
responseContext.getHeaders().add("Access-Control-Allow-Methods",
218
"GET, POST, PUT, DELETE, OPTIONS");
219
responseContext.getHeaders().add("Access-Control-Allow-Headers",
220
"Content-Type, Authorization");
221
}
222
}
223
```
224
225
### @PreMatching Annotation
226
227
Marks filters to be executed before resource method matching.
228
229
```java { .api }
230
@Target({ElementType.TYPE})
231
@Retention(RetentionPolicy.RUNTIME)
232
@Documented
233
public @interface PreMatching {
234
}
235
```
236
237
**Pre-matching Filter Example:**
238
239
```java
240
@Provider
241
@PreMatching
242
@Priority(Priorities.HEADER_DECORATOR)
243
public class PreMatchingFilter implements ContainerRequestFilter {
244
245
@Override
246
public void filter(ContainerRequestContext requestContext) throws IOException {
247
// Modify request before resource matching
248
String userAgent = requestContext.getHeaderString("User-Agent");
249
if (userAgent != null && userAgent.contains("mobile")) {
250
// Redirect mobile users to mobile API
251
String uri = requestContext.getUriInfo().getRequestUri().toString();
252
String mobileUri = uri.replace("/api/", "/mobile-api/");
253
requestContext.setRequestUri(URI.create(mobileUri));
254
}
255
}
256
}
257
```
258
259
## Dynamic Configuration
260
261
### DynamicFeature Interface
262
263
Allows runtime configuration of providers based on resource information.
264
265
```java { .api }
266
public interface DynamicFeature {
267
268
void configure(ResourceInfo resourceInfo, FeatureContext context);
269
}
270
```
271
272
**Dynamic Feature Example:**
273
274
```java
275
@Provider
276
public class SecurityDynamicFeature implements DynamicFeature {
277
278
@Override
279
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
280
Method method = resourceInfo.getResourceMethod();
281
282
// Apply authentication filter only to methods annotated with @Secured
283
if (method.isAnnotationPresent(Secured.class)) {
284
context.register(AuthenticationFilter.class);
285
}
286
287
// Apply admin filter to admin methods
288
if (method.isAnnotationPresent(AdminRequired.class)) {
289
context.register(AdminAuthorizationFilter.class, Priorities.AUTHORIZATION);
290
}
291
}
292
}
293
294
// Custom security annotations
295
@Retention(RetentionPolicy.RUNTIME)
296
@Target({ElementType.METHOD, ElementType.TYPE})
297
public @interface Secured {
298
}
299
300
@Retention(RetentionPolicy.RUNTIME)
301
@Target({ElementType.METHOD})
302
public @interface AdminRequired {
303
}
304
305
// Usage in resource
306
@Path("/admin")
307
public class AdminResource {
308
309
@GET
310
@Path("/users")
311
@Secured
312
@AdminRequired
313
public List<User> getAllUsers() {
314
return userService.findAll();
315
}
316
}
317
```
318
319
### FeatureContext Interface
320
321
Provides a context for configuring providers dynamically.
322
323
```java { .api }
324
public interface FeatureContext extends Configurable<FeatureContext> {
325
326
// Inherited from Configurable<FeatureContext>:
327
Configuration getConfiguration();
328
FeatureContext property(String name, Object value);
329
FeatureContext register(Class<?> componentClass);
330
FeatureContext register(Class<?> componentClass, int priority);
331
FeatureContext register(Class<?> componentClass, Class<?>... contracts);
332
FeatureContext register(Class<?> componentClass, Map<Class<?>, Integer> contracts);
333
FeatureContext register(Object component);
334
FeatureContext register(Object component, int priority);
335
FeatureContext register(Object component, Class<?>... contracts);
336
FeatureContext register(Object component, Map<Class<?>, Integer> contracts);
337
}
338
```
339
340
## Asynchronous Processing
341
342
### AsyncResponse Interface
343
344
Provides asynchronous response processing capabilities.
345
346
```java { .api }
347
public interface AsyncResponse {
348
349
boolean resume(Object response);
350
boolean resume(Throwable response);
351
352
boolean cancel();
353
boolean cancel(int retryAfter);
354
boolean cancel(Date retryAfter);
355
356
boolean isSuspended();
357
boolean isCancelled();
358
boolean isDone();
359
360
boolean setTimeout(long time, TimeUnit unit);
361
void setTimeoutHandler(TimeoutHandler handler);
362
363
Collection<Class<?>> register(Class<?> callback);
364
Map<Class<?>, Collection<Class<?>>> register(Class<?> callback, Class<?>... callbacks);
365
Collection<Class<?>> register(Object callback);
366
Map<Class<?>, Collection<Class<?>>> register(Object callback, Object... callbacks);
367
}
368
```
369
370
### @Suspended Annotation
371
372
Marks a parameter for AsyncResponse injection.
373
374
```java { .api }
375
@Target({ElementType.PARAMETER})
376
@Retention(RetentionPolicy.RUNTIME)
377
@Documented
378
public @interface Suspended {
379
}
380
```
381
382
**Asynchronous Processing Examples:**
383
384
```java
385
@Path("/async")
386
public class AsyncResource {
387
388
@Inject
389
private ExecutorService executorService;
390
391
// Simple async processing
392
@GET
393
@Path("/users/{id}")
394
public void getUser(@PathParam("id") String userId,
395
@Suspended AsyncResponse asyncResponse) {
396
397
executorService.submit(() -> {
398
try {
399
User user = userService.findById(userId);
400
asyncResponse.resume(user);
401
} catch (Exception e) {
402
asyncResponse.resume(e);
403
}
404
});
405
}
406
407
// Async with timeout
408
@GET
409
@Path("/expensive-operation")
410
public void expensiveOperation(@Suspended AsyncResponse asyncResponse) {
411
412
// Set 30 second timeout
413
asyncResponse.setTimeout(30, TimeUnit.SECONDS);
414
asyncResponse.setTimeoutHandler(ar ->
415
ar.resume(Response.status(Response.Status.REQUEST_TIMEOUT)
416
.entity("Operation timed out")
417
.build())
418
);
419
420
executorService.submit(() -> {
421
try {
422
String result = performExpensiveOperation();
423
asyncResponse.resume(Response.ok(result).build());
424
} catch (Exception e) {
425
asyncResponse.resume(Response.serverError()
426
.entity("Operation failed")
427
.build());
428
}
429
});
430
}
431
432
// Async with callbacks
433
@POST
434
@Path("/process")
435
public void processData(DataRequest request,
436
@Suspended AsyncResponse asyncResponse) {
437
438
// Register callbacks
439
asyncResponse.register(CompletionCallback.class);
440
asyncResponse.register(ConnectionCallback.class);
441
442
CompletableFuture.supplyAsync(() -> dataProcessor.process(request))
443
.thenAccept(asyncResponse::resume)
444
.exceptionally(throwable -> {
445
asyncResponse.resume(throwable);
446
return null;
447
});
448
}
449
}
450
```
451
452
### Completion and Connection Callbacks
453
454
```java { .api }
455
public interface CompletionCallback {
456
457
void onComplete(Throwable throwable);
458
}
459
460
public interface ConnectionCallback {
461
462
void onDisconnect(AsyncResponse disconnected);
463
}
464
```
465
466
### TimeoutHandler Interface
467
468
```java { .api }
469
public interface TimeoutHandler {
470
471
void handleTimeout(AsyncResponse asyncResponse);
472
}
473
```
474
475
**Callback Implementation Examples:**
476
477
```java
478
@Provider
479
public class AsyncCallbacks implements CompletionCallback, ConnectionCallback {
480
481
@Override
482
public void onComplete(Throwable throwable) {
483
if (throwable == null) {
484
System.out.println("Async operation completed successfully");
485
} else {
486
System.err.println("Async operation failed: " + throwable.getMessage());
487
}
488
}
489
490
@Override
491
public void onDisconnect(AsyncResponse disconnected) {
492
System.out.println("Client disconnected, cancelling operation");
493
// Cleanup resources, cancel background tasks, etc.
494
}
495
}
496
497
// Custom timeout handler
498
public class CustomTimeoutHandler implements TimeoutHandler {
499
500
@Override
501
public void handleTimeout(AsyncResponse asyncResponse) {
502
// Custom timeout response
503
ErrorResponse error = new ErrorResponse("TIMEOUT",
504
"Request processing timed out");
505
asyncResponse.resume(Response.status(Response.Status.REQUEST_TIMEOUT)
506
.entity(error)
507
.build());
508
}
509
}
510
```
511
512
## Resource Management
513
514
### ResourceContext Interface
515
516
Injectable helper for creating and initializing resource instances.
517
518
```java { .api }
519
public interface ResourceContext {
520
521
<T> T getResource(Class<T> resourceClass);
522
<T> T initResource(T resource);
523
}
524
```
525
526
### ResourceInfo Interface
527
528
Injectable interface providing runtime information about matched resource method.
529
530
```java { .api }
531
public interface ResourceInfo {
532
533
Method getResourceMethod();
534
Class<?> getResourceClass();
535
}
536
```
537
538
**Resource Management Examples:**
539
540
```java
541
@Path("/composite")
542
public class CompositeResource {
543
544
@Context
545
private ResourceContext resourceContext;
546
547
@GET
548
@Path("/user-orders/{userId}")
549
public Response getUserOrders(@PathParam("userId") String userId) {
550
551
// Get other resource instances
552
UserResource userResource = resourceContext.getResource(UserResource.class);
553
OrderResource orderResource = resourceContext.getResource(OrderResource.class);
554
555
// Use resources to build composite response
556
User user = userResource.getUser(userId);
557
List<Order> orders = orderResource.getUserOrders(userId);
558
559
UserOrdersResponse response = new UserOrdersResponse(user, orders);
560
return Response.ok(response).build();
561
}
562
}
563
564
// Resource info usage in filter
565
@Provider
566
public class ResourceInfoFilter implements ContainerRequestFilter {
567
568
@Context
569
private ResourceInfo resourceInfo;
570
571
@Override
572
public void filter(ContainerRequestContext requestContext) throws IOException {
573
Method method = resourceInfo.getResourceMethod();
574
Class<?> resourceClass = resourceInfo.getResourceClass();
575
576
System.out.println("Processing request for " +
577
resourceClass.getSimpleName() + "." + method.getName());
578
579
// Apply method-specific processing
580
if (method.isAnnotationPresent(Audited.class)) {
581
// Enable auditing for this request
582
requestContext.setProperty("audit.enabled", true);
583
}
584
}
585
}
586
```
587
588
## Name Binding
589
590
Name binding allows selective application of filters and interceptors.
591
592
**Name Binding Example:**
593
594
```java
595
// Define name binding annotation
596
@NameBinding
597
@Retention(RetentionPolicy.RUNTIME)
598
@Target({ElementType.TYPE, ElementType.METHOD})
599
public @interface Compress {
600
}
601
602
// Filter bound to @Compress annotation
603
@Provider
604
@Compress
605
public class CompressionFilter implements ContainerResponseFilter {
606
607
@Override
608
public void filter(ContainerRequestContext requestContext,
609
ContainerResponseContext responseContext) throws IOException {
610
611
String acceptEncoding = requestContext.getHeaderString("Accept-Encoding");
612
if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
613
// Apply gzip compression
614
responseContext.getHeaders().add("Content-Encoding", "gzip");
615
// Wrap output stream with GZIPOutputStream
616
}
617
}
618
}
619
620
// Apply to specific methods
621
@Path("/data")
622
public class DataResource {
623
624
@GET
625
@Path("/large")
626
@Compress // Compression filter will be applied
627
public LargeDataSet getLargeData() {
628
return dataService.getLargeDataSet();
629
}
630
631
@GET
632
@Path("/small")
633
// No compression for small responses
634
public SmallData getSmallData() {
635
return dataService.getSmallData();
636
}
637
}
638
```
639
640
## Priority Constants
641
642
JAX-RS provides priority constants for ordering filters and interceptors.
643
644
```java { .api }
645
public final class Priorities {
646
647
public static final int AUTHENTICATION = 1000;
648
public static final int AUTHORIZATION = 2000;
649
public static final int HEADER_DECORATOR = 3000;
650
public static final int ENTITY_CODER = 4000;
651
public static final int USER = 5000;
652
}
653
```
654
655
**Priority Usage Example:**
656
657
```java
658
@Provider
659
@Priority(Priorities.AUTHENTICATION)
660
public class AuthenticationFilter implements ContainerRequestFilter {
661
// Executed first (lowest priority number)
662
}
663
664
@Provider
665
@Priority(Priorities.AUTHORIZATION)
666
public class AuthorizationFilter implements ContainerRequestFilter {
667
// Executed after authentication
668
}
669
670
@Provider
671
@Priority(Priorities.HEADER_DECORATOR)
672
public class HeaderDecoratorFilter implements ContainerResponseFilter {
673
// Executed for response processing
674
}
675
```