Java Jersey: Get client IP in rest method on Tomcat - rest

I have a Jersey rest webservice that runs on tomcat 6. I have a #Post method that consumes Multipart:
#Path("identify")
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_XML)
public String identifyReception(com.sun.jersey.multipart.MultiPart multiPart) throws Exception {
I would like to get the client IP address inside this method. I found out that you can use #Context HttpServletRequest inside Get method. But in post method I need the multipart input argument. I have also found out that tomcat does not support Servlet specification...
Is there another way I can do it?

I found out that you can use #Context HttpServletRequest inside Get method. But in post method I need the multipart input argument.
I don't think the two are mutually exclusive. Let your method take two arguments (I don't think it matters what order they're in) and annotate one of them with #Context. I believe that will work whether it's a get, post, whatever. You could also just annotate a field with #Context and Jersey will initialize it for you before it calls your #GET method.

Related

How can I get the IP address of the caller in a Jersey 2.25.1 application?

I've tried the approach here without luck: As the comments in the answer there mentions the HttpServletRequest is just null.
This is my filter:
public void myFilter(ContainerRequestContext request) throws IOException
{
// I don't see a way to get the IP address from the ContainerRequestContext
}
If I try to use #Context HttpServletRequest httpServletRequest, as the answer in the other question suggests, I just get a NullPointerException.
Another similar question: How to get source address / ip from inside ContainerResponseFilter
The nullpointerexception only occured in our tests. peeskillet helped me realize that injecting HttpServletRequest won't work as long as we're using jersey-test-framework-provider-jetty for our tests (see for example https://github.com/jersey/jersey/issues/2764 or https://github.com/jersey/jersey/issues/3092). If we had used something like GrizzlyWebTestContainerFactory, then injecting the HttpServletRequest would work since we then would have a ServletDeploymentContext.
We went for this solution in our tests, i.e. just mocking the HttpServletRequest where needed.

Create Spring Boot RestController dynamically

I need to create a Rest endpoint dynamically in my Spring Boot application. Instead of statically creating the class with #RestController, is there a way to instantiate and activate a Rest service at runtime? It should be possible to specify the endpoint, input parameters etc at runtime.
Are there some Groovy options too?
Thanks,
Sandeep Joseph
I think the approach to take would be to create a custom MvcEndpoint that will handle all requests on a specific path, from there depending on your internal configuration you can process requests. It's basically just a Servlet (that's also an option). You're fully in control of the request.
public class MyEndpoint extends AbstractMvcEndpoint
// can optionally implements ApplicationContextAware, ServletContextAware
// to inject configuration, etc.
{
#RequestMapping("/dynamic-enpoints-prefix/**")
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// here you have the request and response. Can do anything.
}
}

Jersey 2: filters and #Context injections

I've the following question:
ContainerRequestFilter is a singleton, but reading this:
Jaxrs-2_0 Oracle Spec
in chapter 9.2, they say:
Context is specific to a particular request but instances of certain JAX-RS components (providers and resource classes with a lifecycle other than per-request) may need to support multiple concurrent requests. When injecting an instance of one of the types listed in Section 9.2, the instance supplied MUST be capable of selecting the correct context for a particular request. Use of a thread-local proxy is a common way to achieve this.
In the chapter 9.2, the HttpServletRequest is not mentioned.
So the question is: is it safe in terms of concurrency to inject the HttpServletRequest inside a custom ContainRequestFilter?
I mean this:
#Provider
#PreMatching
public class AuthenticationFilter implements ContainerRequestFilter {
#Context private HttpServletRequest request;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// This is safe because every thread call the method with its requestContext
String path = requestContext.getUriInfo().getPath(true);
// Is this safe? The property request is injected by using #Context annotation (see above)
String toReturn = (String)request.getAttribute(name);
[...]
}
I did some empirical tests on my IDE in debug mode, sending with two different browsers two different and concurrent requests and it seems to work well; I noticed that the filter's instance is ever the same (it's a singleton), but the injected HttpServletRequest is different in the two cases.
I readed even this thread: How to access wicket session from Jersey-2 request filter? and it seems that my tests are confirmed.
But I still have doubts.
Confirm?
Yes it's safe. To understand the problem, you should understand how scopes work. In any framework that deals with scopes (and injection), the feature is implemented similarly. If an object is in a singleton scope and another object in a lesser scope needs to be injected, usually a proxy of the object will be injected instead. When a call is made on the object, it's actually a call on the proxy.
Though the spec may not mention the HttpServletRequest specifically, most JAX-RS implementation have support for this. With Jersey in particular, if this was not possible (meaning the object is not proxiable), then you would get an error message on startup with something like "not within a request scope". The reason is that the ContainerRequestFilter is created on app startup, and all the injections are handled at that time also. If the HttpServletRequest was not proxiable, it would fail to inject because on startup, there is no request scope context.
To confirm that it is not the actual HttpServletRequest and is a proxy, you can log the request.getClass(), and you will see that it is indeed a proxy.
If you are unfamiliar with this pattern, you can see this answer for an idea of how it works.
See Also:
Injecting Request Scoped Objects into Singleton Scoped Object with HK2 and Jersey

How to make the result from a request factory call available for for injection using GIN?

I have a proxy, let's call it ConfigParametersProxy.
It has a method (for example) String getParameter1();
It is a request factory managed value proxy.
I want to be able to do this with it in my java/gwt code...
#Inject
ConfigParameterProxy parameters;
How do I set this up so this works?
I am using GIN, so have a client module etc.

Java EE UriInfo: append Query parameters

I want to append the query parameters list of a received UriInfo in a Rest service. The query comes from the client with some parameters and I need to add some more in server side.
I tried with:
uriInfo.getQueryParameters().add("Param", "value");
but when I display the URI, it doesn't has the new parameter.
On the other hand, if I do it like this:
URI uri = uriInfo.getRequestUriBuilder().queryParam("Param", "value").build();
when I display the URI, it contains the new parameter. The problem in this second case is to reconstruct a UriInfo object to give to the next functions, they require it.
I've seen that it cannot be instantiated, it has no constructors, it has to be added with #Context, its value can be updated by another UriInfo... but how to create this UriInfo with the URI I modified?
It is not possible to modify a UriInfo, there are no methods defined for that. The only option is to recreate it using one implementation of the interface. The only implementation available is org.jboss.resteasy.spi.ResteasyUriInfo.
The problem is that when deployed, and the function using it is called, it throws a ClassDefNotFound exception; even with a dependency in the manifest pointing to resteasy-jaxrs-2.3.2.Final.jar
So, the only option is to make our own implementation of the interface.