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
アノテーションのみです。しかし実際には、標準的なアプローチはやや柔軟性がなく、大規模なプロジェクトに多くのライブラリーが含まれている場合は、プロバイダーの衝突につながる可能性があります。