ローカル・インターフェースを使用する EJB の RESTful なビューの実装

ローカル・インターフェース・ビューを使用して公開される Enterprise JavaBeans (EJB) アプリケーションがある場合は、Java™ API for RESTful Web Services (JAX-RS) を使用してエンタープライズ Bean に RESTful なインターフェースを公開できます。 JAX-RS アノテーション付きエンタープライズ Bean を実装することにより、トランザクション・サポート、 Java EE コンポーネントおよびリソースの注入、およびその他の EJB セッション Bean 機能を含む EJB 機能を保持します。

事前処理

EJB 3.1より前は、EJB ローカル・クライアント・ビューを必要とするエンタープライズ Bean には、ローカル・ビュー・メソッドを宣言した別個の Java インターフェース (通常は別のファイルにあります) も必要でした。 エンタープライズ Bean は、デプロイメント記述子または EJB アノテーションを使用して、 EJB ローカル・ビュー・インターフェースの実装を指定していました。

EJB 3.1 仕様より、EJB ローカル・インターフェースを明示的に宣言せずに、 エンタープライズ Bean のローカル・ビューを公開するオプションが提供されるようになりました。 エンタープライズ Bean は、ローカル・インターフェースを明示的に宣言する代わりに、 Bean クラスの public メソッドに基づいた非インターフェース・クライアント・ビューを使用します。 非インターフェース・ビュー・ エンタープライズ Bean は、以下の理由により、ローカル・ビュー・エンタープライズ Bean よりも 容易に開発することができます。
  • 非インターフェース・ビュー・エンタープライズ Bean は、別個の Java インターフェース宣言を必要としません。
  • 非インターフェース・ビュー・エンタープライズ Bean では、デプロイメント記述子や、アノテーションを使用するときに、追加のメタデータを指定する必要がありません。
エンタープライズ Bean の非インターフェース・ビューについて詳しくは、EJB 3.1 仕様を参照してください。

JAX-RS は、ローカル・ビジネス・インターフェースを宣言するエンタープライズ Bean および非インターフェース・ビュー・エンタープライズ Bean の使用をサポートします。

このタスクでは、ローカル・インターフェースを使用するエンタープライズ Bean に RESTful なビューを実装し、エンタープライズ Bean で JAX-RS リソースを公開できるようにする方法について説明します。

このタスクの概要

JAX-RS アノテーションを使用して、単純なエンタープライズ Bean を作成できます。 このタスクでは、特に、ローカル・インターフェース・ビュー・エンタープライズ Bean に RESTful なビューを実装する 方法について説明していますが、リソース・モデルを決定し、ご使用のエンタープライズ Bean アプリケーションに どの RESTful ビューが適切であるかを判断する際には、アプリケーション・アーキテクチャーの全容および リソースの公開方法を十分に検討することが重要です。 この検討作業については、このタスクでは説明していません。

JAX-RS は、ステートレス・セッション Bean および singleton セッション Bean をサポートします。 セッション Bean のローカル・インターフェースに JAX-RS アノテーションを追加できます。 また、EJB 3.1 では、エンタープライズ Bean が非インターフェース・ビューを公開する場合、 EJB クラスに直接 JAX-RS アノテーションを追加することができます。

EJB 3.1 パッケージ化ルールを使用すると、WEB-INF/classes ディレクトリーに直接、または WEB-INF/lib ディレクトリーにある Java アーカイブ (JAR) ファイルを使用して、Web アプリケーション・アーカイブ (WAR) ファイルに JAX-RS エンタープライズ Bean を追加できます。 アノテーション、または EJB デプロイメント記述子、またはその両方を使用して、エンタープライズ Bean を宣言できます。 WAR または JAR ファイルでの EJB のデプロイを参照してください。
注: JAR ファイル内の JAX-RS エンタープライズ Bean の場合、すべてのアプリケーション、リソース (@path)、プロバイダー (@Provider) を EJB Bean として宣言する必要があります。これは、JAR ファイル内では EJB クラスのみがサポートされ、POJO クラスはサポートされないためです。 EJB JAR ファイルで POJO クラスを使用する場合、EJB ベース・アプリケーション・クラスの getClasses() または getSingletons() メソッドを使用して、当該クラスを登録する必要があります。

