Nestor Milyaev
Nestor Milyaev

Reputation: 6595

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?

Upvotes: 1

Views: 651

Answers (3)

Nestor Milyaev
Nestor Milyaev

Reputation: 6595

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.

Upvotes: 0

ACV
ACV

Reputation: 10562

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 :-)");
    }
}

Upvotes: 1

gsl
gsl

Reputation: 676

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.

Upvotes: 1

Related Questions