Geolocation in Java Jersey - java

I would like to know if it is possible to call a method for every matching HTTP request.
My case:
I need to send geolocation data in http headers, I send the request, it matches a defined operation and at the same time my geolocation is updated.
I can easily replicate a method call for each method in each class, but I would rather find a more adequate way to solve this problem.
Thank you for reading.

What you are looking for is a Jersey ResponseFilter. Here is a very simple example that adds a static header to every outgoing request:
package my.package;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
public class SimpleFilter implements ContainerResponseFilter
{
private static final String HEADER = "MyHeader";
public SimpleFilter()
{
}
#Override
public ContainerResponse filter(final ContainerRequest request, final ContainerResponse response)
{
response.getHttpHeaders().add(HEADER, "MyValue");
return response;
}
}
You can access various information through the request and response parameters to the filter method.
You will need to add the filter through your web.xml file to activate it:
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>my.package.SimpleFilter</param-value>
</init-param>

Related

Java JAX-RS react on ANY endpoint invocation

I have a class implementing a JAX-RS endpoint, as per below:
#Produces({MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_FORM_URLENCODED})
#Path("/site/")
public class ApiSiteResource extends AbstractContentResource {
...
#GET
#Path("/article/")
public Map<String, Object> getArticle (#Context HttpServletRequest request, #Context HttpServletResponse reponse, #BeanParam ApiParams params) {
//do stuff
}
#GET
#Path("/category/")
public Map<String, Object> getCategory (#Context HttpServletRequest request, #Context HttpServletResponse reponse, #BeanParam ApiParams params) {
//do stuff
}
What I need is to perform common processing (for example, capture analytics data) when any of the endponts of the above REST class is invoked, e.g., both for /site/article/ and /site/category/. I'm ideally looking for a solution that would be invoked at the end of the method execution, and ideally with least possible change to the existing methods code, so adding another method call at the end of the method is not the best option as that leads to too much code coupling. Ideally, I would like processing to be fired from an external class.
Is there a way how that could be done?
I am using a method of the Resource class that is annotated with the #Context Annotation and has a parameter that is injected from the context scope.
/**
* This method is called by JAX-RS for each request before
* the identified resource method is invoked, since it is
* annotated with the Context Annotation and carries a
* context-scope parameter which is injected.
*/
#Context
public void setServletContext( ServletContext servletContext ) {
...
}
(If you remove the ServletContext parameter, the automatic invocation on each resource call vanishes - at least in Jersey.)
Furthermore, you can put this method in a base class, say DefaultResourceImpl, which your Resource classes can extend, so you have this for all your Resource classes.
You can use JAX-RS Filters and Interceptors
For example there exist Request filters and response filters. You may do some stuff there:
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Response;
public class PoweredByResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
responseContext.getHeaders().add("X-Powered-By", "Jersey :-)");
}
}
Thank you all for your useful replies and comments.
Actually, capturing analytics was just half the story. In fact, I've also needed to add response headers.
So, I ended up implementing a filter as below:
public class ApiResourceHeadersFilter extends OncePerRequestFilter {
public ApiResourceHeadersFilter() {
}
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.setHeader("Access-Control-Allow-Headers", "accept");
response.setHeader("Access-Control-Allow-Methods", "GET OPTIONS");
filterChain.doFilter(request, response);
}
}
Plus added a mapping in the web.xml:
<filter>
<filter-name>ApiResourceHeadersFilter</filter-name>
<filter-class>com.workangel.eap.filters.ApiResourceHeadersFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ApiResourceHeadersFilter</filter-name>
<url-pattern>/api/site/*</url-pattern>
</filter-mapping>
Works like a charm; no messy code dependencies or modification. I'm sure I can extend it further should I need to collect analytics data as well.

How to retrieve ServletRequest using Jersey and Java EE 5

I'm working on creating a security library that will be used by several RESTful clients. I'm using Java EE 5, Jersey 1.17 and Maven. The clients will use my library to call a third party app using a token. The third party app will then return all the information it has on that token, like expiration, scope and userId.
My idea is to make a filter that will check if there is an Authorization header, and if that's so, it calls the third party app. If the third party app validates the token and returns the token's info, I need to return that information, stored in a TokenInformation object, back to the resources. In a previous post, someone said that I could do this:
public class MyFilter implements Filter{
#Override
public void doFilter(final ServletRequest request,
final ServletResponse response,
final FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String header = req.getHeader("Authorization");
TokenInformation info = new TokenInformation();
info = buildInfo(info);
if (true) {
request.setAttribute("auth", info);
chain.doFilter(request, response);
} else {
handleError(response);
}
}
}
So, by sending the TokenInformation object to the request as an additional attribute, I would be able to retrieve it later in the resource classes. The thing is that I'm using Java EE 5, and I didn't realize that I couldn't use the #Context annotation to inject the ServletRequest object. How can I access the ServletRequest object again from a resource class, so that I can access the TokenInformation object in, for example, the DAO?
The way I'm using jersey is by doing this in my web.xml:
<servlet>
<servlet-name>Security API</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.ni.apps.engineering.securitylibrary.resources.SecurityResource</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Security API</servlet-name>
<url-pattern>/1/*</url-pattern>
</servlet-mapping>
The SecurityResource class has this:
public class SecurityResource extends Application{
public static final String SUPPORTED_REPRESENTATIONS = MediaType.APPLICATION_XML
+ "," + MediaType.APPLICATION_JSON;
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>();
set.add(Security.class);
return set;
}
}
The Security class has this:
#Path("")
public class Security implements ISecurity{
#Override
public Response get(String upId) {
String test = "";
try{
TokenInformation tI = (TokenInformation) HttpServletRequestWrapper.
test = "test1";
}catch(Exception e){
System.out.println(e.getMessage());
}
return null;
}
}
You don't have to access ServletRequest at Dao layer.
In Servlet you can get ServletRequest object and you can pass the value to Dao layer.
If you really want to access then pass ServletRequest object to Dao layer by reference.
<servlet-name>Security API</servlet-name>
<servlet-class>com.packagename.MyServlet</servlet-class>
public MyServlet extends com.sun.jersey.spi.container.servlet.ServletContainer{}
You can extend jersey servlet and you can initialize Servlet with Application Class by programatically.
In MyServlet you can reach the request object.
Servlet Information :
https://jersey.java.net/apidocs/1.17/jersey/com/sun/jersey/spi/container/servlet/ServletContainer.html

is it possible to call one jax-rs method from another?

suppose i have some jax-rs resource class:
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class ResourceA {
#GET
public Something get(#Context UriInfo uriInfo) {
if (...) {
//how to get to ResourceB ?
}
}
}
and i want to conditionally redirect the call to some other jax-rs resource:
public class ResourceB {
#GET
#Path("{identifier}")
public Other get(#PathParam("identifier")String someArg) {
}
}
how do i do this?
note that i dont want this to be visible to the client (so no http redirects) and generally the resource methods i want to redirect to dont share the same signature (they may have path params etc as in the example i gave).
im running jersey 2.6 under apache tomcat (its a spring app, if thats any help)
EDIT - im looking for a jax-rs equivalent of servlet forward. i dont want to do an extra http hop or worry abour instantiating resource classes myself
You can get it using ResourceContext as follows:
#Context
ResourceContext resourceContext;
This will inject the ResourceContext into your Resource. You then get the resource you want using:
ResourceB b = resourceContext.getResource(ResourceB.class);
The Javadoc for ResourceContext is here. You can find a similar question here
I'm not aware of any possibility to do this from a resource method, but if it fits your use case, what you could do is implement your redirect logic in a pre matching request filter, for example like so:
#Provider
#PreMatching
public class RedirectFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) {
UriInfo uriInfo = requestContext.getUriInfo();
String prefix = "/redirect";
String path = uriInfo.getRequestUri().getPath();
if (path.startsWith(prefix)) {
String newPath = path.substring(prefix.length());
URI newRequestURI = uriInfo.getBaseUriBuilder().path(newPath).build();
requestContext.setRequestUri(newRequestURI);
}
}
}
This will redirect every request to /redirect/some/resource to /some/resource (or whatever you pass to requestContext.setRequestUri()) internally, before the resource method has been matched to the request and is executed and without http redirects or an additional internal http request.

Spring 3.2.x: skip the controller method in case of 406 Not Acceptable

So, let's have this simple controller:
#Controller
public class MyController {
private static final Logger logger = LoggerFactory.getLogger(MyController.class);
#RequestMapping(value="/entities", method = RequestMethod.GET)
public #ResponseBody ResultPojo getSomething() {
logger.info("getSometing");
return new ResultPojo();
}
}
...and the following context fragment:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Which basically means I want to be able to return nothing but json representations of the result bean, otherwise return 406.
If I send a GET request with accept=application/json, everything works fine, a json representation is returned in the http response with the 200 Ok status.
If I send a GET request with accept=application/xml, 406 is returned.
My problem in the second case is that even though 406 is returned eventually, the getSomething() method is still called (which I can see in the log). While this is no big deal for GET methods, it can cause confusion for POST methods (the resource is altered, but 406 is returned).
Is there a simple way to tell SpringMVC to check the accept header and return 406 before invoking the controller method? Or do I have to develop a custom http SpringMVC interceptor?
Is there a simple way to tell SpringMVC to check the accept header and return 406 before
invoking the controller method? Or do I have to develop a custom http SpringMVC interceptor?
the problem is I would have to put the produces clause to every
#RequestMapping in every controller. I'd like to set this on an
application level.
as far as I know there is no simpler method with SpringMVC. However, using standard JEE filters this is not very hard to do either. Just do something like:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class YourFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
if (request.getRequestHeader("Accept").contains("application/json")) {
chain.doFilter(req, res);
} else {
((HttpServletResponse)response).setStatus(SC_NOT_ACCEPTABLE);
}
}
public void init(FilterConfig config) throws ServletException {
// any startup stuff here if needed
}
public void destroy() {
// add code to release any resource
}
}
and:
<filter>
<filter-name>YourFilter</filter-name>
<filter-class>
path.to.YourFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>YourFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(didn't test the code, but it should be about right)
Maybe this is what you want:
#RequestMapping(value = "/entities", method = RequestMethod.GET, headers = {"content-type=application/json"})
methodName() {
...
}

Case-insensitive query string request parameters

My goal is that all below URI's should work
https://rest/xyz?sort=name
https://rest/xyz?Sort=name
https://rest/xyz?filter=name=value
https://rest/xyz?Filter=name=value
To achieve this, I have created custom filter that overrides the HttpServletRequest that is passed to the FilterChain. Below is the link for this approach:
http://forum.springsource.org/archive/index.php/t-87433.html
My code:
import java.io.IOException;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class HttpCustomParamFilter implements Filter
{
private static class HttpServletRequestCustomeWrapper extends HttpServletRequestWrapper
{
private String[] parameterValues;
#Override
public String[] getParameterValues(String name)
{
Map<String, String[]> localParameterMap = super.getParameterMap();
// Handle case insensitivity of http request paramters like start, count, query, sort, filter etc.
if (localParameterMap != null && !localParameterMap.isEmpty())
{
parameterValues = new String[localParameterMap.size()];
for (String key : localParameterMap.keySet())
{
if (name.equalsIgnoreCase(key))
parameterValues = localParameterMap.get(key);
else
parameterValues = null;
}
}
return parameterValues;
}
public HttpServletRequestCustomWrapper(final ServletRequest request)
{
super((HttpServletRequest) request);
}
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// override the request passed to the FilterChain
chain.doFilter(new HttpServletRequestCustomWrapper(request), response);
}
#Override
public void init(FilterConfig filterConfig)
throws ServletException
{
// TODO Auto-generated method stub
}
#Override
public void destroy()
{
// TODO Auto-generated method stub
}
}
In this code, i have overriden getParameterValues(String name) method and achieved case-insensitivity of request paramters, but not sure if i need to override any other methods.
my doubts:
do i need to override other methods also like getParameter() and getParameterNames()?
what internal implementation is impacted with this?
which class i can see the code implementation of getParameter(), getParameterNames() and getParameterValues()?
First, let me say my peace: I don't think modifying the HttpServletRequestWrapper is the way to go. I am not even sure how you would go about using it, as my understanding is it's App Server specific. As a side note, this article has specifics on how to use the HttpServletRequest to get a case-insensitive query param without rolling your own.
But, in the spirit of answering your questions:
Do you need to override getParameter() and getParameterNames()? You could, as it would give you the ability to manipulate the case. In fact, I would say the safest way to make the query parameters case-insensitive would be to overwrite ONLY those methods. Make the getParameter() call do a case-insensitive equals on the string names. Not sure what you would do with getParameterNames(), maybe return every possible case, but this seems redundant.
What internal implementation is impacted by this? I am not certain. HttpServletRequest is so core to pretty much everything, there is no telling what you could introduce if your code is not 100% solid. For instance, Spring has a SecurityContextHolderAwareRequestWrapper, so does that mean you just broke Spring Security? No telling without a lot of testing.
Which class can I see the code implementation of getParameter(), getParameterNames(), and getParameterValues()? HttpServletRequestWrapper is the only implementation of HttpServletRequest interface, according to the JavaDocs. The actual implementation of this class is dependent on your application container. For instance, in my app its weblogic.servlet.internal.ServletRequestImpl, since I use Web Logic. Hopefully you are using an open-source app server that has the code readily available. The way I found this was to put a break in one of my Controller handler methods that has HttpServletRequest defined and viewing it's getClass() response in the debugger.

Categories