Red Hat Training
A Red Hat training course is available for Red Hat JBoss Enterprise Application Platform
開発ガイド
Red Hat JBoss Enterprise Application Platform 6 向け
概要
第1章 アプリケーション開発の開始
1.1. はじめに
1.1.1. Red Hat JBoss Enterprise Application Platform 6
1.2. 前提条件
1.2.1. Java Enterprise Edition 6 について
1.2.1.1. EE 6 プロファイルの概要
1.2.1.2. Java Enterprise Edition 6 Web プロファイル
Java EE 6 Web プロファイルの要件
- Java Platform, Enterprise Edition 6
Java Web Technologies
- Servlet 3.0 (JSR 315)
- JSP 2.2 and Expression Language (EL) 1.2
- JavaServer Faces (JSF) 2.1 (JSR 314)
- Java Standard Tag Library (JSTL) for JSP 1.2
- Debugging Support for Other Languages 1.0 (JSR 45)
エンタープライズアプリケーションテクノロジー
- コンテキストおよび依存関係の挿入 (CDI) (JSR 299)
- Dependency Injection for Java (JSR 330)
- Enterprise JavaBeans 3.1 Lite (JSR 318)
- Java Persistence API 2.0 (JSR 317)
- Common Annotations for the Java Platform 1.1 (JSR 250)
- Java Transaction API (JTA) 1.1 (JSR 907)
- Bean Validation (JSR 303)
1.2.1.3. Java Enterprise Edition 6 のフルプロファイル
EE 6 フルプロファイルに含まれるアイテム
- EJB 3.1(Lite ではない) (JSR 318)
- Java EE コネクターアーキテクチャー 1.6 (JSR 322)
- Java Message Service (JMS) API 1.1 (JSR 914)
- JavaMail 1.4 (JSR 919)
Web サービステクノロジー
- Jax-RS RESTful Web サービス 1.1 (JSR 311)
- Implementing Enterprise Web Services 1.3 (JSR 109)
- JAX-WS Java API for XML-Based Web Services 2.2 (JSR 224)
- Java Architecture for XML Binding (JAXB) 2.2 (JSR 222)
- Web Services Metadata for the Java Platform (JSR 181)
- Java APIs for XML-based RPC 1.1 (JSR 101)
- Java APIs for XML Messaging 1.3 (JSR 67)
- Java API for XML Registries (JAXR) 1.0 (JSR 93)
管理およびセキュリティーテクノロジー
- Java Authentication Service Provider Interface for Containers 1.0 (JSR 196)
- コンテナー 1.3 の Java 認証契約 (JSR 115)
- Java EE アプリケーションデプロイメント 1.2 (JSR 88)
- J2EE Management 1.1 (JSR 77)
1.2.2. JBoss EAP 6 で使用されるモジュールと新しい Modular Class Loading System について
1.2.2.1. モジュール
- 静的モジュール
- 静的モジュールは、アプリケーションサーバーの
EAP_HOME/modules/
ディレクトリーで事前定義されます。各サブディレクトリーは 1 つのモジュールを表し、設定ファイル (module.xml
) と必要な JAR ファイルを含むmain/
サブディレクトリーを定義します。モジュールの名前は、module.xml
ファイルで定義されています。アプリケーションサーバーが提供するすべての API は、Java EE API や JBoss Logging などの他の API を含む静的モジュールとして提供されます。例1.1 module.xml ファイルの例
<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.0" name="com.mysql"> <resources> <resource-root path="mysql-connector-java-5.1.15.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
モジュール名、com.mysql
、main/
サブディレクトリー名を除いて、モジュールのディレクトリー構造と一致する必要があります。JBoss EAP ディストリビューションで提供されるモジュールは、EAP_HOME/modules
ディレクトリー内のsystem
ディレクトリーにあります。このため、サードパーティーによって提供されるモジュールから分離されます。JBoss EAP 6.1 以降の上にレイヤー化された Red Hat が提供するレイヤード製品も、system
ディレクトリー内にモジュールをインストールします。カスタム静的モジュールの作成は、同じサードパーティーライブラリーを使用する同じサーバー上に多くのアプリケーションがデプロイされる場合に役立ちます。これらのライブラリーを各アプリケーションとバンドルする代わりに、JBoss 管理者はこれらのライブラリーが含まれるモジュールを作成およびインストールできます。アプリケーションは、カスタム静的モジュールで明示的な依存関係を宣言できます。モジュールレイアウトごとに 1 つのディレクトリーを使用して、カスタムモジュールがEAP_HOME/modules
ディレクトリーにインストールされるようにする必要があります。こうすると、同梱されたバージョンではなく、system
ディレクトリーに存在するカスタムバージョンのモジュールがロードされるようになります。これにより、ユーザー提供のモジュールがシステムモジュールよりも優先されます。JBOSS_MODULEPATH
環境変数を使用して JBoss EAP がモジュールを検索する場所を変更する場合は、指定された場所の 1 つでsystem
サブディレクトリー構造を探します。システム
構造体は、JBOSS_MODULEPATH
で指定された場所のどこかに存在する必要があります。 - 動的モジュール
- 動的モジュールは、各 JAR または WAR デプロイメント (または、EAR 内のサブデプロイメント) に対してアプリケーションサーバーによって作成およびロードされます。動的モジュールの名前は、デプロイされたアーカイブの名前に由来します。デプロイメントはモジュールとしてロードされるため、依存関係を設定し、他のデプロイメントで依存関係として使用することが可能です。
1.3. 開発環境のセットアップ
1.3.1. Red Hat JBoss Developer Studio をダウンロードしてインストールします
1.3.1.1. Setup Red Hat JBoss Developer Studio
1.3.1.2. Red Hat JBoss Developer Studio のダウンロード
- https://access.redhat.com/ にアクセスします。
- ページの上部にあるメニューから Downloads を選択します。
- リストから
Red Hat Developer Studio
を見つけて、クリックします。 - 適切なバージョンを選択し、Download をクリックします。
1.3.1.3. Install Red Hat JBoss Developer Studio
手順1.1 Install Red Hat JBoss Developer Studio
- Open a terminal.
- ダウンロードした
.jar
ファイルを含むディレクトリーに移動します。 - 次のコマンドを実行して、GUI インストーラーを起動します。
java -jar jbdevstudio-build_version.jar
- Next をクリックして、インストールプロセスを開始します。
- I accept the terms of this license agreement を選択し、Next をクリックします。
- インストールパスを調整し、Next をクリックします。注記インストールパスフォルダーが存在しない場合は、プロンプトが表示されます。OK をクリックしてフォルダーを作成します。
- JVM を選択するか、デフォルトの JVM を選択したままにして、Next をクリックします。
- 使用可能なアプリケーションプラットフォームを追加し、Next をクリックします。
- インストールの詳細を確認し、Next をクリックします。
- インストールプロセスが完了したら、Next をクリックします。
- Red Hat JBoss Developer Studio のデスクトップショートカットを設定し、Next をクリックします。
- 完了 をクリックします。
1.3.1.4. Red Hat JBoss Developer Studio の起動
手順1.2 Red Hat JBoss Developer Studio を起動するコマンド
- Open a terminal.
- インストールディレクトリーに移動します。
- 次のコマンドを実行して、Red Hat JBoss Developer Studio を起動します。
[localhost]$ ./jbdevstudio
1.3.1.5. Define New Server を使用して JBossEAP サーバーを追加します
手順1.3 サーバーを追加します
- Servers タブを開きます。Servers タブがない場合は、次のようにパネルに追加します。
- Window → Show View → Other...をクリックします。
- Server フォルダーから Servers を選択し、OK をクリックします。
- 以下をクリックします、No servers are available。このリンクをクリックして、新しいサーバーを作成します。または、必要に応じて、空白のサーバーパネル内を右クリックし、New → Server を選択します。
図1.1 新しいサーバーを追加する - No servers available
[D] - JBoss Enterprise Middleware を展開し、JBoss Enterprise Application Platform 6.1+ を選択します。JBoss Enterprise Application Platform 6.4 などのサーバー名を入力し、Next をクリックして JBoss ランタイムを作成し、サーバーを定義します。次回新しいサーバーを定義するとき、このダイアログには、新しいランタイム定義を含む Server runtime environment の選択が表示されます。
図1.2 新しいサーバーを定義する
[D] - サーバーの起動と停止を管理するサーバーアダプターを作成します。デフォルトのままにして、Next をクリックします。
図1.3 新しいサーバーアダプターを作成する
[D] - JBoss EAP 6.4 Runtime などの名前を入力します。Home Directory で、Browse をクリックして、JBoss EAP のインストール場所に移動します。Next をクリックします。
図1.4 新しいサーバーランタイム環境を追加する
[D]注記一部のクイックスタートでは、別のプロファイルまたは追加の引数を使用してサーバーを実行する必要があります。full
プロファイルを必要とするクイックスタートをデプロイするには、新しいサーバーを定義し、Configuration file にstandalone-full.xml
を指定する Server Runtime Environment を追加する必要があります。新しいサーバーにはわかりやすい名前を付けてください。 - 新しいサーバー用に既存のプロジェクトを設定します。この時点ではプロジェクトがないため、Finish をクリックします。
図1.5 新しい JBoss サーバーのリソースを変更します
[D]
1.4. 最初のアプリケーションを実行する
1.4.1. クイックスタートコード例をダウンロードする
1.4.1.1. クイックスタートにアクセスする
概要
JBoss EAP 6 には、ユーザーが Java EE 6 テクノロジーを使用してアプリケーションを書き始めるのに役立つように設計された一連のクイックスタートの例が付属しています。
前提条件
- Maven 3.0.0 以降。Maven のインストールの詳細は、http://maven.apache.org/download.htmlを参照してください。
- JBoss EAP 6 Maven リポジトリーはオンラインで利用できるため、ローカルにダウンロードしてインストールする必要はありません。オンラインリポジトリーを使用する場合は、次の手順にスキップできます。ローカルリポジトリーをインストールする場合は、以下を参照してください。「JBoss EAP 6 Maven リポジトリーのローカルインストール」。
手順1.4 クイックスタートのダウンロード
- Web ブラウザーを開き、次の URL にアクセスします。https://access.redhat.com/jbossnetwork/restricted/listSoftware.html?product=appplatform。
- リストからクイックスタートを見つけます。
- Download ボタンをクリックして、例を含む Zip アーカイブをダウンロードします。
- 選択したディレクトリーでアーカイブを解凍します。
結果
JBoss EAP クイックスタートがダウンロードされて解凍されました。各クイックスタートの展開手順については、クイックスタートアーカイブの最上位ディレクトリーにある README.md
ファイルを参照してください。
1.4.2. クイックスタートを実行する
1.4.2.1. Red Hat JBoss Developer Studio でクイックスタートを実行します
手順1.5 クイックスタートを Red Hat JBoss Developer Studio にインポートします
- まだ行っていない場合は、 「Maven 設定を使用した JBoss EAP 6 Maven リポジトリーの設定」。
- Red Hat JBoss Developer Studio を起動します。
- メニューから File → Import を選択します。
- 選択リストで、Maven → Existing Maven Projects を選択し、Next をクリックします。
図1.7 既存の Maven プロジェクトのインポート
[D] - テストする予定のクイックスタートのディレクトリー (たとえば、
helloworld
クイックスタート) を参照し、OK をクリックします。Projects リストボックスに、選択したクイックスタートプロジェクトのpom.xml
ファイルが示されます。図1.8 Maven プロジェクトの選択
[D] - Finish をクリックします。
手順1.6 helloworld
クイックスタートをビルドしてデプロイする
helloworld
クイックスタートは最もシンプルなクイックスタートの 1 つであり、JBoss サーバーが正しく設定され実行されていることを確認するための良い方法です。
- Servers タブが表示されない場合、またはサーバーをまだ定義していない場合は、次の手順に従ってください。「Define New Server を使用して JBossEAP サーバーを追加します」。
full
プロファイルまたは追加のスタートアップ引数を必要とするクイックスタートをデプロイする場合は、クイックスタートの手順に記載されているように、必ずサーバーランタイム環境を作成してください。 - Project Explorer タブで
jboss-helloworld
プロジェクトを右クリックし、Run As を選択します。選択肢のリストが提供されます。Run on Server を選択します。図1.9 Run As - Run on Server
[D] - サーバーリストから JBoss EAP 6.1+ Runtime Server を選択し、Next をクリックします。
図1.10 Run on Server
[D] - 次の画面には、サーバーで設定されているリソースが表示されます。
jboss-helloworld
クイックスタートが設定されています。Finish をクリックしてクイックスタートをデプロイします。図1.11 サーバーで設定されたリソースの変更
[D] - 結果を表示します。
Server
タブで、JBoss EAP 6.x ランタイムサーバーのステータスが[Started, Republish]
に変わります。- サーバーの Console タブには、JBoss EAP 6.x サーバーの起動と helloworld クイックスタートのデプロイメントの詳細を示すメッセージが表示されます。
- URL (http://localhost:8080/jboss-helloworld/HelloWorld) とテキスト Hello World! を示す helloworld タブが表示されます。
- Console の次のメッセージは、
jboss-helloworld.war
ファイルのデプロイを確認します。JBAS018210: Register web context: /jboss-helloworld JBAS018559: Deployed "jboss-helloworld.war" (runtime-name : "jboss-helloworld.war")
登録された Web コンテキストはhttp://localhost:8080
に追加され、デプロイされたアプリケーションへのアクセスに使用される URL を提供します。
- JBoss サーバーに正常にデプロイされた
helloworld
クイックスタートを確認するには、Web ブラウザーを開き、次の URL でアプリケーションにアクセスします。http://localhost:8080/jboss-helloworld
手順1.7 bean-validation
クイックスタート Arquillian テストの実行
bean-validation
クイックスタートは、Arquillian テストを提供するクイックスタートの例です。
- 上記の手順に従って、
bean-validation
クイックスタートを Red Hat JBoss Developer Studio にインポートします。 - Servers タブでサーバーを右クリックし、Start を選択して JBoss EAP サーバーを起動します。Servers タブが表示されない場合、またはサーバーをまだ定義していない場合は、次の手順に従ってください。「Define New Server を使用して JBossEAP サーバーを追加します」。
- Project Explorer タブで
jboss-bean-validation
プロジェクトを右クリックし、Run As を選択します。選択肢のリストが提供されます。Maven Build を選択します。 - Edit Configuration ダイアログの Goals 入力フィールドに、次のように入力します clean test -Parq-jbossas-remote。次に、Run をクリックします。
図1.12 設定の編集
[D] - 結果を表示します。サーバーの Console タブには、JBoss EAP サーバーの起動と
bean-validation
クイックスタート Arquillian テストの出力の詳細を示すメッセージが表示されます。------------------------------------------------------- T E S T S ------------------------------------------------------- Running org.jboss.as.quickstarts.bean_validation.test.MemberValidationTest Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.189 sec Results : Tests run: 5, Failures: 0, Errors: 0, Skipped: 0 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------
1.4.2.2. コマンドラインを使用してクイックスタートを実行する
手順1.8 コマンドラインを使用してクイックスタートをビルドおよびデプロイする
- まだ行っていない場合は、 「Maven 設定を使用した JBoss EAP 6 Maven リポジトリーの設定」。
- クイックスタートのルートディレクトリーにある
README.html
ファイルを確認します。このファイルには、システム要件、Maven の設定方法、ユーザーの追加方法、およびクイックスタートの実行方法に関する一般的な情報が含まれています。始める前に必ず読んでください。また、利用可能なクイックスタートを一覧表示する表も含まれています。この表には、各クイックスタート名とそれが示すテクノロジーがリストされています。各クイックスタートと、それを設定するために必要な経験のレベルについて簡単に説明します。クイックスタートの詳細は、クイックスタート名をクリックしてください。一部のクイック起動は、他のクイック起動を強化または拡張するように設計されています。これらは、Prerequisites
の列に記載されています。クイックスタートに前提条件がリストされている場合は、クイックスタートを使用する前にまずそれらをインストールする必要があります。一部のクイックスタートでは、オプションのコンポーネントのインストールと設定が必要です。クイックスタートで必要な場合を除いて、これらのコンポーネントをインストールしないでください。 helloworld
クイックスタートを実行します。helloworld
クイックスタートは最もシンプルなクイックスタートの 1 つであり、JBoss サーバーが正しく設定され実行されていることを確認するための良い方法です。helloworld
クイックスタートのルートにあるREADME.html
ファイルを開きます。クイックスタートをビルドしてデプロイし、実行中のアプリケーションにアクセスする方法の詳細な手順が含まれています- 他のクイックスタートを実行します。各クイックスタートのルートフォルダーにある
README.html
ファイルの指示に従って、例を実行します。
1.4.3. クイックスタートチュートリアルを確認する
1.4.3.1. helloworld クイックスタート
概要
helloworld クイックスタートは JBoss EAP 6 に単純なサーブレットをデプロイする方法を示します。ビジネスロジックは CDI (Contexts and Dependency Injection: コンテキストと依存関係の挿入) Bean として提供されるサービスにカプセル化され、サーブレットに挿入されます。このクイックスタートは非常に簡単です。HelloWorld を Web ページに出力するだけです。サーバーを適切に設定して起動したことを確認することは、良い出発点です。
helloworld
クイックスタートをインポートして正常に実行したことを前提としています。
前提条件
- 以下の手順に従って、Red Hat JBossDeveloperStudio をインストールします。「Install Red Hat JBoss Developer Studio」。
- 以下の手順に従って、Red Hat JBoss Developer Studio で使用するように Maven を設定します。「Red Hat JBoss Developer Studio で使用するための Maven の設定」。
- こちらの手順に従って、Red Hat JBoss Developer Studio で
helloworld
クイックスタートをインポート、ビルド、およびデプロイします。 「Red Hat JBoss Developer Studio でクイックスタートを実行します」 - Web ブラウザーを開き、次の URL でアプリケーションにアクセスして、
helloworld
クイックスタートが JBoss EAP に正常にデプロイされたことを確認します。 http://localhost:8080/jboss-helloworld
手順1.9 ディレクトリー構造の確認
QUICKSTART_HOME/helloworld
ディレクトリーにあります。helloworld クイックスタートはサーブレットと CDI Bean によって構成されます。また、JBoss EAP 6 にこのアプリケーションで Bean を検索し、CDI をアクティブ化するように指示する空の beans.xml ファイルも含まれています。
Beans.xml
ファイルは、クイックスタートのsrc/main/webapp/
ディレクトリーのWEB-INF/
フォルダーにあります。src/main/webapp/
ディレクトリーには、シンプルなメタリフレッシュを使用してユーザーのブラウザーをサーブレットにリダイレクトするindex.html
ファイルも含まれており、これはhttp://localhost:8080/jboss-helloworld/HelloWorldに配置されています。- この例のすべての設定ファイルは、
WEB-INF/
にあります。これは、例のsrc/main/webapp/
ディレクトリーにあります。 - クイックスタートには
web.xml
ファイルも必要ないことに注意してください。
手順1.10 コードの確認
HelloWorldServlet コードを確認します。
HelloWorldServlet.java
ファイルはsrc/main/java/org/jboss/as/quickstarts/helloworld/
ディレクトリーにあります。このサーブレットが情報をブラウザーに送ります。42. @SuppressWarnings("serial") 43. @WebServlet("/HelloWorld") 44. public class HelloWorldServlet extends HttpServlet { 45. 46. static String PAGE_HEADER = "<html><head><title>helloworld</title></head><body>"; 47. 48. static String PAGE_FOOTER = "</body></html>"; 49. 50. @Inject 51. HelloService helloService; 52. 53. @Override 54. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 55. resp.setContentType("text/html"); 56. PrintWriter writer = resp.getWriter(); 57. writer.println(PAGE_HEADER); 58. writer.println("<h1>" + helloService.createHelloMessage("World") + "</h1>"); 59. writer.println(PAGE_FOOTER); 60. writer.close(); 61. } 62. 63. }
表1.1 HelloWorldServlet の詳細
行 注記 43 Java EE 6 より前は、XML ファイルを使用してサーブレットを登録していました。よりきれいになりました。必要な作業は @WebServlet
アノテーションを追加し、サーブレットにアクセスするために使用する URL にマッピングを提供するだけです。46〜48 各 Web ページには適切な形式の HTML が必要になります。本クイックスタートは静的な文字列を使用して最低限のヘッダーとフッターの出力を書き出します。 50〜51 これらの行は、実際のメッセージを生成する HelloService CDI Bean を挿入します。HelloService の API を変更しない限り、ビューレイヤーを変更せずに HelloService の実装を後で変更することが可能です。 58 この行はサービスを呼び出し、「Hello World」というメッセージを生成して HTTP 要求へ書き出します。 HelloService コードを確認します
HelloService.java
ファイルはsrc/main/java/org/jboss/as/quickstarts/helloworld/
ディレクトリーにあります。このサービスはとてもシンプルです。メッセージを返します。XML やアノテーションの登録は必要ありません。public class HelloService { String createHelloMessage(String name) { return "Hello " + name + "!"; } }
1.4.3.2. numberguess クイックスタート
概要
このクイックスタートでは、簡単なアプリケーションを作成して JBoss EAP 6 にデプロイする方法を示します。このアプリケーションは情報を保持しません。情報は JSF ビューを使用して表示され、ビジネスロジックは 2 つの CDI (コンテキストと依存性注入) Bean にカプセル化されます。numberguess クイックスタートでは、1 から 100 までの数字を推測する試みが 10 回行われます。数字を選択した後、その数字が正解の数字よりも大きいかまたは小さいかが表示されます。
QUICKSTART_HOME/numberguess
ディレクトリーにあります。numberguess クイックスタートは複数の Bean、設定ファイル、および Facelets (JSF) ビューによって構成され、WAR モジュールとしてパッケージ化されています。
numberguess
クイックスタートをインポートして正常に実行したことを前提としています。
前提条件
- 以下の手順に従って、Red Hat JBossDeveloperStudio をインストールします。「Install Red Hat JBoss Developer Studio」。
- 以下の手順に従って、Red Hat JBoss Developer Studio で使用するように Maven を設定します。「Red Hat JBoss Developer Studio で使用するための Maven の設定」。
- こちらの手順に従って、Red Hat JBoss Developer Studio で
numberguess
クイックスタートをインポート、ビルド、およびデプロイします。 「Red Hat JBoss Developer Studio でクイックスタートを実行します」 - Web ブラウザーを開き、次の URL でアプリケーションにアクセスして、
numberguess
クイックスタートが JBoss EAP に正常にデプロイされたことを確認します。 http://localhost:8080/jboss-numberguess
手順1.11 設定ファイルの確認
src/main/webapp/
ディレクトリーにある WEB-INF/
ディレクトリーに配置されています。
faces-config.xml
ファイルを確認します。本クイックスタートはfaces-config.xml
ファイル名の JSF 2.0 バージョンを使用します。Facelets の標準化されたバージョンは JSF 2.0 のデフォルトのビューハンドラーであるため、実際に設定する必要はありません。JBoss EAP 6 は、ここで JavaEE を超えています。この設定ファイルを含めると、JSF が自動的に設定されます。その結果、設定はルート要素のみで設定されます。19. <faces-config version="2.0" 20. xmlns="http://java.sun.com/xml/ns/javaee" 21. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 22. xsi:schemaLocation=" 23. http://java.sun.com/xml/ns/javaee> 24. http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"> 25. 26. </faces-config>
beans.xml
ファイルを確認します。空のbeans.xml
ファイルもあります。これは、JBoss EAP 6 にこのアプリケーションで Bean を検索し、CDI をアクティブ化するように指示します。web.xml
ファイルはありませんクイックスタートにはweb.xml
ファイルも必要ないことに注意してください。
手順1.12 JSF コードの確認
.xhtml
ファイル拡張子を使用しますが、レンダリングされたビューは .jsf
拡張子で提供されます。
home.xhtml
コードを調べます。home.xhtml
ファイルはsrc/main/webapp/
ディレクトリーにあります。19. <html xmlns="http://www.w3.org/1999/xhtml" 20. xmlns:ui="http://java.sun.com/jsf/facelets" 21. xmlns:h="http://java.sun.com/jsf/html" 22. xmlns:f="http://java.sun.com/jsf/core"> 23. 24. <head> 25. <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> 26. <title>Numberguess</title> 27. </head> 28. 29. <body> 30. <div id="content"> 31. <h1>Guess a number...</h1> 32. <h:form id="numberGuess"> 33. 34. <!-- Feedback for the user on their guess --> 35. <div style="color: red"> 36. <h:messages id="messages" globalOnly="false" /> 37. <h:outputText id="Higher" value="Higher!" 38. rendered="#{game.number gt game.guess and game.guess ne 0}" /> 39. <h:outputText id="Lower" value="Lower!" 40. rendered="#{game.number lt game.guess and game.guess ne 0}" /> 41. </div> 42. 43. <!-- Instructions for the user --> 44. <div> 45. I'm thinking of a number between <span 46. id="numberGuess:smallest">#{game.smallest}</span> and <span 47. id="numberGuess:biggest">#{game.biggest}</span>. You have 48. #{game.remainingGuesses} guesses remaining. 49. </div> 50. 51. <!-- Input box for the users guess, plus a button to submit, and reset --> 52. <!-- These are bound using EL to our CDI beans --> 53. <div> 54. Your guess: 55. <h:inputText id="inputGuess" value="#{game.guess}" 56. required="true" size="3" 57. disabled="#{game.number eq game.guess}" 58. validator="#{game.validateNumberRange}" /> 59. <h:commandButton id="guessButton" value="Guess" 60. action="#{game.check}" 61. disabled="#{game.number eq game.guess}" /> 62. </div> 63. <div> 64. <h:commandButton id="restartButton" value="Reset" 65. action="#{game.reset}" immediate="true" /> 66. </div> 67. </h:form> 68. 69. </div> 70. 71. <br style="clear: both" /> 72. 73. </body> 74. </html>
表1.2 JSF の詳細
行 注記 36〜40 これらはユーザーに送信できるメッセージ、「Higher」(より大きい) と「Lower」(より小さい) です。 45〜48 ユーザーが数を選択するごとに数字の範囲が狭まります。有効な数の範囲が分かるようにこの文章は変更されます。 55〜58 この入力フィールドは値式を使用して Bean プロパティーにバインドされます。 58 ユーザーが誤って範囲外の数字を入力しないようにバリデーターのバインディングが使用されます。バリデーターがないと、ユーザーが範囲外の数字を使用する可能性があります。 59〜61 ユーザーの選択した数字をサーバーに送る方法がなければなりません。ここでは、Bean 上のアクションメソッドをバインドします。
手順1.13 クラスファイルの確認
src/main/java/org/jboss/as/quickstarts/numberguess/
ディレクトリーにあります。パッケージの宣言とインポートはこれらのリストからは除外されています。完全リストはクイックスタートのソースコードで確認できます。
Random.java
修飾子コードの検証修飾子は、型を基にしたインジェクションの対象となる 2 つの bean 間のあいまいさを取り除くために使用されます。修飾語の詳細については、以下を参照してください。 「修飾子を使用したあいまいなインジェクションの解決」@Random
修飾子は乱数のインジェクトに使用されます。@Target({ TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Documented @Qualifier public @interface Random { }
MaxNumber.java
修飾子コードの検証@MaxNumber
qualifier
は最大許可数の挿入に使用されます。@Target({ TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Documented @Qualifier public @interface MaxNumber { }
Generator.java
コードの検証Generator
クラスは、プロデューサーメソッドを介して乱数を作成するロールを果たします。また、プロデューサーメソッドを介して可能な最大数を公開します。このクラスはアプリケーションスコープであるため、毎回異なる乱数になることはありません。@SuppressWarnings("serial") @ApplicationScoped public class Generator implements Serializable { private java.util.Random random = new java.util.Random(System.currentTimeMillis()); private int maxNumber = 100; java.util.Random getRandom() { return random; } @Produces @Random int next() { // a number between 1 and 100 return getRandom().nextInt(maxNumber - 1) + 1; } @Produces @MaxNumber int getMaxNumber() { return maxNumber; } }
Game.java
コードの検証セッションスコープのクラスGame
は、アプリケーションの主要なエントリーポイントです。ゲームの設定や再設定、ユーザーが選択する数字のキャプチャーや検証、FacesMessage
によるユーザーへのフィードバック提供を行います。コンストラクト後の lifecycle メソッドを使用し、@Random Instance
<Integer>
bean から乱数を取得することによりゲームを初期化します。このクラスの @Named アノテーションを見てください。このアノテーションは式言語 (EL) を使用して Bean が JSF ビューにアクセスできるようにしたい場合のみ必要です。この場合#{game}
が EL になります。@SuppressWarnings("serial") @Named @SessionScoped public class Game implements Serializable { /** * The number that the user needs to guess */ private int number; /** * The users latest guess */ private int guess; /** * The smallest number guessed so far (so we can track the valid guess range). */ private int smallest; /** * The largest number guessed so far */ private int biggest; /** * The number of guesses remaining */ private int remainingGuesses; /** * The maximum number we should ask them to guess */ @Inject @MaxNumber private int maxNumber; /** * The random number to guess */ @Inject @Random Instance<Integer> randomNumber; public Game() { } public int getNumber() { return number; } public int getGuess() { return guess; } public void setGuess(int guess) { this.guess = guess; } public int getSmallest() { return smallest; } public int getBiggest() { return biggest; } public int getRemainingGuesses() { return remainingGuesses; } /** * Check whether the current guess is correct, and update the biggest/smallest guesses as needed. Give feedback to the user * if they are correct. */ public void check() { if (guess > number) { biggest = guess - 1; } else if (guess < number) { smallest = guess + 1; } else if (guess == number) { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!")); } remainingGuesses--; } /** * Reset the game, by putting all values back to their defaults, and getting a new random number. We also call this method * when the user starts playing for the first time using {@linkplain PostConstruct @PostConstruct} to set the initial * values. */ @PostConstruct public void reset() { this.smallest = 0; this.guess = 0; this.remainingGuesses = 10; this.biggest = maxNumber; this.number = randomNumber.get(); } /** * A JSF validation method which checks whether the guess is valid. It might not be valid because there are no guesses left, * or because the guess is not in range. * */ public void validateNumberRange(FacesContext context, UIComponent toValidate, Object value) { if (remainingGuesses <= 0) { FacesMessage message = new FacesMessage("No guesses left!"); context.addMessage(toValidate.getClientId(context), message); ((UIInput) toValidate).setValid(false); return; } int input = (Integer) value; if (input < smallest || input > biggest) { ((UIInput) toValidate).setValid(false); FacesMessage message = new FacesMessage("Invalid guess"); context.addMessage(toValidate.getClientId(context), message); } } }
1.4.4. デフォルトの Welcome Web アプリケーションの置き換え
手順1.14 デフォルトの Welcome Web アプリケーションを独自の Web アプリケーションに置き換える
Welcome アプリケーションを無効にします。
管理 CLI スクリプトEAP_HOME/bin/jboss-cli.sh
を使用して、次のコマンドを実行します。プロファイルを変更して別の管理対象ドメインを変更するか、スタンドアロンサーバーのコマンドの/profile=default
部分を削除する必要があることがあります。/profile=default/subsystem=web/virtual-server=default-host:write-attribute(name=enable-welcome-root,value=false)
ルートコンテキストを使用するよう Web アプリケーションを設定します。
ルートコンテキスト (/) を URL アドレスとして使用するように Web アプリケーションを設定するには、META-INF/
またはWEB-INF/
ディレクトリーにあるjboss-web.xml
を変更します。その<context-root>
ディレクティブを次のようなものに置き換えます。<jboss-web> <context-root>/</context-root> </jboss-web>
アプリケーションをデプロイします。
最初のステップで変更したサーバーグループまたはサーバーにアプリケーションをデプロイします。アプリケーションは現在、http://SERVER_URL:PORT/
。
1.4.5. WS-AtomicTransaction の使用
wsat-simple
クイックスタートは、Red Hat JBoss Enterprise Application Platform にデプロイするために WAR アーカイブにバンドルされた WS-AT(WS-AtomicTransaction) 対応の JAX-WSWeb サービスのデプロイを示しています。
- サービスは、障害が発生した場合の回復をサポートするために必要なフックを実装していません。
- また、トランザクションバックエンドリソースを利用しません。
- プロトコルに参加する Web サービスは 1 つだけです。WS-AT は 2PC 調整プロトコルであるため、複数の参加者がいるシナリオに最適です。
org.jboss.as.quickstarts.wsat.simple.ClientTest#testCommit()
メソッドを実行すると、次の手順が実行されます。
- 新しい Atomic Transaction (AT) がクライアントによって作成されます。
- WS-AT 対応の Web サービスでの操作は、クライアントによって呼び出されます。
- WS クライアントハンドラーチェーンの JaxWSHeaderContextProcessor は、WS-AT コンテキストを送信 SOAP メッセージに挿入します。
- サービスが SOAP 要求を受信すると、ハンドラーチェーン内の JaxWSHeaderContextProcessor が WS-AT コンテキストを検査し、要求をこの AT に関連付けます。
- Web サービス操作が呼び出されます。
- 参加者はこの AT に参加しています。これにより、Web サービスロジックがコミットやロールバックなどのプロトコルイベントに応答できるようになります。
- サービスはビジネスロジックを呼び出します。この場合、レストランへの予約となります。
- バックエンドリソースが準備されます。これにより、コーディネーターから指示されたときに、バックエンドリソースが変更を元に戻したり永続的にしたりできるようになります。
- その後、クライアントは AT をコミットするかロールバックするかを決定できます。クライアントがコミットすることを決定した場合、コーディネーターは 2PC プロトコルを開始します。参加者がロールバックすることを決定した場合、すべての参加者はロールバックするように指示されます。
第2章 Maven ガイド
2.1. Maven について
2.1.1. Maven リポジトリー
http://
やファイルサーバーのリポジトリー用の file://
などの一般的なプロトコルが使用されます。
2.1.2. Maven POM ファイル
pom.xml
ファイルでは一部の設定オプションを設定する必要があり、他のすべてのオプションはデフォルト値に設定されます。詳細は、 「Maven POM ファイルの最低要件」 を参照してください。
pom.xml
ファイルのスキーマは次の場所にあります。http://maven.apache.org/maven-v4_0_0.xsd。
2.1.3. Maven POM ファイルの最低要件
最小要件
pom.xml
ファイルの最低要件は次のとおりです。
- プロジェクトルート
- modelVersion
- groupId - プロジェクトのグループの id
- artifactId - アーティファクト (プロジェクト) の id
- version - 指定したグループ下のアーティファクトのバージョン
サンプル pom.xml ファイル
基本的な pom.xml ファイルの例を以下に示します。
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.jboss.app</groupId> <artifactId>my-app</artifactId> <version>1</version> </project>
2.1.4. Maven 設定ファイル
settings.xml
ファイルには Maven のユーザー固有の設定情報が含まれています。開発者の ID、プロキシー情報、ローカルリポジトリーの場所、ユーザー固有のその他の設定など、pom.xml
ファイルで配布されてはならない情報が含まれます。
settings.xml
ファイルが存在する場所は 2 つあります。
- Maven インストール内:
- 設定ファイルは、
M2_HOME/conf/
ディレクトリーにあります。これらの設定はglobal
設定と呼ばれます。デフォルトの Maven 設定ファイルはコピー可能なテンプレートであり、これを基にユーザー設定ファイルを設定することが可能です。 - ユーザーのインストール内:
- 設定ファイルは、
USER_HOME/.m2/
ディレクトリーにあります。Maven とユーザーのsettings.xml
ファイルが両方存在する場合、内容はマージされます。重複する内容がある場合は、ユーザーのsettings.xml
ファイルが優先されます。
settings.xml
ファイルの例です。
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <profiles> <!-- Configure the JBoss EAP Maven repository --> <profile> <id>jboss-eap-maven-repository</id> <repositories> <repository> <id>jboss-eap</id> <url>file:///path/to/repo/jboss-eap-6.4-maven-repository</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss-eap-maven-plugin-repository</id> <url>file:///path/to/repo/jboss-eap-6.4-maven-repository</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile> </profiles> <activeProfiles> <!-- Optionally, make the repository active by default --> <activeProfile>jboss-eap-maven-repository</activeProfile> </activeProfiles> </settings>
settings.xml
ファイルのスキーマは次の場所にあります。http://maven.apache.org/xsd/settings-1.0.0.xsd。
2.2. Maven と JBoss Maven リポジトリーをインストールします
2.2.1. Maven のダウンロードおよびインストール
- Apache Maven Project - Download Maven にアクセスし、ご使用のオペレーティングシステムに対応する最新のディストリビューションをダウンロードします。
- ご使用のオペレーシングシステムに Apache Maven をダウンロードおよびインストールする方法は、Maven のドキュメントを参照してください。
2.2.2. JBoss EAP 6 Maven リポジトリーをインストールします
2.2.3. JBoss EAP 6 Maven リポジトリーのローカルインストール
概要
JBoss EAP 6 Maven リポジトリーはオンラインで利用できるため、ローカルにダウンロードしてインストールする必要はありません。ただし、JBoss EAP Maven リポジトリーをローカルにインストールする場合は、ローカルファイルシステム、Apache Web サーバー、または Maven リポジトリーマネージャーを使用する 3 つの方法があります。この例では、JBoss EAP 6 Maven リポジトリーをローカルファイルシステムにダウンロードする手順について説明します。このオプションは設定が簡単で、ローカルマシンですぐに実行することができます。開発時における Maven の使用方法を理解することができますが、チームの本番環境では推奨されません。
手順2.1 JBoss EAP 6 Maven リポジトリーをダウンロードしてローカルファイルシステムにインストールします
- Web ブラウザーを開き、次の URL にアクセスします。https://access.redhat.com/jbossnetwork/restricted/listSoftware.html?product=appplatform。
- リストから Red Hat JBoss Enterprise Application Platform VERSION Maven Repository を探します。
- Download ボタンをクリックして、リポジトリーを含む
.zip
ファイルをダウンロードします。 - ローカルファイルシステム上のファイルを、選択したディレクトリーに解凍します。
結果
これにより、jboss-eap-version-maven-repository
という Maven リポジトリーディレクトリーが作成されます。
settings.xml
設定ファイルで個別に設定する必要があります。各ローカルリポジトリーは、独自の <repository>
タグ内で設定する必要があります。
.m2/
ディレクトリーの下にあるキャッシュされた repository/
サブディレクトリーを削除してください。
2.2.4. Apache httpd で使用する JBoss EAP 6 Maven レポジトリーのインストール
前提条件
Apache httpd を設定する必要があります。手順は、Apache HTTP Server Project ドキュメンテーションを参照してください。
手順2.2 JBoss EAP 6 Maven リポジトリーの ZIP アーカイブをダウンロードする
- Web ブラウザーを開き、次の URL にアクセスします。https://access.redhat.com/jbossnetwork/restricted/listSoftware.html?product=appplatform。
- リストから Red Hat JBoss Enterprise Application Platform <VERSION> Maven リポジトリーを見つけます。
- Download ボタンをクリックして、リポジトリーを含む
.zip
ファイルをダウンロードします。 - Apache サーバー上で Web にアクセス可能なディレクトリーに Zip 形式のファイルを展開します。
- 作成されたディレクトリーで読み取りアクセスとディレクトリーの閲覧を許可するよう Apache を設定します。
結果
これにより、マルチユーザー環境が Apache httpd の Maven リポジトリーにアクセスできるようになります。
2.2.5. JBoss EAP 6 リポジトリーマネージャーを使用して JBoss EAP 6 Maven リポジトリーをインストールします
手順2.3 JBoss EAP 6 Maven リポジトリーの ZIP アーカイブをダウンロードする
- Web ブラウザーを開き、次の URL にアクセスします。https://access.redhat.com/jbossnetwork/restricted/listSoftware.html?product=appplatform。
- リストから Red Hat JBoss Enterprise Application Platform <VERSION> Maven リポジトリーを見つけます。
- Download ボタンをクリックして、リポジトリーを含む
.zip
ファイルをダウンロードします。 - Nexus をホストしているサーバー上の選択したディレクトリーにファイルを解凍します。
手順2.4 JBoss EAP 6 リポジトリーマネージャーを使用して JBoss EAP 6 Maven リポジトリーを追加します
- 管理者として Nexus にログインします。
- リポジトリーマネージャーの左側にある Views → Repositories メニューから Repositories セクションを選択します。
- Add... ドロップダウンをクリックし、Hosted Repository を選択します。
- 新しいリポジトリーに名前と ID を付けます。
- Override Local Storage するフィールドに、解凍したリポジトリーへのディスク上のパスを入力します。
- アーティファクトをリポジトリーグループで使用できるようにする場合は、続行します。これが希望どおりでない場合は、この手順を続行しないでください。
- リポジトリーグループを選択します。
- Configure タブをクリックします。
- 新しい JBoss Maven リポジトリーを Available Repositories リストから左側の Ordered Group Repositories リストにドラッグします。注記このリストの順序によって、Maven アーティファクトを検索するための優先順位が決まることに注意してください。
結果
リポジトリーは、Nexus Maven リポジトリーマネージャーを使用して設定されます。
2.2.6. Maven リポジトリーマネージャー
- ユーザーの組織のリポジトリーとリモート Maven リポジトリーとの間のプロキシーを設定する機能を提供します。これには、デプロイメントの高速化や効率化、Maven によるダウンロード対象を制御するレベルの向上など、さまざまな利点があります。
- 独自に生成したアーティファクトのデプロイ先を提供し、組織内の異なる開発チーム間におけるコラボレーションを可能にします。
一般的に使用される Maven リポジトリーマネージャー
- Sonatype Nexus
- Nexus の詳細については、Sonatype Nexus: アーティファクトの管理 を参照してください。
- Artifactory
- Artifactory の詳細は、Artifactory オープンソース を参照してください。
- Apache Archiva
- Apache Archiva の詳細は、Apache Archiva: The Build Artifact Repository Manager を参照してください。
2.3. Maven リポジトリーの使用
2.3.1. JBoss EAP Maven 6 リポジトリーを設定します
概要
プロジェクトで JBoss EAP 6 Maven リポジトリーを使用するよう Maven に指示する方法は 2 つあります。
- リポジトリーを Maven グローバルまたはユーザー設定で設定します。
- リポジトリーをプロジェクトの POM ファイルで設定します。
手順2.5 JBoss EAP 6 Maven リポジトリーを使用するように Maven 設定を設定する
Maven 設定を使用して Maven リポジトリーを設定します
これは、推奨の手法です。リポジトリーマネージャーや共有サーバー上のリポジトリーを使用して Maven を設定すると、プロジェクトの制御および管理を行いやすくなります。また、代替のミラーを使用してプロジェクトファイルを変更せずにリポジトリーマネージャーに特定のリポジトリーのルックアップ要求をすべてリダイレクトすることも可能になります。ミラーの詳細は、http://maven.apache.org/guides/mini/guide-mirror-settings.html を参照してください。プロジェクトの POM ファイルにリポジトリー設定が含まれていない場合、この設定方法はすべての Maven プロジェクトに対して適用されます。プロジェクト POM を使用して Maven リポジトリーを設定します
この設定方法は、通常はお勧めしません。プロジェクトの POM ファイルでリポジトリーを設定する場合は、慎重に計画し、ビルドが遅くなる可能性があり、予期されたリポジトリーからではないアーティファクトが発生する可能性があることに注意してください。注記リポジトリーマネージャーが通常使用されるエンタープライズ環境では、Maven は、このマネージャーを使用してすべてのプロジェクトに対してすべてのアーティファクトを問い合わせる必要があります。Maven は、宣言されたすべてのリポジトリーを使用して不足しているアーティファクトを見つけるため、探しているものが見つからない場合に、central リポジトリー (組み込みの親 POM で定義されます) で検索を試行します。この central の場所をオーバーライドするには、central
で定義を追加してデフォルトの central リポジトリーがリポジトリーマネージャーになるようにします。これは、確立されたプロジェクトには適切ですが、クリーンなプロジェクトや「新しい」プロジェクトの場合は、cyclic 依存関係が作成されるため、問題が発生します。推移的に含まれる POM も、このタイプの設定の問題です。Maven は、これらの外部リポジトリーに欠落しているアーティファクトを照会する必要があります。これにより、ビルドの速度が低下するだけでなく、アーティファクトの発生元を制御できなくなり、ビルドが破損する可能性があります。この設定方法は、設定されたプロジェクトのグローバル設定とユーザー Maven 設定をオーバーライドします。
2.3.2. Maven 設定を使用した JBoss EAP 6 Maven リポジトリーの設定
- Maven の設定を変更できます。これにより、Maven はすべてのプロジェクトで設定を使用するように指示されます。
- プロジェクトの POM ファイルを設定できます。これにより、設定が特定のプロジェクトに制限されます。
- ファイルシステム
- file:///path/to/repo/jboss-eap-6.x-maven-repository
- Apache Web Server
- http://intranet.acme.com/jboss-eap-6.x-maven-repository/
- Nexus リポジトリーマネージャー
- https://intranet.acme.com/nexus/content/repositories/jboss-eap-6.x-maven-repository
手順2.6 クイックスタートの例に含まれる設定を使って Maven を設定する
settings.xml
ファイルが付属しています。これが最も簡単なアプローチです。
- この手順では、既存の Maven 設定ファイルが上書きされるため、既存の
Mavensettings.xml
ファイルをバックアップする必要があります。- オペレーティングシステムの Maven インストールディレクトリーを見つけます。通常、
USER_HOME/.m2/
ディレクトリーにインストールされます。- Linux または Mac では、これは
~/.m2/
になります。 - Windows の場合、これは次のとおりです。
\Documents and Settings\USER_NAME\.m2\
または\Users\USER_NAME\.m2\
- 既存の
USER_HOME/.m2/settings.xml
ファイルがある場合は、後で復元できるように、ファイルの名前を変更するか、バックアップコピーを作成します。
- JBoss EAP 6 に付属のクイックスタートの例をダウンロードして解凍します。詳細は、「クイックスタートにアクセスする」 を参照してください
QUICKSTART_HOME/settings.xml
ファイルをUSER_HOME/.m2/
ディレクトリーにコピーします。- Red Hat JBoss Developer Studio の実行中に
settings.xml
ファイルを変更する場合は、以下のタイトルの手順に従ってください。手順2.9「Red Hat JBoss Developer Studio のユーザー設定を更新します」。
手順2.7 Online JBoss EAP 6 Maven リポジトリーを使用するには、Maven 設定を手動で編集および設定します
- オペレーティングシステムの Maven インストールディレクトリーを見つけます。通常、
USER_HOME/.m2/
ディレクトリーにインストールされます。- Linux または Mac では、これは
~/.m2/
になります。 - Windows の場合、これは
\Documents and Settings\USER_NAME\.m2\
または\Users\USER_NAME\.m2\
です。
settings.xml
ファイルが見つからない場合、settings.xml
ファイルをUSER_HOME/.m2/conf/
ディレクトリーからUSER_HOME/.m2/
ディレクトリへコピーします。- 次の XML を
<profiles>
ファイルの要素にコピーします。<!-- Configure the JBoss GA Maven repository --> <profile> <id>jboss-ga-repository</id> <repositories> <repository> <id>jboss-ga-repository</id> <url>http://maven.repository.redhat.com/techpreview/all</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss-ga-plugin-repository</id> <url>http://maven.repository.redhat.com/techpreview/all</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile> <!-- Configure the JBoss Early Access Maven repository --> <profile> <id>jboss-earlyaccess-repository</id> <repositories> <repository> <id>jboss-earlyaccess-repository</id> <url>http://maven.repository.redhat.com/earlyaccess/all/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss-earlyaccess-plugin-repository</id> <url>http://maven.repository.redhat.com/earlyaccess/all/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile>
次の XML をsettings.xml
ファイルの要素<activeProfiles>
にコピーします。<activeProfile>jboss-ga-repository</activeProfile> <activeProfile>jboss-earlyaccess-repository</activeProfile>
- Red Hat JBoss Developer Studio の実行中に
settings.xml
ファイルを変更する場合は、以下のタイトルの手順に従ってください。手順2.9「Red Hat JBoss Developer Studio のユーザー設定を更新します」。
手順2.8 ローカルにインストールされた JBoss EAP リポジトリーを使用するように設定を設定します
- オペレーティングシステムの Maven インストールディレクトリーを見つけます。通常、
USER_HOME/.m2/
ディレクトリーにインストールされます。- Linux または Mac では、これは
~/.m2/
になります。 - Windows の場合、これは
\Documents and Settings\USER_NAME\.m2\
または\Users\USER_NAME\.m2\
です。
settings.xml
ファイルが見つからない場合、settings.xml
ファイルをUSER_HOME/.m2/conf/
ディレクトリーからUSER_HOME/.m2/
ディレクトリへコピーします。- 次の XML を
settings.xml
ファイルの要素<profiles>
にコピーします。必ず<url>
を実際のリポジトリーの場所に変更するようにしてください。<profile> <id>jboss-eap-repository</id> <repositories> <repository> <id>jboss-eap-repository</id> <name>JBoss EAP Maven Repository</name> <url>file:///path/to/repo/jboss-eap-6.x-maven-repository</url> <layout>default</layout> <releases> <enabled>true</enabled> <updatePolicy>never</updatePolicy> </releases> <snapshots> <enabled>false</enabled> <updatePolicy>never</updatePolicy> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss-eap-repository-group</id> <name>JBoss EAP Maven Repository</name> <url> file:///path/to/repo/jboss-eap-6.x-maven-repository </url> <layout>default</layout> <releases> <enabled>true</enabled> <updatePolicy>never</updatePolicy> </releases> <snapshots> <enabled>false</enabled> <updatePolicy>never</updatePolicy> </snapshots> </pluginRepository> </pluginRepositories> </profile>
次の XML をsettings.xml
ファイルの要素<activeProfiles>
にコピーします。<activeProfile>jboss-eap-repository</activeProfile>
- Red Hat JBoss Developer Studio の実行中に
settings.xml
ファイルを変更する場合は、以下のタイトルの手順に従ってください。手順2.9「Red Hat JBoss Developer Studio のユーザー設定を更新します」。
手順2.9 Red Hat JBoss Developer Studio のユーザー設定を更新します
settings.xml
ファイルを変更する場合は、ユーザー設定を更新する必要があります。
- メニューから、Window → Preferences を選択します。
- Preferences ウインドウで Maven を展開表示し、User Settings を選択します。
- Update Settings ボタンをクリックし、Red Hat JBoss Developer Studio で Maven のユーザー設定を更新します。
図2.1 Maven ユーザー設定を更新する
[D]
- アーティファクト ARTIFACT_NAME がありません
- [ERROR] Failed to execute goal on project PROJECT_NAME; Could not resolve dependencies for PROJECT_NAME
~/.m2/repository/
サブディレクトリー、Windows の場合は %SystemDrive%\Users\USERNAME\.m2\repository\
サブディレクトリーにあります。
2.3.3. Red Hat JBoss Developer Studio で使用するための Maven の設定
手順2.10 Red Hat JBoss Developer Studio で Maven を設定する
- Window → Preferences の順にクリックし、JBoss Tools を展開して JBoss Maven Integration を選択します。
図2.2 Preferences ウィンドウの JBoss Maven 統合ペイン
- Configure Maven Repositories をクリックします。
- Add Repository をクリックして、JBoss GA Tech Preview Maven リポジトリー を設定します。
Add Maven Repository
ダイアログで以下の手順を実行します。- Profile ID、Repository ID、および Repository Name の値を
jboss-ga-repository
に設定します。 - Repository URL 値を
http://maven.repository.redhat.com/techpreview/all
に設定します。 - Active by default チェックボックスをクリックして Maven リポジトリーを有効にします。
- OK をクリックします。
図2.3 Maven リポジトリーの追加 -JBoss Tech Preview
- Add Repositoryをクリックして、JBoss Early Access Maven リポジトリーを設定します。
Add Maven Repository
ダイアログで以下の手順を実行します。- Profile ID、Repository ID、および Repository Name の値を
jboss-earlyaccess-repository
に設定します。 - Repository URL 値を
http://maven.repository.redhat.com/earlyaccess/all/
に設定します。 - Active by default チェックボックスをクリックして Maven リポジトリーを有効にします。
- OK をクリックします。
図2.4 Maven リポジトリーの追加 -JBoss Early Access
- リポジトリーを確認して、Finish をクリックします。
図2.5 Maven リポジトリーを確認する
- Are you sure you want to update the file MAVEN_HOME/settings.xml? というメッセージが表示されます。Yes をクリックして設定を更新します。OK をクリックしてダイアログを閉じます。これで、JBoss EAP Maven リポジトリーが Red Hat JBoss Developer Studio で使用できるように設定されました。
2.3.4. プロジェクト POM を使用した JBoss EAP 6 Maven リポジトリーの設定
- Maven の設定を変更できます。
- プロジェクトの POM ファイルを設定できます。
pom.xml
にリポジトリー情報を追加して、JBoss EAP 6 Maven リポジトリーを使用するように特定のプロジェクトを設定する方法を示します。この設定方法は、グローバル設定とユーザー設定の設定に優先し、オーバーライドします。
central
で定義を追加してデフォルトの central リポジトリーがリポジトリーマネージャーになるようにします。これは、確立されたプロジェクトには適切ですが、クリーンなプロジェクトや「新しい」プロジェクトの場合は、cyclic 依存関係が作成されるため、問題が発生します。
- ファイルシステム
- file:///path/to/repo/jboss-eap-6.x-maven-repository
- Apache Web Server
- http://intranet.acme.com/jboss-eap-6.x-maven-repository/
- Nexus リポジトリーマネージャー
- https://intranet.acme.com/nexus/content/repositories/jboss-eap-6.x-maven-repository
- テキストエディターでプロジェクトの
pom.xml
ファイルを開きます。 - 次のリポジトリー設定を追加します。ファイル内にすでに
<repositories>
の設定がある場合は、それに<repository>
の要素を追加します。必ず<url>
を実際のリポジトリーの場所に変更するようにしてください。<repositories> <repository> <id>jboss-eap-repository-group</id> <name>JBoss EAP Maven Repository</name> <url>file:///path/to/repo/jboss-eap-6.x.0-maven-repository/</url> <layout>default</layout> <releases> <enabled>true</enabled> <updatePolicy>never</updatePolicy> </releases> <snapshots> <enabled>true</enabled> <updatePolicy>never</updatePolicy> </snapshots> </repository> </repositories>
- 次のプラグインリポジトリー設定を追加します。ファイル内にすでに
<pluginRepositories>
の設定がある場合は、それに<pluginRepository>
の要素を追加します。<pluginRepositories> <pluginRepository> <id>jboss-eap-repository-group</id> <name>JBoss EAP Maven Repository</name> <url>file:///path/to/repo/jboss-eap-6.x.0-maven-repository/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories>
2.3.5. プロジェクト依存関係の管理
pom.xml
(POM) ファイルです。バージョン依存関係は、ファイルの依存関係管理セクションにリストされています。
pom.xml
ファイルの依存関係管理セクションに groupId:artifactId:version
(GAV) を追加し、<scope>import</scope>
と<type>pom</type>
の要素値を指定することで BOM を使用します。
provided
スコープが使用されます。これは、これらのクラスが実行時にアプリケーションサーバーによって提供され、ユーザーアプリケーションとともにパッケージ化する必要がないためです。
サポート対象の Maven アーティファクト
1.0.0-redhat-1
のように使用される -redhat
バージョン修飾子によって簡単に識別可能です。
pom.xml
ファイルに追加すると、ローカルビルドおよびテスト向けの適切なバイナリーアーティファクトがビルドで使用されるようになります。-redhat
バージョンのアーティファクトは、サポートされるパブリック API の一部とは限らず、今後の改訂で変更されることがあります。サポートされるパブリック API の詳細は、本リリースに含まれる JavaDoc ドキュメント を参照してください。
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.2.16.Final-redhat-1</version> <scope>provided</scope> </dependency>上記の例では、
<version/>
のフィールドに値が含まれていることに注意してください。ただし、依存関係バージョンの設定には、Maven の依存関係管理を使用することが推奨されます。
依存関係管理
<dependencyManagement> <dependencies> ... <dependency> <groupId>org.jboss.bom</groupId> <artifactId>eap6-supported-artifacts</artifactId> <version>6.4.0.GA</version> <type>pom</type> <scope>import</scope> </dependency> ... </dependencies> </dependencyManagement>
JBoss JavaEE Specs Bom
jboss-javaee-6.0
BOM には、JBoss EAP で使用される Java EE 仕様 API JAR が含まれています。
jboss-javaee-6.0
BOM の 3.0.2.Final-redhat-x
バージョンを使用しています。
<dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.spec</groupId> <artifactId>jboss-javaee-6.0</artifactId> <version>3.0.2.Final-redhat-x</version> <type>pom</type> <scope>import</scope> </dependency> ... </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.spec.javax.servlet</groupId> <artifactId>jboss-servlet-api_3.0_spec</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.spec.javax.servlet.jsp</groupId> <artifactId>jboss-jsp-api_2.2_spec</artifactId> <scope>provided</scope> </dependency> ... </dependencies>
JBoss EAP とクイックスタート
表2.1 クイックスタートで使用される JBoss BOM
Maven artifactId | Description |
---|---|
jboss-javaee-6.0-with-hibernate | この BOM は、Java EE フルプロファイル BOM に基づいて構築されており、Hibernate ORM、Hibernate Search、HibernateValidator などの Hibernate コミュニティープロジェクトが追加されています。また、Hibernate JPA Model Gen や Hibernate Validator Annotation Processor などのツールプロジェクトも提供します。 |
jboss-javaee-6.0-with-hibernate3 | この BOM は、Java EE フルプロファイル BOM に基づいて構築されており、Hibernate 3 ORM、Hibernate Entity Manager (JPA 1.0)、Hibernate Validator などの Hibernate コミュニティープロジェクトが追加されています。 |
jboss-javaee-6.0-with-logging | この BOM は、Java EE フルプロファイル BOM に基づいて構築されており、JBoss Logging Tools と Log4j フレームワークが追加されています。 |
jboss-javaee-6.0-with-osgi | この BOM は、Java EE フルプロファイル BOM に基づいて構築されており、OSGI が追加されています。 |
jboss-javaee-6.0-with-resteasy | この BOM は、Java EE フルプロファイル BOM に基づいて構築されており、RESTEasy が追加されています。 |
jboss-javaee-6.0-with-security | この BOM は、Java EE フルプロファイル BOM に基づいて構築されており、Picketlink が追加されています。 |
jboss-javaee-6.0-with-tools | この BOM は、Java EE フルプロファイル BOM に基づいて構築されており、Arquillian がミックスに追加されています。また、Arquillian での使用が推奨されるバージョンの JUnit と TestNG も提供します。 |
jboss-javaee-6.0-with-transactions | この BOM には、ワールドクラスのトランザクションマネージャーが含まれています。JBossTS API を使用して、その全機能にアクセスします。 |
6.4.0.GA
バージョンのjboss-javaee-6.0-with-hibernate
BOM。
<dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.bom.eap</groupId> <artifactId>jboss-javaee-6.0-with-hibernate</artifactId> <version>6.4.0.GA</version> <type>pom</type> <scope>import</scope> </dependency> ... </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <scope>provided</scope> </dependency> ... </dependencies>
JBoss クライアント BOM
jboss-as-ejb-client-bom
と jboss-as-jms-client-bom
の 2 つのクライアント BOM が含まれています。
7.4.0.Final-redhat-x
バージョンのjboss-as-ejb-client-bom
クライアント BOM。
<dependencies> <dependency> <groupId>org.jboss.as</groupId> <artifactId>jboss-as-ejb-client-bom</artifactId> <version>7.5.0.Final-redhat-x</version> <type>pom</type> </dependency> ...l </dependencies>この例では、
7.4.0.Final-redhat-x
バージョンのjboss-as-jms-client-bom
クライアント BOM。
<dependencies> <dependency> <groupId>org.jboss.as</groupId> <artifactId>jboss-as-jms-client-bom</artifactId> <version>7.4.0.Final-redhat-x</version> <type>pom</type> </dependency> ... </dependencies>
2.4. Maven リポジトリーをアップグレードする
2.4.1. ローカル Maven リポジトリーにパッチを適用する
概要
Maven リポジトリーには、アプリケーションをビルドして JBoss EAP にデプロイするために必要な Java ライブラリー、プラグイン、およびその他のアーティファクトが保管されます。JBoss EAP リポジトリーはオンラインで利用でき、ダウンロードした ZIP ファイルとして使用することもできます。パブリックにホストされているリポジトリーを使用する場合、更新は自動的に適用されます。ただし、Maven リポジトリーをローカルにダウンロードしてインストールする場合は、更新を適用する責任があります。JBoss EAP のパッチが利用可能な場合は常に、対応するパッチが JBoss EAP Maven リポジトリーに提供されます。このパッチは、既存のローカルリポジトリーで展開される増分 ZIP ファイルで提供されます。ZIP ファイルには、新しい JAR ファイルと POM ファイルが含まれています。既存の JAR を上書きしたり、JAR を削除したりすることはないため、ロールバックの要件はありません。
前提条件
- Red Hat カスタマーポータルへの有効なアクセスおよびサブスクリプション。
- Red Hat JBoss Enterprise Application Platform <VERSION> Maven リポジトリーの ZIP ファイル。ローカルにダウンロードおよびインストールされます。
手順2.11 Maven リポジトリーを更新します
- ブラウザーを開き、https://access.redhat.comにログインします。
- ページの上部にあるメニューから Downloads を選択します。
- リストで
Red Hat JBoss Enterprise Application Platform
を見つけ、クリックします。 - この画面に表示される Version ドロップダウンメニューから JBoss EAP の正しいバージョンを選択し、Patches をクリックします。
- リストから
Red Hat JBoss Enterprise Application Platform <VERSION> CPx Incremental Maven Repository
を見つけ、Download をクリックします。 - 選択したディレクトリーに ZIP ファイルを保存するように求められます。ディレクトリーを選択してファイルを保存します。
- オペレーティングシステムの JBoss EAP リポジトリーへのパス (以下のコマンドで EAP_MAVEN_REPOSITORY_PATH と呼ばれる) を見つけます。Maven リポジトリーをローカルファイルシステムにインストールする方法の詳細については、「JBoss EAP 6 Maven リポジトリーのローカルインストール」を参照してください。
- Maven パッチファイルを JBoss EAP <VERSION>.x Maven リポジトリーのインストールディレクトリーに直接解凍します。
- Linux の場合は、ターミナルを開き、次のコマンドを入力します。
[standalone@localhost:9999 /] unzip -o jboss-eap-<VERSION>.x-incremental-maven-repository.zip -d
EAP_MAVEN_REPOSITORY_PATH
- Windows の場合は、Windows 展開ユーティリティーを使用して ZIP ファイルを
EAP_MAVEN_REPOSITORY_PATH
ディレクトリーのルートに展開します。
結果
ローカルにインストールされた Maven リポジトリーは、最新のパッチで更新されます。
第3章 クラスローディングとモジュール
3.1. はじめに
3.1.1. クラスロードとモジュールの概要
3.1.2. クラスの読み込み
3.1.3. モジュール
- 静的モジュール
- 静的モジュールは、アプリケーションサーバーの
EAP_HOME/modules/
ディレクトリーで事前定義されます。各サブディレクトリーは 1 つのモジュールを表し、設定ファイル (module.xml
) と必要な JAR ファイルを含むmain/
サブディレクトリーを定義します。モジュールの名前は、module.xml
ファイルで定義されています。アプリケーションサーバーが提供するすべての API は、Java EE API や JBoss Logging などの他の API を含む静的モジュールとして提供されます。例3.1 module.xml ファイルの例
<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.0" name="com.mysql"> <resources> <resource-root path="mysql-connector-java-5.1.15.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
モジュール名、com.mysql
、main/
サブディレクトリー名を除いて、モジュールのディレクトリー構造と一致する必要があります。JBoss EAP ディストリビューションで提供されるモジュールは、EAP_HOME/modules
ディレクトリー内のsystem
ディレクトリーにあります。このため、サードパーティーによって提供されるモジュールから分離されます。JBoss EAP 6.1 以降の上にレイヤー化された Red Hat が提供するレイヤード製品も、system
ディレクトリー内にモジュールをインストールします。カスタム静的モジュールの作成は、同じサードパーティーライブラリーを使用する同じサーバー上に多くのアプリケーションがデプロイされる場合に役立ちます。これらのライブラリーを各アプリケーションとバンドルする代わりに、JBoss 管理者はこれらのライブラリーが含まれるモジュールを作成およびインストールできます。アプリケーションは、カスタム静的モジュールで明示的な依存関係を宣言できます。モジュールレイアウトごとに 1 つのディレクトリーを使用して、カスタムモジュールがEAP_HOME/modules
ディレクトリーにインストールされるようにする必要があります。こうすると、同梱されたバージョンではなく、system
ディレクトリーに存在するカスタムバージョンのモジュールがロードされるようになります。これにより、ユーザー提供のモジュールがシステムモジュールよりも優先されます。JBOSS_MODULEPATH
環境変数を使用して JBoss EAP がモジュールを検索する場所を変更する場合は、指定された場所の 1 つでsystem
サブディレクトリー構造を探します。システム
構造体は、JBOSS_MODULEPATH
で指定された場所のどこかに存在する必要があります。 - 動的モジュール
- 動的モジュールは、各 JAR または WAR デプロイメント (または、EAR 内のサブデプロイメント) に対してアプリケーションサーバーによって作成およびロードされます。動的モジュールの名前は、デプロイされたアーカイブの名前に由来します。デプロイメントはモジュールとしてロードされるため、依存関係を設定し、他のデプロイメントで依存関係として使用することが可能です。
3.1.4. モジュールの依存性
明示的な依存関係
明示的な依存関係は開発者が設定ファイルで宣言します。静的モジュールは、module.xml
ファイルで依存関係を宣言できます。動的モジュールは、デプロイメントの MANIFEST.MF
または jboss-deployment-structure.xml
デプロイメント記述子で宣言された依存関係を持つことができます。
暗黙的な依存関係
デプロイメントで特定の条件またはメタデータが検出されると、アプリケーションサーバーによって暗黙の依存関係が自動的に追加されます。JBoss EAP 6 に同梱される Java EE 6 API は、デプロイメントで暗黙的な依存関係が検出されたときに追加されるモジュールの例になります。
jboss-deployment-structure.xml
デプロイメント記述子ファイルを使用して行われます。これは通常、アプリケーションサーバーが暗黙的な依存関係として追加しようとする特定のバージョンのライブラリーをアプリケーションがバンドルする場合に行われます。
例3.2 モジュールの依存関係
- モジュール A がモジュール C への明示的な依存関係を宣言する場合。
- または、モジュール B がモジュール B の依存関係をモジュール C でエクスポートする場合。
3.1.5. デプロイメントでのクラスローディング
- WAR デプロイメント
- WAR デプロイメントは 1 つのモジュールとして考慮されます。
WEB-INF/lib
ディレクトリーのクラスはWEB-INF/classes
ディレクトリーにあるクラスと同じように処理されます。WAR にパッケージされているクラスはすべて、同じクラスローダーでロードされます。 - EAR デプロイメント
- EAR デプロイメントは、複数のモジュールで設定されています。これらのモジュールの定義は、次のルールに従います。
- EAR の
lib/
ディレクトリーは親モジュールと呼ばれる 1 つのモジュールです。 - また、EAR 内の各 WAR デプロイメントは 1 つのモジュールです。
- 同様に、EAR 内の EJB JAR デプロイメントも 1 つのモジュールです。
サブデプロイメントモジュール (EAR 内の WAR および JAR デプロイメント) は、自動的に親モジュールに依存しますが、サブデプロイメントモジュール同士が自動的に依存するわけではありません。ただし、相互で自動的な依存関係はありません。これはサブデプロイメントの分離と呼ばれ、デプロイメントごとに、またはアプリケーションサーバー全体に対して無効にすることができます。サブデプロイメントモジュール間の明示的な依存関係は、他のモジュールと同じ方法で追加することが可能です。
3.1.6. クラスローディングの優先順位
- 暗黙的な依存関係これらは、JAVA EE API などの JBoss EAP 6 によって自動的に追加される依存関係です。これらの依存関係には一般的な機能や JBoss EAP 6 によって提供される API が含まれるため、これらの依存関係のクラスローダー優先順位は最も高くなります。各暗黙的依存関係の詳細は、「暗黙的なモジュール依存関係」を参照してください。
- 明示的な依存関係これらは、アプリケーション設定に手動で追加される依存関係です。これは、アプリケーションの
MANIFEST.MF
ファイルまたは新しいオプションの JBoss デプロイメント記述子jboss-deployment-structure.xml
ファイルを使用して実行できます。明示的に依存関係を追加する方法は、「デプロイメントへの明示的なモジュール依存関係の追加」を参照してください。 - ローカルリソースデプロイメント自体の内部にパッケージ化されたクラスファイル。たとえば、WAR ファイルの
WEB-INF/classes
またはWEB-INF/lib
ディレクトリーにあるものです。 - デプロイメント間の依存関係これらは、EAR デプロイメント内の他のデプロイメントへの依存関係です。これには、EAR の
lib
ディレクトリーにあるクラスや他の EJB jar で定義されたクラスが含まれることがあります。
3.1.7. 動的モジュールの名前付け
- WAR および JAR ファイルのデプロイメントは次の形式で名前が付けられます。
deployment.DEPLOYMENT_NAME
例えば、inventory.war
とstore.jar
は、それぞれdeployment.inventory.war
とdeployment.store.jar
というモジュール名を持ちます。 - エンタープライズアーカイブ内のサブデプロイメントは次の形式で名前が付けられます。
deployment.EAR_NAME.SUBDEPLOYMENT_NAME
たとえば、エンタープライズアーカイブaccounts.ear
内のreports.war
のサブデプロイメントには、deployment.accounts.ear.reports.war
というモジュール名が付きます。
3.1.8. jboss-deployment-structure.xml
jboss-deployment-structure.xml
は JBoss EAP 6 の新しい任意のデプロイメント記述子です。このデプロイメント記述子を使用すると、デプロイメントでクラスローディングを制御できます。
EAP_HOME/docs/schema/jboss-deployment-structure-1_2.xsd
にあります。
3.2. デプロイメントへの明示的なモジュール依存関係の追加
前提条件
- モジュールの依存関係を追加する作業用ソフトウェアプロジェクトがすでにある必要があります。
- 依存関係として追加するモジュールの名前を知っている必要があります。JBoss EAP 6 に含まれる静的モジュールの一覧は、「含まれるモジュール」を参照してください。モジュールが他のデプロイメントである場合は、「動的モジュールの名前付け」を参照してモジュール名を決定してください。
- デプロイメントの
MANIFEST.MF
ファイルにエントリーを追加します。 jboss-deployment-structure.xml
デプロイメント記述子にエントリーを追加します。
手順3.1 MANIFEST.MF への依存関係設定の追加
MANIFEST.MF
ファイルの必要な依存関係エントリーを作成するよう Maven プロジェクトを設定できます。「Maven を使用した MANIFEST.MF エントリーの生成」を参照してください。
MANIFEST.MF
ファイルを追加しますプロジェクトにMANIFEST.MF
ファイルがない場合、MANIFEST.MF
というファイルを作成します。Web アプリケーション (WAR) では、このファイルをMETA-INF
ディレクトリーに追加します。EJB アーカイブ (JAR) では、このファイルをMETA-INF
ディレクトリーに追加します。依存関係エントリーを追加
依存関係モジュール名をコンマで区切り、依存関係エントリーをMANIFEST.MF
ファイルへ追加します。Dependencies: org.javassist, org.apache.velocity
オプション: 依存関係をオプションにします
依存関係は、依存関係エントリーのモジュール名にoptional
を追加することでオプションにすることができます。Dependencies: org.javassist optional, org.apache.velocity
オプション: 依存関係をエクスポートします
依存関係エントリーのモジュール名にexport
を付けると、依存関係をエクスポートすることができます。Dependencies: org.javassist, org.apache.velocity export
オプション: アノテーションを使用した依存関係
この annotations フラグは、EJB インターセプターを宣言するときなど、アノテーションのスキャン中に処理する必要があるアノテーションがモジュールの依存関係に含まれる場合に必要になります。これを行わないと、モジュールで宣言された EJB インターセプターをデプロイメントで使用できなくなります。アノテーションのスキャンが関係するその他の状況でも、この設定が必要になる場合があります。このフラグを使用するには、モジュールに Jandex インデックスが含まれている必要があります。Jandex インデックスを作成および使用するための手順は、このトピックの最後に含まれています。
手順3.2 依存関係設定を jboss-deployment-structure.xml に追加します
jboss-deployment-structure.xml
の追加アプリケーションにjboss-deployment-structure.xml
ファイルがない場合は、jboss-deployment-structure.xml
という名前の新しいファイルを作成し、プロジェクトに追加します。このファイルは、ルート要素が<jboss-deployment-structure>
である XML ファイルです。<jboss-deployment-structure> </jboss-deployment-structure>
Web アプリケーション (WAR) では、このファイルをWEB-INF
ディレクトリーに追加します。EJB アーカイブ (JAR) では、このファイルをMETA-INF
ディレクトリーに追加します。依存関係セクションを追加
ドキュメントルート内に<deployment>
要素を作成し、その中に<dependencies>
要素を作成します。モジュール要素を追加する
dependencies ノード内に各モジュールの依存関係に対するモジュール要素を追加します。name
属性にモジュール名を設定します。<module name="org.javassist" />
オプション: 依存関係をオプションにします
依存関係をオプションにするには、optional
属性をモジュールエントリーに追加し、値をtrue
にします。この属性のデフォルト値はfalse
です。<module name="org.javassist" optional="true" />
オプション: 依存関係をエクスポートします
依存関係をエクスポートするには、export
属性をモジュールエントリーに追加し、値をtrue
にします。この属性のデフォルト値はfalse
です。<module name="org.javassist" export="true" />
例3.3 2 つの依存関係を持つ jboss-deployment-structure.xml
<jboss-deployment-structure> <deployment> <dependencies> <module name="org.javassist" /> <module name="org.apache.velocity" export="true" /> </dependencies> </deployment> </jboss-deployment-structure>
Jandex インデックスの作成
annotations
フラグは Jandex インデックスが含まれるモジュールを必要とします。モジュールに追加する新しいインデックス JAR を作成できます。Jandex JAR を使用してインデックスを構築し、新しい JAR ファイルに挿入します。
手順3.3
インデックスの作成
java -jar EAP_HOME/modules/org/jboss/jandex/main/jandex-1.0.3.Final-redhat-1.jar $JAR_FILE
一時作業領域の作成
mkdir /tmp/META-INF
インデックスファイルを作業ディレクトリーに移動します。
mv $JAR_FILE.ifx /tmp/META-INF/jandex.idx
- オプション 1: インデックスを新しい JAR ファイルに含めます。
jar cf index.jar -C /tmp META-INF/jandex.idx
JAR をモジュールディレクトリーに置き、module.xml
を編集してリソースルートへ追加します。 - オプション 2: インデックスを既存の JAR に追加します。
java -jar EAP_HOME/modules/org/jboss/jandex/main/jandex-1.0.3.Final-redhat-1.jar -m $JAR_FILE
モジュールのインポートに注釈インデックスを利用するように指示します
アノテーションインデックスを使用するようモジュールインポートに指示し、アノテーションのスキャンでアノテーションを見つけられるようにします。状況に応じて、以下のいずれかの方法を選択してください。- MANIFEST.MF を使用してモジュールの依存関係を追加する場合は、
annotations
をモジュール名の後に追加します。例を以下に示します。Dependencies: test.module, other.module
上記を以下のように変更します。Dependencies: test.module annotations, other.module
jboss-deployment-structure.xml
を使用してモジュールの依存関係を追加する場合は、モジュールの依存関係にannotations="true"
を追加します。
3.3. Maven を使用した MANIFEST.MF エントリーの生成
Dependencies
エントリーを含む MANIFEST.MF
ファイルを生成することができます。これは依存関係のリストを自動的に生成するのではなく、このプロセスは pom.xml
で指定された内容で MANIFEST.MF
ファイルを作成するのみです。
前提条件
- 作業用の Maven プロジェクトがすでに存在している必要があります。
- Maven プロジェクトは、JAR、EJB、または WAR プラグインのいずれかを使用している必要があります (
maven-jar-plugin
、maven-ejb-plugin
、maven-war-plugin
)。 - プロジェクトのモジュール依存関係の名前を知っている必要があります。JBoss EAP 6 に含まれる静的モジュールの一覧は、「含まれるモジュール」を参照してください。モジュールが他のデプロイメントである場合、「動的モジュールの名前付け」を参照してモジュール名を決定します。
手順3.4 モジュール依存関係が含まれる MANIFEST.MF ファイルの生成
設定の追加
プロジェクトのpom.xml
ファイルにあるパッケージングプラグイン設定に次の設定を追加します。<configuration> <archive> <manifestEntries> <Dependencies></Dependencies> </manifestEntries> </archive> </configuration>
依存関係のリスト
<Dependencies>
要素に、モジュールの依存関係のリストを追加します。MANIFEST.MF
ファイルに依存関係を追加するときと同じ形式を使用します。そのフォーマットの詳細については、「デプロイメントへの明示的なモジュール依存関係の追加」を参照してください。<Dependencies>org.javassist, org.apache.velocity</Dependencies>
ここでは、optional
属性とexport
属性を使用することもできます。<Dependencies>org.javassist optional, org.apache.velocity export</Dependencies>
プロジェクトをビルドします。
Maven アセンブリーゴールを使用してプロジェクトをビルドします。[Localhost ]$ mvn assembly:assembly
MANIFEST.MF
ファイルが最終アーカイブに含まれます。
例3.4 pom.xml で設定されたモジュールの依存関係
<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <configuration> <archive> <manifestEntries> <Dependencies>org.javassist, org.apache.velocity</Dependencies> </manifestEntries> </archive> </configuration> </plugin> </plugins>
3.4. モジュールが暗黙的にロードされないようにする
前提条件
- 暗黙の依存関係を除外したいソフトウェアプロジェクトがすでに機能している必要があります。
- 除外するモジュール名を知っている必要があります。暗黙の依存関係とその条件の一覧は、「暗黙的なモジュール依存関係」を参照してください。
手順3.5 jboss-deployment-structure.xml への依存関係除外設定の追加
- アプリケーションに
jboss-deployment-structure.xml
ファイルがない場合は、jboss-deployment-structure.xml
という名前の新しいファイルを作成し、プロジェクトに追加します。このファイルは、ルート要素が<jboss-deployment-structure>
である XML ファイルです。<jboss-deployment-structure> </jboss-deployment-structure>
Web アプリケーション (WAR) では、このファイルをWEB-INF
ディレクトリーに追加します。EJB アーカイブ (JAR) では、このファイルをMETA-INF
ディレクトリーに追加します。 - ドキュメントルート内に
<deployment>
要素を作成し、その中に<exclusions>
要素を作成します。<deployment> <exclusions> </exclusions> </deployment>
- exclusions 要素内で、除外する各モジュールに対して
<module>
要素を追加します。name
属性にモジュール名を設定します。<module name="org.javassist" />
例3.5 2 つのモジュールを除く
<jboss-deployment-structure> <deployment> <exclusions> <module name="org.javassist" /> <module name="org.dom4j" /> </exclusions> </deployment> </jboss-deployment-structure>
3.5. サブシステムをデプロイメントから除外
概要
このトピックでは、サブシステムをデプロイメントから除外するために必要な手順について説明します。これは、jboss-deployment-structure.xml
設定ファイルを編集することによって行われます。サブシステムの除外は、サブシステムの削除と同じ効果がありますが、単一のデプロイメントにのみ適用されます。
手順3.6 サブシステムの除外
- テキストエディターで
jboss-deployment-structure.xml
ファイルを開きます。 - <deployment> タグ内に以下の XML を追加します。
<exclude-subsystems> <subsystem name="SUBSYSTEM_NAME" /> </exclude-subsystems>
jboss-deployment-structure.xml
ファイルを保存します。
結果
サブシステムは正常に除外されました。サブシステムのデプロイメントユニットプロセッサーがデプロイメント上で実行されなくなります。
例3.6 例: jboss-deployment-structure.xml
ファイル
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2"> <ear-subdeployments-isolated>true</ear-subdeployments-isolated> <deployment> <exclude-subsystems> <subsystem name="jaxrs" /> </exclude-subsystems> <exclusions> <module name="org.javassist" /> </exclusions> <dependencies> <module name="deployment.javassist.proxy" /> <module name="deployment.myjavassist" /> <module name="myservicemodule" services="import"/> </dependencies> <resources> <resource-root path="my-library.jar" /> </resources> </deployment> <sub-deployment name="myapp.war"> <dependencies> <module name="deployment.myear.ear.myejbjar.jar" /> </dependencies> <local-last value="true" /> </sub-deployment> <module name="deployment.myjavassist" > <resources> <resource-root path="javassist.jar" > <filter> <exclude path="javassist/util/proxy" /> </filter> </resource-root> </resources> </module> <module name="deployment.javassist.proxy" > <dependencies> <module name="org.javassist" > <imports> <include path="javassist/util/proxy" /> <exclude path="/**" /> </imports> </module> </dependencies> </module> </jboss-deployment-structure>
3.6. デプロイメントでのプログラムを用いたクラスローダーの使用
3.6.1. デプロイメントでのプログラムによるクラスおよびリソースのロード
- Class.forName() メソッドを使用したクラスのロード
Class.forName()
メソッドを使用すると、プログラムでクラスをロードして初期化することができます。このメソッドには 2 つのシグネチャーがあります。プログラムでクラスをロードする場合は、3 つの引数のシグネチャーを用いる方法が推奨されます。このシグネチャーを使用すると、ロード時に目的のクラスを初期化するかどうかを制御できます。また、JVM はコールスタックをチェックして、使用するクラスローダーを判断する必要がないため、クラスローダーの取得および提供がより効率的になります。コードを含むクラスが- Class.forName(String className)
- このシグネチャーは、1 つのパラメーター (ロードする必要があるクラスの名前) のみを取ります。このメソッドシグネチャーを使用すると、現在のクラスのクラスローダーによってクラスがロードされ、デフォルトで新たにロードされたクラスが初期化されます。
- Class.forName(String className, boolean initialize, ClassLoader loader)
- このシグネチャーは、クラス名、クラスを初期化するかどうかを指定するブール値、およびクラスをロードする ClassLoader の 3 つのパラメーターを想定します。
CurrentClass
という名前だとすると、CurrentClass.class.getClassLoader()
メソッドを使ってそのクラスのクラスローダーを取得することができます。次の例は、TargetClass
クラスをロードして初期化するためのクラスローダーを提供します。例3.7 TargetClass をロードして初期化するためのクラスローダーを提供します。
Class<?> targetClass = Class.forName("com.myorg.util.TargetClass", true, CurrentClass.class.getClassLoader());
- 名前ですべてのリソースを検索
- リソースの名前とパスが分かり、直接そのリソースをロードする場合は、標準的な Java development kit の Class または ClassLoader API を使用するのが最良の方法です。
- 単一のリソースをロードします。
- 自分のクラスまたはデプロイメント内の別のクラスと同じディレクトリーにある単一のリソースをロードするには、
Class.getResourceAsStream()
メソッドを使用します。例3.8 デプロイメントに単一のリソースをロードします。
InputStream inputStream = CurrentClass.class.getResourceAsStream("targetResourceName");
- 単一リソースのインスタンスをすべてロードします。
- デプロイメントのクラスローダーが認識できる単一リソースのすべてのインスタンスをロードするには、
Class.getClassLoader().getResources(String resourceName)
メソッドを使用します。ここで、resourceName
はリソースの完全修飾パスに置き換えます。このメソッドは、指定の名前でクラスローダーがアクセスできるリソースに対し、すべてのURL
オブジェクトの列挙を返します。その後、URL の配列で繰り返し処理し、openStream()
メソッドを使用して各ストリームを開くことができます。例3.9 リソースのすべてのインスタンスをロードし、結果を繰り返し処理します。
Enumeration<URL> urls = CurrentClass.class.getClassLoader().getResources("full/path/to/resource"); while (urls.hasMoreElements()) { URL url = urls.nextElement(); InputStream inputStream = null; try { inputStream = url.openStream(); // Process the inputStream ... } catch(IOException ioException) { // Handle the error } finally { if (inputStream != null) { try { inputStream.close(); } catch (Exception e) { // ignore } } } }
注記URL インスタンスはローカルストレージからロードされるため、openConnection()
や他の関連するメソッドを使用する必要はありません。ストリームは非常に簡単に使用でき、ストリームを使用することにより、コードの複雑さが最小限に抑えられます。
- クラスローダーからクラスファイルをロードします。
- クラスがすでにロードされている場合は、以下の構文を使用して、そのクラスに対応するクラスファイルをロードできます。クラスがロードされていない場合は、クラスローダーを使用し、パスを変換する必要があります。
例3.10 ロードされたクラスのクラスファイルをロードします。
InputStream inputStream = CurrentClass.class.getResourceAsStream(TargetClass.class.getSimpleName() + ".class");
例3.11 ロードされていないクラスのクラスファイルをロードします。
String className = "com.myorg.util.TargetClass" InputStream inputStream = CurrentClass.class.getClassLoader().getResourceAsStream(className.replace('.', '/') + ".class");
3.6.2. デプロイメントでのプログラムによるリソースの繰り返し
MANIFEST.MF
に追加する必要があります。
Dependencies: org.jboss.modulesこれらの API により柔軟性が向上しますが、直接パスを検索するよりも動作がかなり遅くなることに注意してください。
- デプロイメント内およびすべてのインポート内のリソースをリストします。
- 場合によっては、正確なパスでリソースを検索できないことがあります。たとえば、正確なパスがわからない場合や、特定のパス内の複数のファイルを調べる必要がある場合があります。このような場合、JBoss Modules ライブラリーはすべてのデプロイメントを繰り返し処理するための API を複数提供します。2 つのメソッドのいずれかを使用すると、デプロイメントでリソースを繰り返し処理できます。
- 単一のモジュールで見つかったすべてのリソースを繰り返し処理します。
- The
ModuleClassLoader.iterateResources()
メソッドは、このモジュールクラ出力ダー内のすべてのリソースを繰り返します。このメソッドは、検索を開始するディレクトリーの名前と、サブディレクトリーで再帰的に処理するかどうかを指定するブール値の 2 つの引数を取ります。以下の例は、ModuleClassLoader の取得方法と、bin/
ディレクトリーにあるリソースのイテレーターの取得方法 (サブディレクトリーを再帰的に検索) を示しています。取得されたイテレーターは、一致した各リソースをチェックし、名前とサイズのクエリー (可能な場合) を行うために使用できます。また、読み取り可能ストリームを開いたり、リソースの URL を取得するために使用できます。例3.12 bin ディレクトリーでリソースを検索し、サブディレクトリーに繰り返します。
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Iterator<Resource> mclResources = moduleClassLoader.iterateResources("bin",true);
- 単一のモジュールで見つかったすべてのリソースとインポートされたリソースを繰り返し処理します。
- The
Module.iterateResources()
メソッドは、モジュールにインポートされたリソースを含む、このモジュールクラ出力ダー内のすべてのリソースを繰り返します。このメソッドは、前述のメソッドよりもはるかに大きなセットを返します。このメソッドには、特定パターンの結果を絞り込むフィルターとなる引数が必要になります。代わりに、PathFilters.acceptAll() を指定してセット全体を返すことも可能です。例3.13 インポートを含む、このモジュールのリソースのセット全体を検索します。
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Module module = moduleClassLoader.getModule(); Iterator<Resource> moduleResources = module.iterateResources(PathFilters.acceptAll());
- パターンと一致するすべてのリソースを検索します。
- デプロイメント内またはデプロイメントの完全なインポートセット内で特定のリソースのみを見つける必要がある場合は、リソースの繰り返しをフィルターする必要があります。JBoss Modules のフィルター API は、リソースの繰り返しをフィルターする複数のツールを提供します。
- 依存関係の完全セットを確認します。
- 依存関係の完全なセットを調べる必要がある場合は、
Module.iterateResources()
メソッドのPathFilter
各リソースの名前が一致するかどうかを確認するパラメーター。 - デプロイメント依存関係を確認します。
- デプロイメント内のみを調べる必要がある場合は、
ModuleClassLoader.iterateResources()
方法。が、追加のメソッドを使用して結果となるイテレーターをフィルターする必要があります。ThePathFilters.filtered()
この場合、メソッドはリソースイテレータのフィルタリングされたビューを提供できます。PathFilters
クラスには、さまざまな関数を実行するフィルターを作成する多くの静的メソッドが含まれています。これには、子パスや完全一致の検索、Ant 形式の「glob」パターンの一致などが含まれます。
- リソースのフィルターに関する追加のコード例。
- 以下の例は、異なる基準を基にしてリソースをフィルターする方法を示しています。
例3.14 デプロイメントでファイル名が messages.properties のファイルをすべて検索
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Iterator<Resource> mclResources = PathFilters.filtered(PathFilters.match("**/messages.properties"), moduleClassLoader.iterateResources("", true));
例3.15 デプロイメントおよびインポートでファイル名が messages.properties のファイルをすべて検索
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Module module = moduleClassLoader.getModule(); Iterator<Resource> moduleResources = module.iterateResources(PathFilters.match("**/message.properties));
例3.16 デプロイメントでディレクトリー名が my-resources であるディレクトリー内部のファイルをすべて検索
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Iterator<Resource> mclResources = PathFilters.filtered(PathFilters.match("**/my-resources/**"), moduleClassLoader.iterateResources("", true));
例3.17 デプロイメントおよびインポートで messages または errors という名前のファイルをすべて検索
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Module module = moduleClassLoader.getModule(); Iterator<Resource> moduleResources = module.iterateResources(PathFilters.any(PathFilters.match("**/messages"), PathFilters.match("**/errors"));
例3.18 デプロイメントで指定のパッケージにあるすべてのファイルを検索
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Iterator<Resource> mclResources = moduleClassLoader.iterateResources("path/form/of/packagename", false);
3.7. クラスローディングとサブデプロイメント
3.7.1. エンタープライズアーカイブのモジュールおよびクラスロード
- EAR アーカイブのルートにある
lib/
ディレクトリーの内容はモジュールです。これは、親モジュールと呼ばれます。 - 各 WAR および EJB JAR サブデプロイメントはモジュールです。これらのモジュールの動作は、他のモジュールおよび親モジュールの暗黙的な依存関係と同じです。
- サブデプロイメントでは、親モジュールとすべての他の非 WAR サブデプロイメントに暗黙的な依存関係が存在します。
MANIFEST.MF
ファイルの Class-Path
エントリーとして明示的に宣言されている場合を除き、移植可能なアプリケーションがお互いにアクセスできるサブデプロイメントに依存しないことが推奨されます。
3.7.2. サブデプロイメントクラスローダーの分離
3.7.3. EAR 内のサブデプロイメントクラスローダーの分離を有効にする
デプロイメント記述子ファイルを追加します
jboss-deployment-structure.xml
デプロイメント記述子ファイルが EAR のMETA-INF
ディレクトリーに存在しない場合は追加し、次の内容を追加します。<jboss-deployment-structure> </jboss-deployment-structure>
追加します
<ear-subdeployments-isolated>
エレメント追加します<ear-subdeployments-isolated>
true
のコンテンツで jboss-deployment-structure.xml ファイルがまだ存在しない場合は、要素をjboss-deployment-structure.xml
ファイルに追加します。<ear-subdeployments-isolated>true</ear-subdeployments-isolated>
結果:
これで、この EAR デプロイメントでサブデプロイメントクラ出力ダーの分離が有効になります。つまり、EAR のサブデプロイメントは WAR ではないサブデプロイメントごとに自動的な依存関係を持ちません。
3.8. カスタムモードでのタグライブラリー記述子 (TLD) のデプロイ
概要
共通のタグライブラリー記述子 (TLD) を使用する複数のアプリケーションがある場合、アプリケーションから TLD を分離し、一元的で一意な場所に置くと有用であることがあります。これにより、TLD を使用するアプリケーションごとに更新を行う必要がなくなり、TLD への追加や更新が簡単になります。
前提条件
- TLD を含む少なくとも 1 つの JAR。TLD がパックされていることを確認します
META-INF
。
手順3.7 カスタムモジュールでの TLD のデプロイ
- 管理 CLI を使用して、JBoss EAP 6 インスタンスへ接続し、以下のコマンドを実行して TLD JAR が含まれるカスタムモジュールを作成します。
module add --name=MyTagLibs --resources=/path/to/TLDarchive.jar
TLD が依存関係を必要とするクラスとともにパッケージ化されている場合は、--dependencies=DEPENDENCY
オプションを使用して、カスタムモジュールの作成時にこれらの依存関係を指定するようにします。モジュールを作成するときに、それぞれを:
で区切ることにより、複数の JAR リソースを指定できます。以下に例を示します。--resources=/path/to/one.jar:/path/to/two.jar
- アプリケーションで、で説明されているメソッドの 1 つを使用して、新しい MyTagLibs カスタムモジュールへの依存関係を宣言します。「デプロイメントへの明示的なモジュール依存関係の追加」。重要インポートすることも確認してください
META-INF
依存関係を宣言するとき。たとえば、MANIFEST.MF
の場合は以下のようになります。Dependencies: com.MyTagLibs meta-inf
または、jboss-deployment-structure.xml
の場合は、meta-inf
属性。
結果
アプリケーションでは、新しいカスタムモジュールに含まれている TLD を使用できます。
3.9. 参照
3.9.1. 暗黙的なモジュール依存関係
表3.1 暗黙的なモジュール依存関係
依存関係を追加するサブシステム | 常に追加される依存関係 | 条件付きで追加される依存関係 | 依存関係の追加を引き起こす条件 |
---|---|---|---|
Core Server |
| | |
EE サブシステム |
| | |
EJB3 サブシステム |
|
|
Java EE 6 仕様で説明されているように、デプロイメント内の有効な場所に
ejb-jar.xml ファイルが存在する。
注釈ベースの EJB の存在。例:
@Stateless 、@Stateful 、 @MessageDriven
|
JAX-RS(RESTEasy) サブシステム |
|
| デプロイメントに JAX-RS アノテーションが存在すること。 |
JCA サブシステム |
|
| リソースアダプター (RAR) アーカイブのデプロイメント。 |
JPA(Hibernate) サブシステム |
|
|
の存在
@PersistenceUnit また@PersistenceContext 注釈、または<persistence-unit-ref> また<persistence-context-ref> デプロイメント記述子の要素。
JBoss EAP 6 は永続プロバイダー名をモジュール名にマップします。
persistence.xml ファイルで特定のプロバイダーに名前を付けると、適切なモジュールに対して依存関係が追加されます。これが希望の挙動ではない場合は、jboss-deployment-structure.xml を使用して除外できます。
|
ロギングサブシステム |
| |
これらの依存関係は、
add-logging-api-dependencies 属性が false に設定されています。
|
SAR サブシステム | |
| SAR アーカイブの展開。 |
セキュリティーサブシステム |
| | |
Web サブシステム | |
| WAR アーカイブの展開。JavaServer Faces (JSF) は、使用されている場合にのみ追加されます。 |
Web サービスサブシステム |
|
|
アプリケーションクライアントタイプでない場合は、条件付き依存関係が追加されます。
|
溶接 (CDI) サブシステム |
|
| デプロイメントに beans.xml ファイルが存在すること。 |
コンテナー管理による永続性 (CMP) サブシステム | |
|
3.9.2. 含まれるモジュール
3.9.3. JBoss デプロイメント構造デプロイメント記述子リファレンス
- 明示的なモジュール依存関係を定義する。
- 特定の暗黙的な依存関係がロードされないようにする。
- デプロイメントのリソースより追加モジュールを定義する。
- EAR デプロイメントのサブデプロイメント分離の挙動を変更する。
- EAR のモジュールに追加のリソースルートを追加する。
第4章 バルブ
4.1. バルブ
- グローバルバルブはサーバーレベルで設定され、サーバーにデプロイされたすべてのアプリケーションに適用されます。グローバルバルブを設定する手順は、JBoss EAP の 『管理および設定ガイド』 に記載されています。
- アプリケーションレベルで設定されたバルブは、アプリケーションデプロイメントにパッケージ化されており、特定のアプリケーションにのみ影響します。アプリケーションレベルでバルブを設定する手順は、JBoss EAP の 『開発ガイド』 に記載されています。
4.2. グローバルバルブ
4.3. オーセンティケーターバルブ
org.apache.catalina.authenticator.AuthenticatorBase
とオーバーライドしますauthenticate(Request request, Response response, LoginConfig config)
方法。
4.4. バルブを使用するように Web アプリケーションを設定する
jboss-web.xml
デプロイメント記述子で設定されている必要があります。
前提条件
- バルブを作成して、アプリケーションのクラスパスに含める必要があります。これは、アプリケーションの WAR ファイルまたは依存関係として追加されたモジュールに含めることで実行できます。このようなモジュールの例には、サーバーにインストールされた静的モジュールや、WAR が EAR にデプロイされている場合は EAR アーカイブの
lib/
ディレクトリーにある JAR ファイルが含まれます。 - アプリケーションには、
jboss-web.xml
デプロイメント記述子が含まれている必要があります。
手順4.1 ローカルバルブのアプリケーションを設定します
バルブを設定する
作成するvalve
を含む要素class-name
アプリケーションのjboss-web.xml
ファイルの子要素。Theclass-name
バルブクラスの名前です。<valve> <class-name>VALVE_CLASS_NAME</class-name> </valve>
例4.1 jboss-web.xml ファイルで設定されたバルブ要素
<valve> <class-name>org.jboss.security.negotiation.NegotiationAuthenticator</class-name> </valve>
カスタムバルブを設定する
バルブに設定可能なパラメーターがある場合は、param
子要素valve
各パラメーターの要素、指定param-name
とparam-value
それぞれのために。例4.2 jboss-web.xml ファイルで設定されたカスタムバルブエレメント
<valve> <class-name>org.jboss.web.tomcat.security.GenericHeaderAuthenticator</class-name> <param> <param-name>httpHeaderForSSOAuth</param-name> <param-value>sm_ssoid,ct-remote-user,HTTP_OBLIX_UID</param-value> </param> <param> <param-name>sessionCookieForSSOAuth</param-name> <param-value>SMSESSION,CTSESSION,ObSSOCookie</param-value> </param> </valve>
例4.3 jboss-web.xml バルブ設定
<valve> <class-name>org.jboss.samplevalves.RestrictedUserAgentsValve</class-name> <param> <param-name>restrictedUserAgents</param-name> <param-value>^.*MS Web Services Client Protocol.*$</param-value> </param> </valve>
4.5. オーセンティケーターバルブを使用するように Web アプリケーションを設定する
web.xml
デプロイメント記述子を設定する必要があります。最も単純なケースでは、web.xml
設定は、BASIC
認証を使用する場合と同じですが、auth-method
の子要素login-config
設定を実行するバルブの名前に設定されます。
前提条件
- 認証バルブはすでに作成されている必要があります。
- 認証バルブがグローバルバルブである場合、それはすでにインストールおよび設定されている必要があり、設定された名前を知っている必要があります。
- アプリケーションが使用するセキュリティーレルムのレルム名を知っている必要があります。
手順4.2 オーセンティケーターバルブを使用するようにアプリケーションを設定する
バルブを設定する
ローカルバルブを使用する場合は、アプリケーションのjboss-web.xml
デプロイメント記述子で設定する必要があります。「バルブを使用するように Web アプリケーションを設定する」を参照してください。グローバルバルブを使用する場合、これは必要ありません。web.xml にセキュリティー設定を追加します
security-constraint
、login-config
、security-role
などの標準要素を使用して、アプリケーションのweb.xml
ファイルにセキュリティー設定を追加します。login-config
要素で、auth-method
の値をオーセンティケーターバルブの名前に設定します。realm-name 要素は、アプリケーションで使用されている JBoss セキュリティーレルムの名前にも設定する必要があります。<login-config> <auth-method>VALVE_NAME</auth-method> <realm-name>REALM_NAME</realm-name> </login-config>
4.6. カスタムバルブを作成する
手順4.3 カスタムバルブを作成する
Maven の依存関係を設定します。
次の依存関係設定をプロジェクトpom.xml
ファイルに追加します。<dependency> <groupId>org.jboss.web</groupId> <artifactId>jbossweb</artifactId> <version>7.5.7.Final-redhat-1</version> <scope>provided</scope> </dependency>
注記jbossweb -VERSION.jar
ファイルをアプリケーションに含めないでください。これは、JBoss EAP サーバーのランタイムクラスパスで JBoss モジュールとして次の場所で利用できます:EAP_HOME/modules/system/layers/base/org/jboss/as/web/main/jbossweb-7.5.7.Final-redhat-1。jar
。Valve クラスを作成します
のサブクラスを作成しますorg.apache.catalina.valves.ValveBase
。package org.jboss.samplevalves; import org.apache.catalina.valves.ValveBase; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; public class RestrictedUserAgentsValve extends ValveBase { }
invoke メソッドを実装します。
Theinvoke()
このバルブがパイプラインで実行されると、メソッドが呼び出されます。リクエストオブジェクトとレスポンスオブジェクトはパラメーターとして渡されます。ここで、要求と応答の処理と変更を実行します。public void invoke(Request request, Response response) { }
次のパイプラインステップを呼び出します。
invoke メソッドが最後に実行する必要があるのは、パイプラインの次のステップを呼び出して、変更された要求オブジェクトと応答オブジェクトを渡すことです。これは、getNext().invoke()
方法getNext().invoke(request, response);
オプション: パラメーターを指定します。
バルブを設定可能にする必要がある場合は、パラメーターを追加してこれを有効にします。これを行うには、各パラメーターにインスタンス変数とセッターメソッドを追加します。private String restrictedUserAgents = null; public void setRestricteduserAgents(String mystring) { this.restrictedUserAgents = mystring; }
完成したコード例を確認します。
これで、クラスは次の例のようになります。例4.4 サンプルカスタムバルブ
package org.jboss.samplevalves; import java.io.IOException; import java.util.regex.Pattern; import javax.servlet.ServletException; import org.apache.catalina.valves.ValveBase; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; public class RestrictedUserAgentsValve extends ValveBase { private String restrictedUserAgents = null; public void setRestrictedUserAgents(String mystring) { this.restrictedUserAgents = mystring; } public void invoke(Request request, Response response) throws IOException, ServletException { String agent = request.getHeader("User-Agent"); System.out.println("user-agent: " + agent + " : " + restrictedUserAgents); if (Pattern.matches(restrictedUserAgents, agent)) { System.out.println("user-agent: " + agent + " matches: " + restrictedUserAgents); response.addHeader("Connection", "close"); } getNext().invoke(request, response); } }
第5章 開発者のためのロギング
5.1. はじめに
5.1.1. ロギング
5.1.2. JBoss LogManager でサポートされるアプリケーションロギングフレームワーク
- JBoss Logging - JBoss EAP 6 に含まれます
- Apache Commons Logging - http://commons.apache.org/logging/
- Simple Logging Facade for Java (SLF4J) - http://www.slf4j.org/
- Apache Log4j - http://logging.apache.org/log4j/1.2/
- Java SE Logging (java.util.logging) - http://download.oracle.com/javase/6/docs/api/java/util/logging/package-summary.html
- java.util.logging
- JBoss Logging
- Log4j
- SLF4J
- commons-logging
- java.util.logging Handler
- Log4j Appender
Log4j API
と Log4J Appender
を使用している場合、オブジェクトは渡される前に string
に変換されます。
5.1.3. ログレベル
TRACE
、DEBUG
、INFO
、WARN
、ERROR
、FATAL
です。
WARN
レベルのログハンドラーは、WARN
、ERROR
、および FATAL
のレベルのメッセージのみを記録します。
5.1.4. サポート対象のログレベル
表5.1 サポート対象のログレベル
ログのレベル | Value | 説明 |
---|---|---|
FINEST | 300 |
-
|
FINER | 400 |
-
|
TRACE | 400 |
アプリケーションの実行状態に関する詳細情報を提供するメッセージに使用します。
TRACE のログメッセージは通常、アプリケーションのデバッグ時にのみキャプチャされます。
|
DEBUG | 500 |
アプリケーションの個々の要求またはアクティビティーの進行状況を示すメッセージに使用します。
DEBUG のログメッセージは通常、アプリケーションのデバッグ時にのみキャプチャされます。
|
FINE | 500 |
-
|
CONFIG | 700 |
-
|
INFO | 800 |
アプリケーションの全体的な進行状況を示すメッセージに使用します。多くの場合、アプリケーションの起動、シャットダウン、およびその他の主要なライフサイクルイベントに使用されます。
|
WARN | 900 |
エラーではないが理想的とは見なされない状況を示すために使用します。将来エラーにつながる可能性のある状況を示している可能性があります。
|
警告 | 900 |
-
|
ERROR | 1000 |
発生したエラーの中で、現在の活動や要求の完了を妨げる可能性があるが、アプリケーション実行の妨げにはならないエラーを表示するために使用されます。
|
SEVERE | 1000 |
-
|
FATAL | 1100 |
クリティカルなサービス障害やアプリケーションのシャットダウンをもたらしたり、JBoss EAP 6 のシャットダウンを引き起こす可能性があるイベントを表示するのに使用されます。
|
5.1.5. デフォルトのログファイルの場所
表5.2 スタンドアロンサーバーのデフォルトログファイル
ログファイル | Description |
---|---|
EAP_HOME/standalone/log/server.log |
Server Log.サーバー起動メッセージを含む、すべてのサーバーログメッセージが含まれます。
|
EAP_HOME/standalone/log/gc.log |
ガベージコレクションログ。すべてのガベージコレクションの詳細が含まれています。
|
表5.3 管理対象ドメイン用のデフォルトログファイル
ログファイル | Description |
---|---|
EAP_HOME/domain/log/host-controller.log |
ホストコントローラーのブートログ。ホストコントローラーの起動に関連するログメッセージが含まれます。
|
EAP_HOME/domain/log/process-controller.log |
プロセスコントローラーのブートログ。プロセスコントローラーの起動に関連するログメッセージが含まれます。
|
EAP_HOME/domain/servers/SERVERNAME/log/server.log |
指定されたサーバーのサーバーログ。サーバーの起動メッセージを含む、そのサーバーのすべてのログメッセージが含まれます。
|
5.2. JBoss Logging Framework を用いたロギング
5.2.1. JBoss Logging について
5.2.2. JBossLogging の機能
- 革新的で使いやすい型付きロガーを提供します。
- 国際化およびローカリゼーションの完全なサポート。翻訳者は properties ファイルのメッセージバンドルを、開発者はインターフェースやアノテーションを使い作業を行います。
- 実稼働用の型指定されたロガーを生成し、開発用の型指定されたロガーを実行時に生成する構築時ツール。
5.2.3. JBoss Logging を使用したアプリケーションへのロギングの追加
org.jboss.logging.Logger
) そしてそのオブジェクトの適切なメソッドを呼び出します。このタスクでは、これに対するサポートをアプリケーションに追加するために必要な手順について説明します。
前提条件
- ビルドシステムとして Maven を使用している場合は、JBossMaven リポジトリーを含めるようにプロジェクトを設定する必要があります。「Maven 設定を使用した JBoss EAP 6 Maven リポジトリーの設定」 を参照してください。
- JBoss Logging JAR ファイルがアプリケーションのビルドパスに指定されている必要があります。これを行う方法は、Red Hat JBossDeveloperStudio を使用してアプリケーションをビルドするか Maven を使用してアプリケーションをビルドするかによって異なります。
- Red Hat JBoss Developer Studio を使用してビルドする場合は、プロジェクト メニューから プロパティー を選択し、ターゲット ランタイムを選択して、JBoss EAP 6 のランタイムがチェックされていることを確認します。
- Maven を使用してビルドする場合は、次の依存関係設定をプロジェクトの
pom.xml
ファイルに追加します。<dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.1.2.GA-redhat-1</version> <scope>provided</scope> </dependency>
JAR は、JBoss EAP 6 がデプロイされたアプリケーションに提供するため、ビルドされたアプリケーションに含める必要はありません。
手順5.1 アプリケーションにロギングを追加する
インポートを追加
使用する JBoss Logging クラスネームスペースに対してimport
ステートメントを追加します。少なくとも、インポートする必要がありますimport org.jboss.logging.Logger
。import org.jboss.logging.Logger;
Logger オブジェクトを作成します
のインスタンスを作成しますorg.jboss.logging.Logger
静的メソッドを呼び出して初期化しますLogger.getLogger(Class)
。Red Hat は、これをクラスごとに単一のインスタンス変数として作成することをお勧めします。private static final Logger LOGGER = Logger.getLogger(HelloWorld.class);
ロギングメッセージを追加する
のメソッドへの呼び出しを追加しますLogger
ログメッセージを送信するコードに反対します。Logger
オブジェクトには、異なるタイプのメッセージに対して異なるパラメーターを持つさまざまなメソッドがあります。最も使いやすいのは次のとおりです。debug(Object message)
info(Object message)
error(Object message)
trace(Object message)
fatal(Object message)
これらのメソッドは、対応するログレベルとmessage
文字列としてのパラメーター。LOGGER.error("Configuration file not found.");
JBoss Logging メソッドの完全なリストについては、以下を参照してください。org.jboss.logging
JBoss EAP 6 ドキュメントのパッケージ。
例5.1 プロパティーファイルを開くときに JBossLogging を使用する
import org.jboss.logging.Logger; public class LocalSystemConfig { private static final Logger LOGGER = Logger.getLogger(LocalSystemConfig.class); public Properties openCustomProperties(String configname) throws CustomConfigFileNotFoundException { Properties props = new Properties(); try { LOGGER.info("Loading custom configuration from "+configname); props.load(new FileInputStream(configname)); } catch(IOException e) //catch exception in case properties file does not exist { LOGGER.error("Custom configuration file ("+configname+") not found. Using defaults."); throw new CustomConfigFileNotFoundException(configname); } return props; }
5.3. デプロイメントごとのロギング
5.3.1. デプロイメントごとのロギング
5.3.2. デプロイメントごとのロギングをアプリケーションに追加
logging.properties
をデプロイメントに追加します。この設定ファイルは、JBoss Log Manager が基礎となるログマネージャーである場合にどのロギングファサードとも使用できるため、推奨されます。
Simple Logging Facade for Java (SLF4J)
または Apache log4j
を使用している場合は、logging.properties
設定ファイルが適しています。Apache log4j アペンダーを使用している場合は、log4j.properties
設定ファイルが必要になります。jboss-logging.properties
設定ファイルはレガシーデプロイメントのみでサポートされます。
手順5.2 アプリケーションに設定ファイルを追加する
設定ファイルが追加されるディレクトリーは、デプロイメント方法によって異なります。
EAR
、WAR
、JAR
のいずれかです。EAR
デプロイメントロギング設定ファイルをMETA-INF
ディレクトリーにコピーします。WAR
またはJAR
デプロイメントロギング設定ファイルをMETA-INF
またはWEB-INF/classes
ディレクトリーにコピーします。
5.3.3. logging.properties ファイルの例
# Additional loggers to configure (the root logger is always configured) loggers= # Root logger configuration logger.level=INFO logger.handlers=FILE # A handler configuration handler.FILE=org.jboss.logmanager.handlers.FileHandler handler.FILE.level=ALL handler.FILE.formatter=PATTERN handler.FILE.properties=append,autoFlush,enabled,suffix,fileName handler.FILE.constructorProperties=fileName,append handler.FILE.append=true handler.FILE.autoFlush=true handler.FILE.enabled=true handler.FILE.fileName=${jboss.server.log.dir}/app.log # The formatter to use formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter formatter.PATTERN.properties=pattern formatter.PATTERN.constructorProperties=pattern formatter.PATTERN.pattern=%d %-5p %c: %m%n
5.4. ロギングプロファイル
5.4.1. ロギングプロファイル
- 一意な名前これは必須です。
- 任意の数のログハンドラー。
- 任意の数のログカテゴリー。
- 最大 1 つのルートロガー。
logging-profile
属性を使用して、MANIFEST.MF
ファイルで使用するロギングプロファイルを指定できます。
5.4.2. アプリケーションでのロギングプロファイルの指定
MANIFEST.MF
ファイルで指定できます。
要件:
- このアプリケーションが使用するサーバー上に設定されたロギングプロファイルの名前を知っている必要があります。使用するプロファイルの名前については、サーバー管理者に問い合わせてください。
手順5.3 ロギングプロファイル設定のアプリケーションへの追加
MANIFEST.MF を
編集しますアプリケーションにMANIFEST.MF
ファイルがない場合は、次の内容でファイルを作成し、NAME を必要なプロファイル名に置き換えます。Manifest-Version: 1.0 Logging-Profile: NAME
アプリケーションにすでにMANIFEST.MF
ファイルがある場合は、次の行を追加して、NAME を必要なプロファイル名に置き換えます。Logging-Profile: NAME
maven-war-plugin
を使用している場合は、MANIFEST.MF ファイルを src/main/resources/META-INF/
に置き、次の設定を pom.xml
ファイルに追加できます。
<plugin> <artifactId>maven-war-plugin</artifactId> <configuration> <archive> <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin>
第6章 国際化と現地語化
6.1. はじめに
6.1.1. 国際化
6.1.2. 多言語化
6.2. JBoss Logging Tools
6.2.1. 概要
6.2.1.1. JBoss Logging Tools の国際化および現地語化
org.jboss.logging
注釈。インターフェイスを実装する必要はありません。JBossLoggingTools はコンパイル時にこれを実行します。定義すると、これらのメソッドを使用してコードでメッセージをログに記録したり、例外オブジェクトを取得したりできます。
6.2.1.2. JBossLoggingTools クイックスタート
logging-tools
には、JBossLoggingTools の機能を示す単純な Maven プロジェクトが含まれています。このドキュメントでは、コードサンプルとして広く使用されています。
6.2.1.3. メッセージロガー
@org.jboss.logging.MessageLogger
。
6.2.1.4. メッセージバンドル
@org.jboss.logging.MessageBundle
。
6.2.1.5. 国際化されたログメッセージ
@LogMessage
と@Message
注釈を付け、の value 属性を使用してログメッセージを指定します@Message
。国際化されたログメッセージはプロパティーファイルで翻訳を提供することによりローカライズされます。
6.2.1.6. 国際化された例外
6.2.1.7. 国際化されたメッセージ
6.2.1.8. 翻訳プロパティーファイル
6.2.1.9. JBoss Logging Tools のプロジェクトコード
projectCode
の属性@MessageLogger
注釈。
6.2.1.10. JBoss Logging Tools のメッセージ ID
id
の属性@Message
注釈。
6.2.2. 国際化されたロガー、メッセージ、例外の作成
6.2.2.1. 国際化されたログメッセージの作成
logging-tools
クイックスタートを参照してください。
要件:
- 作業用の Maven プロジェクトがすでに存在している必要があります。「JBoss Logging Tools の Maven 設定」 を参照してください。
- プロジェクトには、JBossLoggingTools に必要な Maven 設定が必要です。
手順6.1 国際化されたログメッセージバンドルを作成する
メッセージロガーインターフェイスを作成する
プロジェクトに Java インターフェイスを追加して、ログメッセージ定義を含めます。インターフェイスに定義されるログメッセージの説明的な名前を付けます。ログメッセージインターフェースの要件は次のとおりです。- 注釈を付ける必要があります
@org.jboss.logging.MessageLogger
。 - 延長する必要があります
org.jboss.logging.BasicLogger
。 - インターフェイスは、このインターフェイスを実装する型付きロガーであるフィールドを定義する必要があります。でこれを行う
getMessageLogger()
の方法org.jboss.logging.Logger
。
package com.company.accounts.loggers; import org.jboss.logging.BasicLogger; import org.jboss.logging.Logger; import org.jboss.logging.MessageLogger; @MessageLogger(projectCode="") interface AccountsLogger extends BasicLogger { AccountsLogger LOGGER = Logger.getMessageLogger( AccountsLogger.class, AccountsLogger.class.getPackage().getName() ); }
メソッド定義を追加する
各ログメッセージのインターフェースにメソッド定義を追加します。ログメッセージの各メソッドにその内容を表す名前を付けます。各メソッドの要件は次のとおりです。- メソッドは返す必要があります
void
。 - 注釈を付ける必要があります
@org.jboss.logging.LogMessage
注釈。 - 注釈を付ける必要があります
@org.jboss.logging.Message
注釈。 - の値属性
@org.jboss.logging.Message
デフォルトのログメッセージが含まれています。このメッセージは翻訳がない場合に使用されます。
@LogMessage @Message(value = "Customer query failed, Database not available.") void customerQueryFailDBClosed();
デフォルトのログレベルはINFO
です。メソッドを呼び出します。
メッセージをログに記録する必要があるコードのインターフェイスメソッドへの呼び出しを追加します。インターフェースの実装を作成する必要はありません。これは、プロジェクトがコンパイルされる時にアノテーションプロセッサーにより行われます。AccountsLogger.LOGGER.customerQueryFailDBClosed();
カスタムロガーは BasicLogger からサブクラス化されているため、BasicLogger
((debug()
、error()
など) も使用できます。国際化されていないメッセージをログに記録するために他のロガーを作成する必要はありません。AccountsLogger.LOGGER.error("Invalid query syntax.");
結果
プロジェクトで、現地語化できる 1 つ以上の国際化されたロガーがサポートされるようになります。
6.2.2.2. 国際化されたメッセージの作成と使用
logging-tools
クイックスタートを参照してください。
前提条件
- JBoss EAP 6 リポジトリーを使用する Maven プロジェクトが機能しています。「Maven 設定を使用した JBoss EAP 6 Maven リポジトリーの設定」 を参照してください。
- JBossLoggingTools に必要な Maven 設定が追加されました。「JBoss Logging Tools の Maven 設定」 を参照してください。
手順6.2 国際化されたメッセージの作成と使用
例外のインターフェースを作成します。
JBoss Logging Tools はインターフェースで国際化されたメッセージを定義します。各インターフェイスに、そのインターフェイスで定義されるメッセージの説明的な名前を付けます。インターフェースの要件は以下のとおりです。- public として宣言する必要があります。
- 注釈を付ける必要があります
@org.jboss.logging.MessageBundle
。 - インターフェースと同じ型のメッセージバンドルであるフィールドをインターフェースが定義する必要があります。
@MessageBundle(projectCode="") public interface GreetingMessageBundle { GreetingMessageBundle MESSAGES = Messages.getBundle(GreetingMessageBundle.class); }
メソッド定義を追加する
各メッセージのインターフェースにメソッド定義を追加します。メッセージに対する各メソッドにその内容を表す名前を付けます。各メソッドの要件は次のとおりです。- タイプのオブジェクトを返す必要があります
String
。 - 注釈を付ける必要があります
@org.jboss.logging.Message
注釈。 - の値属性
@org.jboss.logging.Message
デフォルトのメッセージに設定する必要があります。このメッセージは翻訳がない場合に使用されます。
@Message(value = "Hello world.") String helloworldString();
invoke メソッド
メッセージを取得する必要があるアプリケーションでインターフェースメソッドを呼び出します。System.console.out.println(helloworldString());
6.2.2.3. 国際化された例外の作成
logging-tools
クイックスタートを参照してください。
手順6.3 国際化された例外を作成して使用する
JBossLoggingTools 設定を追加します
JBossLoggingTools をサポートするために必要なプロジェクト設定を追加します。「JBoss Logging Tools の Maven 設定」 を参照してください例外のインターフェースを作成します。
JBoss Logging Tools はインターフェースで国際化されたメッセージを定義します。定義される例外について、各インターフェイスにわかりやすい名前を付けます。インターフェースの要件は以下のとおりです。- 次のように宣言する必要があります
public
。 - 注釈を付ける必要があります
@org.jboss.logging.MessageBundle
。 - インターフェースと同じ型のメッセージバンドルであるフィールドをインターフェースが定義する必要があります。
@MessageBundle(projectCode="") public interface ExceptionBundle { ExceptionBundle EXCEPTIONS = Messages.getBundle(ExceptionBundle.class); }
メソッド定義を追加する
各例外のインターフェースにメソッド定義を追加します。例外に対する各メソッドにその内容を表す名前を付けます。各メソッドの要件は次のとおりです。- タイプのオブジェクトを返す必要があります
Exception
またはのサブタイプException
。 - 注釈を付ける必要があります
@org.jboss.logging.Message
注釈。 - の値属性
@org.jboss.logging.Message
デフォルトの例外メッセージに設定する必要があります。このメッセージは翻訳がない場合に使用されます。 - メッセージ文字列の他にパラメーターを必要とするコンストラクターが返される例外にある場合は、
@Param
アノテーションを使用してこれらのパラメーターをメソッド定義に提供する必要があります。パラメーターは、コンストラクターと同じタイプおよび順序である必要があります。
@Message(value = "The config file could not be opened.") IOException configFileAccessError(); @Message(id = 13230, value = "Date string '%s' was invalid.") ParseException dateWasInvalid(String dateString, @Param int errorOffset);
invoke メソッド
例外を取得する必要があるコードでインターフェースメソッドを呼び出します。メソッドによって例外は発生されず、発生できるな例外オブジェクトがメソッドによって返されます。try { propsInFile=new File(configname); props.load(new FileInputStream(propsInFile)); } catch(IOException ioex) //in case props file does not exist { throw ExceptionBundle.EXCEPTIONS.configFileAccessError(); }
6.2.3. 国際化されたロガー、メッセージ、例外の現地語化
6.2.3.1. Maven での新しい翻訳プロパティーファイルの作成
logging-tools
クイックスタートを参照してください。
要件:
- 作業用の Maven プロジェクトがすでに存在している必要があります。
- JBoss Logging Tools に対してプロジェクトが設定されていなければなりません。
- 国際化されたログメッセージや例外を定義する 1 つ以上のインターフェースがプロジェクトに含まれていなければなりません。
手順6.4 Maven での新しい翻訳プロパティーファイルの作成
Maven 設定を追加する
追加します-AgenereatedTranslationFilePath
Maven コンパイラープラグイン設定へのコンパイラー引数を指定し、新しいファイルが作成されるパスを割り当てます。<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> <compilerArgument> -AgeneratedTranslationFilesPath=${project.basedir}/target/generated-translation-files </compilerArgument> <showDeprecation>true</showDeprecation> </configuration> </plugin>
上記の設定により、Maven プロジェクトのtarget/generated-translation-files
ディレクトリーに新しいファイルが作成されます。プロジェクトをビルドします。
Maven を使用してプロジェクトをビルドします。[Localhost]$ mvn compile
@MessageBundle
また@MessageLogger
。各インターフェースが宣言された Java パッケージに対応するサブディレクトリーに新しいファイルが作成されます。
InterfaceName
このファイルが生成されたインターフェイスの名前です: InterfaceName.i18n_locale_COUNTRY_VARIANT.properties
。
6.2.3.2. 国際化されたロガー、例外、またはメッセージの翻訳
logging-tools
クイックスタートを参照してください。
前提条件
- 作業用の Maven プロジェクトがすでに存在している必要があります。
- JBoss Logging Tools に対してプロジェクトが設定されていなければなりません。
- 国際化されたログメッセージや例外を定義する 1 または複数のインターフェースがプロジェクトに含まれていなければなりません。
- テンプレート翻訳プロパティーファイルを生成するようプロジェクトが設定されている必要があります。
手順6.5 国際化されたロガー、例外、またはメッセージの翻訳
テンプレートプロパティーファイルを生成する
mvn compile コマンドを実行して、テンプレート変換プロパティーファイルを作成します。テンプレートファイルをプロジェクトに追加します
翻訳したいインターフェースのテンプレートを、テンプレートが作成されたディレクトリーからプロジェクトのsrc/main/resources
ディレクトリーにコピーします。プロパティーファイルは翻訳するインターフェースと同じパッケージに存在する必要があります。コピーしたテンプレートファイルの名前を変更します
テンプレートファイルに含まれる翻訳に従って、テンプレートファイルのコピーの名前を変更します。例:GreeterLogger.i18n_fr_FR.properties
.テンプレートの内容を翻訳します。
新しい翻訳プロパティーファイルを編集して、適切な翻訳を含めます。# Level: Logger.Level.INFO # Message: Hello message sent. logHelloMessageSent=Bonjour message envoyé.
実行する各バンドルの翻訳ごとに、手順 2、3、および 4 を繰り返します。
target/generated-sources/annotations/
で確認できます。
6.2.4. 国際化されたログメッセージのカスタマイズ
6.2.4.1. ログメッセージへのメッセージ ID とプロジェクトコードの追加
logging-tools
クイックスタートを参照してください。
前提条件
- 国際化されたログメッセージが含まれるプロジェクトが存在する必要があります。「国際化されたログメッセージの作成」 を参照してください。
- 使用するプロジェクトコードを知っている必要があります。プロジェクトコードを 1 つ使用することも、各インターフェースに異なる複数のコードを定義することも可能です。
手順6.6 ログメッセージへのメッセージ ID とプロジェクトコードの追加
インターフェイスのプロジェクトコードを指定します。
の projectCode 属性を使用してプロジェクトコードを指定します@MessageLogger
カスタムロガーインターフェイスに付加された注釈。インターフェースに定義されるすべてのメッセージがこのプロジェクトコードを使用します。@MessageLogger(projectCode="ACCNTS") interface AccountsLogger extends BasicLogger { }
メッセージ ID を指定する
メッセージを定義するメソッドに付けられる@Message
アノテーションのid
属性を使用して、各メッセージのメッセージ ID を指定します。@LogMessage @Message(id=43, value = "Customer query failed, Database not available.") void customerQueryFailDBClosed();
10:55:50,638 INFO [com.company.accounts.ejb] (MSC service thread 1-4) ACCNTS000043: Customer query failed, Database not available.
6.2.4.2. メッセージのログレベル設定
INFO
です。別のログレベルを指定できますlevel
の属性@LogMessage
ロギングメソッドに付加されたアノテーション。
手順6.7 メッセージのログレベル設定
レベル属性を指定する
追加しますlevel
に属性@LogMessage
ログメッセージメソッド定義のアノテーション。ログレベルを割り当てる
を割り当てますlevel
このメッセージのログレベルの値を属性付けします。の有効な値level
で定義されている 6 つの列挙型定数ですorg.jboss.logging.Logger.Level
:DEBUG
、ERROR
、FATAL
、INFO
、TRACE
、とWARN
。Import org.jboss.logging.Logger.Level; @LogMessage(level=Level.ERROR) @Message(value = "Customer query failed, Database not available.") void customerQueryFailDBClosed();
ERROR
レベルのログメッセージが作成されます。
10:55:50,638 ERROR [com.company.app.Main] (MSC service thread 1-4) Customer query failed, Database not available.
6.2.4.3. パラメーターによるログメッセージのカスタマイズ
手順6.8 パラメーターによるログメッセージのカスタマイズ
メソッド定義にパラメーターを追加する
任意のタイプのパラメーターをメソッド定義に追加できます。型に関係なくパラメーターの String 表現がメッセージに表示されます。ログメッセージにパラメーター参照を追加します
参照は明示的なインデックスまたは通常のインデックスを使用できます。- 通常のインデックスを使用するには、各パラメーターを表示したいメッセージ文字列に
%s
文字を挿入します。%s
の最初のインスタンスにより最初のパラメーターが挿入され、2 番目のインスタンスにより 2 番目のパラメーターが挿入されます。 - 明示的なインデックスを使用するには、文字
%{#$}s
をメッセージに挿入します。ここで、# は表示したいパラメーターの数を示します。
@Cause
アノテーションが付けられたパラメーターはパラメーターの数には含まれません。
例6.1 通常のインデックスを使用したメッセージパラメーター
@LogMessage(level=Logger.Level.DEBUG) @Message(id=2, value="Customer query failed, customerid:%s, user:%s") void customerLookupFailed(Long customerid, String username);
例6.2 明示的なインデックスを使用したメッセージパラメーター
@LogMessage(level=Logger.Level.DEBUG) @Message(id=2, value="Customer query failed, user:%2$s, customerid:%1$s") void customerLookupFailed(Long customerid, String username);
6.2.4.4. 例外をログメッセージの原因として指定
Throwable
またはそのサブクラスのいずれかであり、@Cause
注釈。このパラメーターは、他のパラメーターのようにログメッセージで参照することはできず、ログメッセージの後に表示されます。
@Cause
パラメーターを使用して「原因となる」例外を示し、ロギングメソッドを更新する方法を表しています。この機能に追加したい国際化されたロギングメッセージがすでに作成されていることを前提とします。
手順6.9 例外をログメッセージの原因として指定
パラメーターを追加します。
タイプのパラメーターを追加しますThrowable
またはメソッドのサブクラス。@LogMessage @Message(id=404, value="Loading configuration failed. Config file:%s") void loadConfigFailed(Exception ex, File file);
アノテーションを追加します。
追加します@Cause
パラメーターへの注釈。import org.jboss.logging.Cause @LogMessage @Message(value = "Loading configuration failed. Config file: %s") void loadConfigFailed(@Cause Exception ex, File file);
メソッドを呼び出します。
コードでメソッドが呼び出されると、正しい型のオブジェクトが渡され、ログメッセージの後に表示されます。try { confFile=new File(filename); props.load(new FileInputStream(confFile)); } catch(Exception ex) //in case properties file cannot be read { ConfigLogger.LOGGER.loadConfigFailed(ex, filename); }
以下は、コードがタイプの例外を出力した場合の上記のコードサンプルの出力です。FileNotFoundException
。10:50:14,675 INFO [com.company.app.Main] (MSC service thread 1-3) Loading configuration failed. Config file: customised.properties java.io.FileNotFoundException: customised.properties (No such file or directory) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.<init>(FileInputStream.java:120) at com.company.app.demo.Main.openCustomProperties(Main.java:70) at com.company.app.Main.go(Main.java:53) at com.company.app.Main.main(Main.java:43)
6.2.5. 国際化された例外のカスタマイズ
6.2.5.1. メッセージ ID およびプロジェクトコードの例外メッセージへの追加
前提条件
- 国際化された例外が含まれるプロジェクトが存在する必要があります。「国際化された例外の作成」 を参照してください。
- 使用するプロジェクトコードを知っている必要があります。プロジェクトコードを 1 つ使用することも、各インターフェースに異なる複数のコードを定義することも可能です。
手順6.10 メッセージ ID およびプロジェクトコードの例外メッセージへの追加
プロジェクトコードを指定する
を使用してプロジェクトコードを指定しますprojectCode
の属性@MessageBundle
例外バンドルインターフェイスに付加された注釈。インターフェースに定義されるすべてのメッセージがこのプロジェクトコードを使用します。@MessageBundle(projectCode="ACCTS") interface ExceptionBundle { ExceptionBundle EXCEPTIONS = Messages.getBundle(ExceptionBundle.class); }
メッセージ ID を指定する
を使用して、各例外のメッセージ ID を指定します。id
の属性@Message
例外を定義するメソッドに付加されたアノテーション。@Message(id=143, value = "The config file could not be opened.") IOException configFileAccessError();
例6.3 国際化された例外の作成
@MessageBundle(projectCode="ACCTS") interface ExceptionBundle { ExceptionBundle EXCEPTIONS = Messages.getBundle(ExceptionBundle.class); @Message(id=143, value = "The config file could not be opened.") IOException configFileAccessError(); }
throw ExceptionBundle.EXCEPTIONS.configFileAccessError();
Exception in thread "main" java.io.IOException: ACCTS000143: The config file could not be opened. at com.company.accounts.Main.openCustomProperties(Main.java:78) at com.company.accounts.Main.go(Main.java:53) at com.company.accounts.Main.main(Main.java:43)
6.2.5.2. パラメーターによる例外メッセージのカスタマイズ
手順6.11 パラメーターを使用して例外メッセージをカスタマイズする
メソッド定義にパラメーターを追加する
任意のタイプのパラメーターをメソッド定義に追加できます。型に関係なくパラメーターのString
表現がメッセージに表示されます。例外メッセージにパラメーター参照を追加します
参照は明示的なインデックスまたは通常のインデックスを使用できます。- 通常のインデックスを使用するには、各パラメーターを表示したいメッセージ文字列に
%s
文字を挿入します。%s
の最初のインスタンスにより最初のパラメーターが挿入され、2 番目のインスタンスにより 2 番目のパラメーターが挿入されます。 - 明示的なインデックスを使用するには、文字
%{#$}s
をメッセージに挿入します。ここで、#
は表示したいパラメーターの数を示します。
明示的なインデックスを使用すると、メッセージのパラメーター参照の順番がメソッドで定義される順番とは異なるようになります。これは、パラメーターの異なる順序を必要とする可能性のある翻訳されたメッセージにとって重要です。
@Cause
アノテーションが付けられたパラメーターはパラメーターの数には含まれません。
例6.4 通常のインデックスを使用する
@Message(id=2, value="Customer query failed, customerid:%s, user:%s") void customerLookupFailed(Long customerid, String username);
例6.5 明示的なインデックスの使用
@Message(id=2, value="Customer query failed, user:%2$s, customerid:%1$s") void customerLookupFailed(Long customerid, String username);
6.2.5.3. 別の例外の原因として 1 つの例外を指定
@Cause
アノテーションを付けます。このパラメーターは、原因となる例外を渡すために使用されます。このパラメーターは、例外メッセージでは参照できません。
@Cause
パラメーターを使用して原因となる例外を示し、例外バンドルよりメソッドを更新する方法を表しています。この機能に追加したい国際化された例外バンドルがすでに作成されていることを前提とします。
手順6.12 別の例外の原因として 1 つの例外を指定
パラメーターを追加します。
タイプのパラメーターを追加しますThrowable
またはメソッドのサブクラス。@Message(id=328, value = "Error calculating: %s.") ArithmeticException calculationError(Throwable cause, String msg);
アノテーションを追加します。
追加します@Cause
パラメーターへの注釈。import org.jboss.logging.Cause @Message(id=328, value = "Error calculating: %s.") ArithmeticException calculationError(@Cause Throwable cause, String msg);
メソッドを呼び出します。
例外オブジェクトを取得するため、インターフェースメソッドを呼び出します。catch ブロックから新しい例外を発生させ、キャッチした例外を原因として使用するのが最も一般的なユースケースです。try { ... } catch(Exception ex) { throw ExceptionBundle.EXCEPTIONS.calculationError( ex, "calculating payment due per day"); }
例6.6 別の例外の原因として 1 つの例外を指定
@MessageBundle(projectCode = "TPS") interface CalcExceptionBundle { CalcExceptionBundle EXCEPTIONS = Messages.getBundle(CalcExceptionBundle.class); @Message(id=328, value = "Error calculating: %s.") ArithmeticException calcError(@Cause Throwable cause, String value); }
int totalDue = 5; int daysToPay = 0; int amountPerDay; try { amountPerDay = totalDue/daysToPay; } catch (Exception ex) { throw CalcExceptionBundle.EXCEPTIONS.calcError(ex, "payments per day"); }
Exception in thread "main" java.lang.ArithmeticException: TPS000328: Error calculating: payments per day. at com.company.accounts.Main.go(Main.java:58) at com.company.accounts.Main.main(Main.java:43) Caused by: java.lang.ArithmeticException: / by zero at com.company.accounts.Main.go(Main.java:54) ... 1 more
6.2.6. 参照
6.2.6.1. JBoss Logging Tools の Maven 設定
pom.xml
ファイルのプロジェクトの設定に次の変更を加える必要があります。
pom.xml
ファイルの例については、logging-tools
クイックスタートを参照してください。
- プロジェクトで JBossMaven リポジトリーを有効にする必要があります。「Maven 設定を使用した JBoss EAP 6 Maven リポジトリーの設定」 を参照してください。
jboss-logging
およびjboss-logging-processor
の Maven 依存関係を追加する必要があります。両方の依存関係は JBoss EAP 6 で使用できるため、それぞれのスコープ要素を次のように提供
するように設定できます。<dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging-processor</artifactId> <version>1.0.0.Final</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.1.0.GA</version> <scope>provided</scope> </dependency>
maven-compiler-plugin
のバージョンは2.2
以上であり、1.6
のターゲットソースおよび生成されたソースに対して設定する必要があります。<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin>
6.2.6.2. 翻訳プロパティーファイルの形式
key=value
クラス http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html のドキュメントで説明されている単純な行指向の java.util.Properties
ペア形式です。
InterfaceName.i18n_locale_COUNTRY_VARIANT.properties
InterfaceName
は、翻訳が適用されるインターフェイスの名前です。locale
、COUNTRY
、とVARIANT
翻訳が適用される地域の設定を特定します。locale
とCOUNTRY
ISO-639 および ISO-3166 の言語コードと国コードをそれぞれ使用して、言語と国を指定します。COUNTRY
は任意になります。VARIANT
は特定のオペレーティングシステムまたはブラウザーのみに適用される翻訳を識別するために使用できる任意の識別子です。
例6.7 サンプル: 翻訳プロパティーファイル
GreeterService.i18n_fr_FR_POSIX.properties
# Level: Logger.Level.INFO # Message: Hello message sent. logHelloMessageSent=Bonjour message envoyé.
6.2.6.3. JBoss Logging Tools のアノテーションに関するリファレンス
表6.1 JBoss Logging Tools のアノテーション
アノテーション | ターゲット | 説明 | 属性 |
---|---|---|---|
@MessageBundle | Interface |
インターフェースをメッセージバンドルとして定義します。
| projectCode |
@MessageLogger | Interface |
インターフェースをメッセージロガーとして定義します。
| projectCode |
@Message | メソッド |
メッセージバンドルとメッセージロガーで使用できます。メッセージロガーでは、現地語化されたロガーとしてメソッドが定義されます。メッセージバンドルでは、現地語化された String または Exception オブジェクトを返すメソッドとして定義されます。
| value 、id |
@LogMessage | メソッド |
メッセージロガーのメソッドをロギングメソッドとして定義します。
| level (デフォルトは INFO です)。 |
@Cause | パラメーター |
ログメッセージまたは他の例外が発生したときに例外を渡すパラメーターとして定義します。
| - |
@Param | パラメーター |
例外のコンストラクターへ渡されるパラメーターとして定義します。
| - |
第7章 リモート JNDI ルックアップ
7.1. JNDI へのオブジェクトの登録
java:jboss/exported
環境。
メッセージング
サブシステムの JNDI に登録して、リモート JNDI クライアントが検索できるようにする方法の例です。
java:jboss/exported/jms/queue/myTestQueueリモート JNDI クライアントは、上記の名前を使用してオブジェクトを検索できます。ただし、を指定する必要はありません。
java:jboss/exported/
リモートクライアントを検索するときの接頭辞。リモート JNDI クライアントは、次の名前を使用してリモートオブジェクトを検索できます。
jms/queue/myTestQueue
例7.1 スタンドアロンサーバーの JMS キュー設定の例
<subsystem xmlns="urn:jboss:domain:messaging:1.4"> <hornetq-server> ... <jms-destinations> <jms-queue name="myTestQueue"> <entry name="java:jboss/exported/jms/queue/myTestQueue"/> </jms-queue> </jms-destinations> </hornetq-server> </subsystem>
7.2. リモート JNDI クライアントの設定
jboss-client.jar
が必要です。
myTestQueue
リモート JNDI クライアントからの JMS キュー:
例7.2 リモート JNDI ルックアップの例
Properties properties = new Properties(); properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory"); properties.put(Context.PROVIDER_URL, "remote://<hostname>:4447"); context = new InitialContext(properties); Queue myTestQueue = (Queue) context.lookup("jms/queue/myTestQueue");
第8章 Enterprise JavaBeans 3.2
8.1. はじめに
8.1.1. Enterprise JavaBeans の概要
8.1.2. EJB 3.1 機能セット
- セッション Bean
- メッセージ駆動 Bean
- インターフェースなしビュー
- ローカルインターフェース
- リモートインターフェース
- JAX-WS Web サービス
- JAX-RSWeb サービス
- タイマーサービス
- 非同期呼び出し
- インターセプター
- RMI/IIOP の相互運用性
- トランザクションサポート
- セキュリティー
- 組み込み API
- エンティティー Bean (コンテナーおよび Bean で管理された永続性)
- EJB 2.1 エンティティー Bean クライアントビュー
- EJB クエリー言語 (EJB QL)
- JAX-RPC ベースの Web サービス: エンドポイントおよびクライアントビュー
8.1.3. EJB 3.1 Lite
- Web アプリケーションに意味のある機能のみをサポートし、
- EJB を Web アプリケーションと同じ WAR ファイルにデプロイできるようにします。
8.1.4. EJB3.1Lite の機能
- ステートレス、ステートフル、およびシングルトンセッション Bean
- ローカルビジネスインターフェイスとインターフェイスなし Bean
- インターセプター
- コンテナー管理および Bean 管理のトランザクション
- 宣言型およびプログラムによるセキュリティー
- 組み込み API
- リモートインターフェース
- RMI/IIOP の相互運用性
- JAX-WS Web サービスエンドポイント
- EJB タイマーサービス
- 非同期セッション Bean の呼び出し
- メッセージ駆動 Bean
8.1.5. エンタープライズ Bean
8.1.6. EnterpriseBeans の作成の概要
8.1.7. セッション Bean ビジネスインターフェイス
8.1.7.1. エンタープライズ Bean のビジネスインターフェース
8.1.7.2. EJB ローカルビジネスインターフェース
8.1.7.3. EJB リモートビジネスインターフェース
8.1.7.4. EJB No-interface Beans
8.2. エンタープライズ Bean プロジェクトの作成
8.2.1. Red Hat JBossDeveloperStudio を使用して EJB アーカイブプロジェクトを作成する
前提条件
- JBoss EAP 6 のサーバーとサーバーランタイムが設定されました。「Define New Server を使用して JBossEAP サーバーを追加します」 を参照すること。
手順8.1 Red Hat JBossDeveloperStudio で EJB プロジェクトを作成します
新規プロジェクトを作成します。
新規 EJB プロジェクトウィザードを開くには、ファイル メニューに移動し、新規、EJB プロジェクト の順に選択します。図8.1 新しい EJB プロジェクトウィザード
[D]詳細を指定
次の詳細を入力します。- プロジェクト名。Red Hat JBoss Developer Studio に表示されるプロジェクトの名前であるだけでなく、これはデプロイされた JAR ファイルのデフォルトのファイル名でもあります。
- プロジェクトの場所。プロジェクトのファイルが保存されるディレクトリー。デフォルトは、現在のワークスペースのディレクトリーです。
- ターゲットランタイムこれは、プロジェクトに使用されるサーバーランタイムです。これは、デプロイするサーバーによって使用されるものと同じ JBoss EAP 6 ランタイムに設定する必要があります。
- EJB モジュールバージョン。これは、エンタープライズ Bean が準拠する EJB 仕様のバージョンです。Red Hat は、
3.1
の使用を推奨します。 - 設定これにより、プロジェクトでサポートされている機能を調整できます。選択したランタイムにデフォルト設定を使用します。
Next をクリックして先に進みます。Java ビルド設定
この画面では、Java ソースファイルとビルドされた出力が配置されるディレクトリーを含むディレクトリーをカスタマイズできます。この設定は変更せず、Next をクリックします。EJB モジュールの設定
デプロイメント記述子が必要な場合は、ejb-jar.xml デプロイメント記述子を生成 するチェックボックスをオンにします。デプロイメント記述子は EJB 3 1 では任意で、必要な場合は後で追加できます。Finish をクリックするとプロジェクトが作成され、Project Explorer に表示されます。図8.2 Project Explorer で新たに作成された EJB プロジェクト
[D]デプロイのためにビルドアーティファクトをサーバーに追加する
ビルドされたアーティファクトをデプロイするサーバーをサーバータブで右クリックして 追加と削除 ダイアログを開き、追加と削除を選択します。Available コラムからデプロイする リソースを選択し、Add ボタンをクリックします。リソースは Configured コラムに移動します。Finish をクリックしてダイアログを閉じます。図8.3 ダイアログの追加または削除
[D]
結果
これで、Red Hat JBoss Developer Studio に EJB プロジェクトがあり、指定したサーバーにビルドしてデプロイできます。
8.2.2. Maven での EJB アーカイブプロジェクトの作成
要件:
- Maven がすでにインストールされている。
- Maven の基本的な使用方法を理解している。
手順8.2 Maven での EJB アーカイブプロジェクトの作成
Maven プロジェクトを作成する
EJB プロジェクトは、Maven のアーキタイプシステムとejb-javaee6
アーキタイプ。これを実行するには、以下のパラメーターを指定して mvn コマンドを実行します。mvn archetype:generate -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=ejb-javaee6
Maven はプロンプトを表示しますgroupId
、artifactId
、version
とpackage
あなたのプロジェクトのために。[localhost]$ mvn archetype:generate -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=ejb-javaee6 [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building Maven Stub Project (No POM) 1 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] >>> maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom >>> [INFO] [INFO] <<< maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom <<< [INFO] [INFO] --- maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom --- [INFO] Generating project in Interactive mode [INFO] Archetype [org.codehaus.mojo.archetypes:ejb-javaee6:1.5] found in catalog remote Define value for property 'groupId': : com.shinysparkly Define value for property 'artifactId': : payment-arrangments Define value for property 'version': 1.0-SNAPSHOT: : Define value for property 'package': com.shinysparkly: : Confirm properties configuration: groupId: com.company artifactId: payment-arrangments version: 1.0-SNAPSHOT package: com.company.collections Y: : [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 32.440s [INFO] Finished at: Mon Oct 31 10:11:12 EST 2011 [INFO] Final Memory: 7M/81M [INFO] ------------------------------------------------------------------------ [localhost]$
エンタープライズ Bean を追加する
エンタープライズ Bean を作成し、それらを Bean のパッケージの適切なサブディレクトリーのsrc/main/java
ディレクトリーの下のプロジェクトに追加します。プロジェクトをビルドします。
プロジェクトをビルドするには、pom.xml
ファイルと同じディレクトリーで mvnpackage コマンドを実行します。これにより、Java クラスがコンパイルされ、JAR ファイルがパッケージ化されます。ビルドされた JAR ファイルの名前はartifactId -- version.jar
で、target/
ディレクトリーに配置されます。
8.2.3. EJB プロジェクトを含む EAR プロジェクトの作成
前提条件
- JBoss EAP 6 のサーバーとサーバーランタイムが設定されました。「Define New Server を使用して JBossEAP サーバーを追加します」を参照してください。
手順8.3 EJB プロジェクトを含む EAR プロジェクトの作成
新しい EAR アプリケーションプロジェクトウィザードを開きます
ファイル メニューに移動し、新規、プロジェクト の順に選択すると、新規プロジェクト ウィザードが表示されます。Java EE/Enterprise Application Project を選択し、Next をクリックします。図8.4 新規 EAR アプリケーションプロジェクトウィザード
[D]供給の詳細
次の詳細を入力します。- プロジェクト名。Red Hat JBoss Developer Studio に表示されるプロジェクトの名前であるだけでなく、これはデプロイされた EAR ファイルのデフォルトのファイル名でもあります。
- プロジェクトの場所。プロジェクトのファイルが保存されるディレクトリー。デフォルトは、現在のワークスペースのディレクトリーです。
- ターゲットランタイムこれは、プロジェクトに使用されるサーバーランタイムです。これは、デプロイするサーバーによって使用されるものと同じ JBoss EAP 6 ランタイムに設定する必要があります。
- EAR バージョン。これは、プロジェクトが準拠する JavaEnterpriseEdition 仕様のバージョンです。Red Hat は、
6
の使用を推奨します。 - 設定これにより、プロジェクトでサポートされている機能を調整できます。選択したランタイムにデフォルト設定を使用します。
Next をクリックして先に進みます。新しい EJB モジュールを追加します。
ウィザードの Enterprise Applicaiton ページから、新しいモジュールを追加できます。新しい EJB Project をモジュールとして追加するには、以下の手順に従います。新しい EJB モジュールを追加する
New Moduleをクリックし、Create Default Modules チェックボックスのチェックを外し、Enterprise Java Bean を選択して Next をクリックします。New EJB Project ウィザードが表示されます。EJB プロジェクトの作成
新しい EJB プロジェクト ウィザードは、新しいスタンドアロン EJB プロジェクトの作成に使用されるウィザードと同じであり、「Red Hat JBossDeveloperStudio を使用して EJB アーカイブプロジェクトを作成する」。プロジェクトの作成に必要な最低限の詳細は、以下のとおりです。- プロジェクト名
- ターゲットランタイム
- EJB モジュールバージョン
- 設定
ウィザードの他のすべての手順はオプションです。Finish をクリックし、EJB プロジェクトの作成を完了します。
新規作成した EJB プロジェクトは Java EE モジュール依存関係に一覧表示され、チェックボックスにチェックが付けられます。オプション: application.xml デプロイメント記述子を追加します。
必要な場合は、Generate application.xml deployment descriptor チェックボックスにチェックを入れます。Finish をクリックします。
EJB と EAR という 2 つのプロジェクトが表示されます。デプロイのためにビルドアーティファクトをサーバーに追加する
Server タブで、ビルドされたアーティファクトをデプロイするサーバーの Servers タブで Add and Remove ダイアログを開き、Add and Remove を選択します。Available コラムからデプロイする EAR リソースを選択し、Add ボタンをクリックします。リソースは Configured コラムに移動します。Finish をクリックしてダイアログを閉じます。図8.5 ダイアログの追加または削除
[D]
結果
これで、メンバー EJB プロジェクトを含む Enterprise Application Project ができました。これにより、EJB サブデプロイメントを含む単一の EAR デプロイメントとして指定のサーバーにビルドされ、デプロイされます。
8.2.4. EJB プロジェクトへのデプロイメント記述子の追加
必要条件:
- Red Hat JBoss Developer Studio に EJB プロジェクトがあり、そこに EJB デプロイメント記述子を追加します。
手順8.4 EJB プロジェクトへのデプロイメント記述子の追加
プロジェクトを開く
Red Hat JBossDeveloperStudio でプロジェクトを開きます。デプロイメント記述子を追加する
プロジェクトビューの Deployment Descriptor フォルダーを右クリックして、Generate Deployment Descriptor Stub タブを選択します。図8.6 デプロイメント記述子の追加
[D]
ejb-jar.xml
が ejbModule/META-INF/
に作成されます。プロジェクトビューで DeploymentDescriptor フォルダーをダブルクリックすると、このファイルも開きます。
8.3. セッション Bean
8.3.1. セッション Bean
8.3.2. ステートレスセッション Bean
8.3.3. ステートフルセッション Bean
8.3.4. シングルトンセッション Bean
8.3.5. Red Hat JBossDeveloperStudio のプロジェクトにセッション Bean を追加します
要件:
- 1 つ以上のセッション Bean を追加する EJB または動的 Web プロジェクトが Red Hat にあります。
手順8.5 Red Hat JBossDeveloperStudio のプロジェクトにセッション Bean を追加します
プロジェクトを開く
Red Hat JBossDeveloperStudio でプロジェクトを開きます。”Create EJB 3.x Session Bean” ウィザードを開きます。
Create EJB 3.x Session Bean ウィザードを開くには、File メニューに移動し、New を選択して Session Bean (EJB 3.x) を選択します。図8.7 Create EJB 3.x Session Bean ウィザード
[D]クラス情報を指定する
次の詳細を入力します。- プロジェクト正しいプロジェクトが選択されていることを確認します。
- ソースフォルダーこれは、Java ソースファイルが作成されるフォルダーです。通常、これは変更する必要はありません。
- Packageクラスが属するパッケージを指定します。
- クラス名セッション Bean となるクラスの名前を指定します。
- スーパークラスセッション Bean クラスは、スーパークラスから継承できます。セッションにスーパークラスがある場合は、これを指定します。
- 状態タイプセッション Bean の状態タイプ (stateless、stateful、または singleton) を指定します。
- ビジネスインターフェイスデフォルトでは、インターフェイスなしボックスがオンになっているため、インターフェイスは作成されません。定義するインターフェースのボックスにチェックを入れ、必要に応じて名前を調整します。Web アーカイブ (WAR) のエンタープライズ Bean は EJB 3.1 Lite のみをサポートし、これにはリモートビジネスインターフェースが含まれないことに注意してください。
Next をクリックします。セッション Bean 固有の情報
ここで追加情報を入力して、セッション Bean をさらにカスタマイズできます。ここで情報を変更する必要はありません。変更可能なアイテムは次のとおりです。- Bean 名
- マップされた名前
- トランザクションタイプ (管理対象コンテナーまたは管理対象 Bean)
- Bean が実装する必要のある追加のインターフェースを指定可能
- EJB 2.x Home and Component インターフェースを必要に応じて指定することもできます。
Finish
Finish をクリックすると、新しいセッション Bean が作成され、プロジェクトに追加されます。新しいビジネスインターフェースのファイルが指定されていれば、それらも作成されます。
図8.8 Red Hat JBossDeveloperStudio の新しいセッション Bean
[D]
8.4. メッセージ駆動 Bean
8.4.1. メッセージ駆動 Bean
8.4.2. リソースアダプター
8.4.3. Red Hat JBossDeveloperStudio で JMS ベースのメッセージ駆動型 Bean を作成する
要件:
- Red Hat JBossDeveloperStudio で既存のプロジェクトを開いておく必要があります。
- Bean がリッスンする JMS 宛先の名前とタイプを知っている必要があります。
- Java Messaging Service (JMS) のサポートは、この Bean がデプロイされる JBoss EAP 6 設定で有効にする必要があります。
手順8.6 Red Hat JBossDeveloperStudio に JMS ベースのメッセージ駆動型 Bean を追加します
Create EJB 3.x Message-LoadBalancern Bean ウィザードを開きます。
ファイル → 新規 → その他 に移動します。EJB/Message-Driven Bean (EJB 3.x) を選択し、Next ボタンをクリックします。図8.9 Create EJB 3.x Message-Driven Bean ウィザード
[D]クラスファイル宛先の詳細を指定します。
ここでは、bean クラスに指定する詳細セット (プロジェクト、Java クラス、メッセージの宛先) があります。- プロジェクト
- Workspace に複数のプロジェクトが存在する場合は、Project メニューで適切なプロジェクトが選択されていることを確認します。
- 新規 Bean のソースファイルが作成されるフォルダーは、選択したプロジェクトのディレクトリーの下の
ejbModule
になります。これは、特定の要件がある場合にのみ変更します。
- Java class
- 必須フィールドは Java package と class name です。
- アプリケーションのビジネスロジックで必要な場合を除いて、Superclass を指定する必要はありません。
- メッセージの宛先
- 以下は、JMS ベースのメッセージ駆動 Bean に提供する必要のある詳細です。
- 宛先名これは、Bean が応答するメッセージを含むキューまたはトピック名です。
- デフォルトでは、JMS チェックボックスが選択されます。これは変更しないでください。
- 必要に応じて Destination type を Queue または Topic に設定します。
Next ボタンをクリックします。メッセージ駆動 Bean 固有の情報を入力します。
ここでのデフォルト値は、コンテナー管理トランザクションを使用する JMS ベースのメッセージ駆動 Bean に適しています。- Bean が Bean 管理対象トランザクションを使用する場合は、Transaction type を Bean に変更します。
- クラス名とは異なる Bean 名が必要な場合は Bean name を変更します。
- JMS Message Listener インターフェースはすでにリストされています。インターフェースがアプリケーションのビジネスロジックに固有のものでない場合は、インターフェースを追加または削除する必要はありません。
- メソッドスタブを作成するためのチェックボックスは選択したままにしておきます。
Finish ボタンをクリックします。
onMessage()
メソッド用のスタブメソッドで作成されます。対応するファイルで開かれた Red Hat エディターウィンドウ。
8.4.4. MDB に対して jboss-ejb3.xml
でのリソースアダプターの指定
jboss-ejb3.xml
デプロイメント記述子では、MDB が使用するリソースアダプターを指定できます。または、MDB 用に JBoss EAP 6 サーバー全体のデフォルトリソースアダプターを設定するには、『管理および設定ガイド』 の 『メッセージドリブン Bean』 の設定を参照してください。
jboss-ejb3.xml
でリソースアダプターを指定するには、以下の例を使用します。
例8.1 例: MDB リソースアダプターの jboss-ejb3.xml
設定
<jboss xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:jee="http://java.sun.com/xml/ns/javaee" xmlns:mdb="urn:resource-adapter-binding"> <jee:assembly-descriptor> <mdb:resource-adapter-binding> <jee:ejb-name>MyMDB</jee:ejb-name> <mdb:resource-adapter-name>MyResourceAdapter.rar</mdb:resource-adapter-name> </mdb:resource-adapter-binding> </jee:assembly-descriptor> </jboss>
<mdb:resource-adapter-name>
:
- 別の EAR にあるリソースアダプターの場合:
<mdb:resource-adapter-name>OtherDeployment.ear#MyResourceAdapter.rar</mdb:resource-adapter-name>
- MDB と同じ EAR にあるリソースアダプターでは、EAR 名を省略できます。
<mdb:resource-adapter-name>#MyResourceAdapter.rar</mdb:resource-adapter-name>
8.4.5. アプリケーションで EJB および MDB プロパティーの置換を有効にする
@ActivationConfigProperty
と@Resource
注釈。プロパティーの置換には、以下の設定およびコードの変更が必要です。
- JBoss EAP サーバー設定ファイルでプロパティー置換を有効にする必要があります。
- JBoss EAP サーバーの起動時に、システムプロパティーをサーバー設定ファイルに定義するか、引数として渡す必要があります。
- 置換変数を使用するには、コードを変更する必要があります。
手順8.7 MDB アプリケーションにプロパティー置換を実装する
helloworld-mdb
クイックスタートに基づいています。このトピックでは、そのクイックスタートを変更してプロパティーの置換を有効にする方法を示します。
プロパティー置換を有効にするように JBoss EAP サーバーを設定します。
プロパティーの置換を有効にするように JBoss EAP サーバーを設定する必要があります。これを行うには、<annotation-property-replacement>
サーバー設定ファイルのee
サブシステムの属性をtrue
に設定します。- サーバー設定ファイルをバックアップします。
helloworld-mdb
クイックスタートの例では、スタンドアロンサーバーの完全なプロファイルが必要であるため、これはstandalone/configuration/standalone-full.xml
ファイルです。管理対象ドメインでサーバーを実行している場合は、domain/configuration/domain.xml
ファイルになります。 - フルプロファイルで JBoss EAP サーバーを起動します。Linux の場合
EAP_HOME/bin/standalone.sh -c standalone-full.xml
Windows の場合:EAP_HOMEbin\standalone.bat -c standalone-full.xml
- ご使用のオペレーティングシステム向けのコマンドを使用して、管理 CLI を起動します。Linux の場合
EAP_HOME/bin/jboss-cli.sh --connect
Windows の場合:EAP_HOME\bin\jboss-cli.bat --connect
- アノテーションプロパティーの置換を有効にするには、以下のコマンドを実行します。
/subsystem=ee:write-attribute(name=annotation-property-replacement,value=true)
- 以下の結果が表示されるはずです。
{"outcome" => "success"}
- JBoss EAP サーバー設定ファイルへの変更を確認します。
ee
サブシステムには以下の XML が含まれるはずです。<subsystem xmlns="urn:jboss:domain:ee:1.2"> <spec-descriptor-property-replacement>false</spec-descriptor-property-replacement> <jboss-descriptor-property-replacement>true</jboss-descriptor-property-replacement> <annotation-property-replacement>true</annotation-property-replacement> </subsystem>
システムプロパティーの定義
サーバー設定ファイルでシステムプロパティーを指定するか、JBoss EAP サーバーの起動時にコマンドラインの引数としてプロパティーを渡すことができます。サーバー設定ファイルで定義されたシステムプロパティーは、サーバーの起動時にコマンドラインに渡されるプロパティーよりも優先されます。- サーバー設定でのシステムプロパティーの定義
- 前のステップで説明したように、JBoss EAP サーバーと管理 API を起動します。
- 以下のコマンド構文を使用して、JBoss EAP サーバーのシステムプロパティーを設定します。
/system-property=PROPERTY_NAME:add(value=PROPERTY_VALUE)
helloworld-mdb
クイックスタートでは、次のシステムプロパティーを設定します。/system-property=property.helloworldmdb.queue:add(value=java:/queue/HELLOWORLDMDBPropQueue) /system-property=property.helloworldmdb.topic:add(value=java:/topic/HELLOWORLDMDBPropTopic) /system-property=property.connection.factory:add(value=java:/ConnectionFactory)
- JBoss EAP サーバー設定ファイルへの変更を確認します。以下のシステムプロパティーは、
<extensions>
の後に表示されるはずです。<system-properties> <property name="property.helloworldmdb.queue" value="java:/queue/HELLOWORLDMDBPropQueue"/> <property name="property.helloworldmdb.topic" value="java:/topic/HELLOWORLDMDBPropTopic"/> <property name="property.connection.factory" value="java:/ConnectionFactory"/> </system-properties>
- JBoss EAP サーバーを起動するときにコマンドラインでシステムプロパティーを引数として -DPROPERTY_NAME=PROPERTY_VALUE の形式で渡します。以下は、前の手順で定義されたシステムプロパティーの引数を渡す方法の例になります。
EAP_HOME/bin/standalone.sh -c standalone-full.xml -Dproperty.helloworldmdb.queue=java:/queue/HELLOWORLDMDBPropQueue -Dproperty.helloworldmdb.topic=java:/topic/HELLOWORLDMDBPropTopic -Dproperty.connection.factory=java:/ConnectionFactory
システムプロパティーの置換を使用するようにコードを変更します。
ハードコードされたものを置き換える@ActivationConfigProperty
と@Resource
新しく定義されたシステムプロパティーを置換した注釈値。以下は、helloworld-mdb
クイックスタートを変更して、ソースコードのアノテーション内で新しく定義されたシステムプロパティーの置換を使用する方法の例です。- 変更
@ActivationConfigProperty
システムプロパティーの置換を使用するためのHelloWorldQueueMDB
クラスの宛先
プロパティー値。The@MessageDriven
注釈は次のようになります。@MessageDriven(name = "HelloWorldQueueMDB", activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destination", propertyValue = "${property.helloworldmdb.queue}"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
- 変更
@ActivationConfigProperty
システムプロパティーの置換を使用するためのHelloWorldTopicMDB
クラスの宛先
プロパティー値。The@MessageDriven
注釈は次のようになります。@MessageDriven(name = "HelloWorldQTopicMDB", activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"), @ActivationConfigProperty(propertyName = "destination", propertyValue = "${property.helloworldmdb.topic}"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
HelloWorldMDBServletClient
クラスの@Resource
アノテーションを変更して、システムプロパティーの置換を使用します。コードは以下のようになります。@Resource(mappedName = "${property.connection.factory}") private ConnectionFactory connectionFactory; @Resource(mappedName = "${property.helloworldmdb.queue}") private Queue queue; @Resource(mappedName = "${property.helloworldmdb.topic}") private Topic topic;
hornetq-jms.xml
ファイルを変更して、システムプロパティーの置換値を使用します。<?xml version="1.0" encoding="UTF-8"?> <messaging-deployment xmlns="urn:jboss:messaging-deployment:1.0"> <hornetq-server> <jms-destinations> <jms-queue name="HELLOWORLDMDBQueue"> <entry name="${property.helloworldmdb.queue}"/> </jms-queue> <jms-topic name="HELLOWORLDMDBTopic"> <entry name="${property.helloworldmdb.topic}"/> </jms-topic> </jms-destinations> </hornetq-server> </messaging-deployment>
- アプリケーションをデプロイします。アプリケーションは、システムプロパティーで指定された値を使用します。
@Resource
と@ActivationConfigProperty
プロパティー値。
8.5. セッション Bean の呼び出し
8.5.1. JNDI を使用してリモートで SessionBean を呼び出す
ejb-remote
クイックスタートには、この機能を実証する動作中の Maven プロジェクトが含まれています。クイックスタートには、デプロイするセッション Bean とリモートクライアントの両方のプロジェクトが含まれています。以下のコードサンプルは、リモートクライアントプロジェクトから取得したものです。
前提条件
- Maven プロジェクトを作成してすぐに使用できるようにしておく必要があります。
- JBoss EAP 6Maven リポジトリーの設定はすでに追加されています。
- 呼び出すセッション Bean はすでにデプロイされています。
- デプロイされたセッション Bean は、リモートビジネスインターフェイスを実装します。
- セッション Bean のリモートビジネスインターフェイスは、Maven 依存関係として利用できます。リモートビジネスインターフェイスが JAR ファイルとしてのみ利用可能な場合は、JAR をアーティファクトとして Maven リポジトリーに追加することをお勧めします。指示については、install:install-file の 目標について Maven のドキュメントを参照してください。 http://maven.apache.org/plugins/maven-install-plugin/usage.html
- セッション Bean をホストしているサーバーのホスト名と JNDI ポートを知っている必要があります。
手順8.8 セッション Bean のリモート呼び出し用の Maven プロジェクト設定の追加
- 必要なプロジェクトの依存関係を追加しますプロジェクトの
pom.xml
を更新して、必要な依存関係を含める必要があります。 jboss-ejb-client.properties
ファイルを追加しますJBoss EJB クライアント API は、JNDI サービスの接続情報を含むjboss-ejb-client.properties
という名前のプロジェクトのルートでファイルを見つけることを想定しています。このファイルをプロジェクトのsrc/main/resources/
ディレクトリーに次の内容で追加します。# In the following line, set SSL_ENABLED to true for SSL remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false remote.connections=default # Uncomment the following line to set SSL_STARTTLS to true for SSL # remote.connection.default.connect.options.org.xnio.Options.SSL_STARTTLS=true remote.connection.default.host=localhost remote.connection.default.port = 4447 remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false # Add any of the following SASL options if required # remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false # remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false # remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS=JBOSS-LOCAL-USER
サーバーに一致するようにホスト名とポートを変更します。4447
はデフォルトのポート番号です。安全な接続のために、SSL_ENABLED
行をtrue
に設定し、SSL_STARTTLS
行のコメントを解除します。コンテナーの Remoting インターフェイスは、同じポートを使用したセキュリティーで保護された接続とセキュリティーで保護されていない接続をサポートします。- リモートビジネスインターフェイスの依存関係を追加するセッション Bean のリモートビジネスインターフェイスの
pom.xml
に Maven 依存関係を追加します。<dependency> <groupId>org.jboss.as.quickstarts</groupId> <artifactId>jboss-ejb-remote-server-side</artifactId> <type>ejb-client</type> <version>${project.version}</version> </dependency>
手順8.9 JNDI を使用して Bean プロキシーを取得し、Bean のメソッドを呼び出す
- チェックされた例外を処理する次のコードで使用される 2 つのメソッド (
InitialContext()
とlookup()
) タイプのチェックされた例外がありますjavax.naming.NamingException
。これらのメソッド呼び出しは、キャッチする try/catch ブロックで囲む必要がありますNamingException
または出力するように宣言されているメソッドでNamingException
。ejb-remote
クイックスタートは 2 番目の手法を使用します。 - JNDI コンテキストを作成するJNDI コンテキストオブジェクトは、サーバーにリソースを要求するためのメカニズムを提供します。次のコードを使用して JNDI コンテキストを作成します。
final Hashtable jndiProperties = new Hashtable(); jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); final Context context = new InitialContext(jndiProperties);
JNDI サービスの接続プロパティーは、jboss-ejb-client.properties
ファイルから読み取られます。 - JNDI コンテキストの lookup () メソッドを使用して Bean プロキシーを取得しますを呼び出す
lookup()
Bean プロキシーのメソッドを渡し、必要なセッション Bean の JNDI 名を渡します。これにより、呼び出すメソッドを含むリモートビジネスインターフェイスのタイプにキャストする必要があるオブジェクトが返されます。final RemoteCalculator statelessRemoteCalculator = (RemoteCalculator) context.lookup( "ejb:/jboss-ejb-remote-server-side//CalculatorBean!" + RemoteCalculator.class.getName());
セッション Bean の JNDI 名は、特別な構文を使用して定義されます。詳細は、「EJB JNDI 命名リファレンス」 を参照してください。 - invoke メソッドプロキシー Bean オブジェクトができたので、リモートビジネスインターフェイスに含まれている任意のメソッドを呼び出すことができます。
int a = 204; int b = 340; System.out.println("Adding " + a + " and " + b + " via the remote stateless calculator deployed on the server"); int sum = statelessRemoteCalculator.add(a, b); System.out.println("Remote calculator returned sum = " + sum);
プロキシー Bean は、メソッド呼び出し要求をサーバー上のセッション Bean に渡し、そこで実行されます。結果はプロキシー Bean に返され、プロキシー Bean はそれを呼び出し元に返します。プロキシー Bean とリモートセッション Bean の間の通信は、呼び出し元に対して透過的です。
8.5.2. EJB クライアントコンテキスト
- スタンドアロン Java アプリケーションとして実行されるリモートクライアント。
- 別の JBoss EAP 6 インスタンス内で実行されるリモートクライアント。
8.5.3. 単一の EJB コンテキストを使用する場合の考慮事項
概要
スタンドアロンのリモートクライアントで単一の EJB クライアントコンテキストを使用する場合は、アプリケーション要件を考慮する必要があります。さまざまなタイプのリモートクライアントの詳細については、以下を参照してください。「EJB クライアントコンテキスト」。
単一の EJB クライアントコンテキストを持つリモートスタンドアロンクライアントの一般的なプロセス
リモートスタンドアロンクライアントには、通常、任意の数の EJB レシーバーによってサポートされる EJB クライアントコンテキストが 1 つだけあります。次に、スタンドアロンのリモートクライアントアプリケーションの例を示します。
public class MyApplication { public static void main(String args[]) { final javax.naming.Context ctxOne = new javax.naming.InitialContext(); final MyBeanInterface beanOne = ctxOne.lookup("ejb:app/module/distinct/bean!interface"); beanOne.doSomething(); ... } }
jboss-ejb-client.properties
ファイルによってサポートされます。この設定にはセキュリティークレデンシャルも含まれ、JBoss EAP 6 サーバーに接続する EJB レシーバーを作成するために使用されます。上記のコードが呼び出されると、EJB クライアント API は EJB クライアントコンテキストを検索します。このコンテキストは、EJB 呼び出し要求を受信して処理する EJB レシーバーを選択するために使用されます。この場合、EJB クライアントコンテキストは 1 つしかないため、上記のコードでコンテキストを使用して Bean を呼び出します。JNDI を使用してリモートでセッション Bean を呼び出す手順については、以下で詳しく説明します。「JNDI を使用してリモートで SessionBean を呼び出す」。
異なる資格情報を必要とするリモートスタンドアロンクライアント
ユーザーアプリケーションが Bean を複数回呼び出したい場合がありますが、異なるセキュリティークレデンシャルを使用して JBoss EAP 6 サーバーに接続します。以下は、同じ Bean を 2 回呼び出すスタンドアロンのリモートクライアントアプリケーションの例です。
public class MyApplication { public static void main(String args[]) { // Use the "foo" security credential connect to the server and invoke this bean instance final javax.naming.Context ctxOne = new javax.naming.InitialContext(); final MyBeanInterface beanOne = ctxOne.lookup("ejb:app/module/distinct/bean!interface"); beanOne.doSomething(); ... // Use the "bar" security credential to connect to the server and invoke this bean instance final javax.naming.Context ctxTwo = new javax.naming.InitialContext(); final MyBeanInterface beanTwo = ctxTwo.lookup("ejb:app/module/distinct/bean!interface"); beanTwo.doSomething(); ... } }
解決策
スコープ付き EJB クライアントコンテキストは、この問題の解決策を提供します。これらは、EJB クライアントコンテキストとそれに関連する JNDI コンテキスト (通常は EJB 呼び出しに使用される) をより詳細に制御する方法を提供します。スコープ付き EJB クライアントコンテキストの詳細については、以下を参照してください。「スコープ付き EJB クライアントコンテキストの使用」と「スコープ付き EJB クライアントコンテキストを使用して EJB を設定する」。
8.5.4. スコープ付き EJB クライアントコンテキストの使用
概要
EJB を呼び出すには JBoss EAP 6 の以前のバージョンでは、通常、JNDI コンテキストを作成し、ターゲットサーバーを指す PROVIDER_URL を渡します。その JNDI コンテキストを使用してルックアップされた EJB プロキシーで行われた呼び出しはすべて、そのサーバーで終了します。スコープ付き EJB クライアントコンテキストを使用すると、ユーザーアプリケーションは、特定の呼び出しに使用される EJB レシーバーを制御できます。
リモートスタンドアロンクライアントでスコープ付き EJB クライアントコンテキストを使用する
スコープ付き EJB クライアントコンテキストが導入される前は、コンテキストは通常、クライアントアプリケーションにスコープされていました。スコープ付きクライアントコンテキストにより、EJB クライアントコンテキストを JNDI コンテキストでスコープできるようになりました。以下は、スコープ付き EJB クライアントコンテキストを使用して同じ Bean を 2 回呼び出すスタンドアロンのリモートクライアントアプリケーションの例です。
public class MyApplication { public static void main(String args[]) { // Use the "foo" security credential connect to the server and invoke this bean instance final Properties ejbClientContextPropsOne = getPropsForEJBClientContextOne(): final javax.naming.Context ctxOne = new javax.naming.InitialContext(ejbClientContextPropsOne); final MyBeanInterface beanOne = ctxOne.lookup("ejb:app/module/distinct/bean!interface"); beanOne.doSomething(); ... ctxOne.close(); // Use the "bar" security credential to connect to the server and invoke this bean instance final Properties ejbClientContextPropsTwo = getPropsForEJBClientContextTwo(): final javax.naming.Context ctxTwo = new javax.naming.InitialContext(ejbClientContextPropsTwo); final MyBeanInterface beanTwo = ctxTwo.lookup("ejb:app/module/distinct/bean!interface"); beanTwo.doSomething(); ... ctxTwo.close(); } }
jboss-ejb-client.properties
ファイルで使用されているものと同じプロパティーのセットです。EJB クライアントコンテキストを JNDI コンテキストにスコープするには、org.jboss.ejb.client.scoped.context
プロパティーを指定し、その値を true
に設定する必要もあります。このプロパティーは、EJB クライアント API に、EJB レシーバーによってサポートされる EJB クライアントコンテキストを作成する必要があること、および作成されたコンテキストが、それを作成した JNDI コンテキストに対してのみスコープまたは表示されることを通知します。この JNDI コンテキストを使用してルックアップまたは呼び出された EJB プロキシーは、この JNDI コンテキストに関連付けられた EJB クライアントコンテキストのみを認識します。アプリケーションが EJB をルックアップして呼び出すために使用する他の JNDI コンテキストは、他のスコープ付き EJB クライアントコンテキストを認識しません。
org.jboss.ejb.client.scoped.context
プロパティーを渡さず、EJB クライアントコンテキストにスコープされていない JNDI コンテキストは、デフォルトの動作を使用します。これは、通常、アプリケーション全体。
InitialContext
不要になったとき。いつInitialContext
が閉じられると、リソースはすぐに解放されます。それにバインドされているプロキシーは無効になり、呼び出しは例外を出力します。を閉じられなかったInitialContext
リソースとパフォーマンスの問題が発生する可能性があります。
8.5.5. スコープ付き EJB クライアントコンテキストを使用して EJB を設定する
概要
EJB は、マップベースのスコープコンテキストを使用して設定できます。これは、jboss-ejb-client.properties
にある標準プロパティーを使用して プロパティー
マップにプログラムで入力し、org.jboss.ejb.client.scoped.context
プロパティーに true
を指定し、InitialContext
作成時にプロパティーを渡すことで実現されます。
手順8.10 マップベースのスコープコンテキストを使用して EJB を設定する
プロパティーを設定します。
標準のjboss-ejb-client.properties
ファイルで使用されているのと同じプロパティーのセットを指定して、EJB クライアントのプロパティーをプログラムで設定します。スコープコンテキストを有効にするには、org.jboss.ejb.client.scoped.context
プロパティーを指定し、その値をtrue
に設定する必要があります。以下は、プログラムでプロパティーを設定する例です。// Configure EJB Client properties for the InitialContext Properties ejbClientContextProps = new Properties(); ejbClientContextProps.put(“remote.connections”,”name1”); ejbClientContextProps.put(“remote.connection.name1.host”,”localhost”); ejbClientContextProps.put(“remote.connection.name1.port”,”4447”); // Property to enable scoped EJB client context which will be tied to the JNDI context ejbClientContextProps.put("org.jboss.ejb.client.scoped.context", “true”);
コンテキスト作成でプロパティーを渡す
// Create the context using the configured properties InitialContext ic = new InitialContext(ejbClientContextProps); MySLSB bean = ic.lookup("ejb:myapp/ejb//MySLSBBean!" + MySLSB.class.getName());
追加情報
- ルックアップ EJB プロキシーによって生成されたコンテキストは、このスコープコンテキストによってバインドされ、関連する接続パラメーターのみを使用します。これにより、さまざまなコンテキストを作成して、クライアントアプリケーション内のデータにアクセスしたり、さまざまなログインを使用してサーバーに個別にアクセスしたりすることができます。
- クライアントでは、スコープ付き
InitialContext
とスコープ付きプロキシーの両方がスレッドに渡され、各スレッドが指定されたコンテキストで動作できるようになります。プロキシーを同時に使用できる複数のスレッドにプロキシーを渡すこともできます。 - スコープコンテキスト EJB プロキシーは、リモートコールでシリアル化されてから、サーバーで逆シリアル化されます。デシリアライズされると、スコープされたコンテキスト情報が削除され、デフォルトの状態に戻ります。デシリアライズされたプロキシーがリモートサーバーで使用されている場合、作成時に使用されていたスコープコンテキストがなくなったため、
EJBCLIENT000025
エラーが発生したり、EJB 名を使用して不要なターゲットを呼び出したりする可能性があります。
8.5.6. EJB クライアントのプロパティー
概要
次の表に、プログラムまたは jboss-ejb-client.properties
ファイルで設定できるプロパティーを示します。
EJB クライアントのグローバルプロパティー
次の表に、同じスコープ内のライブラリー全体に有効なプロパティーを示します。
表8.1 グローバルプロパティー
プロパティー名 | Description |
---|---|
endpoint.name |
クライアントエンドポイントの名前。設定されていない場合、デフォルト値は
client-endpoint です。
スレッド名にはこのプロパティーが含まれているため、これはさまざまなエンドポイント設定を区別するのに役立ちます。
|
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED |
すべての接続で SSL プロトコルを有効にするかどうかを指定するブール値。
警告
Red Hat は、影響するすべてのパッケージで TLSv1.1 または TLSv1.2 を利用するために SSL を明示的に無効化することを推奨しています。
|
deployment.node.selector | org.jboss.ejb.client.DeploymentNodeSelector の実装の完全修飾名。
これは、EJB の呼び出しの負荷を分散するために使用されます。
|
invocation.timeout |
EJB ハンドシェイクまたはメソッド呼び出しの要求/応答サイクルのタイムアウト。値はミリ秒単位です。
実行にタイムアウト期間より長い時間がかかる場合、メソッドを呼び出すと
java.util.concurrent.TimeoutException が出力されます。実行が完了し、サーバーは中断されません。
|
reconnect.tasks.timeout |
バックグラウンド再接続タスクのタイムアウト。値はミリ秒単位です。
多数の接続がダウンしている場合、次のクライアント EJB 呼び出しはアルゴリズムを使用して、適切なノードを見つけるために再接続が必要かどうかを判断します。
|
org.jboss.ejb.client.scoped.context |
スコープ付き EJB クライアントコンテキストを有効にするかどうかを指定するブール値。デフォルト値は
false です。
true に設定すると、EJB クライアントは JNDI コンテキストに関連付けられたスコープコンテキストを使用します。それ以外の場合、EJB クライアントコンテキストは JVM のグローバルセレクターを使用して、リモート EJB とホストの呼び出しに使用されるプロパティーを決定します。
|
EJB クライアント接続のプロパティー
接続プロパティーは、接頭辞 remote.connection で始まります。CONNECTION_NAME
ここで、CONNECTION_NAME は、接続を一意に識別するためにのみ使用されるローカル識別子です。
表8.2 Connection Properties
プロパティー名 | Description |
---|---|
remote.connections |
アクティブな
接続名 のコンマ区切りのリスト。各接続は、この名前を使用して設定されます。
|
|
接続のホスト名または IP。
|
|
接続用のポート。デフォルト値は 4447 です。
|
|
接続セキュリティーの認証に使用されるユーザー名。
|
|
ユーザーの認証に使用されるパスワード。
|
|
初期接続のタイムアウト期間。その後、再接続タスクは、接続を確立できるかどうかを定期的にチェックします。値はミリ秒単位です。
|
| CallbackHandler クラスの完全修飾名。接続を確立するために使用され、接続が開いている限り変更できません。
|
|
アウトバウンド要求の最大数を指定する整数値。デフォルトでは 80 回です。
すべての呼び出しを処理するために、クライアント (JVM) からサーバーへの接続は 1 つだけです。
|
|
正常に接続するためにクライアントが資格情報を提供する必要があるかどうかを決定するブール値。デフォルト値は
true です。
true に設定されている場合、クライアントは資格情報を提供する必要があります。false に設定すると、リモートコネクターがセキュリティーレルムを要求しない限り、呼び出しが許可されます。
|
|
接続の作成中に認証に使用される特定の SASL メカニズムを無効にします。
JBOSS-LOCAL-USER は、クライアントとサーバーが同じマシン上にある場合に使用されるサイレント認証メカニズムが無効になっていることを意味します。
|
|
認証中のプレーンテキストメッセージの使用を有効または無効にするブール値。JAAS を使用する場合、プレーンテキストのパスワードを許可するには、false に設定する必要があります。
|
|
この接続で SSL プロトコルを有効にするかどうかを指定するブール値。
警告
Red Hat は、影響するすべてのパッケージで TLSv1.1 または TLSv1.2 を利用するために SSL を明示的に無効化することを推奨しています。
|
|
ファイアウォールの場合など、自動クローズを防ぐためにクライアントとサーバー間でハートビートを送信する間隔。値はミリ秒単位です。
|
EJB クライアントクラスターのプロパティー
最初の接続がクラスター化された環境に接続する場合、クラスターのトポロジーは自動的かつ非同期に受信されます。これらのプロパティーは、受信した各メンバーに接続するために使用されます。各プロパティーは、接頭辞 remote.cluster で始まります。CLUSTER_NAME
ここで、CLUSTER_NAME は、サーバーの Infinispan サブシステム設定に関連するものを指します。
表8.3 クラスターのプロパティー
プロパティー名 | Description |
---|---|
| org.jboss.ejb.client.ClusterNodeSelector の実装の完全修飾名。
org.jboss.ejb.client.DeploymentNodeSelector ではなく、このクラスは、クラスター化された環境で EJB 呼び出しの負荷を分散するために使用されます。クラスターが完全にダウンしている場合、呼び出しは失敗し、使用可能な ejb レシーバーがありません 。
|
|
クラスター全体に対して実行できるアウトバウンド要求の最大数を指定する整数値。
|
|
この特定のクラスターノードに対して実行できるアウトバウンド要求の最大数を指定する整数値。
|
8.5.7. リモート EJB データ圧縮
org.jboss.ejb.client.annotation.CompressionHint
。ヒントの値では、リクエスト、応答、要求、応答を圧縮するかどうかを指定します。@CompressionHint
デフォルトをcompressResponse=true
と compressRequest=true
に追加。
import org.jboss.ejb.client.annotation.CompressionHint; @CompressionHint(compressResponse = false) public interface ClassLevelRequestCompressionRemoteView { String echo(String msg); }
import org.jboss.ejb.client.annotation.CompressionHint; public interface CompressableDataRemoteView { @CompressionHint(compressResponse = false, compressionLevel = Deflater.BEST_COMPRESSION) String echoWithRequestCompress(String msg); @CompressionHint(compressRequest = false) String echoWithResponseCompress(String msg); @CompressionHint String echoWithRequestAndResponseCompress(String msg); String echoWithNoCompress(String msg); }
compressionLevel
設定は、以下の値にすることができます。
- BEST_COMPRESSION
- BEST_SPEED
- DEFAULT_COMPRESSION
- NO_COMPRESSION
CompressionLevel
のデフォルト設定は Deflater.DEFAULT_COMPRESSION
です。
@CompressionHint public interface MethodOverrideDataCompressionRemoteView { @CompressionHint(compressRequest = false) String echoWithResponseCompress(final String msg); @CompressionHint(compressResponse = false) String echoWithRequestCompress(final String msg); String echoWithNoExplicitDataCompressionHintOnMethod(String msg); }
org.jboss.ejb.client.view.annotation.scan.enabled
システムプロパティーが true
に設定されていることを確認します。このプロパティーは JBoss EJB Client に対してアノテーションをスキャンするように指示します。
8.6. コンテナーインターセプター
8.6.1. コンテナーインターセプターについて
ejb-jar.xml
ファイルで許可されているものと同じ XSD 要素を使用します。
インターセプターチェーン内のコンテナーインターセプターの配置
EJB 用に設定されたコンテナーインターセプターは、JBoss EAP が提供するセキュリティーインターセプター、トランザクション管理インターセプター、およびその他のサーバーが提供するインターセプターの前に実行されることが保証されています。これにより、特定のアプリケーションコンテナーインターセプターは、呼び出しが進む前に、関連するコンテキストデータを処理または設定できます。
コンテナーインターセプターと Java EE インターセプター API の違い
コンテナーインターセプターは Java EE インターセプターと同様にモデル化されますが、API のセマンティクスにはいくつかの違いがあります。たとえば、コンテナーインターセプターがjavax.interceptor.InvocationContext.getTarget()
これらのインターセプターは、EJB コンポーネントがセットアップまたはインスタンス化されるずっと前に呼び出されるためです。
8.6.2. コンテナーインターセプタークラスを作成する
概要
コンテナーインターセプタクラスは、単純な Plain Old Java Object (POJO) です。彼らは使用します@javax.annotation.AroundInvoke
Bean での呼び出し中に呼び出されるメソッドをマークします。
iAmAround
呼び出しの方法:
例8.2 コンテナーインターセプタークラスの例
public class ClassLevelContainerInterceptor { @AroundInvoke private Object iAmAround(final InvocationContext invocationContext) throws Exception { return this.getClass().getName() + " " + invocationContext.proceed(); } }
jboss-ejb3.xml
ファイルを参照してください。「コンテナーインターセプターの設定」。
8.6.3. コンテナーインターセプターの設定
概要
コンテナーインターセプタは、標準の Java EE インターセプタライブラリーを使用します。つまり、3.1 バージョンの ejb-jar デプロイメント記述子の ejb-jar.xml
ファイルで許可されているものと同じ XSD 要素を使用します。それらは標準の Java EE インターセプターライブラリーをベースとしているため、コンテナーインターセプターはデプロイメント記述子を使用してのみ設定できます。これは設計によって行われたため、アプリケーションは JBoss 固有のアノテーションやその他のライブラリー依存関係を必要としません。コンテナーインターセプターの詳細については、以下を参照してください。「コンテナーインターセプターについて」。
手順8.11 記述子ファイルを作成して、コンテナーインターセプターを設定します
- EJB デプロイメントの
META-INF
ディレクトリーにjboss-ejb3.xml
ファイルを作成します。 - 記述子ファイルにコンテナーインターセプター要素を設定します。
urn:container-interceptors:1.0
ネームスペースを使用して、コンテナーインターセプター要素の設定を指定します。<container-interceptors>
要素を使用してコンテナーインターセプターを指定します。>interceptor-binding>
要素を使用してコンテナーインターセプターを EJB にバインドします。インターセプターは、次のいずれかの方法でバインドできます。- ワイルドカード
*
を使用して、インターセプターをデプロイメントのすべての EJB にバインドします。 - 特定の EJB 名を使用して、個々の Bean レベルでインターセプターをバインドします。
- EJB の特定のメソッドレベルでインターセプターをバインドします。
注記これらの要素は、JavaEE インターセプターの場合と同じ方法で EJB3.1XSD を使用して設定されます。
- 上記の要素の例については、次の記述子ファイルを確認してください。
例8.3 jboss-ejb3.xml
<jboss xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:jee="http://java.sun.com/xml/ns/javaee" xmlns:ci ="urn:container-interceptors:1.0"> <jee:assembly-descriptor> <ci:container-interceptors> <!-- Default interceptor --> <jee:interceptor-binding> <ejb-name>*</ejb-name> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ContainerInterceptorOne</interceptor-class> </jee:interceptor-binding> <!-- Class level container-interceptor --> <jee:interceptor-binding> <ejb-name>AnotherFlowTrackingBean</ejb-name> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ClassLevelContainerInterceptor</interceptor-class> </jee:interceptor-binding> <!-- Method specific container-interceptor --> <jee:interceptor-binding> <ejb-name>AnotherFlowTrackingBean</ejb-name> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.MethodSpecificContainerInterceptor</interceptor-class> <method> <method-name>echoWithMethodSpecificContainerInterceptor</method-name> </method> </jee:interceptor-binding> <!-- container interceptors in a specific order --> <jee:interceptor-binding> <ejb-name>AnotherFlowTrackingBean</ejb-name> <interceptor-order> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ClassLevelContainerInterceptor</interceptor-class> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.MethodSpecificContainerInterceptor</interceptor-class> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ContainerInterceptorOne</interceptor-class> </interceptor-order> <method> <method-name>echoInSpecificOrderOfContainerInterceptors</method-name> </method> </jee:interceptor-binding> </ci:container-interceptors> </jee:assembly-descriptor> </jboss>
urn:container-interceptors:1.0
名前空間の XSD は、EAP_HOME/docs/schema/jboss-ejb
-container-interceptors_1_0.xsd で入手できます。
8.6.4. セキュリティーコンテキスト ID を変更する
概要
デフォルトでは、アプリケーションサーバーにデプロイされた EJB にリモート呼び出しを行うと、サーバーへの接続が認証され、この接続を介して受信した要求はすべて、接続を認証した ID として実行されます。これは、クライアントとサーバー間の呼び出しの両方に適用されます。同じクライアントから異なるアイデンティティーを使用する必要がある場合は、通常は、異なるアイデンティティーとして認証されるように、サーバーへの接続を複数開く必要があります。複数のクライアント接続を開くのではなく、認証されたユーザーに別のユーザーとしてリクエストを実行する権限を与えることができます。
ejb-security-interceptors
クイックスタートを参照してください。
手順8.12 セキュリティーコンテキストの ID を変更する
クライアント側インターセプターを作成する
クライアント側インターセプターは、org.jboss.ejb.client.EJBClientInterceptor
インターフェイスを実装する必要があります。インターセプターは、要求された ID をコンテキストデータマップを介して渡す必要があります。コンテキストデータマップは、EJBClientInvocationContext.getContextData()
。以下は、クライアント側のインターセプターコードの例です。public class ClientSecurityInterceptor implements EJBClientInterceptor { public void handleInvocation(EJBClientInvocationContext context) throws Exception { Principal currentPrincipal = SecurityActions.securityContextGetPrincipal(); if (currentPrincipal != null) { Map<String, Object> contextData = context.getContextData(); contextData.put(ServerSecurityInterceptor.DELEGATED_USER_KEY, currentPrincipal.getName()); } context.sendRequest(); } public Object handleInvocationResult(EJBClientInvocationContext context) throws Exception { return context.getResult(); } }
ユーザーアプリケーションは、次のいずれかの方法で、EJBClientContext
のインターセプターチェーンにインターセプターを挿入できます。プログラムで
このアプローチでは、org.jboss.ejb.client.EJBClientContext.registerInterceptor(int order, EJBClientInterceptor interceptor)
メソッドとパスorder
そしてそのinterceptor
実例。Theorder
このクライアントインターセプターがインターセプターチェーンのどこに配置されるかを決定します。ServiceLoader メカニズム
このアプローチでは、META-INF/services/org.jboss.ejb.client.EJBClientInterceptor
ファイルを作成し、クライアントアプリケーションのクラスパスに配置またはパッケージ化します。ファイルのルールは、Java ServiceLoader Mechanism によって指示されます。このファイルには、EJB クライアントインターセプター実装の完全修飾クラス名ごとに個別の行が含まれることが予想されます。EJB クライアントインターセプタークラスはクラスパスで利用できる必要があります。ServiceLoader
メカニズムを使用して追加された EJB クライアントインターセプターは、クラスパスで検出された順序で、クライアントインターセプターチェーンの最後に追加されます。ejb-security-interceptors
クイックスタートはこのアプローチを使用します。
サーバー側コンテナーインターセプターを作成して設定する
コンテナーインターセプタクラスは、単純な Plain Old Java Object (POJO) です。彼らは使用します@javax.annotation.AroundInvoke
Bean での呼び出し中に呼び出されるメソッドをマークします。コンテナーインターセプターの詳細については、以下を参照してください。「コンテナーインターセプターについて」。コンテナーインターセプターを作成する
このインターセプターは、ID を含むInvocationContext
を受信し、その新しい ID への切り替えを要求します。以下は、実際のコード例の要約版です。public class ServerSecurityInterceptor { private static final Logger logger = Logger.getLogger(ServerSecurityInterceptor.class); static final String DELEGATED_USER_KEY = ServerSecurityInterceptor.class.getName() + ".DelegationUser"; @AroundInvoke public Object aroundInvoke(final InvocationContext invocationContext) throws Exception { Principal desiredUser = null; UserPrincipal connectionUser = null; Map<String, Object> contextData = invocationContext.getContextData(); if (contextData.containsKey(DELEGATED_USER_KEY)) { desiredUser = new SimplePrincipal((String) contextData.get(DELEGATED_USER_KEY)); Collection<Principal> connectionPrincipals = SecurityActions.getConnectionPrincipals(); if (connectionPrincipals != null) { for (Principal current : connectionPrincipals) { if (current instanceof UserPrincipal) { connectionUser = (UserPrincipal) current; break; } } } else { throw new IllegalStateException("Delegation user requested but no user on connection found."); } } ContextStateCache stateCache = null; try { if (desiredUser != null && connectionUser != null && (desiredUser.getName().equals(connectionUser.getName()) == false)) { // The final part of this check is to verify that the change does actually indicate a change in user. try { // We have been requested to use an authentication token // so now we attempt the switch. stateCache = SecurityActions.pushIdentity(desiredUser, new OuterUserCredential(connectionUser)); } catch (Exception e) { logger.error("Failed to switch security context for user", e); // Don't propagate the exception stacktrace back to the client for security reasons throw new EJBAccessException("Unable to attempt switching of user."); } } return invocationContext.proceed(); } finally { // switch back to original context if (stateCache != null) { SecurityActions.popIdentity(stateCache);; } } }
コンテナーインターセプターを設定する
サーバー側のコンテナーインターセプターを設定する方法については、以下を参照してください。「コンテナーインターセプターの設定」。
JAASLoginModule を作成します
このコンポーネントは、ユーザーが要求された ID として要求を実行できることを確認するロールを果たします。次の簡略化されたコード例は、ログインと検証を実行するメソッドを示しています。@SuppressWarnings("unchecked") @Override public boolean login() throws LoginException { if (super.login() == true) { log.debug("super.login()==true"); return true; } // Time to see if this is a delegation request. NameCallback ncb = new NameCallback("Username:"); ObjectCallback ocb = new ObjectCallback("Password:"); try { callbackHandler.handle(new Callback[] { ncb, ocb }); } catch (Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } return false; // If the CallbackHandler can not handle the required callbacks then no chance. } String name = ncb.getName(); Object credential = ocb.getCredential(); if (credential instanceof OuterUserCredential) { // This credential type will only be seen for a delegation request, if not seen then the request is not for us. if (delegationAcceptable(name, (OuterUserCredential) credential)) { identity = new SimplePrincipal(name); if (getUseFirstPass()) { String userName = identity.getName(); if (log.isDebugEnabled()) log.debug("Storing username '" + userName + "' and empty password"); // Add the username and an empty password to the shared state map sharedState.put("javax.security.auth.login.name", identity); sharedState.put("javax.security.auth.login.password", ""); } loginOk = true; return true; } } return false; // Attempted login but not successful. } protected boolean delegationAcceptable(String requestedUser, OuterUserCredential connectionUser) { if (delegationMappings == null) { return false; } String[] allowedMappings = loadPropertyValue(connectionUser.getName(), connectionUser.getRealm()); if (allowedMappings.length == 1 && "*".equals(allowedMappings[1])) { // A wild card mapping was found. return true; } for (String current : allowedMappings) { if (requestedUser.equals(current)) { return true; } } return false; }
ejb-security-interceptors
クイックスタート README.html
ファイルを参照してください。
8.6.5. アプリケーションでクライアント側インターセプターを使用する
プログラムでインターセプターをアプリケーションに接続します
このアプローチでは、org.jboss.ejb.client.EJBClientContext.registerInterceptor(int order, EJBClientInterceptor interceptor)
API とパスorder
そしてそのinterceptor
実例。Theorder
クライアントインターセプターチェーンのどこに正確にこれを決定するために使用されますinterceptor
配置されます。
ServiceLoader メカニズムを介してインターセプターをアプリケーションに接続します
このアプローチでは、META-INF/services/org.jboss.ejb.client.EJBClientInterceptor
ファイルを作成し、クライアントアプリケーションのクラスパスに配置またはパッケージ化します。ファイルのルールは、Java ServiceLoader Mechanism によって指示されます。このファイルには、EJB クライアントインターセプター実装の完全修飾クラス名ごとに個別の行が含まれることが予想されます。EJB クライアントインターセプタークラスはクラスパスで利用できる必要があります。ServiceLoader
メカニズムを使用して追加された EJB クライアントインターセプターは、クラスパスで検出された順序で、クライアントインターセプターチェーンの最後に追加されます。ejb-security-interceptors
クイックスタートはこのアプローチを使用します。
8.7. Clustered Enterprise JavaBeans
8.7.1. Clustered Enterprise JavaBeans (EJB) について
8.7.2. スタンドアロンおよびサーバー内クライアントの設定
jboss-ejb-client.properties
、またはサーバー側のアプリケーションの jboss-ejb-client.xml
ファイルを拡張してクラスター設定を組み込む必要があります。
サーバー
内にあります。つまり、別の EAP インスタンスを呼び出す EAP インスタンスは、サーバー内クライアントと見なされます。
例8.4 jboss-ejb-client.properties
設定のスタンドアロンクライアント
remote.clusters=ejb remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED=false remote.cluster.ejb.username=test remote.cluster.ejb.password=password
jboss-ejb-client.xml
ファイルを設定し、クラスター設定を追加する必要があります。
例8.5 別の EAP6 インスタンスにデプロイされているクライアントアプリケーション (jboss-ejb-client.xml ファイルの設定)
<jboss-ejb-client xmlns:xsi="urn:jboss:ejb-client:1.2" xsi:noNamespaceSchemaLocation="jboss-ejb-client_1_2.xsd"> <client-context> <ejb-receivers> <!-- this is the connection to access the app-one --> <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-1" /> <!-- this is the connection to access the app-two --> <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-2" /> </ejb-receivers> <!-- if an outbound connection connects to a cluster; a list of members is provided after successful connection. To connect to this node this cluster element must be defined. --> <clusters> <!-- cluster of remote-ejb-connection-1 --> <cluster name="ejb" security-realm="ejb-security-realm-1" username="quickuser1"> <connection-creation-options> <property name="org.xnio.Options.SSL_ENABLED" value="false" /> <property name="org.xnio.Options.SASL_POLICY_NOANONYMOUS" value="false" /> </connection-creation-options> </cluster> </clusters> </client-context> </jboss-ejb-client>
8.7.3. EJB 呼び出しのカスタムロードバランシングポリシーの実装
AllClusterNodeSelector
を実装することができます。AllClusterNodeSelector
のノード選択の動作はデフォルトのセレクターと似ていますが、大規模なクラスター (ノード数 >20) の場合でも AllClusterNodeSelector
は利用可能なすべてのクラスターノードを使用する点が異なります。接続されていないクラスターノードが返されると、そのクラスターノードは自動的に開きます。以下の例は、AllClusterNodeSelector
実装を示しています。
package org.jboss.as.quickstarts.ejb.clients.selector; import java.util.Arrays; import java.util.Random; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.ejb.client.ClusterNodeSelector; public class AllClusterNodeSelector implements ClusterNodeSelector { private static final Logger LOGGER = Logger.getLogger(AllClusterNodeSelector.class.getName()); @Override public String selectNode(final String clusterName, final String[] connectedNodes, final String[] availableNodes) { if(LOGGER.isLoggable(Level.FINER)) { LOGGER.finer("INSTANCE "+this+ " : cluster:"+clusterName+" connected:"+Arrays.deepToString(connectedNodes)+" available:"+Arrays.deepToString(availableNodes)); } if (availableNodes.length == 1) { return availableNodes[0]; } final Random random = new Random(); final int randomSelection = random.nextInt(availableNodes.length); return availableNodes[randomSelection]; } }EJB 呼び出しの
SimpleLoadFactorNodeSelector
を実装することもできます。SimpleLoadFactorNodeSelector
での負荷分散は、負荷係数に基づいて実行されます。負荷係数 (2/3/4) は、各ノードの負荷に関係なく、ノードの名前 (A/B/C) を基に計算されます。以下の例は、SimpleLoadFactorNodeSelector
実装を示しています。
package org.jboss.as.quickstarts.ejb.clients.selector; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.ejb.client.DeploymentNodeSelector; public class SimpleLoadFactorNodeSelector implements DeploymentNodeSelector { private static final Logger LOGGER = Logger.getLogger(SimpleLoadFactorNodeSelector.class.getName()); private final Map<String, List<String>[]> nodes = new HashMap<String, List<String>[]>(); private final Map<String, Integer> cursor = new HashMap<String, Integer>(); private ArrayList<String> calculateNodes(Collection<String> eligibleNodes) { ArrayList<String> nodeList = new ArrayList<String>(); for (String string : eligibleNodes) { if(string.contains("A") || string.contains("2")) { nodeList.add(string); nodeList.add(string); } else if(string.contains("B") || string.contains("3")) { nodeList.add(string); nodeList.add(string); nodeList.add(string); } else if(string.contains("C") || string.contains("4")) { nodeList.add(string); nodeList.add(string); nodeList.add(string); nodeList.add(string); } } return nodeList; } @SuppressWarnings("unchecked") private void checkNodeNames(String[] eligibleNodes, String key) { if(!nodes.containsKey(key) || nodes.get(key)[0].size() != eligibleNodes.length || !nodes.get(key)[0].containsAll(Arrays.asList(eligibleNodes))) { // must be synchronized as the client might call it concurrent synchronized (nodes) { if(!nodes.containsKey(key) || nodes.get(key)[0].size() != eligibleNodes.length || !nodes.get(key)[0].containsAll(Arrays.asList(eligibleNodes))) { ArrayList<String> nodeList = new ArrayList<String>(); nodeList.addAll(Arrays.asList(eligibleNodes)); nodes.put(key, new List[] { nodeList, calculateNodes(nodeList) }); } } } } private synchronized String nextNode(String key) { Integer c = cursor.get(key); List<String> nodeList = nodes.get(key)[1]; if(c == null || c >= nodeList.size()) { c = Integer.valueOf(0); } String node = nodeList.get(c); cursor.put(key, Integer.valueOf(c + 1)); return node; } @Override public String selectNode(String[] eligibleNodes, String appName, String moduleName, String distinctName) { if (LOGGER.isLoggable(Level.FINER)) { LOGGER.finer("INSTANCE " + this + " : nodes:" + Arrays.deepToString(eligibleNodes) + " appName:" + appName + " moduleName:" + moduleName + " distinctName:" + distinctName); } // if there is only one there is no sense to choice if (eligibleNodes.length == 1) { return eligibleNodes[0]; } final String key = appName + "|" + moduleName + "|" + distinctName; checkNodeNames(eligibleNodes, key); return nextNode(key); } }
jboss-ejb-client.properties
を使用した設定
remote.cluster.ejb.clusternode.selector
プロパティーを実装クラスの名前 (AllClusterNodeSelector
または SimpleLoadfactorNodeSelector
) とともに追加する必要があります。セレクターは、呼び出し時に利用可能な設定済みのサーバーをすべて表示します。次の例では、デプロイメントノードセレクターとして AllClusterNodeSelector
を使用しています。
remote.clusters=ejb remote.cluster.ejb.clusternode.selector=org.jboss.as.quickstarts.ejb.clients.selector.AllClusterNodeSelector remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED=false remote.cluster.ejb.username=test remote.cluster.ejb.password=password remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false remote.connections=one,two remote.connection.one.host=localhost remote.connection.one.port = 4447 remote.connection.one.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false remote.connection.one.username=user remote.connection.one.password=user123 remote.connection.two.host=localhost remote.connection.two.port = 4547 remote.connection.two.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
JBossejb-clientAPI の使用
プロパティー remote.cluster.ejb.clusternode.selector
を PropertiesBasedEJBClientConfiguration
コンストラクターの一覧に追加する必要があります。次の例では、デプロイメントノードセレクターとして AllClusterNodeSelector
を使用しています。
Properties p = new Properties(); p.put("remote.clusters", "ejb"); p.put("remote.cluster.ejb.clusternode.selector", "org.jboss.as.quickstarts.ejb.clients.selector.AllClusterNodeSelector"); p.put("remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false"); p.put("remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED", "false"); p.put("remote.cluster.ejb.username", "test"); p.put("remote.cluster.ejb.password", "password"); p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false"); p.put("remote.connections", "one,two"); p.put("remote.connection.one.port", "4447"); p.put("remote.connection.one.host", "localhost"); p.put("remote.connection.two.port", "4547"); p.put("remote.connection.two.host", "localhost"); EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(p); ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc); EJBClientContext.setSelector(selector); p = new Properties(); p.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); InitialContext context = new InitialContext(p);
jboss-ejb-client.xml
を使用したサーバーアプリケーション側の設定
サーバー間の通信に負荷分散ポリシーを使用するには、クラスをアプリケーションとともにパッケージ化し、(META-INF
フォルダーにある) jboss-ejb-client.xml
で設定します。次の例では、デプロイメントノードセレクターとして AllClusterNodeSelector
を使用しています。
<jboss-ejb-client xmlns:xsi="urn:jboss:ejb-client:1.2" xsi:noNamespaceSchemaLocation="jboss-ejb-client_1_2.xsd"> <client-context deployment-node-selector="org.jboss.ejb.client.DeploymentNodeSelector"> <ejb-receivers> <!-- this is the connection to access the app --> <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-1" /> </ejb-receivers> <!-- if an outbound connection connect to a cluster a list of members is provided after successful connection. To connect to this node this cluster element must be defined. --> <clusters> <!-- cluster of remote-ejb-connection-1 --> <cluster name="ejb" security-realm="ejb-security-realm-1" username="test" cluster-node-selector="org.jboss.as.quickstarts.ejb.clients.selector.AllClusterNodeSelector"> <connection-creation-options> <property name="org.xnio.Options.SSL_ENABLED" value="false" /> <property name="org.xnio.Options.SASL_POLICY_NOANONYMOUS" value="false" /> </connection-creation-options> </cluster> </clusters> </client-context> </jboss-ejb-client>上記のセキュリティー設定を使用するには、client-server 設定に
ejb-security-realm-1
を追加する必要があります。以下の例は、セキュリティーレルムを追加する CLI コマンド (ejb-security-realm-1
) を示しています。値は、ユーザー "test" の base64 でエンコードされたパスワードです。
core-service=management/security-realm=ejb-security-realm-1:add() core-service=management/security-realm=ejb-security-realm-1/server-identity=secret:add(value=cXVpY2sxMjMr)
standalone.xml
を使用して、サーバー名 (server name = "") を設定します。サーバー名が一意であることを確認します。ドメインモードでは、コントローラーは名前が一意であることを自動的に検証します。
8.7.4. EJB 呼び出しのトランザクション動作
サーバー間の呼び出し
分散 JBoss EAP アプリケーションのトランザクション属性は、アプリケーションが同じサーバー上で呼び出されているかのように処理する必要があります。トランザクションを中止するには、別のインターフェイスを使用して宛先メソッドに REQUIRES_NEW
のマークを付ける必要があります。
クライアント側の呼び出し
JBoss EAP 6 スタンドアロンクライアントで EJB セッション Bean を呼び出すには、EJB プロキシーまたは UserTransaction
が使用されている間、クライアントは InitialContext
オブジェクトへの参照を持っている必要があります。また、EJB プロキシーまたは UserTransaction
が使用されている間、InitialContext
オブジェクトを開いたままにしておくことも重要です。接続の制御は、InitialContext
によってプロパティーを使用して作成されたクラス内で行われます。
InitialContext
オブジェクトへの参照を保持する EJB クライアント API を示しています。
例8.6 InitialContext
オブジェクトを参照する EJB クライアント API
package org.jboss.as.quickstarts.ejb.multi.server; import java.util.Date; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import javax.naming.Context; import javax.naming.InitialContext; import org.jboss.as.quickstarts.ejb.multi.server.app.MainApp; import org.jboss.ejb.client.ContextSelector; import org.jboss.ejb.client.EJBClientConfiguration; import org.jboss.ejb.client.EJBClientContext; import org.jboss.ejb.client.PropertiesBasedEJBClientConfiguration; import org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector; public class Client { /** * @param args no args needed * @throws Exception */ public static void main(String[] args) throws Exception { // suppress output of client messages Logger.getLogger("org.jboss").setLevel(Level.OFF); Logger.getLogger("org.xnio").setLevel(Level.OFF); Properties p = new Properties(); p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false"); p.put("remote.connections", "one"); p.put("remote.connection.one.port", "4447"); p.put("remote.connection.one.host", "localhost"); p.put("remote.connection.one.username", "quickuser"); p.put("remote.connection.one.password", "quick-123"); EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(p); ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc); EJBClientContext.setSelector(selector); Properties props = new Properties(); props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); InitialContext context = new InitialContext(props); final String rcal = "ejb:jboss-ejb-multi-server-app-main/ejb//" + ("MainAppBean") + "!" + MainApp.class.getName(); final MainApp remote = (MainApp) context.lookup(rcal); final String result = remote.invokeAll("Client call at "+new Date()); System.out.println("InvokeAll succeed: "+result); } }
UserTransaction
参照の取得は、スコープ付き EJB クライアントコンテキストを使用するシナリオ、および リモートネーミング
プロトコルを使用する呼び出しではサポートされていません。これは、これらのシナリオでは、InitialContext
が独自の EJB クライアントコンテキストインスタンスをカプセル化するためです。これは、EJBClient
クラスの静的メソッドを使用してアクセスすることはできません。いつEJBClient.getUserTransaction()
が呼び出されると、デフォルトの (グローバル)EJB クライアントコンテキスト (初期化されていない可能性があります) からではなく、目的のコンテキストからトランザクションを返します。
クライアント側の UserTransaction リファレンス
次の例は、スタンドアロンクライアントで UserTransaction
参照を取得する方法を示しています。
例8.7 UserTransaction
オブジェクトを参照するスタンドアロンクライアント
import org.jboss.ejb.client.EJBClient; import javax.transaction.UserTransaction; . . Context context=null; UserTransaction tx=null; try { Properties props = new Properties(); // REMEMBER: there must be a jboss-ejb-client.properties with the connection parameter // in the clients classpath props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); context = new InitialContext(props); System.out.println("\n\tGot initial Context: "+context); tx=EJBClient.getUserTransaction("yourServerName"); System.out.println("UserTransaction = "+tx.getStatus()); tx.begin(); // do some work ... }catch (Exception e) { e.printStackTrace(); tx.rollback(); }finally{ if(context != null) { context.close(); } }
UserTransaction
参照を取得するには;次のシステムプロパティー -Djboss.node.name=yourServerName
を使用してサーバーを起動し、クライアント側で次のように使用します。
tx=EJBClient.getUserTransaction("yourServerName");yourServerName をサーバーの名前に置き換えます。ユーザートランザクションがノードで開始された場合、すべての呼び出しはノードでスティッキーであり、ノードには必要なすべての EJB が必要です。リモートネーミングプロトコルとスコープコンテキストで
UserTransaction
を使用することはできません。
8.8. 参照
8.8.1. EJB JNDI 命名リファレンス
ejb:<appName>/<moduleName>/<distinctName>/<beanName>!<viewClassName>?stateful
<appName>
- セッション Bean の JAR ファイルがエンタープライズアーカイブ (EAR) 内にデプロイされている場合、これはその EAR の名前です。デフォルトでは、EAR の名前は
.ear
接尾辞を含まないファイル名です。アプリケーション名はapplication.xml
ファイルで上書きすることもできます。セッション Bean が EAR にデプロイされていない場合は、これを空白のままにします。 <moduleName>
- モジュール名は、セッション Bean がデプロイされている JAR ファイルの名前です。デフォルトでは、JAR ファイルの名前は
.jar
接尾辞を除いたファイル名です。モジュール名は JAR のejb-jar.xml
ファイルで上書きすることもできます。 <distinctName>
- JBoss EAP 6 では、各デプロイメントでオプションの個別の名前を指定できます。デプロイメントに明確な名前がない場合は、これを空白のままにします。
<beanName>
- Bean 名は、呼び出されるセッション Bean のクラス名です。
<viewClassName>
- ビュークラス名は、リモートインターフェイスの完全修飾クラス名です。これには、インターフェースのパッケージ名が含まれます。
?stateful
- The
?stateful
JNDI 名がステートフルセッション Bean を参照する場合は、接尾辞が必要です。他の Bean タイプには含まれません。
8.8.2. EJB リファレンス解決
@EJB
と@Resource
。XML は常にアノテーションを上書きしますが、同じルールが適用されることに注意してください。
@EJB アノテーションのルール
- The
@EJB
注釈にもmappedName()
属性。仕様ではこれをベンダー固有のメタデータとして残していますが、JBoss はこれを認識しますmappedName()
参照している EJB のグローバル JNDI 名として。mappedName()
を指定した場合は、他のすべての属性は無視され、このグローバル JNDI 名がバインディングに使用されます。 - 指定した場合
@EJB
属性が定義されていない場合:@EJB ProcessPayment myEjbref;
次に、以下のルールが適用されます。- 参照 Bean の EJB jar は、
@EJB
インジェクションで使用されるインターフェースで EJB を検索します。同じビジネスインターフェースを公開する EJB が複数ある場合、例外が発生します。このインターフェースを持つ BIOSean が 1 つしかない場合は、その Bean が使用されます。 - EAR でインターフェースを公開する EJB を検索します。重複が生じると、例外が発生します。それ以外の場合は、一致する Bean を返します。
- JBoss ランタイムで、そのインターフェースの EJB をグローバルに検索します。同様に、複製が見つかると、例外が発生します。
@EJB.beanName()
に対応<ejb-link>
。の場合beanName()
が定義されたら、と同じアルゴリズムを使用します@EJB
を使用する以外に属性が定義されていないbeanName()
検索のキーとして。この規則の例外は、ejb-link'#' 構文を使用する場合です。'#' 構文を使用すると、参照している EJB が配置されている EAR 内の jar への相対パスを設定できます。詳細は EJB 3.1 仕様を参照してください。
8.8.3. リモート EJB クライアントのプロジェクト依存関係
表8.4 リモート EJB クライアントの Maven 依存関係
グループ ID | アーティファクト ID |
---|---|
org.jboss.spec | jboss-javaee-6.0 |
org.jboss.as | jboss-as-ejb-client-bom |
org.jboss.spec.javax.transaction | jboss-transaction-api_1.1_spec |
org.jboss.spec.javax.ejb | jboss-ejb-api_3.1_spec |
org.jboss | jboss-ejb-client |
org.jboss.xnio | xnio-api |
org.jboss.xnio | xnio-nio |
org.jboss.remoting3 | jboss-remoting |
org.jboss.sasl | jboss-sasl |
org.jboss.marshalling | jboss-marshalling-river |
jboss-javaee-6.0
とjboss-as-ejb-client-bom
、これらの依存関係をに追加する必要があります<dependencies>
pom.xml
ファイルのセクション。
jboss-javaee-6.0
とjboss-as-ejb-client-bom
依存関係をに追加する必要があります<dependencyManagement>
スコープ
がimport
。
artifactID
のバージョンは変更される可能性があります。関連するバージョンについては、Maven リポジトリーを参照してください。
<dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.spec</groupId> <artifactId>jboss-javaee-6.0</artifactId> <version>3.0.0.Final-redhat-1</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.jboss.as</groupId> <artifactId>jboss-as-ejb-client-bom</artifactId> <version>7.1.1.Final-redhat-1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
ejb-remote/client/pom.xml
を参照してください。
8.8.4. jboss-ejb3.xml デプロイメント記述子の参照
jboss-ejb3.xml
は、EJB JAR または WAR アーカイブで使用できるカスタムデプロイメント記述子です。EJB JAR アーカイブでは、META-INF/
ディレクトリーに存在する必要があります。WAR アーカイブでは、WEB-INF/
ディレクトリーに配置する必要があります。
ejb-jar.xml
と同様で、同じネームスペースの一部を使用して追加の名前空間を提供します。jboss-ejb3.xml
のコンテンツは ejb-jar.xml
の内容でマージされ、jboss-ejb3.xml
の内容が優先されます。
jboss-ejb3.xml
で使用される追加の非標準の名前空間のみについて説明します。参照するhttp://java.sun.com/xml/ns/javaee/標準の名前空間に関するドキュメント。
http://www.jboss.com/xml/ns/javaee
です。
アセンブリー記述子の名前空間
<assembly-descriptor>
エレメント。これらを使用して、設定を単一の Bean に適用することも、デプロイメント内のすべての Bean に適用することもできます。*
としてejb-name
。
- クラスターリング名前空間:
urn:clustering:1.0
xmlns:c="urn:clustering:1.0"
これにより、EJB をクラスター化済みとしてマークできます。これは、に相当するデプロイメント記述子です。@org.jboss.ejb3.annotation.Clustered
。<c:clustering> <ejb-name>DDBasedClusteredSFSB</ejb-name> <c:clustered>true</c:clustered> </c:clustering>
- セキュリティー名前空間 (
urn:security
)。 xmlns:s="urn:security"
これにより、security-domain
そしてそのrun-as-principal
EJB の場合。<s:security> <ejb-name>*</ejb-name> <s:security-domain>myDomain</s:security-domain> <s:run-as-principal>myPrincipal</s:run-as-principal> </s:security>
- リソースアダプターの名前空間:
urn:resource-adapter-binding
xmlns:r="urn:resource-adapter-binding"
これにより、メッセージ駆動 Bean のリソースアダプターを設定できます。<r:resource-adapter-binding> <ejb-name>*</ejb-name> <r:resource-adapter-name>myResourceAdapter</r:resource-adapter-name> </r:resource-adapter-binding>
- IIOP 名前空間:
urn:iiop
xmlns:u="urn:iiop"
IIOP 名前空間は IIOP 設定が設定される場所です。- プールの名前空間:
urn:ejb-pool:1.0
xmlns:p="urn:ejb-pool:1.0"
これにより、含まれるステートレスセッション Bean またはメッセージ駆動 Bean が使用するプールを選択できます。プールはサーバー設定で定義されます。<p:pool> <ejb-name>*</ejb-name> <p:bean-instance-pool-ref>my-pool</p:bean-instance-pool-ref> </p:pool>
- キャッシュ名前空間:
urn:ejb-cache:1.0
xmlns:c="urn:ejb-cache:1.0"
これにより、含まれるステートフルセッション Bean によって使用されるキャッシュを選択できます。キャッシュはサーバー設定で定義されます。<c:cache> <ejb-name>*</ejb-name> <c:cache-ref>my-cache</c:cache-ref> </c:cache>
例8.8 jboss-ejb3.xml ファイル
<?xml version="1.1" encoding="UTF-8"?> <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="urn:clustering:1.0" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd" version="3.1" impl-version="2.0"> <enterprise-beans> <message-driven> <ejb-name>ReplyingMDB</ejb-name> <ejb-class>org.jboss.as.test.integration.ejb.mdb.messagedestination.ReplyingMDB</ejb-class> <activation-config> <activation-config-property> <activation-config-property-name>destination</activation-config-property-name> <activation-config-property-value>java:jboss/mdbtest/messageDestinationQueue </activation-config-property-value> </activation-config-property> </activation-config> </message-driven> </enterprise-beans> <assembly-descriptor> <c:clustering> <ejb-name>DDBasedClusteredSFSB</ejb-name> <c:clustered>true</c:clustered> </c:clustering> </assembly-descriptor> </jboss:ejb-jar>
jboss-ejb3-spec-2_0.xsd
には、スキーマバリデーションエラーが発生する可能性がある既知の問題があります。これらのエラーは無視して構いません。詳細は、https://bugzilla.redhat.com/show_bug.cgi?id=1192591 を参照してください。
第9章 JBossMBean サービス
9.1. JBoss MBean Service の記述
create
、start
、stop
、および destroy
が実行可能である場合に MBean サービスに通知する複数のライフサイクル操作で構成されます。
- MBean で特定のメソッドを呼び出したい場合は、これらのメソッドを MBean インターフェースで宣言します。この方法では、MBean 実装で JBoss 固有クラスの依存関係を回避できます。
- JBoss 固有クラスの依存関係を気にしない場合は、MBean インターフェースで
ServiceMBean
インターフェースおよびServiceMBeanSupport
クラスを拡張できます。ServiceMBeanSupport
クラスは、次のようなサービスライフサイクルメソッドの実装を提供します。create
、start
とstop
。次のような特定のイベントを処理するにはstart()
イベント、オーバーライドする必要がありますstartService()
ServiceMBeanSupport クラスによって提供されるメソッド。
9.2. 標準の MBean の例
.sar
) で一緒にパッケージ化される 2 つの MBean サービスのサンプルを開発します。
ConfigServiceMBean
インターフェイスは、次のような特定のメソッドを宣言します。start
、getTimeout
とstop
JBoss 固有のクラスを使用せずに、MBean を正しく 開始
、保持
、および 停止
するためのメソッド。ConfigService
クラスは ConfigServiceMBean
インターフェースを実装した後、このインターフェース内で使用されたメソッドを実装します。
PlainThread
クラスは ServiceMBeanSupport
クラスを拡張し、PlainThreadMBean
インターフェイスを実装します。PlainThread
はスレッドを開始し、ConfigServiceMBean.getTimeout()
スレッドがスリープする時間を決定します。
例9.1 サンプル MBean サービス
package org.jboss.example.mbean.support; public interface ConfigServiceMBean { int getTimeout(); void start(); void stop(); } package org.jboss.example.mbean.support; public class ConfigService implements ConfigServiceMBean { int timeout; @Override public int getTimeout() { return timeout; } @Override public void start() { //Create a random number between 3000 and 6000 milliseconds timeout = (int)Math.round(Math.random() * 3000) + 3000; System.out.println("Random timeout set to " + timeout + " seconds"); } @Override public void stop() { timeout = 0; } } package org.jboss.example.mbean.support; import org.jboss.system.ServiceMBean; public interface PlainThreadMBean extends ServiceMBean { void setConfigService(ConfigServiceMBean configServiceMBean); } package org.jboss.example.mbean.support; import org.jboss.system.ServiceMBeanSupport; public class PlainThread extends ServiceMBeanSupport implements PlainThreadMBean { private ConfigServiceMBean configService; private Thread thread; private volatile boolean done; @Override public void setConfigService(ConfigServiceMBean configService) { this.configService = configService; } @Override protected void startService() throws Exception { System.out.println("Starting Plain Thread MBean"); done = false; thread = new Thread(new Runnable() { @Override public void run() { try { while (!done) { System.out.println("Sleeping...."); Thread.sleep(configService.getTimeout()); System.out.println("Slept!"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); thread.start(); } @Override protected void stopService() throws Exception { System.out.println("Stopping Plain Thread MBean"); done = true; } }
jboss-service.xml
記述子は、イン ジェクト
タグを使用して ConfigService
クラスが PlainThread
クラスにインジェクトされる方法を示します。inject
タグは PlainThreadMBean
と ConfigServiceMBean
間の依存関係を確立し、PlainThreadMBean
が簡単に ConfigServiceMBean
を使用できるようにします。
例9.2 JBoss-service.xml サービス記述子
<server xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:jboss:service:7.0 jboss-service_7_0.xsd" xmlns="urn:jboss:service:7.0"> <mbean code="org.jboss.example.mbean.support.ConfigService" name="jboss.support:name=ConfigBean"/> <mbean code="org.jboss.example.mbean.support.PlainThread" name="jboss.support:name=ThreadBean"> <attribute name="configService"> <inject bean="jboss.support:name=ConfigBean"/> </attribute> </mbean> </server>
jboss-service.xml
記述子をサービスアーカイブ (.sar
) の META-INF/
フォルダーでパッケージ化できます。
9.3. JBoss MBean サービスのデプロイ
ServiceMBeanTest.sar
) を ドメイン
モードでビルドおよびデプロイするには、次のコマンドを使用します。
[domain@localhost:9999 /] deploy ~/Desktop/ServiceMBeanTest.sar
[domain@localhost:9999 /] deploy ~/Desktop/ServiceMBeanTest.sar --all-server-groups
ServiceMBeanTest.sar
) を スタンドアロン
モードでビルドおよびデプロイするには、次のコマンドを使用します。
[standalone@localhost:9999 /] deploy ~/Desktop/ServiceMBeanTest.sar
[standalone@localhost:9999 /] undeploy ServiceMBeanTest.sar
第10章 Web アプリケーションのクラスター化
10.1. セッションレプリケーション
10.1.1. HTTP セッションレプリケーション
10.1.2. Web セッションキャッシュについて
standalone-ha.xml
プロファイル、または管理対象ドメインプロファイル ha
または full-ha
を含む任意の HA プロファイルを使用するときに設定できます。最も一般的に設定される要素は、キャッシュモードと分散キャッシュのキャッシュ所有者の数です。所有者
パラメーターは、DIST
モード。
キャッシュモード
キャッシュモードは次のいずれかになりますREPL
(デフォルト) またはDIST
。
- REPL
- The
REPL
モードは、キャッシュ全体をクラスター内の他のすべてのノードに複製します。これは最も安全なオプションですが、より多くのオーバーヘッドが発生します。 - DIST
- The
DIST
モードは、以前の実装で提供された バディモード に似ています。所有者
パラメーターで指定されたノード数にキャッシュを分散することにより、オーバーヘッドを削減します。この所有者の数のデフォルトは2
です。
所有者
所有者
パラメーターは、セッションの複製されたコピーを保持するクラスターノードの数を制御します。デフォルトは 2
です。
10.1.3. Web セッションキャッシュを設定する
REPL
。使用したい場合DIST
モードの場合は、管理 CLI で次の 2 つのコマンドを実行します。別のプロファイルを使用する場合は、コマンドでプロファイル名を変更してください。スタンドアロンサーバーを使用する場合は、コマンドの /profile=ha
部分を削除してください。
手順10.1 Web セッションキャッシュを設定する
デフォルトのキャッシュモードをに変更します
DIST
。/profile=ha/subsystem=infinispan/cache-container=web/:write-attribute(name=default-cache,value=dist)
分散キャッシュの所有者の数を設定します。
以下のコマンドは所有者の数を5
に設定します。デフォルトは2
です。/profile=ha/subsystem=infinispan/cache-container=web/distributed-cache=dist/:write-attribute(name=owners,value=5)
デフォルトのキャッシュモードをに戻します
REPL
。/profile=ha/subsystem=infinispan/cache-container=web/:write-attribute(name=default-cache,value=repl)
サービスを再起動します。
Web キャッシュモードを変更した後、サーバーを再起動する必要があります。
結果
サーバーはセッションレプリケーション用に設定されています。独自のアプリケーションでセッションレプリケーションを使用するには、次のトピックを参照してください。「アプリケーションにおけるセッションレプリケーションの有効化」。
10.1.4. アプリケーションにおけるセッションレプリケーションの有効化
概要
JBoss EAP 6 高可用性 (HA) 機能を利用するには、アプリケーションを配布可能に設定する必要があります。この手順では、その方法を示し、次に、使用できるいくつかの高度な設定オプションについて説明します。
手順10.2 アプリケーションを配布可能にする
必須: アプリケーションが配布可能であることを示します。
アプリケーションが配布可能でないと、そのセッションは配布されません。アプリケーションのweb.xml
記述子ファイルの<web-app>
タグ内に<distributable/>
要素を追加します。以下は例です。例10.1 配布可能なアプリケーションの最低限の設定
<?xml version="1.0"?> <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"> <distributable/> </web-app>
必要に応じて、デフォルトのレプリケーション動作を変更します。
セッションレプリケーションに影響を与える値のいずれかを変更する場合は、アプリケーションのjboss-web.xml
ファイルの<jboss-web>
要素の子要素である<replication-config>
要素内でそれらをオーバーライドできます。該当する要素で、デフォルト値をオーバーライドする場合のみ値を含めます。次の例は、すべてのデフォルト設定をリストし、その後に最も一般的に変更されるオプションを説明する表が続きます。例10.2 例:
<replication-config>
の値<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 5.0//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_5_0.dtd"> <jboss-web> <replication-config> <replication-trigger>SET_AND_NON_PRIMITIVE_GET</replication-trigger> <replication-granularity>SESSION</replication-granularity> <use-jk>false</use-jk> <max-unreplicated-interval>30</max-unreplicated-interval> <snapshot-mode>INSTANT</snapshot-mode> <snapshot-interval>1000</snapshot-interval> <session-notification-policy>com.example.CustomSessionNotificationPolicy</session-notification-policy> </replication-config> </jboss-web>
表10.1 セッションレプリケーションの一般的なオプション
オプション
|
Description
|
---|---|
<replication-trigger>
|
クラスター全体でセッションデータレプリケーションをトリガーする条件を制御します。このオプションが必要なのは、セッションから可変オブジェクト (セッション属性として格納されている) にアクセスした後、メソッドがない限り、コンテナーはオブジェクトが変更されて複製する必要があるかどうかを明確に知る方法がないためです。
setAttribute() 直接呼び出されます。
設定に関係なく、を呼び出すことでいつでもセッションレプリケーションをトリガーできます
setAttribute() 。
|
<replication-granularity>
|
複製されるデータの粒度を決定します。デフォルト値は
SESSION ですが、代わりにATTRIBUTE を設定すると、ほとんどの属性は変更されずにセッションのパフォーマンスを向上させることができます。
注記
JBoss EAP 6 では FIELD はサポートされていません。
|
表10.2 あまり一般的に変更されないセッションレプリケーションのオプション
オプション
|
Description
|
---|---|
<use-jk>
|
次のようなロードバランサーを想定するかどうか
mod_cluster 、mod_jk 、またmod_proxy 使用中です。デフォルトは false です。true に設定されている場合、コンテナーは各リクエストに関連付けられているセッション ID を調べ、jvmRoute フェイルオーバーがある場合は、セッション ID の一部。
|
<max-unreplicated-interval>
|
セッションが変更されていないと見なされた場合でも、セッションがアクセスされた後、セッションのタイムスタンプのレプリケーションをトリガーする前に待機する最大間隔 (秒単位)。これにより、クラスターノードが各セッションのタイムスタンプを認識し、フェイルオーバー中に複製されていないセッションが誤って期限切れになることがなくなります。また、メソッドの呼び出しに正しい値を信頼できることも保証します
HttpSession.getLastAccessedTime() フェイルオーバー中。
デフォルトでは、値は指定されていません。値が
0 の場合、セッションにアクセスするたびにタイムスタンプが複製されます。値が -1 の場合、要求中の他のアクティビティーがレプリケーションをトリガーした場合にのみ、タイムスタンプがレプリケートされます。より大きい正の値HttpSession.getMaxInactiveInterval() 設定ミスとして扱われ、0 に変換されます。
|
<snapshot-mode>
|
セッションを他のノードに複製するタイミングを指定します。デフォルトは
INSTANT で、他の可能な値は INTERVAL です。
インスタント モードでは、変更はリクエスト処理スレッドを使用して、リクエストの最後に複製されます。<snapshot-interval> オプションは無視されます。
INTERVAL モードでは、バックグラウンドタスクは <snapshot-interval> で指定された間隔で実行され、変更されたセッションを複製します。
|
<snapshot-interval>
| <snapshot-mode> の値に INTERVAL を使用するときに、変更されたセッションが複製される間隔 (ミリ秒単位)。
|
<session-notification-policy>
|
インターフェイスの実装の完全修飾クラス名
ClusteredSessionNotificationPolicy これは、サーブレット仕様通知が登録済みに発行されるかどうかを管理しますHttpSessionListener 、HttpSessionAttributeListener 、またHttpSessionBindingListener 。
|
10.2. HttpSession のパッシベーションとアクティベーション
10.2.1. HTTP セッションパッシベーションおよびアクティベーション
- コンテナーが新規セッションの作成を要求するときに現在アクティブなセッションの数が設定上限を超えている場合、サーバーはセッションの一部をパッシベートして新規セッションのスペースを作成しようとします。
- 定期的に、設定された間隔で、バックグラウンドタスクがセッションを非アクティブ化する必要があるかどうかを確認します。
- Web アプリケーションがデプロイされ、他のサーバーでアクティブなセッションのバックアップコピーが、新たにデプロイされる Web アプリケーションのセッションマネージャーによって取得された場合、セッションはパッシベートされることがあります。
- セッションは、設定可能な最大アイドル時間より長く使用されていません。
- アクティブなセッションの数が設定可能な最大値を超えており、セッションが設定可能な最小アイドル時間より長く使用されていません。
10.2.2. アプリケーションで HttpSession パッシベーションを設定する
概要
HttpSession パッシベーションは、アプリケーションの WEB-INF/jboss-web.xml
または META-INF/jboss-web.xml
ファイルで設定されます。
例10.3 jboss-web.xml
ファイル
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 5.0//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_5_0.dtd"> <jboss-web version="6.0" xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_6_0.xsd"> <max-active-sessions>20</max-active-sessions> <passivation-config> <use-session-passivation>true</use-session-passivation> <passivation-min-idle-time>60</passivation-min-idle-time> <passivation-max-idle-time>600</passivation-max-idle-time> </passivation-config> </jboss-web>
パッシベーション設定要素
<max-active-sessions>
- 許可されるアクティブなセッションの最大数。セッションマネージャーによって管理されるセッションの数がこの値を超え、パッシベーションが有効になっている場合、設定された
<passivation-min-idle-time> に
基づいて超過分がパッシベーションされます。その後、アクティブなセッションの数がまだこの制限を超えている場合、新しいセッションを作成する試みは失敗します。デフォルト値の-1
は、アクティブなセッションの最大数に制限を設定しません。 <passivation-config>
- この要素は、子要素として残りのパッシベーション設定パラメーターを保持します。
<passivation-config>
子要素
<use-session-passivation>
- セッションパッシベーションを使用するかどうか。デフォルト値は
false
です。 <passivation-min-idle-time>
- max-active-sessions で定義された値に準拠するようにアクティブなセッション数を減らすために、コンテナーがセッションの非アクティブ化を検討する前に、セッションが非アクティブでなければならない最小時間 (秒単位)。デフォルト値の
-1
は、<passivation-max-idle-time>
が経過する前に不動態化セッションを無効にします。<max-active-sessions>
が設定されている場合は、-1 の値も高い値もお勧めしません。 <passivation-max-idle-time>
- コンテナーがメモリーを節約するためにセッションを非アクティブ化しようとする前に、セッションが非アクティブになることができる最大時間 (秒単位)。このようなセッションのパッシベーションは、アクティブなセッション数が
<max-active-sessions>
を超えているかどうかに関係なく行われます。この値は、web.xml
の<session-timeout>
設定よりも小さくする必要があります。デフォルト値の-1
は、最大非アクティブに基づくパッシベーションを無効にします。
REPL
とDIST
レプリケーションモード<max-active-sessions>
を設定してください。他のノードから複製されるセッションの数は、REPL
またDIST
キャッシュモードが有効になっています。REPL
キャッシュモードでは、各セッションは各ノードにレプリケートされます。のDIST
キャッシュモードの場合、各セッションは、で指定された数のノードにのみ複製されます。owners
パラメーター。見る「Web セッションキャッシュについて」と「Web セッションキャッシュを設定する」セッションキャッシュモードの設定についての情報。
REPL
キャッシュモードでは、各ノードのメモリーに 800 のセッションが格納されます。とDIST
キャッシュモードが有効で、デフォルトowners
2
に設定すると、各ノードは 200 セッションをメモリーに保存します。
10.3. HA シングルトンを実装する
概要
次の手順は、SingletonService デコレータでラップされ、クラスター全体のシングルトンサービスとして使用されるサービスをデプロイする方法を示しています。このサービスは、クラスター内で 1 回だけ開始されるスケジュールされたタイマーをアクティブにします。
手順10.3 HA シングルトンサービスを実装する
- HA シングルトンサービスアプリケーションを作成します。以下は、シングルトンサービスとしてデプロイされる
SingletonService
デコレータでラップされたサービス
の簡単な例です。完全な例は、Red Hat JBoss Enterprise Application Platform に同梱されているcluster-ha-singleton
クイックスタートにあります。このクイックスタートには、アプリケーションをビルドおよびデプロイするためのすべての手順が含まれています。- サービスを作成します。次のリストは、サービスの例です。
package org.jboss.as.quickstarts.cluster.hasingleton.service.ejb; import java.util.Date; import java.util.concurrent.atomic.AtomicBoolean; import javax.naming.InitialContext; import javax.naming.NamingException; import org.jboss.logging.Logger; import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.StartContext; import org.jboss.msc.service.StartException; import org.jboss.msc.service.StopContext; /** * @author <a href="mailto:wfink@redhat.com">Wolf-Dieter Fink</a> */ public class HATimerService implements Service<String> { private static final Logger LOGGER = Logger.getLogger(HATimerService.class); public static final ServiceName SINGLETON_SERVICE_NAME = ServiceName.JBOSS.append("quickstart", "ha", "singleton", "timer"); /** * A flag whether the service is started. */ private final AtomicBoolean started = new AtomicBoolean(false); /** * @return the name of the server node */ public String getValue() throws IllegalStateException, IllegalArgumentException { LOGGER.infof("%s is %s at %s", HATimerService.class.getSimpleName(), (started.get() ? "started" : "not started"), System.getProperty("jboss.node.name")); return ""; } public void start(StartContext arg0) throws StartException { if (!started.compareAndSet(false, true)) { throw new StartException("The service is still started!"); } LOGGER.info("Start HASingleton timer service '" + this.getClass().getName() + "'"); final String node = System.getProperty("jboss.node.name"); try { InitialContext ic = new InitialContext(); ((Scheduler) ic.lookup("global/jboss-cluster-ha-singleton-service/SchedulerBean!org.jboss.as.quickstarts.cluster.hasingleton.service.ejb.Scheduler")).initialize("HASingleton timer @" + node + " " + new Date()); } catch (NamingException e) { throw new StartException("Could not initialize timer", e); } } public void stop(StopContext arg0) { if (!started.compareAndSet(true, false)) { LOGGER.warn("The service '" + this.getClass().getName() + "' is not active!"); } else { LOGGER.info("Stop HASingleton timer service '" + this.getClass().getName() + "'"); try { InitialContext ic = new InitialContext(); ((Scheduler) ic.lookup("global/jboss-cluster-ha-singleton-service/SchedulerBean!org.jboss.as.quickstarts.cluster.hasingleton.service.ejb.Scheduler")).stop(); } catch (NamingException e) { LOGGER.error("Could not stop timer", e); } } } }
- クラスター化されたシングルトンとして
サービス
をインストールするアクティベーターを作成します。次のリストは、HATimerService
をクラスター化されたシングルトンサービスとしてインストールするサービスアクティベーターの例です。package org.jboss.as.quickstarts.cluster.hasingleton.service.ejb; import org.jboss.as.clustering.singleton.SingletonService; import org.jboss.logging.Logger; import org.jboss.msc.service.DelegatingServiceContainer; import org.jboss.msc.service.ServiceActivator; import org.jboss.msc.service.ServiceActivatorContext; import org.jboss.msc.service.ServiceController; /** * Service activator that installs the HATimerService as a clustered singleton service * during deployment. * * @author Paul Ferraro */ public class HATimerServiceActivator implements ServiceActivator { private final Logger log = Logger.getLogger(this.getClass()); @Override public void activate(ServiceActivatorContext context) { log.info("HATimerService will be installed!"); HATimerService service = new HATimerService(); SingletonService<String> singleton = new SingletonService<String>(service, HATimerService.SINGLETON_SERVICE_NAME); /* * To pass a chain of election policies to the singleton, for example, * to tell JGroups to prefer running the singleton on a node with a * particular name, uncomment the following line: */ // singleton.setElectionPolicy(new PreferredSingletonElectionPolicy(new SimpleSingletonElectionPolicy(), new NamePreference("node1/singleton"))); singleton.build(new DelegatingServiceContainer(context.getServiceTarget(), context.getServiceRegistry())) .setInitialMode(ServiceController.Mode.ACTIVE) .install() ; } }
注記上記のコード例では、クラスを使用しています。org.jboss.as.clustering.singleton.SingletonService
、これは JBoss EAP プライベート API の一部です。パブリック API は JBoss EAP リリースで利用可能になり、プライベートクラスは非推奨になりますが、これらのクラスは維持され、JBoss EAP リリースサイクルの間利用可能になります。 - ServiceActivator ファイルを作成するアプリケーションの
resources/META-INF/services/
ディレクトリーにorg.jboss.msc.service.ServiceActivator
という名前のファイルを作成します。前の手順で作成した ServiceActivator クラスの完全修飾名を含む行を追加します。org.jboss.as.quickstarts.cluster.hasingleton.service.ejb.HATimerServiceActivator
- クラスター全体のシングルトンタイマーとして使用されるタイマーを実装するシングルトン Bean を作成します。このシングルトン Bean にはリモートインターフェイスがなく、アプリケーション内の別の EJB からローカルインターフェイスを参照してはなりません。これにより、クライアントまたは他のコンポーネントによるルックアップが防止され、SingletonService がシングルトンを完全に制御できるようになります。
- スケジューラーインターフェイスを作成する
package org.jboss.as.quickstarts.cluster.hasingleton.service.ejb; /** * @author <a href="mailto:wfink@redhat.com">Wolf-Dieter Fink</a> */ public interface Scheduler { void initialize(String info); void stop(); }
- クラスター全体のシングルトンタイマーを実装するシングルトン Bean を作成します。
package org.jboss.as.quickstarts.cluster.hasingleton.service.ejb; import javax.annotation.Resource; import javax.ejb.ScheduleExpression; import javax.ejb.Singleton; import javax.ejb.Timeout; import javax.ejb.Timer; import javax.ejb.TimerConfig; import javax.ejb.TimerService; import org.jboss.logging.Logger; /** * A simple example to demonstrate a implementation of a cluster-wide singleton timer. * * @author <a href="mailto:wfink@redhat.com">Wolf-Dieter Fink</a> */ @Singleton public class SchedulerBean implements Scheduler { private static Logger LOGGER = Logger.getLogger(SchedulerBean.class); @Resource private TimerService timerService; @Timeout public void scheduler(Timer timer) { LOGGER.info("HASingletonTimer: Info=" + timer.getInfo()); } @Override public void initialize(String info) { ScheduleExpression sexpr = new ScheduleExpression(); // set schedule to every 10 seconds for demonstration sexpr.hour("*").minute("*").second("0/10"); // persistent must be false because the timer is started by the HASingleton service timerService.createCalendarTimer(sexpr, new TimerConfig(info, false)); } @Override public void stop() { LOGGER.info("Stop all existing HASingleton timers"); for (Timer timer : timerService.getTimers()) { LOGGER.trace("Stop HASingleton timer: " + timer.getInfo()); timer.cancel(); } } }
- クラスターリングを有効にして各 JBoss EAP 6 インスタンスを起動します。スタンドアロンサーバーのクラスターリングを有効にするには、インスタンスごとに一意のノード名とポートオフセットを使用して、
HA
プロファイルを使用して各サーバーを起動する必要があります。- Linux の場合、次のコマンド構文を使用してサーバーを起動します。
EAP_HOME/bin/standalone.sh --server-config=standalone-ha.xml -Djboss.node.name=UNIQUE_NODE_NAME -Djboss.socket.binding.port-offset=PORT_OFFSET
例10.4 Linux で複数のスタンドアロンサーバーを起動する
$ EAP_HOME/bin/standalone.sh --server-config=standalone-ha.xml -Djboss.node.name=node1 $ EAP_HOME/bin/standalone.sh --server-config=standalone-ha.xml -Djboss.node.name=node2 -Djboss.socket.binding.port-offset=100
- Microsoft Windows の場合、次のコマンド構文を使用してサーバーを起動します。
EAP_HOME\bin\standalone.bat --server-config=standalone-ha.xml -Djboss.node.name=UNIQUE_NODE_NAME -Djboss.socket.binding.port-offset=PORT_OFFSET
例10.5 Microsoft Windows で複数のスタンドアロンサーバーを起動します
C:> EAP_HOME\bin\standalone.bat --server-config=standalone-ha.xml -Djboss.node.name=node1 C:> EAP_HOME\bin\standalone.bat --server-config=standalone-ha.xml -Djboss.node.name=node2 -Djboss.socket.binding.port-offset=100
注記コマンドライン引数を使用したくない場合は、サーバーインスタンスごとにstandalone-ha.xml
ファイルを設定して、個別のインターフェイスにバインドできます。 - アプリケーションをサーバーにデプロイします次の Maven コマンドは、デフォルトのポートで実行されているスタンドアロンサーバーにアプリケーションをデプロイします。
mvn clean install jboss-as:deploy
追加のサーバーにデプロイするには、サーバー名を渡します。別のホストにある場合は、コマンドラインでホスト名とポート番号を渡します。mvn clean package jboss-as:deploy -Djboss-as.hostname=localhost -Djboss-as.port=10099
Maven の設定とデプロイの詳細については、JBoss EAP 6 に同梱されているcluster-ha-singleton
クイックスタートを参照してください。
10.4. Apache mod_cluster-manager アプリケーション
10.4.1. mod_cluster-manager アプリケーション
10.4.2. mod_cluster-manager アプリケーションの使用
図10.1 mod_cluster 管理 Web ページ
- 1 mod_cluster/1.2.8.Final: これは mod_cluster ネイティブライブラリーのバージョンを示します
- 2 ajp://192.168.122.204:8099: これは、使用されるプロトコル (AJP、HTTP、HTTPS のいずれか)、ワーカーノードおよびポートのホスト名または IP アドレスを示します。
- 3 jboss-eap-6.3-2: これはワーカーノードの JVMRoute を示します。
- 4 仮想ホスト 1: これはワーカーノードで設定された仮想ホストを示します
- 5 無効: これは、特定のコンテキストでの新しいセッションの作成を無効にするために使用できる管理オプションです。ただし、現在のセッションは無効にされず、そのまま処理されます。
- 6 停止: これは、コンテキストへのセッション要求のルーティングを停止するために使用できる管理オプションです。プロパティー
sticky-session-force
が true に設定されていない限り、残りのセッションは別のノードにフェイルオーバーします - 7 コンテキストの有効化コンテキストの無効化コンテキストの停止: これらは、ノード全体で実行できる操作を示します。これらのいずれかのオプションを選択すると、すべての仮想ホストのノードのコンテキストすべてが影響を受けます。
- Load balancing group (LBGroup): すべてのワーカーノードをカスタム負荷分散グループにグループ化するために、
load-balancing-group
プロパティーは EAP 設定の modcluster サブシステムで設定されます。負荷分散グループ (LBGroup) は、設定されたすべての負荷分散グループに関する情報を提供する情報フィールドです。このフィールドが設定されていないと、すべてのワーカーノードは単一のデフォルト負荷分散グループにグループ化されます。備考これは唯一の情報フィールドであるため、load-balancing-group
プロパティーの設定に使用できません。プロパティーは、EAP 設定の mod_cluster サブシステムで設定する必要があります。 - 9 負荷 (値): これは、ワーカーノードの負荷率を示します。負荷率は次のように評価されます。
-load > 0
: A load factor with value 1 indicates that the worker node is overloaded. A load factor of 100 denotes a free and not-loaded node.-load = 0
:A load factor of value 0 indicates that the worker node is in a standby mode. This means that no session requests will be routed to this node until and unless the other worker nodes are unavailable-load = -1
: A load factor of value -1 indicates that the worker node is in an error state.-load = -2
: A load factor of value -2 indicates that the worker node is undergoing CPing/CPong and is in a transition state
第11章 CDI
11.1. CDI の概要
11.1.1. CDI の概要
11.1.2. コンテキストと依存関係の注入 (CDI)
11.1.3. CDI の利点
- コードの大きなチャンクを注釈に置き換えることで、コードベースを簡素化および縮小します。
- 柔軟であり、インジェクションおよびイベントを無効または有効にしたり、代替の Bean を使用したり、非 CDI オブジェクトを簡単にインジェクトしたりできます。
- CDI で古いコードを使用するのは簡単です。
META-INF/
またはWEB-INF/
ディレクトリーにbeans.xml
を含めるだけで済みます。ファイルは空にすることができます。 - パッケージ化とデプロイメントを簡素化し、デプロイメントに追加する必要のある XML の量を削減します。
- コンテキストを介したライフサイクル管理を提供します。インジェクションを要求、セッション、会話、またはカスタムコンテキストに割り当てることができます。
- また、文字列ベースのインジェクションよりも安全かつ簡単にデバッグを行える、タイプセーフな依存関係の注入が提供されます。
- インターセプターを Bean から切り離します。
- 複雑なイベント通知を提供します。
11.1.4. タイプセーフな依存性注入について
11.1.5. Weld、Seam 2、および JavaServer Faces 間の関係
11.2. CDI を使用する
11.2.1. 最初の手順
11.2.1.1. CDI を有効にする
概要
Contexts and Dependency Injection (CDI) は、JBoss EAP 6 のコアテクノロジーの 1 つであり、デフォルトで有効になっています。何らかの理由で無効になっていて、有効にする必要がある場合は、次の手順に従ってください。
手順11.1 JBoss EAP 6 で CDI を有効にする
CDI サブシステムの詳細が設定ファイルからコメント化されているかどうかを確認してください。
サブシステムを無効にするには、domain.xml
またはstandalone.xml
設定ファイルの関連セクションをコメントアウトするか、関連セクションを完全に削除します。EAP_HOME/domain/configuration/domain.xml またはEAP_HOME
/standalone/configuration/standalone.xml
で CDI サブシステムを見つけるには、次の文字列を検索します。存在する場合は、<extensions> セクション内にあります。<extension module="org.jboss.as.weld"/>
使用しているプロファイルには、次の行も含まれている必要があります。プロファイルは、<profiles> セクション内の個々の <profile> 要素にあります。<subsystem xmlns="urn:jboss:domain:weld:1.0"/>
ファイルを編集する前に、JBoss EAP 6 を停止します。
JBoss EAP 6 は実行中に設定ファイルを変更するため、設定ファイルを直接編集する前にサーバーを停止する必要があります。設定ファイルを編集して、CDI サブシステムを復元します。
CDI サブシステムがコメント化されている場合は、コメントを削除します。完全に削除された場合は、ファイルの </extensions> タグのすぐ上にある新しい行に次の行を追加して復元します。<extension module="org.jboss.as.weld"/>
- また、<profiles> セクションの関連するプロファイルに次の行を追加する必要があります。
<subsystem xmlns="urn:jboss:domain:weld:1.0"/>
JBoss EAP 6 を再起動します。
更新した設定で JBoss EAP 6 を起動します。
結果
JBoss EAP 6 は、CDI サブシステムを有効にして起動します。
11.2.2. CDI を使用したアプリケーションの開発
11.2.2.1. CDI を使用したアプリケーションの開発
はじめに
コンテキストと依存関係の注入 (CDI: Contexts and Dependency Injection) を使用すると、アプリケーションの開発、コードの再利用、デプロイメント時または実行時のコードの調整、およびユニットテストを非常に柔軟に行うことができます。JBoss EAP 6 には、CDI の参照実装である Weld が含まれます。これらのタスクは、エンタープライズアプリケーションで CDI を使用する方法を示しています。
11.2.2.2. 既存のコードで CDI を使用する
META-INF/
または WEB-INF/
ディレクトリーに beans.xml
というファイルを作成することだけです。ファイルは空にすることができます。
手順11.2 CDI アプリケーションでレガシー Bean を使用する
Bean をアーカイブにパッケージ化します。
Bean を JAR または WAR アーカイブにパッケージ化します。アーカイブに
beans.xml
ファイルを含めます。Beans.xml
ファイルを JAR アーカイブのMETA-INF/
または WAR アーカイブのWEB-INF/
ディレクトリーに配置します。ファイルは空にすることができます。
結果:
これらの Bean は CDI で使用できます。コンテナーは、Bean のインスタンスを作成および破棄し、それらを指定されたコンテキストに関連付け、他の Bean に注入し、EL 式で使用し、修飾子アノテーションで特殊化し、既存の Bean に変更を加えることなく、インターセプターとデコレーターを追加できます。コード。状況によっては、注釈を追加する必要がある場合があります。
11.2.2.3. スキャンプロセスからの Bean の除外
概要
Weld の機能の 1 つである CDI の JBoss EAP 6 実装は、アーカイブ内のクラスをスキャンから除外し、コンテナーライフサイクルイベントを発生させ、Bean としてデプロイする機能です。これは JSR-299 仕様の一部ではありません。
例11.1 Bean からパッケージを除外します
- 最初のものはすべての Swing クラスを除外します。
- 2 つ目は、Google Web Toolkit がインストールされていない場合、GoogleWebToolkit クラスを除外します。
- 3 番目は、システムプロパティーの場合、文字列
Blether
(正規表現を使用) で終わるクラスを除外します verbosity低
に設定されます。 - 4 つ目は、Wicket クラスが存在し、 viewlayerシステムプロパティーが設定されていません。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:weld="http://jboss.org/schema/weld/beans" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://docs.jboss.org/cdi/beans_1_0.xsd http://jboss.org/schema/weld/beans http://jboss.org/schema/weld/beans_1_1.xsd"> <weld:scan> <!-- Don't deploy the classes for the swing app! --> <weld:exclude name="com.acme.swing.**" /> <!-- Don't include GWT support if GWT is not installed --> <weld:exclude name="com.acme.gwt.**"> <weld:if-class-available name="!com.google.GWT"/> </weld:exclude> <!-- Exclude classes which end in Blether if the system property verbosity is set to low i.e. java ... -Dverbosity=low --> <weld:exclude pattern="^(.*)Blether$"> <weld:if-system-property name="verbosity" value="low"/> </weld:exclude> <!-- Don't include JSF support if Wicket classes are present, and the viewlayer system property is not set --> <weld:exclude name="com.acme.jsf.**"> <weld:if-class-available name="org.apache.wicket.Wicket"/> <weld:if-system-property name="!viewlayer"/> </weld:exclude> </weld:scan> </beans>
11.2.2.4. インジェクションを使用した実装の拡張
概要
インジェクションを使用して、既存のコードの機能を追加または変更できます。この例は、既存のクラスに翻訳機能を追加する方法を示しています。翻訳は架空の機能であり、例で実装される方法は擬似コードであり、説明のためにのみ提供されています。
buildPhrase
。buildPhrase
メソッドは、都市の名前を引数として取得し、「Welcome to Boston!」などのフレーズを出力します。 あなたの目標は、のバージョンを作成することですWelcome
挨拶を別の言語に翻訳できるクラス。
例11.2 注入するTranslator
Bean Into theWelcome
クラス
Translator
オブジェクトにWelcome
クラス。TheTranslator
オブジェクトは、EJB ステートレス Bean または別のタイプの Bean であり、文をある言語から別の言語に翻訳できます。この場合、Translator
元の挨拶を実際に変更せずに、挨拶全体を翻訳するために使用されますWelcome
まったくクラス。TheTranslator
の前に注入されますbuildPhrase
メソッドが実装されます。
public class TranslatingWelcome extends Welcome { @Inject Translator translator; public String buildPhrase(String city) { return translator.translate("Welcome to " + city + "!"); } ... }
11.2.3. あいまいな依存関係または満たされていない依存関係
11.2.3.1. あいまいな依存関係または満たされていない依存関係について
- インジェクションポイントの Bean 型を実装する全 Bean にある修飾子アノテーションを解決します。
- 無効となっている Bean をフィルタリングします。無効な Bean とは、明示的に有効化されていない @Alternative Bean のことです。
11.2.3.2. 予選について
例11.3 を定義する@Synchronous
と@Asynchronous
修飾子
@Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface Synchronous {}
@Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface Asynchronous {}
例11.4 使用@Synchronous
と@Asynchronous
修飾子
@Synchronous public class SynchronousPaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }
@Asynchronous public class AsynchronousPaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }
11.2.3.3. 修飾子を使用したあいまいなインジェクションの解決
概要
このタスクは、あいまいなインジェクションを示し、修飾子を使用してあいまいさを取り除きます。あいまいな注入について詳しくは、「あいまいな依存関係または満たされていない依存関係について」。
例11.5 あいまいな注入
Welcome
の 2 つの実装があります。1 つは変換し、もう 1 つは変換しません。そのような状況では、以下のインジェクションはあいまいであり、翻訳する Welcome
を使用するように指定する必要があります。
public class Greeter { private Welcome welcome; @Inject void init(Welcome welcome) { this.welcome = welcome; } ... }
手順11.3 修飾子を使用したあいまいなインジェクションの解決
@Translating
という修飾子アノテーションを作成します。@Qualifier @Retention(RUNTIME) @Target({TYPE,METHOD,FIELD,PARAMETERS}) public @interface Translating{}
翻訳を行う
Welcome
に@Translating
アノテーションを付けます。@Translating public class TranslatingWelcome extends Welcome { @Inject Translator translator; public String buildPhrase(String city) { return translator.translate("Welcome to " + city + "!"); } ... }
インジェクションで翻訳を行う
Welcome
を要求します。ファクトリーメソッドパターンの場合と同様に、修飾された実装を明示的に要求する必要があります。あいまいさはインジェクションポイントで解決されます。public class Greeter { private Welcome welcome; @Inject void init(@Translating Welcome welcome) { this.welcome = welcome; } public void welcomeVisitors() { System.out.println(welcome.buildPhrase("San Francisco")); } }
結果
翻訳
ウェルカム
が使用され、あいまいさはありません。
11.2.4. 管理 Bean
11.2.4.1. マネージド Bean について
Bean
を定義するものについて独自のアイデアを導入しました。
@Inject
アノテーションが指定されたコンストラクター) を持つ具象 Java クラスは bean になります。これには、すべての Java Bean と EJB セッション bean が含まれます。上記のサービスを Bean で有効にするための唯一の要件は、それらが特別なマーカーファイル META-INF/beans.xml
を含むアーカイブ (JAR、または WAR や EJB JAR などの JavaEE モジュール) に存在することです。
11.2.4.2. Bean であるクラスのタイプ
@ManagedBean
アノテーションを付けることで明示的に管理対象 bean を宣言できますが、CDI ではその必要はありません。この仕様によると、CDI コンテナーでは、以下の条件を満たすクラスはすべて管理対象 bean として扱われます。
- 非静的な内部クラスではないこと。
- これは具象クラスであるか、
@Decorator
アノテーションが付けられています。 - EJB コンポーネントを定義するアノテーションが付与されていないこと、あるいは
ejb-jar.xml
で EJB bean クラスとして宣言されていること。 - インターフェイスを実装していません
javax.enterprise.inject.spi.Extension
. - パラメーターのないコンストラクターか、
@Inject
アノテーションが付与されたコンストラクターがあること。
11.2.4.3. CDI を用いたオブジェクトの Bean へのインジェクト
META-INF/beans.xml
または WEB-INF/Beans.xml
ファイルが含まれている場合、デプロイメント内の各オブジェクトは CDI を使用して注入できます。
@Inject
アノテーションを使用して、Bean の任意の部分にオブジェクトを注入します。クラスのインスタンスを取得するには、bean 内でフィールドに@Inject
アノテーションを付けます。例11.6
TextTranslator
インスタンスをTranslateController
に挿入しますpublic class TranslateController { @Inject TextTranslator textTranslator; ...
注入されたオブジェクトのメソッドを使用する
注入されたオブジェクトのメソッドを直接使用できます。TextTranslator
にメソッドがあると仮定しますtranslate
。例11.7 注入されたオブジェクトのメソッドを使用する
// in TranslateController class public void translate() { translation = textTranslator.translate(inputText); }
Bean のコンストラクターでインジェクションを使用します。
ファクトリーやサービスロケーターを使用して作成する代わりに、Bean のコンストラクターへオブジェクトをインジェクトできます。例11.8 Bean のコンストラクターでインジェクションを使用します。
public class TextTranslator { private SentenceParser sentenceParser; private Translator sentenceTranslator; @Inject TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) { this.sentenceParser = sentenceParser; this.sentenceTranslator = sentenceTranslator; } // Methods of the TextTranslator class ... }
Instance(<T>)
インターフェースを使用してインスタンスをプログラムにより取得します。Bean 型でパラメーター化されると、Instance
インターフェースは TextTranslator のインスタンスを返すことができます。例11.9 プログラムでインスタンスを取得する
@Inject Instance<TextTranslator> textTranslatorInstance; ... public void translate() { textTranslatorInstance.get().translate(inputText); }
結果:
オブジェクトを Bean にインジェクトすると、Bean は全オブジェクトのメソッドとプロパティーを使用できるようになります。Bean のコンストラクターにインジェクトするときに、インジェクションがすでに存在するインスタンスを参照する場合以外は、Bean のコンストラクターが呼び出されるとインジェクトされたオブジェクトのインスタンスが作成されます。たとえば、セッションの存続期間内にセッションスコープの Bean をインジェクトしても、新しいインスタンスは作成されません。
11.2.5. コンテキスト、スコープ、および依存関係
11.2.5.1. コンテキストおよびスコープ
@RequestScoped
、@SessionScoped
、および @ConversationScope
です。
11.2.5.2. 利用可能なコンテキスト
表11.1 利用可能なコンテキスト
コンテキスト | Description |
---|---|
@Dependent | Bean は、参照を保持する Bean のライフサイクルにバインドされます。 |
@ApplicationScoped | アプリケーションのライフサイクルにバインドされます。 |
@RequestScoped | リクエストのライフサイクルにバインドされます。 |
@SessionScoped | セッションのライフサイクルにバインドされます。 |
@ConversationScoped | 会話のライフサイクルにバインドされます。会話スコープは、リクエストの長さとセッションの間であり、アプリケーションによって制御されます。 |
カスタムスコープ | 上記のコンテキストで対応できない場合は、カスタムスコープを定義できます。 |
11.2.6. Bean ライフサイクル
11.2.6.1. Bean のライフサイクルを管理する
概要
このタスクは、リクエストの残存期間の間 Bean を保存する方法を示しています。他の複数のスコープが存在し、独自のスコープを定義できます。
@Dependent
です。つまり、bean のライフサイクルは、参照を保持する bean のライフサイクルに依存します。詳細は、「コンテキストおよびスコープ」 を参照してください。
手順11.4 Bean ライフサイクルの管理
目的のスコープに対応するスコープで Bean にアノテーションを付けます。
@RequestScoped @Named("greeter") public class GreeterBean { private Welcome welcome; private String city; // getter & setter not shown @Inject void init(Welcome welcome) { this.welcome = welcome; } public void welcomeVisitors() { System.out.println(welcome.buildPhrase(city)); } }
Bean が JSF ビューで使用されると、Bean は状態を保持します。
<h:form> <h:inputText value="#{greeter.city}"/> <h:commandButton value="Welcome visitors" action="#{greeter.welcomeVisitors}"/> </h:form>
結果:
Bean は、指定するスコープに関連するコンテキストに保存され、スコープが適用される限り存続します。
11.2.6.2. プロデューサーメソッドの使用
概要
このタスクでは、プロデューサーメソッドを使用して、インジェクション用の Bean ではないさまざまなオブジェクトを生成する方法を示します。
例11.10 デプロイ後のポリモーフィズムを可能にするために、代替の代わりにプロデューサーメソッドを使用します
@Preferred
この例のアノテーションは修飾子アノテーションです。修飾子の詳細については、以下を参照してください。「予選について」。
@SessionScoped public class Preferences implements Serializable { private PaymentStrategyType paymentStrategy; ... @Produces @Preferred public PaymentStrategy getPaymentStrategy() { switch (paymentStrategy) { case CREDIT_CARD: return new CreditCardPaymentStrategy(); case CHECK: return new CheckPaymentStrategy(); default: return null; } } }
@Inject @Preferred PaymentStrategy paymentStrategy;
例11.11 プロデューサーメソッドにスコープを割り当てます
@Dependent
。スコープを Bean に割り当てた場合、スコープは適切なコンテキストにバインドされます。この例のプロデューサーメソッドは、1 つのセッションあたり一度だけ呼び出されます。
@Produces @Preferred @SessionScoped public PaymentStrategy getPaymentStrategy() { ... }
例11.12 プロデューサーメソッド内でインジェクションを使用する
@Produces @Preferred @SessionScoped public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps, CheckPaymentStrategy cps ) { switch (paymentStrategy) { case CREDIT_CARD: return ccps; case CHEQUE: return cps; default: return null; } }
結果
プロデューサーメソッドを使用して、Bean ではないオブジェクトをインジェクトし、コードを動的に変更できます。
11.2.7. 名前付き Bean と代替 Bean
11.2.7.1. 名前付き Bean について
@Named
アノテーションを使用して名前が付けられます。Bean に名前を付けると、Java Server Faces (JSF) で直接使用できます。
@Named
アノテーションは、bean 名である任意のパラメーターを取ります。このパラメーターを省略すると、小文字の Bean 名が名前として使用されます。
11.2.7.2. 名前付き Bean の使用
@Named
アノテーションを使用して名前を Bean に割り当てます。@Named("greeter") public class GreeterBean { private Welcome welcome; @Inject void init (Welcome welcome) { this.welcome = welcome; } public void welcomeVisitors() { System.out.println(welcome.buildPhrase("San Francisco")); } }
Bean 名自体はオプションです。省略した場合、Bean はクラス名にちなんで名付けられ、最初の文字は大文字になりません。上記の例では、デフォルト名はgreeterBean
になります。JSF ビューで名前付き Bean を使用します。
<h:form> <h:commandButton value="Welcome visitors" action="#{greeter.welcomeVisitors}"/> </h:form>
結果:
名前付き Bean は、最小限のコーディングで、JSF ビューのコントロールにアクションとして割り当てられます。
11.2.7.3. 代替 Bean について
例11.13 代替案の定義
@Alternative @Synchronous @Asynchronous public class MockPaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }
beans.xml
ファイルを編集することにより、特定の Bean アーカイブに対して有効になります。
11.2.7.4. 代替を用いたインジェクションのオーバーライド
概要
代替 Bean を使用すると、既存の Bean をオーバーライドできます。これらは、同じ役割を満たすクラスをプラグインする方法として考慮できますが、動作が異なります。代替の Bean はデフォルトで無効になります。このタスクは、代替を指定し、有効にする方法を示しています。
手順11.5 インジェクションのオーバーライド
TranslatingWelcome
クラスがすでにあることを前提としています。ただし、これを "mock" TranslatingWelcome クラスでオーバーライドするとします。これは、実際の Translator Bean を使用できないテストデプロイメントのケースに該当します。
代替を定義します。
@Alternative @Translating public class MockTranslatingWelcome extends Welcome { public String buildPhrase(string city) { return "Bienvenue à " + city + "!"); } }
代替案を代用してください。
置換実装をアクティベートするために、完全修飾クラス名をMETA-INF/beans.xml
またはWEB-INF/beans.xml
ファイルに追加します。<beans> <alternatives> <class>com.acme.MockTranslatingWelcome</class> </alternatives> </beans>
結果
元の実装の代わりに代替実装が使用されます。
11.2.8. ステレオタイプ
11.2.8.1. ステレオタイプについて
- デフォルトのスコープ。
- インターセプターバインディングのセット。
- ステレオタイプを持つすべての Bean には、デフォルトの BeanEL 名があります
- ステレオタイプを持つすべての Bean は代替です
@Named
アノテーションを持つ場合、配置された bean はデフォルトの bean 名を持ちます。この bean は、@Named アノテーションが bean で直接指定された場合に、この名前をオーバーライドできます。名前付き Bean の詳細については、を参照してください。「名前付き Bean について」。
11.2.8.2. ステレオタイプの使用
概要
ステレオタイプを使用しないと、アノテーションが煩雑になる可能性があります。このタスクは、ステレオタイプを使用して煩雑さを軽減し、コードを効率化する方法を示しています。ステレオタイプとは何かについての詳細は、を参照してください。「ステレオタイプについて」。
例11.14 注釈が乱雑
@Secure @Transactional @RequestScoped @Named public class AccountManager { public boolean transfer(Account a, Account b) { ... } }
手順11.6 ステレオタイプの定義および使用
ステレオタイプを定義します。
@Secure @Transactional @RequestScoped @Named @Stereotype @Retention(RUNTIME) @Target(TYPE) public @interface BusinessComponent { ... }
ステレオタイプを使用します。
@BusinessComponent public class AccountManager { public boolean transfer(Account a, Account b) { ... } }
結果:
ステレオタイプは、コードを合理化および簡素化します。
11.2.9. オブザーバーメソッド
11.2.9.1. オブザーバーメソッドについて
11.2.9.2. トランザクションオブザーバー
public void refreshCategoryTree(@Observes(during = AFTER_SUCCESS) CategoryUpdateEvent event) { ... }
- IN_PROGRESS: デフォルトではオブザーバーは即座に呼び出されます。
- AFTER_SUCCESS: トランザクションが正常に完了する場合のみ、オブザーバーはトランザクションの完了フェーズの後に呼び出されます。
- AFTER_FAILURE: トランザクションの完了に失敗する場合のみ、オブザーバーはトランザクションの完了フェーズの後に呼び出されます。
- AFTER_COMPLETION: オブザーバーはトランザクションの完了フェーズの後に呼び出されます。
- BEFORE_COMPLETION: オブザーバーはトランザクションの完了フェーズの前に呼び出されます。
import javax.ejb.Singleton; import javax.enterprise.inject.Produces; @ApplicationScoped @Singleton public class Catalog { @PersistenceContext EntityManager em; List<Product> products; @Produces @Catalog List<Product> getCatalog() { if (products==null) { products = em.createQuery("select p from Product p where p.deleted = false") .getResultList(); } return products; } }
import javax.enterprise.event.Event; @Stateless public class ProductManager { @PersistenceContext EntityManager em; @Inject @Any Event<Product> productEvent; public void delete(Product product) { em.delete(product); productEvent.select(new AnnotationLiteral<Deleted>(){}).fire(product); } public void persist(Product product) { em.persist(product); productEvent.select(new AnnotationLiteral<Created>(){}).fire(product); } ... }
import javax.ejb.Singleton; @ApplicationScoped @Singleton public class Catalog { ... void addProduct(@Observes(during = AFTER_SUCCESS) @Created Product product) { products.add(product); } void removeProduct(@Observes(during = AFTER_SUCCESS) @Deleted Product product) { products.remove(product); } }
11.2.9.3. イベントの発生と確認
例11.15 イベントを開始する
public class AccountManager { @Inject Event<Withdrawal> event; public boolean transfer(Account a, Account b) { ... event.fire(new Withdrawal(a)); } }
例11.16 修飾子を使用してイベントを発生させる
public class AccountManager { @Inject @Suspicious Event <Withdrawal> event; public boolean transfer(Account a, Account b) { ... event.fire(new Withdrawal(a)); } }
例11.17 イベントを観察する
@Observes
アノテーションを使用します。
public class AccountObserver { void checkTran(@Observes Withdrawal w) { ... } }
例11.18 資格のあるイベントを観察する
public class AccountObserver { void checkTran(@Observes @Suspicious Withdrawal w) { ... } }
11.2.10. インターセプター
11.2.10.1. インターセプターについて
インターセプションポイント
- ビジネスメソッドの傍受
- ビジネスメソッドインターセプターは、Bean のクライアントによる Bean のメソッドの呼び出しに適用されます。
- ライフサイクルコールバックインターセプト
- ライフサイクルコールバックインターセプターは、コンテナーによるライフサイクルコールバックの呼び出しに適用されます。
- タイムアウトメソッドのインターセプト
- タイムアウトメソッドインターセプターは、コンテナーによる EJB タイムアウトメソッドの呼び出しに適用されます。
11.2.10.2. CDI とのインターセプターの使用
例11.19 CDI のないインターセプター
- Bean は、インターセプター実装を直接指定する必要があります。
- アプリケーションの各 Bean は、インターセプターの完全なセットを適切な順序で指定する必要があります。この場合、アプリケーション全体でインターセプターを追加または削除するには時間がかかり、エラーが発生する傾向があります。
@Interceptors({ SecurityInterceptor.class, TransactionInterceptor.class, LoggingInterceptor.class }) @Stateful public class BusinessComponent { ... }
手順11.7 CDI とのインターセプターの使用
インターセプターバインディングタイプを定義します。
@InterceptorBinding @Retention(RUNTIME) @Target({TYPE, METHOD}) public @interface Secure {}
インターセプター実装をマーク付けします。
@Secure @Interceptor public class SecurityInterceptor { @AroundInvoke public Object aroundInvoke(InvocationContext ctx) throws Exception { // enforce security ... return ctx.proceed(); } }
ビジネスコードでインターセプターを使用します。
@Secure public class AccountManager { public boolean transfer(Account a, Account b) { ... } }
META-INF/beans.xml
またはWEB-INF/beans.xml
ファイルに追加して、デプロイメントでインターセプターを有効にします。<beans> <interceptors> <class>com.acme.SecurityInterceptor</class> <class>com.acme.TransactionInterceptor</class> </interceptors> </beans>
インターセプターは、リストされた順序で適用されます。
結果:
CDI は、インターセプターコードを簡素化し、ビジネスコードへの適用を容易にします。
11.2.11. デコレータについて
@Decorator
。CDI アプリケーションでデコレーターを呼び出すには、beans.xml
ファイルで指定する必要があります。
例11.20 デコレータの例
@Decorator public abstract class LargeTransactionDecorator implements Account { @Inject @Delegate @Any Account account; @PersistenceContext EntityManager em; public void withdraw(BigDecimal amount) { ... } public void deposit(BigDecimal amount); ... } }
@Delegate
インジェクションポイントが 1 つ必要になります。
11.2.12. ポータブル拡張機能について
- ビジネスプロセス管理エンジンとの統合。
- Spring、Seam、GWT、Wicket などのサードパーティーフレームワークとの統合。
- CDI プログラミングモデルに基づく新しいテクノロジー。
- 独自の Bean、インターセプター、およびデコレーターをコンテナーに提供します。
- 依存関係注入サービスを使用した独自のオブジェクトへの依存関係のインジェクション。
- カスタムスコープのコンテキスト実装を提供します。
- アノテーションベースのメタデータを別のソースからのメタデータで拡大またはオーバーライドします。
11.2.13. Bean プロキシー
11.2.13.1. Bean プロキシーについて
コンテナーでプロキシーできない Java タイプ
- パラメーターのない非プライベートコンストラクターを持たないクラス
- 宣言されたクラス
final
または持っているfinal
方法 - アレイおよびプリミティブ型。
11.2.13.2. インジェクションでのプロキシーの使用
概要
各 bean のライフサイクルが異なる場合に、インジェクションにプロキシーが使用されます。プロキシーは起動時に作成されたbean のサブクラスで、bean クラスのプライベートメソッド以外のメソッドをすべて上書きします。プロキシーは実際の bean インスタンスへ呼び出しを転送します。
PaymentProcessor
インスタンスは直接注入されませんShop
。代わりに、プロキシーが注入され、processPayment()
メソッドが呼び出されると、プロキシーは現在のPaymentProcessor
Bean インスタンスを呼び出し、processPayment()
その上でメソッド。
例11.21 プロキシーインジェクション
@ConversationScoped class PaymentProcessor { public void processPayment(int amount) { System.out.println("I'm taking $" + amount); } } @ApplicationScoped public class Shop { @Inject PaymentProcessor paymentProcessor; public void buyStuff() { paymentProcessor.processPayment(100); } }
第12章 Java Transaction API (JTA)
12.1. 概要
12.1.1. Java Transactions API(JTA) の概要
はじめに
これらのトピックは、Java Transactions API(JTA) の基本的な理解を提供します。
12.2. トランザクションの概念
12.2.1. トランザクション
12.2.2. トランザクションの ACID プロパティー
Atomicity
)、一貫性 (Consistency
)、独立性 (Isolation
)、永続性 (Durability
) の略語です。通常、この用語はデータベースやトランザクション操作において使用されます。
ACID の定義
- 原子性 (Atomicity)
- トランザクションの原子性を保つには、すべてのトランザクションメンバーが同じ決定を行う必要があります。これらのメンバーはコミットまたはロールバックを行います。原子性が保たれない場合の結果はヒューリスティックな結果と呼ばれます。
- 一貫性
- 一貫性とは、データベーススキーマの観点から、データベースに書き込まれたデータが有効なデータであることを保証するという意味です。データベースあるいは他のデータソースは常に一貫した状態でなければなりません。一貫性のない状態の例には、操作が中断される前にデータの半分が書き込まれてしまったフィールドなどがあります。すべてのデータが書き込まれた場合や、書き込みが完了しなかった時に書き込みがロールバックされた場合に、一貫した状態となります。
- 分離
- 独立性とは、トランザクションのスコープ外のプロセスがデータを変更できないように、トランザクションで操作されたデータが変更前にロックされる必要があることを意味します。
- 持続性 (Durability)
- 持続性とは、トランザクションのメンバーがコミットするよう指示されてから外部で問題が発生した場合に、問題が解決されるとすべてのメンバーがトランザクションを継続してコミットできることを意味します。このような問題には、ハードウェア、ソフトウェア、ネットワーク、またはその他の関与するシステムが関連することがあります。
12.2.3. トラザクションコーディネーターまたはトランザクションマネージャー
12.2.4. トランザクションの参加者
12.2.5. Java Transactions API(JTA) について
12.2.6. Java Transaction Service (JTS)
12.2.7. XA データソースおよび XA トランザクション
12.2.8. XA リカバリー
12.2.9. 2 フェーズコミットプロトコル
フェーズ 1
最初のフェーズでは、トランザクションをコミットできるか、あるいはロールバックする必要があるかをトランザクションの参加者がトランザクションコーディネーターに通知します。
フェーズ 2
2 番目のフェーズでは、トランザクションコーディネーターがトランザクション全体をコミットするか、またはロールバックするかを決定します。いずれの参加者もコミットできない場合、トランザクションはロールバックしなければなりません。それ以外の場合、トランザクションはコミットできます。コーディネーターは何を行うかをリソースに指示し、トランザクションはその完了時にコーディネーターに通知します。この時点で、トランザクションは完了します。
12.2.10. トランザクションタイムアウト
12.2.11. 分散トランザクション
12.2.12. ORB 移植性 API
ORB ポータビリティ API クラス
com.arjuna.orbportability.orb
com.arjuna.orbportability.oa
12.2.13. ネストされたトランザクションについて
ネストされたトランザクションの利点
- 誤った隔離
- サブトランザクションがロールバックする場合、おそらくそれが使用しているオブジェクトが失敗したために、囲んでいるトランザクションはロールバックする必要はありません。
- モジュール性
- 新しいトランザクションの開始時にトランザクションがすでに呼び出しに関連付けられている場合、新しいトランザクションはその中にネストされます。したがって、オブジェクトにトランザクションが必要であることがわかっている場合は、オブジェクト内にトランザクションを作成できます。オブジェクトのメソッドがクライアントトランザクションなしで呼び出された場合、オブジェクトのトランザクションは最上位になります。それ以外の場合は、クライアントのトランザクションのスコープ内にネストされます。同様に、クライアントはオブジェクトがトランザクションであるかどうかを知る必要はありません。独自のトランザクションを開始できます。
12.2.14. XML トランザクションサービス
12.2.14.1. XTS によって使用されるプロトコルの概要
12.2.14.2. Web Services-Atomic Transaction (WS-AT) プロセス
アトミックトランザクション (AT) プロセス
- AT を開始する際、クライアントは最初に WS-T をサポートする WS-C Activation Coordinator Web サービスを見つけます。
- クライアントはコーディネーション型として指定 http://schemas.xmlsoap.org/ws/2004/10/wsat して WS-C
CreateCoordinationContext
メッセージをサービスに送信します。 - クライアントは適切な WS-T コンテキストをアクティベーションサービスから受け取ります。
CreateCoordinationContext
メッセージの応答であるトランザクションコンテキストのCoordinationType
要素は WS-AT 名前空間 http://schemas.xmlsoap.org/ws/2004/10/wsat に設定されます。また、参加者を登録できるアトミックトランザクションコーディネーターエンドポイントである WS-C Registration Service への参照も含まれます。- クライアントは通常、続いて Web サービスの呼び出しを行い、Web サービスによるすべての変更をコミットまたはロールバックしてトランザクションを完了します。完了できるようにするには、エンドポイントがコーディネーションコンテキストで返された登録サービスに登録メッセージを送信し、クライアントを完了プロトコルの参加者として登録する必要があります。
- クライアントを登録したら、クライアントアプリケーションは Web サービスと対話してビジネスレベルの作業を達成します。クライアントは、ビジネス Web サービスが呼び出されるごとに、トランザクションコンテキストを SOAP ヘッダーブロックの挿入し、各呼び出しがトランザクションによって暗黙的にスコープ付けされます。WS-AT 対応 Web サービスをサポートするツールキットは、SOAP ヘッダーブロックで見つかったコンテキストをバックエンド操作と関連付ける機能を提供します。これにより、Web サービスによる変更がクライアントと同じトランザクションの範囲内で行われるようにし、トランザクションコーディネーターによるコミットまたはロールバックの対象になるようにします。
- 必要なアプリケーションの作業がすべて完了したら、クライアントはサービス状態の変更を永続する目的でトランザクションを終了することができます。完了参加者は、トランザクションをコミットまたはロールバックするようコーディネーターに指示します。コミットまたはロールバック操作が完了すると、トランザクションの結果を示すために状態が参加者に返されます。
12.2.14.3. Web Services-Business Activity (WS-BA) プロセス
WS-BA プロセス
- サービスは作業をするよう要求されます。
- これらのサービスに作業を元に戻す機能があるのであれば、BA が後でその作業の取り消しを決定した場合に備えて BA に通知します。WS-BA に障害が発生した場合は、元に戻す undo 動作を実行するようサービスに指示することができます。
12.2.14.4. トランザクションブリッジングの概要
txbridge
は双方向のリンクを提供し、トランザクションのいずれの型も、別の型と使用するよう設計されているビジネスロジックを含めることができます。ブリッジによって使用される技術は、介入とプロトコルマッピングの組み合わせです。
org.jboss.jbossts.txbridge
およびそのサブパッケージ。これは、クラスの 2 つのセットによって構成され、セットごとに各方向のブリッジング用になります。
12.3. トランザクションの最適化
12.3.1. トランザクション最適化の概要
はじめに
JBoss EAP 6 のトランザクションサブシステムには、アプリケーションで利用できるいくつかの最適化が含まれています。
12.3.2. 1 フェーズコミット (1PC) の LRCO 最適化
12.3.2.1. Commit Markable Resource (CMR)
概要
Commit Markable Resource (CMR) インターフェイスを介してリソースマネージャーへのアクセスを設定すると、1PC リソースマネージャーを 2PC トランザクションに確実に参加させることができます。これは、非 XA リソースを完全にリカバリー可能にする LRCO アルゴリズムの実装です。
- 2PC を準備する
- LRCO をコミットします。
- tx ログを書き込む
- 2PC をコミットする
exception-sorter
パラメーターを使用します。JBoss EAP 『管理および設定ガイド』 に記載されているデータソース設定例に従うことができます。
制約
トランザクションには、CMR リソースを 1 つだけ含めることができます。
前提条件
次の SQL が機能するテーブルを作成する必要があります。
SELECT xid,actionuid FROM _tableName_ WHERE transactionManagerID IN (String[]) DELETE FROM _tableName_ WHERE xid IN (byte[[]]) INSERT INTO _tableName_ (xid, transactionManagerID, actionuid) VALUES (byte[],String,byte[])
例12.1 SQL クエリーのいくつかの例
CREATE TABLE xids (xid varbinary(144), transactionManagerID varchar(64), actionuid varbinary(28))
CREATE TABLE xids (xid RAW(144), transactionManagerID varchar(64), actionuid RAW(28)) CREATE UNIQUE INDEX index_xid ON xids (xid)
CREATE TABLE xids (xid VARCHAR(255) for bit data not null, transactionManagerID varchar(64), actionuid VARCHAR(255) for bit data not null) CREATE UNIQUE INDEX index_xid ON xids (xid)
CREATE TABLE xids (xid varbinary(144), transactionManagerID varchar(64), actionuid varbinary(28)) CREATE UNIQUE INDEX index_xid ON xids (xid)
CREATE TABLE xids (xid bytea, transactionManagerID varchar(64), actionuid bytea) CREATE UNIQUE INDEX index_xid ON xids (xid)
リソースマネージャーを CMR として有効にする
デフォルトでは、CMR 機能はデータソースに対して無効になっています。有効にするには、データソースの設定を作成または変更し、connectable 属性を true に設定する必要があります。サーバー xml 設定ファイルの datasources セクションの設定エントリーの例は次のとおりです。
<datasource enabled="true" jndi-name="java:jboss/datasources/ConnectableDS" pool-name="ConnectableDS" jta="true" use-java-context="true" spy="false" use-ccm="true" connectable="true"/>
/subsystem=datasources/data-source=ConnectableDS:add(enabled="true", jndi-name="java:jboss/datasources/ConnectableDS", jta="true", use-java-context="true", spy="false", use-ccm="true", connectable="true", connection-url="validConnectionURL", exception-sorter="org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLExceptionSorter", driver-name="h2")
新しい CMR 機能を使用するために既存のリソースを更新
新しい CMR 機能を使用するために既存のリソースを更新するだけでよい場合は、接続可能な属性を変更するだけです。
/subsystem=datasources/data-source=ConnectableDS:write-attribute(name=connectable,value=true)
CMR 対応のデータソースの特定
トランザクションサブシステムは、以下に示すように、トランザクションサブシステム設定セクションへのエントリーを通じて CMR 対応のデータソースを識別します。
<subsystem xmlns="urn:jboss:domain:transactions:3.0"> ... <commit-markable-resources> <commit-markable-resource jndi-name="java:jboss/datasources/ConnectableDS"> <xid-location name="xids" batch-size="100" immediate-cleanup="false"/> </commit-markable-resource> ... </commit-markable-resources> </subsystem>
12.3.3. 推定中止 (presumed-abort) の最適化
12.3.4. 読み取り専用の最適化
12.4. トランザクションの結果
12.4.1. トランザクションの結果
- ロールバック
- トランザクションの参加者のいずれかがコミットできなかったり、トランザクションコーディネーターが参加者にコミットを指示できない場合は、トランザクションがロールバックされます。詳細は、「トランザクションのロールバックについて」 を参照してください。
- Commit
- トランザクションの参加者すべてがコミットできる場合、トランザクションコーディネーターはコミットの実行を指示します。詳細は、「トランザクションのコミット」 を参照してください。
- ヒューリスティックな結果
- トランザクションの参加者の一部がコミットし、他の参加者がロールバックした場合をヒューリスティックな結果と呼びます。ヒューリスティックな結果には、人間の介入が必要になります。詳細は、「ヒューリスティックな結果」 を参照してください。
12.4.2. トランザクションのコミット
12.4.3. トランザクションのロールバックについて
12.4.4. ヒューリスティックな結果
- ヒューリスティックロールバック
- 一部またはすべての参加者が一方的にトランザクションをロールバックしたため、コミット操作が失敗しました。
- ヒューリスティックコミット
- 参加者のすべてが一方的にコミットしたため、ロールバック操作に失敗します。たとえば、コーディネーターが正常にトランザクションを準備したにも関わらず、ログ更新の失敗などでコーディネーター側で障害が発生したため、ロールバックの実行を決定した場合などに発生します。暫定的に、参加者はコミットすることを決定することができます。
- ヒューリスティック混合
- 一部の参加者がコミットし、その他の参加者はロールバックした状態です。
- ヒューリスティックハザード
- 一部の更新の結果は不明です。既知のものについては、すべてコミットされているか、すべてロールバックされています。
12.4.5. JBoss Transactions エラーと例外
UserTransaction
クラスのメソッドによって発生する例外の詳細については、『UserTransaction API』 仕様 (http://docs.oracle.com/javaee/6/api/javax/transaction/UserTransaction.html) を参照してください。
12.5. JTA トランザクションの概要
12.5.1. Java Transactions API(JTA) について
12.5.2. JTA トランザクションのライフサイクル
アプリケーションは新しいトランザクションを開始します。
トランザクションを開始するために、アプリケーションは JNDI から (EJB の場合はアノテーションから)UserTransaction
クラスのインスタンスを取得します。UserTransaction
インターフェースには、トップレベルのトランザクションを開始、コミット、およびロールバックするメソッドが含まれています。新規作成されたトランザクションは、そのトランザクションを呼び出すスレッドと自動的に関連付けされます。ネストされたトランザクションは JTA ではサポートされないため、すべてのトランザクションがトップレベルのトランザクションとなります。UserTransaction
を呼び出します。begin()
アノテーションを使用すると、EJB メソッドが呼び出されたときにトランザクションが開始されます (TransactionAttribute ルールによって駆動されます)。この時点以降に使用されたリソースは、このトランザクションと関連付けられます。2 つ以上のリソースが登録された場合、トランザクションは XA トランザクションになり、コミット時に 2 フェーズコミットプロトコルに参加します。注記UserTransaction
オブジェクトは、BMT トランザクションにのみ使用されます。CMT では、UserTransaction オブジェクトは許可されていません。アプリケーションが状態を変更します。
次のステップでは、アプリケーションがその作業を実行し、その状態を変更します。アプリケーションはコミットまたはロールバックの実行を決定します。
アプリケーションの状態の変更が完了すると、アプリケーションはコミットするか、またはロールバックするかを決定します。UserTransaction
のいずれかの適切なメソッドを呼び出します。commit()
またはUserTransaction
。rollback()
。トランザクションマネージャーは、そのレコードからトランザクションを削除します。
コミットまたはロールバックが完了すると、トランザクションマネージャーはレコードをクリーンアップし、トランザクションに関する情報をトランザクションログから削除します。
障害回復
障害回復は自動的に行われます。リソース、トランザクションの参加者、またはアプリケーションサーバーが使用できなくなった場合は、障害が解決され、リソースが再度使用できるようになったときにトランザクションマネージャーがリカバリーを実行します。
12.6. トランザクションサブシステムの設定
12.6.1. トランザクション設定の概要
はじめに
次の手順は、JBoss EAP 6 のトランザクションサブシステムを設定する方法を示しています。
12.6.2. トランザクションデータソースの設定
12.6.2.1. XA Datasource の設定
前提条件
管理コンソールへのログイン
新しいデータソースを追加します。
JBoss EAP 6 に新しいデータソースを追加します。上部の XA データソース タブをクリックします。注記JBoss EAP 6 に新しいデータソースを追加する方法については、Red Hat Customer Portal の 『管理および設定ガイド』 の 『管理インターフェイスを使用した XA データソースの作成』 セクションを参照してください。必要に応じて他のプロパティーを設定します。
すべてのデータソースパラメーターは、「データソースのパラメーター」。
結果
XA Datasource が設定され、使用する準備ができます。
12.6.2.2. 管理インターフェースによる非 XA データソースの作成
概要
ここでは、管理コンソールまたは管理 CLI のいずれかを使用して非 XA データソースを作成する手順について取り上げます。
前提条件
- JBoss EAP 6 サーバーが稼働している必要があります。
手順12.1 管理 CLI または管理コンソールのいずれかを使用したデータソースの作成
管理 CLI
- CLI ツールを起動し、サーバーに接続します。
- 次の管理 CLI コマンドを実行して、非 XA データソースを作成し、必要に応じて変数を設定します。注記DRIVER_NAME の値は、JDBC ドライバー JAR にある
/META-INF/services/java.sql.Driver
ファイルにリストされているクラスの数によって異なります。クラスが 1 つしかない場合、値は JAR の名前です。複数のクラスがある場合、値は JAR の名前 + driverClassName + "_" + majorVersion + "_"+minorVersion です。そうしないと、次のエラーがログに記録されます。JBAS014775: New missing/unsatisfied dependencies
たとえば、MySQL 5.1.31 ドライバーに必要な DRIVER_NAME 値は、mysql-connector-java-5.1.31-bin.jarcom.mysql.jdbc.Driver_5_1
です。data-source add --name=DATASOURCE_NAME --jndi-name=JNDI_NAME --driver-name=DRIVER_NAME --connection-url=CONNECTION_URL
- データソースを有効にします。
data-source enable --name=DATASOURCE_NAME
管理コンソール
- 管理コンソールへログインします。
管理コンソールの データソース パネルに移動します
- コンソール上部の Configuration タブを選択します。
- ドメインモードの場合は、左上のドロップダウンボックスからプロファイルを選択します。
- コンソールの左側にある サブシステム メニューを展開し、コネクター メニューを展開します。
- コンソールの左側にあるメニューから データソース を選択します。
新しいデータソースを作成します。
- データソース パネルの上部にある 追加 をクリックします。
- データソースの 作成 ウィザードに新しいデータソース属性を入力し、次へ ボタンに進みます。
- データソースの作成 ウィザードに JDBC ドライバーの詳細を入力し、次 へをクリックして続行します。
- データソースの作成 ウィザードで接続設定を入力します。
- 接続のテスト ボタンをクリックして、データソースへの接続をテストし、設定が正しいことを確認します。
- 完了 をクリックして終了します
結果
非 XA データソースがサーバーに追加されました。これで、standalone.xml
ファイルまたは domain.xml
ファイルのいずれか、および管理インターフェイスに表示されます。
12.6.2.3. JTA Transaction API を使用するようデータソースを設定
概要
ここでは、データソースで Java Transaction API (JTA) を有効にする方法を説明します。
前提条件
このタスクを続行するには、次の条件を満たしている必要があります。
- データベースまたはその他のリソースは、JavaTransactionAPI をサポートしている必要があります。疑わしい場合は、データベースまたはその他のリソースのドキュメントを参照してください。
- データソースを作成します。「管理インターフェースによる非 XA データソースの作成」 を参照してください。
- JBoss EAP 6 を停止します。
- テキストエディターで設定ファイルを直接編集できる権限を持たなければなりません。
手順12.2 Java Transaction API を使用するようデータソースを設定
テキストエディターで設定ファイルを開きます。
JBoss EAP 6 を管理対象ドメインまたはスタンドアロンサーバーで実行するかによって、設定ファイルの場所は異なります。管理対象ドメイン
管理対象ドメインのデフォルトの設定ファイルは、Red Hat Enterprise Linux の場合はEAP_HOME
/domain/configuration/domain.xml にあり、Microsoft Windows の場合はEAP_HOME\domain \ configuration\domain.xml
にあります。スタンドアロンサーバー
スタンドアロンサーバーのデフォルトの設定ファイルは、Red Hat Enterprise Linux の場合はEAP_HOME
/standalone/configuration/standalone.xml にあり、Microsoft Windows の場合はEAP_HOME\Standalone \ configuration\standalone.xml
にあります。
データソースに対応する
<datasource>
タグを見つけます。データソースのjndi-name
属性は、作成時に指定した属性に設定されます。たとえば、ExampleDS データソースは次のようになります。<datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="H2DS" enabled="true" jta="true" use-java-context="true" use-ccm="true">
jta
属性をtrue
に設定します。前の手順で表示されたように、<datasource>
タグの内容に次を追加します。jta= "true"
特定のユースケース (読み取り専用データソースの定義など) がない限り、Red Hat はデフォルト値のjta=true
をオーバーライドすることをお勧めしません。この設定は、データソースが Java Transaction API を尊重し、JCA 実装による接続の追跡を改善できることを示しています。設定を保存します。
設定ファイルを保存しテキストエディターを終了します。JBoss EAP 6 を起動します。
JBoss EAP 6 サーバーを再起動します。
結果
JBoss EAP 6 が起動し、データソースが Java Transaction API を使用するように設定されます。
12.6.2.4. データベース接続検証設定の指定
概要
データベースのメンテナンス、ネットワークの問題、またはその他の障害により、JBoss EAP 6 からデータベースへの接続が失われることがあります。サーバー設定ファイルの <datasource>
セクション内の <validation>
要素を使用して、データベース接続の検証を有効にします。以下の手順に従って、JBoss EAP 6 でデータベース接続の検証を有効にするようにデータソース設定を設定します。
手順12.3 データベース接続検証設定の指定
検証方法の選択
以下のいずれかの検証方法を選択します。<validate-on-match>true</validate-on-match>
<validate-on-match>
オプションがtrue
に設定されている場合は、データ接続が、次の手順で指定された検証メカニズムを使用して接続プールからチェックアウトされるたびに検証されます。接続が有効でない場合は、警告がログに書き込まれ、プール内の次の接続が取得されます。このプロセスは、有効な接続が見つかるまで続行します。プール内の各接続を繰り返し処理しない場合は、<use-fast-fail>
オプションを使用できます。有効な接続がプールにない場合は、新しい接続が作成されます。接続の作成に失敗すると、例外が要求元アプリケーションに返されます。この設定により、最も早いリカバリーが実現されますが、データベースへの負荷が最も大きくなります。ただし、これは、パフォーマンスを気にする必要がない場合は最も安全な方法です。<background-validation>true</background-validation>
<background-validation>
オプションがtrue
に設定されている場合、これを<background-validation-millis>
値と組み合わせて使用して、バックグラウンド検証を実行する頻度を決定します。<background-validation-millis>
パラメーターのデフォルト値は 0 ミリ秒です。これは、デフォルトで無効になっていることを意味します。この値は<idle-timeout-minutes>
設定とは違う値に設定してください。これは、特定のシステムに最適な<background-validation-millis>
値を決定するためのバランスを取る行為です。値が小さいほどプールの検証頻度が高くなり、より迅速に無効な接続がプールから削除されます。ただし、値が小さいほど、より多くのデータベースリソースが必要になります。値が大きいほど接続検証チェックの頻度が低くなり、データベースリソースの使用量が減りますが、無効な接続が検出されない期間が長くなります。
注記<validate-on-match>
オプションがtrue
に設定されている場合、<background-validation>
オプションはfalse
に設定する必要があります。その逆も同様です。<background-validation>
オプションがtrue
に設定されている場合、<validate-on-match>
オプションはfalse
に設定する必要があります。検証メカニズムの選択
以下のいずれかの検証メカニズムを選択します。<valid-connection-checker> クラス名を指定します
これは、使用中の特定の RDBMS に最適化されているため、推奨されるメカニズムです。JBoss EAP 6 は以下の接続チェッカーを提供します。- org.jboss.jca.adapters.jdbc.extensions.db2.DB2ValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLReplicationValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.novendor.JDBC4ValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.novendor.NullValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.oracle.OracleValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.sybase.SybaseValidConnectionChecker
<check-valid-connection-sql> に SQL を指定します
接続を検証するために使用する SQL ステートメントを提供します。以下は、Oracle 用接続を検証するために SQL ステートメントをどのように指定するかの例です。<check-valid-connection-sql>select 1 from dual</check-valid-connection-sql>
MySQL または PostgreSQL の場合は、以下の SQL ステートメントを指定する必要があります。<check-valid-connection-sql>select 1</check-valid-connection-sql>
<exception-sorter> クラス名を設定します。
例外が致命的とマークされた場合、接続はトランザクションに参加していてもすぐに閉じられます。致命的な接続例外を適切に検出およびクリーンアップするには、例外ソータークラスオプションを使用します。JBoss EAP 6 は、以下の例外ソーターを提供します。- org.jboss.jca.adapters.jdbc.extensions.db2.DB2ExceptionSorter
- org.jboss.jca.adapters.jdbc.extensions.informix.InformixExceptionSorter
- org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter
- org.jboss.jca.adapters.jdbc.extensions.novendor.NullExceptionSorter
- org.jboss.jca.adapters.jdbc.extensions.oracle.OracleExceptionSorter
- org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter
- org.jboss.jca.adapters.jdbc.extensions.sybase.SybaseExceptionSorter
- org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLExceptionSorter
12.6.2.5. データソースのパラメーター
表12.1 非 XA および XA データソースに共通のデータソースパラメーター
パラメーター | 説明 |
---|---|
jndi-name | データソースの一意の JNDI 名。 |
pool-name | データソースの管理プール名。 |
enabled | データソースが有効かどうかを指定します。 |
use-java-context |
データソースをグローバルの JNDI にバインドするかどうかを指定します。
|
spy |
JDBC レイヤーで
spy 機能を有効にします。この機能は、データソースへの JDBC トラフィックをすべてログに記録します。ロギングカテゴリーの jboss.jdbc.spy も logging サブシステムのログレベルである DEBUG に設定する必要があることに注意してください。
|
use-ccm | キャッシュ接続マネージャーを有効にします。 |
new-connection-sql | 接続プールに接続が追加された時に実行する SQL ステートメント。 |
transaction-isolation |
次のいずれかになります。
|
url-selector-strategy-class-name | インターフェイスを実装するクラスorg.jboss.jca.adapters.jdbc.URLSelectorStrategy 。 |
security |
セキュリティー設定である子要素が含まれています。表12.6「セキュリティーパラメーター」を参照してください。
|
検証 |
検証設定である子要素が含まれます。表12.7「検証パラメーター」を参照してください。
|
timeout |
タイムアウト設定である子要素が含まれています。表12.8「タイムアウトパラメーター」を参照してください。
|
statement |
ステートメント設定である子要素が含まれます。表12.9「ステートメントのパラメーター」を参照してください。
|
表12.2 非 XA データソースのパラメーター
パラメーター | Description |
---|---|
jta | XA 以外のデータソースの JTA 統合を有効にします。XA データソースには適用されません。 |
connection-url | JDBC ドライバーの接続 URL。 |
driver-class | JDBC ドライバークラスの完全修飾名。 |
connection-property |
メソッドに渡される任意の接続プロパティー
Driver.connect(url,props) 。各接続プロパティーは、文字列の名前と値のペアを指定します。プロパティー名は名前に由来し、値は要素の内容に由来します。
|
pool |
プーリング設定である子要素が含まれます。表12.4「非 XA および XA データソースに共通のプールパラメーター」を参照してください。
|
url-delimiter |
高可用性 (HA) クラスター化されたデータベースの connection-url にある URL の区切り文字。
|
表12.3 XA データソースのパラメーター
パラメーター | Description |
---|---|
xa-datasource-property |
実装クラス
XADataSource に割り当てるプロパティー。名前 = 値 で指定します。セッターメソッドが存在する場合は、次の形式でsetName 、プロパティーは、次の形式で setter メソッドを呼び出すことによって設定されます。setName(value) 。
|
xa-datasource-class |
実装クラスの完全修飾名
javax.sql.XADataSource 。
|
driver |
JDBC ドライバーを含むクラ出力ダーモジュールへの一意の参照。受け入れられる形式は driverName # majorVersion です。minorVersion。
|
xa-pool |
プーリング設定である子要素が含まれます。表12.4「非 XA および XA データソースに共通のプールパラメーター」 および 表12.5「XA プールパラメーター」 を参照してください。
|
recovery |
リカバリ設定である子要素が含まれています。表12.10「リカバリーパラメーター」を参照してください。
|
表12.4 非 XA および XA データソースに共通のプールパラメーター
パラメーター | Description |
---|---|
min-pool-size | プールが保持する最小接続数 |
max-pool-size | プールが保持可能な最大接続数 |
prefill | 接続プールを事前に入力するかどうか。デフォルトは false です。 |
use-strict-min | min-pool-size に達した後、アイドル接続スキャンがそれ以降の接続を閉じるためのマーキングを厳密に停止する必要があるかどうか。デフォルト値は false です。 |
flush-strategy |
エラーが発生した場合にプールがフラッシュされるかどうか。有効な値は以下のとおりです。
デフォルトは
FailingConnectionOnly です。
|
allow-multiple-users | 複数のユーザーが getConnection(user, password) メソッドを使いデータソースへアクセスするかどうか、および内部プールタイプがこの動作に対応するかを指定します。 |
表12.5 XA プールパラメーター
パラメーター | Description |
---|---|
is-same-rm-override | javax.transaction.xa.XAResource.isSameRM(XAResource) クラスが true または false を返すかどうか。 |
interleaving | XA 接続ファクトリーのインターリービングを有効にするかどうかを指定します。 |
no-tx-separate-pools |
コンテキストごとに個別のサブプールを作成するかどうか。これは、JTA トランザクションの内部と外部の両方で XA 接続を使用できない Oracle データソースに必要です。
このオプションを使用すると、実際のプールがつ作成されるため、合計プールサイズが
max-pool-size の倍になります。
|
pad-xid | Xid のパディングを行うかどうかを指定します。 |
wrap-xa-resource |
XAResource をラップするかどうか
org.jboss.tm.XAResourceWrapper 実例。
|
表12.6 セキュリティーパラメーター
パラメーター | Description |
---|---|
user-name | 新規接続の作成に使うユーザー名 |
password | 新規接続の作成に使うパスワード |
security-domain | 認証処理を行う JAAS security-manager の名前を含みます。この名前は、JAAS ログイン設定の application-policy/name 属性に相関します。 |
reauth-plugin | 物理接続の再認証に使う再認証プラグインを定義します。 |
表12.7 検証パラメーター
パラメーター | Description |
---|---|
valid-connection-checker |
インターフェイスの実装
org.jboss.jca.adaptors.jdbc.ValidConnectionChecker これはSQLException.isValidConnection(Connection e) 接続を検証するメソッド。接続が破棄されると例外が発生します。これは、パラメーター check-valid-connection-sql が存在する場合、それをオーバーライドします。
|
check-valid-connection-sql | プール接続の妥当性を確認する SQL ステートメント。これは、管理対象接続がプールから取得されて使用されるときに呼び出される場合があります。 |
validate-on-match |
接続ファクトリーが指定のセットに対して管理された接続に一致させようとした時に接続レベルの検証を実行するかどうかを示します。
一致検証に true を指定することは、通常、background-validation に true を指定することと組み合わせて実行されません。クライアントが使用前に接続を検証する必要がある場合は、Validate-on-match が必要です。このパラメーターはデフォルトで false です)。
|
background-validation |
接続がバックグラウンドスレッドで検証されることを指定します。バックグラウンド検証は、
validate-on-match で 使用しない場合のパフォーマンスの最適化です。validate-on-match が true の場合、background-validation を使用すると、冗長なチェックが発生する可能性があります。バックグラウンド検証では、使用するためにクライアントに不正な接続が提供される可能性があります (検証スキャンの時点からクライアントに渡される前までの間に接続が不良になる) ため、クライアントアプリケーションはこの可能性を考慮する必要があります。
|
background-validation-millis | バックグラウンド検証を実行する期間 (ミリ秒単位)。 |
use-fast-fail |
true の場合、接続が無効であれば最初に接続を割り当てしようとした時点で失敗します。デフォルトは
false です。
|
stale-connection-checker |
のインスタンス
org.jboss.jca.adapters.jdbc.StaleConnectionChecker ブール値を提供しますisStaleConnection(SQLException e) 方法。このメソッドが true を返す場合、例外はorg.jboss.jca.adapters.jdbc.StaleConnectionException 、のサブクラスですSQLException 。
|
exception-sorter |
のインスタンス
org.jboss.jca.adapters.jdbc.ExceptionSorter ブール値を提供しますisExceptionFatal(SQLException e) 方法。このメソッドは、例外がのすべてのインスタンスにブロードキャストされるかどうかを検証しますjavax.resource.spi.ConnectionEventListener connectionErrorOccurred メッセージとして。
|
表12.8 タイムアウトパラメーター
パラメーター | Description |
---|---|
use-try-lock | 用途tryLock() それ以外のlock() 。ロックが使用できない場合に即座に失敗するのではなく、タイムアウトする前に設定された秒数間ロックの取得を試みます。デフォルトは 60 秒です。例として、5 分のタイムアウトを設定するには、<use-try-lock> 300</use-try-lock> 。 |
blocking-timeout-millis | 接続の待機中にブロックする最大時間 (ミリ秒単位)。この時間を超えると、例外が出力されます。これは、接続の許可を待っている間のみブロックし、新しい接続の作成に時間がかかる場合でも例外を出力しません。デフォルトは 30000、つまり 30 秒です。 |
idle-timeout-minutes |
アイドル状態の接続が閉じられるまでの最大時間 (分単位)。指定がない場合、デフォルトは
30 分になります。実際の最大時間は、idleRemover スキャン時間によって異なります。これは、プールの最小の idle-timeout-minutes の半分です。
|
set-tx-query-timeout |
トランザクションがタイムアウトするまでの残り時間を基にクエリーのタイムアウトを設定するかどうかを指定します。トランザクションが存在しない場合は、設定されたクエリータイムアウトが使用されます。デフォルトは
false です。
|
query-timeout | クエリーのタイムアウト (秒単位)。デフォルトではタイムアウトはありません。 |
allocation-retry | 例外を出力する前に接続の割り当てを再試行する回数。デフォルトは 0 で、初回の割り当て失敗で例外が発生します。 |
allocation-retry-wait-millis |
接続の割り当てを再試行する前に待機する時間 (ミリ秒単位)。デフォルトは 5000、つまり 5 秒です。
|
xa-resource-timeout |
ゼロ以外の場合、この値はメソッドに渡されます
XAResource.setTransactionTimeout 。
|
表12.9 ステートメントのパラメーター
パラメーター | Description |
---|---|
track-statements |
接続がプールへ返され、ステートメントが準備済みステートメントキャッシュへ返された時に、閉じられていないステートメントをチェックするかどうか。false の場合、ステートメントは追跡されません。
有効な値
|
prepared-statement-cache-size | LRU (Least Recently Used) キャッシュにある接続毎の準備済みステートメントの数。 |
share-prepared-statements |
アプリケーションに提供されたラッパーがアプリケーションコードによって閉じられたときに、JBoss EAP が基盤の物理ステートメントを閉じたり終了せずに、キャッシュするかどうか。デフォルトは
false です。
|
表12.10 リカバリーパラメーター
パラメーター | Description |
---|---|
recover-credential | リカバリーに使用するユーザー名とパスワードのペア、あるいはセキュリティードメイン。 |
recover-plugin |
の実装
org.jboss.jca.core.spi.recoveryRecoveryPlugin クラス、リカバリに使用されます。
|
12.6.3. トランザクションログ
12.6.3.1. トランザクションログメッセージ
DEBUG
トランザクションロガーのログレベル。詳細なデバッグについては、TRACE
ログレベル。参照する「トランザクションサブシステムのログ設定」トランザクションロガーの設定についての情報。
TRACE
ログレベルでログを記録するよう設定すると、トランザクションマネージャー は多くのロギング情報を生成できます。最も一般的なメッセージの一部は次のとおりです。このリストは包括的ではないため、これら以外のメッセージが表示される場合があります。
表12.11 トランザクション状態の変更
トランザクションの開始 |
トランザクションが開始されると、次のコードが実行されます。
com.arjuna.ats.arjuna.coordinator.BasicAction::Begin:1342 tsLogger.logger.trace("BasicAction::Begin() for action-id "+ get_uid()); |
トランザクションのコミット |
トランザクションがコミットすると、次のコードが実行されます。
com.arjuna.ats.arjuna.coordinator.BasicAction::End:1342 tsLogger.logger.trace("BasicAction::End() for action-id "+ get_uid()); |
トランザクションのロールバック |
トランザクションがロールバックすると、次のコードが実行されます。
com.arjuna.ats.arjuna.coordinator.BasicAction::Abort:1575 tsLogger.logger.trace("BasicAction::Abort() for action-id "+ get_uid()); |
トランザクションのタイムアウト |
トランザクションがタイムアウトすると、次のコードが実行されます。
com.arjuna.ats.arjuna.coordinator.TransactionReaper::doCancellations:349 tsLogger.logger.trace("Reaper Worker " + Thread.currentThread() + " attempting to cancel " + e._control.get_uid());
この結果、上記のように同じスレッドがトランザクションをロールバックすることが示されます。
|
12.6.3.2. トランザクションサブシステムのログ設定
概要
この手順を使用して、JBoss EAP 6 の他のログ設定とは関係なく、トランザクションに関してログに記録される情報の量を制御します。主な手順は、Web ベースの管理コンソールでこれを行う方法を示しています。その後、管理 CLI コマンドが実行されます。
手順12.4 管理コンソールを使用したトランザクションロガーの設定
ログ設定領域に移動します。
管理コンソールで、Configuration タブをクリックします。管理対象ドメインを使用する場合は、左上の プロファイル 選択ボックスから、設定するサーバープロファイルを選択します。コア メニューを展開し、ログ を選択します。編集します
com.arjuna
属性。Log Categories タブを選択します。選択するcom.arjuna
詳細 セクションで 編集 をクリックします。ここで、クラス固有のログ情報を追加できます。Thecom.arjuna
クラスはすでに存在しています。ログレベルと、親ハンドラーを使用するかどうかを変更できます。- ログレベル
- ログレベルはデフォルトで
WARN
です。トランザクションは大量のログ出力を生成する可能性があるため、標準のログレベルの意味はトランザクションロガーではわずかに異なります。一般に、選択したレベルよりも低い重大度のレベルでタグ付けされたメッセージは破棄されます。トランザクションログのレベル (詳細度の高い順)
- TRACE
- DEBUG
- INFO
- WARN
- ERROR
- FAILURE
- 親ハンドラーの使用
- ロガーがその出力を親ロガーに送信する必要があるかどうか。デフォルトの動作は
true
です。
- 変更は直ちに反映されます。
12.6.3.3. トランザクションの参照と管理
log-store
と呼ばれるリソースとして公開します。と呼ばれる API 操作probe
トランザクションログを読み取り、ログごとにノードを作成します。あなたは呼び出すことができますprobe
コマンドを手動で更新する必要があるときはいつでもlog-store
。トランザクションログが即座に表示され非表示になるのは、正常な挙動です。
例12.2 ログストアの更新
default
を使用するサーバーグループに対してログストアを更新します。スタンドアローンサーバーの場合は、コマンドから profile=default
を削除します。
/profile=default/subsystem=transactions/log-store=log-store/:probe
例12.3 準備済みトランザクションすべての表示
ls /profile=default/subsystem=transactions/log-store=log-store/transactions
トランザクションの管理
- トランザクションの属性を表示します。
- JNDI 名、EIS 製品名とバージョン、またはそのステータスなどのトランザクションに関する情報を表示するには、
:read-resource
CLI コマンド。/profile=default/subsystem=transactions/log-store=log-store/transactions=0\:ffff7f000001\:-b66efc2\:4f9e6f8f\:9:read-resource
- トランザクションの参加者を表示します。
- 各トランザクションログには、という子要素が含まれています
participants
。使用read-resource
この要素に対する CLI コマンドを使用して、トランザクションの参加者を確認します。参加者は JNDI 名によって識別されます。/profile=default/subsystem=transactions/log-store=log-store/transactions=0\:ffff7f000001\:-b66efc2\:4f9e6f8f\:9/participants=java\:\/JmsXA:read-resource
結果は以下のようになります。{ "outcome" => "success", "result" => { "eis-product-name" => "HornetQ", "eis-product-version" => "2.0", "jndi-name" => "java:/JmsXA", "status" => "HEURISTIC", "type" => "/StateManager/AbstractRecord/XAResourceRecord" } }
ここに表示される結果ステータスはHEURISTIC
状態であり、回復の資格があります。詳細は、トランザクションをリカバリーします。 を参照してください。特別な場合では、ログに対応するトランザクションレコードがないオーファンレコード (XAResourceRecords) をオブジェクトストアに作成できます。たとえば、準備済みの XA リソースが TM の記録前にクラッシュし、ドメイン管理 API はアクセス不可能である場合などです。このようなレコードにアクセスするには、管理オプションexpose-all-logs
をtrue
に設定する必要があります。このオプションは管理モデルには保存されず、サーバーが再起動されるとfalse
に戻ります。/profile=default/subsystem=transactions/log-store=log-store:write-attribute(name=expose-all-logs, value=true)
- トランザクションを削除します。
- 各トランザクションログは、トランザクションを表すトランザクションログを削除する
:delete
操作をサポートします。/profile=default/subsystem=transactions/log-store=log-store/transactions=0\:ffff7f000001\:-b66efc2\:4f9e6f8f\:9:delete
- トランザクションをリカバリーします。
- 各トランザクション参加者は、
:recover
CLI コマンド。/profile=default/subsystem=transactions/log-store=log-store/transactions=0\:ffff7f000001\:-b66efc2\:4f9e6f8f\:9/participants=2:recover
ヒューリスティックなトランザクションと参加者のリカバリー
- トランザクションのステータスが
HEURISTIC
の場合、リカバリ操作は状態をPREPARE
に変更し、リカバリをトリガーします。 - トランザクションの参加者の 1 人がヒューリスティックである場合、リカバリ操作は再生を試みます
commit
手術。成功すると、参加者はトランザクションログから削除されます。これを確認するには、:probe
の操作log-store
参加者がリストされていないことを確認します。最後の参加者が削除されると、トランザクションも削除されます。
- リカバリーが必要なトランザクションの状態を更新します。
- トランザクションをリカバリーする必要がある場合は、リカバリーを試行する前に
:refresh
CLI コマンドを使用して、トランザクションのリカバリーが必要であるかを確認できます。/profile=default/subsystem=transactions/log-store=log-store/transactions=0\:ffff7f000001\:-b66efc2\:4f9e6f8f\:9/participants=2:refresh
トランザクション統計情報の表示
トランザクションマネージャーの統計が有効になっている場合は、トランザクションマネージャーとトランザクションサブシステムに関する統計を表示できます。見る「トランザクションマネージャーの設定」TransactionManager 統計を有効にする方法については。
表12.12 トランザクションサブシステム統計情報
統計 | 説明 | CLI コマンド |
---|---|---|
合計 |
このサーバー上でトランザクションマネージャーにより処理されるトランザクションの合計数。
| /host=master/server=server-one/subsystem=transactions/:read-attribute(name=number-of-transactions,include-defaults=true) |
Committed |
このサーバー上でトランザクションマネージャーにより処理されるコミット済みトランザクションの数。
| /host=master/server=server-one/subsystem=transactions/:read-attribute(name=number-of-committed-transactions,include-defaults=true) |
強制終了 |
このサーバー上でトランザクションマネージャーにより処理されるアボートされたトランザクションの数。
| /host=master/server=server-one/subsystem=transactions/:read-attribute(name=number-of-aborted-transactions,include-defaults=true) |
Timed Out |
このサーバー上でトランザクションマネージャーにより処理されるタイムアウトのトランザクションの数。
| /host=master/server=server-one/subsystem=transactions/:read-attribute(name=number-of-timed-out-transactions,include-defaults=true) |
Heuristics |
管理コンソールでは使用できません。ヒューリスティック状態のトランザクションの数。
| /host=master/server=server-one/subsystem=transactions/:read-attribute(name=number-of-heuristics,include-defaults=true) |
フライト状態のトランザクション |
管理コンソールでは使用できません。開始済みであるが終了されていないトランザクション数。
| /host=master/server=server-one/subsystem=transactions/:read-attribute(name=number-of-inflight-transactions,include-defaults=true) |
障害の原因 - アプリケーション |
障害の原因がアプリケーションであった失敗トランザクションの数。
| /host=master/server=server-one/subsystem=transactions/:read-attribute(name=number-of-application-rollbacks,include-defaults=true) |
障害の原因 - リソース |
障害の原因がリソースであった失敗トランザクションの数。
| /host=master/server=server-one/subsystem=transactions/:read-attribute(name=number-of-resource-rollbacks,include-defaults=true) |
参加者 ID |
参加者の ID。
| /host=master/server=server-one/subsystem=transactions/log-store=log-store/transactions=0\:ffff7f000001\:-b66efc2\:4f9e6f8f\:9:read-children-names(child-type=participants) |
トランザクションすべてのリスト |
トランザクションの完全リスト。
| /host=master/server=server-one/subsystem=transactions/log-store=log-store:read-children-names(child-type=transactions) |
12.7. JTA トランザクションを使用する
12.7.1. トランザクション JTA タスクの概要
はじめに
次の手順は、アプリケーションでトランザクションを使用する必要がある場合に役に立ちます。
12.7.2. トランザクションの制御
はじめに
この手順のリストでは、JTS API または JTS API を使用するアプリケーションでトランザクションを制御するさまざまな方法を概説します。
12.7.3. トランザクションの開始
UserTransaction
のインスタンスを取得します。@TransactionManagement(TransactionManagementType.BEAN)
アノテーションを用いると、JNDI、インジェクション、または EJB のコンテキスト EJB が Bean 管理のトランザクションを使用する場合) を使用してインスタンスを取得できます 。JNDI
new InitialContext().lookup("java:comp/UserTransaction")
注入
@Resource UserTransaction userTransaction;
コンテキスト
- ステートレス/ステートフル Bean の場合
@Resource SessionContext ctx; ctx.getUserTransaction();
- メッセージ駆動型 Bean の場合
@Resource MessageDrivenContext ctx; ctx.getUserTransaction()
UserTransaction
を呼び出します。begin()
データソースに接続した後。... try { System.out.println("\nCreating connection to database: "+url); stmt = conn.createStatement(); // non-tx statement try { System.out.println("Starting top-level transaction."); userTransaction.begin(); stmtx = conn.createStatement(); // will be a tx-statement ... } }
JTSAPI を使用して既存のトランザクションに参加します。
EJB (CMT または BMT のいずれかと使用) の利点の 1 つは、コンテナーがトランザクション処理の内部をすべて管理することです。 そのため、ユーザーは EAP コンテナー間の XA トランザクションまたはトランザクションディストリビューションの一部であるトランザクションを処理する必要がありません。
結果:
トランザクションが開始します。トランザクションをコミットまたはロールバックするまで、データソースの使用はすべてトランザクションになります。
12.7.4. Nested Transactions
12.7.5. トランザクションのコミット
要件
トランザクションは、コミットする前に開始する必要があります。トランザクションの開始方法については、を参照してください。「トランザクションの開始」。
電話する
commit()
UserTransaction
のメソッド。あなたが電話するときcommit()
UserTransaction
のメソッドである場合、トランザクションマネージャーはトランザクションのコミットを試みます。@Inject private UserTransaction userTransaction; public void updateTable(String key, String value) EntityManager entityManager = entityManagerFactory.createEntityManager(); try { userTransaction.begin(): <!-- Perform some data manipulation using entityManager --> ... // Commit the transaction userTransaction.commit(); } catch (Exception ex) { <!-- Log message or notify Web page --> ... try { userTransaction.rollback(); } catch (SystemException se) { throw new RuntimeException(se); } throw new RuntimeException(e); } finally { entityManager.close(); } }
CMT (Container Managed Transaction) を使用する場合は、手動でコミットする必要はありません。
Bean がコンテナー管理トランザクションを使用するよう設定すると、コンテナーはコードで設定したアノテーションに基づいてトランザクションライフサイクルを管理します。@PersistenceContext private EntityManager em; @TransactionAttribute(TransactionAttributeType.REQUIRED) public void updateTable(String key, String value) <!-- Perform some data manipulation using entityManager --> ... }
結果
データソースがコミットされ、トランザクションが終了します。 そうでない場合は、例外が発生します。
12.7.6. トランザクションのロールバック
要件
トランザクションは、ロールバックする前に開始する必要があります。トランザクションの開始方法については、を参照してください。「トランザクションの開始」。
電話する
rollback()
UserTransaction
のメソッド。あなたが電話するときrollback()
UserTransaction
のメソッドである場合、トランザクションマネージャーはトランザクションをロールバックし、データを以前の状態に戻そうとします。@Inject private UserTransaction userTransaction; public void updateTable(String key, String value) EntityManager entityManager = entityManagerFactory.createEntityManager(); try { userTransaction.begin(): <!-- Perform some data manipulation using entityManager --> ... // Commit the transaction userTransaction.commit(); } catch (Exception ex) { <!-- Log message or notify Web page --> ... try { userTransaction.rollback(); } catch (SystemException se) { throw new RuntimeException(se); } throw new RuntimeException(e); } finally { entityManager.close(); } }
CMT (Container Managed Transaction) を使用する場合は、トランザクションを手動でロールバックする必要はありません。
Bean がコンテナー管理トランザクションを使用するよう設定すると、コンテナーはコードで設定したアノテーションに基づいてトランザクションライフサイクルを管理します。注記CMT のロールバックは RuntimeException が発生すると実行されます。setRollbackOnly
メソッドを明示的に呼び出してロールバックを発生させることもできます。または、アプリケーション例外の@ApplicationException(rollback=true
) を使用してロールバックできます。
結果
トランザクションは、トランザクションマネージャーによってロールバックされます。
12.7.7. トランザクションにおけるヒューリスティックな結果の処理方法
手順12.5 トランザクションにおけるヒューリスティックな結果の処理方法
原因を確認する
トランザクションのヒューリスティックな結果の最大の原因は、リソースマネージャーがコミットまたはロールバックの実行を約束したにも関わらず、約束を守らなかったことにあります。原因としては、サードパーティーコンポーネント、サードパーティーコンポーネントと JBoss EAP 6 間の統合レイヤー、または JBoss EAP 6 自体の問題が考えられます。ヒューリスティックなエラーの最も一般的な 2 つの原因は、環境での一時的な障害と、リソースマネージャー対応時のコーディングエラーです。環境の一時的な障害を修正する
通常、環境内で一時的な障害が発生した場合は、ヒューリスティックなエラーを発見する前に気づくはずです。ネットワークの停止、ハードウェア障害、データベース障害、電源異常などが考えられます。テスト環境でヒューリスティックな結果を経験した場合、ストレステスト中に、環境の弱点に関する情報が提供されます。ヒューリスティックトランザクションは回復されませんJBoss EAP 6 は、障害時に非ヒューリスティック状態であったトランザクションを自動的に回復しますが、ヒューリスティックトランザクションの回復は試みません。リソースマネージャーベンダーに連絡する
環境に明白な障害が発生していない場合や、ヒューリスティックな結果を簡単に再現できる場合は、おそらくコーディングエラーです。サードパーティーベンダーに連絡して、解決策が利用可能かどうかを確認してください。問題が JBoss EAP 6 自体のトランザクションマネージャーにあると思われる場合は、Red Hat グローバルサポートサービスに連絡してください。テスト環境で、ログを削除して JBoss EAP 6 を再起動します。
テスト環境である場合や、データの整合性を気にしない場合は、トランザクションログを削除して JBoss EAP 6 を再起動すると、ヒューリスティックな結果はなくなります。トランザクションログは、デフォルト
では、スタンドアロンサーバーの場合は EAP_HOME/Standalone/data/tx-object-store/に、管理対象ドメインの場合はEAP_HOME/domain/servers/SERVER_NAME/data/tx-object-store
にあります。管理対象ドメインの場合、SERVER_NAME は、サーバーグループに参加している個々のサーバー名を示します。注記トラザクションログの場所は、使用中のオブジェクトストアや、object-store-relative-to
およびobject-store-path
パラメーターに設定された値にも左右されます。ファイルシステムログ (標準のシャドウログや HornetQ ログなど) の場合、デフォルトの方向の場所が使用されますが、JDBC オブジェクトストアを使用する場合、トランザクションログはデータベースに保存されます。手作業で結果を解決する
トランザクションの結果を手動で解決するプロセスは、障害の正確な状況に大きく依存します。通常、次の手順を実行して、状況に適用する必要があります。- 関係しているリソースマネージャーを特定します。
- トランザクションマネージャーとリソースマネージャーの状態を調べます。
- 関係するコンポーネントの 1 つまたは複数で、ログの消去とデータの照合を手動で強制します。
これらの手順を実行する方法の詳細は、このドキュメントの範囲外です。
12.7.8. トランザクションタイムアウト
12.7.8.1. トランザクションタイムアウト
12.7.8.2. トランザクションマネージャーの設定
default
、次の方法で手順とコマンドを変更する必要がある場合があります。
例のコマンドに関する注意点
- 管理コンソールの場合、
default
プロファイルは、コンソールに最初にログインしたときに選択されるプロファイルです。別のプロファイルでトランザクションマネージャーの設定を変更する必要がある場合は、代わりにプロファイルを選択してくださいdefault
、各命令で。同様に、プロファイルをdefault
サンプル CLI コマンドのプロファイル。 - スタンドアロンサーバーを使用する場合、プロファイルは 1 つだけ存在します。特定のプロファイルを選択するための指示は無視してください。CLI コマンドで、
/profile=default
サンプルコマンドの一部。
transactions
サブシステムを有効にする必要があります。これはデフォルトで有効になっており、他の多くのサブシステムが正しく機能するために必要であるため、無効になる可能性はほとんどありません。
管理コンソールを使用した TM の設定
Web ベースの管理コンソールを使用して TM を設定するには、画面上部の 設定 タブを選択します。管理対象ドメインを使用している場合は、左上の プロファイル 選択ボックスから正しいプロファイルを選択してください。コンテナー メニューを展開し、トランザクション を選択します。
管理 CLI を使用した TM の設定
管理 CLI では、一連のコマンドを使用して TM を設定できます。コマンドはすべてで始まります/profile=default/subsystem=transactions/
プロファイル付きの管理対象ドメインの場合default
、また/subsystem=transactions
スタンドアロンサーバーの場合。
表12.13 TM 設定オプション
オプション | 説明 | CLI コマンド |
---|---|---|
統計の有効化 (Enable Statistics)
|
トランザクション統計を有効にするかどうか。これらの統計は、ランタイム タブの サブシステムメトリック セクションの管理コンソールで表示できます。
| /profile=default/subsystem=transactions/:write-attribute(name=enable-statistics,value=true)
|
Enable TSM Status
|
アウトオブプロセスのリカバリーに使用される TSM (トランザクションステータスマネージャー) サービスを有効にするかどうか。アウトオブプロセスリカバリマネージャーを実行して、別のプロセスから ActionStatusService に接続することはサポートされていません (通常はメモリー内で接続されます)。
|
この設定オプションはサポートされていません。
|
デフォルトのタイムアウト (Default Timeout)
|
デフォルトのトランザクションタイムアウトです。デフォルトでは
300 秒に設定されています。トランザクションごとにプログラムで上書きできます。
| /profile=default/subsystem=transactions/:write-attribute(name=default-timeout,value=300)
|
オブジェクトストアパス (Object Store Path)
|
TM オブジェクトストアがデータを格納する相対または絶対ファイルシステムパス。デフォルトでは、
object-store-relative-to パラメーターの値。
| /profile=default/subsystem=transactions/:write-attribute(name=object-store-path,value=tx-object-store)
|
オブジェクトストアパスに相対的 (Object Store Path Relative To)
|
ドメインモデルのグローバルなパス設定を参照します。デフォルト値は、JBoss EAP 6 のデータディレクトリーで、
jboss.server.data.dir プロパティーの値です。デフォルトは、管理対象ドメインの場合は EAP_HOME/domain/data/ 、スタンドアロンサーバーインスタンスの場合は EAP_HOME/standalone/data/ です。オブジェクトストアの値object-store-path TM 属性は、このパスに関連しています。
| /profile=default/subsystem=transactions/:write-attribute(name=object-store-relative-to,value=jboss.server.data.dir)
|
ソケットバインディング
|
ソケットベースのメカニズムが使用されている場合に、トランザクションマネージャーが回復およびトランザクション ID の生成に使用するソケットバインディングの名前を指定します。参照する
process-id-socket-max-ports 一意の識別子の生成の詳細については。ソケットバインディングは、管理コンソールの サーバー タブでサーバーグループごとに指定されます。
| /profile=default/subsystem=transactions/:write-attribute(name=socket-binding,value=txn-recovery-environment)
|
Status Socket Binding
|
トランザクションステータスマネージャーに使用するソケットバインディングを指定します。
|
この設定オプションはサポートされていません。
|
リカバリーリスナー (Recovery Listener)
|
トランザクションリカバリーのプロセスがネットワークソケットをリッスンするかどうかを指定します。デフォルトは
false です。
| /profile=default/subsystem=transactions/:write-attribute(name=recovery-listener,value=false)
|
表12.14 高度な TM 設定オプション
オプション | 説明 | CLI コマンド |
---|---|---|
jts
|
Java Transaction Service (JTS) トランザクションを使用するかどうかを指定します。デフォルト値は
false で、JTA トランザクションのみを使用します。
| /profile=default/subsystem=transactions/:write-attribute(name=jts,value=false)
|
node-identifier
|
トランザクションマネージャーのノード識別子。このオプションは以下の場合に必要になります。
node-identifier は一意である必要があります。複数のノードが同じリソースマネージャーと対話したり、トランザクションオブジェクトストアを共有したりするため、node-identifier は JTA に対しても一意である必要があります。
| /profile=default/subsystem=transactions/:write-attribute(name=node-identifier,value=1)
|
process-id-socket-max-ports
|
トランザクションマネージャーは、各トランザクションログに対し一意の識別子を作成します。一意の識別子を生成するメカニズムは 2 種類あります。 ソケットベースのメカニズムとプロセスのプロセス識別子をベースにしたメカニズムです。
ソケットベースの識別子の場合、あるソケットを開くと、そのポート番号が識別子に使用されます。ポートがすでに使用されている場合は、空きのポートが見つかるまで次のポートがプローブされます。The
process-id-socket-max-ports TM が失敗する前に試行するソケットの最大数を表します。デフォルト値は 10 です。
| /profile=default/subsystem=transactions/:write-attribute(name=process-id-socket-max-ports,value=10)
|
process-id-uuid
| true に設定すると、プロセス識別子を使用して各トランザクションに一意の識別子が作成されます。そうでない場合は、ソケットベースのメカニズムが使用されます。デフォルトは true です。詳細は、process-id-socket-max-ports を参照してください。有効にするprocess-id-socket-binding 、設定process-id-uuid にfalse 。
| /profile=default/subsystem=transactions/:write-attribute(name=process-id-uuid,value=true)
|
process-id-socket-binding
|
トランザクションマネージャーがソケットベースのプロセス id を使用する必要がある場合に使用するソケットバインディング設定の名前。になります
undefined もしもprocess-id-uuid はtrue ;それ以外の場合は設定する必要があります。
| /profile=default/subsystem=transactions/:write-attribute(name=process-id-socket-binding,value=true)
|
use-hornetq-store
|
トランザクションログには、ファイルベースのストレージではなく、HornetQ のジャーナルストレージメカニズムを使用します。デフォルトでは無効になっていますが、I/O パフォーマンスが改善されます。別々のトランザクションマネージャーで JTS トランザクションを使用することは推奨されません。このオプションの変更を反映するには shutdown コマンドを使用してサーバーを再起動する必要があります。
| /profile=default/subsystem=transactions/:write-attribute(name=use-hornetq-store,value=false)
|
12.7.9. JTA トランザクションのエラー処理
12.7.9.1. トランザクションエラーの処理
トランザクションがタイムアウトになったが、ビジネスロジックスレッドが認識しませんでした。
多くの場合、このようなエラーは、Hibernate がレイジーロードのデータベース接続を取得できない場合に発生します。頻繁に発生する場合は、タイムアウト値を増加できます。「トランザクションマネージャーの設定」 を参照してください。
トランザクションはすでにスレッドで実行されているか、NotSupportedException
例外
The NotSupportedException
例外は通常、JTA トランザクションをネストしようとしたことを示しますが、これはサポートされていません。トランザクションをネストしようとしないときは、多くの場合、スレッドプールタスクで別のトランザクションが開始されますが、トランザクションを中断または終了せずにタスクが終了します。
UserTransaction
、これを自動的に処理します。その場合、フレームワークに問題がある可能性があります。
TransactionManager
また Transaction
メソッドを直接使用する場合は、トランザクションをコミットまたはロールバックするときに次の動作に注意してください。コードで TransactionManager
メソッドを使用してトランザクションを制御する場合は、トランザクションをコミットまたはロールバックすると、現在のスレッドからトランザクションの関連付けが解除されます。ただし、コードで Transaction
メソッドを使用する場合は、トランザクションが実行されているスレッドと関連付けられていないことがあり、スレッドプールに返す前に手動でスレッドからトランザクションの関連付けを解除する必要があります。
2 番目のローカルリソースを登録することはできません。
このエラーは、2 番目の非 XA リソースをトランザクションに登録しようとした場合に、発生します。1 つのトランザクションで複数のリソースが必要な場合、それらのリソースは XA である必要があります。
12.8. ORB 設定
12.8.1. Common Object Request Broker Architecture (CORBA)
12.8.2. JTS トランザクション用 ORB の設定
手順12.6 管理コンソールを使用した ORB の設定
プロファイル設定の表示
管理コンソールの上部から 設定 を選択します。管理対象ドメインを使用する場合は、左上の選択ボックスから フル または フルヘクタールの プロファイルを選択します。イニシャライザ の設定を変更する
サブシステム メニューを展開します。コンテナー メニューを展開し、JacORB を選択します。メイン画面に表示されるフォームで、初期化 タブを選択し、編集 ボタンをクリックします。Security の値をon に
設定して、セキュリティーインターセプターを有効にします。JTS の ORB を有効にするには、Transaction Interceptors の値をデフォルトの仕様
ではなく、on
に設定します。ヘルプが必要ですか? を参照してください。これらの値の詳細な説明については、フォームのリンクを参照してください。値の編集が終了したら、保存 をクリックします。高度な ORB 設定
高度な設定オプションについては、フォームの他のセクションを参照してください。各セクションには ヘルプが必要ですか? パラメーターに関する詳細情報へのリンク。
管理 CLI を使用して ORB を設定
管理 CLI を使用して ORB を設定できます。次のコマンドは、管理コンソールの初期化子を上記の手順と同じ値に設定します。これは、JTS と使用するために行う ORB の最低限の設定です。
/profile=full
部分を省略してください。
例12.4 セキュリティーインターセプターの有効化
/profile=full/subsystem=jacorb/:write-attribute(name=security,value=on)
例12.5 JacORB サブシステムでのトラザクションの有効化
/profile=full/subsystem=jacorb/:write-attribute(name=transactions,value=on)
例12.6 トランザクションサブシステムでの JTS の有効化
/profile=full/subsystem=transactions:write-attribute(name=jts,value=true)
12.9. トランザクションに関するリファレンス
12.9.1. JBoss Transactions エラーと例外
UserTransaction
クラスのメソッドによって発生する例外の詳細については、『UserTransaction API』 仕様 (http://docs.oracle.com/javaee/6/api/javax/transaction/UserTransaction.html) を参照してください。
12.9.2. JTA トランザクションの例
例12.7 JTA トランザクションの例
public class JDBCExample { public static void main (String[] args) { Context ctx = new InitialContext(); // Change these two lines to suit your environment. DataSource ds = (DataSource)ctx.lookup("jdbc/ExampleDS"); Connection conn = ds.getConnection("testuser", "testpwd"); Statement stmt = null; // Non-transactional statement Statement stmtx = null; // Transactional statement Properties dbProperties = new Properties(); // Get a UserTransaction UserTransaction txn = new InitialContext().lookup("java:comp/UserTransaction"); try { stmt = conn.createStatement(); // non-tx statement // Check the database connection. try { stmt.executeUpdate("DROP TABLE test_table"); stmt.executeUpdate("DROP TABLE test_table2"); } catch (Exception e) { // assume not in database. } try { stmt.executeUpdate("CREATE TABLE test_table (a INTEGER,b INTEGER)"); stmt.executeUpdate("CREATE TABLE test_table2 (a INTEGER,b INTEGER)"); } catch (Exception e) { } try { System.out.println("Starting top-level transaction."); txn.begin(); stmtx = conn.createStatement(); // will be a tx-statement // First, we try to roll back changes System.out.println("\nAdding entries to table 1."); stmtx.executeUpdate("INSERT INTO test_table (a, b) VALUES (1,2)"); ResultSet res1 = null; System.out.println("\nInspecting table 1."); res1 = stmtx.executeQuery("SELECT * FROM test_table"); while (res1.next()) { System.out.println("Column 1: "+res1.getInt(1)); System.out.println("Column 2: "+res1.getInt(2)); } System.out.println("\nAdding entries to table 2."); stmtx.executeUpdate("INSERT INTO test_table2 (a, b) VALUES (3,4)"); res1 = stmtx.executeQuery("SELECT * FROM test_table2"); System.out.println("\nInspecting table 2."); while (res1.next()) { System.out.println("Column 1: "+res1.getInt(1)); System.out.println("Column 2: "+res1.getInt(2)); } System.out.print("\nNow attempting to rollback changes."); txn.rollback(); // Next, we try to commit changes txn.begin(); stmtx = conn.createStatement(); ResultSet res2 = null; System.out.println("\nNow checking state of table 1."); res2 = stmtx.executeQuery("SELECT * FROM test_table"); while (res2.next()) { System.out.println("Column 1: "+res2.getInt(1)); System.out.println("Column 2: "+res2.getInt(2)); } System.out.println("\nNow checking state of table 2."); stmtx = conn.createStatement(); res2 = stmtx.executeQuery("SELECT * FROM test_table2"); while (res2.next()) { System.out.println("Column 1: "+res2.getInt(1)); System.out.println("Column 2: "+res2.getInt(2)); } txn.commit(); } catch (Exception ex) { ex.printStackTrace(); System.exit(0); } } catch (Exception sysEx) { sysEx.printStackTrace(); System.exit(0); } } }
12.9.3. JBossTransactionsJTA の API ドキュメント
12.9.4. XA リカバリープロセスの制限
- トランザクションログが正常にコミットされたトランザクションから消去されないことがあります。
XAResource
のコミットメソッドが正常に完了し、トランザクションをコミットした後、コーディネーターがログをアップデートできるようになる前に JBoss EAP サーバーがクラッシュした場合、サーバーの再起動時に以下の警告メッセージが表示されることがあります。ARJUNA016037: Could not find new XAResource to use for recovering non-serializable XAResource XAResourceRecord
これは、リカバリー時に JBoss トランザクションマネージャー はログのトランザクション参加者を確認し、コミットを再試行しようとするからです。最終的に、JBoss Transaction Manager はリソースがコミットされていると想定し、コミットを再試行しなくなります。このような場合、トランザクションはコミットされデータの損失はないため、警告を無視しても問題ありません。警告を防ぐには、com.arjuna.ats.jta.xaAssumeRecoveryCompleteプロパティー値をtrue
に設定します。このプロパティーは、登録されたXAResourceRecovery
インスタンスから新しいXAResource
インスタンスが見つからないとチェックされます。true
に設定すると、リカバリーで、以前のコミットの試行が成功したと見なされ、これ以上リカバリーを試行しなくてもインスタンスをログから削除できます。このプロパティーはグローバルであり、適切に使用しないとXAResource
インスタンスがコミットされていない状態のままになるため、注意して使用する必要があります。- XAResource.prepare() の最後にサーバーがクラッシュすると、JTS トランザクションに対するロールバックは呼び出されません。
XAResource
の完了後に JBoss EAP サーバーがクラッシュした場合prepare()
メソッド呼び出しでは、参加しているすべての XAResources が準備済み状態でロックされ、サーバーの再起動時にその状態が維持されます。トランザクションがタイムアウトするか、DBA が手動でリソースをロールバックしてトランザクションをクリアするまで、トランザクションはロールバックされず、リソースはロックされたままになります。ログ。- 周期リカバリーはコミットされたトランザクションで発生する可能性があります。
- サーバーに過剰な負荷がかかっている場合、サーバーログには以下の警告メッセージとそれに続くスタックトレースが含まれる場合があります。
ARJUNA016027: Local XARecoveryModule.xaRecovery got XA exception XAException.XAER_NOTA: javax.transaction.xa.XAException
負荷が大きい場合、トランザクションにかかる処理時間が周期的リカバリープロセスのアクティビティーと重なることがあります。周期的リカバリープロセスは進行中のトランザクションを検出し、ロールバックを開始しようとしますが、トランザクションは完了するまで続行されます。周期的リカバリーはロールバックの開始に失敗し、ロールバックの失敗がサーバーログに記録されます。この問題の根本的な原因は、今後のリリースで修正される予定ですが、現時点では回避方法を使用できます。を設定して、リカバリプロセスの 2 つのフェーズ間の間隔を増やします。com.arjuna.ats.jta.orphanSafetyIntervalプロパティーをデフォルト値の 10000 ミリ秒よりも高い値に設定します。40000 ミリ秒の値が推奨されます。これで問題が解決するわけではなく、発生する可能性が低くなり、警告メッセージがログに表示されることに注意してください。
第13章 Hibernate
13.1. Hibernate Core
13.2. Java 永続 API (JPA)
13.2.1. JPA について
bean-validation
、greeter
、および kitchensink
クイックスタートを参照してください。「クイックスタートにアクセスする」。
13.2.2. Hibernate EntityManager
13.2.3. はじめに
13.2.3.1. Red Hat JBossDeveloperStudio で JPA プロジェクトを作成します
概要
この例では、Red Hat JBossDeveloperStudio で JPA プロジェクトを作成するために必要な手順について説明します。
手順13.1 Red Hat JBossDeveloperStudio で JPA プロジェクトを作成します
- Red Hat JBoss Developer Studio ウィンドウ で+、 → FileNewProject をクリックします。リストで JPA を見つけ、展開し、JPA Project を選択します。以下のダイアログが表示されます。
[D] - プロジェクト名を入力します。
- Target runtime を選択します。使用可能なターゲットランタイムがない場合は、次の手順に従って新しいサーバーとランタイムを定義します。「Define New Server を使用して JBossEAP サーバーを追加します」。
- JPA version (JPA バージョン) で 2.1 が選択されていることを確認します。
- Configuration (設定) で Basic JPA Configuration (基本的な JPA 設定) を選択します。
- Finish をクリックします。
- 要求されたら、このタイプのプロジェクトを JPA パースペクティブウインドウに関連付けるかどうかを選択します。
13.2.3.2. Red Hat JBossDeveloperStudio で永続性設定ファイルを作成します
概要
このトピックでは、Red Hat JBossDeveloperStudio を使用して Java プロジェクトで persistence.xml
ファイルを作成するプロセスについて説明します。
手順13.2 新しい永続性設定ファイルを作成および設定します。
- Red Hat JBossDeveloperStudio で EJB3.x プロジェクトを開きます。
- Project Explorer (プロジェクトエクスプローラー) パネルでプロジェクトルートディレクトリーを右クリックします。
- 新規 → その他... を選択します。
- XML フォルダーから XML File (XML ファイル) を選択し、Next (次へ) をクリックします。
- 親ディレクトリーとして
ejbModule/META-INF
フォルダーを選択します。 - ファイルの名前を
persistence.xml
と指定し、Next (次へ) をクリックします。 - Create XML file from an XML schema file (XML スキーマファイルから XML ファイルを作成) を選択し、Next (次へ) をクリックします。
- Select XML Catalog entry (XML カタログエントリーを選択) リストから http://java.sun.com/xml/ns/persistence/persistence_2.0.xsd を選択し、Next (次へ) をクリックします。
[D] - Finish (完了) をクリックしてファイルを作成します。
- 結果:
13.2.3.3. 例: 永続設定ファイル
例13.1 persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> <persistence-unit name="example" transaction-type="JTA"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <mapping-file>ormap.xml</mapping-file> <jar-file>TestApp.jar</jar-file> <class>org.test.Test</class> <shared-cache-mode>NONE</shared-cache-mode> <validation-mode>CALLBACK</validation-mode> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit> </persistence>
13.2.3.4. Red Hat JBossDeveloperStudio で Hibernate 設定ファイルを作成します
概要
このトピックでは、Red Hat JBossDeveloperStudio を使用して Java プロジェクトで hibernate.cfg.xml
ファイルを作成するプロセスについて説明します。
手順13.3 新しい Hibernate 設定ファイルを作成する
- Red Hat JBossDeveloperStudio で Java プロジェクトを開きます。
- Project Explorer (プロジェクトエクスプローラー) パネルでプロジェクトルートディレクトリーを右クリックします。
- 新規 → その他... を選択します。
- Hibernate フォルダーから Hibernate 設定ファイル を選択し、次へ をクリックします。
src/
ディレクトリーを選択し、次へ をクリックします。- 以下を設定します。
- セッションファクトリー名
- データベース方言
- Driver class
- 接続 URL
- ユーザ名
- パスワード
- Finish (完了) をクリックしてファイルを作成します。
- 結果:
13.2.3.5. Hibernate 設定ファイルの例
例13.2 hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Datasource Name --> <property name="connection.datasource">ExampleDS</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.H2Dialect</property> <!-- Enable Hibernate's automatic session context management --> <property name="current_session_context_class">thread</property> <!-- Disable the second-level cache --> <property name="cache.region.factory_class">org.hibernate.cache.NoCacheProvider</property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property> <!-- Update the database schema on startup --> <property name="hbm2ddl.auto">update</property> <mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/> </session-factory> </hibernate-configuration>
13.2.4. 設定
13.2.4.1. Hibernate 設定プロパティー
表13.1 HibernateJava プロパティー
プロパティー名 | Description |
---|---|
hibernate.dialect |
Hibernate
org.hibernate. metaect.Dialect のクラス名。Hibernate が特定の関係データベース向けに最適化された SQL を生成できるようにします。
ほとんどの場合、Hibernate は JDBC ドライバーによって返される
JDBC metadata に基づいて適切な org.hibernate. metaect.Dialect 実装を選択できます。
|
hibernate.show_sql |
ブール値。すべての SQL ステートメントをコンソールに書き込みます。これは、ログカテゴリー
org.hibernate.SQL を debug に設定する代わりになります。
|
hibernate.format_sql |
ブール値。pretty print で、ログとコンソールに SQL を出力します。
|
hibernate.default_schema |
生成された SQL で指定のスキーマ/テーブルスペースを持つ修飾されていないテーブル名。
|
hibernate.default_catalog |
生成された SQL で指定のカタログと修飾されていないテーブル名を修飾します。
|
hibernate.session_factory_name |
その
org.hibernate.SessionFactory 作成後、JNDI でこの名前に自動的にバインドされます。たとえば、jndi/composite/name です。
|
hibernate.max_fetch_depth |
単独の関連 (one-to-one、many-to-one) の外部結合フェッチツリーの最大深さを設定します。
0 は、デフォルトの外部ジョインフェッチを無効にします。推奨の値は 0 から 3 の間です。
|
hibernate.default_batch_fetch_size |
関連付けの Hibernate バッチフェッチのデフォルトサイズを設定します。推奨される値は
4 、8 、16 です。
|
hibernate.default_entity_mode |
この
SessionFactory か ら開かれたすべてのセッションに対するエンティティー表現のデフォルトモードを設定します。値には dynamic-map 、dom4j 、pojo が含まれます。
|
hibernate.order_updates |
ブール値。Hibernate は、更新する製品のプライマリーキーの値で SQL 更新の順序を強制します。これにより、非常に同時になるシステムでは、トランザクションのデッドロックが少なくなります。
|
hibernate.generate_statistics |
ブール値。有効にすると、Hibernate はパフォーマンスチューニングに役立つ統計を収集します。
|
hibernate.use_identifier_rollback |
ブール値。有効な場合、オブジェクトが削除されると、生成された識別子プロパティーがデフォルト値にリセットされます。
|
hibernate.use_sql_comments |
ブール値。有効にすると、Hibernate はデバッグを容易にするため、SQL 内でコメントを生成します。デフォルト値は
false です。
|
hibernate.id.new_generator_mappings |
ブール値。
@GeneratedValue を使用する場合、このプロパティーには関係があります。これは、新しい IdentifierGenerator 実装が javax.persistence.GenerationType.AUTO 、javax.persistence.GenerationType.TABLE および javax.persistence.GenerationType.SEQUENCE に使用されるかどうかを示します。デフォルト値は true です。
|
hibernate.ejb.naming_strategy |
を選択します
org.hibernate.cfg.NamingStrategy HibernateEntityManager を使用する場合の実装。このクラスは非推奨であり、このプロパティーは下位互換性のためにのみ提供されています。このプロパティーは、と一緒に使用しないでくださいhibernate.ejb.naming_strategy_delegator 。
アプリケーションが EntityManager を使用しない場合は、以下の手順に従って NamingStrategy: Hibernate Reference Documentation - Implementing a Naming Strategy を設定します。
|
hibernate.ejb.naming_strategy_delegator |
指定します
org.hibernate.cfg.naming.NamingStrategyDelegator HibernateEntityManager を使用する場合のデータベースオブジェクトとスキーマ要素の実装。このプロパティーには、次の可能な値があります。
注記
このプロパティーは、と一緒に使用しないでください hibernate.ejb.naming_strategy 。の一時的な代替品ですorg.hibernate.cfg.NamingStrategy その制限に対処するため。両方を置き換える Hibernate5.0 のより包括的なソリューションが計画されていますorg.hibernate.cfg.NamingStrategy とorg.hibernate.cfg.naming.NamingStrategyDelegator 。
アプリケーションが EntityManager を使用しない場合は、以下の手順に従って NamingStrategy: Hibernate Reference Documentation - Implementing a Naming Strategy を設定します。
|
hibernate.id.new_generator_mappings
の場合、新しいアプリケーションでは、デフォルト値である true
のままにしてください。Hibernate 3.3.x を使用した既存のアプリケーションは、シーケンスオブジェクトまたはテーブルベースのジェネレーターを使用し、後方互換性を維持するために false
に変更する必要がある場合があります。
13.2.4.2. Hibernate JDBC および接続プロパティー
表13.2 プロパティー
プロパティー名 | Description |
---|---|
hibernate.jdbc.fetch_size |
JDBC フェッチサイズを決定するゼロ以外の値 (
Statement.setFetchSize() を呼び出します)。
|
hibernate.jdbc.batch_size |
ゼロ以外の値は、Hibernate による JDBC2 バッチ更新の使用を有効にします。推奨される値は
5 から 30 の間です。
|
hibernate.jdbc.batch_versioned_data |
ブール値。JDBC ドライバーが
executeBatch() から正しい行数を返す場合は、このプロパティーを true に設定します。その後、Hibernate は、自動的にバージョン付けされたデータにバッチ処理を使用します。デフォルト値は false です。
|
hibernate.jdbc.factory_class |
カスタムを選択
org.hibernate.jdbc.Batcher .ほとんどのアプリケーションでは、この設定プロパティーは必要ありません。
|
hibernate.jdbc.use_scrollable_resultset |
ブール値。Hibernate による JDBC2 のスクロール可能な結果セットの使用を有効にします。このプロパティーは、ユーザー指定の JDBC 接続を使用する場合にのみ必要です。Hibernate は接続メタデータを使用します。
|
hibernate.jdbc.use_streams_for_binary |
ブール値。これはシステムレベルのプロパティーです。
binary または serializable を JDBC に書き込む際や、JDBC から読み込む際には、ストリームを使用します。
|
hibernate.jdbc.use_get_generated_keys |
ブール値。JDBC3 の
PreparedStatement.getGeneratedKeys() を使用して、挿入後にネイティブに生成されたキーを取得できます。JDBC3+ ドライバーおよび JRE1.4+ が必要です。JDBC ドライバーに、Hibernate 識別子ジェネレーターの問題がある場合は false に設定します。デフォルトでは、接続メタデータを使用してドライバー機能を判断しようとします。
|
hibernate.connection.provider_class |
カスタムのクラス名
org.hibernate.connection.ConnectionProvider これは、Hibernate への JDBC 接続を提供します。
|
hibernate.connection.isolation |
JDBC トランザクション分離レベルを設定します。Check
java.sql.Connection ただし、ほとんどのデータベースはすべての分離レベルをサポートしているわけではなく、一部のデータベースは追加の非標準分離を定義していることに注意してください。標準値は 1、2、4、8 です。
|
hibernate.connection.autocommit |
ブール値。このプロパティーの使用は推奨されません。JDBC プールされた接続の自動コミットを有効にします。
|
hibernate.connection.release_mode |
Hibernate が JDBC 接続を解放するタイミングを指定します。デフォルトでは、明示的にセッションが閉じられるか、または切断されるまで JDBC 接続が保持されます。デフォルト値
auto は JTA および CMT トランザクションストラテジーに after_statement を選択し、JDBC トランザクションストラテジーに after_transaction を選択します。
使用可能な値は
auto (デフォルト)、on_close 、after_transaction 、after_statement です。
この設定は、
SessionFactory.openSession によって返される Session にのみ影響します。SessionFactory.getCurrentSession から取得した Session の場合、使用するために設定された CurrentSessionContext 実装はその Session の接続リリースモードを制御します。
|
hibernate.connection.<propertyName> |
JDBC プロパティーを <propertyName> から
DriverManager.getConnection() に渡します。
|
hibernate.jndi.<propertyName> |
<propertyName> プロパティーを
InitialContextFactory に渡します。
|
13.2.4.3. Hibernate キャッシュプロパティー
表13.3 プロパティー
プロパティー名 | 説明 |
---|---|
hibernate.cache.region.factory_class |
カスタム
CacheProvider のクラス名。
|
hibernate.cache.use_minimal_puts |
ブール値。書き込みを最小限に抑えるために 2 次レベルのキャッシュ操作を最適化し、読み取りの頻度を上げます。この設定はクラスター化されたキャッシュで最も便利なもので、Hibernate3 ではクラスター化されたキャッシュ実装に対してデフォルトで有効になっています。
|
hibernate.cache.use_query_cache |
ブール値。クエリーキャッシュを有効にします。個別のクエリーをキャッシュ可能に設定する必要があります。
|
hibernate.cache.use_second_level_cache |
ブール値。
<cache> マッピングを指定するクラスに対してデフォルトで有効になっている 2 次レベルのキャッシュを完全に無効にするために使用されます。
|
hibernate.cache.query_cache_factory |
カスタム
QueryCache インターフェイスのクラス名。デフォルト値はビルトインの StandardQueryCache です。
|
hibernate.cache.region_prefix |
2 次キャッシュリージョン名に使用するプレフィックス。
|
hibernate.cache.use_structured_entries |
ブール値。Hibernate が、よりヒューマンリーダブルな形式で、2 次レベルのキャッシュにデータを格納するように強制します。
|
hibernate.cache.default_cache_concurrency_strategy | @Cacheable または @Cache のいずれかが使用された場合に使用するデフォルトの org.hibernate.annotations.CacheConcurrencyStrategy の名前を付与するために使用される設定。@Cache(strategy="..") は、このデフォルトを上書きするのに使用されます。
|
13.2.4.4. Hibernate トランザクションプロパティー
表13.4 プロパティー
プロパティー名 | 説明 |
---|---|
hibernate.transaction.factory_class |
Hibernate
Transaction API で使用するための TransactionFactory のクラス名。デフォルトは JDBCTransactionFactory
|
jta.UserTransaction |
アプリケーションサーバーから JTA
UserTransaction を取得するために JTATransactionFactory によって使用される JNDI 名。
|
hibernate.transaction.manager_lookup_class | TransactionManagerLookup のクラス名。これは、JVM レベルキャッシングが有効な場合や、JTA 環境で hilo ジェネレーターを使用する場合に必要です。
|
hibernate.transaction.flush_before_completion |
ブール値。有効にすると、トランザクションの完了前のフェーズでセッションが自動的にフラッシュされます。組み込みおよび自動セッションコンテキスト管理が推奨されます。
|
hibernate.transaction.auto_close_session |
ブール値。有効にすると、トランザクションの完了フェーズ中にセッションが自動的に閉じられます。組み込みおよび自動セッションコンテキスト管理が推奨されます。
|
13.2.4.5. その他の Hibernate プロパティー
表13.5 プロパティー
プロパティー名 | 説明 |
---|---|
hibernate.current_session_context_class |
「現在」の
Session セッションのスコープ設定にカスタムストラテジーを指定します。値には、jta 、thread 、managed 、custom.Class が含まれます。
|
hibernate.query.factory_class |
HQL パーサー実装 (
org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory または org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory ) を選択します。
|
hibernate.query.substitutions |
Hibernate クエリーのトークンから SQL トークン (トークンは関数またはリテラル名) にマップするために使用されます。たとえば、
hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC 。
|
hibernate.hbm2ddl.auto | SessionFactory の作成時にスキーマをデータベースに自動的に検証またはエクスポートします。Create-drop で SessionFactory を明示的に閉じると、データベーススキーマがドロップされます。プロパティー値のオプションはvalidate 、update 、create 、create-drop です。
|
hibernate.hbm2ddl.import_files | SessionFactory の作成時に実行される SQL Mission ステートメントが含まれるオプションのファイルのコンマ区切りの名前です。これは、テストまたはデモンストレーションに役立ちます。たとえば、AIA ステートメントを追加すると、デプロイ時にデータベースが最小限のデータセットでデータが投入されます。値の例は /humans.sql,/dogs.sql です。
ファイルの順序は重要です。以下のファイルのステートメントの前に特定ファイルのステートメントが実行されるためです。これらのステートメントは、たとえば
hibernate.hbm2ddl.auto がcreate or create-drop に設定されている場合にのみ実行されます。
|
hibernate.hbm2ddl.import_files_sql_extractor |
カスタムのクラス名
ImportSqlCommandExtractor .デフォルトは、ビルトインの SingleLineSqlCommandExtractor です。これは、各インポートファイルから単一の SQL ステートメントを抽出する専用パーサーを実装する際に便利です。Hibernate は、複数の行 (各ステートメントの最後で必須のセミコロン) に散在する命令/コメントおよび引用符で囲まれた文字列をサポートする、複数の MultipleLinesSqlCommandExtractor も提供します。
|
hibernate.bytecode.use_reflection_optimizer |
ブール値。これはシステムレベルのプロパティーで、
hibernate.cfg.xml ファイルで設定することはできません。ランタイムの反映の代わりにバイトコード操作の使用を有効にします。リフレクションはトラブルシューティング時に役に立つことがあります。Hibernate には常に cglib または javassist のいずれかが必要です。
|
hibernate.bytecode.provider |
javassist または cglib は、バイト操作エンジンとして使用できます。デフォルトは
javassist です。プロパティー値は javassist または cglib のいずれかです
|
13.2.4.6. HibernateSQL ダイアレクト
hibernate.dialect
プロパティーは、アプリケーションデータベースの適切な org.hibernate. denialect.Dialect
サブクラスに設定する必要があります。ダイアレクトが指定されている場合、Hibernate は他のプロパティーの一部に対して適切なデフォルトを使用します。これは、手動で指定する必要がないことを意味します。
表13.6 SQL Dialects (hibernate.dialect
)
RDBMS | ダイアレクト |
---|---|
DB2 | org.hibernate.dialect.DB2Dialect |
DB2 AS/400 | org.hibernate.dialect.DB2400Dialect |
DB2 OS390 | org.hibernate.dialect.DB2390Dialect |
Adobird | org.hibernate.dialect.FirebirdDialect |
FrontBase | org.hibernate.dialect.FrontbaseDialect |
H2 Database | org.hibernate.dialect.H2Dialect |
HypersonicSQL | org.hibernate.dialect.HSQLDialect |
Informix | org.hibernate.dialect.InformixDialect |
Ingres | org.hibernate.dialect.IngresDialect |
Interbase | org.hibernate.dialect.InterbaseDialect |
Mckoi SQL | org.hibernate.dialect.MckoiDialect |
Microsoft SQL Server 2000 | org.hibernate.dialect.SQLServerDialect |
Microsoft SQL Server 2005 | org.hibernate.dialect.SQLServer2005Dialect |
Microsoft SQL Server 2008 | org.hibernate.dialect.SQLServer2008Dialect |
Microsoft SQL Server 2012 | org.hibernate.dialect.SQLServer2008Dialect |
MySQL5 | org.hibernate.dialect.MySQL5Dialect |
InnoDB を使用した MySQL5 | org.hibernate.dialect.MySQL5InnoDBDialect |
MyISAM を使用した MySQL | org.hibernate.dialect.MySQLMyISAMDialect |
Oracle (すべてのバージョン) | org.hibernate.dialect.OracleDialect |
Oracle 9i | org.hibernate.dialect.Oracle9iDialect |
Oracle 10g | org.hibernate.dialect.Oracle10gDialect |
Oracle 11g | org.hibernate.dialect.Oracle10gDialect |
Pointbase | org.hibernate.dialect.PointbaseDialect |
PostgreSQL | org.hibernate.dialect.PostgreSQLDialect |
PostgreSQL 9.2 | org.hibernate.dialect.PostgreSQL82Dialect |
Postgres Plus Advanced Server | org.hibernate.dialect.PostgresPlusDialect |
Progress | org.hibernate.dialect.ProgressDialect |
SAP DB | org.hibernate.dialect.SAPDBDialect |
Sybase | org.hibernate.dialect.SybaseASE15Dialect |
Sybase 15.7 | org.hibernate.dialect.SybaseASE157Dialect |
Sybase Anywhere | org.hibernate.dialect.SybaseAnywhereDialect |
13.2.5. 2 次キャッシュ
13.2.5.1. 2 次キャッシュ
- Web セッションのクラスタリング
- ステートフルセッション Bean のクラスタリング
- SSO クラスタリング
- Hibernate 2 次キャッシュ
13.2.5.2. Hibernate の 2 次キャッシュの設定
手順13.4 hibernate.cfg.xml
ファイルを作成および編集します
hibernate.cfg.xml ファイルを作成します
デプロイメントのクラスパスにhibernate.cfg.xml
を作成します。詳細については、を参照してください。「Red Hat JBossDeveloperStudio で Hibernate 設定ファイルを作成します」。- これらの XML 行をアプリケーションの
hibernate.cfg.xml
ファイルに追加します。XML は <session-factory> タグ内にある必要があります。<property name="hibernate.cache.use_second_level_cache">true</property> <property name="hibernate.cache.use_query_cache">true</property>
hibernate.cfg.xml
ファイルの <session-factory> セクションに次のいずれかを追加します。Infinispan CacheManager が JNDI にバインドされている場合:
<property name="hibernate.cache.region.factory_class"> org.hibernate.cache.infinispan.JndiInfinispanRegionFactory </property> <property name="hibernate.cache.infinispan.cachemanager"> java:CacheManager </property>
Infinispan CacheManager がスタンドアロンの場合:
<property name="hibernate.cache.region.factory_class"> org.hibernate.cache.infinispan.InfinispanRegionFactory </property>
結果
Infinispan は、Hibernate の第 2 レベルのキャッシュとして設定されます。
13.3. Hibernate アノテーション
13.3.1. Hibernate アノテーション
表13.7 Hibernate で定義されたアノテーション
Annotation | Description |
---|---|
AccessType | プロパティーアクセスタイプ。 |
すべて | 複数のエンティティータイプを参照するトール関連付けを定義します。一致したエンティティータイプのマッチングは、メタデータの識別子コラムを使用して行われます。このようなマッピングはマージのみにする必要があります。 |
AnyMetaDef | @Any および @ManyToAny メタデータを定義します。 |
AnyMedaDefs | @Any および @ManyToAny のメタデータセットを定義します。エンティティーレベルまたはパッケージレベルで定義できます。 |
BatchSize | SQL 読み込みのバッチサイズ。 |
Cache | キャッシュストラテジーをルートエンティティーまたはコレクションに追加します。 |
Cascade | 関連付けにカスケードストラテジーを適用します。 |
Check | クラス、プロパティー、またはコレクションレベルで定義できる任意の SQL チェック制約。 |
Columns | 列のアレイをサポートします。コンポーネントのユーザータイプマッピングに便利です。 |
ColumnTransformer | 値をコラムから読み取り、コラムに書き込むために使用するカスタムの SQL 式。クエリーとともにオブジェクトの直接読み込み/保存に使用します。書き込み式には、値に対して 1 つの '?' プレースホルダーが必ず含まれている必要があります。 |
ColumnTransformers | @ColumnTransformer の複数のアノテーション複数のコラムがこの動作を使用している場合に便利です。 |
DiscriminatorFormula | ルートエンティティーに配置されるイデンティターの式。 |
DiscriminatorOptions | Hibernate 固有の識別子プロパティーを表示するオプションのアノテーションです。 |
エンティティー | Hibernate 機能でエンティティーを拡張します。 |
Fetch | 指定の関連付けに使用されるフェッチストラテジーを定義します。 |
FetchProfile | フェッチストラテジープロファイルを定義します。 |
FetchProfiles | @FetchProfile の複数形のアノテーション。 |
フィルター | フィルターをエンティティーまたはコレクションのターゲットエンティティーに追加します。 |
FilterDef | フィルター定義。 |
FilterDefs | フィルター定義の配列。 |
FilterJoinTable | フィルターを結合テーブルコレクションに追加します。 |
FilterJoinTables | 複数の @FilterJoinTable をコレクションに追加します。 |
フィルター | 複数の @Filter を追加します。 |
Formula | 大半の場所で、@Column の代わりとして使用するために使用されます。式は有効な SQL フラグメントである必要があります。 |
Generated | このアノテーション付きプロパティーはデータベースによって生成されます。 |
GenericGenerator | タイプ解除された方法で、あらゆる Hibernate generator を記述するジェネレーターアノテーション。 |
GenericGenerators | 汎用ジェネレーター定義のアレイ。 |
Immutable |
エンティティーまたはコレクションにイミュータブルとしてマークを付けます。アノテーションがないということは、要素が変更されたことを意味します。
イミュータブルなエンティティーはアプリケーションによって更新されない可能性があります。イミュータブルなエンティティーの更新は無視されますが、例外は発生しません。
@Immutable をコレクションに配置すると、コレクションがイミュータブルな状態になり、コレクションへの追加および削除は許可されません。この場合、HibernateException が発生します。
|
Index | データベースインデックスを定義します。 |
JoinFormula | 大半の場所で、@JoinColumn の代わりとして使用するために使用されます。式は有効な SQL フラグメントである必要があります。 |
LazyCollection | コレクションのレイジーステータスを定義します。 |
LazyToOne | ToOne 関連づけのレイジーステータスを定義します (OneToOne または ManyToOne)。 |
Loader | Hibernate デフォルトの FIND メソッドを上書きします。 |
ManyToAny | 異なるエンティティータイプを参照する ToMany 関連付けを定義します。一致したエンティティータイプのマッチングは、メタデータの識別子コラムを使用して行われます。このようなマッピングはマージのみにする必要があります。 |
MapKeyType | 永続マップのキーのタイプを定義します。 |
MetaValue | 特定のエンティティータイプに関連付けられた識別子の値を表します。 |
NamedNativeQueries | NamedNativeQueries を拡張して、Hibernate NamedNativeQuery オブジェクトを保持します。 |
NamedNativeQuery | Hibernate 機能を使用した NamedNativeQuery の拡張 |
NamedQueries | NamedQuery を拡張して Hibernate NamedQuery オブジェクトを保持します。 |
NamedQuery | Hibernate 機能を使用して NamedQuery を拡張します。 |
NaturalId | プロパティーがエンティティーの純粋な ID の一部であることを指定します。 |
NotFound | 要素が関連上に見つからない場合に行うアクション。 |
OnDelete | コレクション、アレイ、および結合されたサブクラスの削除で使用するストラテジー。現在、セカンダリーテーブルの OnDelete はサポートされていません。 |
OptimisticLock | アノテーションが付けられたプロパティーの変更によってエンティティーバージョンの増分がトリガーされるかどうか。アノテーションが存在しない場合は、プロパティーが楽観的ロックストラテジーに関与します (デフォルト)。 |
OptimisticLocking | エンティティーに適用される楽観的ロックのスタイルを定義するために使用されます。階層では、ルートエンティティーでのみ有効です。 |
OrderBy | SQL 順序付け (HQL の順序ではなく) を使用してコレクションを順序付けます。 |
ParamDef | パラメーター定義。 |
パラメーター | キー/値のパターン。 |
Parent | プロパティーを所有者 (通常は所有するエンティティー) へのポインターとして参照します。 |
Persister | カスタム永続機能を指定します。 |
Polymorphism | ポリモーフィズム Hibernate のタイプを定義するために使用されます。 |
Proxy | 特定のクラスのレイジーおよびプロキシー設定。 |
RowId | Hibernate の ROWID マッピング機能のサポート。 |
Sort | コレクションのソート (Java レベルのソート)。 |
Source | Version および timestamp version プロパティーと併せてのオプションのアノテーションです。アノテーションの値で、タイムスタンプの生成先が決まります。 |
SQLDelete | Hibernate デフォルトの DELETE メソッドを上書きします。 |
SQLDeleteAll | Hibernate のデフォルト DELETE ALL メソッドを上書きします。 |
SQLInsert | Hibernate のデフォルト INSERT INTO メソッドを上書きします。 |
SQLUpdate | Hibernate デフォルトの UPDATE メソッドを上書きします。 |
Subselect | イミュータブルで読み取り専用のエンティティーを指定の SQL サブ選択式にマッピングします。 |
Synchronization | 自動フラッシュが正しく実行され、派生エンティティーに対するクエリーが古いデータを返さないようにします。大半は Subselect とともに使用されます。 |
テーブル | プライマリーまたはセカンダリーのテーブルに情報を補完します。 |
Tables | Table の複数形のアノテーション。 |
Target | 明示的なターゲットを定義し、反映および汎用的な解決を回避します。 |
Tuplizer | エンティティーまたはコンポーネントの tuplizer を定義します。 |
Tuplizers | エンティティーまたはコンポーネントの一連の tuplizer を定義します。 |
タイプ | Hibernate タイプ。 |
TypeDef | Hibernate タイプ定義。 |
TypeDefs | Hibernate タイプ定義の配列。 |
Where | コレクションのエンティティーまたはターゲットエンティティーに追加する要素。レシピは SQL で記述されます。 |
WhereJoinTable | コレクションジョインテーブルに追加する部分。レシピは SQL で記述されます。 |
13.4. Hibernate Query 言語
13.4.1. Hibernate Query 言語について
13.4.2. HQL ステートメント
SELECT
、UPDATE
、DELETE
、および INSERT
ステートメントを使用できます。HQL INSERT
ステートメントには、JPQL に相当するものはありません。
UPDATE
または DELETE
ステートメントがいつ実行されるかについては注意が必要です。
表13.8 HQL ステートメント
ステートメント | Description |
---|---|
SELECT |
HQL における
SELECT ステートメントの BNF は以下のとおりです。
select_statement :: = [select_clause] from_clause [where_clause] [groupby_clause] [having_clause] [orderby_clause]
最も単純な
HQLSELECT ステートメントの形式は次のとおりです。
from com.acme.Cat |
UDPATE | HQL の UPDATE ステートメントの BNF は JPQL と同じです。 |
DELETE | HQL の DELETE ステートメントの BNF は JPQL と同じです。 |
13.4.3. INSERT ステートメントについて
INSERT
ステートメントを定義する機能を追加します。これと同等の JPQL はありません。HQLINSERT
ステートメントの BNF は次のとおりです。
insert_statement ::= insert_clause select_statement insert_clause ::= INSERT INTO entity_name (attribute_list) attribute_list ::= state_field[, state_field ]*
tribute_list
は、SQL INSERT
ステートメントの column specification
に似ています。マッピングされた継承に関連するエンティティーでは、名前付きエンティティーに直接定義された属性のみが attribute_list
で使用できます。スーパークラスプロパティーは許可されておらず、サブクラスプロパティーは意味を成しません。つまり、INSERT
ステートメントは本質的にはポリモーフィックではありません。
select_statement
には、有効な HQL 選択クエリーを使用できます。この場合、戻り値のタイプは挿入で想定されるタイプと一致する必要があります。現在、これは、チェックによるデータベースへの再参照を許可するのではなく、クエリーのコンパイル時に確認されます。これにより、equal ではなく equivalent である Hibernate タイプ間で問題が発生する可能性があります。たとえば、これは org.hibernate.type.DateType
としてマップされた属性と org.hibernate.type.TimestampType
として定義された属性の間でミスマッチの問題を引き起こす可能性があります。
id
属性には、insert ステートメントに 2 つのオプションを付与します。attribute_list
で id
プロパティーを明示的に指定することができます。この場合、その値は、対応する select 式から取得されるか、または生成された値が使用される場合は attribute_list
から省略されます。後者のオプションは、データベースで (in the database) で動作する ID
ジェネレーターを使用している場合にのみ利用できます。メモリー内 (in memory) タイプジェネレーターでこのオプションを使用しようとすると、解析中に例外が発生します。
attribute_list
に属性を指定できます。この場合、その値は対応する select 式から取得されます。あるいは、attribute_list
から除外できます。その場合は、対応する select 式によって定義される seed value
が使用されます。 org.hibernate.type.VersionType
使用されている。
例13.3 INSERT
クエリーステートメント
String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ..."; int createdEntities = s.createQuery( hqlInsert ).executeUpdate();
13.4.4. FROM 句について
FROM
句は、残りのクエリーで使用できるオブジェクトモデルタイプのスコープを定義します。また、残りのクエリーで使用できるすべての識別変数も定義します。
13.4.5. WITH 句について
WITH
句を定義します。これは HQL に固有です。JPQL はこの機能を定義していません。
例13.4 条項
付き
select distinct c from Customer c left join c.orders o with o.value > 5000.00
with 句
の条件が生成された SQL の on 句
の
一部になり、HQL/JPQL 条件が生成された SQL。この特定の例の違いは、おそらくそれほど重要ではありません。より複雑なクエリーでは 、with 句
が必要になる場合があります。
13.4.6. 一括更新、挿入、削除について
FROM
キーワードおよび WHERE Clause
はオプションです。
例13.5 一括更新ステートメント
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); String hqlUpdate = "update Company set name = :newName where name = :oldName"; int updatedEntities = s.createQuery( hqlUpdate ) .setString( "newName", newName ) .setString( "oldName", oldName ) .executeUpdate(); tx.commit(); session.close();
例13.6 一括削除ステートメント
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); String hqlDelete = "delete Company where name = :oldName"; int deletedEntities = s.createQuery( hqlDelete ) .setString( "oldName", oldName ) .executeUpdate(); tx.commit(); session.close();
int
値は、オペレーションの影響を受けた、データベース内のエンティティーの数を示します。
oldName
という名前の企業用の Company
テーブルだけでなく、結合したテーブルに対しても削除が実行されます。したがって、社員テーブルと双方向の多対多リレーションシップを持つ会社テーブルでは、前述の例の実行が成功すると、対応する結合テーブル Company_Employee から
行が失われることになります。
int deletedEntries
値には、この操作によって影響を受けるすべての行の数 (結合テーブルの行を含む) が含まれます。
例13.7 一括挿入ステートメント
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); String hqlInsert = "insert into Account (id, name) select c.id, c.name from Customer c where ..."; int createdEntities = s.createQuery( hqlInsert ) .executeUpdate(); tx.commit(); session.close();
id
属性の値を指定しない場合、基礎となるデータベースが自動生成キーをサポートする限り、識別子が生成されます。この一括挿入操作の戻り値は、データベースで実際に作成されたエントリー数です。
13.4.7. コレクションメンバーの参照について
例13.8 コレクションの参照
select c from Customer c join c.orders o join o.lineItems l join l.product p where o.status = 'pending' and p.status = 'backorder' // alternate syntax select c from Customer c, in(c.orders) o, in(o.lineItems) l join l.product p where o.status = 'pending' and p.status = 'backorder'
o
は実際には、Customer#orders
関連付けの要素タイプであるオブジェクトモデルタイプ Order
を参照します。
IN
構文を使用してコレクションの関連付けジョインを指定する代替構文も示しています。両方の形式は同じです。アプリケーションの選択を選択するのは、単に好みの問題です。
13.4.8. 修飾パス式について
表13.9 修飾パス式
式 | Description |
---|---|
VALUE |
コレクション値を参照します。修飾子を指定しないのと同じです。意図を明示的に表示するのに役立ちます。いずれかのタイプのコレクションと値の参照に有効です。
|
INDEX |
HQL ルールによると、これはマップとリストの両方で有効です。
javax.persistence.OrderColumn マップキーまたはリスト位置 (別名 OrderColumn 値) を参照するための注釈。ただし、JPQL はこれを List ケースで使用するために予約し、MAP ケースに KEY を追加します。JPA プロバイダーの移植性に関心のあるアプリケーションは、この区別を認識する必要があります。
|
KEY |
Maps にのみ有効です。マップのキーを参照します。キー自体がエンティティーである場合は、さらに移動することができます。
|
ENTRY |
Maps にのみ有効です。マップの論理を参照します
java.util.Map.Entry タプル (キーと値の組み合わせ)。ENTRY はターミナルパスとしてのみ有効で、選択でのみ有効です。
|
例13.9 適格なコレクションの参照
// Product.images is a Map<String,String> : key = a name, value = file path // select all the image file paths (the map value) for Product#123 select i from Product p join p.images i where p.id = 123 // same as above select value(i) from Product p join p.images i where p.id = 123 // select all the image names (the map key) for Product#123 select key(i) from Product p join p.images i where p.id = 123 // select all the image names and file paths (the 'Map.Entry') for Product#123 select entry(i) from Product p join p.images i where p.id = 123 // total the value of the initial line items for all orders for a customer select sum( li.amount ) from Customer c join c.orders o join o.lineItems li where c.id = 123 and index(li) = 1
13.4.9. スカラー関数について
13.4.10. HQL の標準化機能
表13.10 HQL の標準化機能
関数 | 説明 |
---|---|
BIT_LENGTH |
バイナリーデータの長さを返します。
|
CAST |
SQL キャストを実行します。cast ターゲットは、使用する Hibernate マッピングタイプに名前を付ける必要があります。
|
EXTRACT |
Datetime 値に対して SQL の抽出を実行します。抽出により、日時の一部 (たとえば、年) が抽出されます。以下の省略形式を参照してください。
|
SECOND |
2 つ目を抽出するための省略された抽出形式。
|
MINUTE |
分を抽出するための省略された抽出形式。
|
HOUR |
時を抽出するための省略された抽出形式。
|
DAY |
日を抽出するための省略された抽出形式。
|
MONTH |
月を抽出するための省略された抽出形式。
|
YEAR |
年を抽出するための省略された抽出形式。
|
STR |
値を文字データとしてキャストするための省略形式。
|
addSqlFunction
org.hibernate.cfg.Configuration
のメソッド
13.4.11. 連結操作
CONCAT
) 関数のサポートのほかに連結演算子を定義します。これは JPQL では定義されないため、移植可能なアプリケーションは使用しないでください。連結演算子は、SQL 連結演算子 (||
) から取得されます。
例13.10 連結操作例
select 'Mr. ' || c.name.first || ' ' || c.name.last from Customer c where c.gender = Gender.MALE
13.4.12. 動的インスタンス化について
例13.11 動的インスタンス化の例 - コンストラクター
select new Family( mother, mate, offspr ) from DomesticCat as mother join mother.mate as mate left join mother.kittens as offspr
例13.12 動的インスタンス化の例 - リスト
select new list(mother, offspr, mate.name) from DomesticCat as mother inner join mother.mate as mate left outer join mother.kittens as offspr
例13.13 動的インスタンス化の例 - マップ
select new map( mother as mother, offspr as offspr, mate as mate ) from DomesticCat as mother inner join mother.mate as mate left outer join mother.kittens as offspr select new map( max(c.bodyWeight) as max, min(c.bodyWeight) as min, count(*) as n ) from Cat cxt
13.4.13. HQL 述語について
TRUE
または FALSE
に解決されます。ただし、NULL が関係するブール値比較は一般的に UNKNOWN
に解決します。
HQL の述語
- ヌルネス述語
- null の値を確認してください。基本的な属性参照、エンティティーの参照、およびパラメーターに適用できます。さらに HQL を使用すると、コンポーネント/ 組み込み可能なタイプに適用できます。
例13.14 ヌルネスチェックの例
// select everyone with an associated address select p from Person p where p.address is not null // select everyone without an associated address select p from Person p where p.address is null
- 述語と同様
- 文字列値に対して、同様の比較を実行します。構文は以下のとおりです。
like_expression ::= string_expression [NOT] LIKE pattern_value [ESCAPE escape_character]
セマンティクスは、式のような SQL のことに従います。paattern_value
は、string_expression
で一致を試みるパターンです。SQL と同様に、pattern_value
では _ と % をワイルドカードとして使用できます。意味は同じです。_ は任意の 1 文字に一致します。% は任意の数の文字に一致します。オプションのescape_character
は、pattern_value
の _ と % の特別な意味をエスケープするために使用されるエスケープ文字を指定するために使用されます。これは、_ または % のいずれかを含むパターンを検索する必要がある場合に便利です。例13.15 述語の例のように
select p from Person p where p.name like '%Schmidt' select p from Person p where p.name not like 'Jingleheimmer%' // find any with name starting with "sp_" select sp from StoredProcedureMetadata sp where sp.name like 'sp|_%' escape '|'
- BETWEEN 演算子
- SQL
BETWEEN
式と同様です。値が 2 つの他の値の範囲内にあるかどうかの評価を実行します。すべてのオペランドは、同等の型を持つ必要があります。例13.16 述語の例の間
select p from Customer c join c.paymentHistory p where c.id = 123 and index(p) between 0 and 9 select c from Customer c where c.president.dateOfBirth between {d '1945-01-01'} and {d '1965-01-01'} select o from Order o where o.total between 500 and 5000 select p from Person p where p.name between 'A' and 'E'
13.4.14. 関連比較について
例13.17 関係比較の例
// numeric comparison select c from Customer c where c.chiefExecutive.age < 30 // string comparison select c from Customer c where c.name = 'Acme' // datetime comparison select c from Customer c where c.inceptionDate < {d '2000-01-01'} // enum comparison select c from Customer c where c.chiefExecutive.gender = com.acme.Gender.MALE // boolean comparison select c from Customer c where c.sendEmail = true // entity type comparison select p from Payment p where type(p) = WireTransferPayment // entity value comparison select c from Customer c where c.chiefExecutive = c.chiefTechnologist
ALL
、ANY
、SOME
などの修飾子を含めることもできます。some
および ANY
は同義語です。
ALL
修飾子は、サブくエリーの結果のすべての値に対して比較が true の場合に true に解決します。これは、値が空の場合は false に解決します。
例13.18 ALL サブクエリー比較修飾子の例
// select all players that scored at least 3 points // in every game. select p from Player p where 3 > all ( select spg.points from StatsPerGame spg where spg.player = p )
ANY
/SOME
修飾子は、サブクエリーの結果の値のいずれかの比較が true の場合に true に解決します。これは、値が空の場合は false に解決します。
13.4.15. IN 述語について
IN
述語は、特定の値が値の一覧にあることを確認します。構文は次のとおりです。
in_expression ::= single_valued_expression [NOT] IN single_valued_list single_valued_list ::= constructor_expression | (subquery) | collection_valued_input_parameter constructor_expression ::= (expression[, expression]*)
single_valued_expression
のタイプと single_valued_list
の個別の値は一致している必要があります。JPQL は、有効なタイプを文字列、数値、日付、時間、タイムスタンプ、および列挙タイプに制限します。JPQL では、single_valued_expression
は以下のみを参照できます。
- 「状態フィールド」(state fields) は、単純な属性の用語です。具体的には、関連付けおよびコンポーネント/組み込み属性が除外されます。
- エンティティー型式。
single_valued_expression
はより幅広い式タイプを参照することができます。1 価の関連づけが許可されています。コンポーネント/組み込み属性も同様です。ただし、この機能は基盤のデータベースのタプルのサポートレベルまたは「ロー値のコンストラクター構文」 (row value constructor syntax) によって異なります。さらに、HQL では値のタイプは制限されませんが、アプリケーション開発者は、基盤のデータベースベンダーに基づいてサポートが制限される可能性があることに注意する必要があります。これは、通常 JPQL の制限のためです。
constructor_expression
およびcollection_valued_input_parameter
では、値の一覧は空にすることはできません。少なくとも 1 つの値が含まれている必要があります。
例13.19 述語の例では
select p from Payment p where type(p) in (CreditCardPayment, WireTransferPayment) select c from Customer c where c.hqAddress.state in ('TX', 'OK', 'LA', 'NM') select c from Customer c where c.hqAddress.state in ? select c from Customer c where c.hqAddress.state in ( select dm.state from DeliveryMetadata dm where dm.salesTax is not null ) // Not JPQL compliant! select c from Customer c where c.name in ( ('John','Doe'), ('Jane','Doe') ) // Not JPQL compliant! select c from Customer c where c.chiefExecutive in ( select p from Person p where ... )
13.4.16. HQL の順序について
ORDER BY
は、結果の順序付けに使用される選択した値を指定するために使用されます。順序単位で有効とみなされる式のタイプには、以下が含まれます。
- ステートフィールド
- コンポーネント/組み込み可能な属性
- 算術演算、関数などのスカラー式。
- 前の式タイプに対して select 句で宣言された識別変数。
ASC
(昇順) または DESC
(下記) で修飾できます。
例13.20 注文例
// legal because p.name is implicitly part of p select p from Person p order by p.name select c.id, sum( o.total ) as t from Order o inner join o.customer c group by c.id order by t
13.5. Hibernate サービス
13.5.1. Hibernate サービスについて
13.5.2. サービス契約について
org.hibernate.service.Service
のマーカーインターフェースを実装することです。Hibernate は、基本的なタイプの安全のためにこの内部で使用します。
org.hibernate.service.spi.Startable
および org.hibernate.service.spi.Stoppable
インターフェースを実装し、開始および停止の通知を受信することもできます。別のオプションのサービスコントラクトは org.hibernate.service.spi.Manageable
で、JMX 統合が有効になっていると、JMX でサービスが管理可能であるとマークされます。
13.5.3. サービス依存関係の種類
- @
org.hibernate.service.spi.InjectService
- 単一のパラメーターを受け入れ、@
InjectService
でアノテーションが付けられたサービス実装クラスのメソッドは 、別のサービスの挿入を要求していると見なされます。デフォルトでは、method パラメーターのタイプは、インジェクトされるサービスロールになることが想定されます。パラメーターのタイプがサービスロールと異なる場合は、InjectService
のserviceRole
属性を使用してロールに明示的な名前を付ける必要があります。デフォルトでは、インジェクトされたサービスは必須とみなされ、名前付き依存サービスがないと、起動に失敗します。インジェクションするサービスがオプションの場合、InjectService
のrequired
属性はfalse
と宣言する必要があります (デフォルトはtrue
)。 org.hibernate.service.spi.ServiceRegistryAwareService
- 次のアプローチは、単一の
injectServices
メソッドを宣言する、オプションのサービスインターフェースorg.hibernate.service.spi.ServiceRegistryAwareService
をサービスが実装するプルアプローチです。Hibernate は起動時に、org.hibernate.service.ServiceRegistry
自体をこのインターフェースを実装するサービスに挿入します。その後、ServiceRegistry
参照を使用して必要な追加サービスを見つけることができます。
13.5.4. ServiceRegistry
13.5.4.1. ServiceRegistry について
org.hibernate.service.ServiceRegistry
インターフェースです。サービスレジストリーの主な目的は、サービスへのアクセスを保持し、管理し、提供することです。
org.hibernate.service.ServiceRegistryBuilder
を使用して org.hibernate.service.ServiceRegistry
インスタンスをビルドします。
例13.21 ServiceRegistryBuilder を使用して ServiceRegistry を作成します
ServiceRegistryBuilder registryBuilder = new ServiceRegistryBuilder( bootstrapServiceRegistry ); ServiceRegistry serviceRegistry = registryBuilder.buildServiceRegistry();
13.5.5. カスタムサービス
13.5.5.1. カスタムサービスについて
org.hibernate.service.ServiceRegistry
を構築すると、不変とみなされます。このサービス自体は再設定を受け入れる可能性がありますが、ここでの不変性はサービスの追加/置き換えを意味します。そのため、org.hibernate.service.ServiceRegistryBuilder
で利用できる別のロールは、これから生成される org.hibernate.service.ServiceRegistry
に含まれるサービスの調整を許可することです。
org.hibernate.service.ServiceRegistryBuilder
に指示する方法は 2 つあります。
org.hibernate.service.spi.BasicServiceInitiator
クラスを実装し、サービスクラスのオンデマンド構築を制御し、addInitiator
メソッドを使用してorg.hibernate.service.ServiceRegistryBuilder
に追加します。- サービスクラスをインスタンス化し、それを介して
org.hibernate.service.ServiceRegistryBuilder
に追加するだけです。addService
方法。
例13.22 ServiceRegistryBuilder を使用して、既存のサービスをカスタムサービスに置き換える
ServiceRegistryBuilder registryBuilder = new ServiceRegistryBuilder( bootstrapServiceRegistry ); registryBuilder.addService( JdbcServices.class, new FakeJdbcService() ); ServiceRegistry serviceRegistry = registryBuilder.buildServiceRegistry(); public class FakeJdbcService implements JdbcServices{ @Override public ConnectionProvider getConnectionProvider() { return null; } @Override public Dialect getDialect() { return null; } @Override public SqlStatementLogger getSqlStatementLogger() { return null; } @Override public SqlExceptionHelper getSqlExceptionHelper() { return null; } @Override public ExtractedDatabaseMetaData getExtractedMetaDataSupport() { return null; } @Override public LobCreator getLobCreator(LobCreationContext lobCreationContext) { return null; } @Override public ResultSetWrapper getResultSetWrapper() { return null; } }
13.5.6. ブートストラップレジストリー
13.5.6.1. Boot-strap レジストリーについて
ClassLoaderService
です。これは最適な例です。設定ファイルを解決するにも、クラス読み込みサービス (リソース検索) へのアクセスが必要です。これは、通常の使用時の (親ではなく) ルートレジストリーです。
org.hibernate.service.BootstrapServiceRegistryBuilder
クラスを使用して作成されます。
13.5.6.2. BootstrapServiceRegistryBuilder の使用
例13.23 BootstrapServiceRegistryBuilder の使用
BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder() // pass in org.hibernate.integrator.spi.Integrator instances which are not // auto-discovered (for whatever reason) but which should be included .with( anExplicitIntegrator ) // pass in a class loader that Hibernate should use to load application classes .with( anExplicitClassLoaderForApplicationClasses ) // pass in a class loader that Hibernate should use to load resources .with( anExplicitClassLoaderForResources ) // see BootstrapServiceRegistryBuilder for rest of available methods ... // finally, build the bootstrap registry with all the above options .build();
13.5.6.3. BootstrapRegistry サービス
org.hibernate.service.classloading.spi.ClassLoaderService
- アプリケーションクラスを検索する機能
- インテグレーションクラスを検索する機能
- リソース (プロパティーファイル、xml ファイルなど) を見つける機能
java.util.ServiceLoader
をロードする機能
org.hibernate.integrator.spi.IntegratorService
Javajava.util.ServiceLoader
機能を活用します。 org.hibernate.service.classloading.spi.ClassLoaderService
の実装を発見するために org.hibernate.integrator.spi.Integrator
contract.
/META-INF/services/org.hibernate.integrator.spi.Integrator
という名前のファイルを定義し、これをクラスパスで利用できるようにします。
java.util.ServiceLoader
メカニズムによって使用されます。これは、1 行ずつ org.hibernate.integrator.spi.Integrator
インターフェースを実装するクラスの完全修飾名を一覧表示します。
13.5.7. SessionFactory レジストリー
13.5.7.1. SessionFactory レジストリー
org.hibernate.SessionFactory
、このグループのサービスのインスタンスは、明示的に単一に属します org.hibernate.SessionFactory
.
org.hibernate.SessionFactory
開始されます。この特別なレジストリーは org.hibernate.service.spi.SessionFactoryServiceRegistry
13.5.7.2. SessionFactory サービス
org.hibernate.event.service.spi.EventListenerRegistry
- Description
- イベントリスナーを管理するためのサービスです。
- イニシエーター
org.hibernate.event.service.internal.EventListenerServiceInitiator
- 実装
org.hibernate.event.service.internal.EventListenerRegistryImpl
13.5.8. インテグレーター
13.5.8.1. インテグレーター
org.hibernate.integrator.spi.Integrator
開発者が機能する SessionFactory を構築するプロセスにフックできるようにするための簡単な手段を提供することを目的としています。その org.hibernate.integrator.spi.Integrator
インターフェイスは、対象となる 2 つのメソッドを定義します。integrate
構築プロセスにフックすることができます。disintegrate
シャットダウンする SessionFactory にフックすることができます。
org.hibernate.integrator.spi.Integrator
、のオーバーロードされた形式integrate
受け入れる org.hibernate.metamodel.source.MetadataImplementor
org.hibernate.cfg.Configuration
の代わりに。このフォームは、5.0 で完了する予定の新しいメタモデルコードで使用することを目的としています。
13.5.8.2. インテグレーターのユースケース
org.hibernate.integrator.spi.Integrator
現在、イベントリスナーの登録とサービスの提供を行っています (を参照)。 org.hibernate.integrator.spi.ServiceContributingIntegrator
).5.0 では、オブジェクトモデルとリレーショナルモデル間のマッピングを記述するメタモデルを変更できるように拡張する予定です。
例13.24 イベントリスナーの登録
public class MyIntegrator implements org.hibernate.integrator.spi.Integrator { public void integrate( Configuration configuration, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { // As you might expect, an EventListenerRegistry is the thing with which event listeners are registered It is a // service so we look it up using the service registry final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class ); // If you wish to have custom determination and handling of "duplicate" listeners, you would have to add an // implementation of the org.hibernate.event.service.spi.DuplicationStrategy contract like this eventListenerRegistry.addDuplicationStrategy( myDuplicationStrategy ); // EventListenerRegistry defines 3 ways to register listeners: // 1) This form overrides any existing registrations with eventListenerRegistry.setListeners( EventType.AUTO_FLUSH, myCompleteSetOfListeners ); // 2) This form adds the specified listener(s) to the beginning of the listener chain eventListenerRegistry.prependListeners( EventType.AUTO_FLUSH, myListenersToBeCalledFirst ); // 3) This form adds the specified listener(s) to the end of the listener chain eventListenerRegistry.appendListeners( EventType.AUTO_FLUSH, myListenersToBeCalledLast ); } }
13.6. Bean Validation
13.6.1. Bean Validation
bean-validation
クイックスタートの例:「クイックスタートにアクセスする」。
13.6.2. Hibernate Validator
13.6.3. バリデーション制約
13.6.3.1. バリデーション制約
13.6.3.2. Red Hat JBossDeveloperStudio で制約アノテーションを作成する
概要
このタスクでは、Java アプリケーション内で使用するために Red Hat JBossDeveloperStudio で制約アノテーションを作成するプロセスについて説明します。
手順13.5 制約注釈を作成する
- Red Hat JBossDeveloperStudio で Java プロジェクトを開きます。
データセットを作成する
制約アノテーションには、許容値を定義するデータセットが必要です。- プロジェクトエクスプローラ パネルでプロジェクトルートフォルダーを右クリックします。
- NewEnum → を 選択します。
- 次の要素を設定します。
- パッケージ:
- 名前:
- 追加... ボタンをクリックして、必要なインターフェイスを追加します。
- Finish (完了) をクリックしてファイルを作成します。
- データセットに値のセットを追加し、保存 をクリックします。
例13.25 データセットの例
package com.example; public enum CaseMode { UPPER, LOWER; }
注釈ファイルを作成する
新しい Java クラスを作成します。- 制約注釈を設定し、保存 をクリックします。
例13.26 制約注釈ファイルの例
package com.mycompany; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; @Target( { METHOD, FIELD, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = CheckCaseValidator.class) @Documented public @interface CheckCase { String message() default "{com.mycompany.constraints.checkcase}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; CaseMode value(); }
- 結果
- 可能な値のセットを含むカスタム制約アノテーションが作成され、Java プロジェクトで使用できるようになりました。
13.6.3.3. Hibernate Validator の制約
表13.11 組み込みの制約
Annotation | に適用する | ランタイムチェック | Hibernate Metadata の影響 |
---|---|---|---|
@Length(min=, max=) | プロパティー (文字列) | 文字列の長さが指定の範囲と一致するかを確認します。 | カラムの長さを最大に設定します。 |
@Max(value=) | プロパティー (数値または数値の文字列表現) | 値が最大値以下であるかを確認します。 | カラムに check 制約を追加します。 |
@Min(value=) | プロパティー (数値または数値の文字列表現) | 値が最小値以上であるかを確認します。 | カラムに check 制約を追加します。 |
@NotNull | プロパティー | 値が null でないかを確認します。 | カラムが null でないかを確認します。 |
@NotEmpty | プロパティー | 文字列が null あるいは空でないかを確認します。接続が null あるいは空でないかを確認します。 | 列が null ではありません (文字列の場合)。 |
@Past | プロパティー (日付またはカレンダー) | 過去の日付であるかを確認します。 | カラムに check 制約を追加します。 |
@Future | プロパティー (日付またはカレンダー) | 未来の日付であるかを確認します。 | なし。 |
@Pattern(regex="regexp", flag=) or @Patterns( {@Pattern(...)} ) | プロパティー (文字列) | プロパティーが一致フラグを指定して正規表現と一致するかどうかを確認します (java.util.regex.Pattern を参照)。 | なし。 |
@Range(min=, max=) | プロパティー (数値または数値の文字列表現) | 値が最小値と最大値 (含まれている) の間にあるかどうかを確認します。 | カラムに check 制約を追加します。 |
@Size(min=, max=) | プロパティー (配列、コレクション、マップ) | 要素のサイズが最小から最大 (含まれている) の間にあるかどうかを確認します。 | なし。 |
@AssertFalse | プロパティー | メソッドが false と評価することを確認します (アノテーションでなくコードで制約が表現されている場合に便利です)。 | なし。 |
@AssertTrue | プロパティー | メソッドが true と評価することを確認します (アノテーションでなくコードで制約が表現されている場合に便利です)。 | なし。 |
@Valid | プロパティー (オブジェクト) | 紐付けされたオブジェクトに再帰的にバリデーションを実行します。オブジェクトがコレクションかアレイの場合は、要素は再帰的に検証されます。また、オブジェクトがマップの場合、値要素が再帰的に検証されます。 | なし。 |
プロパティー (文字列) | 文字列がメールアドレスの仕様に準拠するかどうかを確認します。 | なし。 | |
@CreditCardNumber | プロパティー (文字列) | 文字列が正規の形式のクレジットカード番号であるかどうかを確認します (Luhn アルゴリズムの派生)。 | なし。 |
@Digits(integerDigits=1) | プロパティー (数値または数値の文字列表現) | プロパティーが integerDigits までの整数部と、fractionalDigits までの小数部を持つ数字であるかを確認します。 | カラムの精度とスケールを定義します。 |
@EAN | プロパティー (文字列) | 文字列が正しくフォーマットされた EAN あるいは UPC-A コードであるかを確認します。 | なし。 |
13.6.4. 設定
13.6.4.1. 例: バリデーション設定ファイル
例13.27 validation.xml
<validation-config xmlns="http://jboss.org/xml/ns/javax/validation/configuration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration"> <default-provider> org.hibernate.validator.HibernateValidator </default-provider> <message-interpolator> org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator </message-interpolator> <constraint-validator-factory> org.hibernate.validator.engine.ConstraintValidatorFactoryImpl </constraint-validator-factory> <constraint-mapping> /constraints-example.xml </constraint-mapping> <property name="prop1">value1</property> <property name="prop2">value2</property> </validation-config>
13.7. エンバーズ
13.7.1. Hibernate Envers について
@Audited
アノテーションが付けられたエンティティーに対して作成されています。これは、エンティティーに加えられた変更の履歴が保存されます。その後、データを取得し、クエリーできます。
- JPA 仕様で定義されているすべてのマッピングの監査
- JPA 仕様を拡張するすべての Hibernate マッピングの監査
- ネイティブ Hibernate API を使用する、または、これによってマッピングされるエンティティーの監査
- リビジョンエンティティーを使用した各リビジョンのデータのログ記録、また
- 履歴データのクエリー
13.7.2. 永続クラスの監査について
@Audited
注釈。アノテーションがクラスに適用されると、エンティティーの改訂履歴を保存するテーブルが作成されます。
13.7.3. 監査ストラテジー
13.7.3.1. 監査ストラテジーについて
- デフォルトの監査ストラテジー
- このストラテジーは、開始リビジョンとともに監査データの保存を永続化します。監査されたテーブルで挿入、更新、削除される行ごとに、有効性の開始リビジョンとともに、監査テーブルに 1 つ以上の行を挿入します。監査テーブルの行は、挿入後には更新されません。監査情報のクエリーはサブクエリーを使用して、監査テーブルの適用可能な行を選択します。これはスピードが遅く、インデックス作成が困難です。
- 有効性監査ストラテジー
- このストラテジーは、監査上の開始リビジョンと最後のリビジョンを保存します。監査されたテーブルで挿入、更新、削除される行ごとに、有効性の開始リビジョンとともに、監査テーブルに 1 つ以上の行を挿入します。同時に、以前の監査行 (利用可能な場合) の終了リビジョンフィールドは、このリビジョンに設定されます。監査情報のクエリーは、サブクエリーの代わりに、 between start と end revision の間で使用できます。つまり、追加の更新により、監査情報の永続化は多少遅くなりますが、監査情報の取得はかなり速くなります。これは、インデックスを追加して改善することもできます。
13.7.3.2. 監査ストラテジーの設定
概要
JBoss EAP 6 でサポートされる監査戦略には、デフォルトと妥当性の監査戦略の 2 つがあります。このタスクでは、アプリケーションの監査戦略を定義するために必要な手順について説明します。
手順13.6 監査戦略を定義する
- を設定します
org.hibernate.envers.audit_strategy
アプリケーションのpersistence.xml
ファイルのプロパティー。プロパティーがpersistence.xml
ファイルで設定されていない場合は、デフォルトの監査ストラテジーが使用されます。例13.28 デフォルトの監査ストラテジーの設定
<property name="org.hibernate.envers.audit_strategy" value="org.hibernate.envers.strategy.DefaultAuditStrategy"/>
例13.29 有効性監査ストラテジーの設定
<property name="org.hibernate.envers.audit_strategy" value="org.hibernate.envers.strategy.ValidityAuditStrategy"/>
13.7.4. エンティティー監査の開始
13.7.4.1. JPA エンティティーへの監査サポートの追加
手順13.7 JPA エンティティーへの監査サポートの追加
- デプロイメントに適した利用可能な監査パラメーターを設定します: 「Envers パラメーターの設定」
- 監査する JPA エンティティーを開きます。
- をインポートします
org.hibernate.envers.Audited
インターフェイス。 - 監査する各フィールドまたはプロパティーに
@Audited
アノテーションを適用するか、クラス全体に対して 1 度適用します。例13.30 2 つのフィールドを監査する
import org.hibernate.envers.Audited; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.GeneratedValue; import javax.persistence.Column; @Entity public class Person { @Id @GeneratedValue private int id; @Audited private String name; private String surname; @ManyToOne @Audited private Address address; // add getters, setters, constructors, equals and hashCode here }
例13.31 クラス全体を監査する
import org.hibernate.envers.Audited; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.GeneratedValue; import javax.persistence.Column; @Entity @Audited public class Person { @Id @GeneratedValue private int id; private String name; private String surname; @ManyToOne private Address address; // add getters, setters, constructors, equals and hashCode here }
結果
JPA エンティティーは監査用に設定されています。履歴の変更を保存するために、Entity_AUD
というテーブルが作成されます。
13.7.5. 設定
13.7.5.1. Envers パラメーターの設定
手順13.8 Envers パラメーターの設定
- アプリケーションの
persistence.xml
ファイルを開きます。 - 必要に応じて Envers プロパティーを追加、削除、または設定します。利用可能なプロパティーのリストについては、を参照してください。「Envers 設定プロパティー」。
例13.32 例: Envers パラメーター
<persistence-unit name="mypc"> <description>Persistence Unit.</description> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode> <properties> <property name="hibernate.hbm2ddl.auto" value="create-drop" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.cache.use_second_level_cache" value="true" /> <property name="hibernate.cache.use_query_cache" value="true" /> <property name="hibernate.generate_statistics" value="true" /> <property name="org.hibernate.envers.versionsTableSuffix" value="_V" /> <property name="org.hibernate.envers.revisionFieldName" value="ver_rev" /> </properties> </persistence-unit>
- 結果
- アプリケーション内のすべての JPA エンティティーに対して監査が設定されています。
13.7.5.2. ランタイム時の監査の有効化または無効化
概要
このタスクでは、実行時にエンティティーバージョンの監査を有効/無効にするために必要な設定手順について説明します。
手順13.9 監査の有効化/無効化
AuditEventListener
クラスをサブクラス化します。- Hibernate イベントで呼び出される以下のメソッドを上書きします。
- onPostInsert
- onPostUpdate
- onPostDelete
- onPreUpdateCollection
- onPreRemoveCollection
- onPostRecreateCollection
- イベントのリスナーとしてサブクラスを指定します。
- 変更を監査する必要があるかどうかを判断します。
- 変更を監査する必要がある場合には、スーパークラスに呼び出しを渡します。
13.7.5.3. 条件監査の設定
概要
Hibernate Envers は、一連のイベントリスナーを使用して、さまざまな Hibernate イベントに対する応答で監査データを永続化します。Envers jar がクラスパスにある場合、これらのリスナーは自動的に登録されます。このタスクでは、Envers イベントリスナーの一部をオーバーライドすることにより、条件付き監査を実装するために必要な手順について説明します。
手順13.10 条件監査の実装
persistence.xml
ファイルでhibernate.listeners.envers.autoRegister
を false に設定します。- 上書きされる各イベントリスナーをサブクラス化します。条件付き監査ロジックをサブクラスに配置し、監査を実行する必要がある場合は super メソッドを呼び出します。
org.hibernate.envers.event.EnversIntegrator
に類似した、org.hibernate.integrator.spi.Integrator
のカスタム実装を作成します。デフォルトのクラスではなく、ステップ 2 で作成したイベントリスナーサブクラスを使用します。META-INF/services/org.hibernate.integrator.spi.Integrator
ファイルを jar に追加します。このファイルには、インターフェースを実装するクラスの完全修飾名が含まれている必要があります。
結果
条件付き監査が設定され、デフォルトの Envers イベントリスナーがオーバーライドされます。
13.7.5.4. Envers 設定プロパティー
表13.12 エンティティーデータのバージョン管理設定パラメーター
プロパティー名 | デフォルト値 | 説明 |
---|---|---|
org.hibernate.envers.audit_table_prefix
| |
監査されたエンティティーの名前の前に付加される文字列。監査情報を保持するエンティティーの名前を作成します。
|
org.hibernate.envers.audit_table_suffix
|
_AUD
|
監査されたエンティティーの名前に付加される文字列。監査情報を保持するエンティティーの名前を作成します。たとえば、テーブル名が
Person のエンティティーが監査されると、Envers は、履歴データを格納する Person_AUD と呼ばれるテーブルを生成します。
|
org.hibernate.envers.revision_field_name
|
REV
|
改訂番号を保持する監査エンティティーのフィールド名。
|
org.hibernate.envers.revision_type_field_name
|
REVTYPE
|
改訂の種類を保持する監査エンティティーのフィールド名。可能なリビジョンの現在のタイプは、
add 、mod 、および del です。
|
org.hibernate.envers.revision_on_collection_change
|
true
|
このプロパティーは、所有の変更のない関係フィールドがある場合にリビジョンを生成するかどうかを決定します。これは、一対多数の関係のコレクションであるか、または一対一の関係で
mappedBy 属性を使用するフィールドになります。
|
org.hibernate.envers.do_not_audit_optimistic_locking_field
|
true
|
true の場合、(
@Version でアノテーション付けされた) 楽観的ロックに使用されるプロパティーは自動的に監査から除外されます。
|
org.hibernate.envers.store_data_at_delete
|
false
|
このプロパティーは、ID のみではなく、エンティティーデータを削除するときに、エンティティーデータをリビジョンに保存するかどうかを定義します。その他のすべてのプロパティーは null とマークされます。通常、データは最後から 2 番目のバージョンにあるため、これは必須ではありません。ただし時折、最後のリビジョンでアクセスすることが簡単で、より効率的になる場合があります。ただし、これは、削除前に含まれるエンティティーのデータが 2 回保存されることを意味します。
|
org.hibernate.envers.default_schema
|
null (通常のテーブルと同じ)
|
監査テーブルに使用されるデフォルトのスキーマ名。
@AuditTable(schema="...") アノテーションを使用して上書き可能。これがない場合、スキーマは通常のテーブルのスキーマと同じになります。
|
org.hibernate.envers.default_catalog
|
null (通常のテーブルと同じ)
|
監査テーブルに使用するデフォルトのカタログ名。
@AuditTable(catalog="...") アノテーションを使用して上書き可能。存在しない場合、カタログは通常のテーブルのカタログと同じになります。
|
org.hibernate.envers.audit_strategy
|
org.hibernate.envers.strategy.DefaultAuditStrategy
|
このプロパティーは、監査データの永続化時に使用する必要のある監査ストラテジーを定義します。デフォルトでは、エンティティーが変更されたリビジョンのみが保存されます。または、
org.hibernate.envers.strategy.ValidityAuditStrategy では、開始リビジョンと終了リビジョンの両方を保存します。これらを組み合わせて、監査行が有効であったタイミングを定義します。
|
org.hibernate.envers.audit_strategy_validity_end_rev_field_name
|
REVEND
|
監査エンティティーで終了リビジョン番号を保持するコラムの名前。このプロパティーは、妥当な監査ストラテジーが使用される場合にのみ有効です。
|
org.hibernate.envers.audit_strategy_validity_store_revend_timestamp
|
false
|
このプロパティーは、終了リビジョン自体に加えて、データが最後に有効であった終了リビジョンのタイムスタンプも保存すべきかどうかを定義します。これは、テーブルパーティションを使用して、リレーショナルデータベースから古い監査レコードをパージする場合に便利です。パーティショニングには、テーブルに存在するコラムが必要です。このプロパティーは
ValidityAuditStrategy が使用される場合にのみ評価されます。
|
org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name
|
REVEND_TSTMP
|
データがまだ有効であった時点での終了リビジョンのタイムスタンプのコラム名。
ValidityAuditStrategy が使用されている場合にのみ使用され、 org.hibernate.envers.audit_strategy_validity_store_revend_timestamp true と評価されます。
|
13.7.6. クエリー
13.7.6.1. 監査情報を取得する
概要
Hibernate Enver は、クエリーを介して監査情報を取得する機能を提供します。このトピックでは、これらのクエリーの例を示します。
live
データに対するクエリーよりもはるかに遅くなります。
例13.33 所定リビジョンでのクラスのエンティティーのクエリー
AuditQuery query = getAuditReader() .createQuery() .forEntitiesAtRevision(MyEntity.class, revisionNumber);
AuditEntity
ファクトリークラスを使用して指定できます。以下のクエリーは、name
プロパティーが John
と同等のエンティティーのみを選択します。
query.add(AuditEntity.property("name").eq("John"));
query.add(AuditEntity.property("address").eq(relatedEntityInstance)); // or query.add(AuditEntity.relatedId("address").eq(relatedEntityId));
List personsAtAddress = getAuditReader().createQuery() .forEntitiesAtRevision(Person.class, 12) .addOrder(AuditEntity.property("surname").desc()) .add(AuditEntity.relatedId("address").eq(addressId)) .setFirstResult(4) .setMaxResults(2) .getResultList();
例13.34 所定クラスエンティティーが変更されるクエリーリビジョン
AuditQuery query = getAuditReader().createQuery() .forRevisionsOfEntity(MyEntity.class, false, true);
AuditEntity.revisionNumber()
- 監査済みエンティティーが変更されたリビジョン番号の制約、展開、および順序を指定します。
AuditEntity.revisionProperty(propertyName)
- 監査済みエンティティーが変更されたリビジョンに対応する、リビジョンエンティティーのプロパティーに対する制約、調整および順序付けを指定します。
AuditEntity.revisionType()
- リビジョンのタイプ (ADD、MOD、DEL) へのアクセスを提供します。
MyEntity
クラス、entityId
リビジョン番号 42 以降、ID が変更されました:
Number revision = (Number) getAuditReader().createQuery() .forRevisionsOfEntity(MyEntity.class, false, true) .setProjection(AuditEntity.revisionNumber().min()) .add(AuditEntity.id().eq(entityId)) .add(AuditEntity.revisionNumber().gt(42)) .getSingleResult();
actualDate
の値が指定の値よりも大きくなるリビジョンを選択しますが、可能な限り小さくなります。
Number revision = (Number) getAuditReader().createQuery() .forRevisionsOfEntity(MyEntity.class, false, true) // We are only interested in the first revision .setProjection(AuditEntity.revisionNumber().min()) .add(AuditEntity.property("actualDate").minimize() .add(AuditEntity.property("actualDate").ge(givenDate)) .add(AuditEntity.id().eq(givenEntityId))) .getSingleResult();
minimize()
および maximize()
のメソッドは基準を返します。これは、制約を追加でき、 maximized/minimized プロパティーを持つエンティティーによって満たされる必要があります。
selectEntitiesOnly
- このパラメーターは、明示的な子が設定されていない場合のみ有効です。true の場合、クエリーの結果は、指定された制約を満たすリビジョンで変更されたエンティティーのリストになります。false の場合、結果は 3 つの要素の配列のリストになります。最初の要素は変更されたエンティティーインスタンスになります。次は、リビジョンデータを含むエンティティーです。カスタムエンティティーが使用されていない場合、
DefaultRevisionEntity
のインスタンスになります。3 番目の要素アレイはリビジョンのタイプ (ADD、MOD、DEL) になります。 selectDeletedEntities
- このパラメーターは、エンティティーが削除されたリビジョンを結果に含める必要があるかどうかを指定します。true の場合、エンティティーにはリビジョンタイプ
DEL
が指定され、id を除くすべてのフィールドの値はnull
になります。
例13.35 所定プロパティーを変更するエンティティーのクエリーの修正
MyEntity
指定された ID を使用します。actualDate
プロパティーが変更されました。
AuditQuery query = getAuditReader().createQuery() .forRevisionsOfEntity(MyEntity.class, false, true) .add(AuditEntity.id().eq(id)); .add(AuditEntity.property("actualDate").hasChanged())
hasChanged
条件は、追加の基準と組み合わせることができます。以下のクエリーは、revisionNumber の生成時に MyEntity
の水平スライスを返します。変更されたリビジョンに限定されますprop1
、だがしかしprop2
。
AuditQuery query = getAuditReader().createQuery() .forEntitiesAtRevision(MyEntity.class, revisionNumber) .add(AuditEntity.property("prop1").hasChanged()) .add(AuditEntity.property("prop2").hasNotChanged());
MyEntities
RevisionNumber で 変更 されましたprop1
変更され、prop2
手つかず。
forEntitiesModifiedAtRevision
クエリー:
AuditQuery query = getAuditReader().createQuery() .forEntitiesModifiedAtRevision(MyEntity.class, revisionNumber) .add(AuditEntity.property("prop1").hasChanged()) .add(AuditEntity.property("prop2").hasNotChanged());
例13.36 指定リビジョンでのクエリーエンティティーの変更
Set<Pair<String, Class>> modifiedEntityTypes = getAuditReader() .getCrossTypeRevisionChangesReader().findEntityTypes(revisionNumber);
org.hibernate.envers.CrossTypeRevisionChangesReader
:
List<Object> findEntities(Number)
- 指定のリビジョンで変更された (追加、更新、削除された) すべての監査済みエンティティーのスナップショットを返します。
n+1
SQL クエリーを実行します。n
は、指定されたリビジョン内で変更された複数の異なるエンティティークラスです。 List<Object> findEntities(Number, RevisionType)
- 変更タイプでフィルターされた特定のリビジョンで変更 (追加、更新、または削除) されたすべての監査済みエンティティーのスナップショットを返します。
n+1
SQL クエリーを実行します。n
は、指定されたリビジョン内で変更された複数の異なるエンティティークラスです。 Map<RevisionType, List<Object>> findEntitiesGroupByRevisionType(Number)
- 変更操作 (追加、更新、削除など) ごとにグループ化されたエンティティースナップショットのリストを含むマップを返します。
3n+1
SQL クエリーを実行します。n
は、指定されたリビジョン内で変更された複数の異なるエンティティークラスです。
13.8. パフォーマンスチューニング
13.8.1. 他のバッチロードアルゴリズム
- クラス当たりのレベルHibernate がクラス当たりのレベルでデータを読み込む場合は、クエリーの実行時にロードする関連付けのバッチサイズが必要になります。たとえば、ランタイム時に、セッションに 30 個のインスタンスの
car
オブジェクトがロードされているとします。各car
オブジェクトはowner
オブジェクトに属します。すべてのcar
オブジェクトを繰り返し処理し、所有者を要求する場合、lazy
読み込みでは、Hibernate は所有者ごとに 30 個の select ステートメントを発行します。これはパフォーマンスのボトルネックです。代わりに、Hibernate に対して、クエリーを経由する前に所有者の次のバッチのデータを事前に読み込むように指示することもできます。owner
オブジェクトがクエリーされると、Hibernate は同じ SELECT ステートメントで多くのこれらのオブジェクトをクエリーします。事前にクエリーするowner
オブジェクトの数は、設定時に指定されたbatch-size
パラメーターによって異なります。<class name="owner" batch-size="10"></class>
これにより、Hibernate は、後で必要と予想される 10 個以上のowner
オブジェクトをクエリーするようになります。ユーザーがクエリーを実行するとowner
のcar A
、owner
のcar B
バッチロードの一部としてすでにロードされている可能性があります。ユーザーがデータベースに移動 (および SELECT ステートメントを実行) する代わりに、実際にcar B
のowner
が必要な場合は、現在のセッションから値を取得できます。batch-size
パラメーターに加えて、Hibernate 4.2.0 ではバッチロードのパフォーマンスを強化する新しい設定項目が導入されました。設定アイテムは呼び出されますBatch Fetch Style
設定であり、hibernate.batch_fetch_style
パラメーターで指定されます。LEGACY、PADDED、DYNAMIC といった異なるバッチフェッチスタイルがサポートされています。使用するスタイルを指定するには、org.hibernate.cfg.AvailableSettings#BATCH_FETCH_STYLE
。- レガシー: レガシースタイルの読み込みでは、に基づいて事前に作成されたバッチサイズのセット
ArrayHelper.getBatchSizes(int)
利用されます。バッチは、既存のバッチ可能な識別子の数からの次に小さな事前ビルドされたバッチサイズを使用してロードされます。上記の例を続けて、batch-size
30 に設定すると、事前に作成されたバッチサイズは 30、15、10、9、8、7、..、1 になります。ロード 29 識別子のバッチ処理を試みると、15、10、および 4 のバッチが発生します。対応する SQL クエリーは 3 つあり、各クエリーはデータベースから 15、10、および 4 の所有者 (owner) を読み込みます。 - PADDED - PADDED は、バッチローディングの LEGACY スタイルに似ています。依然として事前ビルドされたバッチサイズを使用していますが、次に大きなバッチサイズを使用し、追加の識別子プレースホルダーをパディングします。上記の例と同様に、30 個の owner オブジェクトを初期化する場合、データベースに対してクエリーが実行されるのは 1 つのみとなります。ただし、29 個の owner オブジェクトが初期化される場合でも、Hibernate は依然としてバッチサイズ 30 の SQL select ステートメントのみを実行し、識別子が連続する追加スペースがパディングされます。
- Dynamic - バッチサイズの制限に準拠していますが、このスタイルのバッチロードは、実際に読み込まれるオブジェクト数を使用して SQL SELECT ステートメントを動的に構築します。たとえば、owner オブジェクトが 30 個で、最大バッチサイズが 30 の場合、30 個の owner オブジェクトを取得する呼び出しは、1 つの SQL SELECT ステートメントになります。35 個を取得する呼び出しは、バッチサイズ 30 と 5 の 2 つの SQL ステートメントになります。Hibernate は、必要な数である 5 を維持するために 第 2 の SQL ステートメントを動的に変更します。また、バッチサイズは制限の 30 のままに保持します。これは、PADDED バージョンとは異なります。第 2 の SQL は PADDED されません。LEGACY スタイルとは異なり、第 2 の SQL ステートメントには固定サイズがなく、次の SQL は動的に作成されます。クエリーが 30 個の識別子を下回る場合、このスタイルは要求された識別子の数のみを動的に読み込みます。
- コレクション当たりのレベルHibernate では、上記の各クラス当たりのセクションにリストされているバッチフェッチサイズとスタイルを採用するロードコレクションのバッチ処理も可能です。前のセクションで使用した例を戻すには、各
owner
オブジェクトが所有するすべてのcar
オブジェクトをロードする必要があることを考慮してください。10 個のowner
オブジェクトが現行セッションでロードされ、すべての owner で 反復すると、10 個の SELECT ステートメントが生成されます (getCars()
メソッドへの呼び出しごと)。Owner のマッピングで cars コレクションのバッチフェッチを有効にすると、Hibernate は以下のようにこれらのコレクションの事前フェッチを実行できます。<class name="Owner"><set name="cars" batch-size="5"></set></class>
したがって、バッチサイズが 5 で、レガシーバッチスタイルを使用して 10 のコレクションをロードする場合、Hibernate は 2 つの SELECT ステートメントを実行し、それぞれが 5 のコレクションを取得することになります。
13.8.2. 変更不可のデータのオブジェクト参照の 2 次レベルのキャッシング
hibernate.cache.use_reference_entries
にtrue
。デフォルトでは、hibernate.cache.use_reference_entries
に設定されていますfalse
。
hibernate.cache.use_reference_entries
に設定されていますtrue
、関連付けのない不変のデータオブジェクトは、第 2 レベルのキャッシュにコピーされず、そのオブジェクトへの参照のみが保存されます。
hibernate.cache.use_reference_entries
に設定されていますtrue
、関連付けのある不変のデータオブジェクトは、引き続き第 2 レベルのキャッシュに深くコピーされます。
第14章 Hibernate Search
14.1. Hibernate Search の使用
14.1.1. Hibernate Search について
14.1.2. Hibernate Search を使用する最初の手順
- Hibernate Search を設定するには、JBoss EAP 『管理および設定ガイド』 の 『設定』 を参照してください。
14.1.3. Maven を使用した Hibernate Search の有効化
hibernate-search-orm
依存関係を追加します。
<dependencyManagement> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-search-orm</artifactId> <version>4.6.0.Final-redhat-2</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-search-orm</artifactId> <scope>provided</scope> </dependency> </dependencies>
14.1.4. アノテーションの追加
example.Book
および example.Author
が含まれ、アプリケーションにフリーテキスト検索機能を追加して、書籍の検索を有効にする場合。
例14.1 Hibernate Search 固有のアノテーションを追加する前のエンティティーブックおよび作成者
package example; ... @Entity public class Book { @Id @GeneratedValue private Integer id; private String title; private String subtitle; @ManyToMany private Set<Author> authors = new HashSet<Author>(); private Date publicationDate; public Book() {} // standard getters/setters follow here ... }
package example; ... @Entity public class Author { @Id @GeneratedValue private Integer id; private String name; public Author() {} // standard getters/setters follow here ... }
Book
クラスおよび Author
クラスにアノテーションをいくつか追加する必要があります。最初のアノテーション @Indexed
は Book
にインデックス可能 (indexable) のマークを付けます。デザイン上、Hibernate Search は未認証の ID をインデックスに保存し、特定のエンティティーのインデックスの一意性を確保します。@DocumentId
は、この目的に使用するプロパティーをマークし、ほとんどの場合はデータベースのプライマリーキーと同じです。@DocumentId
アノテーションは、@Id
アノテーションが存在する場合は任意です。
title
と subtitle
で始まります。両方に、@Field
アノテーションを付けます。パラメーター index=Index.YES
は、テキストが確実にインデックス化されるようにします。一方、analyze=Analyze.YES
は、デフォルトの Lucene アナライザーを使用してテキストが分析されるようにします。通常、分析とは個別の単語に文章を分け、'a'
や `the
'.などの一般的な単語を除外できる可能性があることを意味します。アナライザーについてもう少し後ほど説明します。@Field
で指定する第 3 のパラメーター store=Store.NO
は、実際のデータがインデックスに保存されないようにします。このデータがインデックスに保存されているかどうかや、そのデータを検索する機能がないかどうかです。Lucene の観点からは、インデックスが作成されてからデータを保持する必要はありません。これを保存する利点は、projections を介してそれを取得することです (「プロジェクション」 を参照してください)。
Index=Index.YES
, analyze=Analyze.YES
および store=Store.NO
はこれらのパラメーターのデフォルト値であるため、省略できることに注意してください。
@DateBridge
です。このアノテーションは、Hibernate Search の組み込みフィールドブリッジのいずれかになります。Lucene インデックスは文字列ベースです。このため、Hibernate Search はインデックス化されたフィールドの値タイプを文字列 (またはその逆) に変換する必要があります。事前定義されたブリッジの範囲が提供されます。これには、java.util.Date
を指定の解決が含まれる String
に変換する DateBridge
が含まれます。詳細は、「ブリッジ」 を参照してください。
@IndexedEmbedded が残ります。
このアノテーションは、所有するエンティティーの一部として、関連付けられたエンティティー (@ ManyToMany
、@ * ToOne
、@ Embedded、および @ElementCollection
)
にインデックスを付けるために使用されます。これは、Lucene インデックスドキュメントがオブジェクト関係について不明なフラットデータ構造であるため必要になります。作成者の名前を確実に検索できるようにするには、名前を書籍の一部としてインデックス化する必要があります。@IndexedEmbedded
のほかに、インデックスに含める関連エンティティーのフィールドすべてを @Indexed
でマークする必要があります。詳細は、「埋め込みおよび関連オブジェクト」 を参照してください。
例14.2 Hibernate Search アノテーションの追加後のエンティティー
package example; ... @Entity @Indexed public class Book { @Id @GeneratedValue private Integer id; @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO) private String title; @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO) private String subtitle; @Field(index = Index.YES, analyze=Analyze.NO, store = Store.YES) @DateBridge(resolution = Resolution.DAY) private Date publicationDate; @IndexedEmbedded @ManyToMany private Set<Author> authors = new HashSet<Author>(); public Book() { } // standard getters/setters follow here ... }
package example;
...
@Entity
public class Author {
@Id
@GeneratedValue
private Integer id;
@Field
private String name;
public Author() {
}
// standard getters/setters follow here
...
}
14.1.5. インデックス化
例14.3 Hibernate セッションを使用してデータにインデックスを付ける
FullTextSession fullTextSession = org.hibernate.search.Search.getFullTextSession(session); fullTextSession.createIndexer().startAndWait();
例14.4 JPA を使用したデータのインデックス作成
EntityManager em = entityManagerFactory.createEntityManager(); FullTextEntityManager fullTextEntityManager = org.hibernate.search.jpa.Search.getFullTextEntityManager(em); fullTextEntityManager.createIndexer().startAndWait();
/var/lucene/indexes/example.Book
に Lucene インデックスが表示されるはずです。Luke でこのインデックスを調べてください。HibernateSearch がどのように機能するかを理解するのに役立ちます。
14.1.6. 検索
org.hibernate.Query
にクエリーをラップし、Hibernate API から必要な機能を取得します。以下のコードは、インデックスフィールドに対するクエリーを準備します。コードを実行すると、Book
の一覧が返されます。
例14.5 Hibernate Search セッションを使用した検索の作成および実行
FullTextSession fullTextSession = Search.getFullTextSession(session); Transaction tx = fullTextSession.beginTransaction(); // create native Lucene query using the query DSL // alternatively you can write the Lucene query using the Lucene query parser // or the Lucene programmatic API. The Hibernate Search DSL is recommended though QueryBuilder qb = fullTextSession.getSearchFactory() .buildQueryBuilder().forEntity( Book.class ).get(); org.apache.lucene.search.Query query = qb .keyword() .onFields("title", "subtitle", "authors.name", "publicationDate") .matching("Java rocks!") .createQuery(); // wrap Lucene query in a org.hibernate.Query org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery(query, Book.class); // execute search List result = hibQuery.list(); tx.commit(); session.close();
例14.6 JPA を使用した検索の作成と実行
EntityManager em = entityManagerFactory.createEntityManager(); FullTextEntityManager fullTextEntityManager = org.hibernate.search.jpa.Search.getFullTextEntityManager(em); em.getTransaction().begin(); // create native Lucene query using the query DSL // alternatively you can write the Lucene query using the Lucene query parser // or the Lucene programmatic API. The Hibernate Search DSL is recommended though QueryBuilder qb = fullTextEntityManager.getSearchFactory() .buildQueryBuilder().forEntity( Book.class ).get(); org.apache.lucene.search.Query query = qb .keyword() .onFields("title", "subtitle", "authors.name", "publicationDate") .matching("Java rocks!") .createQuery(); // wrap Lucene query in a javax.persistence.Query javax.persistence.Query persistenceQuery = fullTextEntityManager.createFullTextQuery(query, Book.class); // execute search List result = persistenceQuery.getResultList(); em.getTransaction().commit(); em.close();
14.1.7. アナライザー
Refactoring: Improving the Design of Existing Code
で、refactor
、refactors
、refactored
、refactoring
のクエリーに必要だとします。インデックス化および検索を行う際にワードステミングを適用する Lucene でアナライザークラスを選択します。Hibernate Search は、アナライザーを設定するためのいくつかの方法を提供します (を参照)。「デフォルトの Analyzer とクラスによる Analyzer」詳細については):
- 設定ファイルに
analyzer
プロパティーを設定します。指定されたクラスがデフォルトのアナライザーになります。 - エンティティーレベルで
アノテーションを設定します。@Analyzer
- フィールドレベルで
@
アノテーションを設定します。Analyzer
@Analyzer
アノテーションとともに @AnalyzerDef
アノテーションで定義されているアナライザーを確認します。Solr アナライザーフレームワークとそのファクトリーは、後者のオプションに使用されます。ファクトリークラスの詳細は、Solr JavaDoc を参照するか、Solr Wiki (http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters) の該当するセクションを参照してください。
StandardTokenizerFactory
が、LowerCaseFilterFactory
と SnowballPorterFilterFactory
の 2 つのフィルターファクトリーによって使用されています。トークンライザーは、英数字とハイフンで単語を分割しますが、メールアドレスとインターネットのホスト名は維持します。標準トークンは、これおよびその他の一般的な操作に適しています。小文字フィルターはトークンのすべての文字を小文字に変換し、snowball フィルターは言語固有のステミングを適用します。
例14.7 @AnalyzerDef および Solr Framework を使用した Analyzer の定義および使用
@Indexed @AnalyzerDef( name = "customanalyzer", tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), filters = { @TokenFilterDef(factory = LowerCaseFilterFactory.class), @TokenFilterDef(factory = SnowballPorterFilterFactory.class, params = { @Parameter(name = "language", value = "English") }) }) public class Book implements Serializable { @Field @Analyzer(definition = "customanalyzer") private String title; @Field @Analyzer(definition = "customanalyzer") private String subtitle; @IndexedEmbedded private Set authors = new HashSet(); @Field(index = Index.YES, analyze = Analyze.NO, store = Store.YES) @DateBridge(resolution = Resolution.DAY) private Date publicationDate; public Book() { } // standard getters/setters follow here ... }
@AnalyzerDef
を使用してアナライザーを定義し、@Analyzer
を使用してエンティティーおよびプロパティーに適用します。この例では、customanalyzer
は定義されますが、エンティティーには適用されません。アナライザーは title
および subtitle
プロパティーのみに適用されます。アナライザーの定義はグローバルです。エンティティーのアナライザーを定義し、必要に応じて他のエンティティーの定義を再利用します。
14.2. インデックス構造へのエンティティーのマッピング
14.2.1. エンティティーのマッピング
14.2.1.1. 基本的なマッピング
- @Indexed
- @Field
- @NumericField
- @Id
14.2.1.1.1. @Indexed
@Indexed
アノテーションを付けることで行われます (@Indexed
アノテーションが付いていないすべてのエンティティーはインデックスプロセスによって無視されます)。
例14.8 @Indexed
を使用してクラスをインデックス可能にする
@Entity
@Indexed
public class Essay {
...
}
index
属性を指定して、インデックスのデフォルト名を変更できます。
14.2.1.1.2. @Field
@Field
はプロパティーをインデックスとして宣言し、以下の属性のいずれかを設定してインデックスプロセスの複数の側面を設定できます。
name
: プロパティーがどの名前下で、Lucene Document に保存されるべきかを説明します。デフォルト値はプロパティー名です (続く JavaBeans 規則)。store
: プロパティーが Lucene インデックスに保存されているかどうかを示します。Store.YES
の値 (インデックスに多くの領域が必要ですが projection を許可 「プロジェクション」 を参照) を保存するか、これを圧縮方式Store.COMPRESS
で保存、あるいは、Store.NO
を回避することができます (デフォルト値)。プロパティーが保存されると、Lucene ドキュメントから元の値を取得できます。これは、要素がインデックス化されるかどうかに関連しません。index
: プロパティーがインデックス化されるかどうかを示します。異なる値は、Index.NO
(インデックス付けなし、つまりクエリーで見つけることができない)、Index.YES
(要素にインデックスが付けられて検索可能) です。デフォルト値はIndex.YES
です。Index.NO
は、プロパティーの検索が不可能であるものの、利用できる必要がある場合に便利です。注記Index.NO
をAnalyze.YES
またはNorms.YES
と組み合わせると有用なわけではありません。これは、analyze
とnorms
と解析のプロパティーのインデックス作成が必要ないためです。analyze
: プロパティーが分析されたかどうか (Analyze.YES
) または (Analyze.NO
) を判断します。デフォルト値はAnalyze.YES
です。注記プロパティーを分析するかどうかは、要素をそのまま0検索する場合と、含まれる単語で検索するかによって異なります。テキストフィールドを分析することは理にかなっていますが、日付フィールドは分析しません。注記ソートに使用されるフィールドは、分析できません。norms
: インデックス時間の改善情報を保存する必要があるかどうか (Norms.YES
) または (Norms.NO
) を示します。これを保存しないと、大量のメモリーを節約できますが、インデックスの時間が改善する情報は提供されません。デフォルト値はNorms.YES
です。termVector
: 用語と周波数のペア (term-frequency) のコレクションについて説明しています。この属性により、インデックス作成中にドキュメント内にベクターを保存することができます。デフォルト値はTermVector.NO
です。この属性の異なる値は次のとおりです。値 定義 TermVector.YES 各ドキュメントのTerm Vectors を保存します。これにより、同期されたアレイが作成され、これらはドキュメント用語が含まれ、他は用語の周波数が含まれます。 TermVector.NO Term Vector は保存しないでください。 TermVector.WITH_OFFSETS Term Verctor およびトークンオフセット情報を保存します。これは TermVector.YES と同様で、用語の開始および終了オフセット位置情報が含まれます。 TermVector.WITH_POSITIONS Term Verctor およびトークン位置情報を保存します。これは TermVector.YES と同じですが、ドキュメント内の各用語の特徴も含まれます。 TermVector.WITH_POSITION_OFFSETS Term Vector 、トークンの位置、およびオフセット情報を格納します。これは、YES、WITH_OFFSETS、および WITH_POSITIONS の組み合わせです。 indexNullAs
: デフォルトの null 値ごとに無視され、インデックスは作成されません。ただし、indexNullAs
を使用すると、null
値のトークンとして挿入される文字列を指定できます。デフォルトでは、この値はに設定されていますField.DO_NOT_INDEX_NULL
そのことを示すnull
値にインデックスを付けないでください。この値を次のように設定できますField.DEFAULT_NULL_TOKEN
デフォルトであることを示すnull
トークンを使用する必要があります。このデフォルトのnull
トークンは、hibernate.search.default_null_token
を使用して設定に指定できます。このプロパティーが設定されておらず、指定した場合Field.DEFAULT_NULL_TOKEN
文字列 _null_ がデフォルトとして使用されます。注記indexNullAs
パラメーターを使用する場合は、検索クエリーで同じトークンを使用してnull
値を検索することが重要です。また、この機能は、非分析フィールド (
) でのみ使用することが推奨されます。analyze=
Analyze.NO警告カスタムFieldBridge
またはTwoWayFieldBridge
を実装する場合、null 値のインデックス作成を処理するのは開発者の責任です (の JavaDocs を参照してください。LuceneOptions.indexNullAs()
)。
14.2.1.1.3. @NumericField
@Field
には @NumericField
というコンパニオンアノテーションがあり、@Field
または @DocumentId
と同じスコープで指定できます。このプロパティーは、Integer、Long、Float、および LastName プロパティーに指定できます。インデックスの作成時に、値は Trie 構造を使用してインデックス化されます。プロパティーを数字フィールドとしてインデックス化すると、標準的な @Field
プロパティーに対して同じクエリーを実行するよりも、効率的な範囲クエリーとソートが可能になります。@NumericField
アノテーションは以下のパラメーターを受け入れます。
値 | 定義 |
---|---|
forField | (オプション) 数値としてインデックス化される関連 @Field の名前を指定します。@Field 宣言を超えるプロパティーが含まれる場合にのみ必須となります。 |
precisionStep | (オプション) インデックスに Trie 構造を格納する方法を変更します。precisionStes を小さくすると、ディスク領域の使用率が高くなり、範囲やソートのクエリーが速くなります。値が大きいほど使用領域が少なくなり、クエリーのパフォーマンスは通常の @Fields の範囲のクエリーに近づくことになります。デフォルト値は 4 です。 |
NumericField
は、Double
、Long
、Integer
、Float
のみをサポートしています。他の数値タイプには Lucene で同様の機能を活用できないため、残りのタイプはデフォルトまたはカスタムの TwoWayFieldBridge
で文字列エンコーディングを使用する必要があります。
NumericFieldBridge
を使用することができます。
例14.9 カスタム NumericFieldBridge
の定義
public class BigDecimalNumericFieldBridge extends NumericFieldBridge { private static final BigDecimal storeFactor = BigDecimal.valueOf(100); @Override public void set(String name, Object value, Document document, LuceneOptions luceneOptions) { if ( value != null ) { BigDecimal decimalValue = (BigDecimal) value; Long indexedValue = Long.valueOf( decimalValue.multiply( storeFactor ).longValue() ); luceneOptions.addNumericFieldToDocument( name, indexedValue, document ); } } @Override public Object get(String name, Document document) { String fromLucene = document.get( name ); BigDecimal storedBigDecimal = new BigDecimal( fromLucene ); return storedBigDecimal.divide( storeFactor ); } }
14.2.1.1.4. @Id
id
(identifier) プロパティーは、特定のエンティティーのインデックスを一意に保つために Hibernate Search で使用される特別なプロパティーです。設計上、id
は保存する必要があり、トークン化しないでください。プロパティーをインデックス識別子としてマークするには、@DocumentId
アノテーションを使用します。JPA を使用し、@Id
を指定した場合は、@DocumentId
を省略できます。選択したエンティティー ID は、ドキュメント識別子として使用されます。
例14.10 インデックス付きプロパティーの指定
@Entity @Indexed public class Essay { ... @Id @DocumentId public Long getId() { return id; } @Field(name="Abstract", store=Store.YES) public String getSummary() { return summary; } @Lob @Field public String getText() { return text; } @Field @NumericField( precisionStep = 6) public float getGrade() { return grade; } }
id
、Abstract
、text
、grade
の 4 つのフィールドでインデックスを定義します。デフォルトでは、JavaBean 仕様にしたがってフィールド名は大文字では表示されないことに注意してください。Grade
フィールドは、デフォルトよりも若干精度の高いステップで数字としてアノテーションが付けられます。
14.2.1.2. 複数回のプロパティーのマッピング
例14.11 @Fields を使用してプロパティーを複数回マップする
@Entity @Indexed(index = "Book" ) public class Book { @Fields( { @Field, @Field(name = "summary_forSort", analyze = Analyze.NO, store = Store.YES) } ) public String getSummary() { return summary; } ... }
summary
は 2 回インデックス化されます。これはトークン化方式の summary
、非トークン化方式の summary_forSort
で行われます。
14.2.1.3. 埋め込みおよび関連オブジェクト
address.city:Atlanta
に変換されます)。場所フィールドは、Place
インデックスでインデックス化されます。Placement
インデックスドキュメントには、クエリー可能な address.id
、address.street
、address.city
フィールドも含まれます。
例14.12 インデックスアソシエーション
@Entity @Indexed public class Place { @Id @GeneratedValue @DocumentId private Long id; @Field private String name; @OneToOne( cascade = { CascadeType.PERSIST, CascadeType.REMOVE } ) @IndexedEmbedded private Address address; .... } @Entity public class Address { @Id @GeneratedValue private Long id; @Field private String street; @Field private String city; @ContainedIn @OneToMany(mappedBy="address") private Set<Place> places; ... }
@IndexedEmbedded
技術を使用すると、データは Lucene インデックスで非正規化されるため、Hibernate Search は Place
オブジェクトのすべての変更と、インデックスを最新の状態に保つため Address
オブジェクトの変更を認識する必要があります。Place
Lucene ドキュメントが Address
の変更時に更新されるようにするには、双方向関係の反対側に @ContainedIn
のマークを付けます。
@ContainedIn
はエンティティーを参照する関連付けや、組み込み (コレクション) オブジェクトを参照する関連付けで役立ちます。
例14.13 @IndexedEmbedded
および @ContainedIn
のネスト化された使用方法
@Entity @Indexed public class Place { @Id @GeneratedValue @DocumentId private Long id; @Field private String name; @OneToOne( cascade = { CascadeType.PERSIST, CascadeType.REMOVE } ) @IndexedEmbedded private Address address; .... } @Entity public class Address { @Id @GeneratedValue private Long id; @Field private String street; @Field private String city; @IndexedEmbedded(depth = 1, prefix = "ownedBy_") private Owner ownedBy; @ContainedIn @OneToMany(mappedBy="address") private Set<Place> places; ... } @Embeddable public class Owner { @Field private String name; ... }
@*ToMany, @*ToOne
および @Embedded
属性は、@IndexedEmbedded
アノテーションを付けることができます。その後、関連クラスの属性が主なエンティティーインデックスに追加されます。例14.13「@IndexedEmbedded
および @ContainedIn
のネスト化された使用方法」 インデックスには以下のフィールドが含まれます。
- id
- name
- address.street
- address.city
- address.ownedBy_name
propertyName.
で、従来のオブジェクトナビゲーション規則に従います。ownedBy
プロパティーに示されるように、prefix
属性を使用して上書きできます。
depth
プロパティーは、オブジェクトグラフにクラス (インスタンスではない) の cyclic 依存関係が含まれるときに必要になります。たとえば、Owner
が Place
をポイントする場合です。Hibernate Search は、予想される深さに達すると (またはオブジェクトグラフの境界に到達する)、インデックス化された組み込み属性を含まなくなります。自己参照を持つクラスは、cyclic 依存関係の例です。この例では、depth
が 1 に設定されているため、Owner の @IndexedEmbedded
属性は無視されます。
@IndexedEmbedded
を使用すると、以下のようなクエリーを表現できます (Lucene のクエリー構文を使用)。
- 名前に JBoss が含まれ、住所の都市がアトランタである場所を返します。Lucene クエリーでは、以下のようになります。
+name:jboss +address.city:atlanta
- 名前に JBoss が含まれ、所有者の名前に Joe が含まれる場所を返します。Lucene クエリーでは、以下のようになります。
+name:jboss +address.ownedBy_name:joe
@Indexed
にすることができます (ただし、必須ではありません)。
@ContainedIn
を付ける必要があります (前述の例を参照)。これがない場合、Hibernate Search は関連エンティティーの更新時にルートインデックスを更新することはできません (この例では、関連付けられた Address
インスタンスの更新時に Place
インデックスドキュメントを更新する必要があります)。
@IndexedEmbedded
アノテーションが付けられたオブジェクトタイプは、Hibernate および Hibernate Search によってターゲットに設定されたオブジェクトタイプではない場合があります。これは、インターフェースが実装の代わりに使用される場合にとくに当てはまります。このため、Hibernate Search の対象となるオブジェクトタイプを、targetElement
パラメーター。
例14.14 @IndexedEmbedded
の targetElement
プロパティーの使用
@Entity
@Indexed
public class Address {
@Id
@GeneratedValue
@DocumentId
private Long id;
@Field
private String street;
@IndexedEmbedded(depth = 1, prefix = "ownedBy_", targetElement = Owner.class)
@Target(Owner.class)
private Person ownedBy;
...
}
@Embeddable
public class Owner implements Person { ... }
14.2.1.4. 特定のパスへのオブジェクト埋め込みの制限
@IndexedEmbedded
アノテーションは属性も提供しますincludePaths
の代わりに使用できますdepth
、またはそれと組み合わせる。
depth
のみを使用すると、埋め込み型のインデックス設定されたフィールドはすべて、同じデプスで再帰的に追加されます。これにより、他のフィールドもすべて追加せずに特定のパスのみを選択することが困難になります。これは必須ではありません。
@IndexedEmbedded
の includePaths
プロパティーの使用」 のようにパスを明示的に指定する必要がある場合があります。
例14.15 @IndexedEmbedded
の includePaths
プロパティーの使用
@Entity
@Indexed
public class Person {
@Id
public int getId() {
return id;
}
@Field
public String getName() {
return name;
}
@Field
public String getSurname() {
return surname;
}
@OneToMany
@IndexedEmbedded(includePaths = { "name" })
public Set<Person> getParents() {
return parents;
}
@ContainedIn
@ManyToOne
public Human getChild() {
return child;
}
...//other fields omitted
@IndexedEmbedded
の includePaths
プロパティーの使用」、名前
や名前、および/または 親
の 名前
で 人物
を検索できます。親の surname
をインデックス化しないため、親の surname を検索することはできません。ただし、インデックス作成を迅速化し、スペースを節約して、全体的なパフォーマンスを向上させることができます。
@IndexedEmbedded
includePaths
制限された値を指定して通常インデックスを作成 するものに加えて、指定されたパスが含まれますdepth
。使用する場合includePaths
、そして去るdepth
未定義、動作は設定と同等ですdepth
= 0
: 含まれているパスのみにインデックスが付けられます。
例14.16 @IndexedEmbedded
の includePaths
プロパティーの使用
@Entity
@Indexed
public class Human {
@Id
public int getId() {
return id;
}
@Field
public String getName() {
return name;
}
@Field
public String getSurname() {
return surname;
}
@OneToMany
@IndexedEmbedded(depth = 2, includePaths = { "parents.parents.name" })
public Set<Human> getParents() {
return parents;
}
@ContainedIn
@ManyToOne
public Human getChild() {
return child;
}
...//other fields omitted
@IndexedEmbedded
の includePaths
プロパティーの使用」、すべての人間の名前と名前の属性にインデックスが付けられます。また、depth
属性が原因で、親の名前と surname (姓) も再帰的に 2 行目にインデックス化されます。人が直接、自身の親、または親の名前で検索することができます。第 2 レベル以外では、姓 (surname) ではなく、もう 1 レベル (名前のみ) をインデックス化します。
id
- プライマリーキーとして_hibernate_class
- エンティティータイプを保存name
- 直接フィールドとしてsurname
- 直接フィールドとしてparents.name
- デプス 1 の埋め込みフィールドとしてparents.surname
- デプス 1 の埋め込みフィールドとしてparents.parents.name
: デプス 2 の埋め込みフィールドとしてparents.parents.surname
- デプス 2 の埋め込みフィールドとして親.parents.parents.name-
によって指定された追加のパスとしてincludePaths
。最初のparents.
はフィールド名から推測され、残りのパスはincludePaths
の属性です。
14.2.2. Boosting
14.2.2.1. 静的インデックスの時間の改善
@Boost
アノテーションを使用できます。このアノテーションは、@Field 内で使用することも、メソッドまたはクラスレベルで直接指定することもできます。
例14.17 @Boost のさまざまな使用方法
@Entity @Indexed @Boost(1.7f) public class Essay { ... @Id @DocumentId public Long getId() { return id; } @Field(name="Abstract", store=Store.YES, boost=@Boost(2f)) @Boost(1.5f) public String getSummary() { return summary; } @Lob @Field(boost=@Boost(1.2f)) public String getText() { return text; } @Field public String getISBN() { return isbn; } }
エッセイ
が検索リストの一番上に到達する確率は 1.7 倍になります。Thesummary
フィールドは 3.0 になります (2 * 1.5、@Field.boost
およびプロパティーの @Boost
は累積的です) より重要ですisbn
分野。Thetext
フィールドは 1.2 倍重要になりますisbn
分野。この説明は、最も厳格な条件では間違っていますが、あらゆる実用的な目的において、実用性に十分に近い点に注意してください。
14.2.2.2. 動的インデックス時間の改善
@Boost
アノテーション「静的インデックスの時間の改善」実行時のインデックス付きエンティティーの状態に依存しない静的ブースト係数を定義します。ただし、改善要因がエンティティーの実際の状態に依存する可能性があるユースケースがあります。この場合は、@DynamicBoost
アノテーションと付随するカスタム BoostStrategy
を使用できます。
例14.18 ダイナミックブーストの例
public enum PersonType { NORMAL, VIP } @Entity @Indexed @DynamicBoost(impl = VIPBoostStrategy.class) public class Person { private PersonType type; // .... } public class VIPBoostStrategy implements BoostStrategy { public float defineBoost(Object value) { Person person = ( Person ) value; if ( person.getType().equals( PersonType.VIP ) ) { return 2.0f; } else { return 1.0f; } } }
BoostStrategy
インターフェースの実装として VIPBoostStrategy
を指定するクラスレベルで定義されます。@DynamicBoost
は、クラスまたはフィールドレベルのいずれかで配置できます。アノテーションの配置に応じて、エンティティー全体が defineBoost
メソッドに渡されるか、アノテーションが付いたフィールド/プロパティー値のみに渡されます。渡されたオブジェクトを正しいタイプにキャストするのはユーザー自身です。この例では、VIP ユーザーのすべてのインデックス化された値が通常の人の値と同じくらい重要になります。
BoostStrategy
実装は、パブリックの no-arg コンストラクターを定義する必要があります。
@Boost
と @DynamicBoost
DynamicBoost アノテーションを混在させることができます。定義されたすべてのブースター要素は累積的です。
14.2.3. 分析
Analysis
、テキストを 単一の用語 (単語) に変換するプロセスであり、フルテキスト検索エンジンの主な機能として見なされます。Lucene は、Analyzer
の概念を使用してこのプロセスを制御します。以下のセクションでは、Hibernate Search がアナライザーを設定するために提供する複数の方法について説明します。
14.2.3.1. デフォルトの Analyzer とクラスによる Analyzer
hibernate.search.analyzer
プロパティーで設定できます。このプロパティーのデフォルト値は org.apache.lucene.analysis.standard.StandardAnalyzer
です。
例14.19 @Analyzer のさまざまな使用方法
@Entity @Indexed @Analyzer(impl = EntityAnalyzer.class) public class MyEntity { @Id @GeneratedValue @DocumentId private Integer id; @Field private String name; @Field @Analyzer(impl = PropertyAnalyzer.class) private String summary; @Field( analyzer = @Analyzer(impl = FieldAnalyzer.class ) private String body; ... }
EntityAnalyzer
を使用して、PropertyAnalyzer
と FieldAnalyzer
でインデックス化される summary
と body
を除き トークン化されたプロパティー (name
) をインデックス化します。
14.2.3.2. Named Analyzers
@Analyzer
宣言の多くで再利用でき、以下で構成されています。
- a name: 定義を参照するために使用される一意な文字列
- a list of char filters: 各文字型フィルターは、トークン化の前に入力文字を事前処理します。文字型フィルターでは、文字の追加、変更、削除ができます。一般的な使用方法として、文字を正規化する方法があります。
- a tokenizer: 入力ストリームを個別の単語にトークン化します。
- a list of filters: 各フィルターは、単語の削除や変更を行い、トークンライザーが提供するストリームに単語を追加することさえあります。
Tokenizer
は、文字入力を TokenFilter
によってさらに処理されるトークンに変換してトークン処理を開始します。Hibernate Search は Solr Analyzer フレームワークを使用してこのインフラストラクチャーをサポートします。
lucene-snowball
jar も含める必要があり、PhoneticFilterFactory
には、commons-codecjar が必要です。Hibernate Search のディストリビューションは、lib/optional
ディレクトリーにこれらの依存関係を提供します。
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-search-analyzers</artifactId> <version>4.6.0.Final-redhat-2</version> <scope>provided</scope> <dependency>
@AnalyzerDef
と Solr フレームワーク」。まず、文字型フィルターはファクトリーによって定義されます。この例では、マッピング文字型フィルターが使用され、マッピングファイルに指定されたルールに基づいて入力内の文字が置き換えられます。次にトークナイザーを定義します。この例では、標準トークナイザーを使用します。最後に同じように重要に、のフィルターの一覧がファクトリーによって定義されます。この例では、StopFilter
フィルターは、専用の用語プロパティーファイルを読み取ります。フィルターはケースを無視することも予想されます。
例14.20 @AnalyzerDef
と Solr フレームワーク
@AnalyzerDef(name="customanalyzer", charFilters = { @CharFilterDef(factory = MappingCharFilterFactory.class, params = { @Parameter(name = "mapping", value = "org/hibernate/search/test/analyzer/solr/mapping-chars.properties") }) }, tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), filters = { @TokenFilterDef(factory = ISOLatin1AccentFilterFactory.class), @TokenFilterDef(factory = LowerCaseFilterFactory.class), @TokenFilterDef(factory = StopFilterFactory.class, params = { @Parameter(name="words", value= "org/hibernate/search/test/analyzer/solr/stoplist.properties" ), @Parameter(name="ignoreCase", value="true") }) }) public class Team { ... }
@AnalyzerDef
アノテーションで定義された順序で適用されます。順序は重要です。
resource_charset
パラメーターを追加して明示的に指定できます。
例14.21 特定の文字セットを使用したプロパティーファイルの読み込み
@AnalyzerDef(name="customanalyzer", charFilters = { @CharFilterDef(factory = MappingCharFilterFactory.class, params = { @Parameter(name = "mapping", value = "org/hibernate/search/test/analyzer/solr/mapping-chars.properties") }) }, tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), filters = { @TokenFilterDef(factory = ISOLatin1AccentFilterFactory.class), @TokenFilterDef(factory = LowerCaseFilterFactory.class), @TokenFilterDef(factory = StopFilterFactory.class, params = { @Parameter(name="words", value= "org/hibernate/search/test/analyzer/solr/stoplist.properties" ), @Parameter(name="resource_charset", value = "UTF-16BE"), @Parameter(name="ignoreCase", value="true") }) }) public class Team { ... }
@Analyzer
宣言で再利用できます。例14.22「名前でアナライザーを参照する」。
例14.22 名前でアナライザーを参照する
@Entity
@Indexed
@AnalyzerDef(name="customanalyzer", ... )
public class Team {
@Id
@DocumentId
@GeneratedValue
private Integer id;
@Field
private String name;
@Field
private String location;
@Field
@Analyzer(definition = "customanalyzer")
private String description;
}
@AnalyzerDef
で宣言された Analyzer インスタンスは、SearchFactory
の名前でも利用できます.これは、クエリーを構築する際に非常に便利です。
Analyzer analyzer = fullTextSession.getSearchFactory().getAnalyzer("customanalyzer");
14.2.3.3. 利用可能なアナライザー
表14.1 利用可能な char フィルターの例
ファクトリー | 説明 | パラメーター | 追加の依存関係 |
---|---|---|---|
MappingCharFilterFactory | リソースファイルで指定されたマッピングに基づいて、1 文字または複数の文字を 1 文字または複数の文字に置き換えます。 | マッピング : 次の形式を使用して、マッピングを含むリソースファイルを指します。
| none |
HTMLStripCharFilterFactory | HTML 標準のタグを削除し、テキストを保持します。 | none | none |
表14.2 利用可能なトークナイザーの例
ファクトリー | 説明 | パラメーター | 追加の依存関係 |
---|---|---|---|
StandardTokenizerFactory | Lucene StandardTokenizer の使用 | none | none |
HTMLStripCharFilterFactory | HTML タグを削除し、テキストを保持して StandardTokenizer に渡します。 | none | solr-core |
PatternTokenizerFactory | 指定された正規表現パターンでテキストを区切ります。 | pattern : トークン化に使用する正規表現
group: トークンに抽出するパターングループを示します。
| solr-core |
表14.3 利用可能なフィルターの例
ファクトリー | 説明 | パラメーター | 追加の依存関係 |
---|---|---|---|
StandardFilterFactory | 略語および単語からドットを削除する | none | solr-core |
LowerCaseFilterFactory | すべての単語を小文字にします | none | solr-core |
StopFilterFactory | ストップワードの一覧に一致する単語 (トークン) を削除します。 | words : ストップワードを含むリソースファイルを参照します。
ignoreCase: ストップワードを比較する際に
case が無視される必要がある場合は true、そうでない場合は false を設定します。
| solr-core |
SnowballPorterFilterFactory | 特定の言語で、単語を語根に減らします (例: protect、protects、protection は同じ語根を共有)。このようなフィルターを使用すると、関連する単語を検索できます。 | language : デンマーク語、オランダ語、英語、フィンランド語、フランス語、ドイツ語、イタリア語、ノルウェー語、ポルトガル語、ロシア語、韓国語、スウェーデン語など | solr-core |
ISOLatin1AccentFilterFactory | フランス語などの言語のアクセントを削除する | none | solr-core |
PhoneticFilterFactory | 音声的に類似したトークンをトークンストリームに挿入します | エンコーダー :DoubleMetaphone、Metaphone、Soundex または RefinedSoundex のいずれか
注入:
true ストリームにトークンを追加し、false 既存のトークンを置き換えます
maxCodeLength : 生成されるコードの最大長を設定します。Metaphone および DoubleMetaphone エンコーディングでのみサポートされます
| solr-core および commons-codec |
CollationKeyFilterFactory | 各トークンを java.text.CollationKey に変換してから、IndexableBinaryStringTools を使用して CollationKey を エンコードし、インデックス用語として保存できるようにします。 | カスタム 、言語 、国 、バリアント 、強度 、分解
詳細については、Lucene の
Collat ionKeyFilterjavadocs を参照してください。
| solr- コア と コモンズ -io |
org.apache.solr.analysis.TokenizerFactory
と org.apache.solr.analysis.TokenFilterFactory
のすべての実装を確認して、利用可能な実装を確認することが推奨されます。
14.2.3.4. 動的アナライザーの選択
BlogEntry
クラスの場合、アナライザーはエントリーの言語プロパティーに依存する可能性があります。このプロパティーによっては、実際のテキストにインデックスを付けるために正しい言語固有のスチーマーを選択する必要があります。
AnalyzerDiscriminator
アノテーションが導入されました。例14.23「@AnalyzerDiscriminator の使用法」 このアノテーションの使用法を示します。
例14.23 @AnalyzerDiscriminator の使用法
@Entity @Indexed @AnalyzerDefs({ @AnalyzerDef(name = "en", tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), filters = { @TokenFilterDef(factory = LowerCaseFilterFactory.class), @TokenFilterDef(factory = EnglishPorterFilterFactory.class ) }), @AnalyzerDef(name = "de", tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), filters = { @TokenFilterDef(factory = LowerCaseFilterFactory.class), @TokenFilterDef(factory = GermanStemFilterFactory.class) }) }) public class BlogEntry { @Id @GeneratedValue @DocumentId private Integer id; @Field @AnalyzerDiscriminator(impl = LanguageDiscriminator.class) private String language; @Field private String text; private Set<BlogEntry> references; // standard getter/setter ... }
public class LanguageDiscriminator implements Discriminator { public String getAnalyzerDefinitionName(Object value, Object entity, String field) { if ( value == null || !( entity instanceof BlogEntry ) ) { return null; } return (String) value; } }
@AnalyzerDiscriminator
を使用するための前提条件は、動的に使用されるすべてのアナライザーが @AnalyzerDef
定義で事前定義されることです 。このような場合、クラスまたはアナライザーを動的に選択するエンティティーの特定のプロパティーに @AnalyzerDiscriminator
アノテーションを配置することができます。AnalyzerDiscriminator
の impl
パラメーターを使用すると、Discriminator
インターフェースの具体的な実装を指定できます。このインターフェースの実装は、ユーザー自身が提供する必要があります。実装が必要な唯一の方法は getAnalyzerDefinitionName()
で、これは Lucene ドキュメントに追加された各フィールドに対して呼び出されます。インデックスを取得するエンティティーもインターフェースメソッドに渡されます。value
パラメーターは、AnalyzerDiscriminator
がクラスレベルではなくプロパティーレベルに配置されている場合にのみ設定されます。この場合、値はこのプロパティーの現在の値を表します。
Discriminator
インターフェースの実装では、既存のアナライザー定義の名前を返し、デフォルトのアナライザーが上書きされない場合は null
を返します。例14.23「@AnalyzerDiscriminator の使用法」 言語パラメーターは @AnalyzerDef
で指定された名前に一致する 'de' または 'en' であることを仮定しています 。
14.2.3.5. アナライザーの取得
例14.24 完全テキストクエリーの構築時のスコープ付きテナントの使用
org.apache.lucene.queryParser.QueryParser parser = new QueryParser( "title", fullTextSession.getSearchFactory().getAnalyzer( Song.class ) ); org.apache.lucene.search.Query luceneQuery = parser.parse( "title:sky Or title_stemmed:diamond" ); org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, Song.class ); List result = fullTextQuery.list(); //return a list of managed objects
title
フィールドでは標準アナライザーが使用され、title_stemmed
フィールドには、スチーミングアナライザーが使用されます。検索ファクトリーによって提供されるアナライザーを使用すると、クエリーはターゲットフィールドに応じて適切なアナライザーを使用します。
@AnalyzerDef
を介して定義されたアナライザーを、次を使用して定義名で取得することもできます。searchFactory.getAnalyzer(String)
。
14.2.4. ブリッジ
@Field
アノテーションが付けられたエンティティープロパティーはすべて、インデックス化される文字列に変換する必要があります。これまでに言及していない理由は、Hibernate Search のほとんどのプロパティーでは、組み込みブリッジのセットにより翻訳ジョブが実行されるためです。ただし、場合によっては、翻訳プロセスをより細かく制御する必要があります。
14.2.4.1. ビルトインブリッジ
- null
- デフォルトごと
null
要素はインデックス付けされません。Lucene は null 要素をサポートしません。ただし、状況によっては、null
値を表すカスタムトークンを追加すると便利です。詳細は、「@Field」 を参照してください。 - java.lang.String
- 文字列はそのままインデックス付けされます
- short、Short、integer、Integer、long、Long、float、Float、double、Double、BigInteger、BigDecimal
- 数値は文字列表現に変換されます。数値は Lucene (範囲指定のクエリーで使用される) によって追加されず、パディングする必要があることに注意してください。注記Range クエリーの使用には欠点があります。別の方法は、結果クエリーを適切な範囲に対してフィルターするフィルタークエリーを使用することです。Hibernate Search は、で説明されているように、カスタム StringBridge の使用もサポートします。「カスタムブリッジ」。
- java.util.Date
- 日付は yyyyMMddHHmmssSSS として GMT 時間 (EST 2006 年 11 月 7 日 4:03 PM 12 秒の場合は 200611072203012) として保存されます。内部形式を気にする必要はありません。TermRangeQuery を使用する場合は、グリニッジ標準時 (GMT) で日付を示す必要があることを把握しておくことが重要です。通常は、ミリ秒単位までの日付を保存する必要はありません。
@DateBridge
は、インデックス に保存する適切な分解能を定義します ((@DateBridge(resolution=Resolution.DAY)
)。日付のパターンは、それに応じて切り捨てられます。@Entity @Indexed public class Meeting { @Field(analyze=Analyze.NO) @DateBridge(resolution=Resolution.MINUTE) private Date date; ...
警告分解能がMILLISECOND
未満の日付は、@DocumentId
にはできません。重要デフォルトのDate
ブリッジは Lucene のDateTools
を使用して、String
との相互互換を行います。これは、すべての日付が GMT 時間で表されることを意味します。固定タイムゾーンに日付を保存する必要がある場合は、カスタムの日付ブリッジを実装する必要があります。日付のインデックス作成および検索に関するアプリケーションの要件を理解している。 - java.net.URI、java.net.URL
- URI および URL は文字列表現に変換されます。
- java.lang.Class
- クラスは完全修飾クラス名に変換されます。スレッドコンテキストクラスローダーは、クラスがリハイドレートされる際に使用されます。
14.2.4.2. カスタムブリッジ
14.2.4.2.1. StringBridge
Object
を String
ブリッジに実装を提供することです。これを実行するには、org.hibernate.search.bridge.StringBridge
インターフェースを実装する必要があります。すべての実装は同時に使用されるため、スレッドセーフである必要があります。
例14.25 カスタム StringBridge の
実装
/** * Padding Integer bridge. * All numbers will be padded with 0 to match 5 digits * * @author Emmanuel Bernard */ public class PaddedIntegerBridge implements StringBridge { private int PADDING = 5; public String objectToString(Object object) { String rawInteger = ( (Integer) object ).toString(); if (rawInteger.length() > PADDING) throw new IllegalArgumentException( "Try to pad on a number too big" ); StringBuilder paddedInteger = new StringBuilder( ); for ( int padIndex = rawInteger.length() ; padIndex < PADDING ; padIndex++ ) { paddedInteger.append('0'); } return paddedInteger.append( rawInteger ).toString(); } }
StringBridge の
実装」、@ FieldBridge
アノテーションのおかげで、どのプロパティーまたはフィールドでもこのブリッジを使用できます。
@FieldBridge(impl = PaddedIntegerBridge.class)
private Integer length;
14.2.4.2.2. パラメーター化されたブリッジ
ParameterizedBridge
インターフェースを実装し、パラメーターは @FieldBridge
アノテーションを介して渡されます。
例14.26 ブリッジ実装にパラメーターを渡す
public class PaddedIntegerBridge implements StringBridge, ParameterizedBridge { public static String PADDING_PROPERTY = "padding"; private int padding = 5; //default public void setParameterValues(Map<String,String> parameters) { String padding = parameters.get( PADDING_PROPERTY ); if (padding != null) this.padding = Integer.parseInt( padding ); } public String objectToString(Object object) { String rawInteger = ( (Integer) object ).toString(); if (rawInteger.length() > padding) throw new IllegalArgumentException( "Try to pad on a number too big" ); StringBuilder paddedInteger = new StringBuilder( ); for ( int padIndex = rawInteger.length() ; padIndex < padding ; padIndex++ ) { paddedInteger.append('0'); } return paddedInteger.append( rawInteger ).toString(); } } //property @FieldBridge(impl = PaddedIntegerBridge.class, params = @Parameter(name="padding", value="10") ) private Integer length;
ParameterizedBridge
インターフェースは、StringBridge
、TwoWayStringBridge
、FieldBridge
実装で実装できます。
14.2.4.2.3. Type Aware Bridge
- field/getter-level ブリッジのプロパティーの戻りタイプ。
- クラスレベルのブリッジのクラスタイプ。
AppliedOnTypeAwareBridge
を実装するブリッジは、挿入時にブリッジが適用されるタイプを取得します。パラメーターと同様に、インジェクトされるタイプには、スレッドセーフティーに関する特別な作業は必要ありません。
14.2.4.2.4. Two-Way Bridge
@DocumentId
アノテーション付き) でブリッジ実装を使用する必要がある場合は、TwoWayStringBridge
という名前の拡張バージョン StringBridge
を使用する必要があります。Hibernate Search は、識別子の文字列表現を読み取り、そこからオブジェクトを生成する必要があります。@FieldBridge
アノテーションの使用方法には違いがありません。
例14.27 id プロパティーに使用できる TwoWayStringBridge の実装
public class PaddedIntegerBridge implements TwoWayStringBridge, ParameterizedBridge {
public static String PADDING_PROPERTY = "padding";
private int padding = 5; //default
public void setParameterValues(Map parameters) {
Object padding = parameters.get( PADDING_PROPERTY );
if (padding != null) this.padding = (Integer) padding;
}
public String objectToString(Object object) {
String rawInteger = ( (Integer) object ).toString();
if (rawInteger.length() > padding)
throw new IllegalArgumentException( "Try to pad on a number too big" );
StringBuilder paddedInteger = new StringBuilder( );
for ( int padIndex = rawInteger.length() ; padIndex < padding ; padIndex++ ) {
paddedInteger.append('0');
}
return paddedInteger.append( rawInteger ).toString();
}
public Object stringToObject(String stringValue) {
return new Integer(stringValue);
}
}
//id property
@DocumentId
@FieldBridge(impl = PaddedIntegerBridge.class,
params = @Parameter(name="padding", value="10")
private Integer id;
14.2.4.2.5. FieldBridge
FieldBridge
としてブリッジを実装することもできます。このインターフェースは、プロパティーの値を提供し、Lucene Document
内で希望する方法でマッピングできるようにします。たとえば、プロパティーを異なるドキュメントフィールドに保存できます。インターフェースの概念は Hibernate UserType
と非常に似ています。
例14.28 FieldBridge インターフェイスの実装
/** * Store the date in 3 different fields - year, month, day - to ease Range Query per * year, month or day (eg get all the elements of December for the last 5 years). * @author Emmanuel Bernard */ public class DateSplitBridge implements FieldBridge { private final static TimeZone GMT = TimeZone.getTimeZone("GMT"); public void set(String name, Object value, Document document, LuceneOptions luceneOptions) { Date date = (Date) value; Calendar cal = GregorianCalendar.getInstance(GMT); cal.setTime(date); int year = cal.get(Calendar.YEAR); int month = cal.get(Calendar.MONTH) + 1; int day = cal.get(Calendar.DAY_OF_MONTH); // set year luceneOptions.addFieldToDocument( name + ".year", String.valueOf( year ), document ); // set month and pad it if needed luceneOptions.addFieldToDocument( name + ".month", month < 10 ? "0" : "" + String.valueOf( month ), document ); // set day and pad it if needed luceneOptions.addFieldToDocument( name + ".day", day < 10 ? "0" : "" + String.valueOf( day ), document ); } } //property @FieldBridge(impl = DateSplitBridge.class) private Date date;
LuceneOptions
ヘルパーシステムに委任されます。このヘルパーは、Store
や TermVector
などの @Field
で選択したオプションを適用するか、選択した @Boost
値を適用します。COMPRESS
実装の複雑性をカプセル化することは特に便利です。Document
にフィールドを追加するために LuceneOptions
に委譲することが推奨されますが、必要であれば、Document
を直接編集して、LuceneOptions
を無視しても問題ありません。
LuceneOptions
などのクラスは、アプリケーションを Lucene API の変更から保護し、コードを簡素化するために作成されます。可能な場合はこれを使用しますが、さらに柔軟性が必要な場合は、使用しなくても問題ありません。
14.2.4.2.6. ClassBridge
@ClassBridge
および @ClassBridges
アノテーションは、プロパティーレベルではなくクラスレベルで定義できます。この場合、カスタムフィールドブリッジ実装は、特定のプロパティーの代わりに、エンティティーインスタンスを値のパラメーターとして受信します。に表示されていませんが例14.29「クラスブリッジの実装」、@ClassBridge
はtermVector
セクションで説明されている属性「基本的なマッピング」。
例14.29 クラスブリッジの実装
@Entity @Indexed @ClassBridge(name="branchnetwork", store=Store.YES, impl = CatFieldsClassBridge.class, params = @Parameter( name="sepChar", value=" " ) ) public class Department { private int id; private String network; private String branchHead; private String branch; private Integer maxEmployees ... } public class CatFieldsClassBridge implements FieldBridge, ParameterizedBridge { private String sepChar; public void setParameterValues(Map parameters) { this.sepChar = (String) parameters.get( "sepChar" ); } public void set( String name, Object value, Document document, LuceneOptions luceneOptions) { // In this particular class the name of the new field was passed // from the name field of the ClassBridge Annotation. This is not // a requirement. It just works that way in this instance. The // actual name could be supplied by hard coding it below. Department dep = (Department) value; String fieldValue1 = dep.getBranch(); if ( fieldValue1 == null ) { fieldValue1 = ""; } String fieldValue2 = dep.getNetwork(); if ( fieldValue2 == null ) { fieldValue2 = ""; } String fieldValue = fieldValue1 + sepChar + fieldValue2; Field field = new Field( name, fieldValue, luceneOptions.getStore(), luceneOptions.getIndex(), luceneOptions.getTermVector() ); field.setBoost( luceneOptions.getBoost() ); document.add( field ); } }
CatMissionClassBridge
が department
インスタンスに適用され、フィールドブリッジはブランチとネットワークの両方を連結し、この連結をインデックス化します。
14.3. クエリ
FullTextSession
の作成- Hibernate Search クエリー DSL (推奨) または Lucene Query API を使用した Lucene クエリーの作成
org.hibernate.Query
を使用した Lucene クエリーのラップ- たとえば、を呼び出して検索を実行します
list()
またscroll()
FullTextSession
を使用します。この検索固有のセッションは、クエリーおよびインデックス機能を提供するために通常の org.hibernate.Session
をラップします。
例14.30 FullTextSession の作成
Session session = sessionFactory.openSession(); ... FullTextSession fullTextSession = Search.getFullTextSession(session);
FullTextSession
を使用して、Hibernate Search クエリー DSL またはネイティブの Lucene クエリーのいずれかでフルテキストクエリーを構築します。
final QueryBuilder b = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity( Myth.class ).get(); org.apache.lucene.search.Query luceneQuery = b.keyword() .onField("history").boostedTo(3) .matching("storm") .createQuery(); org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery ); List result = fullTextQuery.list(); //return a list of managed objects
例14.31 QueryParser
を介した Lucene クエリーの作成
SearchFactory searchFactory = fullTextSession.getSearchFactory(); org.apache.lucene.queryParser.QueryParser parser = new QueryParser("title", searchFactory.getAnalyzer(Myth.class) ); try { org.apache.lucene.search.Query luceneQuery = parser.parse( "history:storm^3" ); } catch (ParseException e) { //handle parsing failure } org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery(luceneQuery); List result = fullTextQuery.list(); //return a list of managed objects
org.hibernate.Query
です。このクエリーは、HQL (Hibernate Query Language)、Native、および Criteria などの他の Hibernate クエリー機能と同じパラダイムに残ります。クエリーには、list()
、uniqueResult()
、iterate()
、scroll()
などのメソッドを使用します。
例14.32 JPAAPI を使用した検索クエリーの作成
EntityManager em = entityManagerFactory.createEntityManager();
FullTextEntityManager fullTextEntityManager =
org.hibernate.search.jpa.Search.getFullTextEntityManager(em);
...
final QueryBuilder b = fullTextEntityManager.getSearchFactory()
.buildQueryBuilder().forEntity( Myth.class ).get();
org.apache.lucene.search.Query luceneQuery =
b.keyword()
.onField("history").boostedTo(3)
.matching("storm")
.createQuery();
javax.persistence.Query fullTextQuery = fullTextEntityManager.createFullTextQuery( luceneQuery );
List result = fullTextQuery.getResultList(); //return a list of managed objects
FullTextQuery
の取得方法を調整すると、同じ例を Java Persistence API で記述することもできます。
14.3.1. クエリーの構築
14.3.1.1. Lucene API を使用した Lucene クエリーの構築
14.3.1.2. Lucene クエリーの構築
QueryBuilder
を使用することが推奨されます。
- メソッド名は英語です。そのため、API 操作は、一連の英語のフレーズおよび命令として読み取り、理解することができます。
- IDE オートコンプリートを使用します。これは、現在の入力プレフィックスの完了を容易にし、ユーザーが適切なオプションを選択できるようにします。
- 多くの場合、チェーンメソッドパターンを使用します。
- API 操作を簡単に使用でき、読み取ることができます。
indexedentitytype
に割り当てられるクエリービルダーを作成します。この QueryBuilder
は、使用するアナライザーと、適用するフィールドブリッジを認識します。複数の QueryBuilder
(クエリーのルートに関連するエンティティータイプごとに 1 つ) を作成できます。QueryBuilder
は SearchFactory
から派生します。
QueryBuilder mythQB = searchFactory.buildQueryBuilder().forEntity( Myth.class ).get();
QueryBuilder mythQB = searchFactory.buildQueryBuilder() .forEntity( Myth.class ) .overridesForField("history","stem_analyzer_definition") .get();
Query
オブジェクトを使用して生成されたカスタマイズされたクエリーは、Hibernate Search DSL とともに使用されます。
14.3.1.3. キーワードのクエリー
Query luceneQuery = mythQB.keyword().onField("history").matching("storm").createQuery();
表14.4 キーワードクエリーパラメーター
パラメーター | 説明 |
---|---|
keyword() | 特定の単語を検索するには、このパラメーターを使用します。 |
onField() | このパラメーターを使用して、単語を検索する lucene フィールドを指定します。 |
matching() | このパラメーターを使用して、検索文字列の一致を指定します。 |
createQuery() | Lucene クエリーオブジェクトを作成します。 |
- 「storm」という値が
history
FieldBridge
から渡されます。これは、数値または日付が必要な場合に便利です。 - フィールドブリッジの値は、
history
フィールドインデックス化に使用されるアナライザーに渡されます。これにより、クエリーはインデックス (小文字、ngram、スチミングなど) よりも、同じ用語変換を使用します。分析プロセスで指定の単語が複数生成されると、ブールクエリーがSHOULD
論理 (おおよそOR
論理) とともに使用されます。
@Indexed public class Myth { @Field(analyze = Analyze.NO) @DateBridge(resolution = Resolution.YEAR) public Date getCreationDate() { return creationDate; } public Date setCreationDate(Date creationDate) { this.creationDate = creationDate; } private Date creationDate; ... } Date birthdate = ...; Query luceneQuery = mythQb.keyword().onField("creationDate").matching(birthdate).createQuery();
Date
オブジェクトをその文字列表現 (この場合は年) に変換する必要がありました
FieldBridge
に objectToString
メソッド (およびすべての組み込み FieldBridge
実装) がある場合、すべてのオブジェクトに対して機能します。
@AnalyzerDef(name = "ngram", tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class ), filters = { @TokenFilterDef(factory = StandardFilterFactory.class), @TokenFilterDef(factory = LowerCaseFilterFactory.class), @TokenFilterDef(factory = StopFilterFactory.class), @TokenFilterDef(factory = NGramFilterFactory.class, params = { @Parameter(name = "minGramSize", value = "3"), @Parameter(name = "maxGramSize", value = "3") } ) } ) public class Myth { @Field(analyzer=@Analyzer(definition="ngram") public String getName() { return name; } public String setName(String name) { this.name = name; } private String name; ... } Date birthdate = ...; Query luceneQuery = mythQb.keyword().onField("name").matching("Sisiphus") .createQuery();
y
) を見つけることができます。ユーザーに透過的に実行されます。
ignoreAnalyzer()
またignoreFieldBridge()
関数を呼び出すことができます。
//search document with storm or lightning in their history Query luceneQuery = mythQB.keyword().onField("history").matching("storm lightning").createQuery();
onFields
方法。
Query luceneQuery = mythQB .keyword() .onFields("history","description","name") .matching("storm") .createQuery();
andField()
メソッドを使用します。
Query luceneQuery = mythQB.keyword() .onField("history") .andField("name") .boostedTo(5) .andField("description") .matching("storm") .createQuery();
14.3.1.4. Fuzzy クエリー
keyword
クエリーから始め、fuzzy
フラグを追加します。
Query luceneQuery = mythQB .keyword() .fuzzy() .withThreshold( .8f ) .withPrefixLength( 1 ) .onField("history") .matching("starm") .createQuery();
threshold
は、両方の用語で照合が考慮される制限です。0 から 1 までの小数で、デフォルト値は 0.5 です。prefixLength
は、「fuzzyness」で無視される接頭辞の長さです。デフォルト値は 0 ですが、多数の異なる用語を含むインデックスにはゼロ以外の値が推奨されます。
14.3.1.5. ワイルドカードクエリー
?
は単一文字で、*
は複数文字を表します。パフォーマンス維持のために、クエリーは ?
または *
で開始しないことが推奨されます。
Query luceneQuery = mythQB .keyword() .wildcard() .onField("history") .matching("sto*") .createQuery();
*
または ?
のリスクが高すぎます。
14.3.1.6. フレーズクエリー
phrase()
そうするために。
Query luceneQuery = mythQB .phrase() .onField("history") .sentence("Thou shalt not kill") .createQuery();
Query luceneQuery = mythQB .phrase() .withSlop(3) .onField("history") .sentence("Thou kill") .createQuery();
14.3.1.7. 範囲クエリー
//look for 0 <= starred < 3 Query luceneQuery = mythQB .range() .onField("starred") .from(0).to(3).excludeLimit() .createQuery(); //look for myths strictly BC Date beforeChrist = ...; Query luceneQuery = mythQB .range() .onField("creationDate") .below(beforeChrist).excludeLimit() .createQuery();
14.3.1.8. クエリーの統合
SHOULD
: クエリーには、サブクエリーの一致する要素が含まれる必要があります。MUST
: クエリーには、サブクエリーの一致する要素が含まれる必要があります。MUST NOT
: クエリーには、サブクエリーの一致する要素を含めないでください。
例14.33 クエリー してはいけません
//look for popular modern myths that are not urban Date twentiethCentury = ...; Query luceneQuery = mythQB .bool() .must( mythQB.keyword().onField("description").matching("urban").createQuery() ) .not() .must( mythQB.range().onField("starred").above(4).createQuery() ) .must( mythQB .range() .onField("creationDate") .above(twentiethCentury) .createQuery() ) .createQuery();
例14.34 クエリー
する必要があります
//look for popular myths that are preferably urban Query luceneQuery = mythQB .bool() .should( mythQB.keyword().onField("description").matching("urban").createQuery() ) .must( mythQB.range().onField("starred").above(4).createQuery() ) .createQuery();
例14.35 クエリーし ない
//look for all myths except religious ones Query luceneQuery = mythQB .all() .except( monthQb .keyword() .onField( "description_stem" ) .matching( "religion" ) .createQuery() ) .createQuery();
14.3.1.9. クエリーオプション
boostedTo
(クエリータイプおよびフィールド上) は、クエリー全体または特定のフィールドを指定された係数に改善します。withConstantScore
(クエリーで) は、ブーストに等しい一定のスコアを持つクエリーに一致するすべての結果を返します。filteredBy(Filter)
(クエリー時)Filter
インスタンスを使用してクエリー結果をフィルタリングします。ignoreAnalyzer
(フィールド上) このフィールドを処理するとき、アナライザーを無視します。ignoreFieldBridge
(フィールド上) このフィールドを処理するときにフィールドブリッジを無視します。
例14.36 クエリーオプションの組み合わせ
Query luceneQuery = mythQB .bool() .should( mythQB.keyword().onField("description").matching("urban").createQuery() ) .should( mythQB .keyword() .onField("name") .boostedTo(3) .ignoreAnalyzer() .matching("urban").createQuery() ) .must( mythQB .range() .boostedTo(5).withConstantScore() .onField("starred").above(4).createQuery() ) .createQuery();
14.3.1.10. Hibernate Search クエリーの構築
14.3.1.10.1. 一般性
例14.37 Lucene クエリーを Hibernate クエリーでラップする
FullTextSession fullTextSession = Search.getFullTextSession( session ); org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );
例14.38 エンティティータイプによる検索結果のフィルタリング
fullTextQuery = fullTextSession .createFullTextQuery( luceneQuery, Customer.class ); // or fullTextQuery = fullTextSession .createFullTextQuery( luceneQuery, Item.class, Actor.class );
Customer
のみを返します。同じ例の次の部分は、一致する Actor
と Item
を返します。タイプ制限はポリモーフィックです。そのため、2 つのサブクラス Salesman
と、ベースクラス Person
の Customer
は、結果タイプに基づいてフィルタリングする Person.class
を指定します。
14.3.1.10.2. ページネーション
例14.39 検索クエリーのページ付けを定義する
org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, Customer.class ); fullTextQuery.setFirstResult(15); //start from the 15th element fullTextQuery.setMaxResults(10); //return 10 elements
fulltextQuery.
getResultSize()
14.3.1.10.3. ソート
例14.40 Lucene ソート
の指定
org.hibernate.search.FullTextQuery query = s.createFullTextQuery( query, Book.class );
org.apache.lucene.search.Sort sort = new Sort(
new SortField("title", SortField.STRING));
query.setSort(sort);
List results = query.list();
14.3.1.10.4. ストラテジーの取得
例14.41 クエリーでの FetchMode
の指定
Criteria criteria = s.createCriteria( Book.class ).setFetchMode( "authors", FetchMode.JOIN ); s.createFullTextQuery( luceneQuery ).setCriteriaQuery( criteria );
getResultSize()
は制限のある Criteria
とともに使用された場合に SearchException
をスローするため、Criteria
クエリーで制限 (完全な句) を使用しないでください。
setCriteriaQuery
。
14.3.1.10.5. プロジェクション
Object[]
のリストを返します。プロジェクションは、データベースのラウンドトリップが長くなるのを防ぎます。ただし、以下の制限があります。
- 予測されるプロパティーはインデックス (
@Field(store=Store.YES)
) に保存され、インデックスサイズが増えます。 - 予測されるプロパティーは、
org.hibernate.search.bridge.TwoWayFieldBridge
またはorg.hibernate.search.bridge.TwoWayStringBridge
を実装するFieldBridge
を使用する必要があり、後者はより単純なバージョンになります。注記Hibernate Search の組み込みタイプはすべて双方向です。 - インデックス化されたエンティティーまたはその埋め込み関連の簡単なプロパティーのみを展開できます。したがって、埋め込みエンティティー全体を展開できません。
@IndexedEmbedded
でインデックス化されるコレクションやマップで機能しません。
例14.42 投影法を使用したメタデータの取得
org.hibernate.search.FullTextQuery query =
s.createFullTextQuery( luceneQuery, Book.class );
query.setProjection( FullTextQuery.SCORE, FullTextQuery.THIS, "mainAuthor.name" );
List results = query.list();
Object[] firstResult = (Object[]) results.get(0);
float score = firstResult[0];
Book book = firstResult[1];
String authorName = firstResult[2];
FullTextQuery.THIS
初期化され管理されたエンティティーを返します (展開されていないクエリーが実行される場合)。FullTextQuery.DOCUMENT
展開されるオブジェクトに関連する Lucene ドキュメントを返します。FullTextQuery.OBJECT_CLASS
: インデックス化されたエンティティーのクラスを返します。FullTextQuery.SCORE
: クエリーのドキュメントスコアを返します。スコアは、あるクエリーの結果を別のクエリーに対する比較には便利ですが、異なるクエリーの結果を比較する場合に有用ではありません。FullTextQuery.ID
: 予測されるオブジェクトの ID プロパティー値。FullTextQuery.DOCUMENT_ID
: Lucene ドキュメント ID。この値を Lucene ドキュメント ID として使用すると、異なる 2 つの IndexReader を開くたびに変更される可能性があります。FullTextQuery.EXPLANATION
: 指定のクエリーの一致するオブジェクト/ドキュメントの Lucene Explanation オブジェクトを返します。これは、大量のデータを取得するのには適していません。通常、実行の説明は、一致する要素ごとに Lucene クエリー全体を実行することを意味します。そのため、展開が推奨されます。
14.3.1.10.6. オブジェクト初期化ストラテジーのカスタマイズ
例14.43 クエリーを使用する前の 2 次キャッシュのチェック
FullTextQuery query = session.createFullTextQuery(luceneQuery, User.class); query.initializeObjectWith( ObjectLookupMethod.SECOND_LEVEL_CACHE, DatabaseRetrievalMethod.QUERY );
ObjectLookupMethod
は、オブジェクトをデータベースから取得せずに簡単にアクセスできるかどうかを確認するストラテジーを定義します。その他のオプションは以下のとおりです。
ObjectLookupMethod.PERSISTENCE_CONTEXT
は、一致する多くのエンティティーが永続コンテキストにすでにロードされている場合に使用されます (Session
またはEntityManager
にロードされている場合)。ObjectLookupMethod.SECOND_LEVEL_CACHE
は永続コンテキストをチェックし、2 次キャッシュを確認します。
- 2 次キャッシュを正しく設定およびアクティブ化します。
- 関連するエンティティーの 2 次キャッシュを有効にします。これは、
@Cacheable
などのアノテーションを使用してを行います。 Session
、EntityManager
、またはQuery
のいずれかの 2 次キャッシュ読み取りアクセスを有効にします。Hibernate ネイティブ API ではCacheMode.NORMAL
を使用し、Java Persistence API ではCacheRetrieveMode.USE
を使用します。
ObjectLookupMethod.SECOND_LEVEL_CACHE
は使用しないでください。他の 2 次レベルのキャッシュプロバイダーはこのオペレーションを効率的に実装しません。
DatabaseRetrievalMethod
を使用して、以下のようにデータベースからオブジェクトを読み込む方法をカスタマイズします。
QUERY
(デフォルト) はクエリーのセットを使用して、複数のオブジェクトを各バッチに読み込みます。このアプローチが推奨されます。FIND_BY_ID
は、Session
を使用して一度に 1 つのオブジェクトをロードします。get
またはEntityManager
。find
セマンティック。これは、Hibernate Core がエンティティーをバッチでロードできるようにする、エンティティーにバッチサイズが設定されている場合に推奨されます。
14.3.1.10.7. クエリー時間の制限
- 制限を指定して受信する際に例外を発生させます。
- 時間制限が発生したときに取得する結果の数に制限します。
14.3.1.10.8. 時間制限の例外発生
QueryTimeoutException
が発生します (プログラム API に応じた、org.hibernate.QueryTimeoutException
または javax.persistence.QueryTimeoutException
)。
例14.44 クエリー実行でのタイムアウトの定義
Query luceneQuery = ...; FullTextQuery query = fullTextSession.createFullTextQuery(luceneQuery, User.class); //define the timeout in seconds query.setTimeout(5); //alternatively, define the timeout in any given time unit query.setTimeout(450, TimeUnit.MILLISECONDS); try { query.list(); } catch (org.hibernate.QueryTimeoutException e) { //do something, too slow }
getResultSize()
、iterate()
とscroll()
メソッド呼び出しが終了するまでのタイムアウトを尊重します。その結果、Iterable
または ScrollableResults
は、タイムアウトを無視します。さらに、explain()
このタイムアウト期間は尊重されません。この方法は、デバッグに使用され、クエリーのパフォーマンス低下の原因をチェックします。
例14.45 クエリー実行でのタイムアウトの定義
Query luceneQuery = ...; FullTextQuery query = fullTextEM.createFullTextQuery(luceneQuery, User.class); //define the timeout in milliseconds query.setHint( "javax.persistence.query.timeout", 450 ); try { query.getResultList(); } catch (javax.persistence.QueryTimeoutException e) { //do something, too slow }
14.3.2. 結果の取得
list()
、uniqueResult()
、iterate()
、scroll()
利用可能です。
14.3.2.1. パフォーマンスに関する考慮事項
list()
またuniqueResult()
をお勧めします。list()
は、エンティティー batch-size
が正しく設定されている場合に最適に機能します。Hibernate Search を使用する場合、(ページネーション内の) すべての LuceneHits 要素を処理する必要があることに注意してください。list()
、uniqueResult()
とiterate()
。
scroll()
の方が適しています。ScrollableResults
オブジェクトは Lucene のリソースを保持しているので、終了したら閉じることを忘れないでください。使用する予定の場合scroll,
ただし、オブジェクトをバッチでロードしたい場合は、次を使用できます。query.setFetchSize()
。オブジェクトにアクセスし、読み込まれていない場合、Hibernate Search は次の fetchSize
オブジェクトをパスに読み込みます。
14.3.2.2. 結果サイズ
- Google 検索で提供された、全体的な検索結果機能を提供たとえば、"約 888,000,000 件のうちの 1-10」のようになります。
- 高速なページネーションナビゲーションを実装する
- クエリーがゼロを返すか、十分な結果がない場合に概算を追加する複数ステップの検索エンジンを実装するには、以下を実行します。
例14.46 クエリーの結果サイズの決定
org.hibernate.search.FullTextQuery query = s.createFullTextQuery( luceneQuery, Book.class ); //return the number of matching books without loading a single one assert 3245 == query.getResultSize(); org.hibernate.search.FullTextQuery query = s.createFullTextQuery( luceneQuery, Book.class ); query.setMaxResult(10); List results = query.list(); //return the total number of matching books regardless of pagination assert 3245 == query.getResultSize();
14.3.2.3. ResultTransformer
Object
配列として返されます。オブジェクトに使用されるデータ構造がアプリケーションの要件と一致しない場合は、ResultTransformer
を適用します。ResultTransformer
は、クエリーの実行後に必要なデータ構造を構築します。
例14.47 プロジェクションでの ResultTransformer の使用
org.hibernate.search.FullTextQuery query =
s.createFullTextQuery( luceneQuery, Book.class );
query.setProjection( "title", "mainAuthor.name" );
query.setResultTransformer( new StaticAliasToBeanResultTransformer( BookView.class, "title", "author" ) );
List<BookView> results = (List<BookView>) query.list();
for(BookView view : results) {
log.info( "Book: " + view.getTitle() + ", " + view.getAuthor() );
}
ResultTransformer
実装の例は、ibernate Core codebase を参照してください。
14.3.2.4. 結果について
Luke
ツールは結果を理解する際に役立ちます。ただし、Hibernate Search を使用すると、所定の結果 (特定のクエリー内) の Lucene Explanation
オブジェクトにアクセスできます。このクラスは Lucene ユーザーに非常に高度なものとみなされますが、オブジェクトの性質をよく理解することができます。特定の結果について Explanation オブジェクトにアクセスするには、以下のいずれかの方法があります。
- 使用
fullTextQuery.explain(int)
方法 - プロジェクションの使用
FullTextQuery.DOCUMENT_ID
定数を使用して取得できます。
FullTextQuery.EXPLANATION
定数を使用して Explanation
オブジェクトをプロジェクトします。
例14.48 プロジェクトを使用した Lucene の説明オブジェクトの取得
FullTextQuery ftQuery = s.createFullTextQuery( luceneQuery, Dvd.class )
.setProjection(
FullTextQuery.DOCUMENT_ID,
FullTextQuery.EXPLANATION,
FullTextQuery.THIS );
@SuppressWarnings("unchecked") List<Object[]> results = ftQuery.list();
for (Object[] result : results) {
Explanation e = (Explanation) result[1];
display( e.toString() );
}
14.3.3. フィルター
- セキュリティー
- 一時的なデータ (例: 先月のデータのみ表示)
- 予測フィルター (例: 検索は所定カテゴリーに限定される)
例14.49 クエリーのフルテキストフィルターの有効化
fullTextQuery = s.createFullTextQuery( query, Driver.class ); fullTextQuery.enableFullTextFilter("bestDriver"); fullTextQuery.enableFullTextFilter("security").setParameter( "login", "andre" ); fullTextQuery.list(); //returns only best drivers where andre has credentials
@FullTextFilterDef
アノテーションを使用して実行されます。このアノテーションは、フィルターが後に適用されるクエリーに関係なく、@Indexed
エンティティーに設定できます。これは、フィルター定義がグローバルであり、名前が一意である必要があることを意味します。同じ名前を持つ @FullTextFilterDef
アノテーションが定義される場合は、SearchException
が発生します。名前付きの各フィルターは、実際のフィルター実装を指定する必要があります。
例14.50 フィルターの定義と実装
@FullTextFilterDefs( { @FullTextFilterDef(name = "bestDriver", impl = BestDriversFilter.class), @FullTextFilterDef(name = "security", impl = SecurityFilterFactory.class) }) public class Driver { ... }
public class BestDriversFilter extends org.apache.lucene.search.Filter {
public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
OpenBitSet bitSet = new OpenBitSet( reader.maxDoc() );
TermDocs termDocs = reader.termDocs( new Term( "score", "5" ) );
while ( termDocs.next() ) {
bitSet.set( termDocs.doc() );
}
return bitSet;
}
}
BestDriversFilter
は簡単な Lucene フィルターの例です。これにより、スコアが 5 のドライバーに設定された結果が減少します。この例では、指定したフィルターは org.apache.lucene.search.Filter
を直接実装し、no-arg コンストラクターが含まれます。
例14.51 ファクトリーパターンを使用してフィルターを作成する
@FullTextFilterDef(name = "bestDriver", impl = BestDriversFilterFactory.class)
public class Driver { ... }
public class BestDriversFilterFactory {
@Factory
public Filter getFilter() {
//some additional steps to cache the filter results per IndexReader
Filter bestDriversFilter = new BestDriversFilter();
return new CachingWrapperFilter(bestDriversFilter);
}
}
@Factory
アノテーションが付けられたメソッドを検索し、そのメソッドを使用してフィルターインスタンスを作成します。ファクトリーには no-arg コンストラクターが必要です。
例14.52 定義されたフィルターへのパラメーターの受け渡し
fullTextQuery = s.createFullTextQuery( query, Driver.class );
fullTextQuery.enableFullTextFilter("security").setParameter( "level", 5 );
例14.53 フィルター実装におけるパラメーターの使用
public class SecurityFilterFactory { private Integer level; /** * injected parameter */ public void setLevel(Integer level) { this.level = level; } @Key public FilterKey getKey() { StandardFilterKey key = new StandardFilterKey(); key.addParameter( level ); return key; } @Factory public Filter getFilter() { Query query = new TermQuery( new Term("level", level.toString() ) ); return new CachingWrapperFilter( new QueryWrapperFilter(query) ); } }
@Key
アノテーションが付けられたメソッドは FilterKey
オブジェクトを返すことに注意してください。返されたオブジェクトには特別なコントラクトを持ちます。キーオブジェクトは equals()
/ hashCode()
を実装し、指定される Filter
タイプが同一で、パラメーターのセットが同じである場合にのみ、両方の鍵が同じになるようにする必要があります。つまり、鍵の生成元となるフィルターが交換可能な場合、あるいは交換可能である場合にのみ、両方のフィルター鍵が同等になります。キーオブジェクトは、キャッシュメカニズムのキーとして使用されます。
@Key
メソッドは以下の場合にのみ必要です。
- フィルターキャッシングシステムが有効になっている (デフォルトでは有効)。
- フィルターにはパラメーターがあります。
StandardFilterKey
実装を使用すれば十分です。それは委任しますequals()
/hashCode()
各パラメーター equals および hashcode メソッドへの実装。
SoftReferences
に最も使用されるフィルターを変換します。ハード参照キャッシュの制限に達すると、追加のフィルターが SoftReferences
としてキャッシュされます。ハード参照キャッシュのサイズを調整するには、hibernate.search.filter.cache_strategy.size
(デフォルトは 128 に設定) を使用します。フィルターキャッシングの高度な使用のために、独自の FilterCachingStrategy
を実装します。classname は hibernate.search.filter.cache_strategy
によって定義されます。
CachingWrapperFilter
を中心に IndexReader
を使用してフィルターをラッピングすることが一般的です。ラッパーは、から返された DocIdSet
をキャッシュしますgetDocIdSet(IndexReader reader)
高価な再計算を回避する方法。リーダーは、開いた時点のインデックスの状態を効果的に表示するため、計算した DocIdSet
が同じ IndexReader
インスタンスに対してのみキャッシュ可能であることを示すことが重要です。ドキュメントリストは、開いている IndexReader
内では変更できません。ただし、別の、新しい IndexReader
インスタンスの場合は、(別のインデックスから、または単にインデックスが変更されたため) 異なる Document
のセットで動作する可能性があるため、キャッシュされた DocIdSet
を再計算する必要があります。
@FullTextFilterDef
の cache
フラグは、デフォルトでは FilterCacheModeType.INSTANCE_AND_DOCIDSETRESULTS
に設定されています。これにより、フィルターインスタンスを自動的にキャッシュし、CachingWrapperFilter
の Hibernate 固有の実装に指定されたフィルターをラップします。このクラスの Lucene のバージョンとは対照的に、SoftReference
はハード参照数とともに使用されます (フィルターキャッシュについて参照)。ハード参照数は、hibernate.search.filter.cache_docidresults.size
(デフォルトは 5 に設定) を使用して調整できます。ラッピング動作は、the@FullTextFilterDef.cache
パラメーターを使用して制御できます。このパラメーターには、以下の異なる値があります。
値 | 定義 |
---|---|
FilterCacheModeType.NONE | フィルターインスタンスがなく、Hibernate Search によって結果がキャッシュされません。フィルター呼び出しごとに、新しいフィルターインスタンスが作成されます。この設定は、データセットまたはメモリーが制限される環境を迅速に変更する際に役に立つことがあります。 |
FilterCacheModeType.INSTANCE_ONLY | フィルターインスタンスはキャッシュされ、同時実行全体で再利用されますFilter.getDocIdSet() 呼び出します。DocIdSet の結果はキャッシュされません。この設定は、フィルターが固有のキャッシングメカニズムを使用するか、アプリケーション固有のイベントにより DocIdSet をキャッシュする必要がない場合に動的にフィルターの結果が変更される場合に役立ちます。 |
FilterCacheModeType.INSTANCE_AND_DOCIDSETRESULTS | フィルターインスタンスと DocIdSet 両方の結果がキャッシュされます。これはデフォルト値です。 |
- システムはターゲットエンティティーインデックスを頻繁に更新しません (つまり、IndexReader は頻繁に再利用されます)。
- Filter の DocIdSet の計算には、クエリーの実行にかかった時間と比較して負荷がかかります。
14.3.3.1. シャード化された環境でのフィルターの使用
手順14.1 インデックスシャードのサブセットのクエリー
- フィルター設定に応じて
IndexManager
のサブセットを選択するシャード化ストラテジーを作成します。 - クエリー時にフィルターをアクティブにします。
例14.54 インデックスシャードのサブセットのクエリー
customer
フィルターがアクティブな場合は、クエリーが特定の顧客シャードに対して実行されます。
public class CustomerShardingStrategy implements IndexShardingStrategy { // stored IndexManagers in a array indexed by customerID private IndexManager[] indexManagers; public void initialize(Properties properties, IndexManager[] indexManagers) { this.indexManagers = indexManagers; } public IndexManager[] getIndexManagersForAllShards() { return indexManagers; } public IndexManager getIndexManagerForAddition( Class<?> entity, Serializable id, String idInString, Document document) { Integer customerID = Integer.parseInt(document.getFieldable("customerID").stringValue()); return indexManagers[customerID]; } public IndexManager[] getIndexManagersForDeletion( Class<?> entity, Serializable id, String idInString) { return getIndexManagersForAllShards(); } /** * Optimization; don't search ALL shards and union the results; in this case, we * can be certain that all the data for a particular customer Filter is in a single * shard; simply return that shard by customerID. */ public IndexManager[] getIndexManagersForQuery( FullTextFilterImplementor[] filters) { FullTextFilter filter = getCustomerFilter(filters, "customer"); if (filter == null) { return getIndexManagersForAllShards(); } else { return new IndexManager[] { indexManagers[Integer.parseInt( filter.getParameter("customerID").toString())] }; } } private FullTextFilter getCustomerFilter(FullTextFilterImplementor[] filters, String name) { for (FullTextFilterImplementor filter: filters) { if (filter.getName().equals(name)) return filter; } return null; } }
custom
という名前のフィルターがある場合、この顧客専用のシャードのみがクエリーされ、それ以外の場合はすべてのシャードが返されます。所定のシャード化ストラテジーは、単一または複数のフィルターに対応し、それらのパラメーターに依存します。
ShardSensitiveOnlyFilter
クラスを指定します。
@Indexed @FullTextFilterDef(name="customer", impl=ShardSensitiveOnlyFilter.class) public class Customer { ... } FullTextQuery query = ftEm.createFullTextQuery(luceneQuery, Customer.class); query.enableFulltextFilter("customer").setParameter("CustomerID", 5); @SuppressWarnings("unchecked") List<Customer> results = query.getResultList();
ShardSensitiveOnlyFilter
を使用して Lucene フィルターを実装する必要はありません。シャード化された環境のクエリーを加速するには、これらのフィルターに対応するフィルターおよびシャード化ストラテジーを使用することが推奨されます。
14.3.4. ファセット
例14.55 Amazon で HibernateSearch を検索する
QueryBuilder
クラスおよび FullTextQuery
クラスは、ファセット API へのエントリーポイントです。前者は要求を作成し、後者は FacetManager
にアクセスします。FacetManager
はクエリーにファセット要求を適用し、検索結果を絞り込むために既存のクエリーに追加されるブックマークを選択します。例では、次に示すようにエンティティー Cd
を使用します。例14.56「エンティティー Cd」:
図14.1 Amazon で HibernateSearch を検索する
例14.56 エンティティー Cd
@Indexed public class Cd { private int id; @Fields( { @Field, @Field(name = "name_un_analyzed", analyze = Analyze.NO) }) private String name; @Field(analyze = Analyze.NO) @NumericField private int price; Field(analyze = Analyze.NO) @DateBridge(resolution = Resolution.YEAR) private Date releaseYear; @Field(analyze = Analyze.NO) private String label; // setter/getter ...
14.3.4.1. ファセット要求の作成
FacetingRequest
を作成することです。現時点では、2 種類のセッティング要求がサポートされています。最初のタイプは discrete faceting と呼ばれ、次のタイプは range faceting 要求と呼ばれます。個別のファセットリクエストの場合は、ファセット (分類) を行うインデックスフィールドと、適用するファセットオプションを指定します。個別のファセットリクエストの例は、次のように表示されます。例14.57「個別のファセットリクエストの作成」:
例14.57 個別のファセットリクエストの作成
QueryBuilder builder = fullTextSession.getSearchFactory() .buildQueryBuilder() .forEntity( Cd.class ) .get(); FacetingRequest labelFacetingRequest = builder.facet() .name( "labelFaceting" ) .onField( "label") .discrete() .orderedBy( FacetSortOrder.COUNT_DESC ) .includeZeroCounts( false ) .maxFacetCount( 1 ) .createFacetingRequest();
label
フィールドの個別値ごとに Facet
インスタンスが作成されます。ファセット
インスタンスは、この特定のフィールド値が元のクエリー結果内で発生する頻度を含む実際のフィールド値を記録します。orderedBy
、includeZeroCounts
とmaxFacetCount
は、任意のファセット要求に適用できるオプションのパラメーターです。orderedBy
作成されたファセットが返される順序を指定できます。デフォルトはFacetSortOrder.COUNT_DESC
、ただし、フィールド値または範囲が指定された順序で並べ替えることもできます。includeZeroCount
カウントが 0 のファセットを結果に含めるかどうかを決定します (デフォルトでは含まれます)。maxFacetCount
返されるファセットの最大量を制限できます。
String
、Date
、または Number
および null
の値を持つものは使用しないでください。さらに、プロパティーは Analyze.NO
でインデックス化する必要があり、数値プロパティー @NumericField
を指定する場合は指定する必要があります。
below
とabove
指定できるのは 1 回だけですが、指定できるのはいくつでもかまいませんfrom
-to
あなたが望むように範囲。範囲の境界ごとに、次の方法で指定することもできます。excludeLimit
範囲に含まれるかどうか。
例14.58 範囲ファセットリクエストの作成
QueryBuilder builder = fullTextSession.getSearchFactory() .buildQueryBuilder() .forEntity( Cd.class ) .get(); FacetingRequest priceFacetingRequest = builder.facet() .name( "priceFaceting" ) .onField( "price" ) .range() .below( 1000 ) .from( 1001 ).to( 1500 ) .above( 1500 ).excludeLimit() .createFacetingRequest();
14.3.4.2. ファセット要求の適用
FullTextQuery
クラスを介して取得できる FacetManager
クラスでクエリーに適用されます。
getFacets()
で後から取得できます。もありますdisableFaceting()
名前を指定してファセットリクエストを無効にできるメソッド。
例14.59 ファセット要求の適用
// create a fulltext query Query luceneQuery = builder.all().createQuery(); // match all query FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, Cd.class ); // retrieve facet manager and apply faceting request FacetManager facetManager = fullTextQuery.getFacetManager(); facetManager.enableFaceting( priceFacetingRequest ); // get the list of Cds List<Cd> cds = fullTextQuery.list(); ... // retrieve the faceting results List<Facet> facets = facetManager.getFacets( "priceFaceting" ); ...
14.3.4.3. クエリー結果の制限
Facet
を適用できます。そのためには、FacetSelection
を使用できます。FacetSelection
は FacetManager
を介して利用可能であり、クエリー基準としてファセットを選択できます (selectFacets
)、ファセット制限を削除します (deselectFacets
)、すべてのファセット制限を削除します (clearSelectedFacets
) そして現在選択されているすべてのファセットを取得します (getSelectedFacets
)。例14.60「FacetSelection
のアプリケーションによるクエリー結果の制限」 例を示します。
例14.60 FacetSelection
のアプリケーションによるクエリー結果の制限
// create a fulltext query Query luceneQuery = builder.all().createQuery(); // match all query FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, clazz ); // retrieve facet manager and apply faceting request FacetManager facetManager = fullTextQuery.getFacetManager(); facetManager.enableFaceting( priceFacetingRequest ); // get the list of Cd List<Cd> cds = fullTextQuery.list(); assertTrue(cds.size() == 10); // retrieve the faceting results List<Facet> facets = facetManager.getFacets( "priceFaceting" ); assertTrue(facets.get(0).getCount() == 2) // apply first facet as additional search criteria facetManager.getFacetGroup( "priceFaceting" ).selectFacets( facets.get( 0 ) ); // re-execute the query cds = fullTextQuery.list(); assertTrue(cds.size() == 2);
14.3.5. クエリープロセスの最適化
- Lucene クエリー。
- 読み込まれたオブジェクト数: ページネーション (常時) またはインデックス処理 (必要な場合) を使用します。
- Hibernate Search が Lucene リーダーと対話する方法: 適切なリーダーストラテジーを定義します。
- インデックスから頻繁に抽出された値をキャッシュします。「インデックス値のキャッシュ: FieldCache」 を参照してください。
14.3.5.1. インデックス値のキャッシュ: FieldCache
CacheFromIndex
アノテーションを使用すると、Hibernate Search に必要なメインのメタデータフィールドのキャッシュをさまざまな方法で試すことができます。
import static org.hibernate.search.annotations.FieldCacheType.CLASS; import static org.hibernate.search.annotations.FieldCacheType.ID; @Indexed @CacheFromIndex( { CLASS, ID } ) public class Essay { ...
CLASS
: Hibernate Search は Lucene FieldCache を使用して、インデックスからクラスタイプの抽出のパフォーマンスを改善します。この値はデフォルトで有効になっており、@CacheFromIndex
アノテーションを指定しない場合に Hibernate Search が適用されます。ID
: プライマリー識別子はキャッシュを使用します。これにより、パフォーマンスが最も高いクエリーが提供されますが、消費するメモリーが多くなり、パフォーマンスが低下する可能性があります。
- メモリー使用量: このキャッシュには、かなりメモリーがハングします。通常、CLASS キャッシュの要件は ID キャッシュの要件よりも低くなります。
- インデックスウォームアップ: フィールドキャッシュを使用する場合、新しいインデックスまたはセグメントの最初のクエリーは、キャッシュが有効になっていない場合よりも遅くなります。
CLASS
フィールドキャッシュを有効にしても使用されない可能性があります。たとえば、単一クラスをターゲットとしている場合は、返される値はすべてそのタイプのものになります (これは各クエリー実行時に評価されます)。
TwoWayFieldBridge
(すべてのブリッジの構築として) を使用し、特定のクエリーに読み込まれるすべてのタイプが id のフィールド名を使用し、同じタイプの ID が割り当てられている必要があります (これは各クエリー実行時に評価されます)。
14.4. 手動によるインデックスの変更
14.4.1. インデックスへのインスタンスの追加
FullTextSession
を使用します。index(T entity)
特定のオブジェクトインスタンスをインデックスに直接追加または更新できます。このエンティティーがすでにインデックス化されている場合は、インデックスが更新されます。インデックスへの変更は、トランザクションコミット時にのみ適用されます。
例14.61 FullTextSession.index (T エンティティー) を介したエンティティーのインデックス作成
FullTextSession fullTextSession = Search.getFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
Object customer = fullTextSession.load( Customer.class, 8 );
fullTextSession.index(customer);
tx.commit(); //index only updated at commit time
MassIndexer
を使用することが推奨されます。詳細は「MassIndexer の使用」を参照してください。
14.4.2. インデックスからのインスタンスの削除
FullTextSession
を介しても実行されます。
例14.62 インデックスからエンティティーの特定のインスタンスを削除
FullTextSession fullTextSession = Search.getFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
for (Customer customer : customers) {
fullTextSession.purge( Customer.class, customer.getId() );
}
tx.commit(); //index is updated at commit time
purgeAll
方法。この操作により、パラメーターとして渡されたタイプのすべてのエンティティーとそのすべてのサブタイプが削除されます。
例14.63 エンティティーのすべてのインスタンスをインデックスから削除する
FullTextSession fullTextSession = Search.getFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
fullTextSession.purgeAll( Customer.class );
//optionally optimize the index
//fullTextSession.getSearchFactory().optimize( Customer.class );
tx.commit(); //index changes are applied at commit time
index
、purge
、とpurgeAll
FullTextEntityManager
でも利用できます。
index
、purge
、とpurgeAll
) データベースではなくインデックスにのみ影響しますが、トランザクションであるため、トランザクションが正常にコミットされるか、使用するまで適用されません。flushToIndexes
。
14.4.3. インデックスの再構築
FullTextSession
を使用します。flushToIndexes()
FullTextSession
を使用している間、定期的に。index()
すべてのエンティティーで。MassIndexer
を使用。
14.4.3.1. FlushToIndexes() の使用
FullTextSession
.purgeAll()
および FullTextSession
.index()
を使用してすべてのエンティティーをインデックスに戻すことで構成されますが、メモリーと効率の制約があります。効率を最大限に高めるためにも、Hibernate Search はインデックス操作をバッチ処理し、コミット時に実行します。大量のデータをインデックス化する場合は、トランザクションがコミットされるまですべてのドキュメントがキューに保存されるため、メモリー消費について注意する必要があります。キューを定期的に空にしないと、OutOfMemoryException
が発生する可能性があります。この使用を行うにはfullTextSession.flushToIndexes()
。毎回fullTextSession.flushToIndexes()
が呼び出されると (またはトランザクションがコミットされた場合)、バッチキューが処理され、すべてのインデックス変更が適用されます。フラッシュ後は、変更をロールバックできないことに注意してください。
例14.64 index() および flushToIndexes() を使用したインデックス再構築
fullTextSession.setFlushMode(FlushMode.MANUAL); fullTextSession.setCacheMode(CacheMode.IGNORE); transaction = fullTextSession.beginTransaction(); //Scrollable results will avoid loading too many objects in memory ScrollableResults results = fullTextSession.createCriteria( Email.class ) .setFetchSize(BATCH_SIZE) .scroll( ScrollMode.FORWARD_ONLY ); int index = 0; while( results.next() ) { index++; fullTextSession.index( results.get(0) ); //index each element if (index % BATCH_SIZE == 0) { fullTextSession.flushToIndexes(); //apply changes to indexes fullTextSession.clear(); //free memory since the queue is processed } } transaction.commit();
hibernate.search.default.worker.batch_size
が非推奨となりました。
14.4.3.2. MassIndexer の使用
MassIndexer
は、複数の並列スレッドを使用してインデックスを再ビルドします。オプションで、リロードする必要のあるエンティティーを選択するか、またはすべてのエンティティーのインデックスを変更できます。このアプローチは、パフォーマンスを最大化するために最適化されていますが、アプリケーションをメンテナンスモードに設定する必要があります。MassIndexer がビジーな場合、インデックスのクエリーは推奨されません。
例14.65 MassIndexer を使用してインデックスを再構築する
fullTextSession.createIndexer().startAndWait();
例14.66 調整された MassIndexer の使用
fullTextSession .createIndexer( User.class ) .batchSizeToLoadObjects( 25 ) .cacheMode( CacheMode.NORMAL ) .threadsToLoadObjects( 12 ) .idFetchSize( 150 ) .progressMonitor( monitor ) //a MassIndexerProgressMonitor implementation .startAndWait();
FieldBridge
または ClassBridge
を処理する必要もあります。スレッドは、変換プロセス中に追加属性のレイジーローディングをトリガーします。そのため、並行して機能しているスレッドは多く必要になります。実際のインデックス書き込みで稼働しているスレッドの数は、各インデックスのバックエンド設定によって定義されます。
CacheMode.IGNORE
(デフォルト) のままにすることが推奨されます。これは、ほとんどの場合でキャッシュが不要な追加オーバーヘッドになるためです。メインのエンティティーがインデックスに含まれる列挙のようなデータに関連する場合は、パフォーマンスを向上させる可能性があるため、データに応じて他の CacheMode
を有効にすると便利です。
hibernate.search.[default|<indexname>].exclusive_index_use
hibernate.search.[default|<indexname>].indexwriter.max_buffered_docs
hibernate.search.[default|<indexname>].indexwriter.max_merge_docs
hibernate.search.[default|<indexname>].indexwriter.merge_factor
hibernate.search.[default|<indexname>].indexwriter.merge_min_size
hibernate.search.[default|<indexname>].indexwriter.merge_max_size
hibernate.search.[default|<indexname>].indexwriter.merge_max_optimize_size
hibernate.search.[default|<indexname>].indexwriter.merge_calibrate_by_deletes
hibernate.search.[default|<indexname>].indexwriter.ram_buffer_size
hibernate.search.[default|<indexname>].indexwriter.term_index_interval
max_field_length
がありましたが、これは Lucene から削除されました。これは、LimitTokenCountAnalyzer
を使用して同様の効果を得ることができます。
.indexwriter
パラメーターは Lucene 固有で、Hibernate Search はこれらのパラメーターを渡します。
MassIndexer
は、前方のみのスクロール可能な結果を使用して、読み込まれるプライマリーキーを繰り返し処理しますが、MySQL の JDBC ドライバーはメモリーのすべての値を読み込みます。この「最適化」を回避するには、idFetchSize
を Integer.MIN_VALUE
に設定します。
14.5. インデックスの最適化
- アイドル状態のシステムの場合、または検索が頻繁に行われない場合
- 多数のインデックス変更が適用された後。
MassIndexer
(「MassIndexer の使用」 を参照) は、デフォルトで、開始時と処理終了時にインデックスを最適化します。MassIndexer
を使用します。optimizeAfterPurge
および MassIndexer
。optimizeOnFinish
このデフォルトの動作を変更します。
14.5.1. 自動最適化
- 一定量の操作 (挿入または削除)。
- 一定量のトランザクション。
例14.67 自動最適化パラメーターの定義
hibernate.search.default.optimizer.operation_limit.max = 1000 hibernate.search.default.optimizer.transaction_limit.max = 100 hibernate.search.Animal.optimizer.transaction_limit.max = 50
Animal
インデックスに対してトリガーされます。
- 追加および削除の数は
1000
に到達します。 - トランザクション数は
50
に達します (hibernate.search.Animal.optimizer.transaction_limit.max
優先するhibernate.search.default.optimizer.transaction_limit.max
)。
org.hibernate.search.store.optimization.OptimizerStrategy
を実装して上書きし、optimizer.implementation
プロパティーを実装の完全修飾名に設定して上書きできます。この実装は、インターフェースを実装し、パブリッククラスであり、引数なしでパブリックコンストラクターを持つ必要があります。
例14.68 カスタム OptimizerStrategy のロード
hibernate.search.default.optimizer.implementation = com.acme.worlddomination.SmartOptimizer hibernate.search.default.optimizer.SomeOption = CustomConfigurationValue hibernate.search.humans.optimizer.implementation = default
default
を使用すると、Hibernate Search のデフォルト実装を選択できます。.optimizer
キーセパレーター以降のすべてのプロパティーは、起動時に実装の initialize
メソッドに渡されます。
14.5.2. 手動の最適化
SearchFactory
を使用して、Hibernate Search からプログラムで Lucene インデックスを最適化 (デフラグ) できます。
例14.69 プログラムによるインデックスの最適化
FullTextSession fullTextSession = Search.getFullTextSession(regularSession); SearchFactory searchFactory = fullTextSession.getSearchFactory(); searchFactory.optimize(Order.class); // or searchFactory.optimize();
Order
を保持している Lucene インデックスを最適化し、次の例はすべてのインデックスを最適化します。
searchFactory.optimize()
は JMS バックエンドには影響を与えません。マスターノードで最適化操作を適用する必要があります。
14.5.3. 最適化の調整
hibernate.search.[default|<indexname>].indexwriter.max_buffered_docs
hibernate.search.[default|<indexname>].indexwriter.max_merge_docs
hibernate.search.[default|<indexname>].indexwriter.merge_factor
hibernate.search.[default|<indexname>].indexwriter.ram_buffer_size
hibernate.search.[default|<indexname>].indexwriter.term_index_interval
14.6. 高度な機能
14.6.1. SearchFactory へのアクセス
SearchFactory
オブジェクトは、Hibernate Search の基礎となる Lucene リソースを追跡します。これは、Lucene にネイティブにアクセスする便利な方法です。SearchFactory
は FullTextSession
からアクセスできます。
例14.70 SearchFactory
へのアクセス
FullTextSession fullTextSession = Search.getFullTextSession(regularSession); SearchFactory searchFactory = fullTextSession.getSearchFactory();
14.6.2. IndexReader の使用
IndexReader
で実行されます。Hibernate Search は、パフォーマンスを最大化するためにインデックスリーダーをキャッシュするか、更新された IndexReader
軽減 I/O 操作を取得するために他の効率的なストラテジーを提供する場合があります。コードはこれらのキャッシュされたリソースにアクセスできますが、要件がいくつかあります。
例14.71 IndexReader
へのアクセス
IndexReader reader = searchFactory.getIndexReaderAccessor().open(Order.class); try { //perform read-only operations on the reader } finally { searchFactory.getIndexReaderAccessor().close(reader); }
SearchFactory
は (シャード化ストラテジーに関連して) このエンティティーのクエリーに必要なインデックスを判別します。各インデックスで設定された ReaderProvider
を使用して、関連するすべてのインデックスの上に複合 IndexReader
を返します。この IndexReader
は複数のクライアント間で共有されるため、以下のルールに従う必要があります。
- IndexReader.close() を呼び出さず、必要に応じて readerProvider.closeReader(reader) を finally ブロックで使用します。
- 変更操作には、この
IndexReader
を使用しないでください (読み取り専用のIndexReader
であり、このような試行によって例外が発生します)。
IndexReader
を自由に使用できます。共有 IndexReader
s を使用すると、たとえばファイルシステムから直接開くよりも、ほとんどのクエリーがより効率的になります。
open(Class... types)
あなたが使用することができますopen(String... indexNames)
、1 つ以上のインデックス名を渡すことができます。このストラテジーを使用して、シャードが使用される場合に、インデックスタイプに対してインデックスのサブセットを選択することもできます。
例14.72 インデックス名による IndexReader
へのアクセス
IndexReader reader = searchFactory.getIndexReaderAccessor().open("Products.1", "Products.3");
14.6.3. Lucene ディレクトリーへのアクセス
Directory
は、インデックスストレージを表すために Lucene で使用される最も一般的な抽象化です。Hibernate Search は Lucene Directory
と直接対話することはありませんが、これらの対話は IndexManager
経由で抽象化されます。インデックスが必ずしも Directory
によって実装される必要はありません。
Directory
として表示され、アクセスする必要がある場合は、IndexManager
から Directory
への参照を取得できます。IndexManager
を DirectoryBasedIndexManager
にキャストし、getDirectoryProvider().getDirectory()
を使用して基礎となる Directory
への参照を取得します。これは推奨されていません.代わりに IndexReader
を使用することが推奨されます。
14.6.4. シャード化インデックス
- 単一のインデックスが大きいと、インデックスの更新時間は遅くなります。
- 一般的な検索は、データが顧客、地域、またはアプリケーションによってセグメント化された場合など、インデックスのサブセットのみに一致します。
hibernate.search.<indexName>.sharding_strategy.nbr_of_shards
プロパティーを使用します。
例14.73 インデックスシャーディングの有効化
hibernate.search.<indexName>.sharding_strategy.nbr_of_shards = 5
IndexShardingStrategy
を使用します。デフォルトのシャード化ストラテジーは、(FieldBridge
によって生成された)ID 文字列表現のハッシュ値に従ってデータを分割します。これにより、シャードが大幅に分散されます。カスタムの IndexShardingStrategy
を実装して、デフォルトのストラテジーを置き換えることができます。カスタムストラテジーを使用するには、hibernate.search.<indexName>.sharding_strategy
プロパティーを設定する必要があります。
例14.74 カスタムシャーディング戦略の指定
hibernate.search.<indexName>.sharding_strategy = my.shardingstrategy.Implementation
IndexShardingStrategy
プロパティーでは、クエリーを実行するシャードを選択して検索を最適化することもできます。フィルターをアクティベートすることで、シャード化ストラテジーはクエリー (IndexShardingStrategy.getIndexManagersForQuery
) に回答するために使用されるシャードのサブセットを選択できるため、クエリーの実行が速くなります。
IndexManager
があるため、異なるディレクトリープロバイダーおよびバックエンド設定を使用するように設定できます。の Animal エンティティーの IndexManager
インデックス名例14.75「エンティティーアニマルのシャーディング設定」Animal.0
から Animal.4
です。つまり、各シャードには所有するインデックス名の後に .
(ドット) とそのインデックス番号が設定されます。
例14.75 エンティティーアニマルのシャーディング設定
hibernate.search.default.indexBase = /usr/lucene/indexes hibernate.search.Animal.sharding_strategy.nbr_of_shards = 5 hibernate.search.Animal.directory_provider = filesystem hibernate.search.Animal.0.indexName = Animal00 hibernate.search.Animal.3.indexBase = /usr/lucene/sharded hibernate.search.Animal.3.indexName = Animal03
Animal
インデックスを 5 つのサブインデックスに使用しています。すべてのサブインデックスはファイルシステムのインスタンスで、各サブインデックスが保存されるディレクトリーは、以下のようになります。
- sub-index 0:
/usr/lucene/indexes/Animal00
(共有 indexBase、indexName を上書き) - sub-index 1 の場合:
/usr/lucene/indexes/Animal.1
(共有 indexBase、デフォルト indexName) - sub-index 2:
/usr/lucene/indexes/Animal.2
(共有 indexBase、デフォルト indexName) - sub-index 3:
/usr/lucene/shared/Animal03
(上書きされた indexBase、上書きされた indexName) - sub-index 4:
/usr/lucene/indexes/Animal.4
(共有 indexBase、デフォルト indexName)
IndexShardingStrategy
を実装する場合は、任意のフィールドを使用してシャード化の選択を判断できます。deletion、purge
、purgeAll
などの操作を処理するには、すべてのフィールド値またはプライマリー識別子を読み取れずにインデックスを返す必要があることもあります。このような場合、すべてのインデックスが返されるため、削除操作は、削除されるドキュメントが含まれる可能性のあるすべてのインデックスに伝播されます。
14.6.5. Lucene のスコアリングカスタマイズ
org.apache.lucene.search.Similarity
を拡張して、そのフラグ式をカスタマイズできます。このクラスで定義された抽象メソッドは、以下の式の係数と一致し、ドキュメント d のクエリー q のスコアを計算します。
ファクター | 説明 |
---|---|
tf(t ind) | ドキュメント (d) の用語 (t) の周波数係数。 |
idf(t) | 用語の頻度に関する記録。 |
coord(q,d) | 指定されたドキュメントのクエリー用語がいくつあるかに基づくスコア要因。 |
queryNorm(q) | クエリー間でスコアを設定するために使用される正規化の要素。 |
t.getBoost() | フィールドブースト。 |
norm(t,d) | いくつかの (インデックス時間) ブーストおよび長さ要素をカプセル化します。 |
Similarity
の Javadoc を参照してください。
類似性
実装の完全に指定されたクラス名を指定することにより、デフォルトの類似性を設定できますhibernate.search.similarity
。デフォルト値は org.apache.lucene.search.DefaultSimilarity
です。
similarity
プロパティーを設定して特定のインデックスに使用される類似性を上書きすることもできます。
hibernate.search.default.similarity = my.custom.Similarity
@Similarity
アノテーションを使用してクラスレベルのデフォルトの類似性を上書きできます。
@Entity
@Indexed
@Similarity(impl = DummySimilarity.class)
public class Book {
...
}
tf(float freq)
1.0 を返す必要があります。
Similarity
実装を宣言する必要があります。同じクラス階層のクラスは常にインデックスを共有するため、Similarity
実装の上書きはできません。
14.6.6. 例外処理の設定
hibernate.search.error_handler = log
ErrorHandler
インターフェイスを実装する必要があります。handle(ErrorContext context)
方法。ErrorContext
プライマリーへの参照を提供しますLuceneWork
インスタンス、根本的な例外およびその後の例外LuceneWork
主な例外のために処理できなかったインスタンス。
public interface ErrorContext { List<LuceneWork> getFailingOperations(); LuceneWork getOperationAtFault(); Throwable getThrowable(); boolean hasErrors(); }
ErrorHandler
実装の完全修飾クラス名を宣言する必要があります。
hibernate.search.error_handler = CustomerErrorHandler
14.6.7. Hibernate Search の無効化
インデックスの無効化
Hibernate Search インデックスを無効にするには、indexing_strategy
設定オプションを manual
に変更して JBoss EAP を再起動します。
hibernate.search.indexing_strategy = manual
Hibernate Search を完全に無効にする
Hibernate Search を完全に無効にするには、autoregister_listeners
設定オプションをfalse
に変更してすべてのリスナーを無効にし、JBoss EAP を再起動します。
hibernate.search.autoregister_listeners = false
第15章 JAX-RSWeb サービス
15.1. JAX-RS について
helloworld-rs
、jax-rs-client
、とkitchensink
クイックスタート:「クイックスタートにアクセスする」。
15.2. RESTEasy について
15.3. RESTfulWeb サービスについて
15.4. RESTEasy で定義された注釈
表15.1 JAX-RS/RESTEasy アノテーション
アノテーション | 用途 |
---|---|
ClientResponseType | これは、応答タイプが返される RESTEasy クライアントインターフェイスに追加できる注釈です。 |
ContentEncoding | アノテーション付きのアノテーションで適用する Content-Encoding を指定するメタアノテーション。 |
DecorateTypes | サポートされているタイプを指定するには、DecoratorProcessor クラスに配置する必要があります。 |
Decorator | デコレーションをトリガーする別のアノテーションに配置されるメタアノテーション。 |
Form | これは、リクエストと要求の発信および受信を行うためにオブジェクトとして使用できます。 |
StringParameterUnmarshallerBinder | 文字列ベースのアノテーションインジェクターに適用されるように StringParameterUnmarshaller をトリガーする別のアノテーションに配置されるメタアノテーション。 |
Cache | 応答の Cache-Control ヘッダーを自動的に設定します。 |
NoCache | nocache の Cache-Control 応答ヘッダーを設定します。 |
ServerCached | この jax-rs メソッドへの応答をサーバーにキャッシュする必要があることを指定します。 |
ClientInterceptor | インターセプターをクライアント側のインターセプターとして特定します。 |
DecoderPrecedence | このインターセプターは、コンテンツエンコーディングデコーダーです。 |
EncoderPrecedence | このインターセプターは、コンテンツエンコーディングエンコーダーです。 |
HeaderDecoratorPrecedence | HeaderDecoratorPrecedence インターセプターは、応答 (サーバー上) または送信要求 (クライアント上) を特別なユーザー定義のヘッダーで装飾するため、常に最初に来る必要があります。 |
RedirectPrecedence | PreProcessInterceptor に配置する必要があります。 |
SecurityPrecedence | PreProcessInterceptor に配置する必要があります。 |
ServerInterceptor | インターセプターをサーバー側のインターセプターとして特定します。 |
NoJackson | Jackson プロバイダーをトリガーしない場合にクラス、パラメーター、フィールド、またはメソッドに配置します。 |
ImageWriterParams | IIOImageProvider にパラメーターを渡すためにリソースクラスが使用できるアノテーション。 |
DoNotUseJAXBProvider | このクラスまたはパラメーターは、JAXB MessageBodyReader/Writer を使用せず、代わりにタイプをマーシャリングするために使用するより具体的なプロバイダーがある場合に使用してください。 |
Formatted | インデントと改行で XML 出力をフォーマットします。これは、JAXB Decorator です。 |
IgnoreMediaTypes | タイプ、メソッド、パラメーター、またはフィールドにフィールドを置くと、特定のメディアタイプに対して JAXRS プロバイダーを使用しないように指示します。 |
Stylesheet | XML スタイルシートヘッダーを指定します。 |
Wrapped | これをメソッドまたはパラメーターに配置すると、指定のオブジェクトのコレクションまたは配列をマーシャリングまたはマーシャリング解除できます。 |
WrappedMap | これは、JAXB オブジェクトのマップのマーシャリングまたはマーシャリング解除を行う場合は、メソッドまたはパラメーターに配置します。 |
XmlHeader | 返されたドキュメントの XML ヘッダーを設定します。 |
BadgerFish | A JSONConfig. |
Mapped | A JSONConfig. |
XmlNsMap | A JSONToXml. |
MultipartForm | これは、multipart/form-data mime タイプの受信/発進のオブジェクトとして使用できます。 |
PartType | List または Map を multipart/* タイプとして書き出す場合は、Multipart プロバイダーと併用する必要があります。 |
XopWithMultipartRelated | このアノテーションは、アノテーション付きのオブジェクト間の XOP メッセージの受信/送信 (multipart / 関連としてパッケージ化) の処理と生成に使用できます。 |
After | 署名時に有効期限属性を追加するため、または検証のための古いチェックとして使用されます。 |
Signed | DOSETA 仕様を使用して要求または応答の署名をトリガーするコンビニエンスアノテーション。 |
Verify | 署名ヘッダーで指定された入力署名の検証。 |
Path | これは、クラスまたはリソースメソッドに存在する必要があります。両方に存在する場合、リソースメソッドへの相対パスはクラスとメソッドの連結になります。 |
PathParam | 変数 URI パスのフラグメントをメソッド呼び出しにマッピングできるようにします。 |
QueryParam | URI クエリー文字列パラメーターまたは URL 形式のエンコードされたパラメーターをメソッド呼び出しにマップできるようにします。 |
CookieParam | HTTP リクエスト cookie のクッキーまたはオブジェクト表現の値をメソッド呼び出しに指定できます。 |
DefaultValue | HTTP リクエスト項目が存在しない場合にデフォルト値を定義するために、その他の @*Param アノテーションと組み合わせることができます。 |
Context | javax.ws.rs.core.HttpHeaders、javax.ws.rs.core.UriInfo、javax.ws.rs.core.Request、javax.servlet.HttpServletRequest、javax.servlet.HttpServletResponse、javax.ws.rs.core.SecurityContext オブジェクトのインスタンスを指定できます。 |
Encoded | クラス、メソッド、またはパラメーターで使用できます。デフォルトでは、@PathParam および @QueryParams はデコードされます。@Encoded アノテーションを追加すると、これらのパラメーターの値がエンコードされた形式で提供されます。 |
15.5. RESTEasy 設定
15.5.1. RESTEasy 設定パラメーター
表15.2 要素
オプション名 | デフォルト値 | 説明 |
---|---|---|
resteasy.servlet.mapping.prefix | デフォルトなし | Resteasy servlet-mapping の url パターンが /*ではない場合。 |
resteasy.scan | false | @Provider および JAX-RS リソースクラス (@Path、@GET、@POST など) の両方に対して WEB-INF/lib JARs および WEB-INF/classes を自動的にスキャンします。 |
resteasy.scan.providers | false | @Provider クラスをスキャンして登録します。 |
resteasy.scan.resources | false | JAX-RS リソースクラスのスキャン。 |
resteasy.providers | デフォルトなし | 登録する完全修飾 @Provider クラス名のコンマ区切りリスト。 |
resteasy.use.builtin.providers | true | デフォルトのビルトイン @Provider クラスを登録するかどうか。 |
resteasy.resources | デフォルトなし | 登録する完全修飾 JAX-RS リソースクラス名のコンマ区切りリスト。 |
resteasy.jndi.resources | デフォルトなし | JAX-RS リソースとして登録するオブジェクトを参照する JNDI 名のカンマ区切りリスト。 |
javax.ws.rs.Application | デフォルトなし | 仕様移植可能な方法でブートストラップする Application クラスの完全修飾名。 |
resteasy.media.type.mappings | デフォルトなし | ファイル名の拡張子 (例: .xml や txt) をメディアタイプにマッピングすることで、Accept ヘッダーの必要性を置き換えます。クライアントが Accept ヘッダーを使用して表示 (ブラウザーなど) を選択できない場合に使用されます。 |
resteasy.language.mappings | デフォルトなし | ファイル名の拡張子 (.en または .fr など) を言語にマッピングすることで、Accept-Language ヘッダーの必要性を置き換えます。クライアントが Accept-Language ヘッダーを使用して言語 (ブラウザーなど) を選択できない場合に使用されます。 |
resteasy.document.expand.entity.references | false | 外部エンティティーを展開するか、空の文字列に置き換えるか。JBoss EAP 6 では、このパラメーターのデフォルトは false であるため、空の文字列に置き換わります。 |
resteasy.document.secure.processing.feature | true | org.w3c.dom.Document ドキュメントとつの JAXB オブジェクト表現を処理する際にセキュリティー制約を課します。 |
resteasy.document.secure.disableDTDs | true | org.w3c.dom.Document ドキュメントおよび JAXB オブジェクトの表現を禁止します。 |
resteasy.scan.*
ファイルの web.xml
設定は無視され、すべての JAX-RS アノテーションが付けられたコンポーネントが自動的にスキャンされます。
15.6. JAX-RSWeb サービスセキュリティー
15.6.1. RESTEasy JAX-RS Web サービスのロールベースのセキュリティーの有効化
概要
RESTEasy は JAX-RS メソッドでの @RolesAllowed、@PermitAll、@DenyAll アノテーションに対応しています。ただし、デフォルトではこれらの注釈は認識されません。以下の手順に従って、web.xml
ファイルを設定し、ロールベースのセキュリティーを有効にします。
- resteasy.document.expand.entity.references
- resteasy.document.secure.processing.feature
- resteasy.document.secure.disableDTDs
手順15.1 RESTEasy JAX-RS Web サービスのロールベースのセキュリティーの有効化
- テキストエディターでアプリケーションの
web.xml
ファイルを開きます。 - 以下の <context-param> をファイルに、
web-app
内に追加します。<context-param> <param-name>resteasy.role.based.security</param-name> <param-value>true</param-value> </context-param>
- <security-role> タグを使用して、RESTEasy JAX-RS WAR ファイル内で使用されるすべてのロールを宣言します。
<security-role> <role-name>ROLE_NAME</role-name> </security-role> <security-role> <role-name>ROLE_NAME</role-name> </security-role>
- すべてのロールについて JAX-RS ランタイムによって処理されるすべての 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>
結果
ロールベースのセキュリティーは、定義されたロールとともにアプリケーション内で有効にされています。
例15.1 例: ロールベースのセキュリティー設定
<web-app> <context-param> <param-name>resteasy.role.based.security</param-name> <param-value>true</param-value> </context-param> <servlet-mapping> <servlet-name>Resteasy</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <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> <security-role> <role-name>admin</role-name> </security-role> <security-role> <role-name>user</role-name> </security-role> </web-app>
15.6.2. アノテーションを使用して JAX-RSWeb サービスを保護する
概要
このトピックでは、サポートされているセキュリティーアノテーションを使用して JAX-RSWeb サービスを保護する手順について説明します。
手順15.2 サポートされているセキュリティーアノテーションを使用して JAX-RSWeb サービスを保護する
- ロールベースセキュリティーを有効化します。詳細は、「RESTEasy JAX-RS Web サービスのロールベースのセキュリティーの有効化」 を参照してください。
- JAX-RS Web サービスにセキュリティーアノテーションを追加します。RESTEasy は以下のアノテーションをサポートします。
- @RolesAllowed
- メソッドにアクセスできるロールを定義します。すべてのロールは
web.xml
ファイルで定義する必要があります。 - @PermitAll
web.xml
ファイルに定義されているすべてのロールがメソッドにアクセスできるようにします。- @DenyAll
- メソッドへのすべてのアクセスを拒否します。
15.7. 例外処理
15.7.1. 例外マッパーを作成する
概要
例外マッパーは、出力された例外をキャッチし、特定の HTTP 応答を書き込むカスタムのアプリケーション提供コンポーネントです。
例15.2 例外マッパー
ExceptionMapper
インターフェイス。
@Provider public class EJBExceptionMapper implements ExceptionMapper<javax.ejb.EJBException> { Response toResponse(EJBException exception) { return Response.status(500).build(); } }
web.xml
ファイルのresteasy.providers
context-param、またはプログラムで登録しますResteasyProviderFactory
クラス。
15.7.2. RESTEasy 内部で出力された例外
表15.3 例外リスト
例外 | HTTP コード | 説明 |
---|---|---|
BadRequestException | 400 | 正しくない要求。リクエストが適切にフォーマットされていなかったか、またはリクエスト入力の処理に問題がありました。 |
UnauthorizedException | 401 | 承認されていません。RESTEasy のアノテーションベースのロールベースのセキュリティーを使用している場合には、セキュリティー例外が発生します。 |
InternalServerErrorException | 500 | 内部サーバーエラー。 |
MethodNotAllowedException | 405 | リソースが呼び出した HTTP 操作を処理できる JAX-RS メソッドはありません。 |
NotAcceptableException | 406 | Accept ヘッダーに一覧表示されるメディアタイプを生成する JAX-RS メソッドはありません。 |
NotFoundException | 404 | リクエストパス/ リソースを提供する JAX-RS メソッドはありません。 |
ReaderException | 400 | から出力されたすべての例外MessageBodyReaders この例外にラップされます。ない場合ExceptionMapper ラップされた例外の場合、または例外がWebApplicationException の場合、RESTEasy はデフォルトで 400 コードを返します。 |
WriterException | 500 | から出力されたすべての例外MessageBodyWriters この例外にラップされます。ない場合ExceptionMapper ラップされた例外の場合、または例外がWebApplicationException の場合、RESTEasy はデフォルトで 400 コードを返します。 |
JAXBUnmarshalException | 400 | JAXB プロバイダー (XML および Jettison) は、読み取り時にこの例外を出力します。JAXBExceptions をラップしている可能性があります。このクラスは拡張しますReaderException 。 |
JAXBMarshalException | 500 | JAXB プロバイダー (XML および Jettison) は、書き込み時にこの例外を出力します。JAXBExceptions をラップしている可能性があります。このクラスは拡張しますWriterException 。 |
ApplicationException | 該当なし | アプリケーションコードから出力されたすべての例外をラップします。と同じように機能しますInvocationTargetException 。ラップされた例外に対する ExceptionMapper がある場合は、要求の処理に使用されます。 |
失敗 | 該当なし | 内部 RESTEasy エラー。ログに記録されない。 |
LoggableFailure | 該当なし | 内部 RESTEasy エラー。ログが記録されています。 |
DefaultOptionsMethodException | 該当なし | ユーザーが HTTP OPTIONS を呼び出しても、JAX-RS メソッドが呼び出されない場合、RESTEasy はこの例外を発生させてデフォルトの動作を提供します。 |
15.8. RESTEasy インターセプター
15.8.1. JAX-RS 呼び出しのインターセプト
概要
RESTEasy は JAX-RS 呼び出しをインターセプトし、インターセプターと呼ばれるリスナーのようなオブジェクトでそれらをルーティングできます。このトピックでは、4 種類のインターセプターについて説明します。
例15.3 MessageBodyReader/Writer インターセプター
@Provider
、およびいずれか@ServerInterceptor
また@ClientInterceptor
RESTEasy がそれらをインターセプターリストに追加するかどうかを認識できるようにします。
MessageBodyReader.readFrom()
またMessageBodyWriter.writeTo()
。これらは、Output や Input ストリームをラップするために使用できます。
public interface MessageBodyReaderInterceptor { Object read(MessageBodyReaderContext context) throws IOException, WebApplicationException; } public interface MessageBodyWriterInterceptor { void write(MessageBodyWriterContext context) throws IOException, WebApplicationException; }
MessageBodyReaderContext.proceed()
またMessageBodyWriterContext.proceed()
次のインターセプターに移動するために呼び出されます。呼び出すインターセプターがこれ以上ない場合は、readFrom()
またwriteTo()
MessageBodyReader または MessageBodyWriter のメソッド。このラッピングにより、オブジェクトは Reader や Writer に到達する前に変更でき、proceed()
が返された後にクリーンアップされます。
@Provider @ServerInterceptor public class MyHeaderDecorator implements MessageBodyWriterInterceptor { public void write(MessageBodyWriterContext context) throws IOException, WebApplicationException { context.getHeaders().add("My-Header", "custom"); context.proceed(); } }
例15.4 PreProcessInterceptor
public interface PreProcessInterceptor { ServerResponse preProcess(HttpRequest request, ResourceMethod method) throws Failure, WebApplicationException; }
preProcess()
メソッドが ServerResponse を返すと、基になる JAX-RS メソッドは呼び出されず、ランタイムは応答を処理してクライアントに戻ります。の場合preProcess()
メソッドは ServerResponse を返さず、基礎となる JAX-RS メソッドが呼び出されます。
例15.5 PostProcessInterceptors
public interface PostProcessInterceptor { void postProcess(ServerResponse response); }
例15.6 ClientExecutionInterceptors
@ClientInterceptor
と@Provider
。これらのインターセプターは、MessageBodyWriter の後、および ClientRequest がクライアント側で構築された後に実行されます。
public interface ClientExecutionInterceptor { ClientResponse execute(ClientExecutionContext ctx) throws Exception; } public interface ClientExecutionContext { ClientRequest getRequest(); ClientResponse proceed() throws Exception; }
15.8.2. インターセプターを JAX-RS メソッドにバインドする
概要
登録されているすべてのインターセプターは、デフォルトですべての要求に対して呼び出されます。The AcceptedByMethod
この動作を微調整するためにインターフェイスを実装できます。
例15.7 バインディングインターセプターの例
accept()
を実装するインターセプターのメソッド AcceptedByMethod
インターフェイス。メソッドが true を返す場合、インターセプターは JAX-RS メソッドのコールチェーンに追加されます。それ以外の場合は、そのメソッドでは無視されます。
accept()
@GET アノテーションが JAX-RS メソッドに存在するかどうかを判別します。そうである場合、インターセプターはメソッドの呼び出しチェーンに適用されます。
@Provider @ServerInterceptor public class MyHeaderDecorator implements MessageBodyWriterInterceptor, AcceptedByMethod { public boolean accept(Class declaring, Method method) { return method.isAnnotationPresent(GET.class); } public void write(MessageBodyWriterContext context) throws IOException, WebApplicationException { context.getHeaders().add("My-Header", "custom"); context.proceed(); } }
15.8.3. インターセプターを登録する
概要
このトピックでは、RESTEasyJAX-RS インターセプターをアプリケーションに登録する方法について説明します。
手順15.3 インターセプターを登録する
- インターセプターを登録するには、以下の
web.xml
ファイルにインターセプターをリストします。resteasy.providers
context-param、またはクラスまたはオブジェクトとして返しますApplication.getClasses()
またApplication.getSingletons()
方法。
例15.8 web.xml ファイル
にインターセプターをリストして登録します。
<context-param> <param-name>resteasy.providers</param-name> <param-value>my.app.CustomInterceptor</paramvalue> </context-param>
例15.9 Application.getClasses () メソッドを使用したインターセプターの登録:
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; } }
例15.10 Application.getSingletons () メソッドを使用したインターセプターの登録:
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 PubSubApplication() { singletons.add(new MyResource()); singletons.add(new MyProvider()); } @Override public Set<Object> getSingletons() { return singletons; } }
15.8.4. インターセプター優先ファミリー
15.8.4.1. インターセプター優先ファミリーについて
概要
インターセプターは、呼び出される順序に敏感になる可能性があります。RESTEasy は、インターセプターをファミリーにグループ化して、順序付けを簡単にします。このリファレンストピックでは、組み込みのインターセプター優先順位ファミリーとそれぞれに関連付けられたインターセプターについて説明します。
- セキュリティー
- SECURITY インターセプターは通常 PreProcessInterceptors です。呼び出しが許可される前に実行する必要があるのは可能な限り少ないため、最初に呼び出されます。
- HEADER_DECORATOR
- HEADER_DECORATOR インターセプターは、応答または送信要求にヘッダーを追加します。追加されたヘッダーが他のインターセプターファミリーの動作に影響を与える可能性があるため、これらはセキュリティーインターセプターに従います。
- エンコーダー
- ENCODER インターセプターは OutputStream を変更します。たとえば、GZIP インターセプターは GZIPOutputStream を作成して、圧縮のために実際の OutputStream をラップします。
- REDIRECT
- REDIRECT インターセプターは、リクエストを再ルーティングして JAX-RS メソッドを完全にバイパスする可能性があるため、通常 PreProcessInterceptors で使用されます。
- デコーダ
- DECODER インターセプターは InputStream をラップします。たとえば、GZIP インターセプターデコーダーは InputStream を GzipInputStream インスタンスにラップします。
org.jboss.resteasy.annotations.interception
パッケージ:@DecoredPrecedence
、@EncoderPrecedence
、@HeaderDecoratorPrecedence
、@RedirectPrecedence
、@SecurityPrecedence
。の代わりにこれらを使用してください@Precedence
注釈。詳細は、「RESTEasy で定義された注釈」 を参照してください。
15.8.4.2. カスタムインターセプター優先順位ファミリーを定義する
概要
カスタム優先順位ファミリーを作成して、web.xml
ファイルに登録できます。このトピックでは、インターセプター優先順位ファミリーを定義するために使用できるコンテキストパラメーターの例について説明します。
例15.11 resteasy.append.interceptor.precedence
resteasy.append.interceptor.precedence
context param は、新しい優先順位ファミリーをデフォルトの優先順位ファミリーリストに追加します。
<context-param> <param-name>resteasy.append.interceptor.precedence</param-name> <param-value>CUSTOM_PRECEDENCE_FAMILY</param-value> </context-param>
例15.12 resteasy.interceptor.before.precedence
resteasy.interceptor.before.precedence
context param は、カスタムファミリーが以前に実行されるデフォルトの優先順位ファミリーを定義します。パラメーター値は、':' で区切られた DEFAULT_PRECEDENCE_FAMILY/CUSTOM_PRECEDENCE_FAMILY の形式を取ります。
<context-param> <param-name>resteasy.interceptor.before.precedence</param-name> <param-value>DEFAULT_PRECEDENCE_FAMILY : CUSTOM_PRECEDENCE_FAMILY</param-value> </context-param>
例15.13 resteasy.interceptor.after.precedence
resteasy.interceptor.after.precedence
context param は、カスタムファミリーが実行されるデフォルトの優先ファミリーを定義します。パラメーター値は、:
で区切られた DEFAULT_PRECEDENCE_FAMILY/CUSTOM_PRECEDENCE_FAMILY の形式を取ります。
<context-param> <param-name>resteasy.interceptor.after.precedence</param-name> <param-value>DEFAULT_PRECEDENCE_FAMILY : CUSTOM_PRECEDENCE_FAMILY</param-value> </context-param>
15.9. 文字列ベースの注釈
15.9.1. 文字列ベースの @*Param アノテーションをオブジェクトに変換する
@*Param
アノテーションは、raw HTTP リクエストで文字列として表されます。これらのタイプのインジェクトされたパラメーターは、それらのオブジェクトに valueOf(String) 静的メソッドまたは String パラメーターを取るコンストラクターがある場合に、オブジェクトに変換できます。
@Provider
どちらも持たないクラスのこの変換を処理するためのインターフェイスvalueOf(String)
静的メソッド、または文字列コンストラクタ。
例15.14 StringConverter
import org.jboss.resteasy.client.ProxyFactory; import org.jboss.resteasy.spi.StringConverter; import org.jboss.resteasy.test.BaseResourceTest; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import javax.ws.rs.HeaderParam; import javax.ws.rs.MatrixParam; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; import javax.ws.rs.ext.Provider; public class StringConverterTest extends BaseResourceTest { public static class POJO { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } @Provider public static class POJOConverter implements StringConverter<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(); } } @Path("/") public static class MyResource { @Path("{pojo}") @PUT public void put(@QueryParam("pojo")POJO q, @PathParam("pojo")POJO pp, @MatrixParam("pojo")POJO mp, @HeaderParam("pojo")POJO hp) { Assert.assertEquals(q.getName(), "pojo"); Assert.assertEquals(pp.getName(), "pojo"); Assert.assertEquals(mp.getName(), "pojo"); Assert.assertEquals(hp.getName(), "pojo"); } } @Before public void setUp() throws Exception { dispatcher.getProviderFactory().addStringConverter(POJOConverter.class); dispatcher.getRegistry().addPerRequestResource(MyResource.class); } @Path("/") public static interface MyClient { @Path("{pojo}") @PUT void put(@QueryParam("pojo")POJO q, @PathParam("pojo")POJO pp, @MatrixParam("pojo")POJO mp, @HeaderParam("pojo")POJO hp); } @Test public void testIt() throws Exception { MyClient client = ProxyFactory.create(MyClient.class, "http://localhost:8081"); POJO pojo = new POJO(); pojo.setName("pojo"); client.put(pojo, pojo, pojo, pojo); } }
例15.15 StringParameterUnmarshaller
StringParameterUnmarshaller
インターフェイスは、挿入するパラメーターまたはフィールドに配置された注釈に敏感です。インジェクターごとに作成されます。setAnnotations () メソッドは、アンマーシャラーを初期化するために resteasy によって呼び出されます。
org.jboss.resteasy.annotations.StringsParameterUnmarshallerBinder
。
java.util.Date
ベースの @PathParam。
public class StringParamUnmarshallerTest extends BaseResourceTest { @Retention(RetentionPolicy.RUNTIME) @StringParameterUnmarshallerBinder(DateFormatter.class) public @interface DateFormat { String value(); } public static class DateFormatter implements StringParameterUnmarshaller<Date> { private SimpleDateFormat formatter; public void setAnnotations(Annotation[] annotations) { DateFormat format = FindAnnotation.findAnnotation(annotations, DateFormat.class); formatter = new SimpleDateFormat(format.value()); } public Date fromString(String str) { try { return formatter.parse(str); } catch (ParseException e) { throw new RuntimeException(e); } } } @Path("/datetest") public static class Service { @GET @Produces("text/plain") @Path("/{date}") public String get(@PathParam("date") @DateFormat("MM-dd-yyyy") Date date) { System.out.println(date); Calendar c = Calendar.getInstance(); c.setTime(date); Assert.assertEquals(3, c.get(Calendar.MONTH)); Assert.assertEquals(23, c.get(Calendar.DAY_OF_MONTH)); Assert.assertEquals(1977, c.get(Calendar.YEAR)); return date.toString(); } } @BeforeClass public static void setup() throws Exception { addPerRequestResource(Service.class); } @Test public void testMe() throws Exception { ClientRequest request = new ClientRequest(generateURL("/datetest/04-23-1977")); System.out.println(request.getTarget(String.class)); } }
15.10. ファイル拡張子を設定する
15.10.1. web.xml ファイルのメディアタイプにファイル拡張子をマップします
概要
ブラウザーなどの一部のクライアントは、Accept および Accept-Language ヘッダーを使用して、表現メディアタイプまたは言語をネゴシエートできません。RESTEasy は、この問題に対処するために、ファイル名サフィックスをメディアタイプおよび言語にマップできます。次の手順に従って、web.xml
ファイルでメディアタイプをファイル拡張子にマップします。
手順15.4 メディアタイプをファイル拡張子にマップする
- テキストエディターでアプリケーションの
web.xml
ファイルを開きます。 - context-param を追加します
resteasy.media.type.mappings
ファイルに、内部web-app
タグ:<context-param> <param-name>resteasy.media.type.mappings</param-name> </context-param>
- パラメーター値を設定します。マッピングはコンマ区切りのリストを形成します。各マッピングは、
:
:例15.16 マッピングの例
<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>
15.10.2. ファイル拡張子を web.xml ファイルの言語にマップする
概要
ブラウザーなどの一部のクライアントは、Accept および Accept-Language ヘッダーを使用して、表現メディアタイプまたは言語をネゴシエートできません。RESTEasy は、この問題に対処するために、ファイル名サフィックスをメディアタイプおよび言語にマップできます。以下の手順に従い、web.xml
ファイルのファイル拡張子に言語をマッピングします。
手順15.5 ファイル拡張子を web.xml ファイルの言語にマップする
- テキストエディターでアプリケーションの
web.xml
ファイルを開きます。 - context-param を追加します
resteasy.language.mappings
ファイルに、内部web-app
タグ:<context-param> <param-name>resteasy.language.mappings</param-name> </context-param>
- パラメーター値を設定します。マッピングはコンマ区切りのリストを形成します。各マッピングは、
:
:例15.17 マッピングの例
<context-param> <param-name>resteasy.language.mappings</param-name> <param-value> en : en-US, es : es, fr : fr</param-name> </context-param>
15.10.3. RESTEasy がサポートするメディアタイプ
表15.4 メディアタイプ
メディアタイプ | Java タイプ |
---|---|
application/*+xml, text/*+xml, application/*+json, application/*+fastinfoset, application/atom+* | JaxB アノテーション付きクラス |
application/*+xml, text/*+xml | org.w3c.dom.Document |
*/* | java.lang.String |
*/* | java.io.InputStream |
text/plain | プリミティブ、java.lang.String、または String コンストラクターを持つタイプ、または入力用の静的 valueOf(String) メソ背戸、出力用の toOf() メソッド。 |
*/* | javax.activation.DataSource |
*/* | byte[] |
*/* | java.io.File |
application/x-www-form-urlencoded | javax.ws.rs.core.MultivaluedMap |
15.11. RESTEasy JavaScript API
15.11.1. RESTEasy JavaScript API について
例15.18 単純な JAX-RSJavaScriptAPI の例
@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){ } }
var text = Foo.get({order: 'desc', 'X-Foo': 'hello', colour: 'blue', 'Foo-Cookie': 123987235444}); Foo.put({$entity: text});
15.11.2. RESTEasy JavaScript API サーブレットの有効化
概要
RESTEasyJavaScriptAPI はデフォルトでは有効になっていません。次の手順に従って、web.xml
ファイルを使用して有効にします。
手順15.6 web.xml を編集して、RESTEasyJavaScriptAPI を有効にします
- テキストエディターでアプリケーションの
web.xml
ファイルを開きます。 - 次の設定をファイル内の
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</url-pattern> </servlet-mapping>
15.11.3. RESTEasy JavaScript API パラメーター
表15.5 パラメータープロパティー
プロパティー | デフォルト値 | 説明 |
---|---|---|
$entity | PUT、POST 要求として送信するエンティティー。 | |
$contentType | Content-Type ヘッダーとして送信されるボディーエンティティーの MIME タイプ。@Consumes アノテーションで決定されます。 | |
$accepts | */* | Accept ヘッダーとして送信される許可される MIME タイプ。@Provides アノテーションで決定されます。 |
$callback | 非同期呼び出しの関数 (httpCode、xmlHttpRequest、value) に設定します。これがない場合、呼び出しは同期され、値を返します。 | |
$apiURL | 最後のスラッシュを含まない JAX-RS エンドポイントのベース URI に設定します。 | |
$username | ユーザー名およびパスワードが設定されている場合は、要求のクレデンシャルに使用されます。 | |
$password | ユーザー名およびパスワードが設定されている場合は、要求のクレデンシャルに使用されます。 |
15.11.4. JavaScriptAPI を使用して AJAX クエリーを作成する
概要
RESTEasy JavaScript API を使用すると、手動で要求を作成することができます。このトピックでは、この動作の例について説明します。
例15.19 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); };
- apiURL
- デフォルトでは、JAX-RS ルート URL に設定されています。要求の作成時にすべての JavaScript クライアント API 機能によって使用されます。
- log
- log: RESTEasy クライアント API ログを受信するために function(string) に設定します。これは、クライアント API のデバッグ、およびそれらを確認できる場所のログの配置を行う場合に便利です。
例15.20 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); });
15.11.5. rest.Request クラスメンバー
表15.6 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) | 要求ヘッダーを追加します。 |
15.12. RESTEasy Asynchronous Job Service
15.12.1. RESTEasy 非同期ジョブサービスについて
15.12.2. 非同期ジョブサービスを有効にする
手順15.7 web.xml ファイルを変更します
- Asynchronous Job Service は
web.xml
ファイルで有効化します。<context-param> <param-name>resteasy.async.job.service.enabled</param-name> <param-value>true</param-value> </context-param>
結果
非同期ジョブサービスが有効になりました。設定オプションについては、以下を参照してください。「非同期ジョブサービス設定パラメーター」。
15.12.3. RESTEasy の非同期ジョブを設定する
概要
本トピックでは、RESTEasy を使用した非同期ジョブのクエリーパラメーターの例について説明します。
web.xml
ファイルでの XML 宣言を使用してアプリケーションセキュリティーを確立する必要があります。
例15.21 非同期パラメーター
asynch
クエリーパラメーターは、バックグラウンドで呼び出しを実行するために使用されます。202 Accepted 応答が返されます。また、バックグラウンドメソッドの応答がある場所を指す URL が含まれる場所のヘッダーも返されます。
POST http://example.com/myservice?asynch=true
HTTP/1.1 202 Accepted Location: http://example.com/asynch/jobs/3332334
/asynch/jobs/{job-id}?wait={millisconds}|nowait=true
- ジョブが完了したら、GET は応答として呼び出される JAX-RS リソースメソッドを返します。ジョブが完了していない場合、この GET は 202Accepted 応答コードを返します。GET を呼び出してもジョブは削除されないため、複数回呼び出すことができます。
- POST はジョブの応答を読み取り、完了するとジョブを削除します。
- DELETE は、ジョブキューを手動でクリーンアップするために呼び出されます。注記ジョブキューが満杯になると、DELETE を呼び出すことなく、メモリーから最も古いジョブを自動的に無効にします。
例15.22 待つ/待つ
wait
とnowait
クエリーパラメーター。の場合wait
パラメーターが指定されていない場合、操作はデフォルトでnowait=true
、およびジョブが完了していない場合はまったく待機しません。Thewait
パラメーターはミリ秒単位で定義されます。
POST http://example.com/asynch/jobs/122?wait=3000
例15.23 一方向パラメーター
oneway
クエリーパラメーター。
POST http://example.com/myservice?oneway=true
15.12.4. 非同期ジョブサービス設定パラメーター
概要
以下の表は、非同期ジョブサービスの設定可能な context-params の詳細を示しています。これらのパラメーターは web.xml
ファイルで設定できます。
表15.7 設定パラメーター
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 です。 |
例15.24 非同期ジョブ設定の例
<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>
15.13. RESTEasy JAXB
15.13.1. JAXB デコレータを作成する
概要
RESTEasy の資料プロバイダーには、Marshaller および Un Marketplaceler インスタンスを切り離すプラグ可能な方法があります。Marshaller または Unmarshaller インスタンスのいずれかをトリガーできるアノテーションが作成されます。このトピックでは、RESTEasy を使用して JAXB デコレータを作成する手順について説明します。
手順15.8 RESTEasy を使用したデコレーターの作成
Processor クラスを作成します。
- DecoratorProcessor<Target, Annotation> を実装するクラスを作成します。ターゲットは JAXB Marshaller または Unmarshallerクラスのいずれかになります。アノテーションは、ステップ 2 で作成されます。
- クラスに @DecorateTypes アノテーションを付け、デコレーターがデコレートする必要のある MIME タイプを宣言します。
- 内でプロパティーまたは値を設定します
decorate
関数。
例15.25 例: 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); } }
アノテーションを作成します。
- @Decorator アノテーションが付けられたカスタムインターフェースを作成します。
- @Decorator アノテーションのプロセッサーおよびターゲットを宣言します。プロセッサーは、ステップ 1 で作成されます。ターゲットは JAXB Marshaller または Unmarshallerクラスのいずれかになります。
例15.26 アノテーションの例
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 {}
- 手順 2 で作成したアノテーションを関数に追加して、入力または出力のいずれかがマーシャリングされるときにデコレートされるようにします。
結果
JAXB デコレータは、JAX-RSWeb サービス内で作成および適用されています。
15.13.2. アイザーおよび XML プロバイダー
@XmlHeader および @Stylesheet
RESTEasy は、@org.jboss.resteasy.annotations.providers.jaxb.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; } }The
@XmlHeader
XML 出力に XML スタイルシートヘッダーがあることを確認します。
@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; } }
15.13.3. JAXB および JSON プロバイダー
<dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jettison-provider</artifactId> <version>${version.org.jboss.resteasy}</version> <scope>provided</scope> </dependency>
BadgerFish
で、もう 1 つは Jettison にマップされたコンベンション形式です。マップされた規則がデフォルトです。JAXB + JSON プロバイダーと Jettison の統合の詳細については、以下を参照してください。 http://docs.jboss.org/resteasy/docs/2.3.7.Final/userguide/html_single/index.html
15.14. RESTEasy Atom サポート
15.14.1. AtomAPI とプロバイダーについて
org.jboss.resteasy.plugins.providers.atom
パッケージにあります。RESTEasy は JAXB を使用して API のマーシャリングおよびマーシャリング解除に使用します。プロバイダーは JAXB ベースであり、XML を使用した Atom オブジェクトの送信に限定されません。RESTEasy が持つすべての JAXB プロバイダーは、JSON を含む Atom API およびプロバイダーによって再利用できます。API の詳細については、カスタマーサービスポータル から入手できる javadocs を参照してください。
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; } }
15.14.2. Atom プロバイダーでの JAXB の使用
@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 () メソッドは、適切にマーシャリングするために JavaJAXB オブジェクトに送り返すコンテンツオブジェクトを指定するために使用されます。XML とは異なるベース形式 (例: application/atom+json) を使用している場合、添付の Mission オブジェクトは同じ形式でマーシャリングされます。atom ドキュメントを入力として用意している場合は、Content.getJAXBObject(Class clazz) メソッドを使用して Content から正確な JAXB オブジェクトを抽出することもできます。これは、入力アトムドキュメントとコンテンツからの Customer オブジェクトの抽出の例です。
@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); } }
15.15. YAML プロバイダー
SnakeYAML
ライブラリーを使用した YAML のサポートが同梱されています。YAML サポートを有効にするには、アプリケーションのプロジェクト pom ファイルに次の依存関係を挿入する必要があります。
<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>
- text/x-yaml
- text/yaml
- application/x-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(); } ... }
15.16. EJB 統合
@Remote
また@Local
JAX-RS アノテーションとのインターフェイス:
@Local @Path("/Library") public interface Library { @GET @Path("/books/{isbn}") public String getBook(@PathParam("isbn") String isbn); } @Stateless public class LibraryBean implements Library { ... }
web.xml
ファイルで、を使用して EJB を RESTEasy に手動で登録する必要があります。 resteasy.jndi.resources <context-param>
<web-app> <display-name>Archetype Created Web Application</display-name> <context-param> <param-name>resteasy.jndi.resources</param-name> <param-value>LibraryBean/local</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>
15.17. Jackson による JSON サポート
<repository> <id>jboss</id> <url>>http://repository.jboss.org/nexus/content/groups/public/</url> </repository> ... <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jackson-provider</artifactId> <version>${version.org.jboss.resteasy}</version> <scope>provided</scope> </dependency>Jackson プロジェクトを介した JSON サポートの詳細については、を参照してください。 http://docs.jboss.org/resteasy/docs/2.3.7.Final/userguide/html_single/index.html
15.18. RESTEasy/Spring 統合
15.18.1. RESTEasy/Spring 統合
前提条件
- アプリケーションに既存の JAX-WS サービスおよびクライアント設定を指定する必要があります。
手順15.9 RESTEasy/Spring 統合機能を有効にする
- RESTEasy は Spring 3.0.x と統合します。Maven ユーザーは resteasy-spring アーティファクトを使用する必要があります。または、jar を JBoss EAP 6 のモジュールとして利用できます。RESTEasy には、Bean が BeanFactory によって作成されたときに JAX-RS アノテーションを処理する RESTEasy 固有の BeanPostProcessor を登録する独自の Spring ContextLoaderListener が付属しています。これは、RESTEasy が Bean クラスの @Provider および JAX-RS リソースアノテーションを自動的にスキャンして登録することを意味します。それらを JAX-RS リソースとして。
例15.27 web.xml を編集します
以下を 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> <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 属性を使用するためです。
第16章 JAX-WS Web Services
16.1. JAX-WSWeb サービスについて
WS-Notification
、WS-Addressing
、WS-Policy
、WS-Security
、とWS-Trust
。これらは、メッセージアーキテクチャーとメッセージ形式を定義する Simple Object Access Protocol (SOAP) と呼ばれる特殊な XML 言語を使用して通信します。
WebService
とWebMethod
インターフェイス。
サービス
サブシステムを介して提供されます。
実例
JBoss EAP クイックスタートには、完全に機能する JAX-WSWeb サービスアプリケーションがいくつか含まれています。これらの例は次のとおりです。
- wsat-simple
- wsba-coordinator-completion-simple
- wsba-participant-completion-simple
16.2. Web サービスサブシステムを設定します
JBoss EAP 6
にデプロイされた Web サービスの動作を制御する Web サービスサブシステムでは、多くの設定オプションを使用できます。管理 CLI スクリプトの各要素を変更するコマンド (EAP_HOME/bin/jboss-cli.sh
または EAP_HOME/bin/jboss-cli.bat
) が提供されています。スタンドアロンサーバーのコマンドの /profile= default
部分を削除するか、default
を設定するプロファイルの名前に置き換えます。
公開されたエンドポイントアドレス
エンドポイントで公開された WSDL コントラクトの <soap:address>
要素を書き換えることができます。この機能を使用して、各エンドポイントのクライアントにアドバタイズされるサーバーアドレスを制御できます。次の各オプション要素は、要件に合わせて変更できます。アクティブな WS 展開がある場合、これらの要素のいずれかを変更するには、サーバーをリロードする必要があります。
表16.1 公開されたエンドポイントアドレスの設定要素
要素 | Description | CLI コマンド |
---|---|---|
modify-wsdl-address |
常に WSDL アドレスを変更するかどうか。true の場合、
<soap:address> の内容は常に上書きされます。false の場合、<soap:address> のコンテンツは、有効な URL でない場合にのみ上書きされます。使用される値は、以下で説明する wsdl-host 、wsdl-port 、および wsdl-secure-port になります。
|
/profile=default/subsystem=webservices/:write-attribute(name=modify-wsdl-address,value=true)
|
wsdl-host | <soap:address> の書き換えに使用するホスト名/IP アドレス。wsdl-host が文字列 jbossws.undefined.host に設定されている場合、<soap:address> を書き換えるときにリクエスターのホストが使用されます。
| /profile=default/subsystem=webservices/:write-attribute(name=wsdl-host,value=10.1.1.1) |
wsdl-port | SOAP アドレスの書き換えに使用される HTTP ポートを明示的に定義する整数。未定義の場合、HTTP ポートは、インストールされている HTTP コネクターのリストを照会することによって識別されます。 | /profile=default/subsystem=webservices/:write-attribute(name=wsdl-port,value=8080)
|
wsdl-secure-port | SOAP アドレスの書き換えに使用される HTTPS ポートを明示的に定義する整数。未定義の場合、HTTPS ポートは、インストールされている HTTPS コネクターのリストを照会することによって識別されます。 | /profile=default/subsystem=webservices/:write-attribute(name=wsdl-secure-port,value=8443)
|
事前定義されたエンドポイント設定
エンドポイントの実装で参照できるエンドポイント設定を定義できます。これを使用する 1 つの方法は、アノテーションが付いた特定のエンドポイント設定でマークされた WS エンドポイントに特定のハンドラーを追加することです。@org.jboss.ws.api.annotation.EndpointConfig
。
Standard-Endpoint-Config
。カスタム設定の例、Recording-Endpoint-Config
、も含まれています。これは、レコーディングハンドラーの例を提供します。TheStandard-Endpoint-Config
他の設定に関連付けられていないエンドポイントに自動的に使用されます。
Standard-Endpoint-Config
管理 CLI を使用して、次のコマンドを使用します。
/profile=default/subsystem=webservices/endpoint-config=Standard-Endpoint-Config/:read-resource(recursive=true,proxies=false,include-runtime=false,include-defaults=true)
エンドポイント設定
管理 API で endpoint-config
と呼ばれるエンドポイント設定には、特定のエンドポイントに適用される pre-handler-chain
、post-handler-chain
、およびいくつかのプロパティーが含まれます。次のコマンドは、エンドポイント設定を読み取り、追加します。
例16.1 エンドポイント設定を読み取る
/profile=default/subsystem=webservices/endpoint-config=Recording-Endpoint-Config:read-resource
例16.2 エンドポイント設定を追加する
/profile=default/subsystem=webservices/endpoint-config=My-Endpoint-Config:add
ハンドラーチェーン
各エンドポイント設定は、PRE
および POST
ハンドラーチェーンに関連付けることができます。各ハンドラーチェーンには、JAXWS 準拠のハンドラーが含まれる場合があります。アウトバウンドメッセージの場合、PRE ハンドラーチェーンハンドラーは、@HandlerChain
アノテーションなどの標準の JAX-WS を使用してエンドポイントにアタッチされたハンドラーの前に実行されます。POST ハンドラーチェーンハンドラーは、通常のエンドポイントハンドラーの後に実行されます。受信メッセージには、逆が適用されます。JAX-WS は XML ベースの Web サービスの標準 API で、で http://jcp.org/en/jsr/detail?id=224 説明されています。
protocol-bindings
属性を含めることもできます。
例16.3 ハンドラーチェーンを読む
/profile=default/subsystem=webservices/endpoint-config=Recording-Endpoint-Config/pre-handler-chain=recording-handlers:read-resource
例16.4 ハンドラーチェーンの追加
/profile=default/subsystem=webservices/endpoint-config=My-Endpoint-Config/post-handler-chain=my-handlers:add(protocol-bindings="##SOAP11_HTTP")
ハンドラー
JAXWS ハンドラーは、ハンドラーチェーン内の子要素 ハンドラー
です。ハンドラーは、ハンドラークラスの完全修飾クラス名である クラス
属性を取ります。エンドポイントがデプロイされると、参照デプロイメントごとにそのクラスのインスタンスが作成されます。モジュールのデプロイメントクラ出力ダーまたはクラ出力ダーのいずれかorg.jboss.as.webservices.server.integration
ハンドラークラスをロードできる必要があります。
例16.5 ハンドラーを読む
/profile=default/subsystem=webservices/endpoint-config=Recording-Endpoint-Config/pre-handler-chain=recording-handlers/handler=RecordingHandler:read-resource
例16.6 ハンドラーの追加
/profile=default/subsystem=webservices/endpoint-config=My-Endpoint-Config/post-handler-chain=my-handlers/handler=foo-handler:add(class="org.jboss.ws.common.invocation.RecordingServerHandler")
Web サービスランタイム情報
エンドポイント自体にクエリーを実行することで、Web コンテキストや WSDLURL などの Web サービスに関するランタイム情報を表示できます。*
文字を使用して、すべてのエンドポイントを一度に照会できます。次の例は、管理対象ドメイン内のサーバーとスタンドアロンサーバーの両方に対するコマンドを示しています。
例16.7 管理対象ドメイン内のサーバー上のすべての Web サービスエンドポイントに関するランタイム情報を表示する
マスター
でホストされ、管理対象ドメインで実行されている server-one
という名前のサーバー上のすべてのエンドポイントに関する情報を表示します。
/host=master/server=server-one/deployment="*"/subsystem=webservices/endpoint="*":read-resource
例16.8 スタンドアロンサーバー上のすべての Web サービスエンドポイントに関するランタイム情報を表示する
/deployment="*"/subsystem=webservices/endpoint="*":read-resource
例16.9 エンドポイント情報の例
{ "outcome" => "success", "result" => [{ "address" => [ ("deployment" => "jaxws-samples-handlerchain.war"), ("subsystem" => "webservices"), ("endpoint" => "jaxws-samples-handlerchain:TestService") ], "outcome" => "success", "result" => { "class" => "org.jboss.test.ws.jaxws.samples.handlerchain.EndpointImpl", "context" => "jaxws-samples-handlerchain", "name" => "TestService", "type" => "JAXWS_JSE", "wsdl-url" => "http://localhost:8080/jaxws-samples-handlerchain?wsdl" } }] }
16.3. アプリケーションごとに HTTP タイムアウトを設定する
- アプリケーション - アプリケーションの
web.xml
設定ファイルで定義されています。 - サーバー
-default-session-timeout
属性を介して指定されます。 - デフォルト - 30 分です。
手順16.1 アプリケーションごとに HTTP タイムアウトを設定する
- アプリケーションの
WEB-INF/web.xml
ファイルを編集します。 - 次の設定 XML をファイルに追加し、
30
を目的のタイムアウト (分単位) に変更します。<session-config> <session-timeout>30</session-timeout> </session-config>
- WAR ファイルを変更した場合は、アプリケーションを再デプロイします。WAR ファイルを展開した場合、JBoss EAP はアプリケーションを自動的にアンデプロイして再デプロイするため、これ以上のアクションは必要ありません。
16.4. JAX-WS Web サービスエンドポイント
16.4.1. JAX-WS Web サービスエンドポイント
- WSDL 記述子は手動で記述できます。
- WSDL 記述子を自動的に作成する JAX-WS アノテーションを使用できます。これは、WSDL 記述子を作成するための最も一般的な方法です。
開発要件
Web サービスは、JAX-WS API および JSR 181: Web Services Metadata for the Java Platform 仕様の要件を満たす必要があります。有効な実装は、以下の要件を満たしている必要があります。
- それは含まれています
javax.jws.WebService
注釈。 - すべてのメソッドパラメーターとリターンタイプは、JAXB2.0 仕様の JSR-222 と互換性があります。詳細は、http://www.jcp.org/en/jsr/summary?id=222 を参照してください。
例16.10 例: POJO エンドポイント
@WebService @SOAPBinding(style = SOAPBinding.Style.RPC) public class JSEBean01 { @WebMethod public String echo(String input) { ... } }
例16.11 例: Web サービスエンドポイント
<web-app ...> <servlet> <servlet-name>TestService</servlet-name> <servlet-class>org.jboss.test.ws.jaxws.samples.jsr181pojo.JSEBean01</servlet-class> </servlet> <servlet-mapping> <servlet-name>TestService</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
例16.12 EJB でのエンドポイントの公開
@Stateless @Remote(EJB3RemoteInterface.class) @RemoteBinding(jndiBinding = "/ejb3/EJB3EndpointInterface") @WebService @SOAPBinding(style = SOAPBinding.Style.RPC) public class EJB3Bean01 implements EJB3RemoteInterface { @WebMethod public String echo(String input) { ... } }
エンドポイントプロバイダー
JAX-WS サービスは通常 Java サービスエンドポイントインターフェース (SEI) を実装します。これは、WSDL ポートタイプから、直接またはアノテーションを使用してマッピングされる可能性があります。この SEI は、Java オブジェクトとその XML 表現の詳細を隠す高度な抽象化を提供します。ただし、サービスは XML メッセージレベルで動作する必要があることがあります。エンドポイントProvider
インターフェイスは、この機能を実装する Web サービスに提供します。
エンドポイントの使用およびアクセス
Web サービスをデプロイしたら、WSDL を消費してアプリケーションの基盤となるコンポーネントのスタブを作成できます。その後、アプリケーションはエンドポイントにアクセスしてその作業を実行できます。
実例
JBoss EAP クイックスタートには、完全に機能する JAX-WSWeb サービスアプリケーションがいくつか含まれています。これらの例は次のとおりです。
- wsat-simple
- wsba-coordinator-completion-simple
- wsba-participant-completion-simple
16.4.2. JAX-WSWeb サービスエンドポイントの作成とデプロイ
はじめに
このトピックでは、サーバー側コンポーネントである単純な JAX-WS サービスエンドポイントの開発について説明します。これは、JAX-WS クライアントからの要求に応答し、それ自体の WSDL 定義を公開します。JAX-WS サービスエンドポイントの詳細については、以下を参照してください。「JAX-WS Common API Reference」JBoss EAP 6 とともに配布される Javadoc 形式の API ドキュメントバンドル。
開発要件
Web サービスは、JAXWS API と Web Services メタデータ仕様の要件に http://www.jcp.org/en/jsr/summary?id=181 対応します。有効な実装は、以下の要件を満たしている必要があります。
- それは含まれています
javax.jws.WebService
注釈。 - すべてのメソッドパラメーターとリターンタイプは、JAXB2.0 仕様の JSR-222 と互換性があります。詳細は、http://www.jcp.org/en/jsr/summary?id=222 を参照してください。
例16.13 サービス実装の例
package org.jboss.test.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) { return new DiscountResponse(request.getCustomer(), 10.00); } }
例16.14 XML ペイロードの例
DiscountRequest
によって使用されるクラスProfileMgmtBean
前の例の Bean。アノテーションは詳細度のために含まれています。通常、これは JAXB デフォルトは妥当な設定であり、指定する必要はありません。
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 エンドポイントが自動的に作成されます。
例16.15 Web サービスデプロイメントの JAR 構造の例
[user@host ~]$ 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
16.5. JAX-WS Web サービスクライアント
16.5.1. JAX-WS Web サービスの消費とアクセス
- クライアントアーティファクトの作成
- サービススタブの構成
クライアントアーティファクトの作成
クライアントアーティファクトを作成する前に、WSDL コントラクトを作成する必要があります。以下の WSDL コントラクトは、本トピックの残りの部分に記載の例に使用します。
ProfileMgmtService.wsdl
ファイルにこの WSDL コントラクトがあることを前提としています。
例16.16 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'> <soap:address location='SERVER:PORT/jaxws-samples-retail/ProfileMgmtBean'/> </port> </service> </definitions>
EAP_HOME/bin/
ディレクトリーにあります。
例16.17 wsconsume.sh コマンドの構文
[user@host 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 JAXB 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 specification 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/
ディレクトリーに生成されます。
表16.2 wsconsume.sh で作成されるアーティファクトの説明
ファイル | 説明 |
---|---|
ProfileMgmt.java
|
サービスエンドポイントインターフェース。
|
Customer.java
|
カスタムデータタイプ。
|
Discount*.java
|
カスタムデータタイプ。
|
ObjectFactory.java
|
JAXB XML レジストリー。
|
package-info.java
|
JAXB パッケージのアノテーション。
|
ProfileMgmtService.java
|
サービスファクトリー。
|
wsconsume.sh
コマンドは、すべてのカスタムデータタイプ (JAXB アノテーションが付けられたクラス)、サービスエンドポイントインターフェース、およびサービスファクトリークラスを生成します。これらのアーティファクトは、Web サービスクライアントの実装をビルドするために使用されます。
サービススタブの構成
Web サービスクライアントはサービススタブを使用して、リモート Web サービス呼び出しの詳細を抽象化します。クライアントアプリケーションの場合、WS の呼び出しは他のビジネスコンポーネントの呼び出しと同様になります。この場合、サービスエンドポイントインターフェースはビジネスインターフェースとして機能し、サービスファクトリークラスはサービススタブとしての構築に使用されません。
例16.18 サービススタブの構築とエンドポイントへのアクセス
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
16.5.2. JAX-WS クライアントアプリケーションの開発
サービス
- 概要
- A
Service
WSDL サービスを表す抽象化です。WSDL サービスは、一連の関連ポートです。それぞれには、特定のプロトコルとエンドポイントアドレスに結合したポートタイプが含まれます。通常、サービスの生成は、残りのコンポーネントのスタブが、既存の WSDL コントラクトから生成されると行われます。WSDL コントラクトは、デプロイされたエンドポイントの WSDL URL 経由で利用できます。または、EAP_HOME/bin/
ディレクトリーのwsprovide.sh
コマンドを使用してエンドポイントソースから作成できます。このタイプの使用は、static ユースケースと呼ばれます。この場合、コンポーネントのスタブのいずれかとして作成されたService
クラスのインスタンスを作成します。を使用して、サービスを手動で作成することもできます。Service.create
方法。これは、dynamic ユースケースと呼ばれます。 - 用途
- 静的ユースケース
- JAX-WS クライアントの static ユースケースでは、すでに WSDL コントラクトが存在することを前提としています。これは外部ツールで生成されるか、JAX-WS エンドポイントの作成時に適切な JAX-WS アノテーションを使用して生成される可能性があります。コンポーネントスタブを生成するには、
wsconsume.sh
またwsconsume.bat
EAP_HOME/bin/
に含まれているスクリプト。このスクリプトは、WSDL URL またはファイルをパラメーターとして受け取り、ディレクトリーツリーで構造化された複数のファイルを生成します。を表すソースファイルとクラスファイルService
名前が付けられていますCLASSNAME_Service.java
とCLASSNAME_Service.class
、それぞれ。生成された実装クラスには、引数のないパブリックコンストラクターと、2 つの引数を持つコンストラクターがあります。2 つの引数は、WSDL の場所を表します (java.net.URL
) およびサービス名 (ajavax.xml.namespace.QName
) それぞれ。引数なしのコンストラクターは最もよく使用されます。この場合、WSDL の場所とサービス名は WSDL にあるものです。これらは、から暗黙的に設定されます@WebServiceClient
生成されたクラスを装飾するアノテーション。例16.19 生成されたサービスクラスの例
@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); } ... }
- 動的ユースケース
- 動的の場合、スタブは自動的に生成されません。代わりに、Web サービスクライアントは
Service.create
作成する方法Service
インスタンス。以下のコードはこのプロセスを示しています。例16.20 手動でサービスを作成する
URL wsdlLocation = new URL("http://example.org/my.wsdl"); QName serviceName = new QName("http://example.org/sample", "MyService"); Service service = Service.create(wsdlLocation, serviceName);
- ハンドラー解決
- JAX-WS は、handlers と呼ばれるメッセージ処理モジュールに柔軟なプラグインフレームワークを提供します。これらのハンドラーは JAX-WS ランタイムシステムの機能を拡張します。A
Service
インスタンスはへのアクセスを提供しますHandlerResolver
のペアを介してgetHandlerResolver
とsetHandlerResolver
サービスごと、ポートごと、またはプロトコルごとのバインディングに基づいて一連のハンドラーを設定できるメソッド。いつService
インスタンスはプロキシーまたはDispatch
たとえば、現在サービスに登録されているハンドラーリゾルバーは、必要なハンドラーチェーンを作成します。に設定されたハンドラーリゾルバーへのその後の変更Service
インスタンスは、以前に作成されたプロキシーのハンドラーに影響を与えません。Dispatch
インスタンス。 - エグゼキューター (Executor)
Service
インスタンスは、java.util.concurrent.Executor
。TheExecutor
アプリケーションによって要求された非同期コールバックを呼び出します。ThesetExecutor
とgetExecutor
の方法Service
変更および取得できますExecutor
サービス用に設定されています。
動的プロキシー
動的プロキシー は、次のいずれかを使用するクライアントプロキシーのインスタンスです。getPort
で提供されるメソッドService
。TheportName
サービスが使用する WSDL ポートの名前を指定します。TheserviceEndpointInterface
作成された動的プロキシーインスタンスでサポートされるサービスエンドポイントインターフェイスを指定します。
例16.21 getPort
Methods
public <T> T getPort(QName portName, Class<T> serviceEndpointInterface) public <T> T getPort(Class<T> serviceEndpointInterface)
wsconsume.sh
ツールを使用して生成されます。これは、WSDL を解析し、そこから Java クラスを作成します。
例16.22 サービスのポートを返す
@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
The@WebServiceRef
アノテーションは、Web サービスへの参照を宣言します。これは、で定義される javax.annotation.Resource
アノテーションで示されるリソースパターンに http://www.jcp.org/en/jsr/summary?id=250 従います。
のユースケース @WebServiceRef
- これを使用して、生成されたタイプの参照を定義できます
Service
クラス。この例では、type および value 要素はそれぞれ、生成されたService
クラスタイプを参照します。さらに、リファンレンスタイプがアノテーションが適用されるフィールドまたはメソッド宣言によって推定される場合、type および value 要素にはデフォルト値のObject.class
が設定されることがあります。これは必須ではありません。タイプを推定できない場合、type 要素がデフォルト以外の値を持つ必要があります。 - これは、タイプが SEI のリファンレスを定義するのに使用できます。この場合、リファレンスのタイプが annotated フィールドまたは method 宣言から推測される場合、type 要素はデフォルト値で存在することがあります (ただし、必須ではありません)。ただし、value 要素は常に存在し、生成されたサービスクラスターイプを参照する必要があります。これは、
javax.xml.ws.Service
。ThewsdlLocation
要素が存在する場合は、で指定された WSDL ロケーション情報をオーバーライドします。@WebService
参照された生成されたサービスクラスのアノテーション。例16.23
@WebServiceRef
例:public class EJB3Client implements EJB3Remote { @WebServiceRef public TestEndpointService service4; @WebServiceRef public TestEndpoint port3;
Dispatch
XML Web サービスは、Java EE コンテナーおよびすべてのクライアントにデプロイされる、エンドポイント間の通信に XML メッセージを使用します。XML メッセージは、Simple Object Access Protocol (SOAP) と呼ばれる XML 言語を使用します。JAX-WS API は、エンドポイントとクライアントのメカニズムを提供し、各エンドポイントが SOAP メッセージを送受信できるようにします。マーシャリングは、Java オブジェクトを SOAP XML メッセージに変換するプロセスです。マーシャリング解除とは、SOAP XML メッセージを Java オブジェクトに変換するプロセスのことです。
Dispatch
クラスはこの機能を提供します。Dispatch
は、以下の定数のいずれかによって識別される、2 つの使用モードのいずれかで動作します。
javax.xml.ws.Service.Mode.MESSAGE
- このモードは、クライアントアプリケーションがプロトコル固有のメッセージ構造を直接操作するように指示します。SOAP プロトコルバインディングを使用すると、クライアントアプリケーションは SOAP メッセージで直接機能します。javax.xml.ws.Service.Mode.PAYLOAD
- このモードでは、クライアントはペイロード自体を操作します。たとえば、SOAP プロトコルバインディングと使用すると、クライアントアプリケーションは SOAP メッセージ全体ではなく SOAP ボディーのコンテンツで動作します。
Dispatch
は低レベルの API で、クライアントはメッセージまたはペイロードを XML として構成する必要があります。これは、個別のプロトコルの標準と、メッセージまたはペイロード構造の詳細な知識とメッセージに忠実に従った状態を意味します。Dispatch
は、メッセージの入出力または、任意のタイプのメッセージペイロードに対応した汎用クラスです。
例16.24 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)));
非同期呼び出し
TheBindingProvider
インターフェイスは、クライアントが使用できるプロトコルバインディングを提供するコンポーネントを表します。これはプロキシーによって実装され、Dispatch
インターフェイス。
BindingProvider
インスタンスは非同期操作機能を提供する場合があります。非同期操作の呼び出しは、BindingProvider
呼び出し時のインスタンス。操作が完了しても、応答コンテキストは更新されません。代わりに、別の応答コンテキストが使用可能になりますResponse
インターフェイス。
例16.25 非同期呼び出しの例
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
メソッドは、ビジネスメソッドの実行前に、制御のスレッドを呼び出しアプリケーションに戻します。
例16.26 例@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
そして 2 番目はjavax.xml.ws.client.receiveTimeout
。それぞれはミリ秒単位で示され、正しい構文を以下に示します。
例16.27 JAX-WS タイムアウト設定
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"); }
16.6. JAX-WS 開発リファレンス
16.6.1. Web サービスアドレス指定を有効にする (WS-Addressing)
前提条件
- アプリケーションに既存の JAX-WS サービスおよびクライアント設定を指定する必要があります。
手順16.2 クライアントコードに注釈を付けて更新する
サービスエンドポイントに注釈を付ける
追加します@Addressing
アプリケーションのエンドポイントコードへの注釈。例16.28
@Addressing
Annotationこの例は、通常の JAX-WS エンドポイントを示しています。@Addressing
注釈が追加されました。package org.jboss.test.ws.jaxws.samples.wsa; 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.test.ws.jaxws.samples.wsa.ServiceIface" ) @Addressing(enabled=true, required=true) public class ServiceImpl implements ServiceIface { public String sayHello() { return "Hello World!"; } }
クライアントコードを更新する
アプリケーションのクライアントコードを更新して、WS-Addressing を設定します。例16.29 WS-Addressing のクライアント設定
この例は、WS-Addressing を設定するために更新された通常の JAX-WS クライアントを示しています。package org.jboss.test.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 AddressingTestCase { private final String serviceURL = "http://localhost:8080/jaxws-samples-wsa/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); ServiceIface proxy = (ServiceIface)service.getPort(ServiceIface.class, new AddressingFeature()); // invoke method proxy.sayHello(); } }
結果
クライアントとエンドポイントは、WS-Addressing を使用して通信しています。
16.6.2. JAX-WS Common API Reference
ハンドラーフレームワーク
ハンドラーフレームワークは、クライアントおよびエンドポイント (サーバーコンポーネント) の JAX-WS プロトコルバインディングによって実装されます。binding providers として知られるプロキシーおよび Dispatch
インスタンスは、それぞれプロトコルバインディングを使用して抽象機能を特定のプロトコルにバインドします。
メッセージハンドラーの種類
- 論理ハンドラー
- Logical handlers は、メッセージコンテキストプロパティーおよびメッセージペイロードでのみ動作します。論理ハンドラーはプロトコルに依存しないため、メッセージのプロトコル固有の部分には影響がありません。論理ハンドラーはインターフェイスを実装します
javax.xml.ws.handler.LogicalHandler
。 - プロトコルハンドラー
- Protocol handlers は、メッセージコンテキストプロパティーおよびプロトコル固有のメッセージで動作します。プロトコルハンドラーは特定のプロトコルに固有のもので、メッセージのプロトコル固有の側面にアクセスし、変更する可能性があります。プロトコルハンドラーは、から派生した任意のインターフェイスを実装します
javax.xml.ws.handler.Handler except javax.xml.ws.handler.LogicalHandler
。 - サービスエンドポイントハンドラー
- サービスエンドポイントでは、ハンドラーは
@HandlerChain
注釈。ハンドラーチェーンファイルの場所は、絶対的なものにすることができますjava.net.URL
のexternalForm
または、ソースファイルまたはクラスファイルからの相対パス。例16.30 サービスエンドポイントハンドラーの例
@WebService @HandlerChain(file = "jaxws-server-source-handlers.xml") public class SOAPEndpointSourceImpl { ... }
- サービスクライアントハンドラー
- JAX-WS クライアントでは、ハンドラーはサービスエンドポイントの場合と同様に
@HandlerChain
アノテーションを使用するか、JAX-WS API を使用して動的に定義されます。例16.31 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
メソッドが必要です。
メッセージコンテキスト
TheMessageContext
interface は、すべての JAX-WS メッセージコンテキストのスーパーインターフェイスです。これは、追加のメソッドと定数を使用して Map<String,Object>
を拡張し、ハンドラーチェーンのハンドラーが処理関連の状態を共有できるようにするプロパティーセットを管理します。たとえば、ハンドラーは put
メソッドを使用してプロパティーをメッセージコンテキストに挿入します。ハンドラーチェーン内の他の 1 つ以上のハンドラーは、その後、get
方法。
APPLICATION
または HANDLER
としてスコープ指定されます。すべてのプロパティーは、特定のエンドポイントのメッセージ交換パターン (MEP) のインスタンスに対するすべてのハンドラーで利用できます。たとえば、論理ハンドラーがプロパティーをメッセージコンテキストに置いた場合、そのプロパティーは MEP インスタンスの実行中にチェーンの任意のプロトコルハンドラーでも利用できます。
APPLICATION
レベルでスコープ設定されているプロパティーは、クライアントアプリケーションおよびサービスエンドポイント実装でも利用可能になります。Thedefaultscope
プロパティーの場合は HANDLER
です。
- 論理メッセージコンテキスト
- 論理ハンドラーが呼び出されると、タイプのメッセージコンテキストを受け取ります
LogicalMessageContext
。LogicalMessageContext
拡張しますMessageContext
メッセージペイロードを取得および変更するメソッドを使用します。メッセージのプロトコル固有の側面へのアクセスは提供しません。プロトコルバインディングは、論理メッセージコンテキストを介して使用できるメッセージのコンポーネントを定義します。SOAP バインディングにデプロイされた論理ハンドラーは SOAP ボディーのコンテンツにアクセスできますが、SOAP ヘッダーにはアクセスできません。一方、XML/HTTP バインディングは論理ハンドラーがメッセージの XML ペイロード全体にアクセスできることを定義します。 - SOAP メッセージコンテキスト
- SOAP ハンドラーが呼び出されると、
SOAPMessageContext
。SOAPMessageContext
拡張しますMessageContext
SOAP メッセージペイロードを取得および変更するメソッドを使用します。
障害処理
アプリケーションが SOAPFaultException
またはアプリケーション固有のユーザー例外をスローする可能性があります。後者の場合、必要な障害ラッパー Bean がデプロイメントに含まれていない場合は、ランタイム時に生成されます。
例16.32 障害処理の例
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"); }
JAX-WS アノテーション
JAX-WS API 経由で利用可能なアノテーションは JSR-224 で定義されています。これについては、を参照してください http://www.jcp.org/en/jsr/detail?id=224。これらの注釈はパッケージに含まれていますjavax.xml.ws
。
javax.jws
。
第17章 WebSocket
17.1. WebSocket について
Upgrade
ヘッダーを使用して WebSocket 接続を要求します。同じ TCP/IP 接続上ではすべて全二重通信になり、データのオーバヘッドが最小化されます。各メッセージには不必要な HTTP ヘッダーコンテンツが含まれていないため、Websocket 通信で必要な帯域幅は小さくなります。その結果、通信パスのレイテンシーが低くなるため、リアルタイムの応答が必要なアプリケーションに適しています。
17.2. WebSocket アプリケーションを作成する
- Javaクライアントまたは WebSocket が有効になっている HTML クライアント。次の場所で HTML クライアントブラウザーのサポートを確認できます。 http://caniuse.com/websockets
- WebSocket サーバーエンドポイントクラス。
- WebSocket を有効にするように設定された
jboss-web.xml
ファイル。 - WebSocket API で依存関係を宣言するために設定されたプロジェクト依存関係。
- Red Hat JBoss Enterprise Application Platform サーバー設定ファイルの
Web
サブシステムでNIO2
コネクターを有効にします。
手順17.1 WebSocket アプリケーションの作成
JavaScript HTML クライアントを作成します。
以下は WebSocket クライアントの例になります。この例には 3 つの JavaScript 関数が含まれています。lconnect()
: この関数は WebSocket URI を渡す WebSocket 接続を作成します。リソースの場所は、サーバーエンドポイントクラスに定義されたリソースと一致します。この関数は、WebSocket をインターセプトして処理しますonopen
、onmessage
、onerror
、とonclose
。sendMessage()
: この関数はフォームに入力された名前を取得し、メッセージを作成します。 さらに、WebSocket.send() コマンドを使用してメッセージを送信します。disconnect()
: この関数は WebSocket.close () コマンドを発行します。displayMessage()
: この関数は、ページ上の表示メッセージを WebSocket エンドポイントメソッドによって返された値に設定します。displayStatus()
: この関数は、WebSocket 接続ステータスを表示します。
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <title>WebSocket: Say Hello</title> <link rel="stylesheet" type="text/css" href="resources/css/hello.css" /> <script type="text/javascript"> var websocket = null; function connect() { var wsURI = 'ws://' + window.location.host + '/jboss-websocket-hello/websocket/helloName'; websocket = new WebSocket(wsURI); websocket.onopen = function() { displayStatus('Open'); document.getElementById('sayHello').disabled = false; displayMessage('Connection is now open. Type a name and click Say Hello to send a message.'); }; websocket.onmessage = function(event) { // log the event displayMessage('The response was received! ' + event.data, 'success'); }; websocket.onerror = function(event) { // log the event displayMessage('Error! ' + event.data, 'error'); }; websocket.onclose = function() { displayStatus('Closed'); displayMessage('The connection was closed or timed out. Please click the Open Connection button to reconnect.'); document.getElementById('sayHello').disabled = true; }; } function disconnect() { if (websocket !== null) { websocket.close(); websocket = null; } message.setAttribute("class", "message"); message.value = 'WebSocket closed.'; // log the event } function sendMessage() { if (websocket !== null) { var content = document.getElementById('name').value; websocket.send(content); } else { displayMessage('WebSocket connection is not established. Please click the Open Connection button.', 'error'); } } function displayMessage(data, style) { var message = document.getElementById('hellomessage'); message.setAttribute("class", style); message.value = data; } function displayStatus(status) { var currentStatus = document.getElementById('currentstatus'); currentStatus.value = status; } </script> </head> <body> <div> <h1>Welcome to JBoss!</h1> <div>This is a simple example of a WebSocket implementation.</div> <div id="connect-container"> <div> <fieldset> <legend>Connect or disconnect using WebSocket :</legend> <input type="button" id="connect" onclick="connect();" value="Open Connection" /> <input type="button" id="disconnect" onclick="disconnect();" value="Close Connection" /> </fieldset> </div> <div> <fieldset> <legend>Type your name below. then click the `Say Hello` button :</legend> <input id="name" type="text" size="40" style="width: 40%"/> <input type="button" id="sayHello" onclick="sendMessage();" value="Say Hello" disabled="disabled"/> </fieldset> </div> <div>Current WebSocket Connection Status: <output id="currentstatus" class="message">Closed</output></div> <div> <output id="hellomessage" /> </div> </div> </div> </body> </html>
WebSocket サーバーエンドポイントを作成します。
以下の方法のいずれかを使用して WebSocket サーバーエンドポイントを作成できます。以下のコード例では、アノテーション付きエンドポイントが使用され、以下のイベントが処理されます。Programmatic Endpoint
: エンドポイントは Endpoint クラスを拡張します。Annotated Endpoint
: エンドポイントクラスはアノテーションを使用して WebSocket イベントと対話します。これは、プログラム的なエンドポイントよりも簡単にコーディングできます。
- The
@ServerEndpoint
アノテーションは、このクラスを WebSocket サーバーエンドポイントとして識別し、パスを指定します。 - WebSocket 接続が開かれると
@OnOpen
アノテーションがトリガーされます。 - The
@OnMessage
メッセージが WebSocket 接続に送信されると、注釈がトリガーされます。 - WebSocket 接続が閉じられると、
@OnClose
アノテーションがトリガーされます。
package org.jboss.as.quickstarts.websocket_hello; import javax.websocket.CloseReason; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/websocket/helloName") public class HelloName { @OnMessage public String sayHello(String name) { System.out.println("Say hello to '" + name + "'"); return ("Hello" + name); } @OnOpen public void helloOnOpen(Session session) { System.out.println("WebSocket opened: " + session.getId()); } @OnClose public void helloOnClose(CloseReason reason) { System.out.println("Closing a WebSocket due to " + reason.getReasonPhrase()); } }
jboss-web.xml ファイルを設定します。
を作成する必要があります<enable-websockets>
アプリケーションWEB-INF/jboss-web.xml
の要素を作成し、true
に設定します。<?xml version="1.0" encoding="UTF-8"?> <!--Enable WebSockets --> <jboss-web> <enable-websockets>true</enable-websockets> </jboss-web>
プロジェクト POM ファイルで WebSocket API の依存関係を宣言します。
Maven を使用する場合は、プロジェクトpom.xml
ファイルに以下の依存関係を追加します。<dependency> <groupId>org.jboss.spec.javax.websocket</groupId> <artifactId>jboss-websocket-api_1.0_spec</artifactId> <version>1.0.0.Final</version> <scope>provided</scope> </dependency>
JBoss EAP サーバーを設定します。
http
を設定します<connector>
サーバー設定ファイルのWeb
サブシステムで、NIO2
プロトコルを使用します。- JBoss EAP サーバーを起動します。
- ご使用のオペレーティングシステム向けのコマンドを使用して、管理 CLI を起動します。Linux の場合
EAP_HOME/bin/jboss-cli.sh --connect
Windows の場合:EAP_HOME\bin\jboss-cli.bat --connect
- JBoss EAP サーバー設定ファイルの
Web
サブシステムでノンブロッキングJavaNIO2
コネクタープロトコルを有効にするには、次のコマンドを入力します。/subsystem=web/connector=http/:write-attribute(name=protocol,value=org.apache.coyote.http11.Http11NioProtocol)
どちらのコマンドでも、次の結果が表示されます。{ "outcome" => "success", "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } }
- 設定を再ロードするようにサーバーに通知します。
reload
以下の結果が表示されるはずです。{ "outcome" => "success", "result" => undefined }
- JBoss EAP サーバー設定ファイルへの変更を確認します。これで、
Web
サブシステムにhttp
用の次の XML が含まれるはずです。<connector>
。<subsystem xmlns="urn:jboss:domain:web:2.1" default-virtual-server="default-host" native="false"> <connector name="http" protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="http" socket-binding="http"/> <virtual-server name="default-host" enable-welcome-root="true"> <alias name="localhost"/> <alias name="example.com"/> </virtual-server> </subsystem>
第18章 アプリケーションセキュリティー
18.1. 基本的な概念
18.1.1. 暗号化について
18.1.2. セキュリティードメイン
18.1.3. SSL 暗号化について
18.1.4. 宣言型セキュリティーについて
18.2. アプリケーションにおけるロールベースのセキュリティー
18.2.1. アプリケーションセキュリティーについて
18.2.2. 認証
18.2.3. 認可について
18.2.4. セキュリティー監査
18.2.5. セキュリティーマッピング
18.2.6. Java 認証および承認サービス (JAAS)
18.2.7. Java 認証および承認サービス (JAAS) について
ドメイン、サーバーグループ、およびサーバー固有の設定
サーバーグループ (管理対象ドメイン内) およびサーバー (スタンドアロンサーバー内) には、セキュリティードメインの設定が含まれます。セキュリティードメインには、認証、承認、マッピング、および監査モジュールの組み合わせに関する情報と、設定の詳細が含まれています。アプリケーションは、jboss-web.xml
で、必要なセキュリティードメインを名前で指定します。
アプリケーション固有の設定
アプリケーション固有の設定は、次の 4 つのファイルの 1 つ以上で行われます。
表18.1 アプリケーション固有の設定ファイル
ファイル | Description |
---|---|
ejb-jar.xml |
アーカイブの
META-INF ディレクトリーにある EnterpriseJavaBean (EJB) アプリケーションのデプロイメント記述子。ejb-jar.xml を使用して、アプリケーションレベルでロールを指定し、それらをプリンシパルにマップします。特定のメソッドとクラスを特定のロールに制限することもできます。また、セキュリティーに関係のない他の EJB 固有の設定にも使用されます。
|
web.xml |
Java Enterprise Edition (EE)Web アプリケーションのデプロイメント記述子。
web.xml を使用して、許可される HTTP リクエストのタイプを制限するなど、アプリケーションのリソースとトランスポートの制約を宣言します。このファイルで単純な Web ベースの認証を設定することもできます。また、セキュリティーに関係のない他のアプリケーション固有の設定にも使用されます。アプリケーションが認証と承認に使用するセキュリティードメインは、jboss-web.xml で定義されています。
|
jboss-ejb3.xml | ejb-jar.xml 記述子に対する JBoss 固有の拡張機能が含まれています。
|
jboss-web.xml | web.xml 記述子に対する JBoss 固有の拡張機能が含まれています。
|
ejb-jar.xml
および web.xml
は、Java Enterprise Edition (Java EE) 仕様で定義されています。jboss-ejb3.xml
は ejb-jar.xml
の JBoss 固有の拡張機能を提供し、jboss-web.xml
は web.xml
の JBoss 固有の拡張機能を提供します。
18.2.8. アプリケーションでのセキュリティードメインの使用
概要
アプリケーションでセキュリティードメインを使用するには、最初にサーバーの設定でセキュリティードメインを定義してから、アプリケーションの展開記述子でアプリケーションに対してセキュリティードメインを有効にする必要があります。次に、それを使用する EJB に必要なアノテーションを追加する必要があります。このトピックでは、アプリケーションでセキュリティードメインを使用するために必要な手順について説明します。
手順18.1 セキュリティードメインを使用するようアプリケーションを設定
セキュリティードメインの定義
サーバーの設定ファイルでセキュリティードメインを定義した後、アプリケーションの記述子ファイルでアプリケーションに対して有効にする必要があります。サーバーの設定ファイルへセキュリティードメインを設定
セキュリティードメインは、サーバーの設定ファイルのセキュリティー
サブシステムで設定されます。JBoss EAP 6 インスタンスが管理対象ドメインで実行されている場合、これはdomain/configuration/domain.xml
ファイルです。JBoss EAP 6 インスタンスがスタンドアロンサーバーとして実行されている場合、これはstandalone/configuration/standalone.xml
ファイルです。他
のjboss-web-policy
およびjboss-ejb-policy
セキュリティードメインは、JBoss EAP 6 でデフォルトで提供されます。次の XML の例は、サーバーの設定ファイルのセキュリティー
サブシステムからコピーされたものです。Thecache-type
セキュリティードメインの属性は、認証チェックを高速化するためのキャッシュを指定します。許可される値は、デフォルト
でキャッシュとして単純なマップを使用するか、infinispan
で Infinispan キャッシュを使用します。<subsystem xmlns="urn:jboss:domain:security:1.2"> <security-domains> <security-domain name="other" cache-type="default"> <authentication> <login-module code="Remoting" flag="optional"> <module-option name="password-stacking" value="useFirstPass"/> </login-module> <login-module code="RealmDirect" flag="required"> <module-option name="password-stacking" value="useFirstPass"/> </login-module> </authentication> </security-domain> <security-domain name="jboss-web-policy" cache-type="default"> <authorization> <policy-module code="Delegating" flag="required"/> </authorization> </security-domain> <security-domain name="jboss-ejb-policy" cache-type="default"> <authorization> <policy-module code="Delegating" flag="required"/> </authorization> </security-domain> </security-domains> </subsystem>
管理コンソールまたは CLI を使用して、追加のセキュリティードメインを必要に応じて設定できます。アプリケーションの記述子ファイルでのセキュリティードメインの有効化
セキュリティードメインは、アプリケーションのWEB-INF/jboss-web.xml
ファイルの<jboss-web>
要素の<security-domain>
子要素で指定されます。次の例では、my-domain
という名前のセキュリティードメインを設定します。<jboss-web> <security-domain>my-domain</security-domain> </jboss-web>
これは、WEB-INF/jboss-web.xml
記述子で指定できる多くの設定の 1 つにすぎません。
EJB への必要なアノテーションの追加
@SecurityDomain
および@RolesAllowed
アノテーションを使用して、EJB でセキュリティーを設定します。次の EJB コード例は、ゲスト
ロールのユーザーによる他の
セキュリティードメインへのアクセスを制限します。package example.ejb3; import java.security.Principal; import javax.annotation.Resource; import javax.annotation.security.RolesAllowed; import javax.ejb.SessionContext; import javax.ejb.Stateless; import org.jboss.ejb3.annotation.SecurityDomain; /** * Simple secured EJB using EJB security annotations * Allow access to "other" security domain by users in a "guest" role. */ @Stateless @RolesAllowed({ "guest" }) @SecurityDomain("other") public class SecuredEJB { // Inject the Session Context @Resource private SessionContext ctx; /** * Secured EJB method using security annotations */ public String getSecurityInfo() { // Session context injected using the resource annotation Principal principal = ctx.getCallerPrincipal(); return principal.toString(); } }
その他のコード例は、Red Hat カスタマーポータルより入手できる JBoss EAP 6 Quickstarts バンドルのejb-security
クイックスタートを参照してください。注記EJB のセキュリティードメインは、jboss-ejb3.xml
デプロイメント記述子を使用して設定することもできます。詳細は、「jboss-ejb3.xml デプロイメント記述子の参照」 を参照してください。
手順18.2 EJB3Bean のカスタムプリンシパルにアクセスするように JBoss EAP 6 を設定します
- JAAS に従うように ApplicationRealm を設定します。
<security-realm name="MyDomainRealm"> <authentication> <jaas name="my-security-domain"/> </security-realm>
- カスタムプリンシパルを使用するように JAAS セキュリティードメインを設定します。
<security-domain name="my-security-domain" cache-type="default"> <authentication> <login-module code="UsersRoles" flag="required"> <module-option name="usersProperties" value="file:///${jboss.server.config.dir}/users.properties"/> <module-option name="rolesProperties" value="file:///${jboss.server.config.dir}/roles.properties"/> <module-option name="principalClass" value="org.jboss.example.CustomPrincipalImpl"/> </login-module> </authentication> </security-domain>
- カスタムプリンシパルを JBoss モジュールとしてデプロイします。
- を設定します
org.jboss.as.remoting
モジュール (modules/org/jboss/as/remoteing/main/module.xml
) は、カスタムプリンシパルを含むモジュールに依存します。<resources> <resource-root path="jboss-as-remoting-7.1.2.Final-redhat-1.jar"/> <!-- Insert resources here --> </resources> <dependencies> <module name="org.jboss.staxmapper"/> <module name="org.jboss.as.controller"/> <module name="org.jboss.as.domain-management"/> <module name="org.jboss.as.network"/> <module name="org.jboss.as.protocol"/> <module name="org.jboss.as.server"/> <module name="org.jboss.as.security" optional="true"/> <module name="org.jboss.as.threads"/> <module name="org.jboss.logging"/> <module name="org.jboss.modules"/> <module name="org.jboss.msc"/> <module name="org.jboss.remoting3"/> <module name="org.jboss.sasl"/> <module name="org.jboss.threads"/> <module name="org.picketbox" optional="true"/> <module name="javax.api" /> <module name="org.jboss.example" /> <!--FIXME: dependency on custom principal added here --> </dependencies>
- 使用するクライアントを設定する
org.jboss.ejb.client.naming
、jboss-ejb-client.properties
ファイルは次のようになります。remote.connections=default endpoint.name=client-endpoint remote.connection.default.port=4447 remote.connection.default.host=localhost remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false # The following setting is required when deferring to JAAS remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false remote.connection.default.username=admin remote.connection.default.password=testing
18.2.9. サーブレットでロールベースのセキュリティーを使用する
jboss-web.xml
で指定されたセキュリティードメインによって処理されます。
前提条件
サーブレットでロールベースのセキュリティーを使用する前に、アクセスの認証と承認に使用されるセキュリティードメインを JBoss EAP 6 コンテナーで設定する必要があります。
手順18.3 サーブレットにロールベースのセキュリティーを追加する
サーブレットと URL パターンの間にマッピングを追加します。
web.xml
の<servlet-mapping>
要素を使用して、個々のサーブレットを URL パターンにマップします。次の例では、DisplayOpResult
というサーブレットを URL パターン/DisplayOpResult
にマップします。<servlet-mapping> <servlet-name>DisplayOpResult</servlet-name> <url-pattern>/DisplayOpResult</url-pattern> </servlet-mapping>
URL パターンにセキュリティー制約を追加します。
URL パターンをセキュリティー制約にマップするには、<security-constraint>
を使用します。次の例では、URL パターン/DisplayOpResult
からのアクセスを、ロールeap_admin
のプリンシパルがアクセスするように制限しています。ロールはセキュリティードメインに存在する必要があります。<security-constraint> <display-name>Restrict access to role eap_admin</display-name> <web-resource-collection> <web-resource-name>Restrict access to role eap_admin</web-resource-name> <url-pattern>/DisplayOpResult/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>eap_admin</role-name> </auth-constraint> </security-constraint> <security-role> <role-name>eap_admin</role-name> </security-role> <login-config> <auth-method>BASIC</auth-method> </login-config>
認証方法を指定する必要があります。これは、BASIC、FORM、DIGEST、CLIENT-CERT、SPNEGO のいずれかになります。
この例では、BASIC
認証を使用しています。WAR の
jboss-web.xml
でセキュリティードメインを指定しますサーブレットを設定済みのセキュリティードメインに接続するために、セキュリティードメインを WAR のjboss-web.xml
に追加します。これは、セキュリティー制約に対してプリンシパルを認証および承認する方法を知っています。次の例では、acme_domain
というセキュリティードメインを使用しています。<jboss-web> ... <security-domain>acme_domain</security-domain> ... </jboss-web>
例18.1 ロールベースのセキュリティーが設定された web.xml
の例
<web-app 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" version="3.0"> <display-name>Use Role-Based Security In Servlets</display-name> <welcome-file-list> <welcome-file>/index.jsp</welcome-file> </welcome-file-list> <servlet-mapping> <servlet-name>DisplayOpResult</servlet-name> <url-pattern>/DisplayOpResult</url-pattern> </servlet-mapping> <security-constraint> <display-name>Restrict access to role eap_admin</display-name> <web-resource-collection> <web-resource-name>Restrict access to role eap_admin</web-resource-name> <url-pattern>/DisplayOpResult/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>eap_admin</role-name> </auth-constraint> </security-constraint> <security-role> <role-name>eap_admin</role-name> </security-role> <login-config> <auth-method>BASIC</auth-method> </login-config> </web-app>
18.2.10. アプリケーションでサードパーティーの認証システムを使用する
context.xml
デプロイメント記述子はなくなりました。代わりに、バルブは jboss-web.xml
記述子で直接設定されます。context.xml
は無視されるようになりました。
例18.2 基本認証バルブ
<jboss-web> <valve> <class-name>org.jboss.security.negotiation.NegotiationAuthenticator</class-name> </valve> </jboss-web>
例18.3 ヘッダー属性が設定されたカスタムバルブ
<jboss-web> <valve> <class-name>org.jboss.web.tomcat.security.GenericHeaderAuthenticator</class-name> <param> <param-name>httpHeaderForSSOAuth</param-name> <param-value>sm_ssoid,ct-remote-user,HTTP_OBLIX_UID</param-value> </param> <param> <param-name>sessionCookieForSSOAuth</param-name> <param-value>SMSESSION,CTSESSION,ObSSOCookie</param-value> </param> </valve> </jboss-web>
カスタムオーセンティケーターの作成
独自のオーセンティケーターを作成することは、このドキュメントの範囲外です。ただし、例として次の Java コードが提供されています。
例18.4 GenericHeaderAuthenticator.java
/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.web.tomcat.security; import java.io.IOException; import java.security.Principal; import java.util.StringTokenizer; import javax.management.JMException; import javax.management.ObjectName; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Realm; import org.apache.catalina.Session; import org.apache.catalina.authenticator.Constants; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.deploy.LoginConfig; import org.jboss.logging.Logger; import org.jboss.as.web.security.ExtendedFormAuthenticator; /** * JBAS-2283: Provide custom header based authentication support * * Header Authenticator that deals with userid from the request header Requires * two attributes configured on the Tomcat Service - one for the http header * denoting the authenticated identity and the other is the SESSION cookie * * @author <a href="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a> * @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a> * @version $Revision$ * @since Sep 11, 2006 */ public class GenericHeaderAuthenticator extends ExtendedFormAuthenticator { protected static Logger log = Logger .getLogger(GenericHeaderAuthenticator.class); protected boolean trace = log.isTraceEnabled(); // JBAS-4804: GenericHeaderAuthenticator injection of ssoid and // sessioncookie name. private String httpHeaderForSSOAuth = null; private String sessionCookieForSSOAuth = null; /** * <p> * Obtain the value of the <code>httpHeaderForSSOAuth</code> attribute. This * attribute is used to indicate the request header ids that have to be * checked in order to retrieve the SSO identity set by a third party * security system. * </p> * * @return a <code>String</code> containing the value of the * <code>httpHeaderForSSOAuth</code> attribute. */ public String getHttpHeaderForSSOAuth() { return httpHeaderForSSOAuth; } /** * <p> * Set the value of the <code>httpHeaderForSSOAuth</code> attribute. This * attribute is used to indicate the request header ids that have to be * checked in order to retrieve the SSO identity set by a third party * security system. * </p> * * @param httpHeaderForSSOAuth * a <code>String</code> containing the value of the * <code>httpHeaderForSSOAuth</code> attribute. */ public void setHttpHeaderForSSOAuth(String httpHeaderForSSOAuth) { this.httpHeaderForSSOAuth = httpHeaderForSSOAuth; } /** * <p> * Obtain the value of the <code>sessionCookieForSSOAuth</code> attribute. * This attribute is used to indicate the names of the SSO cookies that may * be present in the request object. * </p> * * @return a <code>String</code> containing the names (separated by a * <code>','</code>) of the SSO cookies that may have been set by a * third party security system in the request. */ public String getSessionCookieForSSOAuth() { return sessionCookieForSSOAuth; } /** * <p> * Set the value of the <code>sessionCookieForSSOAuth</code> attribute. This * attribute is used to indicate the names of the SSO cookies that may be * present in the request object. * </p> * * @param sessionCookieForSSOAuth * a <code>String</code> containing the names (separated by a * <code>','</code>) of the SSO cookies that may have been set by * a third party security system in the request. */ public void setSessionCookieForSSOAuth(String sessionCookieForSSOAuth) { this.sessionCookieForSSOAuth = sessionCookieForSSOAuth; } /** * <p> * Creates an instance of <code>GenericHeaderAuthenticator</code>. * </p> */ public GenericHeaderAuthenticator() { super(); } public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { log.trace("Authenticating user"); Principal principal = request.getUserPrincipal(); if (principal != null) { if (trace) log.trace("Already authenticated '" + principal.getName() + "'"); return true; } Realm realm = context.getRealm(); Session session = request.getSessionInternal(true); String username = getUserId(request); String password = getSessionCookie(request); // Check if there is sso id as well as sessionkey if (username == null || password == null) { log.trace("Username is null or password(sessionkey) is null:fallback to form auth"); return super.authenticate(request, response, config); } principal = realm.authenticate(username, password); if (principal == null) { forwardToErrorPage(request, response, config); return false; } session.setNote(Constants.SESS_USERNAME_NOTE, username); session.setNote(Constants.SESS_PASSWORD_NOTE, password); request.setUserPrincipal(principal); register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password); return true; } /** * Get the username from the request header * * @param request * @return */ protected String getUserId(Request request) { String ssoid = null; // We can have a comma-separated ids String ids = ""; try { ids = this.getIdentityHeaderId(); } catch (JMException e) { if (trace) log.trace("getUserId exception", e); } if (ids == null || ids.length() == 0) throw new IllegalStateException( "Http headers configuration in tomcat service missing"); StringTokenizer st = new StringTokenizer(ids, ","); while (st.hasMoreTokens()) { ssoid = request.getHeader(st.nextToken()); if (ssoid != null) break; } if (trace) log.trace("SSOID-" + ssoid); return ssoid; } /** * Obtain the session cookie from the request * * @param request * @return */ protected String getSessionCookie(Request request) { Cookie[] cookies = request.getCookies(); log.trace("Cookies:" + cookies); int numCookies = cookies != null ? cookies.length : 0; // We can have comma-separated ids String ids = ""; try { ids = this.getSessionCookieId(); log.trace("Session Cookie Ids=" + ids); } catch (JMException e) { if (trace) log.trace("checkSessionCookie exception", e); } if (ids == null || ids.length() == 0) throw new IllegalStateException( "Session cookies configuration in tomcat service missing"); StringTokenizer st = new StringTokenizer(ids, ","); while (st.hasMoreTokens()) { String cookieToken = st.nextToken(); String val = getCookieValue(cookies, numCookies, cookieToken); if (val != null) return val; } if (trace) log.trace("Session Cookie not found"); return null; } /** * Get the configured header identity id in the tomcat service * * @return * @throws JMException */ protected String getIdentityHeaderId() throws JMException { if (this.httpHeaderForSSOAuth != null) return this.httpHeaderForSSOAuth; return (String) mserver.getAttribute(new ObjectName( "jboss.web:service=WebServer"), "HttpHeaderForSSOAuth"); } /** * Get the configured session cookie id in the tomcat service * * @return * @throws JMException */ protected String getSessionCookieId() throws JMException { if (this.sessionCookieForSSOAuth != null) return this.sessionCookieForSSOAuth; return (String) mserver.getAttribute(new ObjectName( "jboss.web:service=WebServer"), "SessionCookieForSSOAuth"); } /** * Get the value of a cookie if the name matches the token * * @param cookies * array of cookies * @param numCookies * number of cookies in the array * @param token * Key * @return value of cookie */ protected String getCookieValue(Cookie[] cookies, int numCookies, String token) { for (int i = 0; i < numCookies; i++) { Cookie cookie = cookies[i]; log.trace("Matching cookieToken:" + token + " with cookie name=" + cookie.getName()); if (token.equals(cookie.getName())) { if (trace) log.trace("Cookie-" + token + " value=" + cookie.getValue()); return cookie.getValue(); } } return null; } }
18.3. ログインモジュール
18.3.1. モジュールの使用
18.3.1.1. パスワードスタッキング
使用するパスワードスタッキング
属性 FirstPass
。パスワードスタッキングに設定した以前のモジュールがユーザーを認証した場合、他のすべてのスタッキングモジュールがユーザーによって認証されたこととなり、承認の手順でロールの提供のみを行います。
パスワードスタッキング
オプションが useFirstPass
に設定されている場合、このモジュールは最初にプロパティー名の下で共有ユーザー名とパスワードを検索しますjavax.security.auth.login.nameとjavax.security.auth.login.passwordログインモジュールの共有状態マップでそれぞれ。
例18.5 パスワードスタッキングサンプル
/subsystem=security/security-domain=pwdStack/authentication=classic/login-module=Ldap:add( \ code=Ldap, \ flag=required, \ module-options=[ \ ("password-stacking"=>"useFirstPass"), \ ... Ldap login module configuration ]) /subsystem=security/security-domain=pwdStack/authentication=classic/login-module=Database:add( \ code=Database, \ flag=required, \ module-options=[ \ ("password-stacking"=>"useFirstPass"), \ ... Database login module configuration ])
18.3.1.2. パスワードのハッシュ化
例18.6 パスワードのハッシュ化
nobody
を割り当て、usersb64.properties
ファイルに based64 でエンコードされた SHA-256 ハッシュのパスワードを含むログインモジュール設定です。usersb64.properties
ファイルは、デプロイメントクラスパスの一部です。
/subsystem=security/security-domain=testUsersRoles:add /subsystem=security/security-domain=testUsersRoles/authentication=classic:add /subsystem=security/security-domain=testUsersRoles/authentication=classic/login-module=UsersRoles:add( \ code=UsersRoles, \ flag=required, \ module-options=[ \ ("usersProperties"=>"usersb64.properties"), \ ("rolesProperties"=>"test-users-roles.properties"), \ ("unauthenticatedIdentity"=>"nobody"), \ ("hashAlgorithm"=>"SHA-256"), \ ("hashEncoding"=>"base64") \ ])
- hashAlgorithm
- パスワードをハッシュするために使用される
java.security.MessageDigest
アルゴリズムの名前。デフォルトがないため、ハッシュを有効にするには、このオプションを指定する必要があります。一般的な値はSHA-256
、SHA-1
、およびMD5
です。 - hashEncoding
base64
、hex
、rfc2617
の 3 つのエンコーディングタイプのいずれかを指定する文字列。デフォルトはbase64
です。- hashCharset
- クリアテキストのパスワードをバイト配列に変換するために使用されるエンコーディング文字セット。プラットフォームのデフォルトエンコーディングがデフォルトです。
- hashUserPassword
- ユーザーが送信するパスワードにハッシュアルゴリズムを適用する必要があることを指定します。ハッシュ化されたユーザーパスワードは、ログインモジュール内の値と比較されます. これは、パスワードのハッシュです。デフォルトは
true
です。 - hashStorePassword
- サーバー側に保存されているパスワードにハッシュアルゴリズムを適用する必要があることを指定します。これは、ユーザーパスワードのハッシュと、比較対象のサーバーからの要求固有のトークンを送信するダイジェスト認証に使用されます。ハッシュアルゴリズム (ダイジェストの場合は
rfc2617
) を利用してサーバー側のハッシュを計算し、クライアントから送信されたハッシュ値と一致させる必要があります。
org.jboss.security.auth.spi.Util
クラスは、指定されたエンコーディングを使用してパスワードをハッシュする静的ヘルパーメソッドを提供します。次の例では、base64 でエンコードされた MD5 ハッシュパスワードを生成します。
String hashedPassword = Util.createPasswordHash("SHA-256", Util.BASE64_ENCODING, null, null, "password");
パスワード
(password) が OpenSSL ダイジェスト関数にパイプされ、次に別の OpenSSL 関数にパイプされて base64 エンコード形式に変換されます。
echo -n password | openssl dgst -sha256 -binary | openssl base64
XohImNooBHFR0OVvjcYpJ3NgPQ1qq73WKhHvch0VQtg=
。この値は、上記の例ではセキュリティードメインで指定されたユーザーのプロパティーファイル (usersb64.properties
) に保存する必要があります。
18.3.1.3. 認証されていない ID
unauthenticatedIdentity
は、認証情報を持たない要求に特定の ID (例: guest) を割り当てるログインモジュール設定オプションです。これを使用すると、保護されていないサーブレットは特定ロールを必要としない EJB でメソッドを呼び出すことができます。このようなプリンシパルには関連したロールがなく、セキュアでない EJB や、チェックされていないパーミッション制約と関連する EJB メソッドのみにアクセスできます。
- unauthenticatedIdentity: これにより、認証情報を含まない要求に割り当てる必要があるプリンシパル名が定義されます。
18.3.1.4. Ldap ログインモジュール
Ldap
ログインモジュールは、ライトウェイトディレクトリーアクセスプロトコル (LDAP) サーバーに対して認証を行う LoginModule
実装です。ユーザー名と資格情報が、Java Naming and Directory Interface (JNDI)LDAP プロバイダーを使用してアクセスできる LDAP サーバーに保管されている場合は、Ldap
ログインモジュールを使用します。
AdvancedLdap
ログインモジュールの使用を検討するか、AdvancedLdap
ログインモジュールのみの使用を検討してください。
- 識別名 (DN)
- LDAP (Lightweight Directory Access Protocol) において、ディレクトリー内のオブジェクトを一意に特定する識別名。各識別名には、他のオブジェクトと区別するための一意名と場所が必要で、これには属性と値のペア (AVP) を使用します。AVP は、共通名、組織単位などの情報を定義します。LDAP に必要となる一意な文字列は、これらの値の組み合わせになります。
- java.naming.factory.initial
InitialContextFactory
実装クラス名。これは、デフォルトで SunLDAP プロバイダー実装com.sun.jndi.ldap.LdapCtxFactory
になります。- java.naming.provider.url
- LDAP サーバーの LDAP URL。
- java.naming.security.authentication
- 使用するセキュリティープロトコルレベル。使用可能な値には、
none
、simple
、strong
が含まれます。プロパティーが定義されていない場合に、この動作はサービスプロバイダーによって決定されます。 - java.naming.security.protocol
- 安全なアクセスに使用するトランスポートプロトコル。この設定オプションをサービスプロバイダーのタイプ (SSL など) に設定します。プロパティーが定義されていない場合に、この動作はサービスプロバイダーによって決定されます。
- java.naming.security.principal
- サービスへの呼び出し元を認証するためのプリンシパルの ID を指定します。これは、以下で説明されているように、その他のプロパティーから構築されます。
- java.naming.security.credentials
- サービスへの呼び出し元を認証するためのプリンシパルの資格情報を指定します。資格情報は、ハッシュ化されたパスワード、クリアテキストのパスワード、キー、または証明書の形式をとることができます。プロパティーが定義されていない場合に、この動作はサービスプロバイダーによって決定されます。
true
に設定する必要があります。
InitialLdapContext
を作成することによって行われます。
InitialLdapContext
インスタンスが作成されると)、検索属性がに設定された rolesCtxDN
の場所で検索を実行することにより、ユーザーのロールが照会されます。roleAttributeNameとuidAttributeNameオプション値。を呼び出すことによって名前が取得しているロール toString
検索結果セットのロール属性のメソッド。
例18.7 LDAP ログインモジュールセキュリティードメイン
/subsystem=security/security-domain=testLDAP:add(cache-type=default) /subsystem=security/security-domain=testLDAP/authentication=classic:add /subsystem=security/security-domain=testLDAP/authentication=classic/login-module=Ldap:add( \ code=Ldap, \ flag=required, \ module-options=[ \ ("java.naming.factory.initial"=>"com.sun.jndi.ldap.LdapCtxFactory"), \ ("java.naming.provider.url"=>"ldap://ldaphost.jboss.org:1389/"), \ ("java.naming.security.authentication"=>"simple"), \ ("principalDNPrefix"=>"uid="), \ ("principalDNSuffix"=>",ou=People,dc=jboss,dc=org"), \ ("rolesCtxDN"=>"ou=Roles,dc=jboss,dc=org"), \ ("uidAttributeID"=>"member"), \ ("matchOnUserDN"=>true), \ ("roleAttributeID"=>"cn"), \ ("roleAttributeIsDN"=>false) \ ])
java.naming.factory.initial
、java.naming.factory.url
、および java.naming.security
オプションtestLDAPセキュリティードメインの設定は、次の条件を示しています。
- SunLDAPJNDI プロバイダーの実装が使用されます
- LDAP サーバーは、ポート 1389 のホスト
ldaphost.jboss.org
にあります。 - LDAP サーバーへの接続には、LDAP の単純な認証方法が使用されます。
jsmith
は uid = jsmith、ou = People、dc = jboss、dc=org に
マップされます。
デューク
) の userPassword
属性を使用してユーザーを認証することを前提としています。ほとんどの LDAP サーバーはこのように動作しますが、LDAP サーバーが認証を異なる方法で処理する場合は、LDAP が実稼働環境の要件に従って設定されていることを確認する必要があります。
rolesCtxDN
のサブツリー検索を実行して、認証の基になるロールが取得されます。uidAttributeIDユーザーと一致します。もしもmatchOnUserDNtrue の場合、検索はユーザーの完全な DN に基づいて行われます。それ以外の場合、検索は入力された実際のユーザー名に基づいて行われます。この例では、ou = Roles、dc = jboss、dc = org
で、uid = jsmith、ou = People、dc = jboss、dc=org に
等しい メンバー
属性を持つエントリーを検索します。検索では、ロールエントリーの下に cn=JBossAdmin
が見つかります。
cn
です。返される値は JBossAdmin
になるため、jsmith
ユーザーは JBossAdmin
ロールに割り当てられます。
- LDAP データ交換形式 (LDIF)
- LDAP ディレクトリーのコンテンツと更新要求を表すために使用されるプレーンテキストのデータ交換形式。ディレクトリーコンテンツは、オブジェクトまたは更新要求ごとに 1 つのレコードとして表されます。コンテンツは、追加、変更、削除、および名前変更のリクエストで設定されます。
例18.8 LDIF ファイルの例
dn: dc=jboss,dc=org objectclass: top objectclass: dcObject objectclass: organization dc: jboss o: JBoss dn: ou=People,dc=jboss,dc=org objectclass: top objectclass: organizationalUnit ou: People dn: uid=jsmith,ou=People,dc=jboss,dc=org objectclass: top objectclass: uidObject objectclass: person uid: jsmith cn: John sn: Smith userPassword: theduke dn: ou=Roles,dc=jboss,dc=org objectclass: top objectclass: organizationalUnit ou: Roles dn: cn=JBossAdmin,ou=Roles,dc=jboss,dc=org objectclass: top objectclass: groupOfNames cn: JBossAdmin member: uid=jsmith,ou=People,dc=jboss,dc=org description: the JBossAdmin group
18.3.1.5. LdapExtended ログインモジュール
- 識別名 (DN)
- LDAP (Lightweight Directory Access Protocol) において、ディレクトリー内のオブジェクトを一意に特定する識別名。各識別名には、他のオブジェクトと区別するための一意名と場所が必要で、これには属性と値のペア (AVP) を使用します。AVP は、共通名、組織単位などの情報を定義します。LDAP に必要となる一意な文字列は、これらの値の組み合わせになります。
org.jboss.security.auth.spi.LdapExtLoginModule)
ログインモジュールは、ユーザーと認証で関連ロールを検索します。ロールは再帰的にクエリーを行い、DN に従って階層的なロール構造を移動します。
- Context.INITIAL_CONTEXT_FACTORY = "java.naming.factory.initial"
- Context.SECURITY_PROTOCOL = "java.naming.security.protocol"
- Context.PROVIDER_URL = "java.naming.provider.url"
- Context.SECURITY_AUTHENTICATION = "java.naming.security.authentication"
- Context.REFERRAL = "java.naming.referral"
- 最初の LDAP サーバーバインドは、bindDNとbindCredentialプロパティー。ThebindDN両方を検索する権限を持つユーザーですbaseCtxDNとrolesCtxDNユーザーとロールのツリー。Theuser DN認証対象は、で指定されたフィルターを使用して照会されますbaseFilter財産。
- 結果としてuserDNを使用して LDAP サーバーにバインドすることで認証されますuserDNInitialLdapContext 環境としてContext.SECURITY_PRINCIPAL。TheContext.SECURITY_CREDENTIALSプロパティーは、コールバックハンドラーによって取得された文字列パスワードに設定されます。
- これが成功すると、rolesCtxDN、roleAttributeID、roleAttributeIsDN、roleNameAttributeID、および roleFilter オプションを使用して、関連付けられたユーザーロールが照会されます。
- トップレベルのロールは roleAttributeID のみに対してクエリーされ、roleNameAttributeID にはクエリーされません。
- roleAttributeIsDN モジュールプロパティーが false に設定されている場合、recurseRoles モジュールオプションが true に設定されていても、再帰ロール検索は無効になります。
図18.1 LDAP 構造の例
[D]
例18.9 例 2LDAP 設定
version: 1 dn: o=example2,dc=jboss,dc=org objectClass: top objectClass: organization o: example2 dn: ou=People,o=example2,dc=jboss,dc=org objectClass: top objectClass: organizationalUnit ou: People dn: uid=jduke,ou=People,o=example2,dc=jboss,dc=org objectClass: top objectClass: uidObject objectClass: person objectClass: inetOrgPerson cn: Java Duke employeeNumber: judke-123 sn: Duke uid: jduke userPassword:: dGhlZHVrZQ== dn: uid=jduke2,ou=People,o=example2,dc=jboss,dc=org objectClass: top objectClass: uidObject objectClass: person objectClass: inetOrgPerson cn: Java Duke2 employeeNumber: judke2-123 sn: Duke2 uid: jduke2 userPassword:: dGhlZHVrZTI= dn: ou=Roles,o=example2,dc=jboss,dc=org objectClass: top objectClass: organizationalUnit ou: Roles dn: uid=jduke,ou=Roles,o=example2,dc=jboss,dc=org objectClass: top objectClass: groupUserEx memberOf: cn=Echo,ou=Roles,o=example2,dc=jboss,dc=org memberOf: cn=TheDuke,ou=Roles,o=example2,dc=jboss,dc=org uid: jduke dn: uid=jduke2,ou=Roles,o=example2,dc=jboss,dc=org objectClass: top objectClass: groupUserEx memberOf: cn=Echo2,ou=Roles,o=example2,dc=jboss,dc=org memberOf: cn=TheDuke2,ou=Roles,o=example2,dc=jboss,dc=org uid: jduke2 dn: cn=Echo,ou=Roles,o=example2,dc=jboss,dc=org objectClass: top objectClass: groupOfNames cn: Echo description: the echo role member: uid=jduke,ou=People,dc=jboss,dc=org dn: cn=TheDuke,ou=Roles,o=example2,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: TheDuke description: the duke role member: uid=jduke,ou=People,o=example2,dc=jboss,dc=org dn: cn=Echo2,ou=Roles,o=example2,dc=jboss,dc=org objectClass: top objectClass: groupOfNames cn: Echo2 description: the Echo2 role member: uid=jduke2,ou=People,dc=jboss,dc=org dn: cn=TheDuke2,ou=Roles,o=example2,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: TheDuke2 description: the duke2 role member: uid=jduke2,ou=People,o=example2,dc=jboss,dc=org dn: cn=JBossAdmin,ou=Roles,o=example2,dc=jboss,dc=org objectClass: top objectClass: groupOfNames cn: JBossAdmin description: the JBossAdmin group member: uid=jduke,ou=People,dc=jboss,dc=org
/subsystem=security/security-domain=testLdapExample2/authentication=classic/login-module=LdapExtended:add( \ code=LdapExtended, \ flag=required, \ module-options=[ \ ("java.naming.factory.initial"=>"com.sun.jndi.ldap.LdapCtxFactory"), \ ("java.naming.provider.url"=>"ldap://ldaphost.jboss.org"), \ ("java.naming.security.authentication"=>"simple"), \ ("bindDN"=>"cn=Root,dc=jboss,dc=org"), \ ("bindCredential"=>"secret1"), \ ("baseCtxDN"=>"ou=People,o=example2,dc=jboss,dc=org"), \ ("baseFilter"=>"(uid={0})"), \ ("rolesCtxDN"=>"ou=Roles,o=example2,dc=jboss,dc=org"), \ ("roleFilter"=>"(uid={0})"), \ ("roleAttributeIsDN"=>"true"), \ ("roleAttributeID"=>"memberOf"), \ ("roleNameAttributeID"=>"cn") \ ])
例18.10 例 3LDAP 設定
dn: o=example3,dc=jboss,dc=org objectclass: top objectclass: organization o: example3 dn: ou=People,o=example3,dc=jboss,dc=org objectclass: top objectclass: organizationalUnit ou: People dn: uid=jduke,ou=People,o=example3,dc=jboss,dc=org objectclass: top objectclass: uidObject objectclass: person objectClass: inetOrgPerson uid: jduke employeeNumber: judke-123 cn: Java Duke sn: Duke userPassword: theduke dn: ou=Roles,o=example3,dc=jboss,dc=org objectClass: top objectClass: organizationalUnit ou: Roles dn: uid=jduke,ou=Roles,o=example3,dc=jboss,dc=org objectClass: top objectClass: groupUserEx memberOf: cn=Echo,ou=Roles,o=example3,dc=jboss,dc=org memberOf: cn=TheDuke,ou=Roles,o=example3,dc=jboss,dc=org uid: jduke dn: cn=Echo,ou=Roles,o=example3,dc=jboss,dc=org objectClass: top objectClass: groupOfNames cn: Echo description: the JBossAdmin group member: uid=jduke,ou=People,o=example3,dc=jboss,dc=org dn: cn=TheDuke,ou=Roles,o=example3,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: TheDuke member: uid=jduke,ou=People,o=example3,dc=jboss,dc=org
/subsystem=security/security-domain=testLdapExample3/authentication=classic/login-module=LdapExtended:add( \ code=LdapExtended, \ flag=required, \ module-options=[ \ ("java.naming.factory.initial"=>"com.sun.jndi.ldap.LdapCtxFactory"), \ ("java.naming.provider.url"=>"ldap://ldaphost.jboss.org"), \ ("java.naming.security.authentication"=>"simple"), \ ("bindDN"=>"cn=Root,dc=jboss,dc=org"), \ ("bindCredential"=>"secret1"), \ ("baseCtxDN"=>"ou=People,o=example3,dc=jboss,dc=org"), \ ("baseFilter"=>"(cn={0})"), \ ("rolesCtxDN"=>"ou=Roles,o=example3,dc=jboss,dc=org"), \ ("roleFilter"=>"(member={1})"), \ ("roleAttributeID"=>"cn") \ ])
例18.11 例 4LDAP 設定
dn: o=example4,dc=jboss,dc=org objectclass: top objectclass: organization o: example4 dn: ou=People,o=example4,dc=jboss,dc=org objectclass: top objectclass: organizationalUnit ou: People dn: uid=jduke,ou=People,o=example4,dc=jboss,dc=org objectClass: top objectClass: uidObject objectClass: person objectClass: inetOrgPerson cn: Java Duke employeeNumber: jduke-123 sn: Duke uid: jduke userPassword:: dGhlZHVrZQ== dn: ou=Roles,o=example4,dc=jboss,dc=org objectClass: top objectClass: organizationalUnit ou: Roles dn: cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: RG1 member: cn=empty dn: cn=RG2,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: RG2 member: cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org member: uid=jduke,ou=People,o=example4,dc=jboss,dc=org dn: cn=RG3,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: RG3 member: cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org dn: cn=R1,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: R1 member: cn=RG2,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org dn: cn=R2,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: R2 member: cn=RG2,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org dn: cn=R3,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: R3 member: cn=RG2,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org member: cn=RG3,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org dn: cn=R4,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: R4 member: cn=RG3,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org dn: cn=R5,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: R5 member: cn=RG3,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org member: uid=jduke,ou=People,o=example4,dc=jboss,dc=org
/subsystem=security/security-domain=testLdapExample4/authentication=classic/login-module=LdapExtended:add( \ code=LdapExtended, \ flag=required, \ module-options=[ \ ("java.naming.factory.initial"=>"com.sun.jndi.ldap.LdapCtxFactory"), \ ("java.naming.provider.url"=>"ldap://ldaphost.jboss.org"), \ ("java.naming.security.authentication"=>"simple"), \ ("bindDN"=>"cn=Root,dc=jboss,dc=org"), \ ("bindCredential"=>"secret1"), \ ("baseCtxDN"=>"ou=People,o=example4,dc=jboss,dc=org"), \ ("baseFilter"=>"(cn={0})"), \ ("rolesCtxDN"=>"ou=Roles,o=example4,dc=jboss,dc=org"), \ ("roleFilter"=>"(member={1})"), \ ("roleRecursion"=>"1"), \ ("roleAttributeID"=>"memberOf") \ ])
例18.12 デフォルトの Active Directory 設定
/subsystem=security/security-domain=AD_Default/authentication=classic/login-module=LdapExtended:add( \ code=LdapExtended, \ flag=required, \ module-options=[ \ ("java.naming.provider.url"=>"ldap://ldaphost.jboss.org"), \ ("bindDN"=>"JBOSS\searchuser"), \ ("bindCredential"=>"password"), \ ("baseCtxDN"=>"CN=Users,DC=jboss,DC=org"), \ ("baseFilter"=>"(sAMAccountName={0})"), \ ("rolesCtxDN"=>"CN=Users,DC=jboss,DC=org"), \ ("roleFilter"=>"(sAMAccountName={0})"), \ ("roleAttributeID"=>"memberOf"), \ ("roleAttributeIsDN"=>"true"), \ ("roleNameAttributeID"=>"cn"), \ ("searchScope"=>"ONELEVEL_SCOPE"), \ ("allowEmptyPasswords"=>"false") \ ])
例18.13 再帰的なロール Active Directory の設定
/subsystem=security/security-domain=AD_Recursive/authentication=classic/login-module=LdapExtended:add( \ code=LdapExtended, \ flag=required, \ module-options=[ \ ("java.naming.provider.url"=>"ldap://ldaphost.jboss.org"), \ ("java.naming.referral"=>"follow"), \ ("bindDN"=>"JBOSS\searchuser"), \ ("bindCredential"=>"password"), \ ("baseCtxDN"=>"CN=Users,DC=jboss,DC=org"), \ ("baseFilter"=>"(sAMAccountName={0})"), \ ("rolesCtxDN"=>"CN=Users,DC=jboss,DC=org"), \ ("roleFilter"=>"(member={1})"), \ ("roleAttributeID"=>"cn"), \ ("roleAttributeIsDN"=>"false"), \ ("roleRecursion"=>"2"), \ ("searchScope"=>"ONELEVEL_SCOPE"), \ ("allowEmptyPasswords"=>"false") \ ])
18.3.1.6. UsersRoles ログインモジュール
UsersRoles
ログインモジュールは、Java プロパティーファイルからロードされる複数のユーザーおよびユーザーロールをサポートする簡単なログインモジュールです。デフォルトの username-to-password マッピングファイル名は users.properties
で、デフォルトの username-to-roles マッピングファイル名は roles.properties
です。
WAR
アーカイブの WEB-INF/classes
フォルダーなど) またはサーバークラスパスの任意のディレクトリーに配置できます。このログインモジュールの主な目的は、アプリケーションとともにデプロイされたプロパティーファイルを使用して複数のユーザーおよびロールのセキュリティー設定を簡単にテストすることです。
例18.14 UsersRoles ログインモジュール
/subsystem=security/security-domain=ejb3-sampleapp/authentication=classic/login-module=UsersRoles:add( \ code=UsersRoles, \ flag=required, \ module-options=[ \ ("usersProperties"=>"ejb3-sampleapp-users.properties"), \ ("rolesProperties"=>"ejb3-sampleapp-roles.properties") \ ])
ejb3-sampleapp-users.properties
ファイルは username = password
形式を使用し、各ユーザーエントリーは別々の行にあります。
username1=password1 username2=password2 ...
ている ejb3-sampleapp-roles.properties
ファイル例18.14「UsersRoles ログインモジュール」パターン username=role1、role2 を
使用し、オプションのグループ名の値を指定します。以下に例を示します。
username1=role1,role2,... username1.RoleGroup1=role3,role4,... username2=role1,role3,...
ejb3-sampleapp-roles.properties
に存在するプロパティー名パターンは、プロパティー名の XXX
部分がグループ名である特定の名前付きロールグループにユーザー名ロールを割り当てるために使用されます。Theuser name=...form はの略語ですuser name.Roles=...、ここで、Roles
グループ名は、JBossAuthorizationManager
がユーザーの権限を定義するロールを含むことを期待する標準名です。
jduke
ユーザー名の同等の定義です。
jduke=TheDuke,AnimatedCharacter jduke.Roles=TheDuke,AnimatedCharacter
18.3.1.7. Database ログインモジュール
Database
ログインモジュールは、認証とロールマッピングをサポートする JDBC (Java Database Connectivity) ベースのログインモジュールです。ユーザー名、パスワード、およびロール情報がリレーショナルデータベースに保存されている場合は、このログインモジュールを使用してください。
データベース
ログインモジュールは、次の 2 つの論理テーブルに基づいています。
Table Principals(PrincipalID text, Password text) Table Roles(PrincipalID text, Role text, RoleGroup text)
Principals
テーブルはユーザー PrincipalID
を有効なパスワードに関連付けます。また、Roles
テーブルはユーザー PrincipalID
をそのロールセットに関連付けます。ユーザーパーミッションに使用されるロールは、Roles
の RoleGroup
コラムの値を持つ行に含まれる必要があります。
java.sql.ResultSet
は前述の Principals
および Roles
と同じ論理構造を持ちます。テーブル名およびコラムの実際の名前は、コラムのインデックスに基づいてアクセスされるため、関係ありません。
Principals
および Roles
という 2 つのテーブルがあるデータベースを検討してください。以下のステートメントは、以下のデータをテーブルに追加します。
Principals
テーブルのechoman
というパワスワード
を持つPrincipalID
java
Roles
テーブルのRoles
RoleGroup
のEcho
という名前のロールを持つPrincipalID
java
Roles
テーブルのCallerPrincipal
RoleGroup
にcaller_java
という名前のロールを持つPrincipalID
java
INSERT INTO Principals VALUES('java', 'echoman') INSERT INTO Roles VALUES('java', 'Echo', 'Roles') INSERT INTO Roles VALUES('java', 'caller_java', 'CallerPrincipal')
データベースログインモジュール
の設定例は、次のように設定できます。
CREATE TABLE Users(username VARCHAR(64) PRIMARY KEY, passwd VARCHAR(64)) CREATE TABLE UserRoles(username VARCHAR(64), role VARCHAR(32))
/subsystem=security/security-domain=testDB/authentication=classic/login-module=Database:add( \ code=Database, \ flag=required, \ module-options=[ \ ("dsJndiName"=>"java:/MyDatabaseDS"), \ ("principalsQuery"=>"select passwd from Users where username=?"), \ ("rolesQuery"=>"select role, 'Roles' from UserRoles where username=?") \ ])
18.3.1.8. Certificate ログインモジュール
Certificate
ログインモジュールは、X509 証明書を基にユーザーを認証します。このログインモジュールの典型的なユースケースが、web 層の CLIENT-CERT
認証です。
CertRolesLoginModule
および DatabaseCertLoginModule
は動作を拡張し、プロパティーファイルまたはデータベースから承認ロールを取得します。
証明書
ログインモジュールオプションの詳細については、JBoss EAP の 『セキュリティーガイド』 の 『含まれる認証モジュール』 リファレンスを参照してください。
証明書
ログインモジュールには、ユーザー検証を実行するための KeyStore
が必要です。これは、次の設定フラグメントに示すように、リンクされたセキュリティードメインの JSSE 設定から取得されます。
/subsystem=security/security-domain=trust-domain:add /subsystem=security/security-domain=trust-domain/jsse=classic:add( \ truststore={ \ password=>pass1234, \ url=>/home/jbosseap/trusted-clients.jks \ }) /subsystem=security/security-domain=testCert:add /subsystem=security/security-domain=testCert/authentication=classic:add /subsystem=security/security-domain=testCert/authentication=classic/login-module=Certificate:add( \ code=Certificate, \ flag=required, \ module-options=[ \ ("securityDomain"=>"trust-domain"), \ ])
手順18.4 証明書とロールベースの承認による安全な Web アプリケーション
user-app.war
などの Web アプリケーションを保護する方法について説明します。この例では、CertificateRoles
ログインモジュールが認証と承認に使用されています。trusted-clients.keystore
と app-roles.properties
の両方に、クライアント証明書に関連付けられたプリンシパルにマップするエントリーが必要です。
リソースとロールを宣言する
web.xml
を変更して、認証と承認に使用できる許可されたロールとセキュリティードメインとともに、保護するリソースを宣言します。<?xml version="1.0" encoding="UTF-8"?> <web-app 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" version="3.0"> <security-constraint> <web-resource-collection> <web-resource-name>Protect App</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>Admin</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>CLIENT-CERT</auth-method> <realm-name>Secured area</realm-name> </login-config> <security-role> <role-name>Admin</role-name> </security-role> </web-app>
セキュリティードメインを指定する
jboss-web.xml
ファイルで、必要なセキュリティードメインを指定します。<jboss-web> <security-domain>app-sec-domain</security-domain> </jboss-web>
ログインモジュールの設定
管理 CLI を使用して、指定したapp-sec-domain
ドメインのログインモジュール設定を定義します。[ /subsystem=security/security-domain=trust-domain:add /subsystem=security/security-domain=trust-domain/jsse=classic:add( \ truststore={ \ password=>pass1234, \ url=>/home/jbosseap/trusted-clients.jks \ }) /subsystem=security/security-domain=app-sec-domain:add /subsystem=security/security-domain=app-sec-domain/authentication=classic:add /subsystem=security/security-domain=app-sec-domain/authentication=classic/login-module=CertificateRoles:add( \ code=CertificateRoles, \ flag=required, \ module-options=[ \ ("securityDomain"=>"trust-domain"), \ ("rolesProperties"=>"app-roles.properties") \ ])
例18.15 証明書の例
[conf]$ keytool -printcert -file valid-client-cert.crt Owner: CN=valid-client, OU=Security QE, OU=JBoss, O=Red Hat, C=CZ Issuer: CN=EAP Certification Authority, OU=Security QE, OU=JBoss, O=Red Hat, C=CZ Serial number: 2 Valid from: Mon Mar 24 18:21:55 CET 2014 until: Tue Mar 24 18:21:55 CET 2015 Certificate fingerprints: MD5: 0C:54:AE:6E:29:ED:E4:EF:46:B5:14:30:F2:E0:2A:CB SHA1: D6:FB:19:E7:11:28:6C:DE:01:F2:92:2F:22:EF:BB:5D:BF:73:25:3D SHA256: CD:B7:B1:72:A3:02:42:55:A3:1C:30:E1:A6:F0:20:B0:2C:0F:23:4F:7A:8E:2F:2D:FA:AF:55:3E:A7:9B:2B:F4 Signature algorithm name: SHA1withRSA Version: 3
trusted-clients.keystore
には、次の証明書が必要です。例18.15「証明書の例」CN = valid-client、OU = Security QE、OU = JBoss、O = Red Hat、C=CZ
のエイリアスで保存されます。app-roles.properties
には同じエントリーが必要です。DN には通常区切り文字として扱われる文字が含まれているため、以下に示すように、円記号 (' \
') を使用して問題のある文字をエスケープする必要があります。
# A sample app-roles.properties file CN\=valid-client,\ OU\=Security\ QE,\ OU\=JBoss,\ O\=Red\ Hat,\ C\=CZ
18.3.1.9. Identity ログインモジュール
Identity
ログインモジュールは、ハードコードされたユーザー名をモジュールに対して認証されたサブジェクトに関連付ける簡単なログインモジュールです。このモジュールは、principal
のオプションによって指定された名前を使用して SimplePrincipal
インスタンスを作成します。
jduke
という名前のプリンシパルとして認証し、TheDuke
のロール名と AnimatedCharacter
: を割り当てます。
/subsystem=security/security-domain=testIdentity:add /subsystem=security/security-domain=testIdentity/authentication=classic:add /subsystem=security/security-domain=testIdentity/authentication=classic/login-module=Identity:add( \ code=Identity, \ flag=required, \ module-options=[ \ ("principal"=>"jduke"), \ ("roles"=>"TheDuke,AnimatedCharacter") \ ])
18.3.1.10. RunAs ログインモジュール
RunAS
ログインモジュールは、認証のログインフェーズの間に run as
ロールをスタックにプッシュするヘルパーモジュールです。ログインフェーズ後、コミットまたはアボートフェーズで run as
ロールをスタックからポップします。
RunAs
ログインモジュールは、run as
ロールの構築が必要なログインモジュールよりも先に設定する必要があります。
18.3.1.10.1. RunAsIdentity の作成
javax.security.auth.Subject
インスタンスまたは org.jboss.security.RunAsIdentity
インスタンスのいずれかで表されます。これらのクラスは両方とも、ID を表す 1 つ以上のプリンシパルと、ID が所有するロールのリストを格納します。javax.security.auth.Subject
の場合、資格情報のリストも保存されます。
ejb-jar.xml
デプロイメント記述子のセクションでは、ユーザーがさまざまな EJB メソッドにアクセスするために必要な 1 つ以上のロールを指定します。これらのリストを比較すると、ユーザーが EJB メソッドにアクセスするために必要なロールの 1 つを持っているかどうかがわかります。
例18.16 org.jboss.security.RunAsIdentity Creation
ejb-jar.xml
ファイルで、<security-identity>要素と<run-as><session> 要素の子として定義されたロール。
<session> ... <security-identity> <run-as> <role-name>Admin</role-name> </run-as> </security-identity> ... </session>
AdminRunAsIdentity
ロールを作成する必要があることを示しています。
管理者
ロールのプリンシパルに名前を付けるには、jboss-ejb3.xml
ファイルで <run-as-principal>
要素を定義します。
<jboss:ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns:s="urn:security:1.1" version="3.1" impl-version="2.0"> <assembly-descriptor> <s:security> <ejb-name>WhoAmIBean</ejb-name> <s:run-as-principal>John</s:run-as-principal> </s:security> </assembly-descriptor> </jboss:ejb-jar>
ejb-jar.xml
ファイルの <security-identity>
要素と jboss-ejb3.xml
ファイルの <security>
要素の両方がデプロイメント時に解析されます。<run-as>
ロール名と <run-as-principal>
名は、org.jboss.metadata.ejb.spec.SecurityIdentityMetaData
クラスに保存されます。
例18.17 RunAsIdentity への複数のロールの割り当て
jboss-ejb3.xml
デプロイメント記述子 <assembly-descriptor>
エレメントグループのプリンシパルにロールをマッピングすることにより、RunAsIdentity により多くのロールを割り当てることができます。
<jboss:ejb-jar xmlns:sr="urn:security-role" ...> <assembly-descriptor> ... <sr:security-role> <sr:role-name>Support</sr:role-name> <sr:principal-name>John</sr:principal-name> <sr:principal-name>Jill</sr:principal-name> <sr:principal-name>Tony</sr:principal-name> </sr:security-role> </assembly-descriptor> </jboss:ejb-jar>
ジョン
の <run-as-principal>
が作成されました。この例の設定では、サポート
ロールを追加することにより、管理者
ロールを拡張します。新しいロールには、最初に定義されたプリンシパル John
を含む追加のプリンシパルが含まれます。
ejb-jar.xml
ファイルと jboss-ejb3.xml
ファイルの両方の <security-role>
要素は、デプロイメント時に解析されます。<role-name>
および <principal-name>
データは、org.jboss.metadata.ejb.spec.SecurityIdentityMetaData
クラスに保存されます。
18.3.1.11. Client ログインモジュール
Client
ログインモジュール (org.jboss.security.ClientLoginModule
) は、呼び出し元のアイデンティティーとクレデンシャルの確立時に JBoss クライアントによって使用される LoginModule
の実装です。新しい SecurityContext
を作成してプリンシパルとクレデンシャルに割り当て、SecurityContext
を ThreadLocal
セキュリティーコンテキストに設定します。
Client
ログインモジュールは、クライアントが現在のスレッドの呼び出し元を確立するために唯一サポートされるログインモジュールです。セキュリティー環境が JBoss EJB security サブシステムを使用するよう透過的に設定されていない EJB クライアントとして動作するサーバー環境とスタンドアロンクライアントアプリケーションは、Client
ログインモジュールを使用する必要があります。
クライアント
ログインモジュールに加えて別のログインモジュールを設定する必要があります。
18.3.1.12. SPNEGO ログインモジュール
SPNEGO
ログインモジュール (org.jboss.security.negotiation.spnego.SPNEGOLoginModule
) は、KDC で呼び出し元のアイデンティティーとクレデンシャルを確立する LoginModule
の実装です。モジュールは、SPNEGO、Simple、および Protected GSSAPI Negotiation メカニズムを実装し、JBoss Negotiation プロジェクトの一部です。この認証を AdvancedLdap
ログインモジュールとチェーンされた設定で使用すると、LDAP サーバーと連携できます。
SPNEGO
またAdvancedLdap
プロジェクトのログインモジュールでは、META-INF/jboss-deployment-structure.xml
デプロイメント記述子ファイルを編集して、依存関係を手動で追加する必要があります。
例18.18 JBossNegotiationModule を依存関係として追加する
<jboss-deployment-structure> <deployment> <dependencies> <module name="org.jboss.security.negotiation" /> </dependencies> </deployment> </jboss-deployment-structure>
18.3.1.13. RoleMapping ログインモジュール
RoleMapping
ログインモジュールは、1 つ以上の宣言的ロールへの認証プロセスの最終結果となるロールのマッピングをサポートします。たとえば、ユーザー A のロールが ldapAdmin と testAdmin で、web.xml
または ejb-jar.xml
ファイルで定義されたアクセスの宣言的ロールは admin
であると認証プロセスによって判断された場合、このログインモジュールは admin
ロールを A
にマップします。
RoleMapping
ログインモジュールオプションの詳細については、JBoss EAP の 『セキュリティーガイド』 の 『含まれる認証モジュール』 リファレンスを参照してください。
RoleMapping
ログインモジュールは、以前マップされたロールのマッピングを変更するため、ログインモジュール設定でオプションのモジュールとして定義する必要があります。
例18.19 マップされたロールの定義
/subsystem=security/security-domain=test-domain-2/:add /subsystem=security/security-domain=test-domain-2/authentication=classic:add /subsystem=security/security-domain=test-domain-2/authentication=classic/login-module=test-2-lm/:add(\ flag=required,\ code=UsersRoles,\ module-options=[("usersProperties"=>"users.properties"),("rolesProperties"=>"roles.properties")]\ ) /subsystem=security/security-domain=test-domain-2/authentication=classic/login-module=test2-map/:add(\ flag=optional,\ code=RoleMapping,\ module-options=[("rolesProperties"=>"rolesMapping-roles.properties")]\ )
例18.20 マップされたロールを定義するための好ましい方法
/subsystem=security/security-domain=test-domain-2/:add /subsystem=security/security-domain=test-domain-2/authentication=classic:add /subsystem=security/security-domain=test-domain-2/authentication=classic/login-module=test-2-lm/:add(\ flag=required,\ code=UsersRoles,\ module-options=[("usersProperties"=>"users.properties"),("rolesProperties"=>"roles.properties")]\ ) /subsystem=security/security-domain=test-domain-2/mapping=classic/mapping-module=test2-map/:add(\ code=PropertiesRoles,type=role,\ module-options=[("rolesProperties"=>"rolesMapping-roles.properties")]\ )
例18.21 RoleMappingLoginModule によって使用されるプロパティーファイル
ldapAdmin=admin, testAdmin
ldapAdmin
が含まれている場合、ロール admin
および testAdmin
は、認証されたサブジェクトに追加されるか、認証されたサブジェクトに置き換えられます。replaceRoleプロパティー値。
18.3.1.14. bindCredential モジュールオプション
bindCredential
モジュールオプションは、DN の資格情報を保存するために使用され、複数のログインおよびマッピングモジュールで使用できます。パスワードを取得するには、いくつかの方法があります。
- 管理 CLI コマンドのプレーンテキスト。
- のパスワード
bindCredential
モジュールは、管理 CLI コマンドでプレーンテキストで提供できます。例:("bindCredential"=>"secret1")
.セキュリティー上の理由から、パスワードは JBoss EAP ボールトメカニズムを使用して暗号化する必要があります。 - 外部コマンドを使用します。
- 外部コマンドの出力からパスワードを取得するには、次の形式を使用します
{EXT}...
どこ...
外部コマンドです。コマンド出力の最初の行がパスワードとして使用されます。パフォーマンスを向上させるために、{EXTC[:expiration_in_millis]}
バリアントは、指定されたミリ秒数の間パスワードをキャッシュします。デフォルトでは、キャッシュされたパスワードは期限切れになりません。値0
(ゼロ) が指定されている場合、キャッシュされた資格情報は期限切れになりません。TheEXTC
バリアントは、LdapExtended
ログインモジュール。
例18.22 外部コマンドからパスワードを取得する
{EXT}cat /mysecretpasswordfile
例18.23 外部ファイルからパスワードを取得し、500 ミリ秒キャッシュします
{EXTC:500}cat /mysecretpasswordfile
18.3.2. カスタムモジュール
AuthenticationManager
は、Subject
プリンシパルの特定の使用パターンを必要とします。AuthenticationManager
と動作するログインモジュールを作成するには、JAAS Subject クラスの情報ストレージ機能と、これらの機能の想定される使用方法を完全に理解する必要があります。
LoginModule
実装を紹介します。
サブジェクト
に関連付けられたセキュリティー情報を取得できます。
java.util.Set getPrincipals() java.util.Set getPrincipals(java.lang.Class c) java.util.Set getPrivateCredentials() java.util.Set getPrivateCredentials(java.lang.Class c) java.util.Set getPublicCredentials() java.util.Set getPublicCredentials(java.lang.Class c)
サブジェクト
ID とロールについては、EAP が最も論理的な選択肢を選択しました 。getPrincipals ()
および getPrincipals (java.lang.Class)
を介して取得されたプリンシパルセットです。使用パターンは次のとおりです。
- ユーザー ID(たとえば、ユーザー名、社会保障番号、従業員 ID) は、
サブジェクト
プリンシパル
セットにjava.security.Principal
オブジェクトとして格納されます。ユーザー ID を表すプリンシパル
の実装は、プリンシパルの名前に基づいて比較と同等性を確立する必要があります。適切な実装は、org.jboss.security.SimplePrincipal
クラスとして利用できます。他のプリンシパル
インスタンスは、必要に応じてサブジェクト
プリンシパル
セットに追加できます。 - 割り当てられたユーザーロールも
プリンシパル
セットに保存され、java.security.acl.Group
インスタンスを使用して名前付きロールセットにグループ化されます。Group
インターフェイスは、Principal
および/またはGroup
のコレクションを定義し、java.security.Principal
のサブインターフェイスです。 サブジェクト
には、任意の数のロールセットを割り当てることができます。
- EAP セキュリティーフレームワークは、
Roles
とCallerPrincipal
という名前の 2 つのよく知られたロールセットを使用します。ロール
グループは、サブジェクト
が認証されたアプリケーションドメインで知られている名前付きロールのプリンシパル
のコレクションです。このロールセットは、EJBContext.isCallerInRole (String)
などのメソッドによって使用されます。EJB は、このメソッドを使用して、現在の呼び出し元が指定されたアプリケーションドメインロールに属しているかどうかを確認できます。メソッド権限チェックを実行するセキュリティーインターセプタロジックも、このロールセットを使用します。CallerPrincipal
グループ
は、アプリケーションドメインのユーザーに割り当てられた単一のプリンシパル
ID で設定されます。EJBContext.getCallerPrincipal ()
メソッドは、CallerPrincipal
を使用して、アプリケーションドメインが操作環境 ID からアプリケーションに適したユーザー ID にマップできるようにします。サブジェクト
にCallerPrincipalGroup
がない場合
、アプリケーション ID は運用環境 ID と同じです。
18.3.2.1. サブジェクト使用パターンのサポート
サブジェクト
の使用パターンの正しい実装を簡素化するため「カスタムモジュール」、EAP には、認証された サブジェクト
に正しい サブジェクト
の使用を強制するテンプレートパターンを入力するログインモジュールが含まれています。
AbstractServerLoginModule
2 つの中で最も一般的なのは、org.jboss.security.auth.spi.AbstractServerLoginModule
クラスです。
javax.security.auth.spi.LoginModule
インターフェイスの実装を提供し、運用環境のセキュリティーインフラストラクチャーに固有の主要なタスクのための抽象的なメソッドを提供します。クラスの重要な詳細は、例18.24「AbstractServerLoginModule クラスの一部」。JavaDoc コメントは、サブクラスの責任について詳しく説明しています。
loginOk
インスタンス変数は極めて重要です。ログインが成功した場合は true
に設定する必要があり、ログインメソッドをオーバーライドするサブクラスでは false
に設定する必要があります。この変数が正しく設定されていない場合、commit メソッドはサブジェクトを正しく更新しません。
例18.24 AbstractServerLoginModule クラスの一部
package org.jboss.security.auth.spi; /** * This class implements the common functionality required for a JAAS * server-side LoginModule and implements the PicketBox standard * Subject usage pattern of storing identities and roles. Subclass * this module to create your own custom LoginModule and override the * login(), getRoleSets(), and getIdentity() methods. */ public abstract class AbstractServerLoginModule implements javax.security.auth.spi.LoginModule { protected Subject subject; protected CallbackHandler callbackHandler; protected Map sharedState; protected Map options; protected Logger log; /** Flag indicating if the shared credential should be used */ protected boolean useFirstPass; /** * Flag indicating if the login phase succeeded. Subclasses that * override the login method must set this to true on successful * completion of login */ protected boolean loginOk; // ... /** * Initialize the login module. This stores the subject, * callbackHandler and sharedState and options for the login * session. Subclasses should override if they need to process * their own options. A call to super.initialize(...) must be * made in the case of an override. * * <p> * The options are checked for the <em>password-stacking</em> parameter. * If this is set to "useFirstPass", the login identity will be taken from the * <code>javax.security.auth.login.name</code> value of the sharedState map, * and the proof of identity from the * <code>javax.security.auth.login.password</code> value of the sharedState map. * * @param subject the Subject to update after a successful login. * @param callbackHandler the CallbackHandler that will be used to obtain the * the user identity and credentials. * @param sharedState a Map shared between all configured login module instances * @param options the parameters passed to the login module. */ public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { // ... } /** * Looks for javax.security.auth.login.name and * javax.security.auth.login.password values in the sharedState * map if the useFirstPass option was true and returns true if * they exist. If they do not or are null this method returns * false. * Note that subclasses that override the login method * must set the loginOk var to true if the login succeeds in * order for the commit phase to populate the Subject. This * implementation sets loginOk to true if the login() method * returns true, otherwise, it sets loginOk to false. */ public boolean login() throws LoginException { // ... } /** * Overridden by subclasses to return the Principal that * corresponds to the user primary identity. */ abstract protected Principal getIdentity(); /** * Overridden by subclasses to return the Groups that correspond * to the role sets assigned to the user. Subclasses should * create at least a Group named "Roles" that contains the roles * assigned to the user. A second common group is * "CallerPrincipal," which provides the application identity of * the user rather than the security domain identity. * * @return Group[] containing the sets of roles */ abstract protected Group[] getRoleSets() throws LoginException; }
UsernamePasswordLoginModule
カスタムログインモジュールに適した 2 番目の抽象ベースログインモジュールは、org.jboss.security.auth.spi.UsernamePasswordLoginModule
です。
char
パスワードを認証資格情報として適用することにより、カスタムログインモジュールの実装をさらに簡素化します。また、匿名ユーザー (null のユーザー名とパスワードで示される) のロールのないプリンシパルへのマッピングもサポートします。クラスの重要な詳細は、次のクラスフラグメントで強調表示されています。JavaDoc コメントは、サブクラスの責任について詳しく説明しています。
例18.25 UsernamePasswordLoginModule クラスの一部
package org.jboss.security.auth.spi; /** * An abstract subclass of AbstractServerLoginModule that imposes a * an identity == String username, credentials == String password * view on the login process. Subclasses override the * getUsersPassword() and getUsersRoles() methods to return the * expected password and roles for the user. */ public abstract class UsernamePasswordLoginModule extends AbstractServerLoginModule { /** The login identity */ private Principal identity; /** The proof of login identity */ private char[] credential; /** The principal to use when a null username and password are seen */ private Principal unauthenticatedIdentity; /** * The message digest algorithm used to hash passwords. If null then * plain passwords will be used. */ private String hashAlgorithm = null; /** * The name of the charset/encoding to use when converting the * password String to a byte array. Default is the platform's * default encoding. */ private String hashCharset = null; /** The string encoding format to use. Defaults to base64. */ private String hashEncoding = null; // ... /** * Override the superclass method to look for an * unauthenticatedIdentity property. This method first invokes * the super version. * * @param options, * @option unauthenticatedIdentity: the name of the principal to * assign and authenticate when a null username and password are * seen. */ public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { super.initialize(subject, callbackHandler, sharedState, options); // Check for unauthenticatedIdentity option. Object option = options.get("unauthenticatedIdentity"); String name = (String) option; if (name != null) { unauthenticatedIdentity = new SimplePrincipal(name); } } // ... /** * A hook that allows subclasses to change the validation of the * input password against the expected password. This version * checks that neither inputPassword or expectedPassword are null * and that inputPassword.equals(expectedPassword) is true; * * @return true if the inputPassword is valid, false otherwise. */ protected boolean validatePassword(String inputPassword, String expectedPassword) { if (inputPassword == null || expectedPassword == null) { return false; } return inputPassword.equals(expectedPassword); } /** * Get the expected password for the current username available * via the getUsername() method. This is called from within the * login() method after the CallbackHandler has returned the * username and candidate password. * * @return the valid password String */ abstract protected String getUsersPassword() throws LoginException; }
ログインモジュールのサブクラス化
AbstractServerLoginModule
と UsernamePasswordLoginModule
のサブクラスの選択は、ログインモジュールを作成する認証テクノロジーで文字列ベースのユーザー名と資格情報を使用できるかどうかに基づいています。文字列ベースのセマンティクスが有効な場合は、UsernamePasswordLoginModule
をサブクラス化し、そうでない場合は、AbstractServerLoginModule
をサブクラス化します。
サブクラス化の手順
カスタムログインモジュールが実行する必要のある手順は、選択した基本ログインモジュールクラスによって異なります。セキュリティーインフラストラクチャーと統合するカスタムログインモジュールを作成するときは、AbstractServerLoginModule
または UsernamePasswordLoginModule
をサブクラス化して、ログインモジュールが EAP セキュリティーマネージャーが期待する形式で認証された プリンシパル
情報を提供するようにする必要があります。
AbstractServerLoginModule
をサブクラス化するときは、以下をオーバーライドする必要があります。
void initialize (Subject、CallbackHandler、Map、Map)
: 解析するカスタムオプションがある場合。boolean login ()
: 認証アクティビティーを実行します。ログインが成功した場合はloginOk
インスタンス変数を true に設定し、失敗した場合は false に設定してください。Principal getIdentity ()
:log ()
ステップによって認証されたユーザーのPrincipal
オブジェクトを返します。Group getRoleSets ()
:login ()
中に認証されたプリンシパル
に割り当てられたロールを含むRoles
という名前のグループ
を少なくとも 1 つ返します。2 番目の共通グループ
はCallerPrincipal
という名前で、セキュリティードメイン ID ではなくユーザーのアプリケーション ID を提供します。
UsernamePasswordLoginModule
をサブクラス化するときは、以下をオーバーライドする必要があります。
void initialize (Subject、CallbackHandler、Map、Map)
: 解析するカスタムオプションがある場合。Group getRoleSets ()
:login ()
中に認証されたプリンシパル
に割り当てられたロールを含むRoles
という名前のグループ
を少なくとも 1 つ返します。2 番目の共通グループ
はCallerPrincipal
という名前で、セキュリティードメイン ID ではなくユーザーのアプリケーション ID を提供します。String getUsersPassword ()
:getUsername ()
メソッドを介して使用可能な現在のユーザー名の予想されるパスワードを返します。getUsersPassword ()
メソッドは、callbackhandler
がユーザー名と候補パスワードを返した後、login ()
内から呼び出されます。
18.3.2.2. カスタム LoginModule の例
UsernamePasswordLoginModule
を拡張し、JNDI ルックアップからユーザーのパスワードとロール名を取得するカスタムログインモジュールの例を作成するのに役立ちます。
password/<username>
という形式の名前 (<username>
は現在のユーザー) を使用してコンテキストを検索すると、ユーザーのパスワードを返すカスタム JNDI コンテキストログインモジュールを作成します。認証されている)。同様に、roles/<username>
の形式を検索すると、要求されたユーザーのロールが返されます。の例18.26「JndiUserAndPassLoginModule Custom Login Module」JndiUserAndPassLoginModule
カスタムログインモジュールのソースコードです。
JBossUsernamePasswordLoginModule
を拡張するため、JndiUserAndPassLoginModule
は JNDI ストアからユーザーのパスワードとロールを取得することに注意してください。JndiUserAndPassLoginModule
は、JAASLoginModule 操作と相互作用しません。
例18.26 JndiUserAndPassLoginModule Custom Login Module
package org.jboss.book.security.ex2; import java.security.acl.Group; import java.util.Map; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.LoginException; import org.jboss.logging.Logger; import org.jboss.security.SimpleGroup; import org.jboss.security.SimplePrincipal; import org.jboss.security.auth.spi.UsernamePasswordLoginModule; /** * An example custom login module that obtains passwords and roles for a user from a JNDI lookup. * * @author Scott.Stark@jboss.org */ public class JndiUserAndPassLoginModule extends UsernamePasswordLoginModule { /** The JNDI name to the context that handles the password/username lookup */ private String userPathPrefix; /** The JNDI name to the context that handles the roles/username lookup */ private String rolesPathPrefix; private static Logger log = Logger.getLogger(JndiUserAndPassLoginModule.class); /** * Override to obtain the userPathPrefix and rolesPathPrefix options. */ @Override public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { super.initialize(subject, callbackHandler, sharedState, options); userPathPrefix = (String) options.get("userPathPrefix"); rolesPathPrefix = (String) options.get("rolesPathPrefix"); } /** * Get the roles the current user belongs to by querying the rolesPathPrefix + '/' + super.getUsername() JNDI location. */ @Override protected Group[] getRoleSets() throws LoginException { try { InitialContext ctx = new InitialContext(); String rolesPath = rolesPathPrefix + '/' + super.getUsername(); String[] roles = (String[]) ctx.lookup(rolesPath); Group[] groups = { new SimpleGroup("Roles") }; log.info("Getting roles for user=" + super.getUsername()); for (int r = 0; r < roles.length; r++) { SimplePrincipal role = new SimplePrincipal(roles[r]); log.info("Found role=" + roles[r]); groups[0].addMember(role); } return groups; } catch (NamingException e) { log.error("Failed to obtain groups for user=" + super.getUsername(), e); throw new LoginException(e.toString(true)); } } /** * Get the password of the current user by querying the userPathPrefix + '/' + super.getUsername() JNDI location. */ @Override protected String getUsersPassword() throws LoginException { try { InitialContext ctx = new InitialContext(); String userPath = userPathPrefix + '/' + super.getUsername(); log.info("Getting password for user=" + super.getUsername()); String passwd = (String) ctx.lookup(userPath); log.info("Found password=" + passwd); return passwd; } catch (NamingException e) { log.error("Failed to obtain password for user=" + super.getUsername(), e); throw new LoginException(e.toString(true)); } } }
例18.27 セキュリティーの定義 - 新しく作成されたカスタムログインモジュールを使用した ex2 セキュリティードメイン
/subsystem=security/security-domain=security-ex2/:add /subsystem=security/security-domain=security-ex2/authentication=classic:add /subsystem=security/security-domain=security-ex2/authentication=classic/login-module=ex2/:add(\ flag=required,\ code=org.jboss.book.security.ex2.JndiUserAndPassLoginModule,\ module-options=[("userPathPrefix"=>"/security/store/password"),\ ("rolesPathPrefix"=>"/security/store/roles")]\ )
JndiUserAndPassLoginModule
カスタムログインモジュールを使用するかどうかは、セキュリティードメインの例のログイン設定によって決まります。EJB JAR META-INF/jboss-ejb3.xml
記述子は、セキュリティードメインを設定します。Web アプリケーションの場合、これは WEB-INF/jboss-web.xml
ファイルの一部です。
例18.28 jboss-ejb3.xml の
例
<?xml version="1.0"?> <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:s="urn:security" version="3.1" impl-version="2.0"> <assembly-descriptor> <s:security> <ejb-name>*</ejb-name> <s:security-domain>security-ex2</s:security-domain> </s:security> </assembly-descriptor> </jboss:ejb-jar>
例18.29 jboss-web.xml example
<?xml version="1.0"?> <jboss-web> <security-domain>security-ex2</security-domain> </jboss-web>
18.4. EJB アプリケーションセキュリティー
18.4.1. セキュリティーアイデンティティー
18.4.1.1. EJB セキュリティーアイデンティティー
18.4.1.2. EJB のセキュリティーアイデンティティーの設定
<security-identity>
タグで指定します。
<security-identity>
タグが存在しない場合、EJB 自身の呼び出し元 ID が使用されます。
例18.30 EJB のセキュリティーアイデンティティーの呼び出し元と同じ値への設定
<security-identity>
要素の宣言を指定しない場合は、この動作がデフォルトになります。
<ejb-jar> <enterprise-beans> <session> <ejb-name>ASessionBean</ejb-name> <!-- ... --> <security-identity> <use-caller-identity/> </security-identity> </session> <!-- ... --> </enterprise-beans> </ejb-jar>
例18.31 EJB のセキュリティーアイデンティティーの特定のロールへの設定
<security-identity>
タグ内の <run-as>
と <role-name>
タグを使用します。
<ejb-jar> <enterprise-beans> <session> <ejb-name>RunAsBean</ejb-name> <!-- ... --> <security-identity> <run-as> <description>A private internal role</description> <role-name>InternalRole</role-name> </run-as> </security-identity> </session> </enterprise-beans> <!-- ... --> </ejb-jar>
<run-as>
を使用すると、anonymous
という名前のプリンシパルが発信呼び出しに割り当てられます。異なるプリンシパルを割り当てるには、<run-as-principal>
を使用します。
<session> <ejb-name>RunAsBean</ejb-name> <security-identity> <run-as-principal>internal</run-as-principal> </security-identity> </session>
<run-as>
および <run-as-principal>
要素を使用することもできます。
以下も参照してください。
18.4.2. EJB メソッドパーミッション
18.4.2.1. EJB メソッドパーミッションについて
<method-permission>
要素の宣言は、EJB のインターフェイスメソッドを呼び出すことができるロールを指定します。以下の組み合わせのパーミッションを指定できます。
- 名前付き EJB のすべてのホームおよびコンポーネントインターフェースメソッド
- 名前付き EJB のホームまたはコンポーネントインターフェースの指定メソッド
- オーバーロード名を持つ一連のメソッドに指定されたメソッド
18.4.2.2. EJB メソッドパーミッションの使用
概要
<method-permission>
要素は、<method>
要素で定義される EJB メソッドへのアクセスを許可される論理ロールを定義します。複数の例は、XML の構文を示しています。複数のメソッドパーミッションステートメントが存在する可能性があり、それらのステートメントには累積的影響があります。<method-permission>
要素は、<ejb-jar>
記述子の <assembly-descriptor>
要素の子です。
例18.32 ロールに対する EJB の全メソッドへのアクセスの許可
<method-permission> <description>The employee and temp-employee roles may access any method of the EmployeeService bean </description> <role-name>employee</role-name> <role-name>temp-employee</role-name> <method> <ejb-name>EmployeeService</ejb-name> <method-name>*</method-name> </method> </method-permission>
例18.33 ロールが EJB の特定のメソッドにのみアクセスできるようにし、渡すことができるメソッドパラメーターを制限します。
<method-permission> <description>The employee role may access the findByPrimaryKey, getEmployeeInfo, and the updateEmployeeInfo(String) method of the AcmePayroll bean </description> <role-name>employee</role-name> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>findByPrimaryKey</method-name> </method> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>getEmployeeInfo</method-name> </method> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>updateEmployeeInfo</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </method> </method-permission>
例18.34 任意の認証されたユーザーによる EJB のメソッドへのアクセスの許可
<unchecked/>
要素を使用すると、認証されたユーザーが指定されたメソッドを使用できます。
<method-permission> <description>Any authenticated user may access any method of the EmployeeServiceHelp bean</description> <unchecked/> <method> <ejb-name>EmployeeServiceHelp</ejb-name> <method-name>*</method-name> </method> </method-permission>
例18.35 特定の EJB メソッドの使用を完全に除外します
<exclude-list> <description>No fireTheCTO methods of the EmployeeFiring bean may be used in this deployment</description> <method> <ejb-name>EmployeeFiring</ejb-name> <method-name>fireTheCTO</method-name> </method> </exclude-list>
例18.36 複数の <method-permission>
ブロックを含む完全な <assembly-descriptor>
<ejb-jar> <assembly-descriptor> <method-permission> <description>The employee and temp-employee roles may access any method of the EmployeeService bean </description> <role-name>employee</role-name> <role-name>temp-employee</role-name> <method> <ejb-name>EmployeeService</ejb-name> <method-name>*</method-name> </method> </method-permission> <method-permission> <description>The employee role may access the findByPrimaryKey, getEmployeeInfo, and the updateEmployeeInfo(String) method of the AcmePayroll bean </description> <role-name>employee</role-name> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>findByPrimaryKey</method-name> </method> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>getEmployeeInfo</method-name> </method> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>updateEmployeeInfo</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </method> </method-permission> <method-permission> <description>The admin role may access any method of the EmployeeServiceAdmin bean </description> <role-name>admin</role-name> <method> <ejb-name>EmployeeServiceAdmin</ejb-name> <method-name>*</method-name> </method> </method-permission> <method-permission> <description>Any authenticated user may access any method of the EmployeeServiceHelp bean</description> <unchecked/> <method> <ejb-name>EmployeeServiceHelp</ejb-name> <method-name>*</method-name> </method> </method-permission> <exclude-list> <description>No fireTheCTO methods of the EmployeeFiring bean may be used in this deployment</description> <method> <ejb-name>EmployeeFiring</ejb-name> <method-name>fireTheCTO</method-name> </method> </exclude-list> </assembly-descriptor> </ejb-jar>
18.4.3. EJB セキュリティーアノテーション
18.4.3.1. EJB セキュリティーアノテーションについて
javax.annotation.security
アノテーションは JSR-250 で定義されます。
- @DeclareRoles
- 利用可能なロールを宣言します。
- @RunAs
- コンポーネントの伝播セキュリティーアイデンティティーを設定します。
18.4.3.2. EJB セキュリティーアノテーションの使用
概要
XML 記述子またはアノテーションのいずれかを使用して、Enterprise JavaBean (EJB) でメソッドを呼び出すことのできるセキュリティーロールを制御できます。XML 記述子の使用については、「EJB メソッドパーミッションの使用」 を参照してください。
EJB のセキュリティーパーミッションを制御するアノテーション
- @DeclareRoles
- @DeclareRoles を使用して、パーミッションをチェックするセキュリティーロールを定義します。@DeclareRoles がない場合、一覧は @RolesAllowed アノテーションから自動的にビルドされます。ロールの設定に関する詳細は、『Java EE 6 チュートリアル』 Specifying Authorized Users by Declaring Security Roles を参照してください。
- @RolesAllowed, @PermitAll, @DenyAll
- 使用する
@RolesAllowed
1 つまたは複数のメソッドへのアクセスが許可されているロールを一覧表示します。使用する@PermitAll
また@DenyAll
1 つまたは複数のメソッドの使用からすべてのロールを許可または拒否します。アノテーションメソッドのパーミッション設定に関する詳細は、『Java EE 6 チュートリアル』 Specifying Authorized Users by Declaring Security Roles を参照してください。 - @RunAs
@RunAs
を使用して、アノテーション付きのメソッドから呼び出しを行うときにメソッドが使用するロールを指定します。アノテーションを使用してセキュリティーアイデンティティーを伝播する方法は、『Java EE 6 チュートリアル』 Propagating a Security Identity (Run-As) を参照してください。
例18.37 セキュリティー注釈の例
@Stateless @RolesAllowed({"admin"}) @SecurityDomain("other") public class WelcomeEJB implements Welcome { @PermitAll public String WelcomeEveryone(String msg) { return "Welcome to " + msg; } @RunAs("tempemployee") public String GoodBye(String msg) { return "Goodbye, " + msg; } public String GoodbyeAdmin(String msg) { return "See you later, " + msg; } }
WelcomeEveryone
。TheGoodBye
メソッドはを使用しますtempemployee
電話をかけるときのロール。のみadmin
ロールはメソッドにアクセスできますGoodbyeAdmin
、およびセキュリティーアノテーションのないその他のメソッド。
18.4.4. EJB へのリモートアクセス
18.4.4.1. リモートメソッドアクセスについて
サポートされているトランスポートタイプ
- ソケット/セキュアソケット
- RMI/RMI over SSL
- HTTP / HTTPS
- サーブレット/セキュアサーブレット
- Bisocket/Secure Bisocket
データマーシャリング
リモーティングシステムは、データマーシャリングおよびアンマーシャリングサービスも提供します。データマーシャリングとは、ネットワークとプラットフォームの境界を越えてデータを安全に移動し、別のシステムがデータに対して作業を実行できるようにする機能を指します。その後、作業は元のシステムに送り返され、ローカルで処理されたかのように動作します。
アーキテクチャーの概要
Remoting を使用するクライアントアプリケーションを設計するときは、URL タイプ形式の単純な文字列である InvokerLocator
と呼ばれる特別なタイプのリソースロケーターを使用するようにアプリケーションを設定することにより、サーバーと通信するようにアプリケーションに指示します。サーバーは、リモーティング
サブシステムの一部として設定されている コネクター
でリモートリソースの要求をリッスンします。コネクター
は、設定された ServerInvocationHandler
に要求を渡します。各 ServerInvocationHandler
はメソッドを実装しますinvoke(InvocationRequest)
、リクエストの処理方法を知っています。
JBossRemotingFramework レイヤー
- ユーザーは外層と対話します。クライアント側では、外層は
Client
クラス。呼び出し要求を送信します。サーバー側では、ユーザーによって実装され、呼び出し要求を受け取るのは InvocationHandler です。 - トランスポートは、呼び出し側レイヤーによって制御されます。
- 最下層には、データ形式をワイヤ形式に変換するマーシャラーとアンマーシャラーが含まれています。
18.4.4.2. コールバックのリモート処理について
InvocationRequest
クライアントに。サーバー側のコードは、コールバックが同期であるか非同期であるかに関係なく、同じように機能します。クライアントだけが違いを知る必要があります。サーバーの InvocationRequest はresponseObject
クライアントに。これは、クライアントが要求したペイロードです。これは、リクエストまたはイベント通知への直接の応答である可能性があります。
m_listeners
物体。サーバーハンドラーに追加されたすべてのリスナーのリストが含まれています。TheServerInvocationHandler
インターフェイスには、このリストを管理できるメソッドが含まれています。
org.jboss.remoting.InvokerCallbackHandler
、コールバックデータを処理します。コールバックハンドラーを実装した後、プルコールバックのリスナーとして自分自身を追加するか、プッシュコールバックのコールバックサーバーを実装します。
コールバックをプル
プルコールバックの場合、クライアントは、を使用してサーバーのリスナーのリストに自分自身を追加します。Client.addListener()
方法。次に、コールバックデータの同期配信のためにサーバーを定期的にポーリングします。このポーリングは、Client.getCallbacks()
。
プッシュコールバック
プッシュコールバックでは、クライアントアプリケーションが独自の InvocationHandler を実行する必要があります。これを行うには、クライアント自体で Remoting サービスを実行する必要があります。これは、コールバックサーバー と呼ばれます。コールバックサーバーは着信要求を非同期で受け入れ、要求者 (この場合はサーバー) のためにそれらを処理します。クライアントのコールバックサーバーをメインサーバーに登録するには、コールバックサーバーのInvokerLocator
の 2 番目の引数としてaddListener
方法。
18.4.4.3. リモーティングサーバー検出について
18.4.4.4. リモーティングサブシステムを設定する
概要
JBoss Remoting には、3 つのトップレベルの設定可能な要素があります。ワーカースレッドプール、1 つ以上のコネクター、および一連のローカルおよびリモート接続 URI です。このトピックでは、設定可能な各項目の説明、各項目を設定する方法の CLI コマンドの例、および完全に設定されたサブシステムの XML の例を示します。この設定はサーバーにのみ適用されます。独自のアプリケーションにカスタムコネクターを使用する場合を除き、Remoting のサブシステムの設定は必要でないことがほとんどです。EJB などの、リモーティングクライアントとして動作するアプリケーションには特定のコネクターに接続するための別の設定が必要になります。
CLI コマンドの適応
CLI コマンドは、デフォルト
のプロファイルを設定するときに、管理対象ドメイン用に作成されます。別のプロファイルを設定するには、その名前に置き換えます。スタンドアロンサーバーの場合、コマンドの /profile=default
部分を省略します。
リモーティングサブシステム外の設定
リモーティング
サブシステムの外部にあるいくつかの設定の側面があります。
- ネットワークインターフェース
リモーティング
サブシステムで使用されるネットワークインターフェイスは、domain/configuration/domain.xml
またはstandalone/configuration/standalone.xml
で定義されているパブリック
インターフェイスです。<interfaces> <interface name="management"/> <interface name="public"/> <interface name="unsecure"/> </interfaces>
パブリック
インターフェイスのホストごとの定義は、domain.xml
またはstandalone.xml
と同じディレクトリーのhost.xml
で定義されます。このインターフェイスは、他のいくつかのサブシステムでも使用されます。変更するときは注意してください。<interfaces> <interface name="management"> <inet-address value="${jboss.bind.address.management:127.0.0.1}"/> </interface> <interface name="public"> <inet-address value="${jboss.bind.address:127.0.0.1}"/> </interface> <interface name="unsecure"> <!-- Used for IIOP sockets in the standard configuration. To secure JacORB you need to setup SSL --> <inet-address value="${jboss.bind.address.unsecure:127.0.0.1}"/> </interface> </interfaces>
- socket-binding
remoting
サブシステムによって使用されるデフォルトのソケットバインディングは TCP ポート 4447 にバインドされます。これを変更する必要がある場合の詳細は、ソケットバインディングとソケットバインディンググループに関するドキュメントを参照してください。ソケットバインディングおよびソケットバインディンググループに関する情報は、JBoss EAP の 『管理および設定ガイド』 の 『ソケットバインディンググループ』 の章にあります。 https://access.redhat.com/documentation/ja-jp/red_hat_jboss_enterprise_application_platform/?version=6.4- EJB の リモーティングコネクター参照
- EJB サブシステムにはリモートメソッド呼び出しに対するリモーティングコネクターへの参照が含まれています。デフォルト設定は次のとおりです。
<remote connector-ref="remoting-connector" thread-pool-name="default"/>
- セキュアなトランスポート設定
- リモーティングトランスポートはクライアントの要求があれば StartTLS を使用してセキュアな接続 (HTTPS、Secure Servlet など) を使用します。セキュアな接続とセキュアでない接続の両方で同じソケットバインディング (ネットワークポート) が使用されるため、サーバー側に追加の設定をする必要はありません。クライアントは必要に応じてセキュアなトランスポートまたはセキュアでないトランスポートを要求します。EJB、ORB、JMS プロバイダーなどのリモーティングを使用する JBoss EAP 6 のコンポーネントはデフォルトでセキュアなインターフェイスを使用します。
ワーカースレッドプール
ワーカースレッドプールは、Remoting コネクターを介して入ってくる作業を処理するために使用できるスレッドのグループです。これは単一の要素 <worker-thread-pool>
であり、いくつかの属性を取ります。ネットワークタイムアウトが発生した場合、スレッドが不足した場合、またはメモリー使用量を制限する必要がある場合は、これらの属性を調整してください。具体的な推奨事項は、特定の状況によって異なります。詳細は Red Hat グローバルサポートサービスまでお問い合わせください。
表18.2 ワーカースレッドプールの属性
属性 | 説明 | CLI コマンド |
---|---|---|
読み取りスレッド |
リモーティングワーカーに対して作成する読み取りスレッドの数。デフォルトは
1 です。
| /profile=default/subsystem=remoting/:write-attribute(name=worker-read-threads,value=1)
|
write-threads |
リモーティングワーカーに作成する書き込みスレッドの数。デフォルトは
1 です。
| /profile=default/subsystem=remoting/:write-attribute(name=worker-write-threads,value=1)
|
task-keepalive |
コアでないリモーティングワーカーのタスクスレッドにキープアライブを使用する期間 (ミリ秒単位)。デフォルトは
60 です。
| /profile=default/subsystem=remoting/:write-attribute(name=worker-task-keepalive,value=60)
|
task-max-threads |
リモーティングワーカーのタスクスレッドプールに対するスレッドの最大数。デフォルトは
16 です。
| /profile=default/subsystem=remoting/:write-attribute(name=worker-task-max-threads,value=16)
|
task-core-threads |
リモーティングワーカーのタスクスレッドプールに対するコアスレッドの数。デフォルトは
4 です。
| /profile=default/subsystem=remoting/:write-attribute(name=worker-task-core-threads,value=4)
|
task-limit |
許可するリモーティングワーカータスクの最大数。 この数を超えるリモーティングワーカータスクは拒否されます。デフォルトは
16384 です。
| /profile=default/subsystem=remoting/:write-attribute(name=worker-task-limit,value=16384)
|
コネクター
コネクターは主な Remoting 設定要素です。複数のコネクターを設定できます。それぞれは、いくつかのサブ要素といくつかの可能な属性を持つ要素 <connector>
要素で設定されています。デフォルトのコネクターは複数の JBoss EAP 6 サブシステムによって使用されます。カスタムコネクターの要素や属性の設定はアプリケーションによって異なるため、詳細は Red Hat グローバルサポートサービスまでご連絡ください。
表18.3 コネクターの属性
属性 | 説明 | CLI コマンド |
---|---|---|
socket-binding | このコネクターに使用するソケットバインディングの名前。 | /profile = default/subsystem = remoteing/connectedor = remoteing-connector/:write-attribute (name = socket-binding、value = remoteing)
|
authentication-provider |
このコネクターで使用するコンテナー用 Java 認証サービスプロバイダーインターフェイス (JASPIC) モジュール。モジュールはクラスパスに含まれている必要があります。
| /profile = default/subsystem = remoteing/connectedor = remoteing-connector/:write-attribute (name = authentication-provider、value = myProvider)
|
security-realm |
任意。アプリケーションのユーザー、パスワード、およびロールを含むセキュリティーレルム。EJB または Web アプリケーションは、セキュリティーレルムに対して認証できます。
ApplicationRealm は、デフォルトの JBoss EAP 6 インストールで使用できます。
| /profile = default/subsystem = remoteing/connectedor = remoteing-connector/:write-attribute (name = security-realm、value = ApplicationRealm)
|
表18.4 コネクター要素
属性 | 説明 | CLI コマンド |
---|---|---|
sasl |
Simple Authentication and Security Layer (SASL) 認証メカニズムの囲み要素
| 該当なし
|
properties |
1 つ以上の
<property> 要素が含まれ、それぞれに name 属性とオプションの value 属性があります。
| /profile = default/subsystem = remoteing/connectedor = remoteing-connector/property = myProp/:add (value = myPropValue)
|
送信接続
3 つのタイプのアウトバウンド接続を指定することができます。
- STF へのアウトバウンド接続
- ソケットなどのローカルリソースに接続するローカルアウトバウンド接続
- リモートリソースに接続し、セキュリティーレルムを使用して認証を行うリモートアウトバウンド接続
<outbound-connections>
要素で囲まれています。これらの各接続タイプは、outbound-socket-binding-ref
属性を取ります。アウトバウンド接続は uri
属性を取ります。リモートアウトバウンド接続は、オプションの ユーザー名
と セキュリティーレルム
属性を使用して承認に使用します。
表18.5 アウトバウンド接続要素
属性 | 説明 | CLI コマンド |
---|---|---|
outbound-connection | 一般的なアウトバウンド接続。 | /profile = default/subsystem = remoting/outbound-connection = my-connection/:add (uri = http://my-connection)
|
local-outbound-connection | 暗黙の local://URI スキームを使用したアウトバウンド接続。 | /profile = default/subsystem = remoteing/local-outbound-connection = my-connection/:add (outbound-socket-binding-ref = remoteing2)
|
remote-outbound-connection |
セキュリティーレルムで基本/ダイジェスト認証を使用する、remote://URI スキームのアウトバウンド接続。
| /profile = default/subsystem = remoteing/remote-outbound-connection = my-connection/:add (outbound-socket-binding-ref = remoteing、username = myUser、security-realm = ApplicationRealm)
|
SASL 要素
SASL 子要素を定義する前に、最初の SASL 要素を作成する必要があります。以下のコマンドを使用します。
/profile=default/subsystem=remoting/connector=remoting-connector/security=sasl:add
表18.6 SASL 子要素
属性 | 説明 | CLI コマンド |
---|---|---|
include-mechanisms |
SASL メカニズムのリストである
value 属性が含まれています。
|
/profile=default/subsystem=remoting/connector=remoting-connector/security=sasl:write-attribute(name=include-mechanisms,value=["DIGEST","PLAIN","GSSAPI"]) |
qop |
優先度の高い順に、SASL の保護品質値のリストである
value 属性が含まれています。
|
/profile=default/subsystem=remoting/connector=remoting-connector/security=sasl:write-attribute(name=qop,value=["auth"]) |
strength |
優先度の高い順に、SASL 暗号強度値のリストである
value 属性が含まれています。
|
/profile=default/subsystem=remoting/connector=remoting-connector/security=sasl:write-attribute(name=strength,value=["medium"]) |
reuse-session |
ブール値である
value 属性が含まれています。true の場合、セッションの再利用を試みます。
|
/profile=default/subsystem=remoting/connector=remoting-connector/security=sasl:write-attribute(name=reuse-session,value=false) |
server-auth |
ブール値である
value 属性が含まれています。true の場合、サーバーはクライアントに対して認証を行います。
|
/profile=default/subsystem=remoting/connector=remoting-connector/security=sasl:write-attribute(name=server-auth,value=false) |
policy |
以下の要素を 0 個以上含む囲み要素。それぞれが単一の
値 を取ります。
|
/profile=default/subsystem=remoting/connector=remoting-connector/security=sasl/sasl-policy=policy:add /profile=default/subsystem=remoting/connector=remoting-connector/security=sasl/sasl-policy=policy:write-attribute(name=forward-secrecy,value=true) /profile=default/subsystem=remoting/connector=remoting-connector/security=sasl/sasl-policy=policy:write-attribute(name=no-active,value=false) /profile=default/subsystem=remoting/connector=remoting-connector/security=sasl/sasl-policy=policy:write-attribute(name=no-anonymous,value=false) /profile=default/subsystem=remoting/connector=remoting-connector/security=sasl/sasl-policy=policy:write-attribute(name=no-dictionary,value=true) /profile=default/subsystem=remoting/connector=remoting-connector/security=sasl/sasl-policy=policy:write-attribute(name=no-plain-text,value=false) /profile=default/subsystem=remoting/connector=remoting-connector/security=sasl/sasl-policy=policy:write-attribute(name=pass-credentials,value=true) |
properties |
1 つ以上の
<property> 要素が含まれ、それぞれに name 属性とオプションの value 属性があります。
|
/profile=default/subsystem=remoting/connector=remoting-connector/security=sasl/property=myprop:add(value=1) /profile=default/subsystem=remoting/connector=remoting-connector/security=sasl/property=myprop2:add(value=2) |
例18.38 設定例
<subsystem xmlns="urn:jboss:domain:remoting:1.1"> <connector name="remoting-connector" socket-binding="remoting" security-realm="ApplicationRealm"/> </subsystem>
<subsystem xmlns="urn:jboss:domain:remoting:1.1"> <worker-thread-pool read-threads="1" task-keepalive="60" task-max-threads="16" task-core-thread="4" task-limit="16384" write-threads="1" /> <connector name="remoting-connector" socket-binding="remoting" security-realm="ApplicationRealm"> <sasl> <include-mechanisms value="GSSAPI PLAIN DIGEST-MD5" /> <qop value="auth" /> <strength value="medium" /> <reuse-session value="false" /> <server-auth value="false" /> <policy> <forward-secrecy value="true" /> <no-active value="false" /> <no-anonymous value="false" /> <no-dictionary value="true" /> <no-plain-text value="false" /> <pass-credentials value="true" /> </policy> <properties> <property name="myprop1" value="1" /> <property name="myprop2" value="2" /> </properties> </sasl> <authentication-provider name="myprovider" /> <properties> <property name="myprop3" value="propValue" /> </properties> </connector> <outbound-connections> <outbound-connection name="my-outbound-connection" uri="http://myhost:7777/"/> <remote-outbound-connection name="my-remote-connection" outbound-socket-binding-ref="my-remote-socket" username="myUser" security-realm="ApplicationRealm"/> <local-outbound-connection name="myLocalConnection" outbound-socket-binding-ref="my-outbound-socket"/> </outbound-connections> </subsystem>
まだ文書化されていない設定の側面
- JNDI およびマルチキャスト自動検出
18.4.4.5. リモート EJB クライアントでのセキュリティーレルムの使用
- 新しいセキュリティーレルムをドメインコントローラーまたはスタンドアロンサーバーに追加します。
- アプリケーションのクラスパスにある
jboss-ejb-client.properties
ファイルに以下のパラメーターを追加します。この例では、接続がファイル内の他のパラメーターによってdefault
として参照されていることを前提としています。remote.connection.default.username=appuser remote.connection.default.password=apppassword
- 新しいセキュリティーレルムを使用するドメインまたはスタンドアロンサーバーでカスタムリモーティングコネクターを作成します。
- カスタムリモーティングコネクターでプロファイルを使用するよう設定されたサーバーグループに EJB を追加します。または管理対象ドメインを使用していない場合はスタンドアロンサーバーに EJB をデプロイします。
18.4.4.6. 新しいセキュリティーレルムの追加
管理 CLI を実行します。
jboss-cli.sh
またはjboss-cli.bat
コマンドを起動して、サーバーに接続します。新しいセキュリティーレルム自体を作成します。
以下のコマンドを実行し、ドメインコントローラーまたはスタンドアロンサーバーにMyDomainRealm
という名前の新しいセキュリティーレルムを作成します。ドメインインスタンスの場合は、以下のコマンドを使用します。/host=master/core-service=management/security-realm=MyDomainRealm:add()
スタンドアロンインスタンスの場合には、以下のコマンドを使用します。/core-service=management/security-realm=MyDomainRealm:add()
新規ロールに関する情報を格納するプロパティーファイルへの参照を作成します。
以下のコマンドを実行して、新しいロールに関連するプロパティーが含まれるmyfile.properties
ファイルへのポインターを作成します。注記新しく作成されたプロパティーファイルは、含まれるadd-user.sh
およびadd-user.bat
スクリプトでは管理されません。外部で管理する必要があります。ドメインインスタンスの場合は、以下のコマンドを使用します。/host=master/core-service=management/security-realm=MyDomainRealm/authentication=properties:add(path=myfile.properties)
スタンドアロンインスタンスの場合には、以下のコマンドを使用します。/core-service=management/security-realm=MyDomainRealm/authentication=properties:add(path=myfile.properties)
結果
新しいセキュリティーレルムが作成されます。この新しいレルムにユーザーおよびロールを追加すると、情報はデフォルトのセキュリティーレルムとは別のファイルに保存されます。この新しいファイルは、独自のアプリケーションまたは手順を使用して管理できます。
18.4.4.7. セキュリティーレルムへのユーザーの追加
add-user.sh
またはadd-user.bat
コマンドを実行します。ターミナルを開き、EAP_HOME/bin/
ディレクトリーに移動します。Red Hat Enterprise Linux またはその他の UNIX と同様のオペレーティングシステムを使用している場合には、add-user.sh
を実行します。Microsoft Windows Server を実行している場合は、add-user.bat
を実行します。管理ユーザーまたはアプリケーションユーザーを追加するかどうかを選択します。
この手順では、b
と入力してアプリケーションユーザーを追加します。ユーザーを追加するレルムを選択します。
デフォルトでは、利用可能なレルムはApplicationRealm
のみです。カスタムレルムを追加した場合は、代わりにその名前を入力できます。プロンプトが表示されたら、ユーザー名、パスワード、およびロールを入力します。
プロンプトが表示されたら、希望のユーザー名、パスワード、および任意のロールを入力します。yes
を入力して選択を確認するか、no
と入力して変更をキャンセルします。変更は、セキュリティーレルムの各プロパティーファイルに書き込まれます。
18.4.4.8. SSL 暗号化を使用したリモート EJB アクセス
18.5. JAX-RS アプリケーションセキュリティー
18.5.1. RESTEasy JAX-RS Web サービスのロールベースのセキュリティーの有効化
概要
RESTEasy は JAX-RS メソッドでの @RolesAllowed、@PermitAll、@DenyAll アノテーションに対応しています。ただし、デフォルトではこれらの注釈は認識されません。以下の手順に従って、web.xml
ファイルを設定し、ロールベースのセキュリティーを有効にします。
- resteasy.document.expand.entity.references
- resteasy.document.secure.processing.feature
- resteasy.document.secure.disableDTDs
手順18.5 RESTEasy JAX-RS Web サービスのロールベースのセキュリティーの有効化
- テキストエディターでアプリケーションの
web.xml
ファイルを開きます。 - 以下の <context-param> をファイルに、
web-app
内に追加します。<context-param> <param-name>resteasy.role.based.security</param-name> <param-value>true</param-value> </context-param>
- <security-role> タグを使用して、RESTEasy JAX-RS WAR ファイル内で使用されるすべてのロールを宣言します。
<security-role> <role-name>ROLE_NAME</role-name> </security-role> <security-role> <role-name>ROLE_NAME</role-name> </security-role>
- すべてのロールについて JAX-RS ランタイムによって処理されるすべての 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>
結果
ロールベースのセキュリティーは、定義されたロールとともにアプリケーション内で有効にされています。
例18.39 例: ロールベースのセキュリティー設定
<web-app> <context-param> <param-name>resteasy.role.based.security</param-name> <param-value>true</param-value> </context-param> <servlet-mapping> <servlet-name>Resteasy</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <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> <security-role> <role-name>admin</role-name> </security-role> <security-role> <role-name>user</role-name> </security-role> </web-app>
18.5.2. アノテーションを使用して JAX-RSWeb サービスを保護する
概要
このトピックでは、サポートされているセキュリティーアノテーションを使用して JAX-RSWeb サービスを保護する手順について説明します。
手順18.6 サポートされているセキュリティーアノテーションを使用して JAX-RSWeb サービスを保護する
- ロールベースセキュリティーを有効化します。詳細は、「RESTEasy JAX-RS Web サービスのロールベースのセキュリティーの有効化」 を参照してください。
- JAX-RS Web サービスにセキュリティーアノテーションを追加します。RESTEasy は以下のアノテーションをサポートします。
- @RolesAllowed
- メソッドにアクセスできるロールを定義します。すべてのロールは
web.xml
ファイルで定義する必要があります。 - @PermitAll
web.xml
ファイルに定義されているすべてのロールがメソッドにアクセスできるようにします。- @DenyAll
- メソッドへのすべてのアクセスを拒否します。
18.6. 機密性の高い文字列のパスワード vault
18.6.1. パスワード vault システム
18.6.2. パスワード Vault の設定と使用
手順18.7 パスワード Vault の設定および使用に関する基本的な手順
- Java キーストアを設定し、パスワード暗号化用のキーを格納します。キーストアの作成は、「機密性が高い文字列を格納する Java キーストアの作成」 を参照してください。。
- パスワード vault を初期化します。パスワードのマスキングとパスワード Vault の初期化については、「パスワード vault の初期化」 を参照してください。
- パスワード Vault に機密文字列を保存します。機密文字列をパスワード Vault に保存する方法については、「パスワード Vault に Sensitive 文字列を保存します。」 を参照してください。
- パスワード vault を使用するように JBoss EAP 6 を設定します。パスワード Vault を使用するように JBoss EAP 6 を設定する方法については、「パスワード vault を使用するよう JBoss EAP 6 を設定」 を参照してください。カスタム実装については、「パスワード Vault のカスタム実装を使用するよう JBoss EAP 6 を設定」 を参照してください注記暗号化した機密文字列を設定で使用する方法は、「暗号化した機密文字列を設定で使用」 を参照してください。アプリケーションで暗号化した機密文字列を使用する方法は、「アプリケーションで暗号化した機密文字列の使用」 を参照してください。パスワード Vault で機密文字列を確認するには、「機密文字列がパスワード vault 内にあるかどうかを確認します。」 を参照してください。パスワード Vault から機密文字列を削除するには、「パスワード vault からの機密文字列の削除」 を参照してください。
18.6.3. 外部ソースからのキーストアパスワードの取得
<vault-option name="KEYSTORE_PASSWORD" value="[here]"
- これは、そのまま使えるコマンドを参照します。ここでの
{EXT}...
は、実際のコマンドです。例:{EXT}/usr/bin/getmypassword --section 1 --query company
。/usr/bin/getmypassword
を実行すると、パスワードを標準出力に表示し、Security Vault のキーストアのパスワードとして使用します。この例では --section 1 と --query company のオプションを使用しています。 {EXTC[:expiration_in_millis]}...
: 実際のコマンドを参照します。ここでの、... は、プラットフォームコマンドを実行するために Runtime.exec(String) メソッドに渡される、実際のコマンドラインです。コマンド出力の最初の行がパスワードとして使用されます。EXTC バリアントは expiration_in_millis ミリ秒のパスワードをキャッシュします。デフォルトのキャッシュ有効期限は 0 (ゼロ) です。これは、キャッシュ内のアイテムが期限切れにならないことを意味します。例:{EXTC:120000}/usr/bin/getmypassword --section 1 --query company
。/usr/bin/getmypassword
の出力がキャッシュに含まれているかどうかを確認します。出力が含まれている場合はそれを使用します。出力がない場合は、コマンドを実行してこれをキャッシュに出力して使用します。この例では、キャッシュは 2 分 (120000 ミリ秒) で期限切れになります。{CMD}...
or{CMDC[:expiration_in_millis]}...
: 一般的なコマンドは 「,」 (コンマ) で区切られた文字列です。最初の部分は実際のコマンドで、追加の部分はパラメーターを表します。コンマにバックスラッシュを付けることで、パラメーターの一部として維持することができます。例:{CMD}/usr/bin/getmypassword,--section,1,--query,company
{CLASS[@jboss_module_spec]}classname[:ctorargs]
: [:ctorargs] は、クラス名から : (コロン) によって区切られるオプションの文字列です。これは、クラス名 ctor に渡されます。ctorargs は文字列のコンマ区切りの一覧です。例:{CLASS@org.test.passwd}org.test.passwd.ExternamPassworProvider
.この例では、org.test.passwd
モジュールからのorg.test.passwd.ExternamPassworProvider
クラスを読み込んで、toCharArray()
メソッドを使用し、パスワードを取得します。toCharArray()
が利用できない場合はtoString()
メソッドを使用します。org.test.passwd.ExternamPassworProvider
クラスにはデフォルトのコンストラクターが必要です。
18.6.4. 機密性が高い文字列を格納する Java キーストアの作成
前提条件
- Java Runtime Environment (JRE) によって提供される keytool ユーティリティー。このファイルへのパスを見つけます。Red Hat Enterprise Linux では、
/usr/bin/keytool
です。
java.io.IOException: com.sun.crypto.provider.SealedObjectForKeyProtector
手順18.8 Java キーストアの設定
キーストアと他の暗号化された情報を格納するディレクトリーを作成します。
キーストアと他の重要な情報を格納するディレクトリーを作成します。この手順では、ディレクトリーはEAP_HOME/vault/
と想定します。このディレクトリーには機密情報が含まれるため、アクセスは、一部のユーザーに制限する必要があります。JBoss EAP を実行しているユーザーアカウントには少なくとも読み書き込みアクセスが必要です。keytool ユーティリティーで使用するパラメーターを決定します。
以下のパラメーターの値を決めます。- alias
- エイリアスは、vault やキーストアに保存されている他のデータの一意識別子です。エイリアスは大文字と小文字を区別しません。
- storetype
- ストアタイプはキーストアのタイプを指定します。値は、
jceks
が推奨されます。 - keyalg
- 暗号化に使用するアルゴリズム。JRE とオペレーティングシステムのドキュメントを使用して、他にどの選択肢が利用できるかを確認してください。
- keysize
- 暗号化キーのサイズは、ブルートフォースでの暗号解除の難易度に影響します。適切な値の詳細は、keytool ユーティリティーとともに配布されるドキュメントを参照してください。
- storepass
storepass
の値は、キーストアに対する認証に使用されるパスワードであるため、鍵を読み取ることができます。パスワードは 6 文字以上である必要があります。パスワードは、キーストアへのアクセス時に入力する必要があります。このパラメーターを省略すると、コマンドの実行時に入力を求められます。- keypass
keypass
の値は、特定のキーにアクセスするために使用されるパスワードで、storepass
パラメーターの値と一致する必要があります。- validity
validity
の値は、鍵が有効になる期間 (日数) です。- keystore
keystore
の値は、keystore の値が格納される予定のファイルパスおよびファイル名です。キーストアファイルは、データが最初に追加されると作成されます。正しいファイルパス区切り文字が使用されていることを確認します。Red Hat Enterprise Linux および同様のオペレーティングシステムの場合は/
(フォワードスラッシュ)、Microsoft Windows Server の場合は\
(バックスラッシュ) を使用します。
Keytool ユーティリティーには、その他の多くのオプションがあります。詳細は、JRE またはオペレーティングシステムのドキュメントを参照してください。keytool コマンドを実行します。
オペレーティングシステムのコマンドラインインターフェイスを開き、収集した情報を使用して keytool ユーティリティーを実行します。
例18.40 Java キーストアの作成
$ keytool -genseckey -alias vault -storetype jceks -keyalg AES -keysize 128 -storepass vault22 -keypass vault22 -validity 730 -keystore EAP_HOME/vault/vault.keystore
結果
この場合、キーストアはファイルは EAP_HOME/vault/vault.keystore
に作成されています。JBoss EAP では、パスワードなどの暗号化された文字列を保存するために使用されるエイリアス vault
とともに単一のキーを保存します。
18.6.5. パスワード vault の初期化
概要
パスワード vault は、各パラメーターの値を入力するように求められる対話的な方法、またはすべてのパラメーターの値がコマンドラインで指定される非対話的な方法で初期化できます。それぞれの方法で同じ結果が得られるため、どちらの方法を選択してもかまいません。
パラメーター値
- keystore URL (KEYSTORE_URL)
- キーストアファイルのファイルシステムパスまたは URI。この例では、
EAP_HOME/vault/
を使用します。vault.keystore
- キーストアパスワード (KEYSTORE_PASSWORD)
- キーストアのアクセスに使用されるパスワード。
- Salt (SALT)
Salt
値は、キーストアの内容を暗号化するために、iteration count (反復カウント) とともに使用される 8 文字のランダムな文字列です。- keystore Alias (KEYSTORE_ALIAS)
- キーストア認識されているエイリアス。
- Iteration Count (ITERATION_COUNT)
- 暗号化アルゴリズムの実行回数。
- Directory to store encrypted files (ENC_FILE_DIR)
- 暗号化したファイルを保存するパス。これは通常、パスワード vault を含むディレクトリーです。暗号化されたすべての情報をキーストアと同じ場所に格納することは便利ですが、必須ではありません。このディレクトリーには、制限のあるユーザーのみがアクセスできるようにする必要があります。JBoss EAP を実行しているユーザーアカウントには少なくとも読み書き込みアクセスが必要です。「機密性が高い文字列を格納する Java キーストアの作成」 を実行した場合は、キーストアは
EAP_HOME/vault/
というディレクトリーにあります。注記ディレクトリー名の後にはバックスラッシュまたはスラッシュが必要です。正しいファイルパス区切り文字が使用されていることを確認します。Red Hat Enterprise Linux および同様のオペレーティングシステムの場合は / (フォワードスラッシュ)、Microsoft Windows Server の場合は \ (バックスラッシュ) を使用します。 - Vault Block (VAULT_BLOCK)
- パスワード vault でこのブロックに与えられる名前。分かりやすい値を選択してください。
- Attribute (ATTRIBUTE)
- 保存される属性に与えられる名前。分かりやすい値を選択してください。たとえば、データソースに関する名前を選択できます。
- Security Attribute (SEC-ATTR)
- パスワード vault に保存されているパスワード。
手順18.9 パスワード vault コマンドを対話式に実行します。
パスワード vault コマンドをインタラクティブに起動します。
オペレーティングシステムのコマンドラインインターフェイスを起動し、EAP_HOME/bin/vault.sh
(Red Hat Enterprise Linux および同様のオペレーティングシステム) またはEAP_HOME\bin\vault.bat
(Microsoft Windows Server 上) を実行します。新しい対話セッションを開始するには、0
(ゼロ) と入力します。要求パラメーターを入力します。
プロンプトに従って必要なパラメーターを入力します。マスクされたパスワード情報をメモします。
マスクされたパスワード、salt、iteration count (反復数) は、標準出力に出力されます。安全な場所にそれらを書き留めておきます。これらのエントリーは、パスワード Vault に追加する必要があります。キーストアファイルおよびこの値にアクセスすると、攻撃者はパスワード Vault の機密情報にアクセスできるようになります。対話式コンソールを終了します。
3
と入力して、対話式コンソールを終了します。
例18.41 パスワード vault コマンドの対話式実行
Please enter a Digit:: 0: Start Interactive Session 1: Remove Interactive Session 2: Exit 0 Starting an interactive session Enter directory to store encrypted files:EAP_HOME/vault/ Enter Keystore URL:EAP_HOME/vault/vault.keystore Enter Keystore password: vault22 Enter Keystore password again: vault22 Values match Enter 8 character salt:1234abcd Enter iteration count as a number (Eg: 44):120 Enter Keystore Alias:vault Initializing Vault Oct 17, 2014 12:58:11 PM org.picketbox.plugins.vault.PicketBoxSecurityVault init INFO: PBOX000361: Default Security Vault Implementation Initialized and Ready Vault Configuration in AS7 config file: ******************************************** ... </extensions> <vault> <vault-option name="KEYSTORE_URL" value="EAP_HOME/vault/vault.keystore"/> <vault-option name="KEYSTORE_PASSWORD" value="MASK-5dOaAVafCSd"/> <vault-option name="KEYSTORE_ALIAS" value="vault"/> <vault-option name="SALT" value="1234abcd"/> <vault-option name="ITERATION_COUNT" value="120"/> <vault-option name="ENC_FILE_DIR" value="EAP_HOME/vault/"/> </vault><management> ... ******************************************** Vault is initialized and ready for use Handshake with Vault complete
手順18.10 パスワード Vault コマンドの自動実行
- オペレーティングシステムのコマンドラインインターフェイスを起動し、パスワード Vault コマンドを実行します。を参照してくださいパラメーター値リスト、プレースホルダーの値を好みの値に置き換えます。Red Hat Enterprise Linux または同様のオペレーティングシステムでは
EAP_HOME/bin/vault.sh
、Microsoft Windows Server ではEAP_HOME\bin\vault.bat
を使用します。vault.sh --keystore KEYSTORE_URL --keystore-password KEYSTORE_PASSWORD --alias KEYSTORE_ALIAS --vault-block VAULT_BLOCK --attribute ATTRIBUTE --sec-attr SEC-ATTR --enc-dir ENC_FILE_DIR --iteration ITERATION_COUNT --salt SALT
例18.42 パスワード Vault コマンドの自動実行
vault.sh --keystore
EAP_HOME/vault/vault.keystore
--keystore-passwordvault22
--aliasvault
--vault-blockvb
--attributepassword
--sec-attr0penS3sam3
--enc-dirEAP_HOME/vault/
--iteration120
--salt1234abcd
コマンド出力========================================================================= JBoss Vault JBOSS_HOME: EAP_HOME JAVA: java ========================================================================= Oct 17, 2014 2:23:43 PM org.picketbox.plugins.vault.PicketBoxSecurityVault init INFO: PBOX000361: Default Security Vault Implementation Initialized and Ready Secured attribute value has been stored in vault. Please make note of the following: ******************************************** Vault Block:vb Attribute Name:password Configuration should be done as follows: VAULT::vb::password::1 ******************************************** Vault Configuration in AS7 config file: ******************************************** ... </extensions> <vault> <vault-option name="KEYSTORE_URL" value="EAP_HOME/vault/vault.keystore"/> <vault-option name="KEYSTORE_PASSWORD" value="MASK-5dOaAVafCSd"/> <vault-option name="KEYSTORE_ALIAS" value="vault"/> <vault-option name="SALT" value="1234abcd"/> <vault-option name="ITERATION_COUNT" value="120"/> <vault-option name="ENC_FILE_DIR" value="EAP_HOME/vault/"/> </vault><management> ... ********************************************
結果
キーストアパスワードは、設定ファイルおよびデプロイメントで使用するためにマスクされています。さらに、vault は初期化され、使用できる状態になります。
18.6.6. パスワード vault を使用するよう JBoss EAP 6 を設定
概要
設定ファイルにあるパスワードや機密性の高いその他の属性をマスキングする前に、これらを保存し復号化するパスワード vault を JBoss EAP 6 が認識するようにする必要があります。
前提条件
手順18.11 パスワード Vault の有効化
- 「パスワード vault の初期化」 の管理 CLI コマンドを実行し、プレースホルダーの値をパスワード Vault コマンドの出力からの値に置き換えます。。注記Microsoft Windows Server を使用する場合は、通常 1 つを使用するファイルパスで 2 つの円記号 (
\\
) を使用します。例:C:\\data\\vault\\vault.keystore
これは、単一のバックスラッシュ (\
) が文字エスケープに使用されるためです。/core-service=vault:add(vault-options=[("KEYSTORE_URL" => "PATH_TO_KEYSTORE"), ("KEYSTORE_PASSWORD" => "MASKED_PASSWORD"), ("KEYSTORE_ALIAS" => "ALIAS"), ("SALT" => "SALT"),("ITERATION_COUNT" => "ITERATION_COUNT"), ("ENC_FILE_DIR" => "ENC_FILE_DIR")])
例18.43 パスワード Vault の有効化
/core-service=vault:add(vault-options=[("KEYSTORE_URL" => "EAP_HOME/vault/vault.keystore"), ("KEYSTORE_PASSWORD" => "MASK-5dOaAVafCSd"), ("KEYSTORE_ALIAS" => "vault"), ("SALT" => "1234abcd"),("ITERATION_COUNT" => "120"), ("ENC_FILE_DIR" => "EAP_HOME/vault/")])
結果
JBoss EAP 6 が、パスワード Vault に保存されている、マスクされた文字列を復号化するように設定されました。パスワード Vault に文字列を追加して設定で使用するには、「パスワード Vault に Sensitive 文字列を保存します。」を参照してください。
18.6.7. パスワード Vault のカスタム実装を使用するよう JBoss EAP 6 を設定
概要
独自の SecurityVault
実装を使用して、設定ファイルのパスワードや機密性の高いその他の属性をマスクできます。
前提条件
手順18.12 パスワード vault のカスタム実装の使用
SecurityVault
インターフェイスを実装するクラスを作成します。- 直前の手順からクラスを含むモジュールを作成し、インターフェイスが
SecurityVault
のorg.picketbox
で依存関係を指定します。 - 以下の属性を用いて vault 要素を追加して、JBoss EAP サーバー設定でカスタムのパスワード vault を有効にします。
- code
SecurityVault
を実装するクラスの完全修飾名。- module
- カスタムクラスが含まれるモジュールの名前。
オプションでvault-options
パラメーターを使用して、パスワード Vault のカスタムクラスを初期化できます。例18.44
vault-options
パラメーターを使用したカスタムクラスの初期化/core-service=vault:add(code="custom.vault.implementation.CustomSecurityVault", module="custom.vault.module", vault-options=[("KEYSTORE_URL" => "PATH_TO_KEYSTORE"), ("KEYSTORE_PASSWORD" => "MASKED_PASSWORD"), ("KEYSTORE_ALIAS" => "ALIAS"), ("SALT" => "SALT"),("ITERATION_COUNT" => "ITERATION_COUNT"), ("ENC_FILE_DIR" => "ENC_FILE_DIR")])
結果
パスワード vault のカスタム実装を使用して、マスクされた文字列が復号化されるよう JBoss EAP 6 が設定されます。
18.6.8. パスワード Vault に Sensitive 文字列を保存します。
概要
プレーンテキストの設定ファイルにパスワードやその他の機密文字列を含めると、セキュリティーリスクが伴います。セキュリティー上の理由からも、これらの文字列はパスワード vault に保存します。パスワード vault では、これらの文字列は、マスク化した形式で設定ファイル、管理 CLI コマンド、およびアプリケーションで参照できます。
手順18.13 対話式での機密文字列の保存
PasswordVault コマンドを実行します
オペレーティングシステムのコマンドラインインターフェイスを起動し、パスワード Vault コマンドを実行します。Red Hat Enterprise Linux または同様のオペレーティングシステムではEAP_HOME/bin/vault.sh
、Microsoft Windows Server ではEAP_HOME\bin\vault.bat
を使用します。新しい対話セッションを開始するには、0
(ゼロ) と入力します。PasswordVault に関するプロンプトパラメーターを入力します
プロンプトに従って必要な認証パラメーターを入力します。これらの値は、パスワード vault の作成時に提供された値と一致している必要があります。注記キーストアパスワードは、マスク形式ではなく、プレーンテキスト形式で指定する必要があります。機密文字列に関するパラメーター入力を行います。
機密文字列の保存を開始する場合は0
(ゼロ) を入力します。プロンプトに従って必要なパラメーターを入力します。マスクされた文字列についての情報を書き留めておきます。
メッセージは標準出力に出力され、vault ブロック、属性名、マスクされた文字列、設定の文字列の使用に関するアドバイスが表示します。この情報は、安全な場所にメモしておいてください。出力例を以下に示します。Vault Block:ds_Example1 Attribute Name:password Configuration should be done as follows: VAULT::ds_Example1::password::1
対話式コンソールを終了します。
3
と入力して、対話式コンソールを終了します。
例18.45 対話式での機密文字列の保存
========================================================================= JBoss Vault JBOSS_HOME: EAP_HOME/jboss-eap-6.4 JAVA: java ========================================================================= ********************************** **** JBoss Vault *************** ********************************** Please enter a Digit:: 0: Start Interactive Session 1: Remove Interactive Session 2: Exit 0 Starting an interactive session Enter directory to store encrypted files:11:18:46,086 INFO [org.jboss.security] (management-handler-thread - 4) PBOX0 Enter directory to store encrypted files:EAP_HOME/vault/ Enter Keystore URL:EAP_HOME/vault/vault.keystore Enter Keystore password: Enter Keystore password again: Values match Enter 8 character salt:1234abcd Enter iteration count as a number (Eg: 44):120 Enter Keystore Alias:vault Initializing Vault Oct 21, 2014 11:20:49 AM org.picketbox.plugins.vault.PicketBoxSecurityVault init INFO: PBOX000361: Default Security Vault Implementation Initialized and Ready Vault Configuration in AS7 config file: ******************************************** ... </extensions> <vault> <vault-option name="KEYSTORE_URL" value="EAP_HOME/vault/vault.keystore"/> <vault-option name="KEYSTORE_PASSWORD" value="MASK-5dOaAVafCSd"/> <vault-option name="KEYSTORE_ALIAS" value="vault"/> <vault-option name="SALT" value="1234abcd"/> <vault-option name="ITERATION_COUNT" value="120"/> <vault-option name="ENC_FILE_DIR" value="EAP_HOME/vault/"/> </vault><management> ... ******************************************** Vault is initialized and ready for use Handshake with Vault complete Please enter a Digit:: 0: Store a secured attribute 1: Check whether a secured attribute exists 2: Remove secured attribute 3: Exit 0 Task: Store a secured attribute Please enter secured attribute value (such as password): Please enter secured attribute value (such as password) again: Values match Enter Vault Block:ds_Example1 Enter Attribute Name:password Secured attribute value has been stored in vault. Please make note of the following: ******************************************** Vault Block:ds_Example1 Attribute Name:password Configuration should be done as follows: VAULT::ds_Example1::password::1 ******************************************** Please enter a Digit:: 0: Store a secured attribute 1: Check whether a secured attribute exists 2: Remove secured attribute 3: Exit
手順18.14 機密性の高い文字列の非対話式保存
- オペレーティングシステムのコマンドラインインターフェイスを起動し、パスワード Vault コマンドを実行します。Red Hat Enterprise Linux または同様のオペレーティングシステムでは
EAP_HOME/bin/vault.sh
、Microsoft Windows Server ではEAP_HOME\bin\vault.bat
を使用します。プレースホルダーの値を独自の値に置き換えます。パラメーターKEYSTORE_URL
、KEYSTORE_PASSWORD
、およびKEYSTORE_ALIAS
の値は、パスワード vault の作成時に提供された値と一致している必要があります。注記キーストアパスワードは、マスク形式ではなく、プレーンテキスト形式で指定する必要があります。EAP_HOME/bin/vault.sh
--keystore KEYSTORE_URL --keystore-password KEYSTORE_PASSWORD --alias KEYSTORE_ALIAS --vault-block VAULT_BLOCK --attribute ATTRIBUTE --sec-attr SEC-ATTR --enc-dir ENC_FILE_DIR --iteration ITERATION_COUNT --salt SALT マスクされた文字列についての情報を書き留めておきます。
メッセージは標準出力に出力され、vault ブロック、属性名、マスクされた文字列、設定の文字列の使用に関するアドバイスが表示します。この情報は、安全な場所にメモしておいてください。出力例を以下に示します。Vault Block:vb Attribute Name:password Configuration should be done as follows: VAULT::vb::password::1
例18.46 パスワード Vault コマンドの自動実行
EAP_HOME/bin/vault.sh
--keystoreEAP_HOME/vault/vault.keystore
--keystore-passwordvault22
--aliasvault
--vault-blockvb
--attributepassword
--sec-attr0penS3sam3
--enc-dirEAP_HOME/vault/
--iteration120
--salt1234abcd
========================================================================= JBoss Vault JBOSS_HOME: EAP_HOME JAVA: java ========================================================================= Oct 22, 2014 9:24:43 AM org.picketbox.plugins.vault.PicketBoxSecurityVault init INFO: PBOX000361: Default Security Vault Implementation Initialized and Ready Secured attribute value has been stored in vault. Please make note of the following: ******************************************** Vault Block:vb Attribute Name:password Configuration should be done as follows: VAULT::vb::password::1 ******************************************** Vault Configuration in AS7 config file: ******************************************** ... </extensions> <vault> <vault-option name="KEYSTORE_URL" value="EAP_HOME/vault/vault.keystore"/> <vault-option name="KEYSTORE_PASSWORD" value="vault22"/> <vault-option name="KEYSTORE_ALIAS" value="vault"/> <vault-option name="SALT" value="1234abcd"/> <vault-option name="ITERATION_COUNT" value="120"/> <vault-option name="ENC_FILE_DIR" value="EAP_HOME/vault/vault/"/> </vault><management> ... ********************************************
結果
これで機密文字列が PasswordVault に保存され、設定ファイル、管理 CLI コマンド、およびアプリケーションでマスクされた形式で使用できるようになりました。
18.6.9. 暗号化した機密文字列を設定で使用
/host=HOST_NAME
を追加します。
/core-service=SUBSYSTEM:read-resource-description(recursive=true)
例18.47 管理サブシステム内のすべてのリソースの説明を一覧表示します
/core-service=management:read-resource-description(recursive=true)
expressions-allowed
パラメーターの値を探します。これが 当てはまる
場合は、このサブシステムの設定内で式を使用できます。
${VAULT::VAULT_BLOCK::ATTRIBUTE_NAME::MASKED_STRING}
例18.48 マスクされたフォームでのパスワードを使用したデータソース定義
ds_ExampleDS
であり、属性は パスワードです
。
... <subsystem xmlns="urn:jboss:domain:datasources:1.0"> <datasources> <datasource jndi-name="java:jboss/datasources/ExampleDS" enabled="true" use-java-context="true" pool-name="H2DS"> <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url> <driver>h2</driver> <pool></pool> <security> <user-name>sa</user-name> <password>${VAULT::ds_ExampleDS::password::1}</password> </security> </datasource> <drivers> <driver name="h2" module="com.h2database.h2"> <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class> </driver> </drivers> </datasources> </subsystem> ...
18.6.10. アプリケーションで暗号化した機密文字列の使用
例18.49 vault されたパスワードを使用するサーブレット
/*@DataSourceDefinition( name = "java:jboss/datasources/LoginDS", user = "sa", password = "sa", className = "org.h2.jdbcx.JdbcDataSource", url = "jdbc:h2:tcp://localhost/mem:test" )*/ @DataSourceDefinition( name = "java:jboss/datasources/LoginDS", user = "sa", password = "VAULT::DS::thePass::1", className = "org.h2.jdbcx.JdbcDataSource", url = "jdbc:h2:tcp://localhost/mem:test" )
18.6.11. 機密文字列がパスワード vault 内にあるかどうかを確認します。
概要
パスワード vault に機密文字列を保存または使用する前に、その文字列がすでに保存されているかどうかを確認すると便利です。
手順18.15 対話式での機密文字列の確認
PasswordVault コマンドを実行します
オペレーティングシステムのコマンドラインインターフェイスを起動し、パスワード Vault コマンドを実行します。Red Hat Enterprise Linux または同様のオペレーティングシステムではEAP_HOME/bin/vault.sh
、Microsoft Windows Server ではEAP_HOME\bin\vault.bat
を使用します。新しい対話セッションを開始するには、0
(ゼロ) と入力します。PasswordVault に関するプロンプトパラメーターを入力します
プロンプトに従って必要な認証パラメーターを入力します。これらの値は、パスワード vault の作成時に提供された値と一致している必要があります。注記キーストアパスワードは、マスク形式ではなく、プレーンテキスト形式で指定する必要があります。1
を入力してセキュリティー保護された属性が存在するかどうかを確認します。- 機密文字列を保存する vault ブロックの名前を入力します。
- チェックする機密文字列の名前を入力します。
結果
機密文字列が指定された vault ブロックに保存されている場合は、以下のような確認メッセージが表示されます。
A value exists for (VAULT_BLOCK, ATTRIBUTE)
No value has been store for (VAULT_BLOCK, ATTRIBUTE)
例18.50 対話式での機密文字列の確認
========================================================================= JBoss Vault JBOSS_HOME: EAP_HOME JAVA: java ========================================================================= ********************************** **** JBoss Vault *************** ********************************** Please enter a Digit:: 0: Start Interactive Session 1: Remove Interactive Session 2: Exit 0 Starting an interactive session Enter directory to store encrypted files:EAP_HOME/vault Enter Keystore URL:EAP_HOME/vault/vault.keystore Enter Keystore password: Enter Keystore password again: Values match Enter 8 character salt:1234abcd Enter iteration count as a number (Eg: 44):120 Enter Keystore Alias:vault Initializing Vault Oct 22, 2014 12:53:56 PM org.picketbox.plugins.vault.PicketBoxSecurityVault init INFO: PBOX000361: Default Security Vault Implementation Initialized and Ready Vault Configuration in AS7 config file: ******************************************** ... </extensions> <vault> <vault-option name="KEYSTORE_URL" value="EAP_HOME/vault/vault.keystore"/> <vault-option name="KEYSTORE_PASSWORD" value="MASK-5dOaAVafCSd"/> <vault-option name="KEYSTORE_ALIAS" value="vault"/> <vault-option name="SALT" value="1234abcd"/> <vault-option name="ITERATION_COUNT" value="120"/> <vault-option name="ENC_FILE_DIR" value="EAP_HOME/vault/"/> </vault><management> ... ******************************************** Vault is initialized and ready for use Handshake with Vault complete Please enter a Digit:: 0: Store a secured attribute 1: Check whether a secured attribute exists 2: Remove secured attribute 3: Exit 1 Task: Verify whether a secured attribute exists Enter Vault Block:vb Enter Attribute Name:password A value exists for (vb, password) Please enter a Digit:: 0: Store a secured attribute 1: Check whether a secured attribute exists 2: Remove secured attribute 3: Exit
手順18.16 機密性の高い文字列の非対話式チェック
- オペレーティングシステムのコマンドラインインターフェイスを起動し、パスワード Vault コマンドを実行します。Red Hat Enterprise Linux または同様のオペレーティングシステムでは
EAP_HOME/bin/vault.sh
、Microsoft Windows Server ではEAP_HOME\bin\vault.bat
を使用します。プレースホルダーの値を独自の値に置き換えます。パラメーターKEYSTORE_URL
、KEYSTORE_PASSWORD-password
、およびKEYSTORE_ALIAS
の値は、パスワード vault の作成時に提供された値と一致している必要があります。注記キーストアパスワードは、マスク形式ではなく、プレーンテキスト形式で指定する必要があります。EAP_HOME/bin/vault.sh
--keystore KEYSTORE_URL --keystore-password KEYSTORE_PASSWORD --alias KEYSTORE_ALIAS --check-sec-attr --vault-block VAULT_BLOCK --attribute ATTRIBUTE --enc-dir ENC_FILE_DIR --iteration ITERATION_COUNT --salt SALT
結果
機密文字列が指定された vault ブロックに保存されると、以下のメッセージが出力されます。
Password already exists.
Password doesn't exist.
18.6.12. パスワード vault からの機密文字列の削除
概要
セキュリティー上の理由から、機密文字列が不要になった場合は、パスワード vault から削除することが推奨されます。たとえば、アプリケーションの使用を停止する場合、データソース定義で使用される機密文字列を同時に削除する必要があります。
前提条件
パスワード vault から機密文字列を削除するには、JBoss EAP の設定で使用されるかどうかを確認します。これを行う 1 つの方法は、grep ユーティリティーを使用して、マスクされた文字列のインスタンスの設定ファイルを検索することです。Red Hat Enterprise Linux (および同様のオペレーティングシステム) では、grep はデフォルトでインストールされますが、Microsoft Windows の場合は手動でインストールする必要があります。
手順18.17 対話式での機密文字列の削除
PasswordVault コマンドを実行します
オペレーティングシステムのコマンドラインインターフェイスを起動し、EAP_HOME/bin/vault.sh
(Red Hat Enterprise Linux および同様のオペレーティングシステム) またはEAP_HOME\bin\vault.bat
(Microsoft Windows Server 上) を実行します。新しい対話セッションを開始するには、0
(ゼロ) と入力します。認証の詳細を提供する
プロンプトに従って必要な認証パラメーターを入力します。これらの値は、パスワード vault の作成時に提供された値と一致している必要があります。注記キーストアパスワードは、マスク形式ではなく、プレーンテキスト形式で指定する必要があります。2
と入力して、セキュアな属性を削除する
オプションを選択します。- 機密文字列を保存する vault ブロックの名前を入力します。
- 削除する機密文字列の名前を入力します。
結果
機密文字列が正常に削除されると、以下のような確認メッセージが出力されます。
Secured attribute [VAULT_BLOCK::ATTRIBUTE] has been successfully removed from vault
Secured attribute [VAULT_BLOCK::ATTRIBUTE] was not removed from vault, check whether it exist
例18.51 対話式での機密文字列の削除
********************************** **** JBoss Vault *************** ********************************** Please enter a Digit:: 0: Start Interactive Session 1: Remove Interactive Session 2: Exit 0 Starting an interactive session Enter directory to store encrypted files:EAP_HOME/vault/ Enter Keystore URL:EAP_HOME/vault/vault.keystore Enter Keystore password: Enter Keystore password again: Values match Enter 8 character salt:1234abcd Enter iteration count as a number (Eg: 44):120 Enter Keystore Alias:vault Initializing Vault Dec 23, 2014 1:40:56 PM org.picketbox.plugins.vault.PicketBoxSecurityVault init INFO: PBOX000361: Default Security Vault Implementation Initialized and Ready Vault Configuration in configuration file: ******************************************** ... </extensions> <vault> <vault-option name="KEYSTORE_URL" value="EAP_HOME/vault/vault.keystore"/> <vault-option name="KEYSTORE_PASSWORD" value="MASK-5dOaAVafCSd"/> <vault-option name="KEYSTORE_ALIAS" value="vault"/> <vault-option name="SALT" value="1234abcd"/> <vault-option name="ITERATION_COUNT" value="120"/> <vault-option name="ENC_FILE_DIR" value="EAP_HOME/vault/"/> </vault><management> ... ******************************************** Vault is initialized and ready for use Handshake with Vault complete Please enter a Digit:: 0: Store a secured attribute 1: Check whether a secured attribute exists 2: Remove secured attribute 3: Exit 2 Task: Remove secured attribute Enter Vault Block:craft Enter Attribute Name:password Secured attribute [craft::password] has been successfully removed from vault
手順18.18 機密性の高い文字列の非対話式削除
- オペレーティングシステムのコマンドラインインターフェイスを起動し、パスワード Vault コマンドを実行します。Red Hat Enterprise Linux または同様のオペレーティングシステムでは
EAP_HOME/bin/vault.sh
、Microsoft Windows Server ではEAP_HOME\bin\vault.bat
を使用します。プレースホルダーの値を独自の値に置き換えます。パラメーターKEYSTORE_URL
、KEYSTORE_PASSWORD
、およびKEYSTORE_ALIAS
の値は、パスワード vault の作成時に提供された値と一致している必要があります。注記キーストアパスワードは、マスク形式ではなく、プレーンテキスト形式で指定する必要があります。EAP_HOME/bin/vault.sh
--keystore KEYSTORE_URL --keystore-password KEYSTORE_PASSWORD --alias KEYSTORE_ALIAS --remove-sec-attr --vault-block VAULT_BLOCK --attribute ATTRIBUTE --enc-dir ENC_FILE_DIR --iteration ITERATION_COUNT --salt SALT
結果
機密文字列が正常に削除されると、以下のような確認メッセージが出力されます。
Secured attribute [VAULT_BLOCK::ATTRIBUTE] has been successfully removed from vault
Secured attribute [VAULT_BLOCK::ATTRIBUTE] was not removed from vault, check whether it exist
例18.52 機密性の高い文字列の非対話式削除
./vault.sh --keystore EAP_HOME/vault/vault.keystore --keystore-password vault22 --alias vault --remove-sec-attr --vault-block craft --attribute password --enc-dir ../vault/ --iteration 120 --salt 1234abcd ========================================================================= JBoss Vault JBOSS_HOME: EAP_HOME JAVA: java ========================================================================= Dec 23, 2014 1:54:24 PM org.picketbox.plugins.vault.PicketBoxSecurityVault init INFO: PBOX000361: Default Security Vault Implementation Initialized and Ready Secured attribute [craft::password] has been successfully removed from vault
18.7. Java Authorization Contract for Containers (JACC)
18.7.1. JACC (Java Authorization Contract for Containers)
18.7.2. JACC (Java Authorization Contract for Containers) のセキュリティーの設定
jboss-web.xml
を編集する必要があります。
セキュリティードメインへの JACC サポートの追加
セキュリティードメインに JACC サポートを追加するには、required
フラグセットで JACC
承認ポリシーをセキュリティードメインの承認スタックへ追加します。以下は JACC サポートを持つセキュリティードメインの例です。ただし、セキュリティードメインは、XML で直接設定するのではなく、管理コンソールまたは管理 CLI で設定します。
<security-domain name="jacc" cache-type="default"> <authentication> <login-module code="UsersRoles" flag="required"> </login-module> </authentication> <authorization> <policy-module code="JACC" flag="required"/> </authorization> </security-domain>
JACC を使用するよう Web アプリケーションを設定
jboss-web.xml
ファイルは デプロイメントの WEB-INF/
ディレクトリーに存在し、Web コンテナーに対する追加の JBoss 固有の設定を格納し、上書きします。JACC が有効になっているセキュリティードメインを使用するには、<security-domain>
要素が含まれるようにし、さらに <use-jboss-authorization>
要素を true
に設定する必要があります。次のアプリケーションは、上記の JACC セキュリティードメインを使用するように適切に設定されています。
<jboss-web> <security-domain>jacc</security-domain> <use-jboss-authorization>true</use-jboss-authorization> </jboss-web>
JACC を使用するよう EJB アプリケーションを設定
セキュリティードメインと JACC を使用するよう EJB を設定する方法は Web アプリケーションの場合とは異なります。EJB の場合、ejb-jar.xml
記述子にてメソッドまたはメソッドのグループ上で メソッドパーミッション を宣言できます。<ejb-jar>
要素内では、すべての子 <method-permission>
要素に JACC ロールに関する情報が含まれます。詳細は、設定例を参照してください。EJBMethodPermission
クラスは Java Enterprise Edition 6 API の一部であり、で http://docs.oracle.com/javaee/6/api/javax/security/jacc/EJBMethodPermission.html 説明されています。
例18.53 EJB の JACC メソッドパーミッション例
<ejb-jar> <assembly-descriptor> <method-permission> <description>The employee and temp-employee roles may access any method of the EmployeeService bean </description> <role-name>employee</role-name> <role-name>temp-employee</role-name> <method> <ejb-name>EmployeeService</ejb-name> <method-name>*</method-name> </method> </method-permission> </assembly-descriptor> </ejb-jar>
<security>
子要素の jboss-ejb3.xml
記述子に宣言されます。セキュリティードメインの他に、EJB が実行されるプリンシパルを変更する <run-as-principal>
を指定することもできます。
例18.54 EJB におけるセキュリティードメイン宣言の例
<ejb-jar> <assembly-descriptor> <security> <ejb-name>*</ejb-name> <security-domain>myDomain</security-domain> <run-as-principal>myPrincipal</run-as-principal> </security> </assembly-descriptor> </ejb-jar>
18.8. JASPI (Java Authentication SPI for Containers)
18.8.1. JASPI (Java Authentication SPI for Containers) のセキュリティー
18.8.2. JASPI (Java Authentication SPI for Containers) のセキュリティーの設定
<authentication-jaspi>
要素を追加します。設定は標準的な認証モジュールと似ていますが、ログインモジュール要素は <login-module-stack>
要素で囲まれています。設定の構成は次のとおりです。
例18.55 authentication-jaspi
要素の構造
<authentication-jaspi> <login-module-stack name="..."> <login-module code="..." flag="..."> <module-option name="..." value="..."/> </login-module> </login-module-stack> <auth-module code="..." login-module-stack-ref="..."> <module-option name="..." value="..."/> </auth-module> </authentication-jaspi>
domain.xml
または EAP_HOME/standalone/configuration/standalone.xml
に直接追加する前に、JBoss EAP 6 を完全に停止する必要があります。。
第19章 シングルサインオン (SSO)
19.1. Web アプリケーションのシングルサインオン (SSO) について
概要
シングルサインオン (SSO) を使用すると、1 つのリソースへの認証により、他のリソースへのアクセスを暗黙的に許可できます。
クラスター化および非クラスター化 SSO
非クラスターか SSO は、同じ仮想ホストでアプリケーションへの承認情報の共有を制限します。また、ホストに障害が発生した場合の回復性はありません。クラスター化された SSO データは、複数のホスト内のアプリケーション間で共有でき、フェイルオーバーに対して回復力があります。さらに、クラスター化された SSO はロードバランサーからリクエストを受信できます。
SSO のしくみ
リソースが保護されていない場合、ユーザーは認証をまったく要求されません。ユーザーが保護されたリソースにアクセスする場合、ユーザーは認証する必要があります。
19.2. Web アプリケーションのクラスター化されたシングルサインオン (SSO) について
jboss-web.xml
デプロイメント記述子で定義できます。
19.3. 適切な SSO 実装を選択する
web.xml
デプロイメント記述子の <distributable/> タグを使用して、クラスターノード全体に分散できるものとしてマークされます。クラスター化された SSO は、アプリケーション自体がクラスター化されているかどうかに関わらず、セキュリティーコンテキストとアイデンティティー情報のレプリケーションを可能にします。これらのテクノロジーは一緒に使用できますが、別々の概念です。
Kerberos ベースのデスクトップ SSO
組織で既に MicrosoftActiveDirectory などの Kerberos ベースの認証および承認システムを使用している場合は、同じシステムを使用して、Active Directory で実行されているエンタープライズアプリケーションに対して透過的に認証できます。
非クラスター化 Web アプリケーション SSO
1 つのインスタンスで複数のアプリケーションを実行していて、それらのアプリケーションに対して SSO セッションレプリケーションを有効にする必要がある場合、非クラスター化 SSO が要件を満たします。
クラスター化された Web アプリケーション SSO
クラスター全体で単一のアプリケーションまたは複数のアプリケーションを実行していて、それらのアプリケーションの SSO セッションレプリケーションを有効にする必要がある場合、クラスター化された SSO は要件を満たします。
19.4. Web アプリケーションでシングルサインオン (SSO) を使用する
概要
シングルサインオン (SSO) 機能は、Web および Infinispan サブシステムによって提供されます。この手順を使用して、Web アプリケーションで SSO を設定します。
前提条件
- 認証とアクセスを処理する設定済みのセキュリティードメイン。
- The
infinispan
サブシステム。デフォルトでは、管理対象ドメインとスタンドアロンサーバーのすべてのプロファイルに存在します。 - The
web
cache-container
および SSO レプリケートキャッシュ。初期設定ファイルにはすでにweb
cache-container、および一部の設定には、SSO レプリケートされたキャッシュもすでに含まれています。次のコマンドを使用して、SSO レプリケートキャッシュを確認して有効にします。これらのコマンドはha
管理対象ドメインのプロファイル。スタンドアロンサーバーの場合は、コマンドを変更して別のプロファイルを使用するか、コマンドの/profile=ha
部分を削除できます。例19.1 を確認してください
web
キャッシュコンテナー上記のプロファイルと設定には、web
デフォルトでは cache-container。次のコマンドを使用して、その存在を確認します。別のプロファイルを使用する場合は、ha
の代わりにその名前に置き換えてください。/profile=ha/subsystem=infinispan/cache-container=web/:read-resource(recursive=false,proxies=false,include-runtime=false,include-defaults=true)
結果が成功
した場合、サブシステムが存在します。それ以外の場合は、追加する必要があります。例19.2 追加します
web
キャッシュコンテナー次の 3 つのコマンドを使用して、web
cache-container を設定に追加します。プロファイルの名前、およびその他のパラメーターを必要に応じて変更します。ここでのパラメーターは、デフォルト設定で使用されるパラメーターです。/profile=ha/subsystem=infinispan/cache-container=web:add(aliases=["standard-session-cache"],default-cache="repl",module="org.jboss.as.clustering.web.infinispan")
/profile=ha/subsystem=infinispan/cache-container=web/transport=TRANSPORT:add(lock-timeout=60000)
/profile=ha/subsystem=infinispan/cache-container=web/replicated-cache=repl:add(mode="ASYNC",batching=true)
例19.3 を確認してください
SSO
レプリケートされたキャッシュ次の管理 CLI コマンドを実行します。/profile=ha/subsystem=infinispan/cache-container=web/:read-resource(recursive=true,proxies=false,include-runtime=false,include-defaults=true)
次のような出力を探します。"sso" => {
見つからない場合は、SSO レプリケートキャッシュが設定に存在しません。例19.4 追加します
SSO
レプリケートされたキャッシュ/profile=ha/subsystem=infinispan/cache-container=web/replicated-cache=sso:add(mode="SYNC", batching=true)
管理対象ドメインのクラスター化された SSO を設定する
web
サブシステムは SSO を使用するように設定する必要があります。次のコマンドは、default-host
と呼ばれる仮想サーバーと cookie ドメイン domain.com
で SSO を有効にします。キャッシュ名は sso
であり、再認証は無効になっています。
/profile=ha/subsystem=web/virtual-server=default-host/sso=configuration:add(cache-container="web",cache-name="sso",reauthenticate="false",domain="domain.com")
jboss-web.xml
デプロイメント記述子で同じ <security-domain> を使用し、web.xml
設定ファイルで同じレルムを使用するように設定する必要があります。
スタンドアロンサーバーのクラスター化または非クラスター化 SSO の設定
設定、設定sso
サーバープロファイルの Web サブシステムの下。TheClusteredSingleSignOn
バージョンは属性のときに使用されますcache-container
存在する、そうでない場合は標準SingleSignOn
クラスが使用されます。
例19.5 非クラスター化 SSO 設定の例
/subsystem=web/virtual-server=default-host/sso=configuration:add(reauthenticate="false")
セッションを無効にする
アプリケーションは、メソッドを呼び出すことにより、プログラムでセッションを無効にすることができますjavax.servlet.http.HttpSession.invalidate()
。
19.5. Kerberos について
19.6. SPNEGO について
19.7. Microsoft Active Directory について
- ユーザー、コンピューター、パスワード、およびその他のリソースに関する情報を格納する軽量 Directory Access Protocol (LDAP)。
- Kerberos: ネットワーク上でセキュアな認証を提供します。
- ドメインネームサービス (DNS): ネットワーク上のコンピューターおよびその他のデバイスにおける IP アドレスとホスト名との間のマッピングを提供します。
19.8. Web アプリケーション用に Kerberos または MicrosoftActiveDirectory デスクトップ Active Directory を設定する
はじめに
Microsoft Active Directory などの組織の既存の Kerberos ベースの認証および承認インフラストラクチャーを使用して Web または EJB アプリケーションを認証するには、JBoss EAP 6 に組み込まれている JBoss ネゴシエーション機能を使用できます。Web アプリケーションを適切に設定した場合、デスクトップまたはネットワークへのログインが成功すれば、Web アプリケーションに対して透過的に認証できるため、追加のログインプロンプトは必要ありません。
プラットフォームの以前のバージョンとの違い
JBoss EAP 6 と、これまでのバージョンには顕著な違いがいくつかあります。
- セキュリティードメインは、管理対象ドメインの各プロファイル、またはスタンドアロンサーバーごとに設定されます。これらはデプロイメント自体には含まれません。デプロイメントが使用するセキュリティードメインは、デプロイメントの
jboss-web.xml
ファイルまたはjboss-ejb3.xml
ファイルで指定されます。 - セキュリティープロパティーはセキュリティードメインの一部として設定されます。これらはデプロイメントには含まれません。
- デプロイメントの一部としてオーセンティケーターをオーバーライドすることはできなくなりました。ただし、
jboss-web.xml
記述子に NegotiationAuthenticator バルブを追加して、同じ効果を実現することができます。バルブを使用するには、<security-constraint>
および<login-config>
要素をweb.xml
に定義する必要があります。これらの要素は、セキュアなリソースを決定するのに使用されます。しかし、選択した auth-method はjboss-web.xml
の NegotiationAuthenticator バルブによって上書きされます。 - セキュリティードメインの
CODE
属性は、完全修飾クラス名ではなく、単純な名前を使用するようになりました。以下の表は、JBoss Negotiation に使用されるクラスとそれらのクラスとの間のマッピングを示しています。
表19.1 ログインモジュールコードとクラス名
簡単な名前 | クラス名 | 目的 |
---|---|---|
Kerberos |
com.sun.security.auth.module.Krb5LoginModule
com.ibm.security.auth.module.Krb5LoginModule
|
Oracle JDK を使用する場合の Kerberos ログインモジュール
IBMJava 開発キットを使用する場合の Kerberos ログインモジュール
|
SPNEGO | org.jboss.security.negotiation.spnego.SPNEGOLoginModule | Web アプリケーションが Kerberos 認証サーバーに対して認証できるようにするメカニズム。 |
AdvancedLdap | org.jboss.security.negotiation.AdvancedLdapLoginModule | Microsoft Active Directory 以外の LDAP サーバーで使用されます。 |
AdvancedAdLdap | org.jboss.security.negotiation.AdvancedADLoginModule | Microsoft Active Directory LDAP サーバーで使用されます。 |
JBoss Negotiation Toolkit
JBoss Negotiation Toolkit
は、から https://community.jboss.org/servlet/JiveServlet/download/16876-2-34629/jboss-negotiation-toolkit.war ダウンロードできるデバッグツールです。これは、アプリケーションを実稼働環境にデプロイする前に認証メカニズムのデバッグおよびテストに役立つ追加ツールとして提供されます。これはサポート対象のツールではありませんが、SPENEGO を web アプリケーションに対して設定するのは難しいこともあるため、大変便利なツールと言えます。
手順19.1 Web または EJB アプリケーションの SSO 認証を設定する
サーバーの ID を表す 1 つのセキュリティードメインを設定します。必要に応じてシステムプロパティーを設定します。
最初のセキュリティードメインは、コンテナー自体をディレクトリーサービスに対して認証します。実際のユーザーは関与しないため、ある種の静的ログインメカニズムを受け入れるログインモジュールを使用する必要があります。この例では静的プリンシパルを使用し、クレデンシャルが含まれるキータブファイルを参照します。XML コードはわかりやすくするためにここに示されていますが、セキュリティードメインを設定するには管理コンソールまたは管理 CLI を使用する必要があります。<security-domain name="host" cache-type="default"> <authentication> <login-module code="Kerberos" flag="required"> <module-option name="storeKey" value="true"/> <module-option name="useKeyTab" value="true"/> <module-option name="principal" value="host/testserver@MY_REALM"/> <module-option name="keyTab" value="/home/username/service.keytab"/> <module-option name="doNotPrompt" value="true"/> <module-option name="debug" value="false"/> </login-module> </authentication> </security-domain>
1 つまたは複数の Web アプリケーションを保護するために、2 番目のセキュリティードメインを設定します。必要に応じてシステムプロパティーを設定します。
2 番目のセキュリティードメインは、Kerberos または SPNEGO 認証サーバーに対して個々のユーザーを認証するために使用されます。ユーザーを認証するために少なくとも 1 つのログインモジュールが必要であり、ユーザーに適用するロールを検索するために別のログインモジュールが必要です。次の XML コードは、SPNEGO セキュリティードメインの例を示しています。これには、ロールを個々のユーザーにマップするための承認モジュールが含まれています。認証サーバー自体でロールを検索するモジュールを使用することもできます。<security-domain name="SPNEGO" cache-type="default"> <authentication> <!-- Check the username and password --> <login-module code="SPNEGO" flag="requisite"> <module-option name="password-stacking" value="useFirstPass"/> <module-option name="serverSecurityDomain" value="host"/> </login-module> <!-- Search for roles --> <login-module code="UsersRoles" flag="required"> <module-option name="password-stacking" value="useFirstPass" /> <module-option name="usersProperties" value="spnego-users.properties" /> <module-option name="rolesProperties" value="spnego-roles.properties" /> </login-module> </authentication> </security-domain>
web.xml
で security-constraint と login-config を指定しますweb.xml
記述子には、セキュリティーの制約とログイン設定に関する情報が含まれています。以下は、それぞれの値の例です。<security-constraint> <display-name>Security Constraint on Conversation</display-name> <web-resource-collection> <web-resource-name>examplesWebApp</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>RequiredRole</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>SPNEGO</auth-method> <realm-name>SPNEGO</realm-name> </login-config> <security-role> <description> role required to log in to the Application</description> <role-name>RequiredRole</role-name> </security-role>
jboss-web.xml
記述子でセキュリティードメインおよびその他の設定を指定します。デプロイメントのjboss-web.xml
記述子でクライアント側のセキュリティードメイン (この例では 2 番目) の名前を指定して、このセキュリティードメインを使用するようにアプリケーションに指示します。オーセンティケーターを直接オーバーライドすることはできなくなりました。代わりに、必要に応じて、NegotiationAuthenticator をバルブとしてjboss-web.xml
記述子に追加できます。<jacc-star-role-allow>
を使用すると、アスタリスク (*) 文字を使用して複数のロール名と一致させることができます。これはオプションです。<jboss-web> <security-domain>SPNEGO</security-domain> <valve> <class-name>org.jboss.security.negotiation.NegotiationAuthenticator</class-name> </valve> <jacc-star-role-allow>true</jacc-star-role-allow> </jboss-web>
アプリケーションの
MANIFEST.MF
に依存関係を追加して、ネゴシエーションクラスを見つけます。Web アプリケーションにはクラスへの依存が必要ですorg.jboss.security.negotiation
JBoss Negotiation クラスを見つけるために、デプロイメントのMETA-INF/MANIFEST.MF
マニフェストに追加されます。以下に、適切にフォーマットされたエントリーを示します。Manifest-Version: 1.0 Build-Jdk: 1.6.0_24 Dependencies: org.jboss.security.negotiation
- 別の方法として、
META-INF/jboss-deployment-structure.xml
ファイルを編集して、アプリケーションに依存関係を追加します。<?xml version="1.0" encoding="UTF-8"?> <jboss-deployment-structure> <deployment> <dependencies> <module name='org.jboss.security.negotiation'/> </dependencies> </deployment> </jboss-deployment-structure>
結果
Web アプリケーションは、Kerberos、Microsoft Active Directory、またはその他の SPNEGO 互換のディレクトリーサービスに対してクレデンシャルを受け入れて認証します。ユーザーがすでにディレクトリーサービスにログインしているシステムからアプリケーションを実行し、必要なロールがすでにユーザーに適用されている場合、Web アプリケーションは認証のプロンプトを表示せず、SSO 機能が実現されます。
19.9. SPNEGO フォールバックをフォーム認証に設定する
手順19.2 フォーム認証へのフォールバックを備えた SPNEGO セキュリティー
SPNEGO を設定する
「Web アプリケーション用に Kerberos または MicrosoftActiveDirectory デスクトップ Active Directory を設定する」 に記載されている手順を参照してください。web.xml
の変更login-config
要素をアプリケーションに追加し、web.xml でログインページとエラーページを設定します。<login-config> <auth-method>SPNEGO</auth-method> <realm-name>SPNEGO</realm-name> <form-login-config> <form-login-page>/login.jsp</form-login-page> <form-error-page>/error.jsp</form-error-page> </form-login-config> </login-config>
Web コンテンツを追加する
login.html
およびerror.html
の参照をweb.xml
に追加します。これらのファイルは、form-login-config
設定で指定された場所の Web アプリケーションアーカイブに追加されます。詳細は、JBoss EAP6 の 『セキュリティーガイド』 の 『フォームベースの認証』 を有効にするセクションを参照してください。典型的なlogin.html
は次のようになります。<html> <head> <title>Vault Form Authentication</title> </head> <body> <h1>Vault Login Page</h1> <p> <form method="post" action="j_security_check"> <table> <tr> <td>Username</td><td>-</td> <td><input type="text" name="j_username"></td> </tr> <tr> <td>Password</td><td>-</td> <td><input type="password" name="j_password"></td> </tr> <tr> <td colspan="2"><input type="submit"></td> </tr> </table> </form> </p> <hr> </body> </html>
19.10. SAMLWeb ブラウザーベースの SSO について
19.11. クッキーのドメイン。
19.11.1. クッキードメインについて
/
です。これは、発行元のホストのみが Cookie の内容を読み取ることができることを意味します。特定の Cookie ドメインを設定すると、Cookie のコンテンツをより広範囲のホストで利用できるようになります。Cookie ドメインを設定するには、を参照してください。「シングルサインオン用に Cookie ドメインを設定する」。
19.11.2. シングルサインオン用に Cookie ドメインを設定する
http://app1.xyz.com と http://app2.xyz.com
の
アプリケーションが、クラスター内の異なるサーバーまたはそれらが使用する仮想ホストで実行されている場合でも、SSO コンテキストを共有できます。関連付けられている複数のエイリアスがあります。
クラスター化された SSO(クラスター化された JBoss EAP インスタンスに対して共有)
CLI の使用 (スタンドアロンモード):
/subsystem=web/virtual-server=default-host/sso=configuration:add(cache-container="web",cache-name="sso")
Standlone.xml
または domain.xml
を編集し、関連する Web サブシステムに以下を追加します。
<subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="default-host" native="false"> <connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http"/> <virtual-server name="default-host" enable-welcome-root="true"> <alias name="localhost"/> <alias name="example.com"/> <sso cache-container="web" cache-name="sso"/> <!--FIXME: ADD this Line--> </virtual-server> </subsystem>
非クラスター化 SSO(SSO は Jboss EAP インスタンス内のインスタンスに対してのみ共有されます)
CLI の使用 (スタンドアロンモード):
/subsystem=web/virtual-server=default-host/sso=configuration:add()
Standlone.xml
または domain.xml
を編集し、関連する Web サブシステムに以下を追加します。
<subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="default-host" native="false"> <connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http"/> <virtual-server name="default-host" enable-welcome-root="true"> <alias name="localhost"/> <alias name="example.com"/> <sso/> <!--FIXME: ADD this Line--> </virtual-server> </subsystem>
/subsystem=web/virtual-server=default-host/sso=configuration:add(domain="example.com",...)
<sso domain="example.com"/>
第20章 開発セキュリティーリファレンス
20.1. EJB セキュリティーパラメーターリファレンス
表20.1 EJB セキュリティーパラメーター要素
要素 | Description |
---|---|
<security-identity>
|
EJB のセキュリティー ID に関連する子要素が含まれています。
|
<use-caller-identity />
|
EJB が呼び出し元と同じセキュリティー ID を使用することを示します。
|
<run-as>
| <role-name> 要素が含まれています。
|
<run-as-principal>
|
存在する場合、発信コールに割り当てられたプリンシパルを示します。存在しない場合、発信コールは
anonymous という名前のプリンシパルに割り当てられます。
|
<role-name>
|
EJB を実行するロールを指定します。
|
<description>
| <role-name> で指定されたロールについて説明します
|
例20.1 セキュリティー ID の例
<ejb-jar> <enterprise-beans> <session> <ejb-name>ASessionBean</ejb-name> <security-identity> <use-caller-identity/> </security-identity> </session> <session> <ejb-name>RunAsBean</ejb-name> <security-identity> <run-as> <description>A private internal role</description> <role-name>InternalRole</role-name> </run-as> </security-identity> </session> <session> <ejb-name>RunAsBean</ejb-name> <security-identity> <run-as-principal>internal</run-as-principal> </security-identity> </session> </enterprise-beans> </ejb-jar>
jboss-ejb3.xml
ファイルに含めることもできます。jboss-ejb3.xml ファイルについては、「jboss-ejb3.xml デプロイメント記述子の参照」。
第21章 設定リファレンス
21.1. jboss-web.xml 設定リファレンス
はじめに
jboss-web.xml
および web.xml
デプロイメント記述子は両方ともデプロイメントの WEB-INF
ディレクトリーに配置されます。jboss-web.xml
は、JBoss EAP の Web アプリケーションデプロイメント記述子であり、JBossWeb の追加機能のための追加の設定オプションが含まれています。この記述子を使用して、web.xml
記述子の設定をオーバーライドし、JBoss EAP 固有の設定を設定できます。
グローバルリソースの WAR 要件へのマッピング
使用可能な設定の多くは、アプリケーションの web.xml
で設定された要件をローカルリソースにマップします。web.xml
設定の説明は、を参照してください http://docs.oracle.com/cd/E13222_01/wls/docs81/webapp/web_xml.html。
web.xml
で jdbc/MyDataSource
が必要な場合、jboss-web.xml
はこのニーズを満たすためにグローバルデータソース java:/DefaultDS
をマップする場合があります。WAR は、グローバルデータソースを使用して、jdbc/MyDataSource
の必要性を満たします。
表21.1 jboss-web.xml の一般的なトップレベル属性
属性 | Description |
---|---|
servlet |
サーブレット要素は、サーブレット固有のバインディングを指定します。
|
max-active-sessions |
許可されるアクティブなセッションの最大数を決定します。セッションマネージャーによって管理されるセッションの数がこの値を超え、
パッシベーション が有効になっている場合、設定された passivation-min-idle-time に 基づいて超過分がパッシベーションされます。
-1 に設定すると、制限がないことを意味します。
|
replication-config | Replication-config 要素は、jboss-web.xml ファイルでセッションレプリケーションを設定するために使用されます。
|
passivation-config | passivation-config 要素は、jboss-web.xml ファイルでセッションパッシベーションを設定するために使用されます。
|
distinct-name | 個別の名前 要素は、Web アプリケーションの EJB3 の個別の名前を指定します。
|
data-source | web.xml に必要な データソース へのマッピング。
|
context-root | アプリケーションのルートコンテキスト。デフォルト値は、.war 接尾辞のないデプロイメントの名前です。 |
virtual-host | アプリケーションが要求を受け入れる HTTP 仮想ホストの名前。HTTP ホスト ヘッダーの内容を参照します。 |
アノテーション | アプリケーションで使用される注釈について説明します。詳細は、<annotation> を参照してください。 |
listener | アプリケーションで使用されるリスナーについて説明します。詳細は、<listener> を参照してください。 |
session-config | この要素は、web.xml の <session-config> 要素と同じ機能を果たし、互換性のためにのみ含まれています。 |
バルブ | アプリケーションで使用されるバルブについて説明します。詳細は、<valve> を参照してください。 |
overlay | アプリケーションに追加するオーバーレイの名前。 |
security-domain | アプリケーションが使用するセキュリティードメインの名前。セキュリティードメイン自体は、Web ベースの管理コンソールまたは管理 CLI で設定されます。 |
security-role | この要素は、web.xml の <security-role> 要素と同じ機能を果たし、互換性のためにのみ含まれています。 |
jacc-star-role-allow | jacc-star-role-allow 要素は、jacc プロバイダーが許可をバイパスするかどうかを決定できるように、Web レイヤーの jacc 許可生成エージェントが WebResourcePermission 許可を生成する必要があるかどうかを指定します。
|
use-jboss-authorization | この要素が存在し、大文字と小文字を区別しない値 true が含まれている場合、JBossWeb 認証スタックが使用されます。存在しないか、true ではない値が含まれている場合は、JavaEnterpriseEdition 仕様で指定されている許可メカニズムのみが使用されます。この要素は JBoss EAP 6 の新機能です。 |
disable-audit | このブール要素を false に設定すると有効になり、true に設定すると Web 監査が無効になります。Web セキュリティー監査は JavaEE 仕様の一部ではありません。この要素は JBoss EAP 6 の新機能です。 |
disable-cross-context | false の場合、アプリケーションは別のアプリケーションコンテキストを呼び出すことができます。デフォルトは true です。 |
enable-websockets | jboss-web.xml でこの要素を true に設定して、Web アプリケーションで WebSocket アクセスを有効にするかどうかを指定します。 |
<annotation>
の子要素を示します。
表21.2 注釈設定要素
属性 | 説明 |
---|---|
class-name |
注釈のクラスの名前
|
servlet-security |
サーブレットのセキュリティーを表す
@ServletSecurity などの要素。
|
run-as |
実行情報を表す
@RunAs などの要素。
|
multipart-config |
multipart-config 情報を表す
@MultiPart などの要素。
|
<listener>
の子要素を示します。
表21.3 リスナー設定要素
属性 | 説明 |
---|---|
class-name |
リスナーのクラスの名前
|
listener-type |
アプリケーションのコンテキストに追加するリスナーの種類を示す
条件 要素のリスト。有効な選択肢は次のとおりです。
|
module |
リスナークラスを含むモジュールの名前。
|
param |
パラメーター。
<param-name> と <param-value> の 2 つの子要素が含まれます。
|
第22章 補足リファレンス
22.1. Java アーカイブの種類
表22.1
アーカイブタイプ | 範囲 | 目的 | ディレクトリー構造の要件 |
---|---|---|---|
Java アーカイブ | .jar | Java クラスライブラリーが含まれています。 | META-INF/Manifest.mf ファイル (オプション)。どのクラスが メイン クラスであるかなどの情報を指定します。
|
Web アーカイブ | .war |
Java クラスとライブラリーに加えて、Java Server Pages (JSP) ファイル、サーブレット、および XML ファイルが含まれています。Web アーカイブのコンテンツは、Web アプリケーションとも呼ばれます。
| WEB-INF/web.xml ファイル。これには、Web アプリケーションの構造に関する情報が含まれています。他のファイルも WEB-INF/ に存在する可能性があります。
|
リソースアダプターアーカイブ。 | .rar |
ディレクトリー構造は、JCA 仕様で指定されています。
|
Java コネクターアーキテクチャー (JCA) リソースアダプターが含まれています。コネクターとも呼ばれます。
|
エンタープライズアーカイブ | .ear |
Java Enterprise Edition (EE) によって使用され、1 つ以上のモジュールを単一のアーカイブにパッケージ化して、モジュールをアプリケーションサーバーに同時にデプロイできるようにします。Maven と Ant は、EAR アーカイブの構築に使用される最も一般的なツールです。
| META-INF/ ディレクトリー。1 つ以上の XML デプロイメント記述子ファイルが含まれています。
|
次のタイプのモジュールのいずれか。
| |||
サービスアーカイブ | .sar |
エンタープライズアーカイブに似ていますが、JBoss EAP に固有です。
| jboss-service.xml または jboss-beans.xml ファイルを含む META-INF/ ディレクトリー。
|
付録A 改訂履歴
改訂履歴 | |||
---|---|---|---|
改訂 6.4.0-48 | Thursday November 16 2017 | Red Hat Customer Content Services | |
|