Using javax.ws.rs.core.Context with fabric3 - java

I am trying to implement a ContainerRequestFilter for a RESTful web service with fabric3v2.5.3. I have the filter working, but I need to grab the ip address in the request. I have tried using
#Context
HttpServletRequest servletRequest;
But it throws a null pointer exception when trying access the HttpServletRequest. We are using the built in jersey 2.13 that comes with the JAX-RS fabric3 extension. Is there a way to get the #Context to work within fabric3?

#Context injection support will be added in Fabric 3.0 and is not available in previous versions.
For versions earlier than Fabric3 3.0, you can retrieve the HTTP servlet request and response objects via an injected Fabric3RequestContext:
public class SomeFilter implements .... {
#Context
protected F3RequestContext context;
public void filter(ContainerRequestContext requestContext) {
HttpServletRequest req =
context.getHeader(HttpServletRequest.class, "fabric3.httpRequest");
}
}

Related

spring boot get controller class out of ServletRequest in a AuthorizationFilter

Heee there,
right now I am totally stuck. I spend hours asking google but I haven't found any solution or approach yet. Maybe you guys can help me.
Some background information:
I am developing a microservice into an existing microservice infrastructure. I want to use spring boot and connect the service to our existing authentication service. There are plenty of other jax rs microservices which are already connected to it. I started with an authentication and an authorization filter. The authentication filter works perfectly.
The problem:
I want to use my own "Secured" annotation like in the other services.
So there are some annotated resource methods in controllers like this example one:
#Secured({Role.ADMIN,...})
#RequestMapping(value = "/interfaces", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ExportInvoiceInterfaceResponseRepListWrapper> getAll() {
...
}
so when the following filter gets triggered I want to read the roles of the annotated controller method. In jax rs I just used the Class ResourceInfo to do so. As you may know I can't use this class in a default spring boot setup. Is there any way to get the class "the spring boot way"?
public class AuthorizationFilter extends GenericFilterBean {
#Context
private ResourceInfo resourceInfo;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// Get the resource class which matches with the requested URL
// Extract the roles declared by it
Class<?> resourceClass = resourceInfo.getResourceClass();
List<Role> classRoles = extractRoles(resourceClass);
...
}
Any help would be awesome. Thank you in advanced.
Cheers
Frank

How to use Jersey's internal routing mechanism to extract a class/method reference?

I have a Jersey 1.8 application running. Jersey is running as a Servlet.
I need to write a servlet filter that given a plain request/response, is able to figure out which REST resource/method will respond to the request and extract values from annotations.
For example, imagine I have the following resource:
#Path("/foo")
#MyAnnotation("hello")
public class FooResource {
#GET
#Path("/bar")
#MyOtherAnnotation("world")
public Response bar(){
...
}
}
When a request GET /foo/bar comes in, I need my servlet filter to be able to extract the values "hello" and "world" from MyAnnotation and MyOtherAnnotation before Jersey's own servlet processes the request.
This filter logic should be able to work for all requests and all resources registered.
Is there a way to access Jersey's internal routing mechanism to obtain a class/method reference where Jersey will dispatch the request?
I'm open to other suggestions as well, but ideally nothing like trying to hack my own routing mechanism by reading the #Path annotations myself.
#Provider
#Priority(Priorities.AUTHORIZATION)
public class MyFilter implements ContainerRequestFilter
#Context // request scoped proxy
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (resourceInfo.getResourceClass().isAnnotationPresent(MyAnnotationion.class) ||
resourceInfo.getResourceMethod().isAnnotationPresent(MyOtherAnnotation.class)) {
to register the filter use
bind(AuthFilter.class).to(ContainerRequestFilter.class).in(Singleton.class);

Setting response header using interceptor?

I'm writing jax-rs end points. For some set of end points (existing code), I want to set an extra response header which was actually generated in #AroundInvoke interceptor and set to HttpServletRequest attribute. In #AroundInvoke I'm able to access HttpServletRequest using #Inject. But it seems I cannot access HttpServletResponse in the same interceptor itself.
It seems I can do with PostProcessorInterceptor but again I'm confused with the following doc.
The org.jboss.resteasy.spi.interception.PostProcessInterceptor runs after the JAX-RS method was invoked but before MessageBodyWriters are invoked. They can only be used on the server side. Use them if you need to set a response header when there might not be any MessageBodyWriter invoked.
I'm using resteasy, jackson. If I use PostProcessorInterceptor can I inject HttpServletResponse? Or Can I set new http header there some how?
Any code example/direction would be appreciated.
With JaxRS 2 (which comes with javaEE 7) you can use a ContainerResponseFilter see also
public class PoweredByResponseFilter implements ContainerResponseFilter {
#Inject
HttpServletRequest request;
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
String name = "X-My-Header";
String value = "";// some data from request
responseContext.getHeaders().add(name, value);
}
}

Injecting contextual data in Resteasy tests with Netty