EAR に含まれている ejb-jar ファイル内の JAX-RS アノテーション付きエンタープライズ Bean は、サポートされるようになっています。 EAR ファイルへの EJB のデプロイを参照してください。

ベスト・プラクティス: エンタープライズ Bean はさまざまな方法で宣言できますが、EJB ビジネス・ローカル・インターフェースを直接実装し、常に @javax.ejb.Local アノテーションを宣言することがベスト・プラクティスです。 このメソッドを使用すると、EJB bean でローカル・ビジネス・インターフェースを実装する必要があるため、 メソッド名の入力や引数の変更によるエラーがなくなります。 @javax.ejb.Local アノテーションを常に使用することにより、 複数のビジネス・インターフェースがある場合にも、ビジネス・インターフェースをアノテーション値に 簡単に追加できます。 また、この方法により、デプロイメント記述子を使用してエンタープライズ Bean を 変更することもできます。

手順

  1. ご使用のエンタープライズ Bean アプリケーションのエンタープライズ Bean ローカル・インターフェース を作成します。
    以下の例は、簡単なローカル・ビジネス・インターフェースである、 購入品目についての Purchasable EJB ローカル・インターフェースを示しています。
    package com.example.jaxrs;
    @javax.ws.rs.Path("itemsForPurchase/{itemID}")
    public interface Purchasable {
    
        public int getItemsLeft(String itemID);
    
        @javax.ws.rs.POST
        public Order purchase(
            @javax.ws.rs.PathParam("itemID") String itemID,
            @javax.ws.rs.QueryParam("orderId") String orderID);
    }

    getItemsLeft メソッドは、JAX-RS 関連のメソッドではなく、通常の EJB メソッドです。 javax.ws.rs.Path アノテーションは、使用する HTTP 要求パスを示します。 itemsForPurchase/{itemID} オブジェクトに対して HTTP POST 要求が出されると、 JAX-RS ランタイム環境は、Purchasable ローカル・インターフェースを実装する EJB Bean を 検索し、そのエンタープライズ Bean で purchase メソッドを呼び出します。

    JAX-RS ランタイム環境要求以外にも purchase メソッドを使用できます。 purchasable エンタープライズ Bean に対して注入または JNDI 検索を使用して、 itemIDorderID の 2 つのストリング引数を使用して purchase メソッドを呼び出すことができます。

    ベスト・プラクティス: ローカル・ビジネス・インターフェースを実装するエンタープライズ Bean が複数ある場合、JAX-RS ランタイム環境は、JAX-RS 要求が行われたときに使用するランダム EJB Bean を選択します。 JAX-RS アノテーション付き EJB ローカル・インターフェースを実装する Bean クラスを 1 つだけ 使用可能にすることをベスト・プラクティスとしてお勧めします。 必要に応じて、別の EJB ローカル・インターフェースを作成し、 新しく作成したインターフェースで JAX-RS アノテーションを使用して、新しい EJB ローカル・インターフェース を実装するように Bean クラスのメタデータを変更します。
  2. ローカル・ビジネス・インターフェースを実装するエンタープライズ Bean を作成します。
    以下の例は、Purchasable EJB Bean を示しています。
        public int getItemsLeft(String itemID) {
            // Return the number of items that remain.  
        }
    
        public Order purchase(String itemID, String orderId) {
            // Add the given item to the order id and return it.  
        }
    
    }
  3. Book クラスがエンタープライズ Bean であり、ローカル・インターフェースを実装することを宣言します。
    以下のいずれかの方法を使用して、ご使用のクラスを、ローカル・インターフェースを実装する エンタープライズ Bean として宣言します。 以下の例で、Book クラスは、ローカル・インターフェースを 実装するエンタープライズ Bean として宣言されています。
    • Book クラスで EJB アノテーション @javax.ejb.Stateless または @javax.ejb.Singleton を 使用して、EJB をステートレスまたは singleton にすることを指定します。 さらに、アノテーション値としてローカル・インターフェースを指定した @javax.ejb.Local アノテーションを追加します。以下に例を示します。
      @javax.ejb.Stateless
      @javax.ejb.Local(Purchasable.class)
      public class Book {
      複数のローカル・ビジネス・インターフェースを実装している場合は、 以下のように、@javax.ejb.Local アノテーション値にインターフェース・クラスを追加します。
      @javax.ejb.Local({Purchasable.class, Rentable.class})
    • デプロイメント記述子を使用して、EJB Bean と EJB Bean が実装するビジネス・インターフェースを宣言します。以下に例を示します。
      <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" version="3.1"
          xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd">
      <!--
          This file must exist in the WEB-INF/
          directory of your WAR file. See EJB 3.1 spec 20.4 for more details.
      -->
          <enterprise-beans>
              <session>
                  <ejb-name>Book</ejb-name>
                  <business-local>com.example.jaxrs.Purchasable</business-local>
                  <ejb-class>com.example.jaxrs.Book</ejb-class>
                  <session-type>Stateless</session-type>
              </session>
          </enterprise-beans>
      </ejb-jar>

      複数のローカル・ビジネス・インターフェースを実装している場合は、 Bean 定義で各ローカル・インターフェースにビジネス・ローカル・エレメントを追加する必要があります。

    • ローカル・ビジネス・インターフェースが 1 つしかない場合は、以下のように、インターフェースを直接 実装できます。
      @javax.ejb.Stateless
      public class Book implements Purchasable {
  4. (オプション) アプリケーション内のリソースに簡単にアクセスできるように、@javax.annotation.Resource アノテーション付き Java EE リソース・フィールドおよびプロパティーを JAX-RS EJB クラスに追加します。
    Java EE 注入は、JAX-RS アノテーション付きのプレーン Java クラスでは機能しません。 JAX-RS EJB クラスへの @javax.annotation.Resource アノテーション付き Java EE リソース・フィールドおよびプロパティーの注入は、JAX-RS アノテーション付きクラスがエンタープライズ Bean または Java Context and Dependency Injection (JCDI) (JSR-299) 管理 Bean のいずれかである場合にのみ機能します。以下に例を示します。
    package com.example.jaxrs;
    
    @javax.ejb.Stateless
    @javax.ejb.Local(Purchasable.class)
    public class Book implements Purchasable {
        @javax.annotation.Resource(name="jdcb/TestDataSource")
        private javax.sql.DataSource datasource;
    
        public int getItemsLeft(String itemID) {
            // Reads from the datasource. 
            // Returns the number of items that remain.  
        }
    
        public Order purchase(String itemID, String orderId) {
            // Reads from the datasource. 
            // Adds the given item to the order id and returns it.  
        }
    }
    この例では、データ・ソースが正しい JNDI 名で適切に構成されている場合、 DataSource オブジェクトがリソース・クラスに注入されます。
  5. (オプション) JAX-RS @javax.ws.rs.core.Context 注入を使用して、 要求に関する情報へのアクセス権限を取得します。
    @javax.ws.rs.core.Context UriInfo フィールドを JAX-RS EJB クラスに追加して、要求 URI に関する情報にアクセスすることができます。例えば、以下のようにします。
    package com.example.jaxrs;
    
    @javax.ejb.Stateless
    @javax.ejb.Local(Purchasable.class)
    public class Book implements Purchasable {
        @javax.ws.rs.core.Context
        private UriInfo uriInfo;
    
        public int getItemsLeft(String itemID) {
            // Return the number of items that remain.  
        }
    
        public Order purchase(String itemID, String orderId) {
            // Add the given item to the order id and return it.  
        }
    }
    @javax.ws.rs.HeaderParam、@javax.ws.rs.QueryParam、および @javax.ws.rs.PathParam のような要求から パラメーターを読み取るには、以下のように、リソース・メソッドにパラメーターを追加します。
    package com.example.jaxrs;
    
    @javax.ws.rs.Path("itemsForPurchase/{itemID}")
    public interface Purchasable {
        public int getItemsLeft(String itemID);
    
        @javax.ws.rs.POST
        public Order purchase(
            @javax.ws.rs.PathParam("itemID") String itemID,
            @javax.ws.rs.QueryParam("orderId") String orderID);
    }
    package com.example.jaxrs;
    
    @javax.ejb.Stateless
    @javax.ejb.Local(Purchasable.class)
    public class Book implements Purchasable {
        @javax.ws.rs.core.Context
        private UriInfo uriInfo;
    
        public int getItemsLeft(String itemID) {
            // Returns the number of items that remain.  
        }
    
        public Order purchase(String itemID, String orderId) {
            // The method parameters contain the request values. 
            // Add the given item to the order id and return it.  
        }
    
        /*  The following field will not be set. */
        @javax.ws.rs.QueryParam("q")
        private String willNotWork;
    
        @javax.ws.rs.QueryParam("q")
        public void setMyQueryParam(String q) {
            /* This property will not be set. */
        }
    }
    サポートされる構成: ビジネス・インターフェースを使用する場合は、EJB ビジネス・インターフェースのリソース・メソッドに JAX-RS パラメーター・アノテーションを追加する必要があります。 実装 Bean には追加できません。
  6. エンタープライズ Bean を WAR ファイルの WEB-INF/classes ディレクトリー、 または WAR ファイルの WEB-INF/lib ディレクトリーに含まれている JAR ファイルの内部にパッケージします。

    クライアントが JAX-RS アノテーション付きエンタープライズ Bean に要求を出すと、 JAX-RS ランタイム環境はクラスの EJB インスタンスを検索し、それを使用して JAX-RS リソース・メソッドを呼び出します。

結果

既存のエンタープライズ Bean でローカル・インターフェースを使用する既存のエンタープライズ JAX-RS リソースを公開して使用できます。

EAR ファイルでの EJB のデプロイ

ejb-jar ファイルを介して EAR ファイルで EJB をデプロイし、その JAR 内の EJB を JAX-RS エンドポイントとして公開できます。

手順

  1. コマンド・ライン・ツールを開き、ディレクトリーを <WAS HOME>/binに変更します。
  2. 以下のコマンドを実行します。
    endptEnabler -endpointType jaxrs path of myearfile.ear
    同じ名前の新規 ear ファイル myearfile.ear が生成されます。 これには、ルーター・モジュール myejbjaxrs-RSRouter.war が含まれています。
    注:
    • コンテキスト・ルートをカスタマイズしない場合、デフォルトのコンテキスト・ルートは、 myejbjaxrs for myejbjaxrs.jarのように、EJB jar ファイルの短縮ファイル名になります。
    • コンテキスト・ルートをカスタマイズせず、 JaxWS ルーター・モジュールが存在する場合、デフォルトのコンテキスト・ルートは、EJB JAR ファイルの短縮ファイル名に .jaxrsを加えたもの ( myejbjaxrs.jaxrs for <myejbjaxrs.jar>など) になります。
  3. 新しい myearfile.ear ファイルを WebSphere® Application Serverにデプロイし、以下の URL パターンを使用して JAX-RS にアクセスします。
    http://<host>:<port>/<context root>/<path of jaxrs resource>
    例えば、以下の URL を使用して、myejbjaxrs.jar に含まれている EJB JAX-RS にアクセスできます。
    http://<host>:<port>/myejbjaxrs/<path of jaxrs resource>
    ヒント: JAX-RS エンジンで検出された以前のリリースまたは JAX-RS エンジンによって報告された例外に対する振る舞いの変更によってアプリケーションの始動がブロックされる場合は、JAX-RS サービスとして EAR 内の EJB JAR ファイルで JAX-RS アノテーションを持つ EJB クラスを公開する機能を使用不可にするプロパティーを使用してください。
    • バージョン 8.5.5.15 以前の場合、com.ibm.webshere.jaxrs.server.DisableIBMEJBJAXRSInEJBJarSupport プロパティーを使用します。
    • [8.5.5.16 以降]バージョン 8.5.5.16 以降の場合、 com.ibm.websphere.jaxrs.server.DisableIBMEJBJAXRSInEJBJarSupport プロパティーを使用します。