61.3. コンテナー応答フィルター

概要

本セクションでは、コンテナー応答フィルターを実装して登録する方法を説明します。このフィルターは、サーバー側で送信応答メッセージをインターセプトするために使用されます。コンテナー応答フィルターは、応答メッセージでのヘッダーの自動設定に使用でき、通常、あらゆる種類の汎用的な応答処理に使用できます。

ContainerResponseFilter インターフェイス

javax.ws.rs.container.ContainerResponseFilter インターフェイスは以下のように定義されます。

// Java
...
package javax.ws.rs.container;

import java.io.IOException;

public interface ContainerResponseFilter {
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
            throws IOException;
}

ContainerResponseFilter を実装することで、サーバー側で ContainerResponse エクステンションポイントのフィルターを作成できます。これは、呼び出しの実行 にレスポンスメッセージをフィルタリングします。

注記

コンテナーレスポンスフィルターでは、リクエストメッセージ (requestContext 引数経由) とレスポンスメッセージ (responseContext メッセージ経由) の両方にアクセスできますが、この段階ではレスポンスのみを変更できます。

ContainerResponseContext インターフェイス

ContainerResponseFilterfilter メソッドは、型 javax.ws.rs.container.ContainerRequestContext の引数 (「ContainerRequestContext インターフェイス」を参照) と型 javax.ws.rs.container.ContainerResponseContext の引数 (送信レスポンスメッセージとその関連データにアクセスするために使用できる) の 2 つの引数を受け取ります。

ContainerResponseContext インターフェイスは以下のように定義されます。

// 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);
}

サンプル実装

ContainerResponse エクステンションポイントのコンテナーレスポンスフィルター (つまり、呼び出しがサーバー側に実行された後にフィルターが実行された場合) を実装するには、ContainerResponseFilter インターフェイスを実装するクラスを定義します。

たとえば、以下のコードは、ContainerResponse エクステンションポイントにインストールされる単純なコンテナーリクエストフィルターの例を示しています。ここで、優先度は 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!");
    }
  }
}

サーバーの応答フィルターのバインド

サーバー応答フィルターを バインド する (Apache CXF ランタイムにインストールする) には、以下の手順を実行します。

  1. 以下のコードフラグメントで示されるように、@Provider アノテーションをコンテナーレスポンスフィルタークラスに追加します。

    // 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 {
      ...
    }

    コンテナーレスポンスフィルター実装が Apache CXF ランタイムにロードされると、REST 実装はロードされたクラスを自動的にスキャンし、@Provider アノテーション (スキャンフェーズ) の付いたクラスを検索します。

  2. XML で JAX-RS サーバーエンドポイントを定義する場合 (例: 「JAX-RS サーバーエンドポイントの設定」)、jaxrs:providers 要素のプロバイダーリストにサーバーレスポンスフィルターを追加します。

    <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>
    注記

    この手順は、Apache CXF の非標準要件です。厳密に言うと、JAX-RS 標準によれば、フィルターをバインドするために必要なのは @Provider アノテーションのみです。しかし実際には、標準的なアプローチはやや柔軟性がなく、大規模なプロジェクトに多くのライブラリーが含まれている場合は、プロバイダーの衝突につながる可能性があります。