I'm trying to test a resource with Resteasy using an embedded Netty instance as described in the Resteasy Docs.
Injecting path parameters and query parameters works like a charm but then I tried to test a resource that injects HttpServletRequest and HttpServletResponse from the context like this:
#GET
#Path("/")
public void example(#Context HttpServletResponse response,
#Context HttpServletRequest request) { ... }
Resteasy cannot find HttpServletRequestin the context and throws the following exception:
5105 [r #1] DEB o.j.resteasy.core.SynchronousDispatcher - PathInfo: /auth
5201 [r #1] ERR c.s.f.v.s.r.e.ApplicationExceptionMapper - Unhandled application exception: Unable to find contextual data of type: javax.servlet.http.HttpServletRequest
org.jboss.resteasy.spi.LoggableFailure: Unable to find contextual data of type: javax.servlet.http.HttpServletRequest
I tried putting mock versions of request and response in the context as suggested in RESTEasy Mock vs. Exception Mapper vs. Context but it does not work either as the contextual data is a ThreadLocal and Netty spawns a new thread for each request.
Any ideas on how to solve this?
What worked in my case was injecting a org.jboss.seam.mock.HttpServletRequest, since I am using seam in my application. You should try some mock framework like spring.test or mockito.
Here is how my code looks like:
import org.jboss.resteasy.core.Dispatcher;
import org.jboss.resteasy.mock.MockDispatcherFactory;
import org.jboss.resteasy.mock.MockHttpRequest;
import org.jboss.resteasy.mock.MockHttpResponse;
import org.jboss.resteasy.plugins.server.resourcefactory.POJOResourceFactory;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.seam.mock.MockHttpServletRequest;
import org.jboss.seam.mock.DBUnitSeamTest;
public class Test extends DBUnitSeamTest{
#Test
public void test() throws Exception {
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
POJOResourceFactory noDefaults = new POJOResourceFactory(ClasstoBeTested.class); dispatcher.getRegistry().addResourceFactory(noDefaults);
MockHttpRequest request = MockHttpRequest.get("/serviceToBeTested/1961");
MockHttpResponse response = new MockHttpResponse();
HttpServletRequest servletRequest = new MockHttpServletRequest(getSession());
ResteasyProviderFactory.getContextDataMap().put(HttpServletRequest.class, servletRequest);
dispatcher.invoke(request, response);
Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatus());
Assert.assertTrue(response.getContentAsString().contains("1961"));
}
}
I just got hit by this again on another project and decided to investigate once more.
The issue is that in a mock request with Netty, there is no HttpServletRequest available. If you look into the sources of NettyJaxrsServerand related classes, Reasteasy uses its own abstraction for http requests that do not implement HttpServletRequest.
If I change my implementation to use these abstractions, I can access request and response in my resource.
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
#GET
#Path("/")
public void example(#Context HttpResponse response,
#Context HttpRequest request) { ... }
This is not perfect, because it makes my resources depend on Resteasy interfaces but I decided to go with it for now to support mock testing of multipart data.

How can I extract request attributes from Jersey's ContainerRequest?

HttpServletRequest has a method setAttribute(String, Object).
How can I extract this attribute from ContainterRequest?
I didn't find: getAttribute method!
Code
public class AuthenticationFilter implements Filter {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpReq = (HttpServletRequest) servletRequest;
// .... ....
httpReq.setAttribute("businessId", businessId);
}
}
In Jersey Filter:
private class Filter implements ResourceFilter, ContainerRequestFilter {
public ContainerRequest filter(ContainerRequest request) {
// ..extract the attribute from the httpReq
}
}
You can't. They're not exposed through the Jersey API in any way. If you search the Jersey codebase, you'll find that there are no uses of HttpServletRequest.getAttributeNames(), which you'd expect to be used if they were being copied en masse. You'll also find that there are only a handful of uses of HttpServletRequest.getAttribute(), and it's strictly for internal bookkeeping.
Note, however, that when deployed in a Servlet Context, JAX-RS allows you to inject the original HttpServletRequest using the #Context annotation. I'm not certain whether you can do this in a Jersey filter, but it works in MessageBodyReaders/Writers and in resource classes.
Update: I've checked, and you can, in fact, inject the HttpServletRequest into a Jersey ContainerRequestFilter by simply including:
#Context private HttpServletRequest httpRequest;
If you're using Jersey 2, which implements JAX-RS 2.0, you can implement a ContainerRequestFilter which defines a filter method as follows:
public void filter(ContainerRequestContext requestContext) throws IOException;
ContainerRequestContext has getProperty(String) and setProperty(String, Object) methods, which in a Servlet environment (ServletPropertiesDelegate), map to the servlet request's getAttribute(String) and setAttribute(String, Object) methods.
See: Jersey on GitHub
I got the #Context working, but have the problem is that my ContainerRequestFilter is singleton.
I had to implement a custom javax.servlet.Filter and use a ThreadLocal to store the HttpServletRequest.
I wanted to add to previous answers my solution, in addition to adding context:
#Context
private HttpServletRequest httpRequest;
You should set and get attributes from the session.
Set:
httpRequest.getSession().setAttribute("businessId", "yourId");
Get:
Object attribute = httpRequest.getSession().getAttribute("businessId");

Categories