Red Hat Training
A Red Hat training course is available for Red Hat Fuse
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 インターフェイス
ContainerResponseFilter の filter メソッドは、型 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 ランタイムにインストールする) には、以下の手順を実行します。
以下のコードフラグメントで示されるように、
@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アノテーション (スキャンフェーズ) の付いたクラスを検索します。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アノテーションのみです。しかし実際には、標準的なアプローチはやや柔軟性がなく、大規模なプロジェクトに多くのライブラリーが含まれている場合は、プロバイダーの衝突につながる可能性があります。