Reputation: 1887
I have register two ContainerRequestFilter
filters and one ContainerResponseFilter
in my application class that extends a JAX-RS Application:
filters as :
register(LoggingResponseFilter.class);
register(AuthorizationRequestFilter.class);
register(LikeRequestFilter.class);
and when I tries to call a targeted method resource I have an Exception.
Resource method as :
@Override
@POST
@Path("/{userId}/like")
@TokenResource
@GMTResource // to validate GMT of client and server
@Like // for like filter
public Response like(@HeaderParam("token") @NotNull String token,
@HeaderParam("user-agent") String userAgent,
@NotNull @Valid UserFriendsBaseModel userFriendsBaseModel)
throws BadRequestException, UnauthorizedException,
ForbiddenException, InternalServerError {
userService.like(userFriendsBaseModel,userAgent);
return Response.ok().build();
}
Exception :
javax.servlet.ServletException: org.glassfish.jersey.server.ContainerException: java.io.IOException: Stream closed
org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:419)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:221)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
root cause
org.glassfish.jersey.server.ContainerException: java.io.IOException: Stream closed
org.glassfish.jersey.servlet.internal.ResponseWriter.rethrow(ResponseWriter.java:256)
org.glassfish.jersey.servlet.internal.ResponseWriter.failure(ResponseWriter.java:238)
org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:480)
org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:311)
org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
org.glassfish.jersey.internal.Errors.process(Errors.java:315)
org.glassfish.jersey.internal.Errors.process(Errors.java:297)
org.glassfish.jersey.internal.Errors.process(Errors.java:267)
org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:286)
org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1072)
org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:399)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:221)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
root cause
java.io.IOException: Stream closed
org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:312)
org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:200)
org.glassfish.jersey.message.internal.EntityInputStream.read(EntityInputStream.java:101)
org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream.read(ReaderInterceptorExecutor.java:301)
com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper.ensureLoaded(ByteSourceJsonBootstrapper.java:503)
com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper.detectEncoding(ByteSourceJsonBootstrapper.java:129)
com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper.constructParser(ByteSourceJsonBootstrapper.java:224)
com.fasterxml.jackson.core.JsonFactory._createParser(JsonFactory.java:1242)
com.fasterxml.jackson.core.JsonFactory.createParser(JsonFactory.java:753)
com.fasterxml.jackson.jaxrs.base.ProviderBase._createParser(ProviderBase.java:791)
com.fasterxml.jackson.jaxrs.base.ProviderBase.readFrom(ProviderBase.java:760)
org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:259)
org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:235)
org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundReadFrom(MappableExceptionWrapperInterceptor.java:74)
org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1075)
org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:853)
org.glassfish.jersey.server.ContainerRequest.readEntity(ContainerRequest.java:270)
org.glassfish.jersey.server.internal.inject.EntityParamValueFactoryProvider$EntityValueFactory.provide(EntityParamValueFactoryProvider.java:96)
org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:81)
org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:125)
org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:158)
org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:97)
org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:303)
org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
org.glassfish.jersey.internal.Errors.process(Errors.java:315)
org.glassfish.jersey.internal.Errors.process(Errors.java:297)
org.glassfish.jersey.internal.Errors.process(Errors.java:267)
org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:286)
org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1072)
org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:399)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:221)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
I have also set the priority for request filters as:
@Priority(200)
public class LikeRequestFilter implements ContainerRequestFilter {
private final Logger _logger = LoggerFactory.getLogger(LikeRequestFilter.class);
@Inject
ResourceInfo resourceInfo;
@Inject
UriInfo uriInfo;
@Autowired
UserManager userManager;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (resourceInfo.getResourceMethod().isAnnotationPresent(Like.class)) {
try {
ObjectMapper jsonMapper = new ObjectMapper();
final UserFriendsBaseModel usm = jsonMapper
.readValue(requestContext.getEntityStream(), UserFriendsBaseModel.class);
boolean isLiked = userManager.isLiked(usm);
/**
* If already liked (on api server db ) the check for other conditions
* otherwise consider as first time like request and send to resource for processing
*/
if(isLiked) {
/**
* Check if already liked on openfire
*/
boolean isRoster = userManager.isRoster(usm);
/**
* if already roster then check for reverse like
* else add entry in add roster failure request
*/
if(isRoster) {
/**
* Check if reverse like on api server if liked then check for openfire
*/
final UserFriendsBaseModel reverseModel = UserFriendsBaseModel.reverse(usm);
boolean isReverseLiked = userManager.isLiked(reverseModel);
/**
* Reverse liked(Friends) on api server db . Check on openfire
*/
if(isReverseLiked) {
boolean isReverseRoster = userManager.isRosterFriend(reverseModel);
/**
* If friend on openfire then send push to both user for new Match
*/
if(isReverseRoster) {
// TODO send push
} else {
userManager.addRosterFailureRequest(reverseModel);
}
}
} else {
userManager.addRosterFailureRequest(usm);
}
requestContext.abortWith(Response.ok().build());
}
} catch (Exception e) {
_logger.error("Something went wrong in Like request Filter", e);
}
_logger.info("end of if in LIKE Filter : ");
}
_logger.info("End of LIKE Filter : ");
}
}
and for AuthorizationRequestFilter
filter as :
@Priority(100)
public class AuthorizationRequestFilter implements ContainerRequestFilter {
private final Logger _logger = LoggerFactory
.getLogger(AuthorizationRequestFilter.class);
@Inject
ResourceInfo resourceInfo;
@Inject
UriInfo uriInfo;
@Autowired
AuthorizationService authorizationService;
and a Response filter as :
public class LoggingResponseFilter implements ContainerResponseFilter {
final static Logger _logger = Logger.getLogger(LoggingResponseFilter.class
.getName());
public void filter(ContainerRequestContext requestContext,ContainerResponseContext responseContext) throws IOException {
String method = requestContext.getMethod();
_logger.info("Requesting : " + method + " for path " + requestContext.getUriInfo().getPath());
then problem occurs in LikeRequestFilter
when it calls in filter chain after AuthorizationRequestFilter
.
I am unable to find out what's going wrong ? how to chain request filter with response filter ?
Upvotes: 3
Views: 4405
Reputation: 208984
The problem is with the LikeRequestFilter
. You are reading the request entity InputStream
with the ObjectMapper
. Generally, InputStream
s can only be read once, then they are empty. For this reason, after the ObjectMapper
reads the stream, it closes it. So when Jersey tries to read it, it can't, as it's closed. Even if it wasn't closed, it would still be empty.
For this use case, Jersey allows us to buffer the stream, so it can be read multiple times. What you need to do though is cast the ContainerRequestContext
to ContainerRequest
, which has a bufferEntity()
method. It also has methods to help with the reading of the stream, like readEntity
, that is used similar to the client Response#readEntity()
.
So you could do something like
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
try {
ContainerRequest cr = (ContainerRequest) requestContext;
cr.bufferEntity();
final UserFriendsBaseModel bm = cr.readEntity(UserFriendsBaseModel.class);
Upvotes: 3