Web サービスアプリケーションの開発

Red Hat JBoss Enterprise Application Platform 7.4

Red Hat JBoss Enterprise Application Platform の Web サービスアプリケーションの開発手順

Red Hat Customer Content Services

概要

本ガイドでは、Red Hat JBoss Enterprise Application Platform で Web サービスアプリケーションを開発する方法について説明します。

JBoss EAP ドキュメントへのフィードバック (英語のみ)

エラーを報告したり、ドキュメントを改善したりするには、Red Hat Jira アカウントにログインし、課題を送信してください。Red Hat Jira アカウントをお持ちでない場合は、アカウントを作成するように求められます。

手順

  1. このリンクをクリック してチケットを作成します。
  2. ドキュメント URLセクション番号課題の説明 を記入してください。
  3. Summary に課題の簡単な説明を入力します。
  4. Description に課題や機能拡張の詳細な説明を入力します。問題があるドキュメントのセクションへの URL を含めてください。
  5. Submit をクリックすると、課題が作成され、適切なドキュメントチームに転送されます。

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。まずは、マスター (master)、スレーブ (slave)、ブラックリスト (blacklist)、ホワイトリスト (whitelist) の 4 つの用語の置き換えから始めます。この取り組みは膨大な作業を要するため、今後の複数のリリースで段階的に用語の置き換えを実施して参ります。詳細は、Red Hat CTO である Chris Wright のメッセージ をご覧ください。

第1章 Web サービスの概要

Web サービスは、異なるソフトウェアアプリケーション間の標準的な対話手段を提供します。各アプリケーションは、さまざまなプラットフォームやフレームワークで実行できます。

Web サービスは、内部の異種サブシステムの通信を容易にします。さまざまな環境に対して機能を再作成する必要がないため、相互運用性によりサービスの再利用が増加します。

第2章 Jakarta RESTful Web Services Web サービスの開発

Jakarta RESTful Web Services は RESTful Web サービスの Jakarta EE API です。アノテーションと REST (Representational State Transfer) を使用して Web サービスを構築するためのサポートを提供します。これらのアノテーションは、Java オブジェクトを Web リソースにマッピングするプロセスを簡素化します。

RESTEasy は Jakarta RESTful Web Services の Red Hat JBoss Enterprise Application Platform 7 実装です。JBoss EAP 7.3 以降は、Jakarta Enterprise Web Services 1.4 および Jakarta RESTful Web Services 2.1 Jakarta EE 仕様に準拠しています。また、仕様に追加機能も提供します。

Jakarta RESTful Web Services を初めて使用する場合は、Red Hat JBoss Enterprise Application Platform 7 に同梱される helloworld-rsjaxrs-client、および kitchensink クイックスタートを参照してください。

注記

JBoss EAP は resteasy-cryptoresteasy-yaml-provider、および jose-jwt モジュールをサポートしません。

2.1. Jakarta RESTful Web Services アプリケーション

プロバイダーと Web リソースを作成する際に、それらを宣言するには以下のオプションを使用できます。

  • web.xml ファイルなしで javax.ws.rs.core.Application の簡単なサブクラス。
  • web.xml ファイルの使用。
  • Javax.ws.rs.core.Application のサブクラス化とカスタム実装の提供。

2.1.1. javax.ws.rs.core.Application の単純なサブクラス化

javax.ws.rs.core.Application クラスを使用して、これらのプロバイダーと Web リソースを宣言するサブクラスを作成できます。このクラスは、JBoss EAP に含まれる RESTEasy ライブラリーによって提供されます。

javax.ws.rs.core.Application を使用してリソースまたはプロバイダーを設定するには、拡張するクラスを作成して @ApplicationPath アノテーションを追加します。

例: アプリケーションクラス

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/root-path")
public class MyApplication extends Application
{
}

2.1.2. web.xml の使用

または、javax.ws.rs.core.Application を拡張するクラスを作成しない場合は、web.xml ファイルに以下を追加します。

例: web.xml

<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <servlet>
      <servlet-name>javax.ws.rs.core.Application</servlet-name>
  </servlet>
  <servlet-mapping>
      <servlet-name>javax.ws.rs.core.Application</servlet-name>
      <url-pattern>/root-path/*</url-pattern>
  </servlet-mapping>
  ...
</web-app>

2.1.3. カスタム実装による javax.ws.rs.core.Application のサブクラス化

javax.ws.rs.core.Application をサブクラス化する場合、既存のメソッドのいずれかにカスタム実装を提供するよう選択できます。getClasses および getSingletons メソッドは、公開された Jakarta RESTful Web Services アプリケーションに含める必要があるクラスまたはシングルトンのコレクションを返します。

  • getClasses および getSingletons のいずれかが空でないコレクションを返す場合、これらのクラスとシングルトンのみが Jakarta RESTful Web Services アプリケーションで公開されます。
  • getClassesgetSingletons両方が空のコレクションを返す場合、Web アプリケーションにパッケージ化されたすべてのルートリソースクラスおよびプロバイダーが Jakarta RESTful Web Services アプリケーションに含まれます。その後、RESTEasy はこれらのリソースを自動的に検出します。

2.2. Jakarta RESTful Web Services クライアント

2.2.1. Jakarta RESTful Web Services Client API

Jakarta RESTful Web Services 2.0 では、HTTP 要求をリモートの RESTful Web サービスに送信するための新しいクライアント API が導入されました。3 つの主要クラスを持つ fluent request-building API です。

  • Client
  • WebTarget
  • Response

Client インターフェイスは WebTarget インスタンスのビルダーです。WebTarget は、サブリソース WebTargets をビルドしたり、リクエストを呼び出すための固有の URL または URL テンプレートを表します。

クライアントを作成する方法は、標準の方法か、ResteasyClientBuilder クラスを使用する方法です。ResteasyClientBuilder クラスを使用する利点は、クライアントを設定するヘルパーメソッドが他にもいくつか提供されることです。

ResteasyClientBuilder クラス はこれらのヘルパーメソッドを提供しますが、クラスは JBoss EAP API に固有のものです。アプリケーションを新しいサーバーに移行する場合は、アプリケーションを再構築する必要があります。ResteasyClientBuilder クラスは RESTEasy に依存し、クラスは移植できません。

クライアントを作成する標準的な方法は、Jakarta RESTful Web Services と Jakarta EE API 仕様の両方に準拠しており、Jakarta RESTful Web Services 実装間で移植可能です。

注記

Jakarta RESTful Web Services アプリケーションの移植性を維持するには、Jakarta EE API 仕様に準拠し、可能であれば Jakarta EE API アプリケーションを使用します。ユースケースが Jakarta EE API の使用をサポートしていない場合にのみ JBoss 固有の API を使用します。

これらのガイドラインに従うと、アプリケーションを別のサーバーや新しい Jakarta EE と互換性のある JBoss 実装に移行するときに発生する可能性がある問題の数を減らすことができます。

標準の方法を使用したクライアントの作成

以下の例は、クライアントを作成するための標準的な方法のいずれかを示しています。

Client client = ClientBuilder.newClient();

また、別の標準的な方法を使用して、以下の例のようにクライアントを作成することもできます。

Client client = ClientBuilder.newBuilder().build();
WebTarget target = client.target("http://foo.com/resource");
Response response = target.request().get();
String value = response.readEntity(String.class);
response.close();  // You should close connections!
ResteasyClientBuilder クラスを使用したクライアントの作成

以下の例は、ResteasyClientBuilder クラスを使用してクライアントを作成します。

ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://foo.com/resource");

Jakarta RESTful Web Services 2.1 では、ClientBuilder クラスに 2 つのタイムアウトメソッドを追加できます。タイムアウトメソッドは仕様に準拠したメソッドであり、RESTEasy メソッドを使用する代わりに使用することができます。

以下の ClientBuilder 仕様に準拠したメソッドは、非推奨となった RESTEasy メソッドを置き換えます。

  • connectTimeout メソッドは establishConnectionTimeout メソッドに置き換わります。

    connectTimeout メソッドは、新しいサーバー接続を行うときにクライアントが待機する時間を決定します。

  • readTimeout メソッドは socketTimeout メソッドに置き換わります。

    readTimeout メソッドは、クライアントがサーバーからの応答を待つ時間を決定します。

以下の例は、connectTimeout メソッドおよび readTimeout メソッドの指定された値を示しています。

import javx.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Client;

Client client = ClientBuilder.newBuilder()
	       .connectTimeout(100, TimeUnit.SECONDS)
	       .readTimeout(2, TimeUnit.SECONDS)
	       .build();

readTimeout は、既存の接続で実行されたリクエストに適用されることに注意してください。

注記

timeout パラメーターの値をゼロに設定すると、サーバーは永久に待機します。

RESTEasy は、META-INF/services/javax.ws.rs.ext.Providers ファイルにリストされているすべてのクラスを含むデフォルトのプロバイダーのセットを自動的に読み込みます。また、Client.configuration() メソッド呼び出しによって提供される設定オブジェクトを使用して、他のプロバイダー、フィルター、インターセプターを手動で登録できます。設定では、必要になる可能性のある設定プロパティーを設定することもできます。

WebTarget には、親インスタンスに登録されているコンポーネントおよびプロパティーを継承する設定インスタンスがあります。これにより、ユーザー名やパスワードなど、各ターゲットリソースに特定の設定オプションを設定できます。

その他のリソース

RESTEasy クライアントクラスの使用

RESTEasy クライアントの以下の依存関係を Maven pom.xml ファイルに追加する必要があります。

<dependency>
	<groupId>org.jboss.resteasy</groupId>
	<artifactId>resteasy-client</artifactId>
	<version>VERSION_IN_EAP</version>
 </dependency>

RESTEasy クライアントクラスを使用する作業例は、JBoss EAP に同梱される jaxrs-client および resteasy-jaxrs-client クイックスタートを参照してください。

クライアント側のフィルター

クライアント側のフィルターには、以下のタイプがあります。

ClientRequestFilter
ClientRequestFilter は、HTTP リクエストがサーバーへネットワーク経由で送信される前に実行されます。ClientRequestFilter は、要求の実行を中止し、サーバーへの接続を行わずに、実行可能な応答を提供することもできます。
ClientResponseFilter
ClientResponseFilter は、サーバーから応答を受信した後、応答本体がマーシャリング解除される前に実行されます。ClientResponseFilter は、応答オブジェクトをアプリケーションコードに移動する前に変更できます。以下の例は、これらの概念を示しています。
// execute request filters
for (ClientRequestFilter filter : requestFilters) {
	filter.filter(requestContext);
	if (isAborted(requestContext)) {
    return requestContext.getAbortedResponseObject();
  }
}

// send request over the wire
response = sendRequest(request);

// execute response filters
for (ClientResponseFilter filter : responseFilters) {
	filter.filter(requestContext, responseContext);
}
クライアントリクエストへのクライアント側のフィルターの登録

以下の例は、クライアント側のフィルターをクライアント要求に登録する方法を表しています。

client = ClientBuilder.newClient();
WebTarget base = client.target(generateURL("/") + "get");
base.register(ClientExceptionsCustomClientResponseFilter.class).request("text/plain").get();
クライアント側のキャッシュ

RESTEasy には、クライアント側のキャッシュを設定する機能があります。このキャッシュは、サーバーの応答と共に送信されるキャッシュ制御ヘッダーを検索します。cache-control ヘッダーがクライアントが応答のキャッシュを許可するように指定すると、RESTEasy はローカルメモリー内にこれをキャッシュします。

ResteasyWebTarget target = client.target(generateBaseUrl());
target.register(BrowserCacheFeature.class);
チャンク化されたエンコーディングサポート

RESTEasy は、リクエストを チャンク 転送モードで送信するよう指定する機能をクライアント API に提供します。以下のように、チャンク された転送モードを指定する方法を使用できます。

  • org.jboss.resteasy.client.jaxrs.ResteasyWebTarget を設定して、すべてのリクエストをチャンクモードで送信することができます。

    ResteasyClient client = new ResteasyClientBuilder().build();
    ResteasyWebTarget target = client.target("http://localhost:8081/test");
    target.setChunked(b.booleanValue());
    Invocation.Builder request = target.request();
  • または、特定のリクエストをチャンクモードで送信するように設定することもできます。

    ResteasyClient client = new ResteasyClientBuilder().build();
    ResteasyWebTarget target = client.target("http://localhost:8081/test");
    ClientInvocationBuilder request = (ClientInvocationBuilder) target.request();
    request.setChunked(b);

    javax.ws.rs.client.Invocation.Builder クラスとは異なり org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder は RESTEasy クラスです。

注記

チャンクモードでリクエストを送信する機能は、基盤のトランスポート層によって異なります。特に、使用されている org.jboss.resteasy.client.jaxrs.ClientHttpEngine クラスの実装によって異なります。現時点では、デフォルトの実装 ApacheHttpClient43Engine と以前の実装の ApacheHttpClient4Engine のみが、チャンクモードをサポートします。これらはいずれも org.jboss.resteasy.client.jaxrs.engines パッケージで利用できます。詳細は、Implementing RESTEasy with HTTP Client を参照してください。

2.2.2. HTTP クライアントによる RESTEasy の実装

クライアントとサーバー間のネットワーク通信は、RESTEasy でデフォルトで処理されます。Apache HttpComponents プロジェクトの HttpClient HttpClient を使用します。RESTEasy クライアントフレームワークとネットワークの間のインターフェイスは、ClientHttpEngine インターフェイスによって定義されます。

RESTEasy には、このインターフェイスの 4 つの実装が同梱されています。デフォルトの実装は ApacheHttpClient43Engine です。この実装は Apache 4.3 を使用します。

ApacheHttpClient4Engine は、Apache 4.3 よりも前のバージョンを使用する実装です。このクラスは後方互換性を提供します。RESTEasy は、Apache バージョンの検出に基づいて、これらの 2 つの ClientHttpEngine 実装のいずれかを自動的に選択します。InMemoryClientEngine は、同じ JVM のサーバーにリクエストをディスパッチする実装で、URLConnectionEnginejava.net.HttpURLConnection を使用する実装です。

クライアントエグゼキューターは、特定の ClientRequest に渡すことができます。

ResteasyClient client = new
ResteasyClientBuilder().httpEngine(engine).build();

RESTEasy および HttpClient は、HttpClient を参照せずに、デフォルトのクライアントフレームワークを使用するように決定します。ただし、一部のアプリケーションでは、HttpClient の詳細を閲覧する必要がある場合があります。ApacheHttpClient43Engine および ApacheHttpClient4Engine は、org.apache.http.client.HttpClientorg.apache.http.protocol.HttpContext のインスタンスで提供できます。これは、HttpClient レイヤーに追加の設定詳細を実行できます。たとえば、認証は以下のように設定できます。

// Configure HttpClient to authenticate preemptively
// by prepopulating the authentication data cache.

// 1. Create AuthCache instance
AuthCache authCache = new BasicAuthCache();

// 2. Generate BASIC scheme object and add it to the local auth cache
AuthScheme basicAuth = new BasicScheme();
authCache.put(new HttpHost("sippycups.bluemonkeydiamond.com"), basicAuth);

// 3. Add AuthCache to the execution context
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);

// 4. Create client executor and proxy
HttpClient httpClient = HttpClientBuilder.create().build();
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient, localContext);
ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();

HttpContextProvider は RESTEasy が提供するインターフェイスで、これを使用してカスタム HttpContextApacheHttpClient43Engine および ApacheHttpClient4Engine 実装に提供できます。

注記

コネクションの解放とコネクションのクローズの違いを理解しておくことが重要となります。接続を解放すると、接続が再利用できるようになります。接続を閉じると、そのリソースが解放され、使用できなくなります。

RESTEasy は通知なしで接続をリリースします。唯一のカウンター例は、応答が InputStream のインスタンスであるケースです。これは明示的に閉じる必要があります。

一方、呼び出しの結果が Response のインスタンスである場合は、Response.close() メソッドを使用して接続を解放する必要があります。

WebTarget target = client.target("http://localhost:8081/customer/123");
Response response = target.request().get();
System.out.println(response.getStatus());
response.close();

これは try-finally ブロックで実行できます。接続を解放すると、接続を別のことに利用できるようになります。通常、ソケットを閉じることはありません。

ApacheHttpClient4Engine.finalize() は、使用中の HttpClient を作成した場合に、開いているソケットを閉じます。finalize() を呼び出すために JDK を使用するのは安全ではありません。HttpClientApacheHttpClient4Executor に渡される場合、ユーザーは以下のように接続を閉じる必要があります。

HttpClient httpClient = new HttpClientBuilder.create().build();
ApacheHttpClient4Engine executor = new ApacheHttpClient4Engine(httpClient);
...
httpClient.getConnectionManager().shutdown();
注記

ApacheHttpClient4EngineHttpClient の独自のインスタンスを作成した場合は finalize() がオープンソケットを閉じるのを待つ必要はありません。ClientHttpEngine インターフェイスには、この目的のために close() メソッドがあります。

最後に、javax.ws.rs.client.Client クラスがエンジンを自動的に作成している場合は、Client.close() を呼び出します。この呼び出しにより、ソケット接続がクリーンアップされます。

2.2.2.1. HTTP リダイレクト

Apache HttpClient をベースとする ClientHttpEngine 実装 は HTTP リダイレクトをサポートします。この機能はデフォルトで無効になっています。これを有効にするには、以下のように setFollowRedirects メソッドを true に設定します。

ApacheHttpClient43Engine engine = new ApacheHttpClient43Engine();
engine.setFollowRedirects(true);
Client client = new ResteasyClientBuilder().httpEngine(engine).build();

2.3. Jakarta RESTful Web Services のリクエスト処理

2.3.1. 非同期 HTTP リクエストの処理

非同期リクエスト処理により、非ブロッキング入力および出力を使用して単一の HTTP リクエストを処理し、必要に応じて別々のスレッドで処理できます。

クライアントとサーバーの両方からプッシュおよびプルする AJAX クライアントについて考えてみましょう。このシナリオでは、サーバーのソケットでクライアントが長時間ブロックし、新しいメッセージを待ちます。サーバーが着信および発信の入出力でブロックしている同期 HTTP 処理の場合は、クライアント接続ごとに別々のスレッドが消費されます。リクエスト処理のこのモデルでは、大量のメモリーおよび有意なスレッドリソースを消費します。

非同期処理は、受け入れる接続とリクエスト処理操作を切り分けます。クライアント接続を受け入れるスレッドと、長時間の時間がかかる操作を処理させるスレッドと、異なるスレッドが割り当てられます。このモデルでは、コンテナーは以下のように動作します。

  1. アクセプターであるクライアント接続を受け入れるためにスレッドをディスパッチします。
  2. その後、リクエストを処理スレッド (worker) に渡します。
  3. 最後に、アクセプタースレッドを解放します。

結果が、worker (ワーカー) スレッドによってクライアントに戻されます。そのため、クライアントの接続は開いたままであるため、サーバーのスループットとスケーラビリティーが向上します。

2.3.1.1. 非同期 NIO 要求処理

RESTEasy のデフォルトの非同期エンジン実装クラスは ApacheHttpAsyncClient4Engine です。これは Apache httpcomponents の HttpAsyncClient でビルドされ、内部で非ブロッキング IO モデルを使用してリクエストをディスパッチします。

ResteasyClientBuilder クラスで useAsyncHttpEngine メソッドを呼び出すと、非同期エンジンをアクティブなエンジンとして設定できます。

Client asyncClient = new ResteasyClientBuilder().useAsyncHttpEngine()
                     .build();
Future<Response> future = asyncClient
                          .target("http://locahost:8080/test").request()
                          .async().get();
Response res = future.get();
Assert.assertEquals(HttpResponseCodes.SC_OK, res.getStatus());
String entity = res.readEntity(String.class);

2.3.1.2. サーバー非同期の応答処理

サーバー側では、非同期処理は、元のリクエストスレッドを一時停止し、別のスレッドでリクエスト処理を開始します。これにより、元のサーバー側のスレッドが解放され、他の受信リクエストが許可されます。

2.3.1.2.1. AsyncResponse API

Jakarta RESTful Web Services 2.1 仕様は、@Suspended アノテーションと AsyncResponse インターフェイス の 2 つのクラスを使用して非同期 HTTP サポートを定義します。

AsyncResponse をパラメーターとして Jakarta RESTful Web Services メソッドにインジェクトすると、RESTEasy は現在実行されているスレッドから HTTP 要求と応答を切り離すように求められます。これにより、現在のスレッドが応答を自動的に処理しないようにします。

AsyncResponse はコールバックオブジェクトです。resume() メソッドのいずれかを呼び出す動作により、応答がクライアントに返送され、HTTP リクエストも終了します。以下は非同期処理の例になります。

import javax.ws.rs.container.Suspended;
import javax.ws.rs.container.AsyncResponse;

@Path("/")
public class SimpleResource {
   @GET
   @Path("basic")
   @Produces("text/plain")
   public void getBasic(@Suspended final AsyncResponse response) throws Exception {
      Thread t = new Thread() {
         @Override
         public void run() {
            try {
               Response jaxrs = Response.ok("basic").type(MediaType.TEXT_PLAIN).build();
               response.resume(jaxrs);
            }
            catch (Exception e) {
               e.printStackTrace();
            }
         }
      };
      t.start();
   }
}

2.3.1.3. Async Missionr Client API

同様に、クライアント側の非同期処理は、サーバーからの応答待ちがないため、リクエストスレッドのブロックを阻止します。たとえば、リクエストを発行したスレッドは、ユーザーインターフェイスコンポーネントも更新することがあります。応答を待つスレッドがブロックされると、ユーザーが認識したアプリケーションのパフォーマンスに影響が出ます。

2.3.1.3.1. future の使用

以下のコードスニペットでは、get() メソッドはリクエストではなく async() メソッド上で呼び出されます。これにより、呼び出しメカニズムが同期から非同期に変更されます。同期的に応答するのではなく、async() メソッドは future オブジェクトを返します。get() メソッドを呼び出すと、応答の準備ができるまで呼び出しがブロックされます。future.get() メソッドは、応答の準備ができると必ず返されます。

import java.util.concurrent.Future;
import javax.ws.rs.client.Client;
...

@Test
public void AsyncGetTest() throws Exception {
    Client client = ClientBuilder.newClient();
    Future<String> future = client.target(generateURL("/test")).request().async().get(String.class);
    String entity = future.get();
    Assert.assertEquals("get", entity);
}
2.3.1.3.2. InvocationCallback の使用

AsyncInvoker インターフェイスを使用すると、非同期呼び出しの処理の準備ができたときに呼び出されるオブジェクトを登録できます。InvocationCallback インターフェイスは completed() および failed() のメソッドを提供します。completed() メソッドは、処理が正常に完了し、応答を受信するたびに呼び出されます。逆に、要求の処理に成功していないと、failed() メソッドが呼び出されます。

import javax.ws.rs.client.InvocationCallback;
...

@Test
public void AsyncCallbackGetTest() throws Exception {
    Client client = ClientBuilder.newClient();
	final CountDownLatch latch = new CountDownLatch(1);
        Future<Response> future = client.target(generateURL("/test")).request().async().get(new InvocationCallback<Response>() {
         	@Override
                public void completed(Response response) {
                    String entity = response.readEntity(String.class);
                    Assert.assertEquals("get", entity);
                    latch.countDown();
                }

                @Override
                public void failed(Throwable error) {
                }
            });
            Response res = future.get();
            Assert.assertEquals(HttpResponseCodes.SC_OK, res.getStatus());
            Assert.assertTrue("Asynchronous invocation didn't use custom implemented Invocation callback", latch.await(5, imeUnit.SECONDS));
}

2.3.2. カスタム RESTEasy アノテーション

バイトコードにパラメーター名が追加されたため、@PathParam@QueryParam@FormParam@CookieParam@HeaderParam、および @MatrixParam アノテーションでパラメーター名を指定する必要がなくなりました。これには、任意の value パラメーターを持つ異なるパッケージで、同じ名前を持つ新しいアノテーションに切り替える必要があります。これは、以下の手順で実現できます。

  1. org.jboss.resteasy.annotations.jaxrs パッケージをインポートし、Jakarta RESTful Web Services 仕様からのアノテーションを置き換えます。
  2. ビルドシステムがバイトコードにメソッドパラメーター名を記録するように設定します。

    Maven ユーザーは、maven.compiler.parameterstrue に設定すると、バイトコードにメソッドパラメーター名を記録できます。

    <properties>
        <maven.compiler.parameters>true</maven.compiler.parameters>
    </properties>
  3. 名前がアノテーション変数の名前に一致する場合は、アノテーション値を削除します。

    注記

    アノテーション付きのパラメーター、アノテーション付きのフィールド、または JavaBean プロパティーのアノテーション名は省略できます。

以下の使用例を見てみましょう。

import org.jboss.resteasy.annotations.jaxrs.*;

@Path("/library")
public class Library {

   @GET
   @Path("/book/{isbn}")
   public String getBook(@PathParam String isbn) {
      // search my database and get a string representation and return it
   }
}

アノテーションが付けられた変数に path パラメーターと同じ名前がない場合は、以下のように名前を指定できます。

import org.jboss.resteasy.annotations.jaxrs.*;

@Path("/library")
public class Library {

   @GET
   @Path("/book/{isbn}")
   public String getBook(@PathParam("isbn") String id) {
      // search my database and get a string representation and return it
   }
}

2.4. RESTEasy エンドポイントの表示

jaxrs サブシステムの read-resource 操作を使用して、各 RESTEasy エンドポイントの構造化出力を表示できます。以下に、管理 CLI コマンドの例と期待される結果を示します。

/deployment=DEPLOYMENT_NAME/subsystem=jaxrs/rest-resource=org.jboss.as.quickstarts.rshelloworld.HelloWorld:read-resource(include-runtime=true)
{
    "outcome" => "success",
    "result" => {
        "resource-class" => "org.jboss.as.quickstarts.rshelloworld.HelloWorld",
        "rest-resource-paths" => [
            {
                "resource-path" => "/hello/json",
                "consumes" => undefined,
                "produces" => [
                    "application/json",
                    "text/plain"
                ],
                "java-method" => "java.lang.String org.jboss.as.quickstarts.rshelloworld.HelloWorld.getHelloWorldJSON()",
                "resource-methods" => [
                    "POST /wildfly-helloworld-rs/rest/hello/json",
                    "GET /wildfly-helloworld-rs/rest/hello/json"
                ]
            },
            {
                "resource-path" => "/hello/xml",
                "consumes" => undefined,
                "produces" => ["application/xml"],
                "java-method" => "java.lang.String org.jboss.as.quickstarts.rshelloworld.HelloWorld.getHelloWorldXML(@QueryParam java.lang.String name = 'LGAO')",
                "resource-methods" => ["GET /wildfly-helloworld-rs/rest/hello/xml"]
            }
        ],
        "sub-resource-locators" => [{
            "resource-class" => "org.jboss.as.quickstarts.rshelloworld.SubHelloWorld",
            "rest-resource-paths" => [
                {
                    "resource-path" => "/hello/subMessage/",
                    "consumes" => undefined,
                    "produces" => undefined,
                    "java-method" => "java.lang.String org.jboss.as.quickstarts.rshelloworld.SubHelloWorld.helloInSub()",
                    "resource-methods" => ["GET /wildfly-helloworld-rs/rest/hello/subMessage/"]
                },
                {
                    "resource-path" => "/hello/subMessage/subPath",
                    "consumes" => undefined,
                    "produces" => undefined,
                    "java-method" => "java.lang.String org.jboss.as.quickstarts.rshelloworld.SubHelloWorld.subPath()",
                    "resource-methods" => ["GET /wildfly-helloworld-rs/rest/hello/subMessage/subPath"]
                }
            ],
            "sub-resource-locators" => undefined
        }]
    }
}

上記の例では、出力情報が resource-class でグループ化され、resource-path ごとに順序づけされます。

  • resource-path はエンドポイントにアクセスするためのアドレスです。
  • resource-class はエンドポイントが定義されているクラスを定義します。
  • rest-resource-paths には、リソースパス、HTTP メソッドを定義し、エンドポイントを消費して生成する Java メソッドが含まれます。
  • java-method は Java メソッドの名前とそのパラメーターを指定します。また、定義されている場合は @PathParam@QueryParam@HeaderParam@MatrixParam@CookieParam@FormParam、および @DefaultValue の Jakarta RESTful Web Services アノテーションに関する情報も含まれます。

または、以下の例のように、rest-resource パラメーターを定義せずに read-resource 操作を使用し、すべてのエンドポイントに関する情報を取得できます。

/deployment=DEPLOYMENT_NAME/subsystem=jaxrs:read-resource(include-runtime=true,recursive=true)

2.5. RegistryStatsResource を使用した RESTEasy エンドポイントの表示

RegistryStatsResource リソースからアプリケーションの RESTEasy エンドポイントについての情報を取得できます。

手順

  1. アプリケーションのデプロイメント記述子 web.xml ファイルに以下の XML スニペットを追加して、RegistryStatsResource を登録します。

    <context-param>
        <param-name>resteasy.resources</param-name>
        <param-value>org.jboss.resteasy.plugins.stats.RegistryStatsResource</param-value>
    </context-param>
  2. アプリケーションの RESTEasy エンドポイントを表示します。

    • CLI の使用

      • XML で結果を取得する

        $ curl http://localhost:8080/{APPLICATION_PREFIX_URL}/resteasy/registry
      • JSON で結果を取得する

        $ curl http://localhost:8080/{APPLICATION_PREFIX_URL}/resteasy/registry -H "Accept: application/json"
    • Web ブラウザーの使用

      http://localhost:8080/{APPLICATION_PREFIX_URL}/resteasy/registry

2.6. URL ベースのネゴシエーション

2.6.1. メディアタイプへの拡張機能のマッピング

ブラウザーなどの一部のクライアントは、Accept および Accept-Language ヘッダーを使用して、表現メディアタイプまたは言語をネゴシエートできません。RESTEasy は、この問題に対処するために、ファイル名接尾辞をメディアタイプおよび言語にマップできます。

web.xml ファイルを使用してメディアタイプをファイル拡張子にマッピングするには、resteasy.media.type.mappings コンテキストパラメーターとマッピングのリストを param-value として追加する必要があります。この一覧はコンマで区切られ、コロン (:) を使用してファイル拡張子とメディアタイプを区切ります。

web.xml のメディアタイプへのマッピングファイル拡張機能の例

<context-param>
    <param-name>resteasy.media.type.mappings</param-name>
    <param-value>html : text/html, json : application/json, xml : application/xml</param-value>
</context-param>

この例では、http://localhost:8080/my-application/test の以下の URL バリアントがマッピングされます。

  • http://localhost:8080/my-application/test.html
  • http://localhost:8080/my-application/test.json
  • http://localhost:8080/my-application/test.xml

2.6.2. 言語への拡張機能のマッピング

ブラウザーなどの一部のクライアントは、Accept および Accept-Language ヘッダーを使用して、表現メディアタイプまたは言語をネゴシエートできません。RESTEasy は、この問題に対処するために、ファイル名接尾辞をメディアタイプおよび言語にマップできます。以下の手順に従い、web.xml ファイルのファイル拡張子に言語をマッピングします。

web.xml ファイルを使用してメディアタイプをファイル拡張子にマッピングするには、resteasy.language.mappings コンテキストパラメーターとマッピングのリストを param-value として追加する必要があります。この一覧はコンマで区切られ、コロン (:) を使用してファイル拡張子と言語タイプを区切ります。

言語タイプへの web.xml マッピングファイル拡張機能の例

<context-param>
    <param-name>resteasy.language.mappings</param-name>
    <param-value> en : en-US, es : es, fr : fr</param-name>
</context-param>

この例では、http://localhost:8080/my-application/test の以下の URL バリアントがマッピングされます。

  • http://localhost:8080/my-application/test.en
  • http://localhost:8080/my-application/test.es
  • http://localhost:8080/my-application/test.fr

2.7. コンテンツマーシャリングおよびプロバイダー

2.7.1. デフォルトのプロバイダーとデフォルトの Jakarta RESTful Web サービスのコンテンツ

RESTEasy は、いくつかの異なるメッセージ本文を自動的にマーシャリングおよびマーシャリング解除できます。

表2.1 サポートされるメディアタイプと Java タイプ

メディアタイプJava タイプ

application/* +xmltext/* +xml、
application/* +jsonapplication/* +fastinfosetapplication/ atom+*

Jakarta XML Binding アノテーションが付けられたクラス

application/* +xmltext/* +xml

org.w3c.dom.Document

* / *

java.lang.String

* / *

java.io.InputStream

text/plain

プリミティブ、java.lang.String、または String コンストラクターを持つタイプ、または入力用の静的 valueOf(String) メソ背戸、出力用の toOf() メソッド。

* / *

javax.activation.DataSource

* / *

java.io.File

* / *

byte

application/x-www-form-urlencoded

javax.ws.rs.core.MultivaluedMap

2.7.1.1. テキストメディアタイプおよび文字セット

Jakarta RESTful Web Services 仕様に従い、実装は応答の書き込み時にアプリケーション提供の文字セットメタデータに準拠する必要があります。文字セットがアプリケーションによって指定されていない場合、またはサポートされていない文字セットをアプリケーションが指定する場合は、実装で UTF-8 文字セットを使用する必要があります。

反対に、HTTP 仕様によると、送信者が明示的な charset パラメーターを提供しない場合、HTTP 経由で受信すると text タイプのメディアサブタイプは、デフォルトの charset の値である ISO-8859-1 を持つように定義されます。ISO-8859-1 以外の文字セットまたはそのサブセットのデータは、適切な文字セット値でラベル付けする必要があります。

リソースまたはリソースメソッドで指定された文字セットがない場合、RESTEasy は UTF-8 をテキストメディアタイプの文字セットとして使用します。これを行うため、RESTEasy は明示的な charset パラメーターを content-type 応答ヘッダーに追加します。

テキストメディアタイプに UTF-8 が使用されますが、明示的な charset パラメーターが追加されない場合は、コンテキストパラメーター resteasy.add.charsetfalse に設定します。このパラメーターのデフォルト値は true です。

注記

以下は、テキストメディアタイプです。

  • タイプ text と任意のサブタイプを含むメディアタイプ
  • タイプ application を持つメディアタイプ、xml で始まるサブタイプ。これには、application/xml-external-parsed-entity および application/xml-dtd が含まれます。

2.7.2. @Provider クラスを使用したコンテンツマーシャルリング

Jakarta RESTful Web Services 仕様を使用すると、独自のリクエスト/レスポンスボディーリーダーおよびライターをプラグインできます。そのためには、クラスに @Provider アノテーションを付け、ライターに @Produces を指定し、リーダーに @Consumes タイプを指定します。MessageBodyReader/Writer インターフェイスも実装する必要があります。

@Provider を使用してアノテーションが付けられたクライアントプロバイダーは、Jakarta RESTful Web Services コンテナーランタイムがアノテーションを処理するためにすべてのクライアントインスタンスに登録する必要があります。不要または重複したクライアントプロバイダー登録の問題を回避するために、システムプロパティー resteasy.client.providers.annotations.disabled は、@Provider アノテーションが付けられたクライアントプロバイダーのデフォルトの処理を無効にます。

RESTEasy ServletContextLoader は自動的に、@Provider アノテーションが付けられたクラスの WEB-INF/lib およびクラスディレクトリーを自動的にスキャンします。または、web.xml ファイルで手動で設定することができます。

2.7.3. Providers ユーティリティークラス

javax.ws.rs.ext.Providers は、MessageBodyReadersWritersContextResolversExceptionMappers を検索できるようにする単純なインジェクト可能なインターフェイスです。これは、他のランダムなコンテンツタイプを埋め込みする multipart プロバイダーおよびコンテンツタイプの実装に非常に便利です。

public interface Providers {
  <T> MessageBodyReader<T> getMessageBodyReader(Class<T> type, Type genericType, Annotation annotations[], MediaType mediaType);
  <T> MessageBodyWriter<T> getMessageBodyWriter(Class<T> type, Type genericType, Annotation annotations[], MediaType mediaType);
  <T extends="" throwable=""> ExceptionMapper<T> getExceptionMapper(Class<T> type);
  <T> ContextResolver<T> getContextResolver(Class<T> contextType, MediaType mediaType);
}

Providers インスタンスは MessageBodyReader または Writers にインジェクトできます。

@Provider
@Consumes("multipart/fixed")
public class MultipartProvider implements MessageBodyReader {

  private @Context Providers providers;
  ...
}

2.7.4. ドキュメントマーシャリングの設定

XML ドキュメントパーサーは XXE (XML eXternal Entity) 攻撃と呼ばれる攻撃の形式に依存し、外部エンティティーを拡張すると安全でないファイルが読み込まれます。たとえば、次のドキュメントでは、/etc/passwd ファイルが読み込まれる可能性があります。

<!--?xml version="1.0"?-->
<!DOCTYPE foo
[<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<search>
 <user>bill</user>
 <file>&xxe;<file>
</search>

デフォルトでは、org.w3c.dom.Document ドキュメントの RESTEasy ビルドインアンマーシャルは外部エンティティーを拡張しません。それらは空の文字列に置き換えられます。これは、外部エンティティーを DTD で定義された値に置き換えるように設定できます。そのためには web.xml ファイルで resteasy.document.expand.entity.references コンテキストパラメーターを true に設定します。

例: resteasy.document.expand.entity.references コンテキストパラメーターの設定

<context-param>
 <param-name>resteasy.document.expand.entity.references</param-name>
 <param-value>true</param-value>
</context-param>

この問題に対処するもう 1 つの方法として、RESTEasy がデフォルトで行う DTD を禁止します。この動作を変更するには、resteasy.document.secure.disableDTDs コンテキストパラメーターを false に設定します。

例: resteasy.document.secure.disableDTDs コンテキストパラメーターの設定

<context-param>
 <param-name>resteasy.document.secure.disableDTDs</param-name>
 <param-value>false</param-value>
</context-param>

ドキュメントは、バッファーが大規模なエンティティーやあまりにも多くの属性によって引き継がれる場合にドス攻撃の対象となります。たとえば、以下のエンティティーを定義すると、&foo6; の拡張が 1,000,000 foos になります。

<!--ENTITY foo 'foo'-->
<!--ENTITY foo1 '&foo;&foo;&foo;&foo;&foo;&foo;&foo;&foo;&foo;&foo;'-->
<!--ENTITY foo2 '&foo1;&foo1;&foo1;&foo1;&foo1;&foo1;&foo1;&foo1;&foo1;&foo1;'-->
<!--ENTITY foo3 '&foo2;&foo2;&foo2;&foo2;&foo2;&foo2;&foo2;&foo2;&foo2;&foo2;'-->
<!--ENTITY foo4 '&foo3;&foo3;&foo3;&foo3;&foo3;&foo3;&foo3;&foo3;&foo3;&foo3;'-->
<!--ENTITY foo5 '&foo4;&foo4;&foo4;&foo4;&foo4;&foo4;&foo4;&foo4;&foo4;&foo4;'-->
<!--ENTITY foo6 '&foo5;&foo5;&foo5;&foo5;&foo5;&foo5;&foo5;&foo5;&foo5;&foo5;'-->

デフォルトでは、RESTEasy は展開の数とエンティティーごとの属性数を制限します。正確な動作は、基礎となるパーサーによって異なります。この制限を無効にするには、resteasy.document.secure.processing.feature コンテキストパラメーターを false に設定します。

例: resteasy.document.secure.processing.feature コンテキストパラメーターの設定

<context-param>
 <param-name>resteasy.document.secure.processing.feature</param-name>
 <param-value>false</param-value>
</context-param>

2.7.5. MapProvider の使用

MapProvider を使用して、Jakarta RESTful Web Services リソースでマップを受け入れて返すことができます。

例: マップを許可して返すリソース

@Path("manipulateMap")
@POST
@Consumes("application/x-www-form-urlencoded")
@Produces("application/x-www-form-urlencoded")
public MultivaluedMap<String, String> manipulateMap(MultivaluedMap<String, String> map) {
  //do something
  return map;
}

クライアントを使用して Jakarta RESTful Web Services リソースへのマッピングを送受信することもできます。

例: クライアント

MultivaluedMap<String, String> map = new MultivaluedHashMap<String, String>();

//add values to the map...

Response response = client.target(generateURL("/manipulateMap"))
                          .request(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
                          .post(Entity.entity(map, MediaType.APPLICATION_FORM_URLENCODED_TYPE));

String data = response.readEntity(String.class);

//handle data...

2.7.6. 文字列ベースのアノテーションのオブジェクトへの変換

@QueryParam@MatrixParam@HeaderParam@PathParam、および @FormParam などの Jakarta RESTful Web Services の @*Param アノテーションは、raw HTTP 要求で文字列として表されます。これらのタイプのインジェクトされたパラメーターは、それらのオブジェクトに valueOf(String) 静的メソッドまたは String パラメーターを取るコンストラクターがある場合に、オブジェクトに変換できます。

valueOf() メソッドまたは文字列コンストラクターが存在しないクラスがある場合、または HTTP リクエストに不適切な場合、Jakarta RESTful Web Services は javax.ws.rs.ext.ParamConverterProvider および javax.ws.rs.ext.ParamConverter を提供し、メッセージパラメーター値を対応するカスタム Java タイプに変換します。ParamConverterProvider は、プログラムを用いて Jakarta RESTful Web Services ランタイムに登録されるか、プロバイダースキャンフェーズで Jakarta RESTful Web Services ランタイムによって自動的に検出されるよう @Provider アノテーションを付ける必要があります。

たとえば、以下の手順では、カスタム pos オブジェクトを作成する方法を示します。@QueryParam@PathParam@MatrixParam@HeaderParam などのメッセージパラメーターから POJO オブジェクトへの変換は、ParamConverter インターフェイスおよび ParamConverterProvider インターフェイスの実装によって実行されます。

  1. カスタム POJO クラスを作成します。

    public class POJO {
      private String name;
    
      public String getName() {
        return name;
      }
    
      public void setName(String name) {
        this.name = name;
      }
    }
  2. カスタム POJO Converter クラスを作成します。

    public class POJOConverter implements ParamConverter<POJO> {
      public POJO fromString(String str) {
        System.out.println("FROM STRNG: " + str);
        POJO pojo = new POJO();
        pojo.setName(str);
        return pojo;
      }
    
      public String toString(POJO value) {
        return value.getName();
      }
    }
  3. カスタム POJO Converter Provider クラスを作成します。

    public class POJOConverterProvider implements ParamConverterProvider {
      @Override
      public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
        if (!POJO.class.equals(rawType)) return null;
        return (ParamConverter<T>)new POJOConverter();
      }
    }
  4. カスタム MyResource クラスを作成します。

    @Path("/")
    public class MyResource {
      @Path("{pojo}")
      @PUT
      public void put(@QueryParam("pojo") POJO q, @PathParam("pojo") POJO pp, @MatrixParam("pojo") POJO mp,
        @HeaderParam("pojo") POJO hp) {
        ...
      }
    }
ParamConverter の機能の拡張

Jakarta RESTful Web Services セマンティクスでは、ParamConverter は個別のオブジェクトを表す単一の文字列を変換します。RESTEasy はセマンティックを拡張して、ParamConverter が複数オブジェクトの文字列表現を解析できるようにし、List<T>Set<T>SortedSet<T>array、またはその他の複数値のデータ構造の生成を可能にします。

たとえば、以下のリソースについて見てみましょう。

@Path("queryParam")
public static class TestResource {
   @GET
   @Path("")
   public Response conversion(@QueryParam("q") List<String> list) {
      return Response.ok(stringify(list)).build();
   }
}

private static <T> String stringify(List<T> list) {
   StringBuffer sb = new StringBuffer();
   for (T s : list) {
      sb.append(s).append(',');
   }
   return sb.toString();
}

以下のように、標準の表記を使用して TestResource を呼び出します。

@Test
public void testQueryParamStandard() throws Exception {
   ResteasyClient client = new ResteasyClientBuilder().build();
   Invocation.Builder request = client.target("http://localhost:8081/queryParam?q=20161217&q=20161218&q=20161219").request();
   Response response = request.get();
   System.out.println("response: " + response.readEntity(String.class));
}

結果: response: 20161217,20161218,20161219,.

代わりにコンマ区切りの表記を使用する場合は、以下を追加できます。

public static class MultiValuedParamConverterProvider implements ParamConverterProvider
   @SuppressWarnings("unchecked")
   @Override
   public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
      if (List.class.isAssignableFrom(rawType)) {
         return (ParamConverter<T>) new MultiValuedParamConverter();
      }
      return null;
   }
}

public static class MultiValuedParamConverter implements ParamConverter<List<?>> {
   @Override
   public List<?> fromString(String param) {
      if (param == null || param.trim().isEmpty()) {
         return null;
      }
      return parse(param.split(","));
   }

   @Override
   public String toString(List<?> list) {
      if (list == null || list.isEmpty()) {
         return null;
      }
      return stringify(list);
   }

   private static List<String> parse(String[] params) {
      List<String> list = new ArrayList<String>();
      for (String param : params) {
         list.add(param);
      }
      return list;
   }
}

これで、以下のように TestResource を呼び出すことができます。

@Test
public void testQueryParamCustom() throws Exception {
   ResteasyClient client = new ResteasyClientBuilder().build();
   Invocation.Builder request = client.target("http://localhost:8081/queryParam?q=20161217,20161218,20161219").request();
   Response response = request.get();
   System.out.println("response: " + response.readEntity(String.class));
}

取得: : 20161217,20161218,20161219,

この場合では、MultiValuedParamConverter.fromString() 関数は ArrayList を作成して返すため、TestResource.conversion() 関数を書き換えることができます。

@Path("queryParam")
public static class TestResource {

   @GET
   @Path("")
   public Response conversion(@QueryParam("q") ArrayList<String> list) {
      return Response.ok(stringify(list)).build();
   }
}

または MultiValuedParamConverter は再書き込みして LinkList を返すことができます。また、TestResource.conversion() のパラメーターリストは、List または LinkedList のいずれかになります。

最後に、この拡張はアレイにも機能することに注意してください。以下に例を示します。

public static class Foo {
    private String foo;
    public Foo(String foo) {
        this.foo = foo;
    }
    public String getFoo() {
        return foo;
    }
}

public static class FooArrayParamConverter implements ParamConverter < Foo[] > {
    @Override
    public Foo[] fromString(String value) {
        String[] ss = value.split(",");
        Foo[] fs = new Foo[ss.length];
        int i = 0;
        for (String s: ss) {
            fs[i++] = new Foo(s);
        }
        return fs;
    }

    @Override
    public String toString(Foo[] values) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < values.length; i++) {
            sb.append(values[i].getFoo()).append(",");
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }
}

@Provider
public static class FooArrayParamConverterProvider implements ParamConverterProvider {
    @SuppressWarnings("unchecked")
    @Override
    public < T > ParamConverter < T > getConverter(Class < T > rawType, Type genericType, Annotation[] annotations) {
        if (rawType.equals(Foo[].class));
        return (ParamConverter < T > ) new FooArrayParamConverter();
    }
}

@Path("")
public static class ParamConverterResource {

    @GET
    @Path("test")
    public Response test(@QueryParam("foos") Foo[] foos) {
        return Response.ok(new FooArrayParamConverter().toString(foos)).build();
    }
}
java.util.Optional パラメータータイプ

RESTEasy は、複数の追加の java.util.Optional パラメータータイプを提供します。これらのパラメータータイプは、ラッパーオブジェクトタイプとして機能します。これにより、ユーザーは任意のタイプパラメーターを入力でき、Optional.orElse() などのメソッドを使用してすべての null チェックを削除できます。

@Path("/double")
@GET
public String optDouble(@QueryParam("value") OptionalDouble value) {
    return Double.toString(value.orElse(4242.0));
}

上記の例は、OptionalDouble をパラメータータイプとして使用できることを示しています。値が @QueryParam で指定されていない場合は、デフォルト値が返されます。以下のパラメータータイプでは、オプションのパラメーターがサポートされています。

  • @QueryParam
  • @MatrixParam
  • @FormParam
  • @HeaderParam
  • @CookieParam

2.7.7. シリアライズ可能なプロバイダー

信用できないソースから Java オブジェクトをデシリアライズすることは危険です。そのため、org.jboss.resteasy.plugins.providers.SerializableProvider はデフォルトで無効になっています。このプロバイダーの使用は推奨されません。

2.7.8. JSON プロバイダー

2.7.8.1. RESTEasy Jackson2 での JsonFilter サポート

JsonFilter は、@JsonFilter でクラスにアノテーションを付けることで、動的なフィルタリングを容易にします。以下の例では、nameFilter クラスからフィルターインスタンスへのマッピングを定義し、インスタンスを JSON 形式にシリアライズする際に Bean プロパティーを除外します。

@JsonFilter(value="nameFilter")
public class Jackson2Product {
    protected String name;
    protected int id;
    public Jackson2Product() {
    }
    public Jackson2Product(final int id, final String name) {
        this.id = id;
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}

@JsonFilter はリソースクラスにアノテーションを付け、JSON 応答でシリアライズすべきでないプロパティーをフィルターアウトします。フィルター ID とインスタンスをマップするには、別の Jackson クラスを作成し、以下の例のようにその ID とフィルターインスタンスマップを追加する必要があります。

public class ObjectFilterModifier extends ObjectWriterModifier {
	public ObjectFilterModifier() {
	}
	@Override
	public ObjectWriter modify(EndpointConfigBase<?> endpoint,
		MultivaluedMap<String, Object> httpHeaders, Object valueToWrite,
		ObjectWriter w, JsonGenerator jg) throws IOException {

		FilterProvider filterProvider = new SimpleFilterProvider().addFilter(
			"nameFilter",
			SimpleBeanPropertyFilter.filterOutAllExcept("name"));
		return w.with(filterProvider);
	}
}

上記の例では、メソッド modify() は応答を記述する前に、name プロパティー以外のすべてのプロパティーをフィルタリングします。これを機能させるには、RESTEasy はこのマッピング情報を知っておく必要があります。以下の例が示すように、WriterInterceptor またはサーブレットフィルターのいずれかに設定できます。

例: WriterInterceptor を使用した ObjectFilterModifier の設定

@Provider
public class JsonFilterWriteInterceptor implements WriterInterceptor{

	private ObjectFilterModifier modifier = new ObjectFilterModifier();
	@Override
	public void aroundWriteTo(WriterInterceptorContext context)
		throws IOException, WebApplicationException {
	    	//set a threadlocal modifier
            ObjectWriterInjector.set(modifier);
                context.proceed();
	}

}

例: サーブレットフィルターを使用した ObjectFilterModifier の設定

public class ObjectWriterModifierFilter implements Filter {
	private static ObjectFilterModifier modifier = new ObjectFilterModifier();

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
		FilterChain chain) throws IOException, ServletException {
		    ObjectWriterInjector.set(modifier);
		    chain.doFilter(request, response);
	}

	@Override
	public void destroy() {
	}

}

これで、RESTEasy は ObjectFilterModifierThreadLocal 変数から取得して、応答の作成前に ObjectWriter を変更するように設定できます。

2.7.8.2. 時間および期間オブジェクトの JSON シリアル化

注記

Jackson2 プロバイダーを設定せずに RESTEasy を使用して、LocalDateTimeLocalDate、または Duration クラスなどの時間および期間オブジェクトをシリアル化すると、エラーが発生します。

RESTEasy は、Jackson2 プロバイダーを使用した時間オブジェクトと期間オブジェクトのシリアル化をサポートしています。次の例は、シリアライゼーションをアクティブ化するように Jackson2 プロバイダーを設定する方法を示しています。

例: シリアライゼーション用に Jackson2 プロバイダーを設定する

import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonDatatypeJacksonProducer implements ContextResolver<ObjectMapper> {

    private final ObjectMapper json;

    public JacksonDatatypeJacksonProducer() throws Exception {
        this.json = JsonMapper.builder()
                .findAndAddModules()
                .build();
    }

    @Override
    public ObjectMapper getContext(Class<?> objectType) {
        return json;
    }
}

2.7.8.3. JSON Binding

RESTEasy は Jakarta JSON Binding と Jakarta JSON Processing の両方をサポートします。仕様に従い、Jakarta JSON Binding のエンティティープロバイダーは、JsonValue とそのサブタイプ以外のすべてのタイプのエンティティーで Jakarta JSON Processing のエンティティープロバイダーよりも優先されます。

resteasy-json-binding-provider モジュールからの JsonBindingProvider は、JSON-B のサポートを提供します。Jakarta RESTful Web Services 2.1 の要件を満たすため、JsonBindingProvider プロバイダーは特に Jackson ペイロードで JSON ペイロードを処理する他のプロバイダーよりも優先されます。

同じ入力では、Jackson および Jakarta JSON Binding リファレンス実装からの JSON 出力は異なる場合があります。後方互換性を維持するには、resteasy.preferJacksonOverJsonB コンテキストプロパティーを true に設定し、現在のデプロイメントの JsonBindingProvider 設定を無効にします。

JBoss EAP は、同じ名前のシステムプロパティーを設定して、resteasy.preferJacksonOverJsonB コンテキストプロパティーのデフォルト値を指定することをサポートします。コンテキストおよびシステムプロパティーに値が設定されていない場合、Jackson アノテーションの Jakarta RESTful Web Services デプロイメントをスキャンし、これらのアノテーションのいずれかが見つからない場合にプロパティーを true に設定します。

2.7.9. Jakarta XML Binding プロバイダー

2.7.9.1. Jakarta XML Binding および XML プロバイダー

RESTEasy は XML で Jakarta XML Binding プロバイダーをサポートします。

@XmlHeader および @Stylesheet

RESTEasy は、@org.jboss.resteasy.annotations.providers.jaxb.XmlHeader アノテーションを使用した XML ヘッダーの設定を提供します。

例: @XmlHeader アノテーションの使用

@XmlRootElement
public static class Thing {
   private String name;

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
}

@Path("/test")
public static class TestService {

   @GET
   @Path("/header")
   @Produces("application/xml")
   @XmlHeader("<?xml-stylesheet type='text/xsl' href='${baseuri}foo.xsl' ?>")
   public Thing get() {
      Thing thing = new Thing();
      thing.setName("bill");
      return thing;
   }
}

@XmlHeader は、XML 出力に XML スタイルシートヘッダーがあることを確認します。

RESTEasy にはスタイルシートヘッダーの便利なアノテーションがあります。

例: @Stylesheet アノテーションの使用

@XmlRootElement
public static class Thing {
   private String name;

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
}

@Path("/test")
public static class TestService {

   @GET
   @Path("/stylesheet")
   @Produces("application/xml")
   @Stylesheet(type="text/css", href="${basepath}foo.xsl")
   @Junk
   public Thing getStyle() {
      Thing thing = new Thing();
      thing.setName("bill");
      return thing;
   }
}

2.7.9.2. Jakarta XML Binding および JSON プロバイダー

RESTEasy では、JSON プロバイダーを使用して Jakarta XML Binding アノテーションが付けられた POJO と JSON との間でマーシャリングを行うことができます。このプロバイダーは、このタスクを実行するために Jackson JSON ライブラリーをラップします。Jakarta XML Binding と同様の Java Bean ベースのモデルおよび API があります。

Jackson にすでに Jakarta RESTful Web Services 統合が含まれていますが、RESTEasy によって拡張されました。これをプロジェクトに組み込むには、Maven 依存関係を更新する必要があります。

Jackson の Maven 依存関係

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-jackson2-provider</artifactId>
    <version>${version.org.jboss.resteasy}</version>
    <scope>provided</scope>
</dependency>

注記

RESTEasy のデフォルトの JSON プロバイダーは Jackson2 です。JBoss EAP の以前のバージョンには Jackson1 JSON プロバイダーが含まれていました。Jackson1 プロバイダーから既存アプリケーションを移行する方法の詳細は、JBoss EAP Migration Guide を参照してください。Jackson1 プロバイダーを使用する場合は、Maven 依存関係を明示的に更新して取得 する必要があります。

注記

以前のバージョンの JBoss EAP の RESTEasy のデフォルト JSON プロバイダーは Jettison でしたが、JBoss EAP 7 では非推奨になっています。詳細は、JBoss EAPMigration Guide を参照してください。

JSON プロバイダーの例

@XmlRootElement
public static class Thing {
  private String name;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}

@Path("/test")
public static class TestService {
  @GET
  @Path("/thing")
  @Produces("application/json")
  public Thing get() {
    Thing thing = new Thing();
    thing.setName("the thing");
    return thing;
  }
}

2.7.9.2.1. Java 8 の Jackson モジュールサポート

ここでは、Maven の依存関係を説明します。また、コアの Jackson モジュールが Java 8 ランタイム環境を必要としない場合に Java 8 機能をサポートするために必要な Jackson モジュールを登録する方法について説明します。これらの Jackson モジュールには以下が含まれます。

  • Java 8 データ型
  • Java 8 日付/時刻

以下の Maven 依存関係を追加します。

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

以下の例のように、findAndRegisterModules() または ObjectMapper.registerModule() を使用してすべてのモジュールを検索し、登録することができます。

ObjectMapper mapper = new ObjectMapper();
mapper.findAndRegisterModules();
ObjectMapper mapper = new ObjectMapper()
   .registerModule(new ParameterNamesModule())
   .registerModule(new Jdk8Module())
   .registerModule(new JavaTimeModule());

例: 期間のデータタイプ

@GET
@Path("/duration")
@Produces(MediaType.APPLICATION_JSON)
public Duration getDuration() {
    return Duration.ofSeconds(5, 6);
}

例: 任意のデータタイプ

@GET
@Path("/optional/{nullParam}")
@Produces(MediaType.APPLICATION_JSON)
public Optional<String> getOptional(@PathParam("nullParam") boolean nullParameter) {
    return nullParameter ? Optional.<String>empty() : Optional.of("info@example.com");
}

RESTEasy でこれらの Jackson モジュールを使用するには、ContextResolver のカスタム実装を使用する必要があります。

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonDatatypeJacksonProducer implements ContextResolver<ObjectMapper> {
    private final ObjectMapper json;
    public JacksonDatatypeJacksonProducer() throws Exception {
        this.json = new ObjectMapper()
                .findAndRegisterModules()
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }
    @Override
    public ObjectMapper getContext(Class<?> objectType) {
        return json;
    }
}
2.7.9.2.2. デフォルトの Jackson プロバイダーの切り替え

JBoss EAP 7 には Jackson 2.6.x 以上が含まれ、resteasy-jackson2-provider がデフォルトの Jackson プロバイダーになりました。

以前のリリースの JBoss EAP に含まれていたデフォルトの resteasy-jackson-provider に切り替えるには、新しいプロバイダーを除外し、jboss-deployment-structure.xml アプリケーションデプロイメント記述子ファイルに以前のプロバイダーの依存関係を追加します。

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
   <deployment>
       <exclusions>
           <module name="org.jboss.resteasy.resteasy-jackson2-provider"/>
       </exclusions>
       <dependencies>
           <module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
       </dependencies>
   </deployment>
</jboss-deployment-structure>

2.7.10. Jakarta XML Binding デコレーターの作成

RESTEasy の Jakarta XML Binding プロバイダーには、Marshaller インスタンスと Unmarshaller インスタンスを修飾するプラグ可能な方法があります。メソッドを切り離すために使用できる Marshaller または Un markler インスタンスのいずれかをトリガーできるアノテーションを作成できます。

RESTEasy での Jakarta XML Binding デコレーターの作成
  1. Processor クラスを作成します。

    1. DecoratorProcessor<Target, Annotation> を実装するクラスを作成します。ターゲットは Jakarta XML Binding Marshaller または Unmarshaller クラスです。アノテーションは、ステップ 2 で作成されます。
    2. クラスに @DecorateTypes アノテーションを付け、デコレーターがデコレートする必要のある MIME タイプを宣言します。
    3. decorate 関数内にプロパティーまたは値を設定します。

      例: Processor クラス

      import org.jboss.resteasy.core.interception.DecoratorProcessor;
      import org.jboss.resteasy.annotations.DecorateTypes;
      import javax.xml.bind.Marshaller;
      import javax.xml.bind.PropertyException;
      import javax.ws.rs.core.MediaType;
      import javax.ws.rs.Produces;
      import java.lang.annotation.Annotation;
      
      @DecorateTypes({"text/*+xml", "application/*+xml"})
      public class PrettyProcessor implements DecoratorProcessor<Marshaller, Pretty> {
          public Marshaller decorate(Marshaller target, Pretty annotation,
            Class type, Annotation[] annotations, MediaType mediaType) {
          target.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
          }
      }

  2. アノテーションを作成します。

    1. @Decorator アノテーションが付けられたカスタムインターフェイスを作成します。
    2. @Decorator アノテーションのプロセッサーおよびターゲットを宣言します。プロセッサーは、ステップ 1 で作成されます。ターゲットは Jakarta XML Binding Marshaller または Unmarshaller クラスです。

      例: @Decorator アノテーションのあるカスタムインターフェイス

      import org.jboss.resteasy.annotations.Decorator;
      
      @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
      @Retention(RetentionPolicy.RUNTIME)
      @Decorator(processor = PrettyProcessor.class, target = Marshaller.class)
      public @interface Pretty {}

  3. 手順 2 で作成したアノテーションを関数に追加して、入力または出力のいずれかがマーシャリングされるときにデコレートされるようにします。

Jakarta RESTful Web Services Web サービス内で適用可能な Jakarta XML Binding デコレーターが作成されました。

2.7.11. Jakarta RESTful Web Services のマルチパートプロバイダー

multipart MIME 形式は、単一のメッセージに埋め込まれたコンテンツボディーのリストを渡すために使用されます。multipart MIME 形式の一例として、multipart/form-data MIME タイプが挙げられます。これは Web アプリケーションの HTML 形式のドキュメントにあり、通常はファイルをアップロードするために使用されます。この MIME タイプの form-data 形式は、インラインコンテンツのそれぞれに関連する名前がある以外は、他の multipart 形式と同じです。

RESTEasy は、multipart/form-data および multipart/* MIME タイプを許可します。RESTEasy は、multipart タイプの読み書きや、任意の List (任意の multipart タイプ) および Map (multipart/form-data のみ) オブジェクトのマーシャリングを行うためのカスタム API も提供します。

重要

Seam の org.jboss.seam.web.MultipartFilter や Spring の org.springframework.web.multipart.MultipartResolver など、フィルターやインターセプターの支援により、multipart 解析を自動的に行うフレームワークが多数あります。ただし、着信 multipart 要求ストリームは 1 回のみ解析できます。multipart を使用する RESTEasy ユーザーは、RESTEasy がそれを取得する前にストリームを解析しないようにする必要があります。

2.7.11.1. multipart データでの入力

Jakarta RESTful Web Services サービスを作成する場合、RESTEasy は org.jboss.resteasy.plugins.providers.multipart.MultipartInput インターフェイスを提供し、すべてのマルチパート MIME タイプで読み取りできるようにします。

package org.jboss.resteasy.plugins.providers.multipart;

public interface MultipartInput {

   List<InputPart> getParts();
   String getPreamble();

   // You must call close to delete any temporary files created
   // Otherwise they will be deleted on garbage collection or on JVM exit
   void close();
}

public interface InputPart {

   MultivaluedMap<String, String> getHeaders();
   String getBodyAsString();
   <T> T getBody(Class<T> type, Type genericType) throws IOException;
   <T> T getBody(org.jboss.resteasy.util.GenericType<T> type) throws IOException;
   MediaType getMediaType();
   boolean isContentTypeFromMessage();
}

MultipartInput は、multipart メッセージの各パーツにアクセスできる簡単なインターフェイスです。各パーツは InputPart インターフェイスによって表示され、各パートにはそれに関連するヘッダーのセットがあります。getBody() メソッドのいずれかを呼び出すと、この部分のマーシャルを解除できます。genericType パラメーターは null にすることができますが、type パラメーターは設定する必要があります。RESTEasy は、パーツのメディアタイプおよび渡すタイプ情報に基づいて MessageBodyReader を検出します。

2.7.11.1.1. multipart/mixed での入力

例: パーツのマーシャリング解除

@Path("/multipart")
public class MyService {

    @PUT
    @Consumes("multipart/mixed")
    public void put(MultipartInput input) {
        List<Customer> customers = new ArrayList...;
        for (InputPart part : input.getParts()) {
            Customer cust = part.getBody(Customer.class, null);
            customers.add(cust);
        }
        input.close();
    }
}

注記

上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。

汎用型のメタデータの影響を受けるボディー部分をマーシャリング解除する必要があることも考えられます。この場合は、org.jboss.resteasy.util.GenericType クラスを使用できます。

例: 汎用型メタデータに影響を受けやすいタイプのマーシャリング解除

@Path("/multipart")
public class MyService {

    @PUT
    @Consumes("multipart/mixed")
    public void put(MultipartInput input) {
        for (InputPart part : input.getParts()) {
            List<Customer> cust = part.getBody(new GenericType<List<Customer>>() {});
        }
        input.close();
    }
}

GenericType の使用は、ランタイム時に汎用型情報を取得する唯一の方法であるため、必要になります。

2.7.11.1.2. multipart/mixed および java.util.List による入力

ボディーの部分が均一である場合は、各部分と各パーツを手動でマーシャリング解除する必要はありません。入力パラメーターとして java.util.List を指定できます。List タイプ宣言の汎用パラメーターを使用してマーシャリング解除されている型が必要です。

例: CustomersList のマーシャリング解除

@Path("/multipart")
public class MyService {

    @PUT
    @Consumes("multipart/mixed")
    public void put(List<Customer> customers) {
        ...
    }
}

注記

上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。

2.7.11.1.3. multipart/form-data による入力

Jakarta RESTful Web Services サービスを作成する場合、RESTEasy は multipart/form-data MIME タイプで読み取りできるインターフェイスを提供します。multipart/form-data は、Web アプリケーションの HTML 形式のドキュメントにあり、通常はファイルをアップロードするために使用されます。form-data 形式は、インラインコンテンツのそれぞれに関連する名前がある以外は、他の multipart 形式と同じです。from-data 入力に使用されるインターフェイスは org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput です。

例: MultipartFormDataInput インターフェイス

public interface MultipartFormDataInput extends MultipartInput {

    @Deprecated
    Map<String, InputPart> getFormData();
    Map<String, List<InputPart>> getFormDataMap();
    <T> T getFormDataPart(String key, Class<T> rawType, Type genericType) throws IOException;
    <T> T getFormDataPart(String key, GenericType<T> type) throws IOException;
}

これは、前述の MultipartInput と同じように機能します。

2.7.11.1.4. ultipart/form-data を含む java.utol.Map

form-data では、ボディーの部分が均一である場合は、あらゆるパーツを手動でマーシャリング解除する必要はありません。入力パラメーターとして java.util.Map を指定できます。List タイプ宣言の汎用パラメーターを使用してマーシャリング解除されている型が必要です。

例: Customer オブジェクトの Map のマーシャリング解除

@Path("/multipart")
public class MyService {

    @PUT
    @Consumes("multipart/form-data")
    public void put(Map<String, Customer> customers) {
        ...
    }
}

注記

上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。

2.7.11.2. multipart データでの出力

RESTEasy は、multipart データを出力するための簡単な API を提供します。

package org.jboss.resteasy.plugins.providers.multipart;

public class MultipartOutput {

    public OutputPart addPart(Object entity, MediaType mediaType)
    public OutputPart addPart(Object entity, GenericType type, MediaType mediaType)
    public OutputPart addPart(Object entity, Class type, Type genericType, MediaType mediaType)
    public List<OutputPart> getParts()
    public String getBoundary()
    public void setBoundary(String boundary)
}

public class OutputPart {

    public MultivaluedMap<String, Object> getHeaders()
    public Object getEntity()
    public Class getType()
    public Type getGenericType()
    public MediaType getMediaType()
}

multipart データを出力するには、MultipartOutput オブジェクトを作成し、addPart() メソッドを呼び出します。RESTEasy は、エンティティーオブジェクトをマーシャリングするための MessageBodyWriter を自動的に検出します。MultipartInput と同様に、汎用型メタデータに影響しやすいマーシャリングがある場合があります。この場合は、GenericType を使用します。通常は、オブジェクトとその MediaType を渡すだけで十分です。

例: multipart/mixed 形式の戻り値

@Path("/multipart")
public class MyService {

    @GET
    @Produces("multipart/mixed")
    public MultipartOutput get() {

        MultipartOutput output = new MultipartOutput();
        output.addPart(new Customer("bill"), MediaType.APPLICATION_XML_TYPE);
        output.addPart(new Customer("monica"), MediaType.APPLICATION_XML_TYPE);
        return output;
    }
}

注記

上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。

2.7.11.2.1. java.util.List でのマルチ出力

ボディーの部分が均一である場合は、各パーツおよび各パーツを手動でマーシャリングしたり、MultipartOutput オブジェクトを使用したりする必要はありません。java.util.List を指定できます。これは、List 型宣言の汎用パラメーターでマーシャリングされる汎用型である必要があります。また、各パーツのメディアタイプを指定するには @PartType アノテーションを使用してメソッドにアノテーションを付ける必要もあります。

例: Customer オブジェクトの List 戻り値

@Path("/multipart")
public class MyService {

    @GET
    @Produces("multipart/mixed")
    @PartType("application/xml")
    public List<Customer> get(){
        ...
    }
}

注記

上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。

2.7.11.2.2. multipart/form-data による出力

RESTEasy は、multipart/form-data を出力する簡単な API を提供します。

package org.jboss.resteasy.plugins.providers.multipart;

public class MultipartFormDataOutput extends MultipartOutput {

    public OutputPart addFormData(String key, Object entity, MediaType mediaType)
    public OutputPart addFormData(String key, Object entity, GenericType type, MediaType mediaType)
    public OutputPart addFormData(String key, Object entity, Class type, Type genericType, MediaType mediaType)
    public Map<String, OutputPart> getFormData()
}

multipart/form-data を出力するには、MultipartFormDataOutput オブジェクトを作成し、addFormData() メソッドを呼び出します。RESTEasy は、エンティティーオブジェクトをマーシャリングするための MessageBodyWriter を自動的に検出します。MultipartInput と同様に、汎用型メタデータに影響しやすいマーシャリングがある場合があります。この場合は、GenericType を使用します。通常は、オブジェクトとその MediaType を渡すだけで十分です。

例: multipart/form-data 形式の戻り値

@Path("/form")
public class MyService {

    @GET
    @Produces("multipart/form-data")
    public MultipartFormDataOutput get() {

        MultipartFormDataOutput output = new MultipartFormDataOutput();
        output.addPart("bill", new Customer("bill"), MediaType.APPLICATION_XML_TYPE);
        output.addPart("monica", new Customer("monica"), MediaType.APPLICATION_XML_TYPE);
        return output;
    }
}

注記

上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。

2.7.11.2.3. java.util.Map による Multipart FormData Output

ボディーの部分が均一である場合は、各パーツを手動でマーシャリングしたり、MultipartFormDataOutput オブジェクトを使用したりする必要はありません。java.util.Map のみを指定できます。この Map には、Map タイプ宣言の汎用パラメーターを使用してマーシャリングする汎用型が必要です。また、各パーツのメディアタイプを指定するには @PartType アノテーションを使用してメソッドにアノテーションを付ける必要もあります。

例: Customer オブジェクトの Map 戻り値

@Path("/multipart")
public class MyService {

    @GET
    @Produces("multipart/form-data")
    @PartType("application/xml")
    public Map<String, Customer> get() {
        ...
    }
}

注記

上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。

2.7.11.3. Multipart フォームの POJO へのマッピング

multipart/form-data パッケージについて正確な知識がある場合は、POJO クラスとマップすることができます。これは、org.jboss.resteasy.annotations.providers.multipart.MultipartForm アノテーション (@MultipartForm) および Jakarta RESTful Web Services @FormParam アノテーションを使用して実現できます。これを行うには、少なくともデフォルトのコンストラクターを使用して POJO を定義し、@FormParams でフィールドとプロパティーにアノテーションを付ける必要があります。これらの @FormParams にも org.jboss.resteasy.annotations.providers.multipart.PartType (@PartType) のアノテーションを付ける必要があります (出力を作成する場合)。

例: multipart フォームの POJO へのマッピング

public class CustomerProblemForm {

    @FormParam("customer")
    @PartType("application/xml")
    private Customer customer;

    @FormParam("problem")
    @PartType("text/plain")
    private String problem;

    public Customer getCustomer() { return customer; }
    public void setCustomer(Customer cust) { this.customer = cust; }
    public String getProblem() { return problem; }
    public void setProblem(String problem) { this.problem = problem; }
}

POJOI クラスを定義したら、それを使用して multipart/form-data を表すことができます。

例: CustomerProblemForm の送信

@Path("portal")
public interface CustomerPortal {

    @Path("issues/{id}")
    @Consumes("multipart/form-data")
    @PUT
    public void putProblem(@MultipartForm CustomerProblemForm,
                           @PathParam("id") int id);
}

// Somewhere using it:
{
    CustomerPortal portal = ProxyFactory.create(CustomerPortal.class, "http://example.com");
    CustomerProblemForm form = new CustomerProblemForm();
    form.setCustomer(...);
    form.setProblem(...);

    portal.putProblem(form, 333);
}

@MultipartForm アノテーションは、オブジェクトに @FormParam があり、そこからマーシャリングが必要であることを RESTEasy に指示します。また、同じオブジェクトを使用して multipart データを受信することもできます。

例: CustomerProblemForm の受信

@Path("portal")
public class CustomerPortalServer {

    @Path("issues/{id})
    @Consumes("multipart/form-data")
    @PUT
    public void putIssue(@MultipartForm CustomerProblemForm,
                         @PathParam("id") int id) {
       ... write to database...
    }
}

2.7.11.4. XML-binary Optimized Packaging (XOP)

一部のバイナリーコンテンツも保持する Jakarta XML Binding アノテーションが付けられた POJO がある場合は、バイナリーを base64 や 16 進などでエンコードする必要がないように送信することを選択できます。これは XOP を使用して実現でき、便利な POJO を使用しながらトランスポートが高速になります。

RESTEasy は、multipart/related としてパッケージ化された XOP メッセージを許可します。

XOP を設定するには、まず Jakarta XML Binding アノテーションが付けられた POJO が必要です。

例: Jakarta XML Binding POJO

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class Xop {

    private Customer bill;
    private Customer monica;

    @XmlMimeType(MediaType.APPLICATION_OCTET_STREAM)
    private byte[] myBinary;

    @XmlMimeType(MediaType.APPLICATION_OCTET_STREAM)
    private DataHandler myDataHandler;

    // methods, other fields ...
}

注記

@XmlMimeType は、Jakarta XML Binding にバイナリーコンテンツの mime タイプを伝えます。これは XOP パッケージ化を行う必要はありませんが、正確なタイプが分かっている場合は設定することが推奨されます。

上記の myBinary および myDataHandler はバイナリー添付として処理され、XOP オブジェクト全体が XML として送信されます。バイナリーの代わり、それらの参照のみが生成されます。javax.activation.DataHandler は、最も一般的なサポートされているタイプです。java.io.InputStream または javax.activation.DataSource が必要な場合は、DataHandler を使用する必要があります。java.awt.Image および javax.xml.transform.SourceSome も利用できます。

例: XOP でバイナリーコンテンツを送信するクライアント

// our client interface:
@Path("mime")
public static interface MultipartClient {
    @Path("xop")
    @PUT
    @Consumes(MultipartConstants.MULTIPART_RELATED)
    public void putXop(@XopWithMultipartRelated Xop bean);
}

// Somewhere using it:
{
    MultipartClient client = ProxyFactory.create(MultipartClient.class,
        "http://www.example.org");
    Xop xop = new Xop(new Customer("bill"), new Customer("monica"),
        "Hello Xop World!".getBytes("UTF-8"),
        new DataHandler(new ByteArrayDataSource("Hello Xop World!".getBytes("UTF-8"),
        MediaType.APPLICATION_OCTET_STREAM)));
    client.putXop(xop);
}

注記

上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。

@Consumes(MultipartConstants.MULTIPART_RELATED) は、multipart/related パッケージを送信するように RESTEasy に指示するために使用されます。@XopWithMultipartRelated は、XOP メッセージ を作成するように RESTEasy に指示するために使用されます。

例: XOP を受信する RESTEasy サーバー

@Path("/mime")
public class XopService {
    @PUT
    @Path("xop")
    @Consumes(MultipartConstants.MULTIPART_RELATED)
    public void putXopWithMultipartRelated(@XopWithMultipartRelated Xop xop) {
        // do very important things here
    }
}

@Consumes(MultipartConstants.MULTIPART_RELATED) は、multipart/related パッケージを読み取るように RESTEasy に指示するために使用されます。@XopWithMultipartRelated は、XOP メッセージを読み取ることを RESTEasy に伝えるために使用されます。RESTEasy サーバーは、@Produces アノテーションを追加し、適切な型を返すことで、同様の方法で XOP 値を生成するように設定できます。

2.7.11.5. multipart メッセージのデフォルトのフォールバックコンテンツタイプの上書き

デフォルトでは、Content-Type ヘッダーが一部にない場合、text/plain; charset=us-ascii がフォールバックとして使用されます。これは MIME RFC によって定義されます。ただし、多くのブラウザーなどの一部の Web クライアントはファイルパーツの Content-Type ヘッダーを送信しますが、multipart/form-data のすべてのフィールドについては送信しません。これにより、サーバー側で文字エンコーディングおよびマーシャリング解除エラーが発生する可能性があります。この問題を修正するには、RESTEasy の PreProcessInterceptor インフラストラクチャーを使用できます。これを使用して、リクエストごとに、RFC に準拠していない別のフォールバック値を動的に定義することができます。

例: * / *; charset=UTF-8 をデフォルトフォールバックとして設定

import org.jboss.resteasy.plugins.providers.multipart.InputPart;

@Provider
@ServerInterceptor
public class ContentTypeSetterPreProcessorInterceptor implements PreProcessInterceptor {

    public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
            throws Failure, WebApplicationException {
        request.setAttribute(InputPart.DEFAULT_CONTENT_TYPE_PROPERTY, "*/*; charset=UTF-8");
        return null;
    }
}

2.7.11.6. 複数パートメッセージのコンテンツタイプの上書き

インターセプターおよび InputPart.DEFAULT_CONTENT_TYPE_PROPERTY 属性を使用すると、デフォルトの Content-Type を設定できます。org.jboss.resteasy.plugins.providers.multipart.InputPart.setMediaType() を呼び出して、任意の入力部分で Content-Type をオーバーライドすることもできます。

例: Content-Type の上書き

@POST
@Path("query")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
public Response setMediaType(MultipartInput input) throws IOException {

    List<InputPart> parts = input.getParts();
    InputPart part = parts.get(0);
    part.setMediaType(MediaType.valueOf("application/foo+xml"));
    String s = part.getBody(String.class, null);
    ...
}

2.7.11.7. multipart メッセージのデフォルトのフォールバック charset の上書き

multipart メッセージの一部が、charset パラメーターのない Content-Type ヘッダーを持つ場合があります。InputPart.DEFAULT_CONTENT_TYPE_PROPERTY プロパティーが設定され、値に charset パラメーターがある場合、その値は charset パラメーターのない既存の Content-Type ヘッダーに追加されます。

また、デフォルトの charset は、定数 InputPart.DEFAULT_CHARSET_PROPERTY (resteasy.provider.multipart.inputpart.defaultCharset) を使用して指定することもできます。

例: デフォルトの charset の指定

import org.jboss.resteasy.plugins.providers.multipart.InputPart;

@Provider
@ServerInterceptor
public class ContentTypeSetterPreProcessorInterceptor implements PreProcessInterceptor {

    public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
            throws Failure, WebApplicationException {
        request.setAttribute(InputPart.DEFAULT_CHARSET_PROPERTY, "UTF-8");
        return null;
    }
}

注記

InputPart.DEFAULT_CONTENT_TYPE_PROPERTYInputPart.DEFAULT_CHARSET_PROPERTY の両方が設定されている場合は、InputLookup .DEFAULT_CHARSET_PROPERTY の値は InputPart.DEFAULT_CONTENT_TYPE_PROPERTY の値の charset を上書きします。

2.7.11.8. RESTEasy クライアントでの multipart エンティティーの送信

multipart プロバイダーを設定する他に、multipart データを送信するように RESTEasy クライアントを設定することもできます。

RESTEasy クライアントクラスの使用

アプリケーションで RESTEasy クライアントクラスを使用するには、Maven 依存関係をプロジェクトの POM ファイルに追加する必要があります。

例: Maven 依存関係

<dependency>
  <groupId>org.jboss.resteasy</groupId>
  <artifactId>resteasy-client</artifactId>
  <version>${version.org.jboss.resteasy}</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>org.jboss.resteasy</groupId>
  <artifactId>resteasy-multipart-provider</artifactId>
  <version>${version.org.jboss.resteasy}</version>
  <scope>provided</scope>
</dependency>

RESTEasy クライアントを使用した multipart データの送信

マルチパートデータを送信するには、まず RESTEasy Client を設定し、マルチパートデータが含まれるように org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput オブジェクトを構築する必要があります。次に、クライアントを使用してその MultipartFormDataOutput オブジェクトを javax.ws.rs.core.GenericEntity として送信することができます。

例: RESTEasy クライアント

ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://foo.com/resource");

MultipartFormDataOutput formOutputData = new MultipartFormDataOutput();
formOutputData.addFormData("part1", "this is part 1", MediaType.TEXT_PLAIN);
formOutputData.addFormData("part2", "this is part 2", MediaType.TEXT_PLAIN);

GenericEntity<MultipartFormDataOutput> data = new GenericEntity<MultipartFormDataOutput>(formOutputData) { };

Response response = target.request().put(Entity.entity(data, MediaType.MULTIPART_FORM_DATA_TYPE));

response.close();

2.7.12. RESTEasy Atom サポート

RESTEasy Atom API およびプロバイダーは、RESTEasy が Atom を表すように定義する簡単なオブジェクトモデルです。API の主なクラスは org.jboss.resteasy.plugins.providers.atom パッケージにあります。RESTEasy は Jakarta XML Binding を使用して API をマーシャリングおよびアンマーシャリングします。プロバイダーは Jakarta XML Binding をベースとしており、XML を使用した Atom オブジェクトの送信のみに限定されません。RESTEasy のすべての Jakarta XML Binding プロバイダーは、JSON を含む Atom API およびプロバイダーが再利用できます。

import org.jboss.resteasy.plugins.providers.atom.Content;
import org.jboss.resteasy.plugins.providers.atom.Entry;
import org.jboss.resteasy.plugins.providers.atom.Feed;
import org.jboss.resteasy.plugins.providers.atom.Link;
import org.jboss.resteasy.plugins.providers.atom.Person;

@Path("atom")
public class MyAtomService {

   @GET
   @Path("feed")
   @Produces("application/atom+xml")
   public Feed getFeed() throws URISyntaxException {
      Feed feed = new Feed();
      feed.setId(new URI("http://example.com/42"));
      feed.setTitle("My Feed");
      feed.setUpdated(new Date());
      Link link = new Link();
      link.setHref(new URI("http://localhost"));
      link.setRel("edit");
      feed.getLinks().add(link);
      feed.getAuthors().add(new Person("John Brown"));
      Entry entry = new Entry();
      entry.setTitle("Hello World");
      Content content = new Content();
      content.setType(MediaType.TEXT_HTML_TYPE);
      content.setText("Nothing much");
      entry.setContent(content);
      feed.getEntries().add(entry);
      return feed;
   }
}

2.7.12.1. Atom プロバイダーでの Jakarta XML バインディングの使用

org.jboss.resteasy.plugins.providers.atom.Content クラスを使用すると、コンテンツの本文である Jakarta XML Binding アノテーションが付けられたオブジェクトをアンマーシャリングおよびマーシャリングすることができます。

例: カスタマーのエントリー

@XmlRootElement(namespace = "http://jboss.org/Customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
   @XmlElement
   private String name;

   public Customer() {
   }

   public Customer(String name) {
      this.name = name;
   }

   public String getName() {
      return name;
   }
}

@Path("atom")
public static class AtomServer {
   @GET
   @Path("entry")
   @Produces("application/atom+xml")
   public Entry getEntry() {
      Entry entry = new Entry();
      entry.setTitle("Hello World");
      Content content = new Content();
      content.setJAXBObject(new Customer("bill"));
      entry.setContent(content);
      return entry;
   }
}

Content.setJAXBObject() メソッドを使用すると、Jakarta XML Binding に送信するコンテンツオブジェクトを指定して適切にマーシャルできます。XML 以外の別のベース形式を使用している場合 (application/atom+json)、アタッチされた Jakarta XML Binding オブジェクトは同じ形式でマーシャリングされます。Atom ドキュメントを入力とする場合は、Content.getJAXBObject(Class clazz) メソッドを使用して Content から Jakarta XML Binding オブジェクトを抽出することもできます。

例: カスタマーオブジェクトを抽出する Atom ドキュメント

@Path("atom")
public static class AtomServer {
   @PUT
   @Path("entry")
   @Produces("application/atom+xml")
   public void putCustomer(Entry entry) {
      Content content = entry.getContent();
      Customer cust = content.getJAXBObject(Customer.class);
   }
}

2.7.13. YAML プロバイダー

警告

resteasy-yaml-provider モジュールはサポートされません。RESTEasy のマーシャリング解除に使用される SnakeYAML ライブラリーでセキュリティー上の問題があるため、この使用は推奨されません。

RESTEasy には、SnakeYAML ライブラリーを使用した YAML のサポートが同梱されています。

JBoss EAP 7.1 より前のリリースでは、YAML プロバイダー設定はデフォルトで有効にされていました。そのため、YAML がアプリケーションでこれを使用するよう Maven 依存関係を設定することのみが必要でした。JBoss EAP 7.1 より、YAML プロバイダーはデフォルトで無効になり、アプリケーションで明示的に有効にする必要があります。

YAML プロバイダーの有効化

アプリケーションで YAML プロバイダーを有効にするには、以下の手順を実行します。

  1. javax.ws.rs.ext.Providers という名前のファイルを作成または更新します。
  2. 以下の内容をファイルに追加します。

    org.jboss.resteasy.plugins.providers.YamlProvider
  3. WAR または JAR ファイルの META-INF/services/ フォルダーにファイルを配置します。
YAML プロバイダー Maven の依存関係

アプリケーションで YAML プロバイダーを使用するには、アプリケーションのプロジェクト POM ファイルに snakeyaml JAR 依存関係を追加する必要があります。

例: YAML の Maven 依存関係

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-yaml-provider</artifactId>
    <version>${version.org.jboss.resteasy}</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>${version.org.yaml.snakeyaml}</version>
</dependency>

YAML プロバイダーコードの例

YAML プロバイダーは以下の mime タイプを認識します。

  • text/x-yaml
  • text/yaml
  • application/x-yaml

以下は、リソースメソッドで YAML を使用する方法の例になります。

例: リソース生成 YAML

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/yaml")
public class YamlResource {

  @GET
  @Produces("text/x-yaml")
  public MyObject getMyObject() {
    return createMyObject();
  }
...
}

2.8. Jakarta JSON Processing の使用

Jakarta JSON Processing は Jakarta JSON Processing 1.1 仕様 で定義されています。

Jakarta JSON Processing は、JSON を処理する API を定義します。JBoss EAP は、リクエストまたは応答エンティティーとして javax.json.JsonObjectjavax.json.JsonArrayjavax.json.JsonStructure をサポートします。

注記

Jakarta JSON Processing は、JSON with Padding (JSONP) とは異なります。

注記

Jakarta JSON Processing は、同じクラスパス上にある場合は Jackson と競合しません。

JsonObject を作成するには、Json.createObjectBuilder() を呼び出して JSON オブジェクトをビルドして JsonObjectBuilder を使用します。

例: javax.json.JsonObject の作成

JsonObject obj = Json.createObjectBuilder().add("name", "Bill").build();

例: javax.json.JsonObject の対応 JSON

{
  "name":"Bill"
}

JsonArray を作成するには、Json.createArrayBuilder() を呼び出して SON アレイを構築し、JsonArrayBuilder を使用します。

例: javax.json.JsonArray の作成

JsonArray array =
  Json.createArrayBuilder()
    .add(Json.createObjectBuilder().add("name", "Bill").build())
    .add(Json.createObjectBuilder().add("name", "Monica").build()).build();

例: javax.json.JsonArray の対応 JSON

[
  {
  "name":"Bill"
  },
  {
  "name":"Monica"
  }
]

JsonStructureJsonObject および JsonArray の親クラスです。

例: javax.json.JsonStructure の作成

JsonObject obj = Json.createObjectBuilder().add("name", "Bill").build();

JsonArray array =
  Json.createArrayBuilder()
    .add(Json.createObjectBuilder().add("name", "Bill").build())
    .add(Json.createObjectBuilder().add("name", "Monica").build()).build();

JsonStructure sObj = (JsonStructure) obj;
JsonStructure sArray = (JsonStructure) array;

JsonObjectJsonArray、および JsonStructure は、Jakarta RESTful Web Services リソースで直接使用できます。

例: Jakarta JSON Processing での Jakarta RESTful Web Services リソース

@Path("object")
@POST
@Produces("application/json")
@Consumes("application/json")
public JsonObject object(JsonObject obj) {
  // do something
  return obj;
 }

@Path("array")
@POST
@Produces("application/json")
@Consumes("application/json")
public JsonArray array(JsonArray array) {
  // do something
  return array;
}

@Path("structure")
@POST
@Produces("application/json")
@Consumes("application/json")
public JsonStructure structure(JsonStructure structure) {
  // do something
  return structure;
}

クライアントからの Jakarta JSON Processing を使用して JSON を送信することもできます。

例: Jakarta JSON Processing を使用したクライアント

WebTarget target = client.target(...);
JsonObject obj = Json.createObjectBuilder().add("name", "Bill").build();
JsonObject newObj = target.request().post(Entity.json(obj), JsonObject.class);

2.9. RESTEasy/Jakarta Enterprise Beans の統合

RESTEasy を Jakarta Enterprise Beans と統合するには、Jakarta RESTful Web Services アノテーションを Jakarta RESTful Web Services エンドポイントとして公開する Jakarta Enterprise Beans クラスに追加します。また、Bean のビジネスインターフェイスにアノテーションを適用することもできます。Bean をエンドポイントとしてアクティブ化するには、以下の 2 つの方法があります。

  • web.xml ファイルの使用。
  • javax.ws.rs.core.Application の使用

Jakarta Enterprise Beans を Jakarta RESTful Web Services リソースとして機能させるには、ステートレスセッション Bean の @Remote または @Local インターフェイスに Jakarta RESTful Web Services アノテーションを付けます。

@Local
@Path("/Library")
public interface Library {
   @GET
   @Path("/books/{isbn}")
   public String getBook(@PathParam("isbn") String isbn);
}
@Stateless
public class LibraryBean implements Library {
...
}
注記

Library インターフェイスは完全修飾名で参照され、LibraryBean は単純なクラス名でのみ参照されることに注意してください。

次に、RESTEasy web.xml ファイルで resteasy.jndi.resources コンテキストパラメーターを使用して、Jakarta Enterprise Beans を RESTEasy で手動で登録します。

<web-app>
   <display-name>Archetype Created Web Application</display-name>
   <context-param>
      <param-name>resteasy.jndi.resources</param-name>
      <param-value>java:module/LibraryBean!org.app.Library</param-value>
   </context-param>
   <listener>
      <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
   </listener>
   <servlet>
      <servlet-name>Resteasy</servlet-name>
      <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>Resteasy</servlet-name>
      <url-pattern>/*</url-pattern>
   </servlet-mapping>
</web-app>

resteasy.jndi.resources コンテキストパラメーターに対して、複数の Jakarta Enterprise Bean 名をコンマで区切り、複数の Java Naming and Directory Interface 名を指定することもできます。

Jakarta Enterprise Beans を RESTEasy エンドポイントとしてアクティベートする代替の Jakarta EE-standard 方法は、javax.ws.rs.core.Application を使用することです。これには、Jakarta Enterprise Beans 実装クラスをアプリケーションの getClasses() メソッドによって返されるセットに追加します。このアプローチでは、web.xml ファイルで指定する必要はありません。

RESTEasy と Jakarta Enterprise Beans の統合を示す実例については、JBoss EAP に同梱される kitchensinkhelloworld-html5managed-executor-service クイックスタートを参照してください。

2.10. Spring の統合

注記

アプリケーションには既存の Jakarta XML Web Services サービスおよびクライアント設定が必要です。

RESTEasy は Spring 4.2.x と統合します。

Maven ユーザーは resteasy-spring アーティファクトを使用する必要があります。または、JAR を JBoss EAP のモジュールとして利用できます。

RESTEasy には独自の Spring ContextLoaderListener が含まれています。これは、BeanFactory が Bean を作成する際に Jakarta RESTful Web Services アノテーションを処理する RESTEasy 固有の BeanPostProcessor を登録します。そのため、RESTEasy は Bean クラスで @Provider および Jakarta RESTful Web Services リソースアノテーションを自動的にスキャンし、それらを Jakarta RESTful Web Services リソースとして登録します。

以下を web.xml ファイルに追加し、RESTEasy/Spring 統合機能を有効にします。

<web-app>
   <display-name>Archetype Created Web Application</display-name>
   <listener>
      <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
   </listener>
   <listener>
      <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
   </listener>
   <listener>
      <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
   </listener>
   <servlet>
      <servlet-name>Resteasy</servlet-name>
      <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>Resteasy</servlet-name>
      <url-pattern>/*</url-pattern>
   </servlet-mapping>
</web-app>

SpringContextLoaderListener は、ResteasyBootstrap の後に宣言する必要があります。これは、初期化される ServletContext 属性を使用するためです。

RESTEasy と Spring の統合を示す web アプリケーションの作業例は、JBoss EAP に同梱される spring-resteasy クイックスタートを参照してください。

2.11. Jakarta Contexts and Dependency Injection の統合

RESTEasy と Jakarta Contexts and Dependency Injection 間の統合は resteasy-cdi モジュールによって提供されます。

Jakarta RESTful Web Services および Jakarta Contexts and Dependency Injection 仕様の両方が独自のコンポーネントモデルを導入します。基本的な制約のセットを満たす Jakarta Contexts and Dependency Injection アーカイブに置かれているすべてのクラスは暗黙的に Jakarta Contexts and Dependency Injection Bean です。 @Path または @Provider を持つ Java クラスの明示的な宣言は、Jakarta RESTful Web Services コンポーネントとなるために必要です。統合コードがないと、Jakarta Contexts and Dependency Injection Bean に適したクラスに Jakarta RESTful Web Services アノテーションを付けると、誤った結果が得られ、Jakarta RESTful Web Services コンポーネントは Jakarta Contexts and Dependency Injection によって管理されません。resteasy-cdi モジュールは、RESTEasy が Jakarta Contexts and Dependency Injection コンテナーから取得したクラスインスタンスと連携できるようにするブリッジです。

web サービスの呼び出し中に、resteasy-cdi モジュールは Jakarta RESTful Web Services コンポーネントの管理対象インスタンスに対して Jakarta Contexts and Dependency Injection コンテナーを要求します。次に、このインスタンスが RESTEasy に渡されます。Bean デプロイメントアーカイブではない JAR ファイルに置かれているクラスなど、何らかの理由で管理インスタンスが利用できない場合、RESTEasy はクラス自体をインスタンス化するためにフォールバックします。

そのため、インジェクション、ライフサイクル管理、イベントデコレーション、インターセプターバインディングなどの Jakarta Contexts and Dependency Injection サービスは Jakarta RESTful Web Services コンポーネントで使用できます。

2.11.1. デフォルトのスコープ。

スコープを明示的に定義しない Jakarta Contexts and Dependency Injection Bean は、デフォルトで @Dependent スコープです。この擬似スコープは、Bean がインジェクトされる Bean のライフサイクルに適応することを意味します。要求、セッション、アプリケーションを含む通常のスコープは、コンポーネントのライフサイクル境界を明示的に指定するため、Jakarta RESTful Web Services コンポーネントにより適しています。そのため、resteasy-cdi モジュールは以下の方法でデフォルトのスコーピングを変更します。

  • Jakarta RESTful Web Services ルートリソースが明示的にスコープを定義しない場合、これは要求スコープにバインドされます。
  • Jakarta RESTful Web Services プロバイダーまたは javax.ws.rs.Application サブクラスがスコープを明示的に定義しない場合、アプリケーションスコープにバインドされます。
警告

スコープを宣言しないすべての bean のスコープは resteasy-cdi モジュールによって変更されるため、セッション bean にも影響を及ぼします。これにより、仕様によりこれらのコンポーネントが @RequestScoped になることが禁止されるため、ステートレスセッション Bean またはシングルトンの範囲が自動的に変更されると競合が発生します。そのため、ステートレスセッション Bean またはシングルトンを使用する場合は、スコープを明示的に定義する必要があります。この要件は、今後のリリースで削除される可能性があります。

resteasy-cdi モジュールは JBoss EAP にバンドルされています。したがって、モジュールを個別にダウンロードしたり、設定を追加したりする必要はありません。Jakarta RESTful Web Services リソースで Jakarta Contexts and Dependency Injection bean を使用する例は、JBoss EAP に同梱される kitchensink クイックスタートを参照してください。

2.12. RESTEasy フィルターおよびインターセプター

Jakarta RESTful Web Services には、フィルターとインターセプターという 2 つの異なる概念があります。フィルターは主に、着信および発信要求ヘッダーまたは応答ヘッダーを変更または処理するために使用されます。リクエストおよび応答処理の前後に実行されます。

2.12.1. サーバー側フィルター

サーバー側では、ContainerRequestFilters および ContainerResponseFilters という 2 種類のフィルターを利用できます。ContainerRequestFilters は、Jakarta RESTful Web Services リソースメソッドが呼び出される前に実行されます。ContainerResponseFilters は、Jakarta RESTful Web Services リソースメソッドが呼び出された後に実行されます。

さらに、ContainerRequestFilters には pre-matching および post-matching のタイプがあります。事前一致する ContainerRequestFilters@PreMatching アノテーションで指定され、Jakarta RESTful Web Services リソースメソッドが受信 HTTP 要求に一致する前に実行されます。事後一致する ContainerRequestFilters は、@PostMatching アノテーションで指定され、Jakarta RESTful Web Services リソースメソッドが受信 HTTP 要求と照合された後に実行されます。

事前一致フィルターは多くの場合、要求属性を変更して、.xml をストリップし、Accept ヘッダーを追加するなど、特定のリソースメソッドへの一致方法を変更するために使用されます。ContainerRequestFiltersContainerRequestContext.abortWith (Response) を呼び出して要求を中止できます。たとえば、フィルターはカスタム認証プロトコルを実装している場合に中止する必要があるかもしれません。

リソースクラスメソッド実行後、Jakarta RESTful Web Services はすべての ContainerResponseFilters を実行します。これらのフィルターにより、発信応答がマーシャリングされ、クライアントに送信される前に送信応答を変更できます。

例: 要求フィルター

public class RoleBasedSecurityFilter implements ContainerRequestFilter {
  protected String[] rolesAllowed;
  protected boolean denyAll;
  protected boolean permitAll;

  public RoleBasedSecurityFilter(String[] rolesAllowed, boolean denyAll, boolean permitAll) {
    this.rolesAllowed = rolesAllowed;
    this.denyAll = denyAll;
    this.permitAll = permitAll;
  }

  @Override
  public void filter(ContainerRequestContext requestContext) throws IOException  {
    if (denyAll) {
       requestContext.abortWith(Response.status(403).entity("Access forbidden: role not allowed").build());
       return;
    }
    if (permitAll) return;
    if (rolesAllowed != null) {
       SecurityContext context = ResteasyProviderFactory.getContextData(SecurityContext.class);
       if (context != null) {
          for (String role : rolesAllowed) {
             if (context.isUserInRole(role)) return;
          }
          requestContext.abortWith(Response.status(403).entity("Access forbidden: role not allowed").build());
          return;
       }
    }
    return;
  }
}

例: 応答フィルター

public class CacheControlFilter implements ContainerResponseFilter {
   private int maxAge;

   public CacheControlFilter(int maxAge) {
      this.maxAge = maxAge;
   }

   public void filter(ContainerRequestContext req, ContainerResponseContext res)
           throws IOException {
      if (req.getMethod().equals("GET")) {
         CacheControl cc = new CacheControl();
         cc.setMaxAge(this.maxAge);
         res.getHeaders().add("Cache-Control", cc);
      }
   }
}

2.12.2. クライアント側のフィルター

クライアント側のフィルターの詳細は、本書の Jakarta RESTful Web Services Client API のセクションを参照してください。

2.12.3. RESTEasy インターセプター

2.12.3.1. Jakarta RESTful Web Services 呼び出しのインターセプト

RESTEasy は Jakarta RESTful Web Services 呼び出しをインターセプトし、インターセプターと呼ばれるリスナーのようなオブジェクトを介してルーティングすることができます。

フィルターはリクエストまたは応答ヘッダーを変更しますが、インターセプターはメッセージボディーを処理します。インターセプターは、対応するリーダーまたはライターと同じ呼び出しスタックで実行されます。ReaderInterceptorsMessageBodyReaders の実行をラップします。WriterInterceptorsMessageBodyWriters の実行をラップします。これは、特定のコンテンツエンコーディングを実装するために使用できます。これらは、デジタル署名の生成や、マーシャリング前後の Java オブジェクトモデルの投稿または事前処理に使用することができます。

ReaderInterceptors および WriterInterceptors は、サーバー側またはクライアント側のいずれかで使用することができます。これらは、@ServerInterceptor または @ClientInterceptor のいずれかや、@Provider でアノテーションが付けられたため、RESTEasy はそれらをインターセプター一覧に追加するかどうかを認識できます。

これらのインターセプターは、MessageBodyReader.readFrom() または MessageBodyWriter.writeTo() の呼び出しをラップします。これらは、OutputInput ストリームをラップするために使用できます。

例: インターセプター

@Provider
public class BookReaderInterceptor implements ReaderInterceptor {
    @Inject private Logger log;
    @Override
    @ReaderInterceptorBinding
    public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
        log.info("*** Intercepting call in BookReaderInterceptor.aroundReadFrom()");
        VisitList.add(this);
        Object result = context.proceed();
        log.info("*** Back from intercepting call in BookReaderInterceptor.aroundReadFrom()"); return result;
    }
}

インターセプターと MessageBodyReader または Writer は、単一の大きな Java 呼び出しスタックで呼び出されます。ReaderInterceptorContext.proceed() または WriterInterceptorContext.proceed() は、次のインターセプターに移動するために呼び出されます。または、呼び出すインターセプターがない場合は、MessageBodyReaderMessageBodyWriterreadFrom()writeTo() メソッドになります。このラッピングにより、オブジェクトは ReaderWriter に到達する前に変更でき、proceed() が返された後にクリーンアップされます。

以下の例は、ヘッダー値を応答に追加するサーバー側のインターセプターです。

@Provider
public class BookWriterInterceptor implements WriterInterceptor {
   @Inject private Logger log;

   @Override
   @WriterInterceptorBinding
   public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
      log.info("*** Intercepting call in BookWriterInterceptor.aroundWriteTo()");
      VisitList.add(this);
      context.proceed();
      log.info("*** Back from intercepting call in BookWriterInterceptor.aroundWriteTo()");
   }
}

2.12.3.2. インターセプターの登録

アプリケーションで RESTEasy Jakarta RESTful Web Services インターセプターを登録するには、context-param 要素の resteasy.providers パラメーターの下の web.xml ファイルにこれをリストするか、これを Application.getClasses() または Application.getSingletons() メソッドのクラスまたはオブジェクトとして返します。

<context-param>
    <param-name>resteasy.providers</param-name>
    <param-value>my.app.CustomInterceptor</paramvalue>
</context-param>
package org.jboss.resteasy.example;

import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;

public class MyApp extends Application {

  public java.util.Set<java.lang.Class<?>> getClasses() {
    Set<Class<?>> resources = new HashSet<Class<?>>();
    resources.add(MyResource.class);
    resources.add(MyProvider.class);
    return resources;
  }
}
package org.jboss.resteasy.example;

import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;

public class MyApp extends Application {

    protected Set<Object> singletons = new HashSet<Object>();

    public MyApp() {
        singletons.add(new MyResource());
        singletons.add(new MyProvider());
    }

    @Override
    public Set<Object> getSingletons() {
        return singletons;
    }
}

2.12.4. gzip 圧縮および展開

RESTEasy は GZIP 圧縮および展開に対応しています。GZIP の展開をサポートするため、クライアントフレームワークまたは Jakarta RESTful Web Services サービスはメッセージボディーを gzipContent-Encoding で自動的に展開し、Accept-Encoding ヘッダーを gzip, deflate に自動的に設定できるため、ヘッダーの手動設定は必要ありません。GZIP 圧縮をサポートするため、クライアントフレームワークがリクエストを送信している場合や、サーバーが gzip に設定された Content-Encoding ヘッダーを使用して応答を送信している場合に、RESTEasy は出力メッセージを圧縮します。@org.jboss.resteasy.annotation.GZIP アノテーションを使用して Content-Encoding ヘッダーを設定できます。

以下の例は、gzip 圧縮する、出力メッセージボディーの order をタグ付けします。

例: GZIP 圧縮

@Path("/")
public interface MyProxy {

   @Consumes("application/xml")
   @PUT
   public void put(@GZIP Order order);
}

例: サーバー応答のタグ付け GZIP 圧縮

@Path("/")
public class MyService {

   @GET
   @Produces("application/xml")
   @GZIP
   public String getData() {...}
}

2.12.4.1. GZIP 圧縮および展開の設定

注記

RESTEasy は、サイズが大きいものの、攻撃者が圧縮し、サーバーに送信しているエンティティーの展開を防ぐために、GZIP 圧縮および展開をデフォルトで無効にします。

GZIP 圧縮と展開には、以下の 3 つのインターセプターが関係します。

  • org.jboss.resteasy.plugins.interceptors.GZIPDecodingInterceptor: Content-Encoding ヘッダーが存在し、値が gzip の場合、GZIPDecodingInterceptor はメッセージボディーを展開する InputStream をインストールします。
  • org.jboss.resteasy.plugins.interceptors.GZIPEncodingInterceptor: Content-Encoding ヘッダーが存在し、値が gzip の場合、GZIPEncodingInterceptor はメッセージボディーを圧縮する OutputStream をインストールします。
  • org.jboss.resteasy.plugins.interceptors.AcceptEncodingGZIPFilter: Accept-Encoding ヘッダーが存在しない場合、AcceptEncodingGZIPFiltergzip, deflate の値で Accept-Encoding ヘッダーを追加します。Accept-Encoding ヘッダーが存在するが gzip が含まれていない場合は、AcceptEncodingGZIPFilter インターセプターが値 , gzip を追加します。

    注記

    GZIP 圧縮または展開を有効にしても、AcceptEncodingGZIPFilter インターセプターの存在には依存しません。

GZIP デコンプレッシングを有効にすると、GZIPDecodingInterceptor が圧縮メッセージボディーから抽出できるバイト数の上限が設定されます。デフォルトの制限は 10,000,000 です。

2.12.4.2. サーバー側の GZIP 設定

インターセプターを有効にするには、クラスパスの javax.ws.rs.ext.Providers ファイルにクラス名を追加します。圧縮ファイルの上限は、web アプリケーションコンテキストパラメーター resteasy.gzip.max.input を使用して設定します。サーバー側でこの制限を超えると、GZIPDecodingInterceptor はステータス 413 - Request Entity Too Large の応答と、上限を指定するメッセージを返します。

2.12.4.2.1. クライアント側の GZIP 設定

GZIP インターセプターを有効にするには、ClientWebTarget などでこれを登録します。例を以下に示します。

Client client = new ResteasyClientBuilder() // Activate gzip compression on client:
    .register(AcceptEncodingGZIPFilter.class)
    .register(GZIPDecodingInterceptor.class)
    .register(GZIPEncodingInterceptor.class)
    .build();

圧縮ファイルの上限を設定するには、特定の値で GZIPDecodingInterceptor のインスタンスを作成します。

Client client = new ResteasyClientBuilder() // Activate gzip compression on client:
    .register(AcceptEncodingGZIPFilter.class)
    .register(new GZIPDecodingInterceptor(256))
    .register(GZIPEncodingInterceptor.class)
    .build();

クライアント側で上限を超えると、GZIPDecodingInterceptor は上限を指定するメッセージとともに ProcessingException を出力します。

2.12.5. リソースごとのメソッドフィルターとインターセプター

フィルターまたはインターセプターを特定のリソースメソッドに対してのみ実行したい場合があります。これは、以下の 2 つのの方法で実行できます。

DynamicFeature インターフェイスの実装

DynamicFeature インターフェイスには、コールバックメソッド configure(ResourceInfo resourceInfo, FeatureContext context) が含まれます。これは、デプロイされた各 Jakarta RESTful Web Services メソッドおよびデプロイされた各 Jakarta RESTful Web Services メソッドに対して呼び出されます。ResourceInfo パラメーターには、デプロイされている現在の Jakarta RESTful Web Services メソッドに関する情報が含まれています。FeatureContext は、Configurable インターフェイスの拡張機能です。このパラメーターの register() メソッドを使用して、このメソッドに割り当てるフィルターとインターセプターをバインドできます。

例: DynamicFeature インターフェイスの使用

@Provider
public class AnimalTypeFeature implements DynamicFeature {
    @Override
    public void configure(ResourceInfo info, FeatureContext context) {
        if (info.getResourceMethod().getAnnotation(GET.class) != null)
            AnimalFilter filter = new AnimalFilter();
            context.register(filter);
        }
    }
}

上記の例では、AnimalTypeFeature を使用して登録するプロバイダーは、インターフェイスのいずれかを実装する必要があります。この例では、以下のインターフェイスのいずれかを実装する必要があるプロバイダー AnimalFilter を登録します。これは、ContainerRequestFilterContainerResponseFilterReaderInterceptorWriterInterceptor、または Feature のいずれかを実装する必要があります。この場合、AnimalFilter は GET アノテーションが付けられたすべてのリソースメソッドに適用されます。詳細は DynamicFeature Documentation を参照してください。

@NameBinding アノテーションを使用します。

@NameBinding の動作は、Jakarta Contexts and Dependency Injection インターセプターと似ています。@NameBinding でカスタムアノテーションにアノテーションを付け、そのカスタムアノテーションをフィルターおよびリソースメソッドに適用します。

例: @NameBinding の使用

@NameBinding
public @interface DoIt {}

@DoIt
public class MyFilter implements ContainerRequestFilter {...}

@Path("/root")
public class MyResource {

   @GET
   @DoIt
   public String get() {...}
}

詳細は NameBinding Documentation のドキュメントを参照してください。

2.12.6. 順序付け

順序付けは、フィルターまたはインターセプタークラスの @Priority アノテーションを使用して実行されます。

2.12.7. フィルターおよびインターセプターによる例外処理

フィルターまたはインターセプターに関連する例外は、クライアント側またはサーバー側で発生する可能性があります。クライアント側では、javax.ws.rs.client.ProcessingException および javax.ws.rs.client.ResponseProcessingException という例外を処理する必要があります。javax.ws.rs.client.ProcessingException は、リクエストがサーバーに送信される前にエラーが発生していた場合、クライアント側で出力されます。サーバーからクライアントが受信した応答の処理にエラーが発生すると、javax.ws.rs.client.ResponseProcessingException がクライアント側で出力されます。

サーバー側で、フィルターまたはインターセプターによって出力される例外は、Jakarta RESTful Web Services メソッドから出力された他の例外と同じ方法で処理されます。これは、出力される例外の ExceptionMapper を見つけようとします。Jakarta RESTful Web Services メソッドでの例外の処理方法は Exception Handling を参照してください。

2.13. RESTEasy プロバイダーおよびインターセプターのロギング

RESTEasy は、使用されたプロバイダーとインターセプターを DEBUG レベルのロギングでログに記録します。以下の管理 CLI コマンドを使用すると、RESTEasy に関連するすべてのログレベルを有効にできます。

/subsystem=logging/console-handler=CONSOLE:write-attribute(name=level,value=ALL)

/subsystem=logging/logger=org.jboss.resteasy:add(level=ALL)

/subsystem=logging/logger=javax.xml.bind:add(level=ALL)

/subsystem=logging/logger=com.fasterxml.jackson:add(level=ALL)

2.14. 例外処理

2.14.1. 例外マッパーの作成

例外マッパーは、発生する例外をキャッチし、特定の HTTP 応答を書き込むアプリケーションが提供するカスタムコンポーネントです。

例外マッパーを作成する場合は、@Provider アノテーションが付けられたクラスを作成し、ExceptionMapper インターフェイスを実装します。

以下は例外マッパーの例です。

@Provider
public class EJBExceptionMapper implements ExceptionMapper<javax.ejb.EJBException> {
  public Response toResponse(EJBException exception) {
    return Response.status(500).build();
  }
}

例外マッパーを登録するには、web.xml ファイルの resteasy.providers context-param 一覧し、ResteasyProviderFactory クラスでプログラムで登録します。

2.14.2. 内部で出力される例外の管理

表2.2 例外リスト

例外HTTP コード説明

BadRequestException

400

正しくない要求。リクエストが適切にフォーマットされていなかったか、リクエスト入力の処理に問題がありました。

UnauthorizedException

401

承認されていません。RESTEasy のアノテーションベースのロールベースのセキュリティーを使用している場合には、セキュリティー例外が発生します。

InternalServerErrorException

500

内部サーバーエラー。

MethodNotAllowedException

405

リソースによって呼び出された HTTP 操作を処理するための Jakarta RESTful Web Services メソッドはありません。

NotAcceptableException

406

Accept ヘッダーにリストされているメディアタイプを生成できる Jakarta RESTful Web Services メソッドはありません。

NotFoundException

404

リクエストパス/リソースを提供する Jakarta RESTful Web Services メソッドはありません。

ReaderException

400

MessageBodyReaders から発生するすべての例外は、この例外内でラップされます。ラップされた例外に対する ExceptionMapper がない場合、または例外が WebApplicationException ではない場合、デフォルトでは RESTEasy は 400 コードを返します。

WriterException

500

MessageBodyWriters から発生するすべての例外は、この例外内でラップされます。ラップされた例外に対する ExceptionMapper がない場合、または例外が WebApplicationException ではない場合、デフォルトでは RESTEasy は 400 コードを返します。

JAXBUnmarshalException

400

Jakarta XML Bidning プロバイダー (XML および Jackson) は、JAXBExceptions をラップする可能性のある読み取りでこの例外を出力します。このクラスは ReaderException を拡張します。

JAXBMarshalException

500

Jakarta XML Bidning プロバイダー (XML および Jackson) は、JAXBExceptions をラップする可能性のある書き込みでこの例外を出力します。このクラスは WriterException を拡張します。

ApplicationException

該当なし

アプリケーションコードから出力されるすべての例外をラップし、InvocationTargetException と同じように機能します。ラップされた例外に対する ExceptionMapper がある場合は、要求の処理に使用されます。

失敗

該当なし

内部 RESTEasy エラー。ログに記録されない。

LoggableFailure

該当なし

内部 RESTEasy エラー。ログが記録されています。

DefaultOptionsMethodException

該当なし

ユーザーが HTTP OPTIONS を呼び出しても、Jakarta RESTful Web Services メソッドが呼び出されない場合、RESTEasy はこの例外を発生させてデフォルトの動作を提供します。

UnrecognizedPropertyExceptionHandler

400

RESTEasy Jackson プロバイダーは、JSON データが無効であると判断するとこの例外が発生します。

2.15. Jakarta RESTful Web Services Web サービスのセキュア化

RESTEasy は、Jakarta RESTful Web Services メソッドの @RolesAllowed@PermitAll、および @DenyAll アノテーションをサポートします。ただし、これらのアノテーションを認識させるには、ロールベースのセキュリティーを有効にする必要があります。

2.15.1. ロールベースのセキュリティーの有効化

以下の手順に従って、web.xml ファイルを設定し、ロールベースのセキュリティーを有効にします。

警告

アプリケーションが Jakarta Enterprise Beans を使用する場合は、ロールベースのセキュリティーをアクティベートしないでください。Jakarta Enterprise Beans コンテナーは、RESTEasy の代わりにこの機能を提供します。

RESTEasy Jakarta RESTful Web Services Web Service のロールベースセキュリティーの有効化

  1. テキストエディターでアプリケーションの web.xml ファイルを開きます。
  2. 以下の <context-param> をファイルに、<web-app> 内に追加します。

    <context-param>
      <param-name>resteasy.role.based.security</param-name>
      <param-value>true</param-value>
    </context-param>
  3. <security-role> タグを使用して、RESTEasy Jakarta RESTful Web Services WAR ファイル内で使用するすべてのロールを宣言します。

    <security-role>
      <role-name>ROLE_NAME</role-name>
    </security-role>
    <security-role>
      <role-name>ROLE_NAME</role-name>
    </security-role>
  4. すべてのロールに対して、Jakarta RESTful Web Services ランタイムによって処理されるすべての URL へのアクセスを承認します。

    <security-constraint>
      <web-resource-collection>
        <web-resource-name>Resteasy</web-resource-name>
        <url-pattern>/PATH</url-pattern>
      </web-resource-collection>
      <auth-constraint>
        <role-name>ROLE_NAME</role-name>
        <role-name>ROLE_NAME</role-name>
      </auth-constraint>
    </security-constraint>
  5. このアプリケーションの適切なログイン設定を定義します。

    <login-config>
      <auth-method>BASIC</auth-method>
      <realm-name>jaxrs</realm-name>
    </login-config>

ロールベースのセキュリティーは、定義されたロールとともにアプリケーション内で有効にされています。

例: ロールベースのセキュリティー設定

<web-app>

  <context-param>
    <param-name>resteasy.role.based.security</param-name>
    <param-value>true</param-value>
  </context-param>

  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Resteasy</web-resource-name>
      <url-pattern>/security</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>admin</role-name>
      <role-name>user</role-name>
    </auth-constraint>
  </security-constraint>

  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>jaxrs</realm-name>
  </login-config>

  <security-role>
    <role-name>admin</role-name>
  </security-role>
  <security-role>
    <role-name>user</role-name>
  </security-role>

</web-app>

2.15.2. アノテーションを使用した Jakarta RESTful Web Services Web Services のセキュア化

アノテーションを使用して Jakarta RESTful Web Services Web サービスのセキュリティーを保護するには、以下の手順を実行します。

  1. ロールベースセキュリティーを有効化します
  2. セキュリティーアノテーションを Jakarta RESTful Web Services Web サービスに追加します。RESTEasy は以下のアノテーションをサポートします。

    @RolesAllowed
    メソッドにアクセスできるロールを定義します。すべてのロールは web.xml ファイル で定義する必要があります。
    @PermitAll
    web.xml ファイルに定義されているすべてのロールがメソッドにアクセスできるようにします。
    @DenyAll
    メソッドへのすべてのアクセスを拒否します。

以下の例は、@RolesAllowed アノテーションを使用して admin ロールが Web サービスにアクセスできることを指定します。

@RolesAllowed("admin")
@Path("/test")
public class TestService {
  ...
}

2.15.3. プログラムによるセキュリティーの設定

Jakarta RESTful Web Services には、セキュアな要求に関するセキュリティー情報を収集するためのプログラムによる API が含まれています。javax.ws.rs.core.SecurityContext インターフェイスには、セキュアな HTTP 呼び出しを行うユーザーのアイデンティティーを判断するメソッドがあります。また、現在のユーザーが特定のロールに属するかどうかをチェックすることができるメソッドもあります。

public interface SecurityContext {

   public Principal getUserPrincipal();
   public boolean isUserInRole(String role);
   public boolean isSecure();
   public String getAuthenticationScheme();
}

SecurityContext インスタンスにアクセスするには、@Context アノテーションを使用して、フィールド、セッターメソッド、またはリソースメソッドパラメーターにインジェクトします。

@Path("test")
public class SecurityContextResource {
    @Context
    SecurityContext securityContext;

    @GET
    @Produces("text/plain")
    public String get() {
        if (!securityContext.isUserInRole("admin")) {
            throw new WebApplicationException(Response.serverError().status(HttpResponseCodes.SC_UNAUTHORIZED)
                    .entity("User " + securityContext.getUserPrincipal().getName() + " is not authorized").build());
        }
        return "Good user " + securityContext.getUserPrincipal().getName();
    }
}

2.16. RESTEasy Asynchronous Job Service

RESTEasy Asynchronous Job Service は、HTTP プロトコルに非同期動作を追加するように設計されています。HTTP は同期プロトコルですが、非同期呼び出しを認識します。HTTP 1.1 202 accepted は、サーバーが処理応答を受信し、承認したものの、処理が完了していないことを示します。Asynchronous Job Service はこれに基づいてビルドされます。

2.16.1. 非同期ジョブサービスの有効化

Asynchronous Job Service は web.xml ファイルで有効化します。

<context-param>
    <param-name>resteasy.async.job.service.enabled</param-name>
    <param-value>true</param-value>
</context-param>

2.16.2. 非同期ジョブの設定

このセクションでは、RESTEasy を使用した非同期ジョブのクエリーパラメーターの例について説明します。

警告

ロールベースのセキュリティーは、ポータブルに実装できないため Asynchronous Job Service とは連携しません。Asynchronous Job Service を使用する場合は、代わりに web.xml ファイルでの XML 宣言を使用してアプリケーションセキュリティーを確立する必要があります。

重要

GET、DELETE、および PUT メソッドは非同期的に呼び出すことができますが、これらのメソッドの HTTP 1.1 コントラクトが破損します。これらの呼び出しによってリソースが複数回呼び出されると、その状態が変更されることはありませんが、各呼び出しで新しいジョブエントリーとしてサーバーの状態が変更されます。

asynch クエリーパラメーターは、バックグラウンドで呼び出しを実行するために使用されます。202 Accepted 応答が返されます。また、バックグラウンドメソッドの応答がある場所を指す URL が含まれる場所のヘッダーも返されます。

POST http://example.com/myservice?asynch=true

上記の例では、202 Accepted 応答を返します 。また、バックグラウンドメソッドの応答がある場所を指す URL のある場所のヘッダーも返します。以下は場所ヘッダーの例です。

HTTP/1.1 202 Accepted
Location: http://example.com/asynch/jobs/3332334

URI は以下の形式になります。

/asynch/jobs/{job-id}?wait={milliseconds}|nowait=true

この URL では、GET、POST、および DELETE 操作を実行できます。

  • GET は、ジョブの完了時に応答として呼び出される Jakarta RESTful Web Services リソースメソッドを返します。ジョブが完了していない場合、GET は 202 Accepted 応答コードを返します。GET を呼び出してもジョブは削除されないため、複数回呼び出すことができます。
  • POST はジョブの応答を読み取り、完了するとジョブを削除します。
  • DELETE は、ジョブキューを手動でクリーンアップするために呼び出されます。
注記

ジョブキューが満杯になると、DELETE を呼び出すことなく、メモリーから最も古いジョブを自動的に無効にします。

GET および POST 操作では、wait および nowait クエリーパラメーターを使用して、最大待機時間を定義できます。wait パラメーターが指定されていない場合、操作はデフォルトで nowait=true に設定され、ジョブが完了しない場合には待機しません。wait パラメーターはミリ秒単位で定義されます。

POST http://example.com/asynch/jobs/122?wait=3000

RESTEasy は、一方向のクエリーパラメーターを使用して oneway ジョブの発生と無効化をサポートします。

POST http://example.com/myservice?oneway=true

上記の例では 202 Accepted 応答が返されますが、ジョブは作成されません。

注記

Asynchronous Job Service の設定パラメーターは、付録の RESTEasy Asynchronous Job Service Configuration Parameters のセクションを参照してください。

2.17. RESTEasy JavaScript API

2.17.1. RESTEasy JavaScript API について

RESTEasy は、AJAX 呼び出しを使用して Jakarta RESTful Web Services 操作を呼び出す JavaScript API を生成することができます。各 Jakarta RESTful Web Services リソースクラスは、宣言するクラスまたはインターフェイスと同じ名前を持つ JavaScript オブジェクトを生成します。JavaScript オブジェクトには、プロパティーとして各 Jakarta RESTful Web Services メソッドが含まれます。

@Path("foo")
public class Foo {

  @Path("{id}")
  @GET
  public String get(@QueryParam("order") String order, @HeaderParam("X-Foo") String header,
    @MatrixParam("colour") String colour, @CookieParam("Foo-Cookie") String cookie) {
  }

  @POST
  public void post(String text) {
  }
}

以下の JavaScript コードは、前述の例で生成された Jakarta RESTful Web Services API を使用します。

var text = Foo.get({order: 'desc', 'X-Foo': 'hello', colour: 'blue', 'Foo-Cookie': 123987235444});
Foo.post({$entity: text});

各 JavaScript API メソッドは、任意のオブジェクトを単一のパラメーターとして取得します。ここでの各プロパティーは名前で識別される Cookie、ヘッダー、パス、クエリーまたはフォームパラメーター、または API パラメータープロパティーです。API パラメータープロパティーの詳細は、RESTEasy Javascript API Parameters の付録を参照してください。

2.17.1.1. RESTEasy JavaScript API サーブレットの有効化

RESTEasy JavaScript API はデフォルトで無効にされています。以下の手順に従って、web.xml ファイルを更新して有効にします。

  1. テキストエディターでアプリケーションの web.xml ファイルを開きます。
  2. 以下の設定を web-app タグ内のファイルに追加します。

    <servlet>
        <servlet-name>RESTEasy JSAPI</servlet-name>
        <servlet-class>org.jboss.resteasy.jsapi.JSAPIServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>RESTEasy JSAPI</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

2.17.1.2. ビルド AJAX クエリー

RESTEasy JavaScript API を使用すると、手動で要求を作成することができます。以下にこの動作の例をいくつか示します。

例: RESTEasy JavaScript API クライアントの動作をオーバーライドするために使用される REST オブジェクト

// Change the base URL used by the API:
REST.apiURL = "http://api.service.com";

// log everything in a div element
REST.log = function(text) {
  jQuery("#log-div").append(text);
};

REST オブジェクトには以下の読み書きプロパティーが含まれます。

  • APIURL: デフォルトで Jakarta RESTful Web Services ルート URL に設定されます。要求の作成時にすべての JavaScript クライアント API 機能によって使用されます。
  • log: RESTEasy クライアント API ログを受信するために function(string) に設定します。これは、クライアント API のデバッグ、およびそれらを確認できる場所のログの配置を行う場合に便利です。

例: REST.Request() メソッドを使用したカスタムリクエストの構築

var r = new REST.Request();
r.setURI("http://api.service.com/orders/23/json");
r.setMethod("PUT");
r.setContentType("application/json");
r.setEntity({id: "23"});
r.addMatrixParameter("JSESSIONID", "12309812378123");
r.execute(function(status, request, entity) {
  log("Response is " + status);
});

2.18. リソースメタデータを変更する RESTEasy SPI

JBoss EAP は、ResourceBuilder を使用して作成されるリソースクラスメタデータを編集するための RESTEasy サービスプロバイダーインターフェイス (SPI) を提供します。Jakarta RESTful Web Services デプロイメントを処理する際に、RESTEasy は ResourceBuilder を使用して各 Jakarta RESTful Web Services リソースのメタデータを作成します。このようなメタデータは、特に ResourceClass インターフェイスで org.jboss.resteasy.spi.metadata パッケージのメタデータ SPI を使用して定義されます。

package org.jboss.resteasy.spi.metadata;

public interface ResourceClass
{
  String getPath();

  Class<?> getClazz();

  ResourceConstructor getConstructor();

  FieldParameter[] getFields();

  SetterParameter[] getSetters();

  ResourceMethod[] getResourceMethods();

  ResourceLocator[] getResourceLocators();
}

RESTasy では、ResourceClassProcessor インターフェイスの実装によって、メタデータ生成のカスタマイズが可能になります。以下の例は、この SPI の使用例を示しています。

package org.jboss.resteasy.test.core.spi.resource;

import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.metadata.ResourceClass;
import org.jboss.resteasy.spi.metadata.ResourceClassProcessor;

import javax.ws.rs.ext.Provider;

@Provider
public class ResourceClassProcessorImplementation implements ResourceClassProcessor {

    protected static final Logger logger = Logger.getLogger(ResourceClassProcessorImplementation.class.getName());
@Override
    public ResourceClass process(ResourceClass clazz) {
        logger.info(String.format("ResourceClassProcessorImplementation#process method called on class %s",
                            clazz.getClazz().getSimpleName()));
        String clazzName = clazz.getClazz().getSimpleName();
        if (clazzName.startsWith("ResourceClassProcessorEndPoint")
                || clazzName.equals("ResourceClassProcessorProxy")
                || clazzName.equals("ResourceClassProcessorProxyEndPoint")) {
            return new ResourceClassProcessorClass(clazz);
        }
        return clazz;
    }

ResteasyProviderFactory クラスを使用して保存される新しいプロセッサーは、通常の Jakarta RESTful Web Services アノテーションが付けられたプロバイダーとして解決されます。これにより、リソースメタデータクラスを、以下のようなさまざまな高度なシナリオに使用できるカスタムバージョンでラップできます。

  • 追加リソースメソッドまたはロケーターをリソースに追加。
  • HTTP メソッドの変更
  • @Produces または @Consumes メディアタイプの変更。

2.19. MicroProfile REST クライアント

重要

MicroProfile REST クライアントはテクノロジープレビューとしてのみ提供されます。テクノロジープレビューの機能は、Red Hat の本番環境のサービスレベルアグリーメント (SLA) ではサポートされず、機能的に完全ではないことがあるため、Red Hat は本番環境での使用は推奨しません。テクノロジープレビューの機能は、最新の製品機能をいち早く提供して、開発段階で機能のテストを行いフィードバックを提供していただくことを目的としています。

テクノロジープレビュー機能のサポート範囲は、Red Hat カスタマーポータルの テクノロジープレビュー機能のサポート範囲 を参照してください。

JBoss EAP 7.4 は、HTTP 上で RESTful サービスを呼び出すためにタイプセーフなアプローチを提供するために Jakarta RESTful Web Services 2.1 クライアント API 上に構築される MicroProfile REST クライアント 1.4.x をサポートします。MicroProfile Type Safe REST クライアントは、Java インターフェイスとして定義されます。MicroProfile REST クライアントでは、実行可能コードでクライアントアプリケーションの書き込みを行うことができます。

MicroProfile REST クライアントは以下を有効にします。

  • 直感的構文
  • プロバイダーのプログラムによる登録
  • プロバイダーの宣言的登録
  • ヘッダーの宣言的仕様
  • サーバー上のヘッダーの伝搬
  • ResponseExceptionMapper
  • Jakarta Contexts and Dependency Injection の統合

2.19.1. 直感的構文

MicroProfile REST クライアントは、CORBA、Java Remote Method Invocation (RMI)、JBoss Remoting Project、および RESTEasy にも実装されている分散オブジェクト通信のバージョンを有効にします。たとえば、リソースについて考えてみましょう。

@Path("resource")
public class TestResource {
   @Path("test")
   @GET
   String test() {
      return "test";
   }
 }

TestResource クラスにアクセスする Jakarta RESTful Web Services のネイティブな方法は次のとおりです。

Client client = ClientBuilder.newClient();
String response = client.target("http://localhost:8081/test").request().get(String.class);

ただし、Microprofile REST クライアントは test() メソッドを直接呼び出すことで、より直感的な構文をサポートします。

@Path("resource")
public interface TestResourceIntf {
    @Path("test")
    @GET
    public String test();
}

TestResourceIntf service = RestClientBuilder.newBuilder()
                              .baseUrl(http://localhost:8081/))
                              .build(TestResourceIntf.class);
String s = service.test();

上記の例では、TestResource クラスへの呼び出しは、呼び出し service.test() が示すように TestResourceIntf クラスにより大幅に容易になります。

以下の例は、TestResourceIntf クラスのより詳細なバージョンです。

@Path("resource")
public interface TestResourceIntf2 {
   @Path("test/{path}")mes("text/plain")
   @Produces("text/html")
   @POST
   public String test(@PathParam("path") String path, @QueryParam("query") String query, String entity);
}

service.test("p", "q", "e") メソッドを呼び出すと、以下のような HTTP メッセージが生成されます。

POST /resource/test/p/?query=q HTTP/1.1
Accept: text/html
Content-Type: text/plain
Content-Length: 1

e

2.19.2. プロバイダーのプログラムによる登録

MicroProfile REST クライアントでは、プロバイダーを登録してクライアント環境を設定することもできます。例を以下に示します。

TestResourceIntf service = RestClientBuilder.newBuilder()
                              .baseUrl(http://localhost:8081/))
                              .register(MyClientResponseFilter.class)
                              .register(MyMessageBodyReader.class)
                              .build(TestResourceIntf.class);

2.19.3. プロバイダーの宣言型登録

以下のように org.eclipse.microprofile.rest.client.annotation.RegisterProvider アノテーションをターゲットインターフェイスに追加して、プロバイダーを宣言的に登録することもできます。

@Path("resource")
@RegisterProvider(MyClientResponseFilter.class)
@RegisterProvider(MyMessageBodyReader.class)
public interface TestResourceIntf2 {
   @Path("test/{path}")
   @Consumes("text/plain")
   @Produces("text/html")
   @POST
   public String test(@PathParam("path") String path, @QueryParam("query") String query, String entity);
}

MyClientResponseFilter クラスと MyMessageBodyReader クラスをアノテーションで宣言すると、RestClientBuilder.register() メソッドを呼び出す必要がなくなります。

2.19.4. ヘッダーの宣言的仕様

HTTP リクエストのヘッダーは、以下の方法で指定できます。

  • リソースメソッドパラメーターのいずれかにアノテーションを付けます。
  • org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam アノテーションを宣言で使用。

以下の例では、@HeaderValue アノテーションを持つリソースメソッドパラメーターのいずれかにアノテーションを付け、ヘッダーの設定を示しています。

@POST
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.TEXT_PLAIN)
String contentLang(@HeaderParam(HttpHeaders.CONTENT_LANGUAGE) String contentLanguage, String subject);

以下の例は、org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam アノテーションを使用してヘッダーを設定する例になります。

@POST
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.TEXT_PLAIN)
@ClientHeaderParam(name=HttpHeaders.CONTENT_LANGUAGE, value="{getLanguage}")
String contentLang(String subject);

default String getLanguage() {
   return ...;
}

2.19.5. サーバー上のヘッダーの伝搬

org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory のインスタンスが有効であれば、受信ヘッダーの送信要求に一括転送できます。デフォルトのインスタンス org.eclipse.microprofile.rest.client.ext.DefaultClientHeadersFactoryImpl は、コンマ区切りの設定プロパティー org.eclipse.microprofile.rest.client.propagateHeaders に一覧表示される着信ヘッダーで設定されるマップを返します。ClientHeadersFactory インターフェイスをインスタンス化するルールは次のとおりです。

  • Jakarta RESTful Web Services リクエストのコンテキストで呼び出される ClientHeadersFactory インスタンス は、@Context アノテーションが付けられたフィールドおよびメソッドの注入をサポートする必要があります。
  • Jakarta Contexts and Dependency Injection によって管理される ClientHeadersFactory インスタンスは、適切な Jakarta Contexts and Dependency Injection-managed インスタンスを使用する必要があります。@Inject インジェクションもサポートする必要があります。

org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory インターフェイスは以下のように定義されます。

public interface ClientHeadersFactory {

/**
 * Updates the HTTP headers to send to the remote service. Note that providers
 * on the outbound processing chain could further update the headers.
 *
 * @param incomingHeaders - the map of headers from the inbound Jakarta RESTful Web Services request. This will
 * be an empty map if the associated client interface is not part of a Jakarta RESTful Web Services request.
 * @param clientOutgoingHeaders - the read-only map of header parameters specified on the
 * client interface.
 * @return a map of HTTP headers to merge with the clientOutgoingHeaders to be sent to
 * the remote service.
 */
MultivaluedMap<String, String> update(MultivaluedMap<String, String> incomingHeaders,
                                      MultivaluedMap<String, String> clientOutgoingHeaders);
}

ClientHeadersFactory インターフェイスの詳細は、ClientHeadersFactory Javadoc を参照してください。

2.19.6. ResponseExceptionMapper

org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper クラスは、Jakarta RESTful Web Services で定義される javax.ws.rs.ext.ExceptionMapper クラスのクライアント側の逆です。つまり、ExceptionMapper.toResponse () メソッドは、サーバー側の処理中に出力された Exception クラスを Response に変えるため、ResponseExceptionMapper.toThrowable() メソッドは HTTP エラーステータスとともにクライアント側で受信された Response クラスを Exception クラスに変換します。

ResponseExceptionMapper クラスは、プログラム上または宣言的に登録できます。登録された ResponseExceptionMapper クラスがない場合、デフォルトの ResponseExceptionMapper クラスはステータス >= 400 のレスポンスを WebApplicationException クラスにマップします。

2.19.7. Jakarta Contexts and Dependency Injection の統合

MicroProfile REST クライアントでは、@RegisterRestClient クラスで Jakarta Contexts and Dependency Injection Bean として管理されるインターフェイスにアノテーションを付ける必要があります。以下に例を示します。

@Path("resource")
@RegisterProvider(MyClientResponseFilter.class)
public static class TestResourceImpl {
      @Inject TestDataBase db;

      @Path("test/{path}")
      @Consumes("text/plain")
      @Produces("text/html")
      @POST
      public String test(@PathParam("path") String path, @QueryParam("query")
      String query, String entity) {
         return db.getByName(query);
      }
   }
   @Path("database")
   @RegisterRestClient
   public interface TestDataBase {

      @Path("")
      @POST
      public String getByName(String name);
   }

ここで、MicroProfile REST クライアント実装は TestDataBase クラスサービスのクライアントを作成し、TestResourceImpl クラスによるアクセスを容易にします。ただし、TestDataBase クラス実装へのパスに関する情報は含まれません。この情報は、オプションの @Reg- isterProvider パラメーター baseUri で提供されます。

@Path("database")
@RegisterRestClient(baseUri="https://localhost:8080/webapp")
public interface TestDataBase {
   @Path("")
   @POST
   public String getByName(String name);
}

これは、https://localhost:8080/webappTestDataBase 実装にアクセスできることを示しています。以下のシステム変数を外部に提供することもできます。

<fully qualified name of TestDataBase>/mp-rest/url=<URL>

たとえば、以下は、https://localhost:8080/webapp で com.bluemonkeydiamond.TestDatabase クラスの実装にアクセスできることを示しています。

com.bluemonkeydiamond.TestDatabase/mp-rest/url=https://localhost:8080/webapp

2.20. CompletionStage タイプのサポート

Jakarta RESTful Web Services 2.1 仕様は、@Suspended アノテーションを使用する代わりに CompletionStage を返して非同期リソースメソッドを宣言することをサポートします。

リソースのメソッドがサブスクライブしている CompletionStage を返すと常に、リクエストは一時停止されます。このリクエストは、 CompletionStage が以下の場合にのみ再開されます。

  • 値に解決され、メソッドの戻り値として処理される。
  • エラーケースとして処理され、例外はリソースメソッドによって発生したかのように処理される。

以下は、CompletionStage を使用した非同期処理の例です。

public class SimpleResource
{

   @GET
   @Path("basic")
   @Produces("text/plain")
   public CompletionStage<Response> getBasic() throws Exception
   {
      final CompletableFuture<Response> response = new CompletableFuture<>();
      Thread t = new Thread()
      {
         @Override
         public void run()
         {
            try
            {
               Response jaxrs = Response.ok("basic").type(MediaType.TEXT_PLAIN).build();
               response.complete(jaxrs);
            }
            catch (Exception e)
            {
               response.completeExceptionally(e);
            }
         }
      };
      t.start();
      return response;
   }
}

2.21. 非同期リクエスト処理および反応的戻り値の型の RESTEasy サポートの拡張

重要

RESTEasy サポートの拡張はテクノロジープレビューとしてのみ提供されます。テクノロジープレビューの機能は、Red Hat の本番環境のサービスレベルアグリーメント (SLA) ではサポートされず、機能的に完全ではないことがあるため、Red Hat は本番環境での使用は推奨しません。テクノロジープレビューの機能は、最新の製品機能をいち早く提供して、開発段階で機能のテストを行いフィードバックを提供していただくことを目的としています。

テクノロジープレビュー機能のサポート範囲については、Red Hat カスタマーポータルの テクノロジープレビュー機能のサポート範囲 を参照してください。

2.21.1. プラグ可能なリアクティブタイプ

Jakarta RESTful Web Services 2.1 は、さまざまなリアクティブライブラリーをサポートするために拡張可能です。RESTEasy のオプションのモジュール resteasy-rxJava2 は、以下のリアクティブタイプをサポートします。

  • IO.reactivex.Single: 最も大きな値を保持するため CompletionStage に類似しています。
  • io.reactivex.Flowable: io.reactivex.Publisher を実装します。
  • io.reactivex.Observable: Flowable に似ていますが、バックプレッシャーに対応していないことを除き、ロードを制御するサブスクライバーの機能は、Subscription.request() を呼び出すことでプロデューサーから受信します。

Resteasy-RxJava2 をインポートする場合は、サーバー側でリソースメソッドからこれらのリアクティブタイプを返し、クライアント側でそれを受け取ります。

Resteasy-RxJava2 モジュールは、クライアント側で Singles、Observables、および Flowables にそれぞれアクセスするための以下のクラスをサポートします。

  • org.jboss.resteasy.rxjava2.SingleRxInvoker
  • org.jboss.resteasy.rxjava2.FlowableRxInvoker
  • org.jboss.resteasy.rxjava2.ObservableRxInvoker

2.21.2. 追加のリアクティブクラスの拡張

RESTEasy は、追加のリアクティブクラスの拡張をサポートするフレームワークを実装します。サーバー側では、リソースメソッドが CompletionStage タイプを返すと、RESTEasy は org.jboss.resteasy.core.AsyncResponseConsumer.CompletionStageResponseConsumer クラスを使用してそれにサブスクライブします。CompletionStage が完了すると、CompletionStageResponseConsumer.accept() が呼び出され、結果がクライアントに返されます。

CompletionStage のサポートは RESTEasy に組み込まれています。Single などのクラスにこのサポートを拡張するには、SingleCompletionStage に変換するメカニズムを提供します。resteasy-rxjava2 モジュールでは、org.jboss.resteasy.spi.AsyncResponseProvider<Single<?>> インターフェイスを実装する org.jboss.resteasy.rxjava2.SingleProvider がこのメカニズムを提供します。

public interface AsyncResponseProvider<T> {
   public CompletionStage toCompletionStage(T asyncResponse);
}

SingleProvider では、RESTEasy は Single を取得し CompletionStage に変換して CompletionStageResponseConsumer を使用し、Single の最終的な値を処理できます。同様に、リソースメソッドが Flowable などのストリーミングの反応的なクラスを返す場合、RESTEasy はそのクラスをサブスクライブし、データ要素のストリームを受け取り、クライアントに送信します。AsyncResponseConsumer には複数のサポートクラスがあり、それぞれは異なるストリーミングモードを実装します。

たとえば、AsyncResponseConsumer.AsyncGeneralStreamingSseResponseConsumer は一般的なストリーミングおよび SSE ストリーミングを処理します。サブスクリプションは、org.reactivestreams.Publisher.subscribe() を呼び出すことで行われるため、たとえば FlowablePublisher に変えるメカニズが必要です。つまり、org.jboss.resteasy.spi.AsyncStreamProvider<Flowable> の実装が呼び出されます。これは、AsyncStreamProvider を定義します。

public interface AsyncStreamProvider<T> {
   public Publisher toAsyncStream(T asyncResponse);
}

resteasy-rxjava2 モジュールでは、org.jboss.resteasy.FlowableProvider は、Flowable のメカニズムを提供します。

つまり、サーバー側では、ストリームの AsyncStreamProvider インターフェイスの @Provider アノテーションを宣言するか、単一値の AsyncResponseProvider インターフェイスを宣言して、他の反応的なタイプのサポートを追加できます。これらのインターフェイスには、ストリームの場合には、新しいリアクティブタイプを Publisher に、単一の値の場合には CompletionStage に変換する単一のメソッドがあります。

クライアント側では、Jakarta RESTful Web Services 2.1 は、リアクティブクラスのサポートに 2 つの要件を課します。

  • javax.ws.rs.client.CompletionStageRxInvoker のインターフェイスの実装としての CompletionStage のサポート。
  • 実装するプロバイダーの登録をサポートしていることによる拡張性
public interface RxInvokerProvider<T extends RxInvoker> {
    public boolean isProviderFor(Class<T> clazz);
    public T getRxInvoker(SyncInvoker syncInvoker, ExecutorService executorService);
}

RxInvokerProvider が登録されれば javax.ws.rs.client.Invocation.Builder メソッドを呼び出して RxInvoker をリクエストできます。

public <T extends RxInvoker> T rx(Class<T> clazz);

RxInvoker を使用して、適切な反応的なクラスを返す呼び出しを作成できます。例を以下に示します。

FlowableRxInvoker invoker = client.target(generateURL("/get/string")).request().rx(FlowableRxInvoker.class);
Flowable<String> flowable = (Flowable<String>) invoker.get();

RESTEasy は、RxInvokers の実装に部分的なサポートを提供します。たとえば、上記の SingleProviderorg.jboss.resteasy.spi.AsyncClientResponseProvider<Single<?>> も実装します。ここでは AsyncClientResponseProvider は以下のように定義されます。

public interface AsyncClientResponseProvider<T> {
   public T fromCompletionStage(CompletionStage<?> completionStage);
}

2.21.3. Reactive Clients API

RESTEasy は RxInvoker という新型のインボーカーと、CompletionStageRxInvoker というこの型のデフォルト実装を定義します。CompletionStageRxInvoker は、Java 8 のインターフェイス CompletionStage を実装します。このインターフェイスは、非同期計算の管理専用のメソッドを多数宣言します。

2.21.4. 非同期フィルター

特定のリソースが利用可能になるまでフィルターの実行を一時停止する必要がある場合は、非同期フィルターに変換できます。リクエストを非同期にしても、リソースメソッド宣言や追加のフィルター宣言を変更する必要はありません。

フィルターの実行を非同期にするには、以下をキャストする必要があります。

  • 事前およびポスト要求フィルターの SuspendableContainerRequestContext への ContainerRequestContext
  • 応答フィルターの SuspendableContainerResponseContext への ContainerResponseContext

これらのコンテキストオブジェクトは、suspend() メソッドを呼び出して、現在のフィルターの実行を非同期にすることができます。非同期の場合には、フィルターチェーンは中断され、以下のメソッドのいずれかがコンテキストオブジェクトで呼び出された後にのみ再開されます。

  • abortWith(Response): フィルターチェーンを終了し、指定の Response をクライアントに返します。これは ContainerRequestFilter にのみ適用されます。
  • resume(): 次のフィルターを呼び出して、フィルターチェーンの実行を切り替えます。
  • resume(Throwable): 指定された例外を出力して、フィルターチェーンの実行を中止します。これは、フィルターが同期され、指定の例外が発生したかのように動作します。

2.21.5. プロキシー

プロキシーは、直感的なプログラミング言語をサポートする RESTEasy 拡張で、一般的な Jakarta RESTful Web Services インボーカーコールをアプリケーション固有のインターフェイス呼び出しに置き換えます。プロキシーフレームワークは CompletionStage と RxJava2 タイプの両方、SingleObservableFlowable を含めるように拡張されています。以下の例は、RESTEasy プロキシーがどのように機能するかを表しています。

例 1:

@Path("")
public interface RxCompletionStageResource {

   @GET
   @Path("get/string")
   @Produces(MediaType.TEXT_PLAIN)
   public CompletionStage<String> getString();
}

@Path("")
public class RxCompletionStageResourceImpl {

   @GET
   @Path("get/string")
   @Produces(MediaType.TEXT_PLAIN)
   public CompletionStage<String> getString() { .... }
}

public class RxCompletionStageProxyTest {

   private static ResteasyClient client;
   private static RxCompletionStageResource proxy;

   static {
      client = new ResteasyClientBuilder().build();
      proxy = client.target(generateURL("/")).proxy(RxCompletionStageResource.class);
   }

   @Test
   public void testGet() throws Exception {
      CompletionStage<String> completionStage = proxy.getString();
      Assert.assertEquals("x", completionStage.toCompletableFuture().get());
   }
}

例 2:

public interface Rx2FlowableResource {

   @GET
   @Path("get/string")
   @Produces(MediaType.TEXT_PLAIN)
   @Stream
   public Flowable<String> getFlowable();
}

@Path("")
public class Rx2FlowableResourceImpl {

   @GET
   @Path("get/string")
   @Produces(MediaType.TEXT_PLAIN)
   @Stream
   public Flowable<String> getFlowable() { ... }
}

public class Rx2FlowableProxyTest {

   private static ResteasyClient client;
   private static Rx2FlowableResource proxy;

   static {
      client = new ResteasyClientBuilder().build();
      proxy = client.target(generateURL("/")).proxy(Rx2FlowableResource.class);
   }

   @Test
   public void testGet() throws Exception {
      Flowable<String> flowable = proxy.getFlowable();
      flowable.subscribe(
         (String o) -> stringList.add(o),
         (Throwable t) -> errors.incrementAndGet(),
         () -> latch.countDown());
      boolean waitResult = latch.await(30, TimeUnit.SECONDS);
      Assert.assertTrue("Waiting for event to be delivered has timed out.", waitResult);
      Assert.assertEquals(0, errors.get());
      Assert.assertEquals(xStringList, stringList);
   }
}

第3章 Jakarta XML Web Services の開発

Jakarta XML Web Services は、WSDL と Java 間のマッピングと、Web サービスへのアクセスおよび公開に使用されるクラスを定義します。JBossWS は Jakarta XML Web Services 2.3 を実装します。これは、これは、ユーザーがベンダーに依存しない Web サービスの使用ニーズについて参照できます。

3.1. Jakarta XML Web Services Tools の使用

以下の Jakarta XML Web Services コマンドラインツールは JBoss EAP ディストリビューションに含まれています。これらのツールは、サーバー および クライアント側 の開発にさまざまな方法で使用できます。

表3.1 Jakarta XML Web Services コマンドラインツール

コマンド説明

wsprovide

Jakarta XML Web Services の移植可能なアーティファクトを生成し、抽象コントラクトを提供します。ボトムアップ開発に使用します。

wsconsume

抽象的なコントラクト (WSDL や Schema ファイル) を使用し、サーバーとクライアントの両方に対してアーティファクトを生成します。トップダウンおよびクライアント開発に使用されます。

これらのツールの使用方法は、Jakarta XML Web Services Tools を参照してください。

3.1.1. サーバー側開発ストラテジー

サーバー側で Web サービスエンドポイントを開発する場合、ボトムアップ開発 として知られる Java コードや、トップダウン開発というサービスを定義する WSDL から開始するオプションを利用できます。これが新しいサービスで、既存のコントラクトがない場合、ボトムアップアプローチが最速のルートになります。サービスを稼働させるためには、クラスにアノテーションをいくつか追加する必要があります。ただし、すでに定義されているコントラクトでサービスを開発する場合は、ツールによるアノテーション付きコードの生成を可能にするため、トップダウンアプローチを使用した方がはるかに簡単です。

ボトムアップのユースケース:

  • 既存の Jakarta Enterprise Beans 3 Bean を Web サービスとして公開している。
  • 新規サービスの提供と、コントラクトが生成されるようにする。

トップダウンのユースケース:

  • 既存の Web サービスの実装を置き換え、古いクライアントとの互換性を失うことはできません。
  • サードパーティーが指定したコントラクトに準拠するサービスを公開している (たとえば、定義済みプロトコルを使用して返送するベンダー)。
  • 事前に開発した XML Schema と WSDL に準拠するサービスを作成します。
wsprovide を使用したダウンアップグレードストラテジー

ボトムアップ戦略には、サービスの Java コードを開発し、 Jakarta XML Web Services アノテーションを使用してアノテーションを付けることが関係します。これらのアノテーションを使用して、サービスに生成されるコントラクトをカスタマイズできます。たとえば、操作名を任意のものにマッピングするように変更できます。ただし、すべてのアノテーションには適切なデフォルトがあるため、@WebService アノテーションのみが必要になります。

これは、単一クラスを作成するのと同じように簡単に実行できます。

package echo;

@javax.jws.WebService
public class Echo {

   public String echo(String input) {
      return input;
   }
}

デプロイメントはこのクラスを使用して構築でき、JBossWS にデプロイするために必要な唯一の Java コードです。ラッパークラスと呼ばれるその他の Java アーティファクトは、デプロイ時に生成されます。

wsprovide ツールの主な目的は、移植可能な Jakarta XML Web Services アーティファクトを生成することです。さらに、サービスの WSDL ファイルを提供するのに使用できます。これは、-w オプションを使用して wsprovide を呼び出すことで取得できます。

$ javac -d . Echo.java
$ EAP_HOME/bin/wsprovide.sh --classpath=. -w echo.Echo

アクセスメントを検査すると、EchoService という名前のサービスが表示されます。

<wsdl:service name="EchoService">
  <wsdl:port name="EchoPort" binding="tns:EchoServiceSoapBinding">
    <soap:address location="http://localhost:9090/EchoPort"/>
  </wsdl:port>
</wsdl:service>

予想通りに、このサービスは、echo という操作を定義します。

<wsdl:portType name="Echo">
  <wsdl:operation name="echo">
    <wsdl:input name="echo" message="tns:echo">
    </wsdl:input>
    <wsdl:output name="echoResponse" message="tns:echoResponse">
    </wsdl:output>
  </wsdl:operation>
</wsdl:portType>

デプロイ時に、このツールを実行する必要はありません。これは、移植可能なアーティファクトまたはサービスの抽象的なコントラクトを生成する場合にのみ必要です。

デプロイメントの POJO エンドポイントは、簡単な web.xml ファイルに作成できます。

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">

  <servlet>
    <servlet-name>Echo</servlet-name>
    <servlet-class>echo.Echo</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>Echo</servlet-name>
    <url-pattern>/Echo</url-pattern>
  </servlet-mapping>
</web-app>

web.xml と単一の Java クラスを使用して WAR を作成できます。

$ mkdir -p WEB-INF/classes
$ cp -rp echo WEB-INF/classes/
$ cp web.xml WEB-INF
$ jar cvf echo.war WEB-INF
added manifest
adding: WEB-INF/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/echo/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/echo/Echo.class(in = 340) (out= 247)(deflated 27%)
adding: WEB-INF/web.xml(in = 576) (out= 271)(deflated 52%)

WAR は JBoss EAP にデプロイできます。これにより、内部的に wsprovide が呼び出され、その WSDL が生成されます。デプロイメントに成功し、デフォルト設定を使用している場合は、管理コンソールで利用できるようにする必要があります。

注記

移植可能な Jakarta XML Web Services デプロイメントでは、先に生成されたラッパークラスをデプロイメントに追加することができます。

wsconsume を使用したトップダウンストラテジー

トップダウンの開発ストラテジーは、サービスの抽象的なコントラクトで始まります。これには WSDL ファイルおよびゼロ以上のスキーマファイルが含まれます。wsconsume ツールを使用してこのコントラクトを消費し、アノテーション付きの Java クラスと、それを定義するオプションのプションのソースを生成します。

注記

wsconsume には、Unix システムのシンボリックリンクに問題がある可能性があります。

ボトムアップの例から WSDL ファイルを使用して、このサービスに準拠する新しい Java 実装を生成することができます。-k オプションは wsconsume に渡され、Java クラスのみを提供する代わりに、生成された Java ソースファイルを保存します。

$ EAP_HOME/bin/wsconsume.sh -k EchoService.wsdl

以下の表には、生成される各ファイルの目的をまとめています。

表3.2 生成されるファイル

ファイル目的

Echo.java

サービスエンドポイントインターフェイス

EchoResponse.java

応答メッセージのラッパー Bean

EchoService.java

Jakarta XML Web Services クライアントでのみ使用

Echo_Type.java

要求メッセージのラッパー Bean

ObjectFactory.java

Jakarta XML Binding XML Registry

package-info.java

Jakarta XML Binding パッケージアノテーションのホルダー

サービスエンドポイントインターフェイスを調べると、ボトムアップの例で手動で記述したクラスよりも明示的なアノテーションが表示されますが、これらは同じコントラクトに対して評価されます。

@WebService(targetNamespace = "http://echo/", name = "Echo")
@XmlSeeAlso({ObjectFactory.class})
public interface Echo {

    @WebMethod
    @RequestWrapper(localName = "echo", targetNamespace = "http://echo/", className = "echo.Echo_Type")
    @ResponseWrapper(localName = "echoResponse", targetNamespace = "http://echo/", className = "echo.EchoResponse")
    @WebResult(name = "return", targetNamespace = "")
    public java.lang.String echo(
        @WebParam(name = "arg0", targetNamespace = "")
        java.lang.String arg0
    );
}

パッケージ化以外の不明な部分は実装クラスで、上記のインターフェイスを使用して記述できるようになりました。

package echo;

@javax.jws.WebService(endpointInterface="echo.Echo")
public class EchoImpl implements Echo {
   public String echo(String arg0) {
      return arg0;
   }
}

3.1.2. クライアント側の開発ストラテジー

クライアント側の詳細を確認する前に、Web サービスの中心となる切り離す概念を理解することが重要です。Web サービスは、この方法で使用することもできますが、内部 RPC には適していません。CORBA や RMI などのより優れた技術があります。Web サービスは、特に相互運用可能な粒度の細かい対応のために設計されました。Web サービスの対話に参加しているいかなるパーティも、特定のオペレーティングシステム上で実行したり、特定のプログラミング言語で記述されているといった保証はありません。そのため、クライアントおよびサーバー実装は明確に分離することが重要です。一般的なのは、抽象的なコントラクト定義のみです。何らかの理由でソフトウェアがこの原理に準拠しない場合は、Web サービスを使用しないことをお勧めします。上記の理由により、クライアント開発に推奨される方法は、クライアントが同じサーバーで実行されている場合でもトップダウンアプローチに従うことです。

wsconsume を使用したトップダウンストラテジー

このセクションは、サーバー側のトップダウンセクションのプロセスを繰り返しますが、デプロイ済みの WSDL を使用します。これは、デプロイ時に計算される soap:address の正しい値を取得します (下記参照)。この値は、必要に応じて手動で編集できますが、正しいパスを指定する必要があります。

例: デプロイ済みコンポーネントの soap:address

<wsdl:service name="EchoService">
  <wsdl:port name="EchoPort" binding="tns:EchoServiceSoapBinding">
    <soap:address location="http://localhost.localdomain:8080/echo/Echo"/>
  </wsdl:port>
</wsdl:service>

wsconsume を使用して、デプロイされた WSDL の Java クラスを生成します。

$ EAP_HOME/bin/wsconsume.sh -k http://localhost:8080/echo/Echo?wsdl

EchoService.java クラスが、WSDL が取得元の場所を保存する方法に注目してください。

@WebServiceClient(name = "EchoService",
                  wsdlLocation = "http://localhost:8080/echo/Echo?wsdl",
                  targetNamespace = "http://echo/")
public class EchoService extends Service {

    public final static URL WSDL_LOCATION;

    public final static QName SERVICE = new QName("http://echo/", "EchoService");
    public final static QName EchoPort = new QName("http://echo/", "EchoPort");

    ...

    @WebEndpoint(name = "EchoPort")
    public Echo getEchoPort() {
        return super.getPort(EchoPort, Echo.class);
    }

    @WebEndpoint(name = "EchoPort")
    public Echo getEchoPort(WebServiceFeature... features) {
        return super.getPort(EchoPort, Echo.class, features);
    }
}

ご覧のとおり、この生成されたクラスは Jakarta XML Web Services javax.xml.ws.Service のメインクライアントのエントリーポイントを拡張します。Service を直接使用することはできますが、設定情報を提供するため、これははるかに簡単です。サービスエンドポイントインターフェイスのインスタンスを返す getEchoPort() メソッドに注意してください。返されたインターフェイスでメソッドを呼び出すと、Web サービスの操作をすべて呼び出すことができます。

重要

実稼働環境のアプリケーションで、リモート WSDL URL を参照しないでください。これにより、Service オブジェクトをインスタンス化するたびにネットワーク I/O が発生します。代わりに、保存されたローカルコピーでツールを使用するか、コンストラクターの URL バージョンを使用して、新しい WSDL の場所を提供します。

クライアントの書き込みとコンパイル:

import echo.*;

public class EchoClient {

   public static void main(String args[]) {

      if (args.length != 1) {
          System.err.println("usage: EchoClient <message>");
          System.exit(1);
      }

      EchoService service = new EchoService();
      Echo echo = service.getEchoPort();
      System.out.println("Server said: " + echo.echo(args0));
   }
}

以下のように ENDPOINT_ADDRESS_PROPERTY を設定すると、ランタイム時に操作のエンドポイントアドレスを変更できます。

EchoService service = new EchoService();
Echo echo = service.getEchoPort();

/* Set NEW Endpoint Location */
String endpointURL = "http://NEW_ENDPOINT_URL";
BindingProvider bp = (BindingProvider)echo;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);

System.out.println("Server said: " + echo.echo(args0));

3.2. Jakarta XML Web Services Web Service エンドポイント

3.2.1. Jakarta XML Web Services Web Service エンドポイントについて

Jakarta XML Web Services Web サービスエンドポイントは、Web サービスのサーバーコンポーネントです。クライアントおよび他の Web サービスは、Simple Object Access Protocol (SOAP) と呼ばれる XML 言語を使用して HTTP プロトコルを介して通信します。エンドポイント自体は JBoss EAP コンテナーにデプロイされます。

WSDL 記述子は、以下のいずれかの方法で作成できます。

  • WSDL 記述子の手動書き込み
  • WSDL 記述子を自動的に作成する Jakarta XML Web Services アノテーションの使用。これは、WSDL 記述子を作成するための最も一般的な方法です。

エンドポイント実装 Bean には、Jakarta XML Web Services アノテーションが付けられ、サーバーにデプロイされます。サーバーは、クライアント消費のために、抽象的なコントラクトを自動的に生成し、パブリッシュします。マーシャリングおよびアンマーシャリングはすべて Jakarta XML Binding サービスに委譲されます。

エンドポイント自体は Plain Old Java Object (POJO) または Jakarta EE Web アプリケーションである場合があります。Jakarta Enterprise Beans 3 ステートレスセッション Bean を使用してエンドポイントを公開することもできます。Web アーカイブ (WAR) ファイルにパッケージ化されます。エンドポイントをパッケージ化するための仕様は、Jakarta Web Services Metadata Specification 2.1 で定義されています。

例: POJO エンドポイント

@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class JSEBean {
    @WebMethod
    public String echo(String input) {
        ...
    }
}

例: Web サービスエンドポイント

<web-app ...>
  <servlet>
    <servlet-name>TestService</servlet-name>
    <servlet-class>org.jboss.quickstarts.ws.jaxws.samples.jsr181pojo.JSEBean01</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>TestService</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

以下の Jakarta Enterprise Beans 3 ステートレスセッション Bean は、リモートインターフェイスとエンドポイント操作で同じメソッドを公開します。

@Stateless
@Remote(EJB3RemoteInterface.class)

@WebService

@SOAPBinding(style = SOAPBinding.Style.RPC)
public class EJB3Bean implements EJB3RemoteInterface {
    @WebMethod
    public String echo(String input) {
        ...
    }
}

サービスエンドポイントインターフェイス

Jakarta XML Web Services サービスは通常、Java サービスエンドポイントインターフェイス (SEI) を実装します。これは、直接またはアノテーションを使用して WSDL ポートタイプからマップされる場合があります。この SEI は、Java オブジェクトとその XML 表現の詳細を隠す高度な抽象化を提供します。

エンドポイントプロバイダーインターフェイス

場合によっては、Jakarta XML Web Services サービスに XML メッセージレベルで操作する機能が必要になる場合があります。エンドポイント Provider インターフェイスは、この機能を実装する Web サービスにこの機能を提供します。

エンドポイントの使用およびアクセス

Web サービスをデプロイしたら、WSDL を消費してアプリケーションの基盤となるコンポーネントのスタブを作成できます。その後、アプリケーションはエンドポイントにアクセスしてその作業を実行できます。

3.2.2. Jakarta XML Web Services Web Service エンドポイントの開発およびデプロイ

Jakarta XML Web Services サービスのエンドポイントは、Jakarta XML Web Services クライアントからリクエストに応答し、それ自体の WSDL 定義を公開するするサーバー側のコンポーネントです。

Jakarta XML Web Services エンドポイントアプリケーションの開発方法の実例は、JBoss EAP に同梱される以下のクイックスタートを参照してください。

  • jaxws-addressing
  • jaxws-ejb
  • jaxws-pojo
  • jaxws-retail
  • wsat-simple
  • wsba-coordinator-completion-simple
  • wsba-participant-completion-simple

開発要件

Web サービスは、Jakarta XML Web Services API および Jakarta Web Services Metadata Specification 2.1 仕様の要件を満たす必要があります。

  • これには javax.jws.WebService アノテーションが含まれます。
  • すべてのメソッドパラメーターおよび戻り値タイプは、Jakarta XML Binding 2.3 仕様 と互換性があります。

これらの要件を満たす Web サービス実装の例を以下に示します。

例: Web サービス実装

package org.jboss.quickstarts.ws.jaxws.samples.retail.profile;

import javax.ejb.Stateless;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.soap.SOAPBinding;

@Stateless

@WebService(
    name = "ProfileMgmt",
    targetNamespace = "http://org.jboss.ws/samples/retail/profile",
    serviceName = "ProfileMgmtService")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public class ProfileMgmtBean {
    @WebMethod
    public DiscountResponse getCustomerDiscount(DiscountRequest request) {
        DiscountResponse dResponse = new DiscountResponse();
        dResponse.setCustomer(request.getCustomer());
        dResponse.setDiscount(10.00);
        return dResponse;
    }
}

以下は、ProfileMgmtBean bean によって DiscountRequest の例です。アノテーションは詳細度のために含まれています。通常、Jakarta XML Binding のデフォルト値は妥当であり、指定する必要はありません。

例: DiscountRequest クラス

package org.jboss.test.ws.jaxws.samples.retail.profile;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

import org.jboss.test.ws.jaxws.samples.retail.Customer;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(
  name = "discountRequest",
  namespace="http://org.jboss.ws/samples/retail/profile",
  propOrder = { "customer" }
)
public class DiscountRequest {

   protected Customer customer;

   public DiscountRequest() {
   }

   public DiscountRequest(Customer customer) {
      this.customer = customer;
   }

   public Customer getCustomer() {
      return customer;
   }

   public void setCustomer(Customer value) {
      this.customer = value;
   }

}

デプロイメントのパッケージ化

実装クラスは JAR デプロイメントでラップされます。デプロイメントに必要なメタデータは、実装クラスとサービスエンドポイントインターフェイス上のアノテーションから取得されます。管理 CLI または管理コンソールを使用して JAR をデプロイでき、HTTP エンドポイントが自動的に作成されます。

以下のリストは、Jakarta Enterprise Beans Web サービスの JAR デプロイメントの構造例を示しています。

$ jar -tf jaxws-samples-retail.jar
org/jboss/test/ws/jaxws/samples/retail/profile/DiscountRequest.class
org/jboss/test/ws/jaxws/samples/retail/profile/DiscountResponse.class
org/jboss/test/ws/jaxws/samples/retail/profile/ObjectFactory.class
org/jboss/test/ws/jaxws/samples/retail/profile/ProfileMgmt.class
org/jboss/test/ws/jaxws/samples/retail/profile/ProfileMgmtBean.class
org/jboss/test/ws/jaxws/samples/retail/profile/ProfileMgmtService.class
org/jboss/test/ws/jaxws/samples/retail/profile/package-info.class

3.3. Jakarta XML Web Services Web サービスクライアント

3.3.1. Jakarta XML Web Services Web サービスの消費およびアクセス

手動または Jakarta XML Web Services アノテーションを使用して Web サービスのエンドポイントを作成した後に、その WSDL にアクセスできます。これは、Web サービスと通信する基本的なクライアントアプリケーションを作成するのに使用できます。パブリッシュされた WSDL から Java コードを生成するプロセスは、Web サービスを使用すると呼ばれます。これは以下の場合に発生します。

クライアントアーティファクトの作成

クライアントアーティファクトを作成する前に、WSDL コントラクトを作成する必要があります。以下の WSDL コントラクトは、本セクションの残りの部分に記載の例に使用します。

以下の例は、ProfileMgmtService.wsdl ファイルにこの WSDL コントラクトがあることを前提としています。

<definitions
    name='ProfileMgmtService'
    targetNamespace='http://org.jboss.ws/samples/retail/profile'
    xmlns='http://schemas.xmlsoap.org/wsdl/'
    xmlns:ns1='http://org.jboss.ws/samples/retail'
    xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
    xmlns:tns='http://org.jboss.ws/samples/retail/profile'
    xmlns:xsd='http://www.w3.org/2001/XMLSchema'>

   <types>

      <xs:schema targetNamespace='http://org.jboss.ws/samples/retail'
                 version='1.0' xmlns:xs='http://www.w3.org/2001/XMLSchema'>
         <xs:complexType name='customer'>
            <xs:sequence>
               <xs:element minOccurs='0' name='creditCardDetails' type='xs:string'/>
               <xs:element minOccurs='0' name='firstName' type='xs:string'/>
               <xs:element minOccurs='0' name='lastName' type='xs:string'/>
            </xs:sequence>
         </xs:complexType>
      </xs:schema>

      <xs:schema
          targetNamespace='http://org.jboss.ws/samples/retail/profile'
          version='1.0'
          xmlns:ns1='http://org.jboss.ws/samples/retail'
          xmlns:tns='http://org.jboss.ws/samples/retail/profile'
          xmlns:xs='http://www.w3.org/2001/XMLSchema'>

         <xs:import namespace='http://org.jboss.ws/samples/retail'/>
         <xs:element name='getCustomerDiscount'
                     nillable='true' type='tns:discountRequest'/>
         <xs:element name='getCustomerDiscountResponse'
                     nillable='true' type='tns:discountResponse'/>
         <xs:complexType name='discountRequest'>
            <xs:sequence>
               <xs:element minOccurs='0' name='customer' type='ns1:customer'/>

            </xs:sequence>
         </xs:complexType>
         <xs:complexType name='discountResponse'>
            <xs:sequence>
               <xs:element minOccurs='0' name='customer' type='ns1:customer'/>
               <xs:element name='discount' type='xs:double'/>
            </xs:sequence>
         </xs:complexType>
      </xs:schema>

   </types>

   <message name='ProfileMgmt_getCustomerDiscount'>
      <part element='tns:getCustomerDiscount' name='getCustomerDiscount'/>
   </message>
   <message name='ProfileMgmt_getCustomerDiscountResponse'>
      <part element='tns:getCustomerDiscountResponse'
            name='getCustomerDiscountResponse'/>
   </message>
   <portType name='ProfileMgmt'>
      <operation name='getCustomerDiscount'
                 parameterOrder='getCustomerDiscount'>

         <input message='tns:ProfileMgmt_getCustomerDiscount'/>
         <output message='tns:ProfileMgmt_getCustomerDiscountResponse'/>
      </operation>
   </portType>
   <binding name='ProfileMgmtBinding' type='tns:ProfileMgmt'>
      <soap:binding style='document'
                    transport='http://schemas.xmlsoap.org/soap/http'/>
      <operation name='getCustomerDiscount'>
         <soap:operation soapAction=''/>
         <input>

            <soap:body use='literal'/>
         </input>
         <output>
            <soap:body use='literal'/>
         </output>
      </operation>
   </binding>
   <service name='ProfileMgmtService'>
      <port binding='tns:ProfileMgmtBinding' name='ProfileMgmtPort'>

         <!-- service address will be rewritten to actual one when WSDL is requested from running server -->
         <soap:address location='http://SERVER:PORT/jaxws-retail/ProfileMgmtBean'/>
      </port>
   </service>
</definitions>
注記

Jakarta XML Web Services アノテーションを使用して Web サービスエンドポイントを作成する場合、WSDL コントラクトは自動的に生成され、その URL のみが必要になります。この URL を見つけるには、Runtime に移動して、該当するサーバーを選択し、Webservicesを 選択してエンドポイントを選択します。

Wsconsume.sh ツールまたは wsconsume.bat ツールは、抽象的なコントラクト (WSDL) を消費し、アノテーション付きの Java クラスと、これを定義するオプションのソースを生成するために使用されます。このファイルは EAP_HOME/bin/ ディレクトリーにあります。

$ ./wsconsume.sh --help
WSConsumeTask is a cmd line tool that generates portable JAX-WS artifacts from a WSDL file.

usage: org.jboss.ws.tools.cmd.WSConsume [options] <wsdl-url>

options:
    -h, --help                  Show this help message
    -b, --binding=<file>        One or more JAX-WS or Java XML Binding files
    -k, --keep                  Keep/Generate Java source
    -c  --catalog=<file>        Oasis XML Catalog file for entity resolution
    -p  --package=<name>        The target package for generated source
    -w  --wsdlLocation=<loc>    Value to use for @WebService.wsdlLocation
    -o, --output=<directory>    The directory to put generated artifacts
    -s, --source=<directory>    The directory to put Java source
    -t, --target=<2.0|2.1|2.2>  The JAX-WS target
    -q, --quiet                 Be somewhat more quiet
    -v, --verbose               Show full exception stack traces
    -l, --load-consumer         Load the consumer and exit (debug utility)
    -e, --extension             Enable SOAP 1.2 binding extension
    -a, --additionalHeaders     Enable processing of implicit SOAP headers
    -n, --nocompile             Do not compile generated sources

以下のコマンドは、出力に一覧表示されている .java ファイルを ProfileMgmtService.wsdl ファイルから生成します。ソースは、-p スイッチで指定されたパッケージのディレクトリー構造を使用します。

[user@host bin]$ wsconsume.sh -k -p org.jboss.test.ws.jaxws.samples.retail.profile ProfileMgmtService.wsdl
output/org/jboss/test/ws/jaxws/samples/retail/profile/Customer.java
output/org/jboss/test/ws/jaxws/samples/retail/profile/DiscountRequest.java
output/org/jboss/test/ws/jaxws/samples/retail/profile/DiscountResponse.java
output/org/jboss/test/ws/jaxws/samples/retail/profile/ObjectFactory.java
output/org/jboss/test/ws/jaxws/samples/retail/profile/ProfileMgmt.java
output/org/jboss/test/ws/jaxws/samples/retail/profile/ProfileMgmtService.java
output/org/jboss/test/ws/jaxws/samples/retail/profile/package-info.java
output/org/jboss/test/ws/jaxws/samples/retail/profile/Customer.class
output/org/jboss/test/ws/jaxws/samples/retail/profile/DiscountRequest.class
output/org/jboss/test/ws/jaxws/samples/retail/profile/DiscountResponse.class
output/org/jboss/test/ws/jaxws/samples/retail/profile/ObjectFactory.class
output/org/jboss/test/ws/jaxws/samples/retail/profile/ProfileMgmt.class
output/org/jboss/test/ws/jaxws/samples/retail/profile/ProfileMgmtService.class
output/org/jboss/test/ws/jaxws/samples/retail/profile/package-info.class

.java ソースファイルとコンパイルされた .class ファイルはどちらも、コマンドを実行するディレクトリー内の output/ ディレクトリーに生成されます。

表3.3 wsconsume.sh で作成されるアーティファクトの説明

ファイル説明

ProfileMgmt.java

サービスエンドポイントインターフェイス。

Customer.java

カスタムデータタイプ。

Discount.java

カスタムデータタイプ。

ObjectFactory.java

Jakarta XML Binding XML レジストリー。

package-info.java

Jakarta XML Binding パッケージアノテーション。

ProfileMgmtService.java

サービスファクトリー。

wsconsume コマンドは、すべてのカスタムデータタイプ (Jakarta XML Binding アノテーションが付けられたクラス)、サービスエンドポイントインターフェイス、およびサービスファクトリークラスを生成します。これらのアーティファクトは、Web サービスクライアントの実装をビルドするために使用されます。

サービススタブの設定

Web サービスクライアントはサービススタブを使用して、リモート Web サービス呼び出しの詳細を抽象化します。クライアントアプリケーションの場合、Web サービスの呼び出しは他のビジネスコンポーネントの呼び出しと同様になります。この場合、サービスエンドポイントインターフェイスはビジネスインターフェイスとして機能し、サービスファクトリークラスはサービススタブとしての構築に使用されません。

以下の例では、まずは WSDL の場所とサービス名を使用してサービスファクトリーを作成します。次に、 wsconsume により作成されたサービスエンドポイントインターフェイスを使用してサービススタブを構築します。最後に、スタブは他のビジネスインターフェイスと同様に使用できます。

JBoss EAP 管理コンソールでは、エンドポイントの WSDL URL を確認できます。この URL を見つけるには、Runtime に移動して、該当するサーバーを選択し、Webservicesを 選択してエンドポイントを選択します。

import javax.xml.ws.Service;
[...]
Service service = Service.create(
new URL("http://example.org/service?wsdl"),
new QName("MyService")
);
ProfileMgmt profileMgmt = service.getPort(ProfileMgmt.class);

// Use the service stub in your application

3.3.2. Jakarta XML Web Services クライアントアプリケーションの開発

クライアントは Java Enterprise Edition 7 コンテナーにデプロイされる Jakarta XML Web Services エンドポイントと通信し、そのエンドポイントから作業を要求します。以下のクラス、メソッド、およびその他の実装の詳細は、JBoss EAP に含まれる Javadocs バンドルの関連セクションを参照してください。

概要

Service は、WSDL サービスを表す抽象化です。WSDL サービスは、一連の関連ポートです。それぞれには、特定のプロトコルとエンドポイントアドレスに結合したポートタイプが含まれます。

通常、サービスの生成は、残りのコンポーネントのスタブが、既存の WSDL コントラクトから生成されると行われます。WSDL コントラクトは、デプロイされたエンドポイントの WSDL URL 経由で利用できます。または、EAP_HOME/bin/ ディレクトリーの wsprovide ツールを使用してエンドポイントソースから作成できます。

このタイプの使用は、静的なユースケースと呼ばれます。この場合、コンポーネントのスタブのいずれかとして作成された Service クラスのインスタンスを作成します。

Service.create メソッドを使用してサービスを手動で作成することもできます。これは、動的なユースケースと呼ばれます。

使用方法
静的ユースケース

Jakarta XML Web Services クライアントの静的ユースケースでは、WSDL コントラクトがすでにあることを前提としています。これは外部ツールで生成されるか、Jakarta XML Web Services エンドポイントの作成時に正しい Jakarta XML Web Services アノテーションを使用して生成される可能性があります。

コンポーネントのスタブを生成するには、EAP_HOME/bin に含まれる wsconsume ツールを使用します。このツールは、コンテナー URL またはファイルをパラメーターとして取り、ディレクトリーツリーで構造化された複数のファイルを生成します。Service を表すソースおよびクラスファイルはそれぞれ _Service.java_Service.class です。

生成された実装クラスには、引数のないパブリックコンストラクターと、2 つの引数を持つコンストラクターがあります。これら 2 つの引数はそれぞれ WSDL の場所 (java.net.URL) とサービス名 (javax.xml.namespace.QName) を表します。

引数なしのコンストラクターは最もよく使用されます。この場合、WSDL の場所とサービス名は WSDL にあるものです。これらは、生成されたクラスをデコレートする @WebServiceClient アノテーションから暗黙的に設定されます。

@WebServiceClient(name="StockQuoteService", targetNamespace="http://example.com/stocks", wsdlLocation="http://example.com/stocks.wsdl")
public class StockQuoteService extends javax.xml.ws.Service
{
   public StockQuoteService() {
      super(new URL("http://example.com/stocks.wsdl"), new QName("http://example.com/stocks", "StockQuoteService"));
   }

   public StockQuoteService(String wsdlLocation, QName serviceName) {
      super(wsdlLocation, serviceName);
   }
   ...
}

サービスからポートを取得する方法と、ポートでの操作の呼び出し方法に関する詳細は、Dynamic Proxy を参照してください。XML ペイロードを直接使用するか、SOAP メッセージ全体の XML 表現を使用する方法は、Dispatch を参照してください。

動的ユースケース

動的の場合、スタブは自動的に生成されません。代わりに、Web サービスクライアントは Service.create メソッドを使用して Service インスタンスを作成します。以下のコードはこのプロセスを示しています。

URL wsdlLocation = new URL("http://example.org/my.wsdl");
QName serviceName = new QName("http://example.org/sample", "MyService");
Service service = Service.create(wsdlLocation, serviceName);
ハンドラー解決

Jakarta XML Web Services は、ハンドラーと呼ばれるメッセージ処理モジュールの柔軟なプラグインフレームワークを提供します。これらのハンドラーは Jakarta XML Web Services ランタイムシステムの機能を拡張します。Service インスタンスは、getHandlerResolversetHandlerResolver メソッドのペア経由で HandlerResolver へのアクセスを提供し、サービス別、ポート別、またはプロトコル別のバインディングベースでハンドラーのセットを設定することができます。

Service インスタンスでプロキシーまたは Dispatch インスタンスを作成すると、現在サービスに登録されているハンドラーリゾルバーが必要なハンドラーチェーンを作成します。Service インスタンスに設定されたハンドラーリゾルバーへの変更は、以前に作成されたプロキシーまたは Dispatch インスタンスでのハンドラーには影響を与えません。

Executor

Service インスタンスは、java.util.concurrent.Executor を使用して設定できます。Executor は、アプリケーションによってリクエストされた非同期コールバックを呼び出します。ServicesetExecutor および getExecutor メソッドは、サービスに設定された Executor を変更および取得できます。

動的プロキシー

動的プロキシーは、Service で提供される getPort メソッドのいずれかを使用するクライアントプロキシーのインスタンスです。portName は、サービスが使用する WSDL ポートの名前を指定します。serviceEndpointInterface は、作成された動的プロキシーインスタンスでサポートされるサービスエンドポイントインターフェイスを指定します。

public <T> T getPort(QName portName, Class<T> serviceEndpointInterface)
public <T> T getPort(Class<T> serviceEndpointInterface)

Service Endpoint Interface は通常 wsconsume ツールを使用して生成されます。これは、WSDL を解析し、そこから Java クラスを作成します。

ポートを返す、タイプ指定されたメソッドも提供されます。これらのメソッドは、SEI を実装する動的プロキシーも返します。以下の例を参照してください。

@WebServiceClient(name = "TestEndpointService", targetNamespace = "http://org.jboss.ws/wsref",
   wsdlLocation = "http://localhost.localdomain:8080/jaxws-samples-webserviceref?wsdl")

public class TestEndpointService extends Service {
    ...

    public TestEndpointService(URL wsdlLocation, QName serviceName) {
        super(wsdlLocation, serviceName);
    }

    @WebEndpoint(name = "TestEndpointPort")
    public TestEndpoint getTestEndpointPort() {
        return (TestEndpoint)super.getPort(TESTENDPOINTPORT, TestEndpoint.class);
    }
}
@WebServiceRef

@WebServiceRef アノテーションは Web サービスへの参照を宣言します。これは、JSR 250 で定義された javax.annotation.Resource アノテーションによって示されるリソースパターンに従います。これらのアノテーションの Jakarta EE と同等の Jakarta EE は、Jakarta Annotations 1.3 仕様 に含まれています。

  • これを使用して、生成される Service クラスであるタイプのリファンレスを定義できます。この例では、type および value 要素はそれぞれ、生成された Service クラスターイプを参照します。さらに、リファンレンスタイプがアノテーションが適用されるフィールドまたはメソッド宣言によって推定される場合、type および value 要素にはデフォルト値の Object.class が設定されることがあります。これは必須ではありません。タイプを推定できない場合、type 要素がデフォルト以外の値を持つ必要があります。
  • これは、タイプが SEI のリファンレスを定義するのに使用できます。この場合、リファレンスのタイプが annotated フィールドまたは method 宣言から推測される場合、type 要素はデフォルト値で存在することがあります (ただし、必須ではありません)。ただし、value 要素は常に存在し、javax.xml.ws.Service ファイルのサブタイプである、生成されたサービスクラスターイプを参照する必要があります。wsdlLocation 要素が存在する場合は、参照される生成サービスクラスの @WebService アノテーションで指定された WSDL の場所情報を上書きします。

    public class EJB3Client implements EJB3Remote
    {
       @WebServiceRef
       public TestEndpointService service4;
    
       @WebServiceRef
       public TestEndpoint port3;
     }
Dispatch

XML Web サービスは、Jakarta EE コンテナーおよびすべてのクライアントにデプロイされる、エンドポイント間の通信に XML メッセージを使用します。XML メッセージは、Simple Object Access Protocol (SOAP) と呼ばれる XML 言語を使用します。Jakarta XML Web Services API は、SOAP メッセージを送受信できるエンドポイントおよびクライアントのメカニズムを提供します。マーシャリングは、Java オブジェクトを SOAP XML メッセージに変換するプロセスです。マーシャリング解除とは、SOAP XML メッセージを Java オブジェクトに変換するプロセスのことです。

変換の結果ではなく、raw SOAP メッセージ自体にアクセスする必要がある場合があります。Dispatch クラスはこの機能を提供します。Dispatch は、以下の定数のいずれかによって識別される、2 つの使用モードのいずれかで動作します。

  • javax.xml.ws.Service.Mode.MESSAGE: このモードは、クライアントアプリケーションがプロトコル固有のメッセージ構造で直接動作するようにします。SOAP プロトコルバインディングを使用すると、クライアントアプリケーションは SOAP メッセージで直接機能します。
  • javax.xml.ws.Service.Mode.PAYLOAD: このモードでは、クライアントがペイロード自体と動作します。たとえば、SOAP プロトコルバインディングと使用すると、クライアントアプリケーションは SOAP メッセージ全体ではなく SOAP ボディーのコンテンツで動作します。

Dispatch は低レベルの API で、クライアントはメッセージまたはペイロードを XML として設定する必要があります。これは、個別のプロトコルの標準と、メッセージまたはペイロード構造の詳細な知識とメッセージに忠実に従った状態を意味します。Dispatch は、メッセージの入出力または、任意のタイプのメッセージペイロードに対応した汎用クラスです。

Service service = Service.create(wsdlURL, serviceName);
Dispatch dispatch = service.createDispatch(portName, StreamSource.class, Mode.PAYLOAD);

String payload = "<ns1:ping xmlns:ns1='http://oneway.samples.jaxws.ws.test.jboss.org/'/>";
dispatch.invokeOneWay(new StreamSource(new StringReader(payload)));

payload = "<ns1:feedback xmlns:ns1='http://oneway.samples.jaxws.ws.test.jboss.org/'/>";
Source retObj = (Source)dispatch.invoke(new StreamSource(new StringReader(payload)));
非同期呼び出し

BindingProvider インターフェイスは、クライアントが使用できるプロトコルバインディングを提供するコンポーネントを表します。これはプロキシーによって実装され、Dispatch インターフェイスによって拡張されます。

BindingProvider インスタンスは非同期操作機能を提供する可能性があります。非同期操作の呼び出しは、呼び出し時に BindingProvider インスタンスから切り離されます。操作が完了しても、応答コンテキストは更新されません。代わりに、Response インターフェイスを使用して個別の応答コンテキストを利用できます。

public void testInvokeAsync() throws Exception {
   URL wsdlURL = new URL("http://" + getServerHost() + ":8080/jaxws-samples-asynchronous?wsdl");
   QName serviceName = new QName(targetNS, "TestEndpointService");
   Service service = Service.create(wsdlURL, serviceName);
   TestEndpoint port = service.getPort(TestEndpoint.class);
   Response response = port.echoAsync("Async");
   // access future
   String retStr = (String) response.get();
   assertEquals("Async", retStr);
}
@oneway 呼び出し

@oneway アノテーションは、指定の web メソッドが入力メッセージを取得し、出力メッセージを返しないことを示します。通常、@Oneway メソッドは、ビジネスメソッドの実行前に、制御のスレッドを呼び出しアプリケーションに戻します。

@WebService (name="PingEndpoint")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class PingEndpointImpl {
   private static String feedback;

   @WebMethod
   @Oneway
   public void ping() {
      log.info("ping");
      feedback = "ok";
   }

   @WebMethod
   public String feedback() {
      log.info("feedback");
      return feedback;
   }
}
タイムアウトの設定

2 種類のプロパティーが HTTP 接続のタイムアウトの動作と、メッセージの受信を待機しているクライアントのタイムアウトを制御します。最初のプロパティーは、javax.xml.ws.client.connectionTimeout で、次のプロパティーは、javax.xml.ws.client.receiveTimeout です。それぞれはミリ秒単位で示され、正しい構文を以下に示します。

public void testConfigureTimeout() throws Exception {
   //Set timeout until a connection is established
   ((BindingProvider)port).getRequestContext().put("javax.xml.ws.client.connectionTimeout", "6000");

   //Set timeout until the response is received
   ((BindingProvider) port).getRequestContext().put("javax.xml.ws.client.receiveTimeout", "1000");

   port.echo("testTimeout");
}

3.4. Web Services サブシステムの設定

JBossWS コンポーネントは Web サービスエンドポイントの処理を処理し、webservices サブシステムを介して JBoss EAP に提供されます。サブシステムは、パブリッシュされたエンドポイントアドレスおよびエンドポイントハンドラーチェーンの設定をサポートします。

デフォルトの webservices サブシステムはサーバーのドメインおよびスタンドアロン設定ファイルで提供されます。これには、事前定義されたエンドポイントおよびクライアント設定が複数含まれます。

<subsystem xmlns="urn:jboss:domain:webservices:2.0">
  <wsdl-host>${jboss.bind.address:127.0.0.1}</wsdl-host>
  <endpoint-config name="Standard-Endpoint-Config"/>
  <endpoint-config name="Recording-Endpoint-Config">
    <pre-handler-chain name="recording-handlers" protocol-bindings="##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM">
      <handler name="RecordingHandler" class="org.jboss.ws.common.invocation.RecordingServerHandler"/>
    </pre-handler-chain>
  </endpoint-config>
  <client-config name="Standard-Client-Config"/>
</subsystem>

3.4.1. エンドポイント設定

JBossWS では、追加の設定データを事前定義し、エンドポイント実装に関連付けることができます。事前定義されたエンドポイント設定は、Jakarta XML Web Services クライアントと Jakarta XML Web Services エンドポイントの設定に使用できます。エンドポイント設定には、Jakarta XML Web Services ハンドラーおよびキー/バリュープロパティー宣言を含めることができます。この機能は、ハンドラーを Web サービスのエンドポイントに追加し、JBossWS および Apache CXF 内部を制御する key/value プロパティーを設定する便利な方法を提供します。

webservices サブシステムを使用すると、エンドポイント設定データの名前付きセットを定義できます。各エンドポイント設定にはサブシステム内で一意な名前を付ける必要があります。その後、org.jboss.ws.api.annotation.EndpointConfig アノテーションを使用して、デプロイされたアプリケーションの Jakarta XML Web Services 実装にエンドポイント設定を割り当てることができます。エンドポイント設定の割り当ての詳細は、Assigning a Configuration を参照してください。

デフォルトの JBoss EAP 設定には、事前定義されたエンドポイント設定があります。

  • Standard-Endpoint-Config は、明示的に割り当てられたエンドポイント設定のないエンドポイントに使用されるエンドポイント設定です。
  • Recording-Endpoint-Config は、録画ハンドラーを含むカスタムエンドポイント設定の例になります。
エンドポイント設定の追加

管理 CLI を使用して新しいエンドポイント設定を追加できます。

/subsystem=webservices/endpoint-config=My-Endpoint-Config:add
エンドポイント設定の設定

管理 CLI を使用してエンドポイント設定の key/value プロパティー宣言を追加できます。

/subsystem=webservices/endpoint-config=Standard-Endpoint-Config/property=PROPERTY_NAME:add(value=PROPERTY_VALUE)

これらのエンドポイント設定の handler chains および handlers を設定できます。

エンドポイント設定の削除

管理 CLI を使用してエンドポイント設定を削除できます。

/subsystem=webservices/endpoint-config=My-Endpoint-Config:remove

3.4.2. ハンドラーチェーン

各エンドポイント設定は PRE または POST ハンドラーチェーンに関連付けることができます。各ハンドラーチェーンにはメッセージに対して追加の処理を実行するための Jakarta XML Web Services 準拠のハンドラーが含まれることがあります。アウトバウンドメッセージの場合、PRE ハンドラーチェーンハンドラーは、@HandlerChain アノテーションなどの標準の Jakarta XML Web Services の手段を使用してエンドポイントにアタッチされたハンドラーの前に実行されます。POST ハンドラーチェーンハンドラーは、通常のエンドポイントハンドラーの後に実行されます。受信メッセージには、逆が適用されます。

サーバーアウトバウンドメッセージ

Endpoint --> PRE Handlers --> Endpoint Handlers --> POST Handlers --> ... --> Client

サーバーインバウンドメッセージ

Client --> ... --> POST Handlers --> Endpoint Handlers --> PRE Handlers --> Endpoint

ハンドラーチェーンの追加

以下の管理 CLI コマンドを使用すると、POST ハンドラーチェーンをエンドポイント設定に追加できます。

/subsystem=webservices/endpoint-config=My-Endpoint-Config/post-handler-chain=my-post-handler-chain:add

以下の管理 CLI コマンドを使用すると、PRE ハンドラーチェーンをエンドポイント設定に追加できます。

/subsystem=webservices/endpoint-config=My-Endpoint-Config/pre-handler-chain=my-pre-handler-chain:add
ハンドラーチェーンの設定

protocol-bindings 属性を使用して、ハンドラーチェーンの開始をトリガーするプロトコルを設定します。

/subsystem=webservices/endpoint-config=My-Endpoint-Config/post-handler-chain=my-post-handler-chain:write-attribute(name=protocol-bindings,value=##SOAP11_HTTP)

ハンドラーチェーンのハンドラーの設定に関する詳細は、ハンドラー のセクションを参照してください。

ハンドラーチェーンの削除

管理 CLI を使用してハンドラーチェーンを削除できます。

/subsystem=webservices/endpoint-config=My-Endpoint-Config/post-handler-chain=my-post-handler-chain:remove

3.4.3. ハンドラー

Jakarta XML Web Services ハンドラーはハンドラーチェーンに追加され、ハンドラークラスの完全修飾名を指定します。エンドポイントがデプロイされると、参照デプロイメントごとにそのクラスのインスタンスが作成されます。org.jboss.as.webservices.server.integration モジュールのデプロイメントクラスローダーまたはクラスローダーのいずれかがハンドラークラスをロードできる必要があります。

利用可能な ハンドラーのリストは、HandlerJavadocs を参照してください。

ハンドラーの追加

以下の管理 CLI コマンドを使用するとハンドラーをハンドラーチェーンに追加できます。ハンドラーのクラス名を指定する必要があります。

/subsystem=webservices/endpoint-config=My-Endpoint-Config/post-handler-chain=my-post-handler-chain/handler=my-handler:add(class="com.arjuna.webservices11.wsarj.handler.InstanceIdentifierInHandler")
ハンドラーの設定

管理 CLI を使用してハンドラーのクラスを更新できます。

/subsystem=webservices/endpoint-config=My-Endpoint-Config/post-handler-chain=my-post-handler-chain/handler=my-handler:add(class="org.jboss.ws.common.invocation.RecordingServerHandler")
ハンドラーの削除

管理 CLI を使用してハンドラーを削除できます。

/subsystem=webservices/endpoint-config=My-Endpoint-Config/post-handler-chain=my-post-handler-chain/handler=my-handler:

3.4.4. 公開されたエンドポイントアドレス

WSDL コントラクトで公開されるエンドポイントの <soap:address> 要素の書き換えがサポートされます。この機能は、各エンドポイントのクライアントに公開されるサーバーアドレスを制御するのに役立ちます。

以下の表は、この機能に設定できる属性を表しています。

名前説明

modify-wsdl-address

このブール値は、アドレスのリライト機能を有効化・無効化します。

modify-wsdl-addresstrue に設定され、<soap:address> の内容が有効な URL の場合、JBossWS は wsdl-host および wsdl-port または wsdl-secure-port の値を使用して URL を再書き込みします。

modify-wsdl-addressfalse に設定され、<soap:address> の内容が有効な URL の場合、JBossWS は URL を再書き込みしません。<soap:address> URL が使用されます。

<soap:address> の内容が有効な URL ではない場合、JBossWS は modify-wsdl-address の設定に関係なく書き直します。modify-wsdl-addresstrue に設定され、wsdl-host が定義されていないか、 jbossws.undefined.host に明示的に設定されている場合、<soap:address> URL の内容が使用されます。JBossWS は <soap:address> の書き換え時にリクエスターのホストを使用します。

modify-wsdl-address が定義されていない場合、JBossWS はデフォルト値の true を使用します。

wsdl-host

<soap:address> の書き換えに使用するホスト名または IP アドレス。wsdl-hostjbossws.undefined.host に設定されている場合、JBossWS は <soap:address> の書き換え時にリクエスターのホストを使用します。wsdl-host が定義されていない場合、JBossWS はデフォルト値の jbossws.undefined.host を使用します。

wsdl-path-rewrite-rule

この文字列は、サーバーから公開される各 <soap:address> URL のパスコンポーネントに対して JBossWS が実行される s/regexp/replacement/g などの SED の代コマンドを定義します。wsdl-path-rewrite-rule が定義されていない場合、JBossWS は各 <soap:address> URL の元のパスコンポーネントを保持します。Modify-ogg-addressfalse に設定されている場合、この要素は無視されます。

wsdl-port

SOAP アドレスの書き換えに使用される HTTP ポートを明示的に定義するには、このプロパティーを設定します。それ以外の場合は、インストールされた HTTP コネクターのリストをクエリーして HTTP ポートを特定します。

wsdl-secure-port

SOAP アドレスの書き換えに使用される HTTPS ポートを明示的に定義するには、このプロパティーを設定します。そうでない場合は、インストールされた HTTPS コネクターのリストをクエリーして HTTPS ポートを特定します。

wsdl-uri-scheme

このプロパティーは、<soap:address> の書き換えに使用する URI スキームを明示的に設定します 。有効な値は http および https です。この設定により、トランスポート保証が指定されている場合でも、エンドポイントの処理によって計算されたスキームが上書きされます。wsdl-port および wsdl-secure-port の指定の値、またはそのデフォルト値は、指定されたスキームによって異なります。

管理 CLI を使用してこれらの属性を更新できます。例を以下に示します。

/subsystem=webservices:write-attribute(name=wsdl-uri-scheme, value=https)

3.4.5. ランタイム情報の表示

各 Web サービスエンドポイントは、エンドポイント実装を提供するデプロイメントで公開されます。各エンドポイントはデプロイメントリソースとしてクエリーできます。各 Web サービスのエンドポイントは、Web コンテキストと WSDL URL を指定します。管理 CLI または管理コンソールを使用してこのランタイム情報にアクセスできます。

以下の管理 CLI コマンドは、jaxws-samples-handlerchain.war デプロイメントからの TestService エンドポイントの詳細を表示します。

/deployment="jaxws-samples-handlerchain.war"/subsystem=webservices/endpoint="jaxws-samples-handlerchain:TestService":read-resource(include-runtime=true)
{
    "outcome" => "success",
    "result" => {
        "average-processing-time" => 23L,
        "class" => "org.jboss.test.ws.jaxws.samples.handlerchain.EndpointImpl",
        "context" => "jaxws-samples-handlerchain",
        "fault-count" => 0L,
        "max-processing-time" => 23L,
        "min-processing-time" => 23L,
        "name" => "TestService",
        "request-count" => 1L,
        "response-count" => 1L,
        "total-processing-time" => 23L,
        "type" => "JAXWS_JSE",
        "wsdl-url" => "http://localhost:8080/jaxws-samples-handlerchain?wsdl"
    }
}
注記

read-resource 操作で include-runtime=true フラグを使用すると、ランタイム統計が返されます。ただし、Web サービスエンドポイントの統計収集はデフォルトで無効にされています。以下の管理 CLI コマンドを使用すると、Web サービスエンドポイントの統計を有効にできます。

/subsystem=webservices:write-attribute(name=statistics-enabled,value=true)

管理コンソールの Runtime タブから、Web サービスエンドポイントのランタイム情報を表示することもできます。そのためには、該当するサーバーを選択し、Webservices を選択してエンドポイントを選択します。

3.5. クライアントおよびエンドポイント設定の割り当て

クライアントおよびエンドポイント設定は以下の方法で割り当てることができます。

  • クライアントに対するアノテーション、エンドポイント、または API プログラムによる使用による明示的な割り当て。
  • デフォルト記述子からの設定の自動割り当て。
  • コンテナーからの設定の自動割り当て。

3.5.1. 明示的な設定の割り当て

明示的な設定割り当ては、指定の設定に従ってセットアップされる必要のあるエンドポイントまたはクライアントを開発者が事前に認識するためのものです。この設定は、アプリケーションデプロイメントに含まれる記述子か、 webservices サブシステムに含まれます。

3.5.1.1. 設定デプロイメント記述子

Jakarta XML Web Services クライアントとエンドポイント実装を含むことができる Jakarta EE アーカイブには、事前定義済みのクライアントおよびエンドポイント設定宣言が含まれる場合もあります。すべてのエンドポイントまたは特定のアーカイブのクライアント設定定義は、単一のデプロイメント記述子ファイルに提供する必要があります。これは、EAP_HOME/docs/schema/jbossws-jaxws-config_4_0.xsd にあるスキーマの実装である必要があります。デプロイメント記述子ファイルには、多くのエンドポイントまたはクライアント設定を定義できます。各設定には、アプリケーションがデプロイされるサーバー内で一意の名前が必要です。設定名は、アプリケーション外のエンドポイントまたはクライアント実装で参照することはできません。

例: 2 つのエンドポイント設定を持つ記述子

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
  xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
  <endpoint-config>
    <config-name>org.jboss.test.ws.jaxws.jbws3282.Endpoint4Impl</config-name>
    <pre-handler-chains>
      <javaee:handler-chain>
        <javaee:handler>
          <javaee:handler-name>Log Handler</javaee:handler-name>
          <javaee:handler-class>org.jboss.test.ws.jaxws.jbws3282.LogHandler</javaee:handler-class>
        </javaee:handler>
      </javaee:handler-chain>
    </pre-handler-chains>
    <post-handler-chains>
      <javaee:handler-chain>
        <javaee:handler>
          <javaee:handler-name>Routing Handler</javaee:handler-name>
          <javaee:handler-class>org.jboss.test.ws.jaxws.jbws3282.RoutingHandler</javaee:handler-class>
        </javaee:handler>
      </javaee:handler-chain>
    </post-handler-chains>
  </endpoint-config>
  <endpoint-config>
    <config-name>EP6-config</config-name>
    <post-handler-chains>
      <javaee:handler-chain>
        <javaee:handler>
          <javaee:handler-name>Authorization Handler</javaee:handler-name>
          <javaee:handler-class>org.jboss.test.ws.jaxws.jbws3282.AuthorizationHandler</javaee:handler-class>
        </javaee:handler>
      </javaee:handler-chain>
    </post-handler-chains>
  </endpoint-config>
</jaxws-config>

同様に、クライアント設定は記述子に指定できます。これは前述のスキーマを実装しています。

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
  xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
  <client-config>
    <config-name>Custom Client Config</config-name>
    <pre-handler-chains>
      <javaee:handler-chain>
        <javaee:handler>
          <javaee:handler-name>Routing Handler</javaee:handler-name>
          <javaee:handler-class>org.jboss.test.ws.jaxws.clientConfig.RoutingHandler</javaee:handler-class>
        </javaee:handler>
        <javaee:handler>
          <javaee:handler-name>Custom Handler</javaee:handler-name>
          <javaee:handler-class>org.jboss.test.ws.jaxws.clientConfig.CustomHandler</javaee:handler-class>
        </javaee:handler>
      </javaee:handler-chain>
    </pre-handler-chains>
  </client-config>
  <client-config>
    <config-name>Another Client Config</config-name>
    <post-handler-chains>
      <javaee:handler-chain>
        <javaee:handler>
          <javaee:handler-name>Routing Handler</javaee:handler-name>
          <javaee:handler-class>org.jboss.test.ws.jaxws.clientConfig.RoutingHandler</javaee:handler-class>
        </javaee:handler>
      </javaee:handler-chain>
    </post-handler-chains>
  </client-config>
</jaxws-config>

3.5.1.2. アプリケーションサーバー設定

JBoss EAP では、webservices サブシステムで JBossWS クライアントおよびサーバーの事前定義設定を宣言できます。そのため、サーバー全体のハンドラーを宣言して、特定の設定に割り当てられた各エンドポイントまたはクライアントのチェーンに追加することができます。

標準設定

同じ JBoss EAP インスタンスおよびエンドポイントで実行されているクライアントには、デフォルトで標準設定が割り当てられます。異なる設定が設定されていない限り、デフォルトが使用されます。これにより、管理者はクライアントおよびエンドポイント設定のデフォルトのハンドラーチェーンを調整することができます。webservices サブシステムで使用されるデフォルトのクライアントおよびエンドポイント設定の名前は、Standard-Client-Config および Standard-Endpoint-Config です。

ハンドラーのクラスローディング

サーバー全体のハンドラーを設定する場合、ハンドラークラスは各 ws デプロイメントクラスローダーで利用可能である必要があります。そのため、特定の事前に定義された設定を使用するデプロイメントで適切なモジュール依存関係を指定する必要がある場合があります。適切なモジュール依存関係がデプロイメントで指定されるようにする方法として、org.jboss.ws.spi などのデプロイメントに対する依存関係として自動的に設定されるいずれかのモジュールのハンドラークラスを含むモジュールに依存関係を追加します。

設定例:

例: デフォルトのサブシステム設定

<subsystem xmlns="urn:jboss:domain:webservices:2.0">
    <!-- ... -->
    <endpoint-config name="Standard-Endpoint-Config"/>
    <endpoint-config name="Recording-Endpoint-Config">
        <pre-handler-chain name="recording-handlers" protocol-bindings="##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM">
            <handler name="RecordingHandler" class="org.jboss.ws.common.invocation.RecordingServerHandler"/>
        </pre-handler-chain>
    </endpoint-config>
    <client-config name="Standard-Client-Config"/>
</subsystem>

デプロイメント固有の ws-security エンドポイントセットアップの設定ファイル:

<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:javaee="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
  <endpoint-config>
    <config-name>Custom WS-Security Endpoint</config-name>
    <property>
      <property-name>ws-security.signature.properties</property-name>
      <property-value>bob.properties</property-value>
    </property>
    <property>
      <property-name>ws-security.encryption.properties</property-name>
      <property-value>bob.properties</property-value>
    </property>
    <property>
      <property-name>ws-security.signature.username</property-name>
      <property-value>bob</property-value>
    </property>
    <property>
      <property-name>ws-security.encryption.username</property-name>
      <property-value>alice</property-value>
    </property>
    <property>
      <property-name>ws-security.callback-handler</property-name>
      <property-value>org.jboss.test.ws.jaxws.samples.wsse.policy.basic.KeystorePasswordCallback</property-value>
    </property>
  </endpoint-config>
</jaxws-config>

JBoss EAP のデフォルト設定は以下で SOAP メッセージの schema-validation にデフォルト設定変更されました。

<subsystem xmlns="urn:jboss:domain:webservices:2.0">
    <!-- ... -->
    <endpoint-config name="Standard-Endpoint-Config">
        <property name="schema-validation-enabled" value="true"/>
    </endpoint-config>
    <!-- ... -->
    <client-config name="Standard-Client-Config">
        <property name="schema-validation-enabled" value="true"/>
    </client-config>
</subsystem>

3.5.1.3. EndpointConfig アノテーション

特定のアプリケーションで設定が利用できるようになったら、org.jboss.ws.api.annotation.EndpointConfig アノテーションを使用して、エンドポイント設定を Jakarta XML Web Services エンドポイント実装に割り当てます。webservices サブシステムに定義された設定を割り当てる場合は、設定名のみを指定する必要があります。アプリケーションに定義されている設定を割り当てる場合は、デプロイメント記述子への相対パスと設定名を指定する必要があります。

例: EndpointConfig アノテーション

@EndpointConfig(configFile = "WEB-INF/my-endpoint-config.xml", configName = "Custom WS-Security Endpoint")
public class ServiceImpl implements ServiceIface {
   public String sayHello() {
      return "Secure Hello World!";
   }
}

3.5.1.4. Jakarta XML Web Services の機能

org.jboss.ws.api.configuration.ClientConfigFeature を使用して、JBossWS によって提供される Jakarta XML Web Services Feature エクステンションである設定を行うことができます。

import org.jboss.ws.api.configuration.ClientConfigFeature;

Service service = Service.create(wsdlURL, serviceName);

Endpoint port = service.getPort(Endpoint.class, new ClientConfigFeature("META-INF/my-client-config.xml", "Custom Client Config"));
port.echo("Kermit");

また、trueClientConfigFeature コンストラクターに渡すことで、指定された設定からプロパティーを設定することもできます。

Endpoint port = service.getPort(Endpoint.class, new ClientConfigFeature("META-INF/my-client-config.xml", "Custom Client Config"), true);

JBossWS は、現在のスレッドコンテキストクラスローダーを使用してリソースとして解決した後、指定された設定ファイルを解析します。EAP_HOME/docs/schema/jbossws-jaxws-config_4_0.xsd スキーマは記述子の内容を定義し、jbossws-spi アーティファクトに含まれます。

設定ファイルの null を渡すと、利用可能な場合に、現在のコンテナー設定から設定が読み込まれます。

Endpoint port = service.getPort(Endpoint.class, new ClientConfigFeature(null, "Container Custom Client Config"));

3.5.1.5. API での明示的なセットアップ

または、JBossWS API にはクライアントのビルド時に設定の割り当てに使用できるファシリティークラスが含まれています。

ハンドラー

Jakarta XML Web Services ハンドラーは、以下のようにクライアント設定から読み取られます。

import org.jboss.ws.api.configuration.ClientConfigUtil;
import org.jboss.ws.api.configuration.ClientConfigurer;

Service service = Service.create(wsdlURL, serviceName);
Endpoint port = service.getPort(Endpoint.class);
BindingProvider bp = (BindingProvider)port;

ClientConfigurer configurer = ClientConfigUtil.resolveClientConfigurer();
configurer.setConfigHandlers(bp, "META-INF/my-client-config.xml", "Custom Client Config");
port.echo("Kermit");

ClientConfigUtil ユーティリティークラスを使用してハンドラーを設定することもできます。

ClientConfigUtil.setConfigHandlers(bp, "META-INF/my-client-config.xml", "Custom Client Config");

デフォルトの ClientConfigurer 実装は、現在のスレッドコンテキストクラスローダーを使用してリソースとして解決した後、指定された設定ファイルを解析します。EAP_HOME/docs/schema/jbossws-jaxws-config_4_0.xsd スキーマは記述子の内容を定義し、jbossws-spi アーティファクトに含まれます。

設定ファイルの null を渡すと、利用可能な場合に、現在のコンテナー設定から設定が読み込まれます。

ClientConfigurer configurer = ClientConfigUtil.resolveClientConfigurer();
configurer.setConfigHandlers(bp, null, "Container Custom Client Config");
プロパティー

同様に、プロパティーは以下のようにクライアント設定から読み込まれます。

import org.jboss.ws.api.configuration.ClientConfigUtil;
import org.jboss.ws.api.configuration.ClientConfigurer;

Service service = Service.create(wsdlURL, serviceName);
Endpoint port = service.getPort(Endpoint.class);

ClientConfigUtil.setConfigProperties(port, "META-INF/my-client-config.xml", "Custom Client Config");
port.echo("Kermit");

ClientConfigUtil ユーティリティークラスを使用してプロパティーを設定することもできます。

ClientConfigurer configurer = ClientConfigUtil.resolveClientConfigurer();
configurer.setConfigProperties(port, "META-INF/my-client-config.xml", "Custom Client Config");

デフォルトの ClientConfigurer 実装は、現在のスレッドコンテキストクラスローダーを使用してリソースとして解決した後、指定された設定ファイルを解析します。EAP_HOME/docs/schema/jbossws-jaxws-config_4_0.xsd スキーマは記述子の内容を定義し、jbossws-spi アーティファクトに含まれます。

設定ファイルの null を渡すと、利用可能な場合に、現在のコンテナー設定から設定が読み込まれます。

ClientConfigurer configurer = ClientConfigUtil.resolveClientConfigurer();
configurer.setConfigProperties(port, null, "Container Custom Client Config");

3.5.2. デフォルト記述子からの自動設定

アプリケーション開発者は、クライアントおよびエンドポイントの実装に使用する必要がある設定を認識していない場合があります。その他の場合は、コンパイルタイム依存関係であるため、JBossWS API の明示的な使用が許可されない可能性があります。このようなシナリオに対応するため、JBossWS ではデフォルトのクライアント、jaxws-client-config.xml、およびエンドポイント、jaxws-endpoint-config.xml、記述子をルートディレクトリー内のアプリケーションに含めることができます。これらは、設定ファイル名が指定されていない場合に設定を取得するために解析されます。

<config-file>WEB-INF/jaxws-endpoint-config.xml</config-file>

設定名が指定されていない場合、JBossWS は以下のようにという名前の設定を自動的に検索します。

  • Jakarta XML Web Services エンドポイントの場合は、エンドポイント実装クラスの完全修飾名 (FQN)。
  • Jakarta XML Web Services クライアントの場合は、サービスエンドポイントインターフェイスの FQN。

Dispatch クライアントの自動設定名は選択されません。

たとえば、事前設定されていないエンドポイント実装クラス org.foo.bar.EndpointImpl により、JBossWS はアプリケーションデプロイメントのルートで jaxws-endpoint-config.xml 記述子内で org.foo.bar.EndpointImpl という名前の設定を検索します。同様に、クライアント側では、org.foo.bar.Endpoint インターフェイスを実装するクライアントプロキシーには、jaxws-client-config.xml 記述子の org.foo.bar.Endpoint という名前の設定からセットアップ読み取りが行われます。

3.5.3. コンテナーからの自動設定割り当て

JBossWS は、明示的な設定が指定されておらず、デフォルトの記述子が利用できないか、関連する設定を含まない場合に、コンテナーから事前定義された設定を取得するようフォールバックします。この動作により、コンテナーをデプロイされたアプリケーションから独立して管理できるため、Jakarta XML Web Services クライアントおよびエンドポイント設定をさらに制御できます。

JBossWS は明示的に名前が付けられた設定の webservices サブシステムにアクセスします。使用されるデフォルト設定名は以下のようになります。

  • Jakarta XML Web Services エンドポイントの場合は、エンドポイント実装クラスの完全修飾名。
  • Jakarta XML Web Services クライアントの場合は、サービスエンドポイントインターフェイスの完全修飾名。

Dispatch クライアントは自動的には設定されません。上記で計算した名前を使用して設定が見つからない場合、Standard-Client-Config および Standard-Endpoint-Config 設定がクライアントとエンドポイントにそれぞれ使用されます。

3.6. Web サービスアプリケーションのモジュール依存関係の設定

JBoss EAP Web サービスは、org.jboss.as.webservices.*org.jboss.ws.* モジュールを含むモジュールおよびライブラリーのセットとして提供されます。これらのモジュールを変更する必要はありません。

JBoss EAP では、対応するモジュールに依存関係を明示的に設定しない限り、直接 JBossWS 実装クラスを使用することはできません。デプロイメントに追加するモジュール依存関係を宣言します。

JBossWS API は、webservices サブシステムが利用可能になるたびにデフォルトで利用可能です。これらのモジュールの明示的な依存関係宣言を作成せずに使用できます。

3.6.1. MANIFEST.MF の使用

デプロイメントの依存関係を設定するには、MANIFEST.MF ファイルに追加します。例を以下に示します。

Manifest-Version: 1.0
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client services export,foo.bar

この MANIFEST.MF ファイルは、org.jboss.ws.cxf.jbossws-cxf-client および foo.bar モジュールの依存関係を宣言します。export および services オプションなど、MANIFEST.MF ファイルに依存関係を宣言する方法の詳細は、JBoss EAPDevelopment GuideAdd a Dependency Configuration to MANIFEST.MF を参照してください。

Apache CXF エンドポイントやハンドラーなどのエンドポイントおよびハンドラーでアノテーションを使用する場合は、マニフェストファイルに適切なモジュール依存関係を追加します。この手順を省略すると、アノテーションは選択されず、完全に無視されます。

3.6.1.1. Jakarta XML Binding の使用

コンテナー内で実行されているクライアントまたはエンドポイントで Jakarta XML Binding コンテキストを正常かつ直接使用するには、Jakarta XML Binding 実装を設定します。たとえば、以下の依存関係を設定します。

Dependencies: com.sun.xml.bind services export

3.6.1.2. Apache CXF の使用

Apache CXF API および実装クラスを使用するには、org.apache.cxf (API) モジュールまたは org.apache.cxf.impl (実装) モジュールに依存関係を追加します。例を以下に示します。

Dependencies: org.apache.cxf services

依存関係は、JBossWS のカスタマイズや追加の拡張がない純粋な Apache CXF です。そのため、クライアント側の集約モジュールは、必要なすべての Web サービスの依存関係で利用できます。

3.6.1.3. クライアント側の Web サービスアグリゲーションモジュール

Web サービスの機能すべてを使用する場合は、便利なクライアントモジュールへの依存関係を設定できます。例を以下に示します。

Dependencies: org.jboss.ws.cxf.jbossws-cxf-client services

JBossWS 固有のクラスをロードしてすべての JBossWS 機能を有効にするには、services オプションが必要です。org.jboss.ws.cxf.jbossws-cxf-client および org.apache.cxf モジュールの依存関係を宣言する場合は、services オプションがほぼ常に必要になります。このオプションは、多くの JBossWS コンポーネントおよび Apache CXF Bus 拡張の接続に使用される Service API でのクラスのロードに影響します。

3.6.1.4. アノテーションのスキャン

アプリケーションサーバーは、ユーザーデプロイメントで Jakarta XML Web Services エンドポイントを検出するためにアノテーションインデックスを使用します。web.xml 記述子で参照しているなど、異なるモジュールに属するクラスの Web サービスエンドポイントを宣言する場合は、annotations タイプ依存関係を使用します。この依存関係がないと、エンドポイントは webservices サブシステムのアノテーション付きクラスとして表示されないため、無視されます。

Dependencies: my.org annotations

3.6.2. jboss-deployment-structure.xml の使用

状況によっては、MANIFEST.MF ファイルでモジュールの依存関係を設定する便利なアプローチは機能しない場合があります。たとえば、MANIFEST.MF ファイルに依存関係を設定しても、指定のモジュール依存関係から特定のリソースをインポートおよびエクスポートしても機能しません。これらのシナリオでは、jboss-deployment-structure.xml 記述子ファイルをデプロイメントに追加し、そのデプロイメントにモジュール依存関係を設定します。

jboss-deployment-structure.xml の使用に関する詳細は、JBoss EAPDevelopment GuideAdd a Dependency Configuration to the jboss-deployment-structure.xml を参照してください。

3.7. HTTP タイムアウトの設定

HTTP セッションタイムアウトは、指定した期間内にアクティビティーがないため、HTTP セッションが無効とみなされる期間を定義します。

HTTP セッションのタイムアウトは、以下の場所で優先順に設定できます。

  1. アプリケーション

    以下の設定をファイルに追加すると、アプリケーションの web.xml 設定ファイルで HTTP セッションタイムアウトを定義できます。この値は分単位です。

    <session-config>
      <session-timeout>30</session-timeout>
    </session-config>

    WAR ファイルを変更した場合は、アプリケーションを再デプロイします。WAR ファイルを展開する場合、JBoss EAP は自動的にアプリケーションをアンデプロイおよび再デプロイするため、追加のアクションは必要ありません。

  2. サーバー

    以下の管理 CLI コマンドを使用すると、undertow サブシステムでデフォルトの HTTP セッションタイムアウトを設定できます。この値は分単位です。

    /subsystem=undertow/servlet-container=default:write-attribute(name=default-session-timeout,value=30)
  3. デフォルト

    デフォルトの HTTP セッションタイムアウトは 30 分です。

3.8. Jakarta XML Web Services のセキュア化

WS-Security は、HTTPS などのトランスポートレベルプロトコルを超えたサービスを保護する手段を提供します。WS-Security 標準で定義されたヘッダーなど、多くの標準を使用して以下を実行できます。

  • サービス間で認証トークンを渡します。
  • メッセージまたはメッセージの一部を暗号化する。
  • メッセージに署名します。
  • メッセージにタイムスタンプを付けます。

WS-Security は、公開鍵暗号および秘密鍵暗号を使用します。公開鍵暗号により、ユーザーは公開鍵と秘密鍵のペアを持ちます。これらは、高い素数とキー関数を使用して生成されます。

キーは関連するものですが、相互に派生させることはできません。これらの鍵を使用すると、メッセージを暗号化できます。たとえば、Scott が Adam にメッセージを送信する場合は、公開鍵を使用してメッセージを暗号化できます。次に、Adam は秘密鍵を使用してこのメッセージを復号化できます。秘密鍵のある唯一のメッセージであるため、このメッセージは Adam のみが復号化できます。

メッセージは署名することもできます。これにより、メッセージの信頼性を確保できます。Adam が Scott にメッセージを送信し、Scott が Adam からのメッセージであることを確認する必要がある場合、Adam は秘密鍵を使用してそのメッセージを署名できます。Scott は、公開鍵を使用して、メッセージが Adam からのものであることを検証できます。

3.8.1. Web Services Security (WS-Security) の適用

Web サービスは、WS-Security 機能が必要な多くの実際のシナリオをサポートします。これらのシナリオには、X509 証明書による署名および暗号化サポート、ユーザー名トークンによる認証および承認、および WS-SecurityPolicy 仕様でカバーされるすべての WS-Security 設定が含まれます。

その他の WS-* 機能については、WS-Security 機能のコアは Apache CXF エンジンを介して提供されます。さらに、JBossWS 統合では、WS-Security が有効なエンドポイントの設定を簡素化するいくつかの設定拡張が追加されました。

3.8.1.1. Apache CXF WS-Security 実装

Apache CXF は、複数の設定をサポートし、簡単に拡張できる WS-Security モジュールを特長としています。

システムは、低レベルのセキュリティー操作に対して Apache WSS4J に委譲するインターセプターに基づいています。インターセプターは、Spring 設定ファイルを使用するか、Apache CXF クライアント API を使用して直接設定できます。

Apache CXF の最近のバージョンでは、WS-SecurityPolicy のサポートが導入されました。WS-SecurityPolicy は、多くのセキュリティー設定をポリシーを介してサービスコントラクトに移動することを目的としています。これにより、クライアントがほぼ自動的に設定できるようになりました。これにより、ユーザーは必要なインターセプターの設定とインストールを手動で行う必要がなくなります。代わりに、Apache CXF WS-Policy エンジンがこれを行います。

3.8.1.2. WS-Security Policy のサポート

WS-SecurityPolicy は、特定の WSDL コントラクトで公開されるサービスとセキュアに通信するために必要なアクションを説明します。WSDL バインディングと操作は、WS-Policy フラグメントと、サービスと対話するためのセキュリティー要件を参照します。WS-SecurityPolicy 仕様は、暗号化にトランスポート (HTTPS) を使用して、暗号化に非対称および対称鍵などのものを指定できます。これは、暗号化または署名する部分またはヘッダー、その後に暗号化または署名するかどうか、タイムスタンプを含めるかどうか、派生キーを使用するかどうか、その他のキーを使用するかどうかなどを指定します。

ただし、一部の必須設定要素は公開されたエンドポイントコントラクトの一部やパブリックではなく、含まれるため、WS-SecurityPolicy では扱われません。これには、キーストアの場所、ユーザー名とパスワードなどが含まれます。Apache CXF では、Spring XML 記述子を使用するか、クライアント API またはアノテーションのいずれかを使用してこれらの要素を設定できます。

表3.4 サポートされる設定プロパティー

設定プロパティー説明

ws-security.username

UsernameToken ポリシーアサーションに使用するユーザー名。

ws-security.password

UsernameToken ポリシーアサーションに使用されるパスワード。指定されていない場合は、コールバックハンドラーが呼び出されます。

ws-security.callback-handler

キーストアおよび UsernameToken のパスワードを取得するために使用される WSS4J セキュリティー CallbackHandler

ws-security.signature.properties

署名キーストアと crypto オブジェクトを設定するための WSS4J プロパティーが含まれるプロパティーファイル/オブジェクト。

ws-security.encryption.properties

暗号キーストアおよび暗号化オブジェクトを設定するための WSS4J プロパティーが含まれるプロパティーファイル/オブジェクト。

ws-security.signature.username

使用される署名キーストアのキーのユーザー名またはエイリアス。指定されていない場合は、プロパティーファイルに設定されたデフォルトのエイリアスが使用されます。これが設定されておらず、キーストアに単一のキーのみが含まれる場合、そのキーが使用されます。

ws-security.encryption.username

使用される暗号キーストアのキーのユーザー名またはエイリアス。指定されていない場合は、プロパティーファイルに設定されたデフォルトのエイリアスが使用されます。これが設定されておらず、キーストアに単一のキーのみが含まれる場合、そのキーが使用されます。Web サービスプロバイダーの場合は、useReqSigCert キーワードを使用して、パブリックキーがサービスのトラストストアにあるクライアント (ws-security.encryption.properties で定義) を許可 (暗号化) できます。

ws-security.signature.crypto

これは、signature プロパティーを指定する代わりに、完全な WSS4J Crypto オブジェクトに向けることができます。これにより、暗号情報のプログラムによる設定が容易になります。

ws-security.encryption.crypto

これは、暗号化プロパティーを指定する代わりに、完全な WSS4J Crypto オブジェクトを参照します。これにより、暗号情報のプログラムによる設定が容易になります。

ws-security.enable.streaming

WS-Security メッセージのストリーミング (StAX ベースの) 処理を有効にします。

3.8.2. WS-Trust

WS-Trust は、WS-Security の拡張機能を定義する Web サービス仕様です。これは、分散システムにセキュリティーを実装するための一般的なフレームワークです。標準は、クライアントを認証し、さまざまなタイプの認証および承認データを含むトークンを発行できる集中型セキュリティートークンサービス (STS) に基づいています。この仕様は、セキュリティートークンの発行、交換、および検証に使用されるプロトコルを記述します。WS-Trust アーキテクチャーでは、以下の仕様が重要なロールを果たします。

  • WS-SecurityPolicy 1.2
  • SAML 2.0
  • ユーザー名トークンプロファイル
  • X.509 トークンプロファイル
  • SAML トークンプロファイル
  • Kerberos トークンプロファイル

WS-Trust 拡張機能は、複数のドメインにまたがり、セキュリティー鍵の共有を必要とするアプリケーションのニーズに対応します。これは、Web サービスプロバイダーと Web サービスプロバイダー間の信頼関係をブローカーするために、標準ベースの信頼できるサードパーティーの Web サービス (STS) を提供することで行います。このアーキテクチャーは、この情報の一般的な場所を提供することで、認証情報の変更を必要とするサービス更新の一時停止も軽減します。STS は、要求側とプロバイダーの両方がセキュリティートークンを取得し、検証する一般的なアクセスポイントです。

WS-Trust 仕様には、主に以下のコンポーネントがあります。

  • セキュリティートークンを発行、更新、および検証するためのセキュリティートークンサービス (STS)。
  • セキュリティートークン要求および応答のメッセージ形式。
  • 鍵交換のメカニズム。

次のセクションでは、基本的な WS-Trust シナリオについて説明します。高度なシナリオは、Advanced WS-Trust Scenarios を参照してください。

3.8.2.1. シナリオ: 基本的な WS-Trust

ここでは、基本的な WS-Trust シナリオの例を示します。これは、Web サービス要求側 (ws-requester)、Web サービスプロバイダー (ws-provider)、およびセキュリティートークンサービス (STS) で設定されます。

ws-provider では、非対称バインディングを使用して ws-requester によって提示される SAML 2.0 トークンが必要です。これらの通信要件は、ws-provider の WSDL で宣言されます。STS では、対称バインディングを使用して WSS UsernameToken 形式の要求に ws-requester 認証情報を提供する必要があります。STS からの応答には SAML 2.0 トークンが含まれています。これらの通信要件は、STS の WSDL で宣言されます。

  1. ws-requesterws-provider に接続し、その WSDL を消費します。セキュリティートークンの発行者要件を見つけると、ws-requester は、有効なリクエストを生成するために必要な情報を使用して STSClient を作成し、設定します。
  2. STSClient は STS に接続し、その WSDL を使用します。セキュリティーポリシーが検出されます。STSClient は、適切な認証情報を使用して認証リクエストを作成し、送信します。
  3. STS はクレデンシャルを検証します。
  4. 応答として、STS は ws-requester が STS で認証したことを証明するセキュリティートークンを発行します。
  5. STSClient は、セキュリティートークンを含むメッセージを ws-provider に提示します。
  6. ws-provider は、トークンが STS によって発行されたことを確認し、ws-requester が STS で正常に認証されたことを証明します。
  7. ws-provider は要求されたサービスを実行し、結果を ws-requester に返します。

3.8.2.2. Apache CXF サポート

Apache CXF はオープンソースの完全な Web サービスフレームワークです。JBossWS オープンソースプロジェクトは、JBoss Web Services (JBossWS) スタックと Apache CXF プロジェクトモジュールを統合し、WS-Trust およびその他の Jakarta XML Web Services 機能を提供します。この統合により、Apache CXF STS 実装のデプロイメントが容易になります。Apache CXF API は、Web サービスリクエスターとその STS との通信を容易にする STSClient ユーティリティーも提供します。

3.8.3. セキュリティートークンサービス (STS)

Security Token Service (STS) は WS-Trust 仕様の中核となります。認証および承認の標準ベースのメカニズムです。STS は、トークンの形式、名前空間、または信頼の境界に基づいて、セキュリティートークンの発行、変更、および検証を行うための WS-Trust 仕様のプロトコルの実装です。STS は、Web サービス要求側と Web サービスプロバイダーとの間の信頼関係をブローカー化するために信頼できるサードパーティーとして機能する Web サービスです。これは、要求側とプロバイダーの両方が信頼する共通のアクセスポイントで、相互運用可能なセキュリティートークンを提供します。これにより、要求元とプロバイダー間の直接的な関係が不要になります。STS は認証用の標準ベースのメカニズムであるため、レルム間および異なるプラットフォーム間での相互運用性を確保します。

STS コントラクトは、他のアプリケーションおよびプロセスが対話する方法を定義します。特に、WSDL は WS-Trust ポリシーと WS-Security ポリシーを定義します。このポリシーでは、リクエストャーが STS のエンドポイントと正常に通信するために満たさなければならなりません。Web サービスリクエスターは STS のパッケージを使用し、STSClient ユーティリティーを使用して、指定されたセキュリティーポリシーに準拠するメッセージリクエストを生成し、STS エンドポイントに送信します。STS は要求を検証し、適切な応答を返します。

3.8.3.2. クライアントでの WS-Trust Security Token Service (STS) の使用

STS からセキュリティートークンを取得するようにクライアントを設定するには、org.picketlink.identity.federation.api.wstrust.WSTrustClient クラスを利用して STS に接続し、トークンを発行するように要求する必要があります。

最初にクライアントをインスタンス化する必要があります。

例: WSTrustClient の作成

 WSTrustClient client = new WSTrustClient("PicketLinkSTS", "PicketLinkSTSPort",
       "http://localhost:8080/SecureTokenService/PicketLinkSTS",
       new SecurityInfo(username, password));

次に、WSTrustClient を使用して SAML アサーションなどのトークンが発行されるように要求する必要があります。

例: アサーションの取得

org.w3c.dom.Element assertion = null;
try {
   assertion = client.issueToken(SAMLUtil.SAML2_TOKEN_TYPE);
} catch (WSTrustException wse) {
   System.out.println("Unable to issue assertion: " + wse.getMessage());
   wse.printStackTrace();
}

アサーションを取得したら、そのアサーションを SOAP メッセージに追加および送信する方法があります。

  • クライアントは、org.picketlink.trust.saml.assertion キー下で SOAP MessageContext に SAML2 Assertion をプッシュできます。例を以下に示します。

    bindingProvider.getRequestContext().put(SAML2Constants.SAML2_ASSERTION_PROPERTY, assertion);
  • SAML2 Assertion は、セキュリティーコンテキストで JAAS サブジェクトの一部として利用できます。これは、PicketLink STS ログインモジュールと JAAS の対話がある場合に生じる可能性があります。

3.8.3.3. STS クライアントプール

警告

JBoss EAP では、STS クライアントプール機能はサポートされていません

STS クライアントプールは、サーバーに STS クライアントのプールを設定できるようにする機能であり、STS クライアント作成のボトルネックをなくすことができます。クライアントプールは、STS クライアントが SAML チケットを取得する必要があるログインモジュールに使用できます。これらの型には次のようなものがあります。

  • org.picketlink.identity.federation.core.wstrust.auth.STSIssuingLoginModule
  • org.picketlink.identity.federation.core.wstrust.auth.STSValidatingLoginModule
  • org.picketlink.trust.jbossws.jaas.JBWSTokenIssuingLoginModule

各ログインモジュールのプール内のクライアントのデフォルト数は、initialNumberOfClients ログインモジュールオプションを使用して設定されます。

org.picketlink.identity.federation.bindings.stspool.STSClientPoolFactory クラスはクライアントプール機能をアプリケーションに提供します。

STSClientPoolFactory の使用

STS クライアントは、STSClientConfig 設定をキーとして使用し 、サブプールに挿入されます。STS クライアントをサブプールに挿入するには、STSClientPool インスタンスを取得して、設定に基づいてサブプールを初期化する必要があります。オプションで、プールを初期化する際に STS クライアントの最初の数を指定することができます。または、デフォルトの数を使用することもできます。

例: STS クライアントのサブプールへの挿入

final STSClientPool pool = STSClientPoolFactory.getPoolInstance();
pool.createPool(20, stsClientConfig);
final STSClient client = pool.getClient(stsClientConfig);

クライアントでの作業が完了したら returnClient() メソッドを呼び出し、クライアントをプールに返すことができます。

例: STS クライアントのサブプールへの返信

pool.returnClient();

例: 任意の設定でサブプールが存在するかどうかの確認

if (! pool.configExists(stsClientConfig) {
    pool.createPool(stsClientConfig);
}

picketlink-federation サブシステムを有効にすると、デプロイメント用に作成されたすべてのクライアントプールがアンデプロイプロセス中に自動的に破棄されます。プールを手動で破棄するには、以下を実行します。

例: サブプールの手動破棄

pool.destroyPool(stsClientConfig);

3.8.4. Jakarta Enterprise Beans サブシステムへの認証済みアイデンティティーの伝搬

webservices サブシステムには、アダプターが含まれます。これは、アノテーションまたはデプロイメント記述子のいずれかを使用して、Web サービスエンドポイントをセキュアにするために Elytron セキュリティードメインの設定することができます。

Elytron セキュリティーが有効になっている場合、JAAS サブジェクトまたはプリンシパルを Apache CXF エンドポイントの SecurityContext にプッシュし、認証済みアイデンティティーを Jakarta Enterprise Beans コンテナーに伝播できます。

以下は、Apache CXF インターセプターを使用して認証された情報を Jakarta Enterprise Beans コンテナーに伝播する方法の例になります。

public class PropagateSecurityInterceptor extends WSS4JInInterceptor {
    public PropagateSecurityInterceptor() {
      super();
      getAfter().add(PolicyBasedWSS4JInInterceptor.class.getName());
   }
   @Override
   public void handleMessage(SoapMessage message) throws Fault {
      ...
      final Endpoint endpoint = message.getExchange().get(Endpoint.class);
      final SecurityDomainContext securityDomainContext = endpoint.getSecurityDomainContext();
      //push subject principal retrieved from CXF to ElytronSecurityDomainContext
      securityDomainContext.pushSubjectContext(subject, principal, null)
      }
    }

3.9. Jakarta XML Web Services のロギング

Jakarta XML Web Services ハンドラー または Apache CXF ロギングインターセプター を使用して、インバウンドおよびアウトバウンドメッセージのロギングを処理できます。

3.9.1. Jakarta XML Web Services ハンドラーの使用

Jakarta XML Web Services ハンドラーを設定して、渡されたメッセージをログに記録できます。このアプローチは、@HandlerChain Jakarta XML Web Services アノテーションを使用して、ハンドラーを目的のクライアントとエンドポイントにプログラムで追加できるため、移植可能です。

事前定義されたクライアントおよびエンドポイント設定メカニズムにより、ロギングハンドラーを任意のクライアントおよびエンドポイントの組み合わせに追加したり、一部のクライアントおよびエンドポイントのみに追加したりできます。ロギングハンドラーを一部のクライアントまたはエンドポイントのみに追加するには、@EndpointConfig アノテーションと JBossWS API を使用します。

org.jboss.ws.api.annotation.EndpointConfig アノテーションは、エンドポイント設定を Jakarta XML Web Services エンドポイント実装に割り当てるために使用されます。webservices サブシステムに定義された設定を割り当てる場合、設定名のみが指定されます。アプリケーションに定義されている設定を割り当てる場合は、デプロイメント記述子への相対パスと設定名を指定する必要があります。

3.9.2. Apache CXF ロギングインターセプターの使用

Apache CXF には、コンソール、クライアントのログファイル、またはサーバーのログファイルにメッセージをログに記録するために使用できるロギングインターセプターが同梱されています。これらのインターセプターは、以下を含む複数の方法でクライアント、エンドポイント、およびバスに追加できます。

  • システムプロパティー

    org.apache.cxf.logging.enabled システムプロパティーを true に設定すると、ロギングインターセプターが、JVM で作成されるバスインスタンスに追加されます。システムプロパティーを pretty に設定して、きれいな形式の XML 出力を出力することもできます。以下の管理 CLI コマンドを使用すると、このシステムプロパティーを設定できます。

    /system-property=org.apache.cxf.logging.enabled:add(value=true)
  • 手動インターセプターの追加

    ロギングインターセプターは、Apache CXF アノテーション @org.apache.cxf.interceptor.InInterceptors および @org.apache.cxf.interceptor.OutInterceptors を使用してエンドポイントに選択的に追加できます。プログラムでロギングインターセプターの新しいインスンタスをクライアントまたはバスに追加することにより、クライアント側の同じ結果が得られます。

3.10. Web Services Addressing (WS-Addressing) の有効化

Web サービスのアドレス指定 (WS-Addressing) は、Web サービスと関連メッセージを処理するトランスポートに中立的なメカニズムを提供します。WS-Addressing を有効にするには、@Addressing アノテーションを Web サービスエンドポイントに追加し、アクセスするクライアントを設定する必要があります。

以下の例は、アプリケーションに既存の Jakarta XML Web Services サービスおよびクライアント設定があることを前提としています。使用できる完全な例は、JBoss EAP に同梱される jaxws-addressing クイックスタートを参照してください。

  1. @Addressing アノテーションをアプリケーションの Jakarta XML Web Services エンドポイントコードに追加します。

    例: @Addressing アノテーションのある Jakarta XML Web Services エンドポイント

    package org.jboss.quickstarts.ws.jaxws.samples.wsa;
    
    import org.jboss.quickstarts.ws.jaxws.samples.wsa.ServiceIface;
    
    import javax.jws.WebService;
    import javax.xml.ws.soap.Addressing;
    
    @WebService(
        portName = "AddressingServicePort",
        serviceName = "AddressingService",
        wsdlLocation = "WEB-INF/wsdl/AddressingService.wsdl",
        targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wsaddressing",
        endpointInterface = "org.jboss.quickstarts.ws.jaxws.samples.wsa.ServiceIface")
    @Addressing(enabled = true, required = true)
    public class ServiceImpl implements ServiceIface {
        public String sayHello() {
            return "Hello World!";
        }
    }

  2. Jakarta XML Web Services クライアントコードを更新し、WS-Addressing を設定します。

    例: WS-Addressing 用に設定された Jakarta XML Web Services クライアント

    package org.jboss.quickstarts.ws.jaxws.samples.wsa;
    
    import java.net.URL;
    import javax.xml.namespace.QName;
    import javax.xml.ws.Service;
    import javax.xml.ws.soap.AddressingFeature;
    
    public final class AddressingClient {
        private static final String serviceURL =
            "http://localhost:8080/jaxws-addressing/AddressingService";
    
        public static void main(String[] args) throws Exception {
            // construct proxy
            QName serviceName =
                new QName("http://www.jboss.org/jbossws/ws-extensions/wsaddressing",
                    "AddressingService");
            URL wsdlURL = new URL(serviceURL + "?wsdl");
            Service service = Service.create(wsdlURL, serviceName);
            org.jboss.quickstarts.ws.jaxws.samples.wsa.ServiceIface proxy =
                (org.jboss.quickstarts.ws.jaxws.samples.wsa.ServiceIface) service.getPort(org.jboss.quickstarts.ws.jaxws.samples.wsa.ServiceIface.class,
                    new AddressingFeature());
            // invoke method
            System.out.println(proxy.sayHello());
        }
    }

クライアントおよびエンドポイントは WS-Addressing を使用して通信するようになりました。

3.11. Web サービス信頼できるメッセージングの有効化

Web Services Reliable Messaging (WS-Reliable Messaging) は、Apache CXF に内部で実装されます。インターセプターのセットは、信頼できるメッセージングプロトコルの低レベル要件と対話します。

WS-Reliable Messaging を有効にするには、以下のいずれかの手順を実行します。

  • 適切な WS-Reliable Messaging ポリシー、アサーション、またはそれらの両方を指定する WSDL コントラクトを消費します。
  • 信頼できるメッセージングインターセプターを手動で追加し、設定します。
  • オプションの CXF Spring XML 記述子で信頼できるメッセージングポリシーを指定します。
  • オプションの CXF Spring XML 記述子に Apache CXF 信頼性メッセージング機能を指定します。

最初のアプローチは移植可能な唯一の方法であり、Apache CXF WS-Policy エンジンに依存します。プロプライエタリーの他のアプローチにより、WS-Reliable Messaging Policy で対応していないプロトコル側面の詳細な設定が可能になります。

3.12. Web サービスポリシーの指定

Web Services Policies (WS-Policy) は Apache CXF WS-Policy フレームワークに依存します。このフレームワークは、以下の仕様に準拠しています。

ポリシーは、以下を含む複数の方法で使用することができます。

  • ポリシーアサーションを WSDL コントラクトに追加し、ランタイムにアサーションを消費させ、適切に動作させます。
  • CXF アノテーションまたは機能のいずれかを使用してエンドポイントポリシー添付を指定します。
  • Apache CXF ポリシーフレームワークを使用してカスタムアサーションを定義し、他のタスクを完了します。

3.13. Apache CXF の統合

JBoss EAP 上に JBossWS によって提供されるすべての Jakarta XML Web Services 機能は、現在、ほとんどの Apache CXF プロジェクトモジュールと JBossWS スタックとの適切な統合を介して提供されます。

Apache CXF はオープンソースサービスフレームワークです。これにより、Jakarta XML Web Services を含むフロントエンドプログラミング API を使用してサービスをビルドおよび開発できます。サービスは、HTTP や Jakarta メッセージングなどのさまざまなトランスポートを介して SOAP や XML/HTTP などのさまざまなプロトコルと対話します。

JBossWS と Apache CXF 間の統合レイヤーは主に以下の目的で使用されます。

  • JBoss EAP で Jakarta XML Web Services などの標準の Web サービス API の使用を許可します。これは、ユーザーが対処しなくても、Apache CXF を活用して内部的に実行されます。
  • JBoss EAP 上で WS-* を含む Apache CXF の高度な機能を使用できるようにし、これらのコンテナーでの実行に必要な統合手順をユーザーが処理、設定、考慮したりする必要性を省きます。

これらの目的をサポートするため、Apache CXF を使用した JBossWS 統合は JBossWS エンドポイントデプロイメントメカニズムをサポートし、Apache CXF 上で多数の内部カスタマイズが提供されます。

Apache CXF アーキテクチャーの詳細は、Apache CXF 公式ドキュメント を参照してください。

3.13.1. サーバー側統合のカスタマイズ

JBossWS サーバー側の Apache CXF との統合では、提供された Web サービスデプロイメントに適切な Apache CXF 構造を内部で作成します。デプロイメントに複数のエンドポイントが含まれる場合、それらはすべて同じ Apache CXF バス内に存在し、他のデプロイメントのバスインスタンスとは分離されます。

JBossWS はサーバー側で Apache CXF 設定オプションのほとんどに対して適切なデフォルト値を設定しますが、ユーザーはデプロイメント用に作成される Bus インスタンスを微調整する必要があるかもしれません。jboss-webservices.xml 記述子はデプロイメントレベルのカスタマイズに使用できます。

3.13.1.1. デプロイメント記述子プロパティー

jboss-webservices.xml 記述子は、プロパティー値を提供するために使用できます。

<webservices xmlns="http://www.jboss.com/xml/ns/javaee" version="1.2">
  ...
  <property>
    <name>...</name>
    <value>...</value>
  </property>
  ...
</webservices>

Apache CXF との JBossWS 統合には、Apache CXF 内部を制御するために許可されるプロパティー名のセットが含まれています。

3.13.1.2. WorkQueue の設定

Apache CXF は、@Oneway 要求処理などの一部の操作を処理する WorkQueue インスタンスを使用します。WorkQueueManager は拡張として Bus にインストールされ、キューを追加または削除したり、既存のキューを制御したりできます。

サーバー側では、jboss-webservices.xmlcxf.queue.<queue-name>.* プロパティーを使用してキューを指定できます。たとえば、cxf.queue.default.maxQueueSize プロパティーを使用して、デフォルトの WorkQueue の最大キューサイズを設定できます。デプロイメント時に、JBossWS 統合は AutomaticWorkQueueImpl の新しいインスタンスを現在設定されている WorkQueueManager に追加できます。以下のプロパティーは、AutomaticWorkQueueImpl constructor パラメーターを埋めるために使用されます。

表3.5 AutomaticWorkQueueImpl コンストラクトープロパティー

プロパティーデフォルト値

cxf.queue.<queue-name>.maxQueueSize

256

cxf.queue.<queue-name>.initialThreads

0

cxf.queue.<queue-name>.highWaterMark

25

cxf.queue.<queue-name>.lowWaterMark

5

cxf.queue.<queue-name>.dequeueTimeout

120000

3.13.1.3. ポリシー代替セレクター

Apache CXF ポリシーエンジンは、ポリシーの代替に対応するさまざまなストラテジーをサポートします。JBossWS 統合のデフォルトは MaximalAlternativeSelector ですが、jboss-webservices.xml ファイルで cxf.policy.alternativeSelector プロパティーを使用して異なるセレクター実装を設定することもできます。

3.13.1.4. MBean 管理

Apache CXF を使用すると、JBoss EAP MBean サーバーにインストールされた MBean オブジェクトを管理できます。この機能は、jboss-webservices.xml ファイルの cxf.management.enabled プロパティーを使用してデプロイメントベースで有効にできます。cxf.management.installResponseTimeInterceptors プロパティーを使用して、CXF 応答時間インターセプターのインストールを制御することもできます。これらのインターセプターは、MBean 管理を有効にするとデフォルトで追加されますが、場合によっては必要ない可能性があります。

例: jboss-webservices.xml ファイルの MBean 管理

<webservices xmlns="http://www.jboss.com/xml/ns/javaee" version="1.2">
  <property>
    <name>cxf.management.enabled</name>
    <value>true</value>
  </property>
  <property>
    <name>cxf.management.installResponseTimeInterceptors</name>
    <value>false</value>
  </property>
</webservices>

3.13.1.5. スキーマの検証

Apache CXF には、クライアントとサーバーの両方での SOAP メッセージの受信および送信を検証する機能が含まれます。検証は、サービスプロキシー (クライアント側) のビルドに使用されるエンドポイントの WSDL コントラクト (サーバー側) または WSDL コントラクトの関連するスキーマに対して実行されます。

スキーマの検証は、以下のいずれかの方法で有効にできます。

  • JBoss EAP サーバー設定の最適化

    たとえば、以下の管理 CLI コマンドは、デフォルトの Standard-Endpoint-Config エンドポイント設定のスキーマ検証を有効にします。

    /subsystem=webservices/endpoint-config=Standard-Endpoint-Config/property=schema-validation-enabled:add(value=true)
  • 事前定義されたクライアントまたはエンドポイント設定ファイルです。

    参照された設定ファイルで schema-validation-enabled プロパティーを true に設定すると、事前に設定されている設定 に、コンテナー内で実行しているエンドポイントまたはクライアントを関連付けることができます。

  • クライアント側でプログラムで

    クライアント側では、スキーマ検証をプログラムで有効にできます。例を以下に示します。

    ((BindingProvider)proxy).getRequestContext().put("schema-validation-enabled", true);
  • サーバー側で @org.apache.cxf.annotations.SchemaValidation アノテーションを使用します。

    サーバー側では、@org.apache.cxf.annotations.SchemaValidation アノテーションを使用できます。例を以下に示します。

    import javax.jws.WebService;
    import org.apache.cxf.annotations.SchemaValidation;
    
    @WebService(...)
    @SchemaValidation
    public class ValidatingHelloImpl implements Hello {
       ...
    }

3.13.1.6. Apache CXF インターセプター

jboss-webservices.xml 記述子 では、cxf.interceptors.in および cxf.interceptors.out プロパティーを指定できます。これらのプロパティーにより、宣言しているインターセプターを、デプロイメントを提供するために作成された Bus インスタンスに割り当てることができます。

例: jboss-webservices.xml ファイル

<?xml version="1.1" encoding="UTF-8"?>
<webservices
  xmlns="http://www.jboss.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  version="1.2"
  xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee">

  <property>
    <name>cxf.interceptors.in</name>
    <value>org.jboss.test.ws.jaxws.cxf.interceptors.BusInterceptor</value>
  </property>
  <property>
    <name>cxf.interceptors.out</name>
    <value>org.jboss.test.ws.jaxws.cxf.interceptors.BusCounterInterceptor</value>
  </property>
</webservices>

以下の方法のいずれかを使用してインターセプターを宣言できます。

  • エンドポイントクラスのアノテーションの使用 (@org.apache.cxf.interceptor.InInterceptor または @org.apache.cxf.interceptor.OutInterceptor)。
  • org.apache.cxf.interceptor.InterceptorProvider インターフェイスを使用したクライアント側での直接 API 使用。
  • JBossWS 記述子の使用方法。

JBoss EAP では Spring 統合がサポートされなくなったため、JBossWS 統合では、際のクライアントまたはエンドポイントコードの変更を不要にするために jaxws-endpoint-config.xml 記述子ファイルを使用します。cxf.interceptors.in および cxf.interceptors.out プロパティーのインターセプタークラス名のリストを指定して、事前定義されたクライアントおよびエンドポイント設定内でインターセプターを宣言します。

例: jaxws-endpoint-config.xml ファイル

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
  xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
  <endpoint-config>
    <config-name>org.jboss.test.ws.jaxws.cxf.interceptors.EndpointImpl</config-name>
    <property>
      <property-name>cxf.interceptors.in</property-name>
      <property-value>org.jboss.test.ws.jaxws.cxf.interceptors.EndpointInterceptor,org.jboss.test.ws.jaxws.cxf.interceptors.FooInterceptor</property-value>
    </property>
    <property>
      <property-name>cxf.interceptors.out</property-name>
      <property-value>org.jboss.test.ws.jaxws.cxf.interceptors.EndpointCounterInterceptor</property-value>
    </property>
  </endpoint-config>
</jaxws-config>

注記

指定された各インターセプタークラスの新規インスタンスは、設定が割り当てられるクライアントまたはエンドポイントに追加されます。インターセプタークラスには no-argument コンストラクターが必要です。

3.13.1.7. Apache CXF の機能

jboss-webservices.xml 記述子を使用すると、cxf.features プロパティーを指定できます。このプロパティーを使用すると、デプロイメントを提供するために作成された Bus インスタンスに属するエンドポイントに機能を宣言できます。

例: jboss-webservices.xml ファイル

<?xml version="1.1" encoding="UTF-8"?>
<webservices
  xmlns="http://www.jboss.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  version="1.2"
  xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee">

  <property>
    <name>cxf.features</name>
    <value>org.apache.cxf.feature.FastInfosetFeature</value>
  </property>
</webservices>

以下の方法のいずれかを使用して機能を宣言できます。

  • エンドポイントクラスでのアノテーション使用 (例: @org.apache.cxf.feature.Features)
  • org.apache.cxf.feature.AbstractFeature クラスの拡張により、クライアント側で API の直接使用。
  • JBossWS 記述子の使用方法。

JBoss EAP では Spring 統合がサポートされなくなったため、JBossWS 統合は追加の記述子 (jaxws-endpoint-config.xml ファイルベースのアプローチ) を追加して、実際のクライアントまたはエンドポイントコードへの変更を回避します。cxf.features プロパティーの機能クラス名のリストを指定して、事前定義のクライアントおよびエンドポイント設定内で機能を宣言できます。

例: jaxws-endpoint-config.xml ファイル

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
  xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
  <endpoint-config>
    <config-name>Custom FI Config</config-name>
    <property>
      <property-name>cxf.features</property-name>
      <property-value>org.apache.cxf.feature.FastInfosetFeature</property-value>
    </property>
  </endpoint-config>
</jaxws-config>

注記

指定された各機能クラスの新規インスタンスは、設定が割り当てられるクライアントまたはエンドポイントに追加されます。機能クラスには no-argument コンストラクターが必要です。

3.13.1.8. プロパティー駆動 Bean の作成

Apache CXF Interceptors および Apache CXF Features セクションでは、クライアントまたはエンドポイントの事前定義設定または jboss-webservices.xml 記述子でプロパティーを使用して CXF インターセプターおよび機能を宣言する方法を説明します。指定された feature または interceptor クラス名のみを取得することにより、コンテナーはクラスデフォルトコンストラクターを使用して bean インスタンスを作成しようとします。これは、vanilla CXF クラスのカスタム拡張機能が提供されない限り、機能またはインターセプター設定の制限を設定します。ただし、デフォルトのコンストラクター設定プロパティーは、最終的にスーパーコンストラクターを使用する前に設定されます。

この問題に対処するために、JBossWS 統合には、プロパティーからビルドする際に単純な bean 階層を設定するメカニズムが含まれています。プロパティーには bean 参照値を持たせることができます。これは、## で始まる文字列です。プロパティー参照キーは、bean クラス名と各属性の値を指定するために使用されます。

たとえば、以下のプロパティーを使用すると、スタックは機能インスタンスをインストールします。

キー

cxf.features

##foo, ##bar

##foo

org.jboss.Foo

##foo.par

34

##bar

org.jboss.Bar

##bar.color

blue

以下のコードでは、同じ結果を作成できます。

import org.Bar;
import org.Foo;
...
Foo foo = new Foo();
foo.setPar(34);
Bar bar = new Bar();
bar.setColor("blue");

このメカニズムは、クラスが適切な getter() および setter() メソッドを持つ有効な Bean であることを前提としています。値オブジェクトは、クラス定義を検査して正しいプリミティブ型にキャストされます。ネストされた Bean を設定することもできます。

付録A 参考資料

A.1. Jakarta RESTful Web Services/RESTEasy アノテーション

表A.1 Jakarta RESTful Web Services/RESTEasy アノテーション

Annotation使用方法

Cache

応答の Cache-Control ヘッダーを自動的に設定します。

ClientInterceptor

インターセプターをクライアント側のインターセプターとして特定します。

ContentEncoding

アノテーション付きのアノテーションで適用する Content-Encoding を指定するメタアノテーション。

Context

javax.ws.rs.core.HttpHeadersjavax.ws.rs.core.UriInfojavax.ws.rs.core.Requestjavax.servlet.HttpServletRequestjavax.servlet.HttpServletResponsejavax.ws.rs.core.SecurityContext オブジェクトのインスタンスを指定できます。

@CookieParam

HTTP リクエスト cookie のクッキーまたはオブジェクト表現の値をメソッド呼び出しに指定できます。

DecorateTypes

サポートされているタイプを指定するには、DecoratorProcessor クラスに配置する必要があります。

デコレーター

デコレーションをトリガーする別のアノテーションに配置されるメタアノテーション。

DefaultValue

HTTP リクエスト項目が存在しない場合にデフォルト値を定義するために、その他の @*Param アノテーションと組み合わせることができます。

DELETE

メソッドが HTTP DELETE リクエストに応答することを示すアノテーション。

DoNotUseJAXBProvider

Jakarta XML Binding MessageBodyReader/Writer が使用されないようにし、代わりに型のマーシャリングに使用するより具体的なプロバイダーがある場合はこれをクラスまたはパラメーターに配置します。

Encoded

クラス、メソッド、またはパラメーターで使用できます。デフォルトでは、@PathParam および @QueryParams はデコードされます。@Encoded アノテーションを追加すると、これらのパラメーターの値がエンコードされた形式で提供されます。

Form

これは、リクエストと要求の発信および受信を行うためにオブジェクトとして使用できます。

Formatted

インデントと改行で XML 出力をフォーマットします。これは Jakarta XML Binding Decorator です。

GET

メソッドが HTTP GET リクエストに応答することを示すアノテーション。

IgnoreMediaTypes

タイプ、メソッド、パラメーター、またはフィールドに配置し、特定のメディアタイプに Jakarta XML Binding プロバイダーを使用しないように Jakarta RESTful Web Services に指示します。

ImageWriterParams

IIOImageProvider にパラメーターを渡すためにリソースクラスが使用できるアノテーション。

Mapped

JSONConfig

MultipartForm

これは、multipart/form-data MIME タイプの受信/発進のオブジェクトとして使用できます。

NoCache

nocacheCache-Control 応答ヘッダーを設定します。

NoJackson

Jackson プロバイダーをトリガーしない場合にクラス、パラメーター、フィールド、またはメソッドに配置します。

PartType

List または Map を multipart/* タイプとして書き出す場合は、Multipart プロバイダーと併用する必要があります。

Path

これは、クラスまたはリソースメソッドに存在する必要があります。両方に存在する場合、リソースメソッドへの相対パスはクラスとメソッドの連結になります。

PathParam

変数 URI パスのフラグメントをメソッド呼び出しにマッピングできるようにします。

POST

メソッドが HTTP POST リクエストに応答することを示すアノテーション。

Priority

クラスの使用順序を示すアノテーション。値が小さい整数パラメーターを使用すると優先度が高くなります。

Provider

プロバイダースキャンフェーズ中に、Jakarta RESTful Web Services ランタイムによって プロバイダー として検出できるようにクラスをマークします。

PUT

メソッドが HTTP PUT リクエストに応答することを示すアノテーション。

QueryParam

URI クエリー文字列パラメーターまたは URL 形式のエンコードされたパラメーターをメソッド呼び出しにマップできるようにします。

ServerInterceptor

インターセプターをサーバー側のインターセプターとして特定します。

StringParameterUnmarshallerBinder

文字列ベースのアノテーションインジェクターに適用されるように StringParameterUnmarshaller をトリガーする別のアノテーションに配置されるメタアノテーション。

Stylesheet

XML スタイルシートヘッダーを指定します。

Wrapped

Jakarta XML Binding オブジェクトのコレクションまたは配列をマーシャリングまたはアンマーシャリングする場合は、これをメソッドまたはパラメーターに配置します。

WrappedMap

Jakarta XML Binding オブジェクトのマップをマーシャリングまたはアンマーシャリングする場合に、これをメソッドまたはパラメーターに配置します。

XmlHeader

返されたドキュメントの XML ヘッダーを設定します。

XmlNsMap

JSONToXml

XopWithMultipartRelated

このアノテーションは、Jakarta XML Binding アノテーションが付けられたオブジェクトを送受信先または送受信元とする受信または送信 XOP メッセージ (multipart/related としてパッケージ化) を処理または生成するために使用できます。

A.2. RESTEasy 設定パラメーター

表A.2 要素

オプション名デフォルト値説明

resteasy.servlet.mapping.prefix

デフォルトなし

Resteasy servlet-mapping の URL パターンが /* ではない場合。

resteasy.scan

false

@Provider および Jakarta RESTful Web Services リソースクラス (@Path@GET@POST など) の両方に対して WEB-INF/lib JAR および WEB-INF/classes ディレクトリーを自動的にスキャンして、登録します。

resteasy.scan.providers

false

@Provider クラスをスキャンして登録します。

resteasy.scan.resources

false

Jakarta RESTful Web Services リソースクラスのスキャン。

resteasy.providers

デフォルトなし

登録する完全修飾 @Provider クラス名のコンマ区切りリスト。

resteasy.use.builtin.providers

true

デフォルトのビルトイン @Provider クラスを登録するかどうか。

resteasy.resources

デフォルトなし

登録する完全修飾 Jakarta RESTful Web Services リソースクラス名のコンマ区切りリスト。

resteasy.jndi.resources

デフォルトなし

Jakarta RESTful Web Services リソースとして登録するオブジェクトを参照する JNDI 名のコンマ区切りリスト。

javax.ws.rs.Application

デフォルトなし

仕様移植可能な方法でブートストラップする Application クラスの完全修飾名。

resteasy.media.type.mappings

デフォルトなし

ファイル名の拡張子 (例: .xmltxt) をメディアタイプにマッピングすることで、Accept ヘッダーの必要性を置き換えます。クライアントが Accept ヘッダーを使用して表示 (ブラウザーなど) を選択できない場合に使用されます。これは、resteasy.media.type.mappings および resteasy.language.mappings. を使用して WEB-INF/web.xml ファイルで設定します。

resteasy.language.mappings

デフォルトなし

ファイル名の拡張子 (.en または .fr など) を言語にマッピングすることで、Accept-Language ヘッダーの必要性を置き換えます。クライアントが Accept-Language ヘッダーを使用して言語 (ブラウザーなど) を選択できない場合に使用されます。

resteasy.document.expand.entity.references

false

外部エンティティーを展開するか、空の文字列に置き換えるか。JBoss EAP では、このパラメーターのデフォルトは false であるため、空の文字列に置き換わります。

resteasy.document.secure.processing.feature

true

org.w3c.dom.Document ドキュメントと Jakarta XML Binding オブジェクト表現を処理するためのセキュリティー制約を適用します。

resteasy.document.secure.disableDTDs

true

org.w3c.dom.Document ドキュメントおよび Jakarta XML Binding オブジェクト表現で DTD を禁止します。

resteasy.wider.request.matching

true

Jakarta RESTful Web Services 仕様に定義されているクラスレベルの式フィルターをオフにし、代わりに各 Jakarta RESTful Web Services メソッドの完全な式に基づいて照合します。

resteasy.use.container.form.params

true

HttpServletRequest.getParameterMap() メソッドを使用して、フォームパラメーターを取得します。サーブレットフィルター内でこのメソッドを呼び出す場合や、フィルター内で入力ストリームを使用する場合は、このスイッチを使用します。

resteasy.add.charset

true

リソースメソッドが明示的な文字セットなしで text/* または application/xml* メディアタイプを返す場合、RESTEasy は charset=UTF-8 を、返された content-type ヘッダーに追加します。この場合、charset は、このパラメーターの設定とは関係なく UTF-8 にデフォルト設定されることに注意してください。

注記

これらのパラメーターは WEB-INF/web.xml ファイルで設定されます。

重要

Servlet 3.0 コンテナーでは、web.xml ファイルの resteasy.scan.* 設定は無視され、Jakarta RESTful Web Services アノテーションが付けられたコンポーネントがすべて自動的にスキャンされます。

たとえば、javax.ws.rs.Application パラメーターはサーブレット設定の init-param 内で設定されています。

<servlet>
    <servlet-name>Resteasy</servlet-name>
    <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>org.jboss.resteasy.utils.TestApplication</param-value>
    </init-param>
</servlet>

たとえば、resteasy.document.expand.entity.referencescontext-param 内で設定されます。

<context-param>
    <param-name>resteasy.document.expand.entity.references</param-name>
    <param-value>true</param-value>
</context-param>
警告

以下の RESTEasy パラメーターのデフォルト値を変更すると、RESTEasy アプリケーションが XXE 攻撃に対して脆弱になる可能性があります。

  • resteasy.document.expand.entity.references
  • resteasy.document.secure.processing.feature
  • resteasy.document.secure.disableDTDs

A.3. RESTEasy JavaScript API パラメーター

表A.3 パラメータープロパティー

プロパティーデフォルト値説明

$entity

 

PUTPOST 要求として送信するエンティティー。

$contentType

 

Content-Type ヘッダーとして送信されるボディーエンティティーの MIME タイプ。@Consumes アノテーションで決定されます。

$accepts

*/*

Accept ヘッダーとして送信される許可される MIME タイプ。@Provides アノテーションで決定されます。

$callback

 

非同期呼び出しの関数 (httpCodexmlHttpRequestvalue) に設定します。これがない場合、呼び出しは同期され、値を返します。

$apiURL

 

最後のスラッシュを含まない Jakarta RESTful Web Services エンドポイントのベース URI に設定します。

$username

 

ユーザー名およびパスワードが設定されている場合は、要求のクレデンシャルに使用されます。

$password

 

ユーザー名およびパスワードが設定されている場合は、要求のクレデンシャルに使用されます。

A.4. rest.Request クラスメンバー

表A.4 rest.Request クラス

メンバー説明

execute(callback)

現在のオブジェクトに設定されたすべての情報でリクエストを実行します。値はオプションの引数コールバックに渡され、返されません。

setAccepts(acceptHeader)

Accept 要求ヘッダーを設定します。デフォルトは */* です。

setCredentials(username, password)

要求の認証情報を設定します。

setEntity(entity)

リクエストエンティティーを設定します。

setContentType(contentTypeHeader)

Content-Type リクエストヘッダーを設定します。

setURI(uri)

要求 URI を設定します。絶対 URI である必要があります。

setMethod(method)

要求メソッドを設定します。デフォルトは GET です。

setAsync(async)

リクエストを非同期にするかどうかを制御します。デフォルト値は true です。

addCookie(name, value)

要求の実行時に現在のドキュメントに指定の Cookie を設定します。これは、ブラウザーで永続化されます。

addQueryParameter(name, value)

クエリーパラメーターを URI クエリー部分に追加します。

addMatrixParameter(name, value)

リクエスト URI の最後のパスセグメントにマトリクスパラメーター (path パラメーター) を追加します。

addHeader(name, value)

要求ヘッダーを追加します。

addForm(name, value)

フォームを追加します。

addFormParameter(name, value)

フォームパラメーターを追加します。

A.5. RESTEasy 非同期ジョブサービスの設定パラメーター

以下の表は、非同期ジョブサービスの設定可能な context-params の詳細を示しています。これらのパラメーターは web.xml ファイルで設定できます。

表A.5 設定パラメーター

Parameter説明

resteasy.async.job.service.max.job.results

メモリーに一度に保持できるジョブ結果の数。デフォルト値は 100 です。

resteasy.async.job.service.max.wait

クライアントがそのジョブをクエリーする際のジョブの最大待機時間。デフォルト値は、300000 です。

resteasy.async.job.service.thread.pool.size

ジョブを実行するバックグラウンドスレッドのスレッドプールサイズ。デフォルト値は 100 です。

resteasy.async.job.service.base.path

ジョブ URI のベースパスを設定します。デフォルト値は /asynch/jobs です。

<web-app>
    <context-param>
        <param-name>resteasy.async.job.service.enabled</param-name>
        <param-value>true</param-value>
    </context-param>

    <context-param>
        <param-name>resteasy.async.job.service.max.job.results</param-name>
        <param-value>100</param-value>
    </context-param>
    <context-param>
        <param-name>resteasy.async.job.service.max.wait</param-name>
        <param-value>300000</param-value>
    </context-param>
    <context-param>
        <param-name>resteasy.async.job.service.thread.pool.size</param-name>
        <param-value>100</param-value>
    </context-param>
    <context-param>
        <param-name>resteasy.async.job.service.base.path</param-name>
        <param-value>/asynch/jobs</param-value>
    </context-param>

    <listener>
        <listener-class>
            org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>Resteasy</servlet-name>
        <servlet-class>
            org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
        </servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Resteasy</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

A.6. Jakarta XML Web Services のツール

wsconsume

wsconsume は、WSDL を使用し、移植可能な Jakarta XML Web Services サービスおよびクライアントアーティファクトを生成する JBoss EAP で提供されるコマンドラインツールです。

使用方法

wsconsume ツールは EAP_HOME/bin ディレクトリーにあり、以下の構文を使用します。

EAP_HOME/bin/wsconsume.sh [options] <wsdl-url>
注記

Windows には、wsconsume.bat スクリプトを使用してください。

使用例:

  • Example.wsdl WSDL ファイルから Java クラスファイルを生成

    EAP_HOME/bin/wsconsume.sh Example.wsdl
  • Example.wsdl WSDL ファイルから Java ソースおよびクラスファイルを生成

    EAP_HOME/bin/wsconsume.sh -k Example.wsdl
  • Example.wsdl WSDL ファイルから my.org パッケージに Java ソースとクラスファイルを生成

    EAP_HOME/bin/wsconsume.sh -k -p my.org Example.wsdl
  • 複数のバインディングファイルを使用した Java ソースおよびクラスファイルの生成

    EAP_HOME/bin/wsconsume.sh -k -b schema-binding1.xsd -b schema-binding2.xsd Example.wsdl
  • wsconsume.sh スクリプトで使用するように、JAVA_OPTS 環境変数で -Dlog4j プロパティーを設定します。

    • この設定により、カスタマイズ可能なログファイルを作成し、アプリケーションのログレベルを設定できます。
    • ログ設定ファイルをロードするには、次の例に示すように、-Dlog4j.configuration=file:log4j.prsoperties または -Dlog4j.configuration=file:log4j.xml を使用します。

      JAVA_OPTS="-Dlog4j.configuration=file:log4j.properties" ./bin/wsconsume.sh <WSDL_URL>

      <WSDL_URL> は、コードの生成時に使用する WSDL ファイルのパスを示します。

利用可能な wsconsume オプションの全一覧は、--help 引数を使用するか、以下の表を参照してください。

表A.6 wsconsume オプション

オプション説明

-a、--additionalHeaders

暗黙的な SOAP ヘッダーの処理を有効にします。

-b, --binding=<file>

1 つ以上の Jakarta XML Web Services または Jakarta XML Binding バインディングファイル。

-c --catalog=<file>

エンティティー解決用の Casis XML Catalog ファイル。

-d --encoding=<charset>

生成されるソースに使用する文字セットエンコーディング。

-e、--extension

SOAP 1.2 バインディング拡張を有効にします。

-h、--help

このヘルプメッセージを表示します。

-j --clientjar=<name>

Web サービスを呼び出すために生成されたアーティファクトの JAR ファイルを作成します。

-k, --keep

Java ソースを維持/生成します。

-l, --load-consumer

コンシューマーを読み込み、終了します (debug ユーティリティー)。

-n, --nocompile

生成されたソースをコンパイルしません。

-o, --output=<directory>

生成されたアーティファクトを配置するディレクトリー。

-p --package=<name>

生成されるソースのターゲットパッケージ。

-q, --quiet

より静かに

-s, --source=<directory>

Java ソースを配置するディレクトリー。

-t, --target=<2.1 2.2>

Jakarta XML Web Services 仕様ターゲット。

-v、--verbose

完全例外スタックトレースを表示します。

-w --wsdlLocation=<loc>

@WebService.wsdlLocation を使用する値。

wsprovide

wsprovide は、サービスエンドポイント実装の移植可能な Jakarta XML Web Services アーティファクトを生成する JBoss EAP で提供されるコマンドラインツールです。また、AIA ファイルを生成するオプションもあります。

使用方法

wsprovide ツールは EAP_HOME/bin ディレクトリーにあり、以下の構文を使用します。

EAP_HOME/bin/wsprovide.sh [options] <endpoint class name>
注記

Windows には wsprovide.bat スクリプトを使用してください。

使用例:

  • output ディレクトリーに移植可能なアーティファクト用のラッパークラスを生成します。

    EAP_HOME/bin/wsprovide.sh -o output my.package.MyEndpoint
  • 出力ディレクトリーにラッパークラスと output を生成します。

    EAP_HOME/bin/wsprovide.sh -o output -w my.package.MyEndpoint
  • 他の JAR を参照するエンドポイントの output ディレクトリーでラッパークラスを生成します。

    EAP_HOME/bin/wsprovide.sh -o output -c myapplication1.jar:myapplication2.jar my.org.MyEndpoint
  • wsprovide.sh スクリプトで使用するように、JAVA_OPTS 環境変数で -Dlog4j プロパティーを設定します。

    • この設定により、カスタマイズ可能なログファイルを作成し、アプリケーションのログレベルを設定できます。
    • ロギング設定ファイルをロードするには、次の例に示すように、-Dlog4j.configuration=file:log4j.properties または -Dlog4j.configuration=file:log4j.xml を使用します。

      JAVA_OPTS="-Dlog4j.configuration=file:log4j.properties" ./bin/wsprovide.sh

利用可能な wsprovide オプションの全一覧は、--help 引数を使用するか、以下の表を参照してください。

表A.7 wsprovide オプション

オプション説明

-a, --address=<address>

WSDL で生成されたポート soap:address。

-c, --classpath=<path>

エンドポイントが含まれるクラスパス。

-e、--extension

SOAP 1.2 バインディング拡張を有効にします。

-h、--help

このヘルプメッセージを表示します。

-k, --keep

Java ソースを維持/生成します。

-l, --load-provider

プロバイダーを読み込み、終了します (debug ユーティリティー)。

-o, --output=<directory>

生成されたアーティファクトを配置するディレクトリー。

-q, --quiet

より静かに

-r, --resource=<directory>

リソースのアーティファクトを配置するディレクトリー。

-s, --source=<directory>

Java ソースを配置するディレクトリー。

-t, --show-traces

完全例外スタックトレースを表示します。

-w, --wsdl

WSDL ファイル生成を有効にします。

A.7. Jakarta XML Web Services Common API リファレンス

複数の Jakarta XML Web Services 開発概念が、Web サービスエンドポイントとクライアント間で共有されます。これには、ハンドラーフレームワーク、メッセージコンテキスト、および障害処理が含まれます。

ハンドラーフレームワーク

ハンドラーフレームワークは、サーバーコンポーネントであるクライアントおよびエンドポイントのランタイムで Jakarta XML Web Services プロトコルバインディングによって実装されます。バインディングプロバイダーとして知られるプロキシーおよび Dispatch インスタンスは、それぞれプロトコルバインディングを使用して抽象機能を特定のプロトコルにバインドします。

クライアントおよびサーバー側のハンドラーは、ハンドラーチェーンと呼ばれる順序付けされたリストに編成されます。ハンドラーチェーン内のハンドラーは、メッセージが送受信されるたびに呼び出されます。受信メッセージは、バインディングプロバイダーが処理する前にハンドラーによって処理されます。アウトバウンドメッセージは、バインディングプロバイダーが処理した後にハンドラーによって処理されます。

ハンドラーは、受信メッセージおよびアウトバウンドメッセージにアクセスして変更し、プロパティーのセットを管理するメソッドを提供するメッセージコンテキストで呼び出されます。メッセージコンテキストプロパティーは、ハンドラーとクライアントおよびサービスの実装間の通信だけでなく、個別のハンドラー間の通信を容易にします。異なるタイプのハンドラーは異なるタイプのメッセージコンテキストで呼び出されます。

論理ハンドラー
論理ハンドラーは、メッセージコンテキストプロパティーおよびメッセージペイロードでのみ動作します。論理ハンドラーはプロトコルに依存しないため、メッセージのプロトコル固有の部分には影響がありません。論理ハンドラーは、インターフェイス javax.xml.ws.handler.LogicalHandler を実装します。
プロトコルハンドラー
プロトコルハンドラーは、メッセージコンテキストプロパティーおよびプロトコル固有のメッセージで動作します。プロトコルハンドラーは特定のプロトコルに固有のもので、メッセージのプロトコル固有の側面にアクセスし、変更する可能性があります。プロトコルハンドラーは、javax.xml.ws.handler.LogicalHandler を除き、javax.xml.ws.handler.Handler から派生するインターフェイスを実装します。
サービスエンドポイントハンドラー

サービスエンドポイントでは、ハンドラーは @HandlerChain アノテーションを使用して定義されます。ハンドラーチェーンファイルの場所は、externalForm の絶対 java.net.URL か ソースファイルまたはクラスファイルからの相対パスのいずれかになります。

@WebService
@HandlerChain(file = "jaxws-server-source-handlers.xml")
public class SOAPEndpointSourceImpl {
   ...
}
サービスクライアントハンドラー

Jakarta XML Web サービスクライアントでは、ハンドラーは、サービスエンドポイントのように @HandlerChain アノテーションを使用して定義されるか、Jakarta XML Web Services API を使用して動的に定義されます。

Service service = Service.create(wsdlURL, serviceName);
Endpoint port = (Endpoint)service.getPort(Endpoint.class);

BindingProvider bindingProvider = (BindingProvider)port;
List<Handler> handlerChain = new ArrayList<Handler>();
handlerChain.add(new LogHandler());
handlerChain.add(new AuthorizationHandler());
handlerChain.add(new RoutingHandler());
bindingProvider.getBinding().setHandlerChain(handlerChain);

setHandlerChain メソッドの呼び出しが必要です。

メッセージコンテキスト

MessageContext インターフェイスは、すべての Jakarta XML Web Services メッセージコンテキストのスーパーインターフェイスです。これは、追加のメソッドと定数を使用して Map<String,Object> を拡張し、ハンドラーチェーンのハンドラーが処理関連の状態を共有できるようにするプロパティーセットを管理します。たとえば、ハンドラーは put メソッドを使用してプロパティーをメッセージコンテキストに挿入します。その後、ハンドラーチェーンの他のハンドラーは get メソッドを使用してメッセージを取得する可能性があります。

プロパティーは APPLICATION または HANDLER としてスコープ指定されます。すべてのプロパティーは、特定のエンドポイントのメッセージ交換パターン (MEP) のインスタンスに対するすべてのハンドラーで利用できます。たとえば、論理ハンドラーがプロパティーをメッセージコンテキストに置いた場合、そのプロパティーは MEP インスタンスの実行中にチェーンの任意のプロトコルハンドラーでも利用できます。

注記

非同期メッセージ交換パターン (MEP) を使用すると、HTTP 接続レベルでメッセージを非同期に送受信できます。これを有効にするには、要求コンテキストに追加のプロパティーを設定します。

APPLICATION レベルでスコープ設定されているプロパティーは、クライアントアプリケーションおよびサービスエンドポイント実装でも利用可能になります。プロパティーの defaultscope のスコープは HANDLER です。

論理メッセージと SOAP メッセージは、異なるコンテキストを使用します。

論理メッセージコンテキスト
論理ハンドラーが呼び出されると、LogicalMessageContext タイプのメッセージコンテキストを受け取ります。LogicalMessageContextMessageContext を、メッセージペイロードを取得および変更するメソッドで拡張します。メッセージのプロトコル固有の側面へのアクセスは提供しません。プロトコルバインディングは、論理メッセージコンテキストを介して使用できるメッセージのコンポーネントを定義します。SOAP バインディングにデプロイされた論理ハンドラーは SOAP ボディーのコンテンツにアクセスできますが、SOAP ヘッダーにはアクセスできません。一方、XML/HTTP バインディングは論理ハンドラーがメッセージの XML ペイロード全体にアクセスできることを定義します。
SOAP メッセージコンテキスト
SOAP ハンドラーが呼び出されると、SOAPMessageContext を受け取ります。SOAPMessageContextMessageContext を SOAP メッセージペイロードを取得および変更するメソッドで拡張します。

障害処理

アプリケーションが SOAPFaultException またはアプリケーション固有のユーザー例外を出力する可能性があります。後者の場合、必要な障害ラッパー Bean がデプロイメントに含まれていない場合は、ランタイム時に生成されます。

public void throwSoapFaultException() {
   SOAPFactory factory = SOAPFactory.newInstance();
   SOAPFault fault = factory.createFault("this is a fault string!", new QName("http://foo", "FooCode"));
   fault.setFaultActor("mr.actor");
   fault.addDetail().addChildElement("test");
   throw new SOAPFaultException(fault);
}
public void throwApplicationException() throws UserException {
   throw new UserException("validation", 123, "Some validation error");
}

Jakarta XML Web Services のアノテーション

Jakarta XML Web Services API で利用可能なアノテーションは、Jakarta XML Web Services Specification 2.3 仕様 で定義されています。これらのアノテーションは javax.xml.ws パッケージにあります。

JWS API で利用可能なアノテーションは、Web Services Metadata で定義され、Jakarta Web Services Metadata Specification 2.1 仕様 にあります。これらのアノテーションは javax.jws パッケージにあります。

A.8. 高度な WS-Trust シナリオ

A.8.1. シナリオ: SAML Holder-Of-Key Assertion シナリオ

WS-Trust は、ソフトウェアセキュリティートークンの管理に役立ちます。SAML アサーションは、セキュリティートークンのタイプです。Holder-Of-Key メソッドでは、STS はクライアントの公開鍵を含む SAML トークンを作成し、その秘密鍵で SAML トークンに署名します。クライアントには SAML トークンが含まれ、その秘密鍵で Web サービスへ発進 soap エンベロープを署名します。Web サービスは SOAP メッセージと SAML トークンを検証します。

このシナリオの実装には、以下が必要になります。

  • キーサブジェクトの確認メソッド Holder-Of-Key を持つ SAML トークンは、トークンをスヌーピングできないように保護する必要があります。多くの場合、トークンの所有を防ぐには、HTTPS と組み合わせたホルダーのキートークンで十分です。これは、セキュリティーポリシーが sp:TransportBinding および sp:HttpsToken を使用することを意味します。
  • Holder-Of-Key トークンには暗号化または署名キーがないため、SymmetricKey または PublicKeysp:IssuedTokensp:SignedEndorsingSupportingTokens とともに使用する必要があります。

A.8.1.1. Web サービスプロバイダー

本セクションでは、SAML Holder-Of-Key シナリオの web サービス要素の一覧を紹介します。コンポーネントには以下が含まれます。

A.8.1.1.1. Web Service Provider WSDL

Web Service Provider はコントラクトファーストエンドポイントです。その WS-trust とセキュリティーポリシーはすべて HolderOfKeyService.wsdl WSDL で宣言されます。このシナリオでは、指定された STS から発行される SymmetricKey の SAML 2.0 トークンを提供するには、ws-requester が必要です。STS アドレスは、WSDL に提供されます。トランスポートバインディングポリシーが使用されます。トークンは署名と、sp:SignedEndorsingSupportingTokens に宣言されます。

セキュリティー設定の詳細は、以下の一覧のコメントに記載されています。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/holderofkeywssecuritypolicy"
             name="HolderOfKeyService"
        xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/holderofkeywssecuritypolicy"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns="http://schemas.xmlsoap.org/wsdl/"
        xmlns:wsp="http://www.w3.org/ns/ws-policy"
        xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:wsaws="http://www.w3.org/2005/08/addressing"
    xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"
    xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
    xmlns:t="http://docs.oasis-open.org/ws-sx/ws-trust/200512">

  <types>
    <xsd:schema>
      <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/holderofkeywssecuritypolicy"
                  schemaLocation="HolderOfKeyService_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="sayHello">
    <part name="parameters" element="tns:sayHello"/>
  </message>
  <message name="sayHelloResponse">
    <part name="parameters" element="tns:sayHelloResponse"/>
  </message>
  <portType name="HolderOfKeyIface">
    <operation name="sayHello">
      <input message="tns:sayHello"/>
      <output message="tns:sayHelloResponse"/>
    </operation>
  </portType>
<!--
        The wsp:PolicyReference binds the security requirements on all the endpoints.
        The wsp:Policy wsu:Id="#TransportSAML2HolderOfKeyPolicy" element is defined later in this file.
-->
  <binding name="HolderOfKeyServicePortBinding" type="tns:HolderOfKeyIface">
    <wsp:PolicyReference URI="#TransportSAML2HolderOfKeyPolicy" />
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="sayHello">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
<!--
  The soap:address has been defined to use JBoss's https port, 8443.  This is
  set in conjunction with the sp:TransportBinding policy for https.
-->
  <service name="HolderOfKeyService">
    <port name="HolderOfKeyServicePort" binding="tns:HolderOfKeyServicePortBinding">
      <soap:address location="https://@jboss.bind.address@:8443/jaxws-samples-wsse-policy-trust-holderofkey/HolderOfKeyService"/>
    </port>
  </service>


  <wsp:Policy wsu:Id="TransportSAML2HolderOfKeyPolicy">
    <wsp:ExactlyOne>
      <wsp:All>
  <!--
        The wsam:Addressing element, indicates that the endpoints of this
        web service MUST conform to the WS-Addressing specification.  The
        attribute wsp:Optional="false" enforces this assertion.
  -->
        <wsam:Addressing wsp:Optional="false">
          <wsp:Policy />
        </wsam:Addressing>
<!--
  The sp:TransportBinding element indicates that security is provided by the
  message exchange transport medium, https.  WS-Security policy specification
  defines the sp:HttpsToken for use in exchanging messages transmitted over HTTPS.
-->
          <sp:TransportBinding
            xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
            <wsp:Policy>
              <sp:TransportToken>
                <wsp:Policy>
                  <sp:HttpsToken>
                    <wsp:Policy/>
                  </sp:HttpsToken>
                </wsp:Policy>
              </sp:TransportToken>
<!--
     The sp:AlgorithmSuite element, requires the TripleDes algorithm suite
     be used in performing cryptographic operations.
-->
              <sp:AlgorithmSuite>
                <wsp:Policy>
                  <sp:TripleDes />
                </wsp:Policy>
              </sp:AlgorithmSuite>
<!--
     The sp:Layout element,  indicates the layout rules to apply when adding
     items to the security header.  The sp:Lax sub-element indicates items
     are added to the security header in any order that conforms to
     WSS: SOAP Message Security.
-->
              <sp:Layout>
                <wsp:Policy>
                  <sp:Lax />
                </wsp:Policy>
              </sp:Layout>
              <sp:IncludeTimestamp />
            </wsp:Policy>
          </sp:TransportBinding>

<!--
  The sp:SignedEndorsingSupportingTokens, when transport level security level is
  used there will be no message signature and the signature generated by the
  supporting token will sign the Timestamp.
-->
        <sp:SignedEndorsingSupportingTokens
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
<!--
  The sp:IssuedToken element asserts that a SAML 2.0 security token of type
  Bearer is expected from the STS.  The
  sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
  attribute instructs the runtime to include the initiator's public key
  with every message sent to the recipient.

  The sp:RequestSecurityTokenTemplate element directs that all of the
  children of this element will be copied directly into the body of the
  RequestSecurityToken (RST) message that is sent to the STS when the
  initiator asks the STS to issue a token.
-->
            <sp:IssuedToken
              sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
              <sp:RequestSecurityTokenTemplate>
                <t:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</t:TokenType>
 <!--
   KeyType of "SymmetricKey", the client must prove to the WS service that it
   possesses a particular symmetric session key.
 -->
                <t:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</t:KeyType>
              </sp:RequestSecurityTokenTemplate>
              <wsp:Policy>
                <sp:RequireInternalReference />
              </wsp:Policy>
<!--
  The sp:Issuer element defines the STS's address and endpoint information
  This information is used by the STSClient.
-->
              <sp:Issuer>
                <wsaws:Address>http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-sts-holderofkey/SecurityTokenService</wsaws:Address>
                <wsaws:Metadata
                  xmlns:wsdli="http://www.w3.org/2006/01/wsdl-instance"
                  wsdli:wsdlLocation="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-sts-holderofkey/SecurityTokenService?wsdl">
                  <wsaw:ServiceName
                    xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
                    xmlns:stsns="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
                    EndpointName="UT_Port">stsns:SecurityTokenService</wsaw:ServiceName>
                </wsaws:Metadata>
              </sp:Issuer>

            </sp:IssuedToken>
          </wsp:Policy>
        </sp:SignedEndorsingSupportingTokens>
<!--
    The sp:Wss11 element declares WSS: SOAP Message Security 1.1 options
    to be supported by the STS.  These particular elements generally refer
    to how keys are referenced within the SOAP envelope.  These are normally handled by Apache CXF.
-->
        <sp:Wss11>
          <wsp:Policy>
            <sp:MustSupportRefIssuerSerial />
            <sp:MustSupportRefThumbprint />
            <sp:MustSupportRefEncryptedKey />
          </wsp:Policy>
        </sp:Wss11>
<!--
    The sp:Trust13 element declares controls for WS-Trust 1.3 options.
    They are policy assertions related to exchanges specifically with
    client and server challenges and entropy behaviors.  Again these are
    normally handled by Apache CXF.
-->
        <sp:Trust13>
          <wsp:Policy>
            <sp:MustSupportIssuedTokens />
            <sp:RequireClientEntropy />
            <sp:RequireServerEntropy />
          </wsp:Policy>
        </sp:Trust13>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

</definitions>
A.8.1.1.2. SSL 設定

この Web サービスは HTTPS を使用するため、undertow サブシステムで SSL/TLS サポートを提供するよう JBoss EAP サーバーを設定する必要があります。

Web アプリケーションの HTTPS 設定に関する詳細は、How to Configure Server SecurityConfigure One-way and Two-way SSL/TLS for Applications を参照してください。

A.8.1.1.3. Web Service Provider インターフェイス

Web サービスプロバイダーのインターフェイス HolderOfKeyIface クラスは、簡単な Web サービス定義です。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.holderofkey;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
(
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/holderofkeywssecuritypolicy"
)
public interface HolderOfKeyIface {
   @WebMethod
   String sayHello();
}
A.8.1.1.4. Web Service Provider の実装

Web サービス実装の HolderOfKeyImpl クラスは単純な POJO です。標準の WebService アノテーションを使用してサービスのエンドポイントを定義します。さらに、Apache CXF ランタイムのエンドポイントを設定するために使用される EndpointProperties および EndpointProperty には、Apache CXF アノテーションがあります。これらのアノテーションは、Web サービスの主な WS-Security 標準を Java で実装する Apache WSS4J プロジェクトから提供されます。これらのアノテーションは、プログラムでプロパティーをエンドポイントに追加します。プレーン Apache CXF では、これらのプロパティーは、Spring 設定の <jaxws:endpoint> 要素で <jaxws:properties> 要素を使用して設定されることがよくあります。これらのアノテーションにより、プロパティーをコードに設定できます。

WSS4J は、Crypto インターフェイスを使用して、署名の作成/検証に使用するキーと証明書を取得します。これは、このサービスの WSDL によってアサートされます。HolderOfKeyImpl が提供する WSS4J 設定情報は Crypto の Merlin 実装用です。

最初の EndpointProperty ステートメントは、Basic Security Profile 1.1 への準拠を無効にします。次の EndpointProperty ステートメントは、(Merlin) Crypto 設定情報を含む Java プロパティーファイルを宣言します。最後の EndpointProperty ステートメントは STSHolderOfKeyCallbackHandler 実装クラスを宣言します。これは、キーストアファイルの証明書のユーザーパスワードを取得するために使用されます。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.holderofkey;

import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;

import javax.jws.WebService;

@WebService
   (
      portName = "HolderOfKeyServicePort",
      serviceName = "HolderOfKeyService",
      wsdlLocation = "WEB-INF/wsdl/HolderOfKeyService.wsdl",
      targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/holderofkeywssecuritypolicy",
      endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.holderofkey.HolderOfKeyIface"
   )
@EndpointProperties(value = {
   @EndpointProperty(key = "ws-security.is-bsp-compliant", value = "false"),
   @EndpointProperty(key = "ws-security.signature.properties", value = "serviceKeystore.properties"),
   @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.holderofkey.HolderOfKeyCallbackHandler")
})
public class HolderOfKeyImpl implements HolderOfKeyIface {
   public String sayHello() {
      return "Holder-Of-Key WS-Trust Hello World!";
   }
}
A.8.1.1.5. 暗号化プロパティーおよびキーストアファイル

WSS4J の Crypto 実装は、Crypto 設定データを含む Java プロパティーファイルを使用してロードおよび設定されます。このファイルには、キーストアの場所、パスワード、デフォルトエイリアスなどの実装固有のプロパティーが含まれます。このアプリケーションは Merlin 実装を使用します。ServiceKeystore.properties ファイルにはこの情報が含まれます。

servicestore.jks ファイルは Java KeyStore (JKS) リポジトリーです。これには、myservicekey および mystskey の自己署名証明書が含まれています。

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=sspass
org.apache.ws.security.crypto.merlin.keystore.alias=myservicekey
org.apache.ws.security.crypto.merlin.keystore.file=servicestore.jks
A.8.1.1.6. デフォルトの MANIFEST.MF

このアプリケーションには、org.jboss.ws.cxf.jbossws-cxf-client モジュールで提供される JBossWS および Apache CXF API へのアクセスが必要です。依存関係ステートメントは、デプロイメント時に提供するようサーバーに指示します。

Manifest-Version: 1.0
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client

A.8.2. シナリオ: SAML Bearer Assertion

WS-Trust は、ソフトウェアセキュリティートークンを管理します。SAML アサーションは、セキュリティートークンのタイプです。SAML Bearer シナリオでは、サービスプロバイダーは、サービスがトークンの署名を検証した後に SAML トークンで定義されたサブジェクトから受信 SOAP リクエストが送信されたことを自動的に信頼します。

このシナリオの実装には、以下の要件があります。

  • Bearer サブジェクト確認メソッドを持つ SAML トークンは、トークンをスヌーピングしないように保護する必要があります。多くの場合、HTTPS と組み合わせてベアラートークンを使用することで、a man in the middle(中間者) によるトークンの所有を防ぐだけで十分です。これは、sp:TransportBinding および sp:HttpsToken を使用するセキュリティーポリシーを意味します。
  • ベアラートークンには暗号化または署名キーがないため、bearer keyType の sp:IssuedTokensp:SupportingToken または sp:SignedSupportingTokens とともに使用する必要があります。

A.8.2.1. Web サービスプロバイダー

本セクションでは、SAML Bearer シナリオの web サービス要素を検証します。コンポーネントには以下が含まれます。

A.8.2.1.1. Bearer Web Service Provider WSDL

Web サービスプロバイダーは、コントラクトファーストエンドポイントです。このファイルの WS-trust とセキュリティーポリシーはすべて BearerService.wsdl WSDL で宣言されます。このシナリオでは、指定された STS から発行される SAML 2.0 Bearer トークンを提供するには、ws-requester が必要です。STS のアドレスが WSDL に提供されます。HTTPS、TransportBinding、および HttpsToken ポリシーは HttpsToken ポリシーを使用して、ws-requester および ws-provider の間で送信されるメッセージの SOAP ボディーを保護します。セキュリティー設定の詳細は、以下の一覧にコメントとして提供されます。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/bearerwssecuritypolicy"
             name="BearerService"
             xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/bearerwssecuritypolicy"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:wsp="http://www.w3.org/ns/ws-policy"
             xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
             xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
             xmlns:wsaws="http://www.w3.org/2005/08/addressing"
             xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"
             xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
             xmlns:t="http://docs.oasis-open.org/ws-sx/ws-trust/200512">

  <types>
    <xsd:schema>
      <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/bearerwssecuritypolicy"
                  schemaLocation="BearerService_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="sayHello">
    <part name="parameters" element="tns:sayHello"/>
  </message>
  <message name="sayHelloResponse">
    <part name="parameters" element="tns:sayHelloResponse"/>
  </message>
  <portType name="BearerIface">
    <operation name="sayHello">
      <input message="tns:sayHello"/>
      <output message="tns:sayHelloResponse"/>
    </operation>
  </portType>

<!--
        The wsp:PolicyReference binds the security requirments on all the endpoints.
        The wsp:Policy wsu:Id="#TransportSAML2BearerPolicy" element is defined later in this file.
-->
  <binding name="BearerServicePortBinding" type="tns:BearerIface">
    <wsp:PolicyReference URI="#TransportSAML2BearerPolicy" />
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="sayHello">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>

<!--
  The soap:address has been defined to use JBoss's https port, 8443.  This is
  set in conjunction with the sp:TransportBinding policy for https.
-->
  <service name="BearerService">
    <port name="BearerServicePort" binding="tns:BearerServicePortBinding">
      <soap:address location="https://@jboss.bind.address@:8443/jaxws-samples-wsse-policy-trust-bearer/BearerService"/>
    </port>
  </service>


  <wsp:Policy wsu:Id="TransportSAML2BearerPolicy">
    <wsp:ExactlyOne>
      <wsp:All>
  <!--
        The wsam:Addressing element, indicates that the endpoints of this
        web service MUST conform to the WS-Addressing specification.  The
        attribute wsp:Optional="false" enforces this assertion.
  -->
        <wsam:Addressing wsp:Optional="false">
          <wsp:Policy />
        </wsam:Addressing>

<!--
  The sp:TransportBinding element indicates that security is provided by the
  message exchange transport medium, https.  WS-Security policy specification
  defines the sp:HttpsToken for use in exchanging messages transmitted over HTTPS.
-->
        <sp:TransportBinding
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:TransportToken>
              <wsp:Policy>
                <sp:HttpsToken>
                  <wsp:Policy/>
                </sp:HttpsToken>
              </wsp:Policy>
            </sp:TransportToken>
<!--
     The sp:AlgorithmSuite element, requires the TripleDes algorithm suite
     be used in performing cryptographic operations.
-->
            <sp:AlgorithmSuite>
              <wsp:Policy>
                <sp:TripleDes />
              </wsp:Policy>
            </sp:AlgorithmSuite>
<!--
     The sp:Layout element,  indicates the layout rules to apply when adding
     items to the security header.  The sp:Lax sub-element indicates items
     are added to the security header in any order that conforms to
     WSS: SOAP Message Security.
-->
            <sp:Layout>
              <wsp:Policy>
                <sp:Lax />
              </wsp:Policy>
            </sp:Layout>
            <sp:IncludeTimestamp />
          </wsp:Policy>
        </sp:TransportBinding>

<!--
  The sp:SignedSupportingTokens element causes the supporting tokens
  to be signed using the primary token that is used to sign the message.
-->
        <sp:SignedSupportingTokens
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
<!--
  The sp:IssuedToken element asserts that a SAML 2.0 security token of type
  Bearer is expected from the STS.  The
  sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
  attribute instructs the runtime to include the initiator's public key
  with every message sent to the recipient.

  The sp:RequestSecurityTokenTemplate element directs that all of the
  children of this element will be copied directly into the body of the
  RequestSecurityToken (RST) message that is sent to the STS when the
  initiator asks the STS to issue a token.
-->
            <sp:IssuedToken
              sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
              <sp:RequestSecurityTokenTemplate>
                <t:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</t:TokenType>
                <t:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</t:KeyType>
              </sp:RequestSecurityTokenTemplate>
              <wsp:Policy>
                <sp:RequireInternalReference />
              </wsp:Policy>
<!--
  The sp:Issuer element defines the STS's address and endpoint information
  This information is used by the STSClient.
-->
              <sp:Issuer>
                <wsaws:Address>http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-sts-bearer/SecurityTokenService</wsaws:Address>
                <wsaws:Metadata
                  xmlns:wsdli="http://www.w3.org/2006/01/wsdl-instance"
                  wsdli:wsdlLocation="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-sts-bearer/SecurityTokenService?wsdl">
                  <wsaw:ServiceName
                    xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
                    xmlns:stsns="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
                    EndpointName="UT_Port">stsns:SecurityTokenService</wsaw:ServiceName>
                </wsaws:Metadata>
              </sp:Issuer>

            </sp:IssuedToken>
          </wsp:Policy>
        </sp:SignedSupportingTokens>
<!--
    The sp:Wss11 element declares WSS: SOAP Message Security 1.1 options
    to be supported by the STS.  These particular elements generally refer
    to how keys are referenced within the SOAP envelope.  These are normally handled by Apache CXF.
-->
        <sp:Wss11>
          <wsp:Policy>
            <sp:MustSupportRefIssuerSerial />
            <sp:MustSupportRefThumbprint />
            <sp:MustSupportRefEncryptedKey />
          </wsp:Policy>
        </sp:Wss11>
<!--
    The sp:Trust13 element declares controls for WS-Trust 1.3 options.
    They are policy assertions related to exchanges specifically with
    client and server challenges and entropy behaviors.  Again these are
    normally handled by Apache CXF.
-->
        <sp:Trust13>
          <wsp:Policy>
            <sp:MustSupportIssuedTokens />
            <sp:RequireClientEntropy />
            <sp:RequireServerEntropy />
          </wsp:Policy>
        </sp:Trust13>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

</definitions>
A.8.2.1.2. SSL 設定

この Web サービスは HTTPS を使用します。そのため、undertow サブシステムで SSL サポートを提供するよう JBoss EAP サーバーを設定する必要があります。

Web アプリケーションの HTTPS 設定に関する詳細は、How to Configure Server SecurityConfigure One-way and Two-way SSL/TLS for Applications を参照してください。

A.8.2.1.3. Bearer Web Service Providers Interface

BearerIface Bearer Web Service Provider Interface クラスは簡単な Web サービス定義です。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.bearer;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
(
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/bearerwssecuritypolicy"
)
public interface BearerIface {
   @WebMethod
   String sayHello();
}
A.8.2.1.4. Bearer Web Service Providers 実装

BearerImpl Web Service Provider Implementation クラスは単純な POJO です。標準の WebService アノテーションを使用してサービスのエンドポイントを定義します。さらに、Apache CXF ランタイムのエンドポイントを設定するために使用される EndpointProperties および EndpointProperty には、Apache CXF アノテーションがあります。これらのアノテーションは、Web サービスの主な WS-Security 標準を Java で実装する Apache WSS4J プロジェクトから提供されます。これらのアノテーションは、プログラムでプロパティーをエンドポイントに追加します。プレーン Apache CXF では、これらのプロパティーは、Spring 設定の <jaxws:endpoint> 要素で <jaxws:properties> 要素を使用して設定されることがよくあります。これらのアノテーションにより、プロパティーをコードに設定できます。

WSS4J は、Crypto インターフェイスを使用して、署名の作成/検証に使用するキーと証明書を取得します。これは、このサービスの WSDL によってアサートされます。BearerImpl が提供する WSS4J 設定情報は、Crypto の Merlin 実装用です。

Web サービスプロバイダーは SAML トークンで定義されたサブジェクトから受信した受信 SOAP リクエストを自動的に信頼します。そのため、以前の例とは異なり、Crypto CallbackHandler クラスや署名ユーザー名では必要ありません。ただし、メッセージ署名を検証するには、(Merlin) 暗号化設定情報を含む Java プロパティーファイルが必要になります。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.bearer;

import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;

import javax.jws.WebService;

@WebService
(
   portName = "BearerServicePort",
   serviceName = "BearerService",
   wsdlLocation = "WEB-INF/wsdl/BearerService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/bearerwssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.bearer.BearerIface"
)
@EndpointProperties(value = {
   @EndpointProperty(key = "ws-security.signature.properties", value = "serviceKeystore.properties")
})
public class BearerImpl implements BearerIface {
   public String sayHello() {
      return "Bearer WS-Trust Hello World!";
   }
}
A.8.2.1.5. 暗号化プロパティーおよびキーストアファイル

WSS4J の Crypto 実装は、Crypto 設定データを含む Java プロパティーファイルを使用してロードおよび設定されます。このファイルには、キーストアの場所、パスワード、デフォルトエイリアスなどの実装固有のプロパティーが含まれます。このアプリケーションは、Merlin 実装を使用します。ServiceKeystore.properties ファイルにはこの情報が含まれます。

servicestore.jks ファイルは Java KeyStore (JKS) リポジトリーです。これには、myservicekey および mystskey の自己署名証明書が含まれています。

注記

自己署名証明書は、実稼働環境での使用には適していません。

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=sspass
org.apache.ws.security.crypto.merlin.keystore.alias=myservicekey
org.apache.ws.security.crypto.merlin.keystore.file=servicestore.jks
A.8.2.1.6. デフォルトの MANIFEST.MF

このアプリケーションがデプロイされると、org.jboss.ws.cxf.jbossws-cxf-client モジュールで提供される JBossWS および Apache CXF API へのアクセスが必要になります。依存関係ステートメントは、デプロイメント時に提供するようサーバーに指示します。

Manifest-Version: 1.0
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client

A.8.2.2. Bearer Security トークンサービス

本セクションでは、SAML Bearer トークンを提供する Security Token Service 機能を提供するために重要な要素を説明します。コンポーネントには以下が含まれます。

A.8.2.2.1. セキュリティードメイン

STS では JBoss セキュリティードメインを設定する必要があります。Jboss-web.xml 記述子は JBossWS-trust-sts という名前のセキュリティードメインを宣言し、認証にこのサービスによって使用されます。このセキュリティードメインには、プロパティーファイルと、JBoss EAP サーバー設定ファイルにセキュリティードメイン宣言を追加する必要があります。

このシナリオでは、ドメインにユーザー alice、パスワード clarinet、ロール friend を含める必要があります。jbossws-users.properties および jbossws-roles.properties の以下のリストを参照してください。さらに、以下の XML をサーバー設定ファイルの JBoss security サブシステムに追加する必要があります。

注記

SOME_PATH を適切な情報に置き換えてください。

<security-domain name="JBossWS-trust-sts">
  <authentication>
    <login-module code="UsersRoles" flag="required">
      <module-option name="usersProperties" value="/SOME_PATH/jbossws-users.properties"/>
      <module-option name="unauthenticatedIdentity" value="anonymous"/>
      <module-option name="rolesProperties" value="/SOME_PATH/jbossws-roles.properties"/>
    </login-module>
  </authentication>
</security-domain>

例: jboss-web.xml ファイル

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.4//EN" ">
<jboss-web>
  <security-domain>java:/jaas/JBossWS-trust-sts</security-domain>
</jboss-web>

例: .jbossws-users.properties ファイル

# A sample users.properties file for use with the UsersRolesLoginModule
alice=clarinet

例: jbossws-roles.properties ファイル

# A sample roles.properties file for use with the UsersRolesLoginModule
alice=friend

A.8.2.2.2. STS WSDL
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
  targetNamespace="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
  xmlns:tns="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
  xmlns:wstrust="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:wsap10="http://www.w3.org/2006/05/addressing/wsdl"
  xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
  xmlns:wsp="http://www.w3.org/ns/ws-policy"
  xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata">

  <wsdl:types>
    <xs:schema elementFormDefault="qualified"
               targetNamespace='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>

      <xs:element name='RequestSecurityToken'
                  type='wst:AbstractRequestSecurityTokenType'/>
      <xs:element name='RequestSecurityTokenResponse'
                  type='wst:AbstractRequestSecurityTokenType'/>

      <xs:complexType name='AbstractRequestSecurityTokenType'>
        <xs:sequence>
          <xs:any namespace='##any' processContents='lax' minOccurs='0'
                  maxOccurs='unbounded'/>
        </xs:sequence>
        <xs:attribute name='Context' type='xs:anyURI' use='optional'/>
        <xs:anyAttribute namespace='##other' processContents='lax'/>
      </xs:complexType>
      <xs:element name='RequestSecurityTokenCollection'
                  type='wst:RequestSecurityTokenCollectionType'/>
      <xs:complexType name='RequestSecurityTokenCollectionType'>
        <xs:sequence>
          <xs:element name='RequestSecurityToken'
                      type='wst:AbstractRequestSecurityTokenType' minOccurs='2'
                      maxOccurs='unbounded'/>
        </xs:sequence>
      </xs:complexType>

      <xs:element name='RequestSecurityTokenResponseCollection'
                  type='wst:RequestSecurityTokenResponseCollectionType'/>
      <xs:complexType name='RequestSecurityTokenResponseCollectionType'>
        <xs:sequence>
          <xs:element ref='wst:RequestSecurityTokenResponse' minOccurs='1'
                      maxOccurs='unbounded'/>
        </xs:sequence>
        <xs:anyAttribute namespace='##other' processContents='lax'/>
      </xs:complexType>

    </xs:schema>
  </wsdl:types>

  <!-- WS-Trust defines the following GEDs -->
  <wsdl:message name="RequestSecurityTokenMsg">
    <wsdl:part name="request" element="wst:RequestSecurityToken"/>
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenResponseMsg">
    <wsdl:part name="response"
               element="wst:RequestSecurityTokenResponse"/>
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenCollectionMsg">
    <wsdl:part name="requestCollection"
               element="wst:RequestSecurityTokenCollection"/>
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenResponseCollectionMsg">
    <wsdl:part name="responseCollection"
               element="wst:RequestSecurityTokenResponseCollection"/>
  </wsdl:message>

  <!-- This portType an example of a Requestor (or other) endpoint that
  Accepts SOAP-based challenges from a Security Token Service -->
  <wsdl:portType name="WSSecurityRequestor">
    <wsdl:operation name="Challenge">
      <wsdl:input message="tns:RequestSecurityTokenResponseMsg"/>
      <wsdl:output message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
  </wsdl:portType>

  <!-- This portType is an example of an STS supporting full protocol -->
  <!--
      The wsdl:portType and data types are XML elements defined by the
      WS_Trust specification.  The wsdl:portType defines the endpoints
      supported in the STS implementation.  This WSDL defines all operations
      that an STS implementation can support.
  -->
  <wsdl:portType name="STS">
    <wsdl:operation name="Cancel">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Cancel"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/CancelFinal"
        message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Issue">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal"
        message="tns:RequestSecurityTokenResponseCollectionMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Renew">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Renew"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/RenewFinal"
        message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Validate">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Validate"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/ValidateFinal"
        message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="KeyExchangeToken">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/KET"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/KETFinal"
        message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="RequestCollection">
      <wsdl:input message="tns:RequestSecurityTokenCollectionMsg"/>
      <wsdl:output message="tns:RequestSecurityTokenResponseCollectionMsg"/>
    </wsdl:operation>
  </wsdl:portType>

  <!-- This portType is an example of an endpoint that accepts
  Unsolicited RequestSecurityTokenResponse messages -->
  <wsdl:portType name="SecurityTokenResponseService">
    <wsdl:operation name="RequestSecurityTokenResponse">
      <wsdl:input message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
  </wsdl:portType>

  <!--
      The wsp:PolicyReference binds the security requirments on all the STS endpoints.
      The wsp:Policy wsu:Id="UT_policy" element is later in this file.
  -->
  <wsdl:binding name="UT_Binding" type="wstrust:STS">
    <wsp:PolicyReference URI="#UT_policy"/>
    <soap:binding style="document"
                  transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="Issue">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue"/>
      <wsdl:input>
        <wsp:PolicyReference
          URI="#Input_policy"/>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <wsp:PolicyReference
          URI="#Output_policy"/>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Validate">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Validate"/>
      <wsdl:input>
        <wsp:PolicyReference
          URI="#Input_policy"/>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <wsp:PolicyReference
          URI="#Output_policy"/>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Cancel">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Cancel"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Renew">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Renew"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="KeyExchangeToken">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/KeyExchangeToken"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="RequestCollection">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/RequestCollection"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>

  <wsdl:service name="SecurityTokenService">
    <wsdl:port name="UT_Port" binding="tns:UT_Binding">
      <soap:address location="http://localhost:8080/SecurityTokenService/UT"/>
    </wsdl:port>
  </wsdl:service>


  <wsp:Policy wsu:Id="UT_policy">
    <wsp:ExactlyOne>
      <wsp:All>
        <!--
            The sp:UsingAddressing element, indicates that the endpoints of this
            web service conforms to the WS-Addressing specification.  More detail
            can be found here: [http://www.w3.org/TR/2006/CR-ws-addr-wsdl-20060529]
        -->
        <wsap10:UsingAddressing/>
        <!--
            The sp:SymmetricBinding element indicates that security is provided
            at the SOAP layer and any initiator must authenticate itself by providing
            WSS UsernameToken credentials.
        -->
        <sp:SymmetricBinding
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <!--
                In a symmetric binding, the keys used for encrypting and signing in both
                directions are derived from a single key, the one specified by the
                sp:ProtectionToken element.  The sp:X509Token sub-element declares this
                key to be a X.509 certificate and the
                IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never"
                attribute adds the requirement that the token MUST NOT be included in
                any messages sent between the initiator and the recipient; rather, an
                external reference to the token should be used.  Lastly the WssX509V3Token10
                sub-element declares that the Username token presented by the initiator
                should be compliant with Web Services Security UsernameToken Profile
                1.0 specification. [ http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0.pdf ]
            -->
            <sp:ProtectionToken>
              <wsp:Policy>
                <sp:X509Token
                  sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
                  <wsp:Policy>
                    <sp:RequireDerivedKeys/>
                    <sp:RequireThumbprintReference/>
                    <sp:WssX509V3Token10/>
                  </wsp:Policy>
                </sp:X509Token>
              </wsp:Policy>
            </sp:ProtectionToken>
            <!--
                The sp:AlgorithmSuite element, requires the Basic256 algorithm suite
                be used in performing cryptographic operations.
            -->
            <sp:AlgorithmSuite>
              <wsp:Policy>
                <sp:Basic256/>
              </wsp:Policy>
            </sp:AlgorithmSuite>
            <!--
                The sp:Layout element,  indicates the layout rules to apply when adding
                items to the security header.  The sp:Lax sub-element indicates items
                are added to the security header in any order that conforms to
                WSS: SOAP Message Security.
            -->
            <sp:Layout>
              <wsp:Policy>
                <sp:Lax/>
              </wsp:Policy>
            </sp:Layout>
            <sp:IncludeTimestamp/>
            <sp:EncryptSignature/>
            <sp:OnlySignEntireHeadersAndBody/>
          </wsp:Policy>
        </sp:SymmetricBinding>

        <!--
            The sp:SignedSupportingTokens element declares that the security header
            of messages must contain a sp:UsernameToken and the token must be signed.
            The attribute IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"
            on sp:UsernameToken indicates that the token MUST be included in all
            messages sent from initiator to the recipient and that the token MUST
            NOT be included in messages sent from the recipient to the initiator.
            And finally the element sp:WssUsernameToken10 is a policy assertion
            indicating the Username token should be as defined in  Web Services
            Security UsernameToken Profile 1.0
        -->
        <sp:SignedSupportingTokens
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:UsernameToken
              sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
              <wsp:Policy>
                <sp:WssUsernameToken10/>
              </wsp:Policy>
            </sp:UsernameToken>
          </wsp:Policy>
        </sp:SignedSupportingTokens>
        <!--
            The sp:Wss11 element declares WSS: SOAP Message Security 1.1 options
            to be supported by the STS.  These particular elements generally refer
            to how keys are referenced within the SOAP envelope.  These are normally
            handled by Apache CXF.
        -->
        <sp:Wss11
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:MustSupportRefKeyIdentifier/>
            <sp:MustSupportRefIssuerSerial/>
            <sp:MustSupportRefThumbprint/>
            <sp:MustSupportRefEncryptedKey/>
          </wsp:Policy>
        </sp:Wss11>
        <!--
            The sp:Trust13 element declares controls for WS-Trust 1.3 options.
            They are policy assertions related to exchanges specifically with
            client and server challenges and entropy behaviors.  Again these are
            normally handled by Apache CXF.
        -->
        <sp:Trust13
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:MustSupportIssuedTokens/>
            <sp:RequireClientEntropy/>
            <sp:RequireServerEntropy/>
          </wsp:Policy>
        </sp:Trust13>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

  <wsp:Policy wsu:Id="Input_policy">
    <wsp:ExactlyOne>
      <wsp:All>
        <sp:SignedParts
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <sp:Body/>
          <sp:Header Name="To"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="From"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="FaultTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="ReplyTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="MessageID"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="RelatesTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="Action"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
        </sp:SignedParts>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

  <wsp:Policy wsu:Id="Output_policy">
    <wsp:ExactlyOne>
      <wsp:All>
        <sp:SignedParts
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <sp:Body/>
          <sp:Header Name="To"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="From"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="FaultTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="ReplyTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="MessageID"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="RelatesTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="Action"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
        </sp:SignedParts>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

</wsdl:definitions>
A.8.2.2.3. STS 実装クラス

Apache CXF の SecurityTokenServiceProvider は、WS-Trust 仕様で定義されているプロトコルおよび機能に準拠する Web サービスプロバイダーです。モジュールアーキテクチャーがあり、そのコンポーネントは設定可能または置き換え可能です。プラグインは実装および設定することで有効にされるオプション機能があります。SecurityTokenServiceProvider から拡張し、デフォルト設定を上書きすることで、独自の STS をカスタマイズできます。

SampleSTSBearer STS 実装クラスは、SecurityTokenServiceProvider から拡張される属性です。

注記

SampleSTSBearer クラスは WebService アノテーションではなく、WebServiceProvider アノテーションで定義されます。このアノテーションは、Provider サービスをプロバイダーベースのエンドポイントとして定義し、Web サービスへのメッセージング指向アプローチをサポートします。特に、交換したメッセージが XML ドキュメントであることを示唆します。SecurityTokenServiceProviderjavax.xml.ws.Provider インターフェイスの実装です。一方、WebService アノテーションは SOAP レンダリングを使用したメッセージ交換をサポートするサービスエンドポイントのインターフェイスベースのエンドポイントを定義します。

BearerImpl クラスで行ったように WSS4J アノテーションの EndpointProperties および EndpointProperty は Apache CXF ランタイムのエンドポイント設定を提供します。最初の EndpointProperty ステートメントは、メッセージ署名に使用するユーザーの名前を宣言します。これは、キーストアのエイリアス名として使用され、署名用にユーザーの証明書および秘密鍵を取得します。次の EndpointProperty ステートメントは、(Merlin) Crypto 設定情報を含む Java プロパティーを宣言します。この場合、メッセージの署名および暗号化の両方を行います。WSS4J はこのファイルと、メッセージ処理に必要な情報を読み取ります。最後の EndpointProperty ステートメントは STSBearerCallbackHandler 実装クラスを宣言します。これは、キーストアファイルの証明書のユーザーパスワードを取得するために使用されます。

この実装では、トークンの発行、トークンの検証、および静的なプロパティーの操作をカスタマイズします。

StaticSTSProperties は、STS でリソースを設定するための選択プロパティーを設定するために使用されます。これは、WSS4J アノテーションの設定の重複のように表示されます。値は同じですが、設定される基礎の構造は異なるため、この情報は両方の場所で宣言する必要があります。

setIssuer 設定は、発行している STS を一意に識別するため、重要です。発行者文字列は発行されたトークンに組み込まれ、トークンを検証すると、STS は発行者の文字列値を確認します。したがって、STS が発行されたトークンを認識できるように、一貫性のある方法で発行者の文字列を使用することが重要になります。

setEndpoints 呼び出しは、アドレス別に許可されるトークン受信側のセットの宣言を許可します。アドレスは reg-ex パターンとして指定されます。

tokenIssue にはモジュラー構造があります。これにより、カスタム動作をメッセージの処理にインジェクトできます。この場合、SecurityTokenServiceProvider のデフォルト動作を上書きし、SAML トークン処理を実行します。Apache CXF は、SAMLTokenProvider の実装を提供します。これは、SAMLTokenProvider を作成する代わりに使用できます。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.stsbearer;

import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.sts.StaticSTSProperties;
import org.apache.cxf.sts.operation.TokenIssueOperation;
import org.apache.cxf.sts.service.ServiceMBean;
import org.apache.cxf.sts.service.StaticService;
import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
import org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider;

import javax.xml.ws.WebServiceProvider;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

@WebServiceProvider(serviceName = "SecurityTokenService",
      portName = "UT_Port",
      targetNamespace = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/",
      wsdlLocation = "WEB-INF/wsdl/bearer-ws-trust-1.4-service.wsdl")
//dependency on org.apache.cxf module or on module that exports org.apache.cxf (e.g. org.jboss.ws.cxf.jbossws-cxf-client) is needed, otherwise Apache CXF annotations are ignored
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "mystskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value = "stsKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.stsbearer.STSBearerCallbackHandler")
})
public class SampleSTSBearer extends SecurityTokenServiceProvider {

   public SampleSTSBearer() throws Exception {
      super();

      StaticSTSProperties props = new StaticSTSProperties();
      props.setSignatureCryptoProperties("stsKeystore.properties");
      props.setSignatureUsername("mystskey");
      props.setCallbackHandlerClass(STSBearerCallbackHandler.class.getName());
      props.setEncryptionCryptoProperties("stsKeystore.properties");
      props.setEncryptionUsername("myservicekey");
      props.setIssuer("DoubleItSTSIssuer");

      List<ServiceMBean> services = new LinkedList<ServiceMBean>();
      StaticService service = new StaticService();
      service.setEndpoints(Arrays.asList(
         "https://localhost:(\\d)*/jaxws-samples-wsse-policy-trust-bearer/BearerService",
         "https://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-bearer/BearerService",
         "https://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-bearer/BearerService"
      ));
      services.add(service);

      TokenIssueOperation issueOperation = new TokenIssueOperation();
      issueOperation.getTokenProviders().add(new SAMLTokenProvider());
      issueOperation.setServices(services);
      issueOperation.setStsProperties(props);
      this.setIssueOperation(issueOperation);
   }
}
A.8.2.2.4. STSBearerCallbackHandler クラス

STSBearerCallbackHandler は、WSS4J Crypto API のコールバックハンドラーです。これは、キーストアの秘密鍵のパスワードを取得するために使用されます。このクラスにより、Apache CXF はメッセージ署名に使用するユーザー名のパスワードを取得できます。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.stsbearer;

import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;

import java.util.HashMap;
import java.util.Map;

public class STSBearerCallbackHandler extends PasswordCallbackHandler {
   public STSBearerCallbackHandler() {
      super(getInitMap());
   }

   private static Map<String, String> getInitMap() {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("mystskey", "stskpass");
      passwords.put("alice", "clarinet");
      return passwords;
   }
}
A.8.2.2.5. 暗号化プロパティーおよびキーストアファイル

WSS4J の Crypto 実装は、Crypto 設定データを含む Java プロパティーファイルを使用してロードおよび設定されます。このファイルには、キーストアの場所、パスワード、デフォルトエイリアスなどの実装固有のプロパティーが含まれます。このアプリケーションは、Merlin 実装を使用します。stsKeystore.properties ファイルにはこの情報が含まれます。

servicestore.jks ファイルは Java KeyStore (JKS) リポジトリーです。これには、myservicekey および mystskey の自己署名証明書が含まれています。

注記

自己署名証明書は、実稼働環境での使用には適していません。

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=stsspass
org.apache.ws.security.crypto.merlin.keystore.file=stsstore.jks
A.8.2.2.6. デフォルトの MANIFEST.MF

このアプリケーションには、org.jboss.ws.cxf.jbossws-cxf-client モジュールで提供される JBossWS および Apache CXF API へのアクセスが必要です。また、org.jboss.ws.cxf.sts モジュールも SampleSTS コンストラクターで STS 設定を構築するために必要です。依存関係ステートメントは、デプロイメント時に提供するようサーバーに指示します。

Manifest-Version: 1.0
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client,org.jboss.ws.cxf.sts

A.8.2.3. Web Service Requester

このセクションでは、SAML Bearer シナリオで説明したように、エンドポイントセキュリティーを実装する Web サービスを呼び出す際に重要な要素について詳しく説明します。ここで説明するコンポーネントには、以下が含まれます。

A.8.2.3.1. Web Service Requester 実装

ws-requester (クライアント) は、Web サービスへの参照を作成する標準手順を使用します。エンドポイントのセキュリティー要件に対応するため、Web サービスの Request Context にはメッセージ生成に必要な情報が設定されます。さらに、STS と通信する STSClient は、同じ値で設定されます。

注記

接尾辞が .it のキー文字列は、これらの設定を STSClient に属するものとしてフラグします。内部 Apache CXF コードにより、のサービス呼び出し用に自動生成される STSClient にこの情報が割り当てられます。

STSCLient のセットアップには別の方法があります。ユーザーは STSClient の独自のインスタンスを提供できます。Apache CXF コードはこのオブジェクトを使用し、自動生成は行いません。この方法で STSClient を提供する場合は、ユーザーには org.apache.cxf.Bus を指定する必要があります。また、設定キーには .it 接尾辞を付けないでください。これは、ActAs および OnBehalfOf の例で使用されます。

String serviceURL = "https://" + getServerHost() + ":8443/jaxws-samples-wsse-policy-trust-bearer/BearerService";

final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/bearerwssecuritypolicy", "BearerService");
Service service = Service.create(new URL(serviceURL + "?wsdl"), serviceName);
BearerIface proxy = (BearerIface) service.getPort(BearerIface.class);

Map<String, Object> ctx = ((BindingProvider)proxy).getRequestContext();

// set the security related configuration information for the service "request"
ctx.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
  Thread.currentThread().getContextClassLoader().getResource(
  "META-INF/clientKeystore.properties"));
ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
  Thread.currentThread().getContextClassLoader().getResource(
  "META-INF/clientKeystore.properties"));
ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myclientkey");
ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myservicekey");

//-- Configuration settings that will be transfered to the STSClient
// "alice" is the name provided for the WSS Username. Her password will
// be retreived from the ClientCallbackHander by the STSClient.
ctx.put(SecurityConstants.USERNAME + ".it", "alice");
ctx.put(SecurityConstants.CALLBACK_HANDLER + ".it", new ClientCallbackHandler());
ctx.put(SecurityConstants.ENCRYPT_PROPERTIES + ".it",
  Thread.currentThread().getContextClassLoader().getResource(
  "META-INF/clientKeystore.properties"));
ctx.put(SecurityConstants.ENCRYPT_USERNAME + ".it", "mystskey");
ctx.put(SecurityConstants.STS_TOKEN_USERNAME + ".it", "myclientkey");
ctx.put(SecurityConstants.STS_TOKEN_PROPERTIES + ".it",
  Thread.currentThread().getContextClassLoader().getResource(
  "META-INF/clientKeystore.properties"));
ctx.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO + ".it", "true");

proxy.sayHello();
A.8.2.3.2. ClientCallbackHandler

ClientCallbackHandler は WSS4J Crypto API のコールバックハンドラーです。これは、キーストアの秘密鍵のパスワードを取得するために使用されます。このクラスにより、Apache CXF はメッセージ署名に使用するユーザー名のパスワードを取得できます。

注記

ここでは、ユーザー alice とパスワードが提供されています。この情報は (JKS) キーストアではなく、セキュリティードメインで提供されています。これは jbossws-users.properties ファイルで宣言されます。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared;

import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;

public class ClientCallbackHandler implements CallbackHandler {

    public void handle(Callback[] callbacks) throws IOException,
            UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof WSPasswordCallback) {
                WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
                if ("myclientkey".equals(pc.getIdentifier())) {
                    pc.setPassword("ckpass");
                    break;
                } else if ("alice".equals(pc.getIdentifier())) {
                    pc.setPassword("clarinet");
                    break;
                } else if ("bob".equals(pc.getIdentifier())) {
                    pc.setPassword("trombone");
                    break;
                } else if ("myservicekey".equals(pc.getIdentifier())) {  // rls test  added for bearer test
                   pc.setPassword("skpass");
                   break;
                }
            }
        }
    }
}
A.8.2.3.3. 暗号化プロパティーおよびキーストアファイル

WSS4J の Crypto 実装は、Crypto 設定データを含む Java プロパティーファイルを使用してロードおよび設定されます。このファイルには、キーストアの場所、パスワード、デフォルトエイリアスなどの実装固有のプロパティーが含まれます。このアプリケーションは、Merlin 実装を使用します。clientKeystore.properties ファイルにはこの情報が含まれます。

clientstore.jks ファイルは Java KeyStore (JKS) リポジトリーです。これには、myservicekey および mystskey の自己署名証明書が含まれています。

注記

自己署名証明書は、実稼働環境での使用には適していません。

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=cspass
org.apache.ws.security.crypto.merlin.keystore.alias=myclientkey
org.apache.ws.security.crypto.merlin.keystore.file=META-INF/clientstore.jks

A.8.3. シナリオ: onBehalfOf WS-Trust

OnBehalfOf 機能は、プロキシーパターンを使用するシナリオで使用されます。このようなシナリオでは、クライアントは直接 STS にアクセスできず、プロキシーゲートウェイを介して通信します。プロキシーゲートウェイは呼び出し元を認証し、処理するために実際の STS に送信された RequestSecurityToken (RST) の OnBehalfOf 要素に呼び出し元に関する情報を配置します。生成されるトークンにはプロキシーのクライアントに関連する要求のみが含まれるため、プロキシーは発行されたトークンの受信側に対して完全に透過的になります。

onBehalfOf は RST の新しいサブ要素にすぎません。これは、トークンが STS とネゴシエートされる場合の元の呼び出し元に関する追加情報を提供します。OnBehalfOf 要素は通常、クライアントがサービスにアクセスするために、アイデンティティー要求 (名前、ロール、承認コードなど) を持つトークンの形式を取ります。

OnBehalfOf シナリオは、基本的な WS-Trust シナリオの拡張機能です。この例では、onBehalfOf サービスはユーザーの代わりに ws-service を呼び出します。基本的なシナリオのコードには少数のみ追加されています。OnBehalfOf Web サービスプロバイダーとコールバックハンドラーが追加されました。OnBehalfOf Web サービス の WSDL は、ws-provider と同じセキュリティーポリシーが適用されます。UsernameTokenCallbackHandler は、ActAs と共有するユーティリティーです。OnBehalfOf 要素のコンテンツを生成します。最後に、OnBehalfOfActAs の両方に共通なコードの追加があります。

A.8.3.1. Web サービスプロバイダー

ここでは、OnBehalfOf の例の要件に対応するために更新された、基本的な WS-Trust シナリオからの web サービス要素について説明します。コンポーネントには以下が含まれます。

A.8.3.1.1. Web Service Provider WSDL

OnBehalfOf web サービスプロバイダーの WSDL は、ws-provider のクローンです。wsp:policy セクションは同じです。サービスエンドポイント、targetNamespaceportTypebinding 名、service の更新があります。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/onbehalfofwssecuritypolicy" name="OnBehalfOfService"
             xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/onbehalfofwssecuritypolicy"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:wsp="http://www.w3.org/ns/ws-policy"
             xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
             xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
             xmlns:wsaws="http://www.w3.org/2005/08/addressing"
             xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
             xmlns:t="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
    <types>
        <xsd:schema>
            <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/onbehalfofwssecuritypolicy"
                  schemaLocation="OnBehalfOfService_schema1.xsd"/>
        </xsd:schema>
    </types>
    <message name="sayHello">
        <part name="parameters" element="tns:sayHello"/>
    </message>
    <message name="sayHelloResponse">
        <part name="parameters" element="tns:sayHelloResponse"/>
    </message>
    <portType name="OnBehalfOfServiceIface">
        <operation name="sayHello">
            <input message="tns:sayHello"/>
            <output message="tns:sayHelloResponse"/>
        </operation>
    </portType>
    <binding name="OnBehalfOfServicePortBinding" type="tns:OnBehalfOfServiceIface">
        <wsp:PolicyReference URI="#AsymmetricSAML2Policy" />
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <operation name="sayHello">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
                <wsp:PolicyReference URI="#Input_Policy" />
            </input>
            <output>
                <soap:body use="literal"/>
                <wsp:PolicyReference URI="#Output_Policy" />
            </output>
        </operation>
    </binding>
    <service name="OnBehalfOfService">
        <port name="OnBehalfOfServicePort" binding="tns:OnBehalfOfServicePortBinding">
            <soap:address location="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-onbehalfof/OnBehalfOfService"/>
        </port>
    </service>
</definitions>
A.8.3.1.2. Web Service Provider インターフェイス

OnBehalfOfServiceIface Web サービスプロバイダーのインターフェイスクラスは簡単な Web サービス定義です。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.onbehalfof;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
(
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/onbehalfofwssecuritypolicy"
)
public interface OnBehalfOfServiceIface {
   @WebMethod
   String sayHello();
}
A.8.3.1.3. Web Service Provider の実装

OnBehalfOfServiceImpl Web サービスプロバイダー実装は単純な POJO です。このアノテーションは標準の WebService アノテーションを使用して、サービスエンドポイントと Apache CXF ランタイムのエンドポイントを設定するために使用される EndpointProperties および EndpointProperty の 2 つ Apache WSS4J アノテーションを定義します。提供される WSS4J 設定情報は、WSS4J の Crypto Merlin 実装用です。

OnBehalfOfServiceImpl は、ユーザーの代替として動作する ServiceImpl を呼び出します。setupService メソッドは、必要な設定を実行します。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.onbehalfof;

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.trust.STSClient;
import org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service.ServiceIface;
import org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared.WSTrustAppUtils;

import javax.jws.WebService;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import java.net.*;
import java.util.Map;

@WebService
(
   portName = "OnBehalfOfServicePort",
   serviceName = "OnBehalfOfService",
   wsdlLocation = "WEB-INF/wsdl/OnBehalfOfService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/onbehalfofwssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.onbehalfof.OnBehalfOfServiceIface"
)

@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "myactaskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value =  "actasKeystore.properties"),
      @EndpointProperty(key = "ws-security.encryption.properties", value = "actasKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.onbehalfof.OnBehalfOfCallbackHandler")
})

public class OnBehalfOfServiceImpl implements OnBehalfOfServiceIface {
   public String sayHello() {
      try {

         ServiceIface proxy = setupService();
         return "OnBehalfOf " + proxy.sayHello();

      } catch (MalformedURLException e) {
         e.printStackTrace();
      }
      return null;
   }

   /**
    *
    * @return
    * @throws MalformedURLException
    */
   private  ServiceIface setupService()throws MalformedURLException {
      ServiceIface proxy = null;
      Bus bus = BusFactory.newInstance().createBus();

      try {
         BusFactory.setThreadDefaultBus(bus);

         final String serviceURL = "http://" + WSTrustAppUtils.getServerHost() + ":8080/jaxws-samples-wsse-policy-trust/SecurityService";
         final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService");
         final URL wsdlURL = new URL(serviceURL + "?wsdl");
         Service service = Service.create(wsdlURL, serviceName);
         proxy = (ServiceIface) service.getPort(ServiceIface.class);

         Map<String, Object> ctx = ((BindingProvider) proxy).getRequestContext();
         ctx.put(SecurityConstants.CALLBACK_HANDLER, new OnBehalfOfCallbackHandler());

         ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource(
            "actasKeystore.properties" ));
         ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myactaskey" );
         ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource(
            "../../META-INF/clientKeystore.properties" ));
         ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myservicekey");

         STSClient stsClient = new STSClient(bus);
         Map<String, Object> props = stsClient.getProperties();
         props.put(SecurityConstants.USERNAME, "bob");
         props.put(SecurityConstants.ENCRYPT_USERNAME, "mystskey");
         props.put(SecurityConstants.STS_TOKEN_USERNAME, "myactaskey" );
         props.put(SecurityConstants.STS_TOKEN_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource(
            "actasKeystore.properties" ));
         props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");

         ctx.put(SecurityConstants.STS_CLIENT, stsClient);

      } finally {
         bus.shutdown(true);
      }

      return proxy;
   }

}
A.8.3.1.4. OnBehalfOfCallbackHandler クラス

OnBehalfOfCallbackHandler は、WSS4J Crypto API のコールバックハンドラーです。これは、キーストアの秘密鍵のパスワードを取得するために使用されます。このクラスにより、Apache CXF はメッセージ署名に使用するユーザー名のパスワードを取得できます。このクラスは、このサービス myactaskey のパスワード、OnBehalfOf ユーザー、alice を返すように更新されました。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.onbehalfof;

import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;
import java.util.HashMap;
import java.util.Map;

public class OnBehalfOfCallbackHandler extends PasswordCallbackHandler {

   public OnBehalfOfCallbackHandler() {
      super(getInitMap());
   }

   private static Map<String, String> getInitMap() {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("myactaskey", "aspass");
      passwords.put("alice", "clarinet");
      passwords.put("bob", "trombone");
      return passwords;
   }

}

A.8.3.2. Web Service Requester

ここでは、OnBehalfOf の例の要件に対応するために更新された、基本的な WS-Trust シナリオからの ws-requester 要素について説明します。コンポーネントは次のとおりです。

A.8.3.2.1. OnBehalfOf Web Service Requester Implementation クラス

OnBehalfOf ws-requester クライアントは、Web サービスへの参照を最初の 4 行で作成するために標準手順を使用します。エンドポイントのセキュリティー要件に対応するため、Web サービスのリクエストコンテキストは BindingProvider を使用して設定されます。メッセージ生成に必要な情報は、それを介して提供されます。OnBehalfOf ユーザー alice はこのセクションおよび callbackHandler で宣言され、OnBehalfOf メッセージ要素 の内容の生成のために UsernameTokenCallbackHandlerSTSClient に提供されます。この例では、STSClient オブジェクトが作成され、プロキシーのリクエストコンテキストに提供されます。別の方法として、Basic Scenario クライアントで行なわれたように、.it 接尾辞でタグ付けされた鍵を提供する方法があります。OnBehalfOf の使用は、stsClient.setOnBehalfOf 呼び出しメソッドによって設定されます。または、SecurityConstants.STS_TOKEN_ON_BEHALF_OF キーと properties マップの値を使用します。

final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/onbehalfofwssecuritypolicy", "OnBehalfOfService");
final URL wsdlURL = new URL(serviceURL + "?wsdl");
Service service = Service.create(wsdlURL, serviceName);
OnBehalfOfServiceIface proxy = (OnBehalfOfServiceIface) service.getPort(OnBehalfOfServiceIface.class);


Bus bus = BusFactory.newInstance().createBus();
try {

    BusFactory.setThreadDefaultBus(bus);

    Map<String, Object> ctx = proxy.getRequestContext();

    ctx.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
    ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myactaskey");
    ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myclientkey");

    // user and password OnBehalfOf user
    // UsernameTokenCallbackHandler will extract this information when called
    ctx.put(SecurityConstants.USERNAME,"alice");
    ctx.put(SecurityConstants.PASSWORD, "clarinet");

    STSClient stsClient = new STSClient(bus);

    // Providing the STSClient the mechanism to create the claims contents for OnBehalfOf
    stsClient.setOnBehalfOf(new UsernameTokenCallbackHandler());

    Map<String, Object> props = stsClient.getProperties();
    props.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
    props.put(SecurityConstants.ENCRYPT_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    props.put(SecurityConstants.ENCRYPT_USERNAME, "mystskey");
    props.put(SecurityConstants.STS_TOKEN_USERNAME, "myclientkey");
    props.put(SecurityConstants.STS_TOKEN_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");

    ctx.put(SecurityConstants.STS_CLIENT, stsClient);

} finally {
    bus.shutdown(true);
}
proxy.sayHello();

A.8.4. シナリオ: ActAs WS-Trust

ActAs 機能は、複合委任が必要なシナリオで使用されます。これは一般的に、ログインユーザーの代わりにサービスが呼び出される、またはサービスが元の呼び出し元の代わりに別のサービスを呼び出す、階層化システムで使用されます。

ActAs は、RequestSecurityToken (RST) の新しいサブ要素ではありません。これは、トークンが STS とネゴシエートされる場合の元の呼び出し元に関する追加情報を提供します。ActAs 要素は通常、クライアントがサービスにアクセスするために、アイデンティティー要求 (名前、ロール、承認コードなど) を持つトークンの形式を取ります。

ActAs シナリオは、基本的な WS-Trust シナリオの拡張機能です。この例では、ActAs サービスはユーザーの代わりに ws-service を呼び出します。基本的なシナリオのコードには少数のみ追加されています。ActAs Web サービスプロバイダーとコールバックハンドラーが追加されました。ActAs web サービスの WSDL では、ws-provider と同じセキュリティーポリシーが適用されます。UsernameTokenCallbackHandler は、ActAs 要素のコンテンツを生成する新しいユーティリティーです。最後に、ActAs リクエストをサポートするために、STS にコードがいくつか追加されています。

A.8.4.1. Web サービスプロバイダー

ここでは、ActAs の例のニーズに対応するために変更された基本的な WS-Trust シナリオからの web サービス要素について詳しく説明します。コンポーネントには以下が含まれます。

A.8.4.1.1. Web Service Provider WSDL

ActAs web サービスプロバイダーの WSDL は ws-provider WSDL のクローンです。wsp:policy セクションは同じです。サービスエンドポイント、targetNamespaceportTypebinding 名、service の変更があります。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy" name="ActAsService"
             xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:wsp="http://www.w3.org/ns/ws-policy"
             xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
             xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
             xmlns:wsaws="http://www.w3.org/2005/08/addressing"
             xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
             xmlns:t="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
    <types>
        <xsd:schema>
            <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy"
                    schemaLocation="ActAsService_schema1.xsd"/>
        </xsd:schema>
    </types>
    <message name="sayHello">
        <part name="parameters" element="tns:sayHello"/>
    </message>
    <message name="sayHelloResponse">
        <part name="parameters" element="tns:sayHelloResponse"/>
    </message>
    <portType name="ActAsServiceIface">
        <operation name="sayHello">
            <input message="tns:sayHello"/>
            <output message="tns:sayHelloResponse"/>
        </operation>
    </portType>
    <binding name="ActAsServicePortBinding" type="tns:ActAsServiceIface">
        <wsp:PolicyReference URI="#AsymmetricSAML2Policy" />
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <operation name="sayHello">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
                <wsp:PolicyReference URI="#Input_Policy" />
            </input>
            <output>
                <soap:body use="literal"/>
                <wsp:PolicyReference URI="#Output_Policy" />
            </output>
        </operation>
    </binding>
    <service name="ActAsService">
        <port name="ActAsServicePort" binding="tns:ActAsServicePortBinding">
            <soap:address location="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-actas/ActAsService"/>
        </port>
    </service>

</definitions>
A.8.4.1.2. Web Service Provider インターフェイス

ActAsServiceIface Web サービスプロバイダーのインターフェイスクラスは簡単な Web サービス定義です。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
(
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy"
)
public interface ActAsServiceIface {
   @WebMethod
   String sayHello();
}
A.8.4.1.3. Web Service Provider の実装

ActAsServiceImpl Web サービスプロバイダー実装は単純な POJO です。このアノテーションは標準の WebService アノテーションを使用して、サービスエンドポイントと Apache CXF ランタイムのエンドポイントを設定するために使用される EndpointProperties および EndpointProperty の 2 つ Apache WSS4J アノテーションを定義します。提供される WSS4J 設定情報は、WSS4J の Crypto Merlin 実装用です。

ActAsServiceImplServiceImpl をユーザーの代わりに呼び出します。setupService メソッドは、必要な設定を実行します。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas;

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.trust.STSClient;
import org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service.ServiceIface;
import org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared.WSTrustAppUtils;

import javax.jws.WebService;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

@WebService
(
   portName = "ActAsServicePort",
   serviceName = "ActAsService",
   wsdlLocation = "WEB-INF/wsdl/ActAsService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas.ActAsServiceIface"
)

@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "myactaskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value =  "actasKeystore.properties"),
      @EndpointProperty(key = "ws-security.encryption.properties", value = "actasKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas.ActAsCallbackHandler")
})

public class ActAsServiceImpl implements ActAsServiceIface {
   public String sayHello() {
      try {
         ServiceIface proxy = setupService();
         return "ActAs " + proxy.sayHello();
      } catch (MalformedURLException e) {
         e.printStackTrace();
      }
      return null;
   }

   private  ServiceIface setupService()throws MalformedURLException {
      ServiceIface proxy = null;
      Bus bus = BusFactory.newInstance().createBus();

      try {
         BusFactory.setThreadDefaultBus(bus);

         final String serviceURL = "http://" + WSTrustAppUtils.getServerHost() + ":8080/jaxws-samples-wsse-policy-trust/SecurityService";
         final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService");
         final URL wsdlURL = new URL(serviceURL + "?wsdl");
         Service service = Service.create(wsdlURL, serviceName);
         proxy = (ServiceIface) service.getPort(ServiceIface.class);

         Map<String, Object> ctx = ((BindingProvider) proxy).getRequestContext();
         ctx.put(SecurityConstants.CALLBACK_HANDLER, new ActAsCallbackHandler());

         ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource("actasKeystore.properties" ));
         ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myactaskey" );
         ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource("../../META-INF/clientKeystore.properties" ));
         ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myservicekey");

         STSClient stsClient = new STSClient(bus);
         Map<String, Object> props = stsClient.getProperties();
         props.put(SecurityConstants.USERNAME, "alice");
         props.put(SecurityConstants.ENCRYPT_USERNAME, "mystskey");
         props.put(SecurityConstants.STS_TOKEN_USERNAME, "myactaskey" );
         props.put(SecurityConstants.STS_TOKEN_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource("actasKeystore.properties" ));
         props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");

         ctx.put(SecurityConstants.STS_CLIENT, stsClient);

      } finally {
         bus.shutdown(true);
      }

      return proxy;
   }

}
A.8.4.1.4. ActAsCallbackHandler クラス

ActAsCallbackHandler は WSS4J Crypto API のコールバックハンドラーです。これは、キーストアの秘密鍵のパスワードを取得するために使用されます。このクラスにより、Apache CXF はメッセージ署名に使用するユーザー名のパスワードを取得できます。このクラスは、このサービス myactaskey のパスワード、ActAs ユーザー、alice を返すように更新されました。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas;

import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;
import java.util.HashMap;
import java.util.Map;

public class ActAsCallbackHandler extends PasswordCallbackHandler {

   public ActAsCallbackHandler() {
      super(getInitMap());
   }

   private static Map<String, String> getInitMap() {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("myactaskey", "aspass");
      passwords.put("alice", "clarinet");
      return passwords;
   }
}
A.8.4.1.5. UsernameTokenCallbackHandler

RequestSecurityTokenActAs および OnBeholdOf サブ要素を WSSE UsernameTokens として定義する必要があります。このユーティリティーは、適切にフォーマットされた要素を生成します。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared;

import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.message.Message;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.trust.delegation.DelegationCallback;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.message.token.UsernameToken;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
import java.util.Map;

/**
* A utility to provide the 3 different input parameter types for jaxws property
* "ws-security.sts.token.act-as" and "ws-security.sts.token.on-behalf-of".
* This implementation obtains a username and password via the jaxws property
* "ws-security.username" and "ws-security.password" respectively, as defined
* in SecurityConstants.  It creates a wss UsernameToken to be used as the
* delegation token.
*/

public class UsernameTokenCallbackHandler implements CallbackHandler {

   public void handle(Callback[] callbacks)
      throws IOException, UnsupportedCallbackException {
      for (int i = 0; i < callbacks.length; i++) {
         if (callbacks[i] instanceof DelegationCallback) {
            DelegationCallback callback = (DelegationCallback) callbacks[i];
            Message message = callback.getCurrentMessage();

            String username =
               (String)message.getContextualProperty(SecurityConstants.USERNAME);
            String password =
               (String)message.getContextualProperty(SecurityConstants.PASSWORD);
            if (username != null) {
               Node contentNode = message.getContent(Node.class);
               Document doc = null;
               if (contentNode != null) {
                  doc = contentNode.getOwnerDocument();
               } else {
                  doc = DOMUtils.createDocument();
               }
               UsernameToken usernameToken = createWSSEUsernameToken(username,password, doc);
               callback.setToken(usernameToken.getElement());
            }
         } else {
            throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
         }
      }
   }

   /**
    * Provide UsernameToken as a string.
    * @param ctx
    * @return
    */
   public String getUsernameTokenString(Map<String, Object> ctx){
      Document doc = DOMUtils.createDocument();
      String result = null;
      String username = (String)ctx.get(SecurityConstants.USERNAME);
      String password = (String)ctx.get(SecurityConstants.PASSWORD);
      if (username != null) {
         UsernameToken usernameToken = createWSSEUsernameToken(username,password, doc);
         result = toString(usernameToken.getElement().getFirstChild().getParentNode());
      }
      return result;
   }

   /**
    *
    * @param username
    * @param password
    * @return
    */
   public String getUsernameTokenString(String username, String password){
      Document doc = DOMUtils.createDocument();
      String result = null;
      if (username != null) {
         UsernameToken usernameToken = createWSSEUsernameToken(username,password, doc);
         result = toString(usernameToken.getElement().getFirstChild().getParentNode());
      }
      return result;
   }

   /**
    * Provide UsernameToken as a DOM Element.
    * @param ctx
    * @return
    */
   public Element getUsernameTokenElement(Map<String, Object> ctx){
      Document doc = DOMUtils.createDocument();
      Element result = null;
      UsernameToken usernameToken = null;
         String username = (String)ctx.get(SecurityConstants.USERNAME);
      String password = (String)ctx.get(SecurityConstants.PASSWORD);
      if (username != null) {
         usernameToken = createWSSEUsernameToken(username,password, doc);
         result = usernameToken.getElement();
      }
      return result;
   }

   /**
    *
    * @param username
    * @param password
    * @return
    */
   public Element getUsernameTokenElement(String username, String password){
      Document doc = DOMUtils.createDocument();
      Element result = null;
      UsernameToken usernameToken = null;
      if (username != null) {
         usernameToken = createWSSEUsernameToken(username,password, doc);
         result = usernameToken.getElement();
      }
      return result;
   }

   private UsernameToken createWSSEUsernameToken(String username, String password, Document doc) {

      UsernameToken usernameToken = new UsernameToken(true, doc,
         (password == null)? null: WSConstants.PASSWORD_TEXT);
      usernameToken.setName(username);
      usernameToken.addWSUNamespace();
      usernameToken.addWSSENamespace();
      usernameToken.setID("id-" + username);

      if (password != null){
         usernameToken.setPassword(password);
      }

      return usernameToken;
   }


   private String toString(Node node) {
      String str = null;

      if (node != null) {
         DOMImplementationLS lsImpl = (DOMImplementationLS)
            node.getOwnerDocument().getImplementation().getFeature("LS", "3.0");
         LSSerializer serializer = lsImpl.createLSSerializer();
         serializer.getDomConfig().setParameter("xml-declaration", false); //by default its true, so set it to false to get String without xml-declaration
         str = serializer.writeToString(node);
      }
      return str;
   }

}
A.8.4.1.6. Crypto プロパティーおよびキーストアファイル

ActAs サービスは、独自の認証情報を提供する必要があります。必須の actasKeystore.properties プロパティーファイルと actasstore.jks キーストアが作成されます。

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=aapass
org.apache.ws.security.crypto.merlin.keystore.alias=myactaskey
org.apache.ws.security.crypto.merlin.keystore.file=actasstore.jks
A.8.4.1.7. デフォルトの MANIFEST.MF

このアプリケーションには、org.jboss.ws.cxf.jbossws-cxf-client モジュールで提供される JBossWS および Apache CXF API へのアクセスが必要です。また、org.jboss.ws.cxf.sts モジュールも ActAs および OnBehalfOf 拡張機能を処理するために必要です。依存関係ステートメントは、デプロイメント時に提供するようサーバーに指示します。

Manifest-Version: 1.0
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client, org.jboss.ws.cxf.sts

A.8.4.2. セキュリティートークンサービス

ここでは、ActAs の例のニーズに対応するために変更された基本的な WS-Trust シナリオからの STS 要素の詳細を説明します。コンポーネントには以下が含まれます。

A.8.4.2.1. STS 実装クラス

アドレス別に許可されるトークン受信側のセットの宣言が、ActAs アドレスおよび OnBehalfOf アドレスを受け入れるように拡張されました。アドレスは reg-ex パターンとして指定されます。

TokenIssueOperation では、OnBehalfOf の内容を検証するために UsernameTokenValidator クラスを提供し、OnBehalfOf ユーザーの ActAs のトークン委任要求を処理するために UsernameTokenDelegationHandler クラスを提供する必要があります。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import javax.xml.ws.WebServiceProvider;

import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.interceptor.InInterceptors;
import org.apache.cxf.sts.StaticSTSProperties;
import org.apache.cxf.sts.operation.TokenIssueOperation;
import org.apache.cxf.sts.operation.TokenValidateOperation;
import org.apache.cxf.sts.service.ServiceMBean;
import org.apache.cxf.sts.service.StaticService;
import org.apache.cxf.sts.token.delegation.UsernameTokenDelegationHandler;
import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
import org.apache.cxf.sts.token.validator.SAMLTokenValidator;
import org.apache.cxf.sts.token.validator.UsernameTokenValidator;
import org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider;

@WebServiceProvider(serviceName = "SecurityTokenService",
      portName = "UT_Port",
      targetNamespace = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/",
      wsdlLocation = "WEB-INF/wsdl/ws-trust-1.4-service.wsdl")
//dependency on org.apache.cxf module or on module that exports org.apache.cxf (e.g. org.jboss.ws.cxf.jbossws-cxf-client) is needed, otherwise Apache CXF annotations are ignored
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "mystskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value = "stsKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts.STSCallbackHandler"),
      @EndpointProperty(key = "ws-security.validate.token", value = "false") //to let the JAAS integration deal with validation through the interceptor below
})
@InInterceptors(interceptors = {"org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingPolicyInterceptor"})
public class SampleSTS extends SecurityTokenServiceProvider {
   public SampleSTS() throws Exception {
      super();

      StaticSTSProperties props = new StaticSTSProperties();
      props.setSignatureCryptoProperties("stsKeystore.properties");
      props.setSignatureUsername("mystskey");
      props.setCallbackHandlerClass(STSCallbackHandler.class.getName());
      props.setIssuer("DoubleItSTSIssuer");

      List<ServiceMBean> services = new LinkedList<ServiceMBean>();
      StaticService service = new StaticService();
      service.setEndpoints(Arrays.asList(
         "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
         "http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
         "http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",

         "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust-actas/ActAsService",
         "http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-actas/ActAsService",
         "http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-actas/ActAsService",

         "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust-onbehalfof/OnBehalfOfService",
         "http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-onbehalfof/OnBehalfOfService",
         "http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-onbehalfof/OnBehalfOfService"
      ));
      services.add(service);

      TokenIssueOperation issueOperation = new TokenIssueOperation();
      issueOperation.setServices(services);
      issueOperation.getTokenProviders().add(new SAMLTokenProvider());
      // required for OnBehalfOf
      issueOperation.getTokenValidators().add(new UsernameTokenValidator());
      // added for OnBehalfOf and ActAs
      issueOperation.getDelegationHandlers().add(new UsernameTokenDelegationHandler());
      issueOperation.setStsProperties(props);

      TokenValidateOperation validateOperation = new TokenValidateOperation();
      validateOperation.getTokenValidators().add(new SAMLTokenValidator());
      validateOperation.setStsProperties(props);

      this.setIssueOperation(issueOperation);
      this.setValidateOperation(validateOperation);
   }
}
A.8.4.2.2. STSCallbackHandler クラス

ActAs の例には、ユーザー alice、および対応するパスワードを追加する必要があります。

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts;

import java.util.HashMap;
import java.util.Map;

import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;

public class STSCallbackHandler extends PasswordCallbackHandler {
   public STSCallbackHandler() {
      super(getInitMap());
   }

   private static Map<String, String> getInitMap() {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("mystskey", "stskpass");
      passwords.put("alice", "clarinet");
      return passwords;
   }
}
A.8.4.2.3. Web Service Requester

ここでは、ActAs の例の要件に対応するために更新された、基本的な WS-Trust シナリオからの ws-requester 要素について説明します。コンポーネントは次のとおりです。

A.8.4.2.4. Web Service Requester 実装クラス

ActAs ws-requester (クライアント) は、Web サービスへの参照を最初の 4 行で作成するために標準手順を使用します。エンドポイントのセキュリティー要件に対応するため、Web サービスのリクエストコンテキストは BindingProvider を使用してメッセージの生成に必要な情報を提供します。ActAs ユーザー myactaskey はこのセクションで宣言され、UsernameTokenCallbackHandlerActAs 要素のコンテンツを STSClient に提供するために使用されます。この例では、STSClient オブジェクトが作成され、プロキシーのリクエストコンテキストに提供されます。別の方法として、Basic Scenario クライアントで行なわれたように、.it 接尾辞でタグ付けされた鍵を提供する方法があります。ActAs の使用は、SecurityConstants .STS_TOKEN_ACT_AS キーを使用してプロパティーマップで設定します。または、STSClient.setActAs メソッドを使用します。

final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy", "ActAsService");
final URL wsdlURL = new URL(serviceURL + "?wsdl");
Service service = Service.create(wsdlURL, serviceName);
ActAsServiceIface proxy = (ActAsServiceIface) service.getPort(ActAsServiceIface.class);

Bus bus = BusFactory.newInstance().createBus();
try {
    BusFactory.setThreadDefaultBus(bus);

    Map<String, Object> ctx = proxy.getRequestContext();

    ctx.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
    ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myactaskey");
    ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myclientkey");

    // Generate the ActAs element contents and pass to the STSClient as a string
    UsernameTokenCallbackHandler ch = new UsernameTokenCallbackHandler();
    String str = ch.getUsernameTokenString("alice","clarinet");
    ctx.put(SecurityConstants.STS_TOKEN_ACT_AS, str);

    STSClient stsClient = new STSClient(bus);
    Map<String, Object> props = stsClient.getProperties();
    props.put(SecurityConstants.USERNAME, "bob");
    props.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
    props.put(SecurityConstants.ENCRYPT_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    props.put(SecurityConstants.ENCRYPT_USERNAME, "mystskey");
    props.put(SecurityConstants.STS_TOKEN_USERNAME, "myclientkey");
    props.put(SecurityConstants.STS_TOKEN_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");

    ctx.put(SecurityConstants.STS_CLIENT, stsClient);
} finally {
    bus.shutdown(true);
}
proxy.sayHello();





改訂日時: 2024-02-08

法律上の通知

Copyright © 2024 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.