Red Hat Training

A Red Hat training course is available for Red Hat Fuse

59.3. Container Response Filter

Overview

This section explains how to implement and register a container response filter, which is used to intercept an outgoing response message on the server side. Container response filters can be used to populate headers automatically in a response message and, in general, can be used for any kind of generic response processing.

ContainerResponseFilter interface

The javax.ws.rs.container.ContainerResponseFilter interface is defined as follows:
// Java
...
package javax.ws.rs.container;

import java.io.IOException;

public interface ContainerResponseFilter {
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
            throws IOException;
}
By implementing the ContainerResponseFilter, you can create a filter for the ContainerResponse extension point on the server side, which filters the response message after the invocation has executed.
Note
The container response filter gives you access both to the request message (through the requestContext argument) and the response message (through the responseContext message), but only the response can be modified at this stage.

ContainerResponseContext interface

The filter method of ContainerResponseFilter receives two arguments: an argument of type javax.ws.rs.container.ContainerRequestContext (see the section called “ContainerRequestContext interface”); and an argument of type javax.ws.rs.container.ContainerResponseContext, which can be used to access the outgoing response message and its related metadata.
The ContainerResponseContext interface is defined as follows:
// Java
...
package javax.ws.rs.container;

import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.core.EntityTag;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.MessageBodyWriter;

public interface ContainerResponseContext {

    public int getStatus();

    public void setStatus(int code);

    public Response.StatusType getStatusInfo();

    public void setStatusInfo(Response.StatusType statusInfo);

    public MultivaluedMap<String, Object> getHeaders();

    public abstract MultivaluedMap<String, String> getStringHeaders();

    public String getHeaderString(String name);

    public Set<String> getAllowedMethods();

    public Date getDate();

    public Locale getLanguage();

    public int getLength();

    public MediaType getMediaType();

    public Map<String, NewCookie> getCookies();

    public EntityTag getEntityTag();

    public Date getLastModified();

    public URI getLocation();

    public Set<Link> getLinks();

    boolean hasLink(String relation);

    public Link getLink(String relation);

    public Link.Builder getLinkBuilder(String relation);

    public boolean hasEntity();

    public Object getEntity();

    public Class<?> getEntityClass();

    public Type getEntityType();

    public void setEntity(final Object entity);

    public void setEntity(
            final Object entity,
            final Annotation[] annotations,
            final MediaType mediaType);

    public Annotation[] getEntityAnnotations();

    public OutputStream getEntityStream();

    public void setEntityStream(OutputStream outputStream);
}

Sample implementation

To implement a container response filter for the ContainerResponse extension point (that is, where the filter is executed after the invocation has been executed on the server side), define a class that implements the ContainerResponseFilter interface.
For example, the following code shows an example of a simple container response filter that gets installed in the ContainerResponse extension point, with a priority of 10:
// Java
package org.jboss.fuse.example;
 
import javax.annotation.Priority;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
 
@Provider
@Priority(value = 10)
public class SampleContainerResponseFilter implements ContainerResponseFilter {

  public SampleContainerResponseFilter() {
    System.out.println("SampleContainerResponseFilter starting up");
  }

  @Override
  public void filter(
      ContainerRequestContext requestContext,
      ContainerResponseContext responseContext
  )
  {
    // This filter replaces the response message body with a fixed string
    if (responseContext.hasEntity()) {
      responseContext.setEntity("New message body!");
    }
  }
}

Binding the server response filter

To bind a server response filter (that is, to install it into the Apache CXF runtime), perform the following steps:
  1. Add the @Provider annotation to the container response filter class, as shown in the following code fragment:
    // Java
    package org.jboss.fuse.example;
     
    import javax.annotation.Priority;
    import javax.ws.rs.container.ContainerRequestContext;
    import javax.ws.rs.container.ContainerResponseContext;
    import javax.ws.rs.container.ContainerResponseFilter;
    import javax.ws.rs.ext.Provider;
     
    @Provider
    @Priority(value = 10)
    public class SampleContainerResponseFilter implements ContainerResponseFilter {
      ...
    }
    When the container response filter implementation is loaded into the Apache CXF runtime, the REST implementation automatically scans the loaded classes to search for the classes marked with the @Provider annotation (the scanning phase).
  2. When defining a JAX-RS server endpoint in XML (for example, see Section 16.1, “Configuring JAX-RS Server Endpoints”), add the server response filter to the list of providers in the jaxrs:providers element.
    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
        xmlns:cxf="http://cxf.apache.org/blueprint/core"
        ...
    >
        ...
        <jaxrs:server id="customerService" address="/customers">
          ...
          <jaxrs:providers>
            <ref bean="filterProvider" />
          </jaxrs:providers>
          <bean id="filterProvider" class="org.jboss.fuse.example.SampleContainerResponseFilter"/>
    
        </jaxrs:server>
    
    </blueprint>
    Note
    This step is a non-standard requirement of Apache CXF. Strictly speaking, according to the JAX-RS standard, the @Provider annotation should be all that is required to bind the filter. But in practice, the standard approach is somewhat inflexible and can lead to clashing providers when many libraries are included in a large project.