ヘッダーをスキップ

Oracle Containers for J2EE Enterprise JavaBeans開発者ガイド
10g(10.1.3.1.0)

B31852-03
目次
目次
索引
索引

戻る 次へ

29 クライアントからのEnterprise Beanへのアクセス

この章では、次のようなクライアントからのEJBへのアクセス方法を説明します。

詳細は、次を参照してください。

使用しているクライアントのタイプ

Enterprise Beanには、次のような様々なクライアントからアクセスできます。

Enterprise Bean、リソースまたは環境変数へのアクセス方法は、クライアントのタイプおよびアプリケーションのアセンブルとデプロイの方法によって決まります。

詳細は、「クライアントの構成」を参照してください。

EJBクライアント

1つのEnterprise Bean(ソースEnterprise Beanと呼ぶ)が別のEnterprise Bean(ターゲットEnterprise Beanと呼ぶ)にアクセスする場合、ソースEnterprise BeanはターゲットEnterprise Beanのクライアントです。

EJB 3.0を使用している場合は、アノテーションおよび依存性注入を通じて、OC4Jはターゲット参照に対応するインスタンス変数を初期化します。

EJB 2.1を使用している場合、このシナリオではJNDIルックアップを使用する必要があります。

スタンドアロンJavaクライアント

スタンドアロンJavaクライアントは、OC4Jの外部で実行し、OC4JにデプロイされるEJBリソースにアクセスするクライアントです。

通常、スタンドアロンJavaクライアントは、Java RMIコールを利用してEJBリソースにアクセスします。スタンドアロンJavaクライアントは、OC4Jで実施されるセキュリティおよび認証の要件を満たすようにコーディングする必要があります。

デフォルトでは、OC4Jは設定範囲内でRMIポートを動的に割り当てるように構成されます。このリリースでは、厳密なRMIポートを指定せずに、スタンドアロンJavaクライアントからOC4JでデプロイされるEnterprise Beanをルックアップできます。厳密なポート番号を使用するようにOC4Jを構成する必要はありません。

EJB 3.0を使用している場合、スタンドアロンJavaクライアントではアノテーションおよび依存性注入がサポートされないことに注意してください。

EJB 2.1を使用している場合は、このシナリオに適応するように初期コンテキストを構成する必要があります(「RMIを使用した、スタンドアロンJavaクライアントからのEJB 2.1 Enterprise Beanへのアクセス」を参照)。

サーブレットまたはJSPクライアント

サーブレットまたはJSPはEnterprise Beanにアクセスできます。

このリリースでは、OC4JによりWeb層でのアノテーションおよびリソース・インジェクションがサポートされます(「Web層でのアノテーション」を参照)。

依存性注入は、EJB 3.0アプリケーションでサーブレットまたはJSPクライアントから使用できます。

JNDIルックアップは、EJB 3.0アプリケーションとEJB 2.1アプリケーションの両方でサーブレットまたはJSPクライアントから使用できます。

クライアントの構成

クライアントからEnterprise Beanにアクセスする前に、次の点を考慮する必要があります。

OC4Jのクライアント・クラスパスの構成

表29-1に、クライアントのルックアップ対象に応じてクライアントにインストールする必要のあるOC4J固有のJARファイルをリストします。「ソース」列は、<OC4J_HOME>から必要なJARのコピーを取得する場所を示します。

クライアント・クラスパスに含める必要があるのは、oc4jclient.jarのみです。クライアントにより必要とされる他のすべてのJARファイルは、oc4jclient.jarのマニフェスト・クラスパスで参照されます。

表29-1    OC4Jクライアントのクラスパス要件 
OC4J JAR  ソース(<OC4J_HOME>に対する相対パス)  EJBルックアップ  JMSコネクタ・ルックアップ  OEMS JMSルックアップ  OEMS JMSデータベース・ルックアップ 

adminclient.jar 

/j2ee/<instance>/lib 


 

 

 

 

bcel.jar 

/j2ee/<instance>/lib 


 

 

 

 

connector.jar 

/j2ee/<instance>/lib 


 

 

 

 

dms.jar 

/j2ee/<instance>/lib 


 

 

 

 

ejb.jar 

/j2ee/<instance>/lib 


 

 

 

 

javax77.jar 

/j2ee/<instance>/lib 


 

 

 

 

jazncore.jar 

/j2ee/<instance> 


 

 

 

 

jdbc.jar 

/j2ee/<instance>/../../lib 


 

 

 

 

jms.jar 

/j2ee/<instance>/lib 


 

 

 

 

jmxri.jar 

/j2ee/<instance>/lib 


 

 

 

 

jndi.jar 

/j2ee/<instance>/lib 


 

 

 

 

jta.jar 

/j2ee/<instance>/lib 


 

 

 

 

oc4j.jar 

/j2ee/<instance> 


 

 

 

 

oc4jclient.jar 

/j2ee/<instance> 


 

 

 

 

oc4j-internal.jar 

/j2ee/<instance>/lib 


 

 

 

 

ojdbc14dms.jar 

/j2ee/<instance>/../../oracle/jdbc/lib 


 

 

 

 

optic.jar1 

/opmn/lib 


 

 

 

 
1 Context.PROVIDER_URLでのJNDIルックアップでopmn:ormi接頭辞を使用することを計画している場合にのみ必要です(「Oracle初期コンテキスト・ファクトリの構成」を参照)。

これらのJARファイルのいずれかをブラウザにダウンロードする場合は、特定の権限を付与する必要があります(「ブラウザにおける権限の付与」を参照)。

初期コンテキスト・ファクトリ・クラスの選択

初期コンテキスト・ファクトリを使用して、初期コンテキスト(JNDIネームスペースへの参照)を取得します。初期コンテキストを使用すると、JNDI APIを使用してEnterprise Bean、リソース・マネージャのコネクション・ファクトリ、環境変数、またはJNDIでアクセス可能なその他のオブジェクトをルックアップできます。使用する初期コンテキスト・ファクトリのタイプは、使用しているクライアント・タイプおよびOC4Jの使用方法(スタンドアロンまたはOracle Application Serverの一部として)によって決まります(「初期コンテキスト・ファクトリの構成」を参照)。

セキュリティ資格証明の指定

クライアントとターゲットEnterprise Beanが同一JVM上になく、同じアプリケーションにデプロイされず、ターゲットEJBアプリケーションがクライアントの親でない場合、クライアントでは、ターゲットEnterprise Beanにアクセスする前に資格証明を指定する必要があります(「EJBクライアントの資格証明の指定」を参照)。

EJB参照の選択

EJB 3.0では、EJBクライアントでEJB 3.0 Enterprise Beanまたはリソースにアクセスするために、事前定義の環境参照でJNDIルックアップを行うかわりに、アノテーション、リソース・インジェクションおよびデフォルトのJNDI名(クラス名およびインタフェース名に基づく)を使用できます。

EJB 2.1またはEJB 3.0(スタンドアロンJavaクライアントの場合)では、Enterprise Beanまたはリソースにアクセスするには、事前定義の環境参照でJNDIルックアップを行う必要があります(「環境参照の構成」を参照)。EJB 2.1 Enterprise Beanまたはリソースにアクセスするには、適切な事前定義環境参照(実際または論理、ローカルまたはリモート)を選択し、JNDI初期コンテキスト(「初期コンテキスト・ファクトリ・クラスの選択」を参照)を使用してそれをルックアップします。

クライアント実装からの参照によりEnterprise Beanにアクセスする場合は、EJBデプロイメント・ディスクリプタで定義されている<ejb-ref-name>を使用してJNDIルックアップを実行します。ターゲットEnterprise BeanへのEJB参照の定義の詳細は、「EJB環境参照」を参照してください。

表29-2に、参照にjava:comp/env/ejb/という接頭辞を付ける場合を示します。これは、コンテナがデプロイメント・ディスクリプタで定義されたEJB参照を入れる場所です。

表29-2    java:comp/env/ejb/接頭辞を使用する場合 
クライアント  初期コンテキスト・ファクトリ  接頭辞の使用方法 

EJBクライアント 

デフォルト

RMIInitialContext 

オプション

未使用 

スタンドアロンJavaクライアント 

デフォルト

ApplicationClientInitialContext 

オプション

必須 

サーブレットまたはJSPクライアント 

デフォルト

RMIInitialContext 

オプション

未使用 

例29-1に、java:comp/env/ejb/接頭辞を使用して論理名ejb/HelloWorldでEnterprise Beanをルックアップする方法を示し、例29-2に、接頭辞を使用せずにこのEnterprise Beanをルックアップする方法を示します。

例29-1    接頭辞を使用したEnterprise Beanのルックアップ

InitialContext ic = new InitialContext();
HelloHome hh = (HelloHome)ic.lookup("java:comp/env/ejb/HelloWorld");


例29-2    接頭辞を使用しないEnterprise Beanのルックアップ

InitialContext ic = new InitialContext(); HelloHome hh = (HelloHome)ic.lookup("ejb/HelloWorld");

 

EJB 3.0 Enterprise Beanへのアクセス

JNDIからBeanインスタンスを直接ルックアップ(またはEJB 3.0 EJBクライアントでリソース・インジェクションを使用)し、ホーム・インタフェースを使用せずにBeanインスタンスを取得できます。<home>または<local-home>要素がEJB参照から削除される場合、BeanインスタンスはホームではなくJNDIから返されます。

Beanインスタンスは、ホーム・インタフェースで引数なしのcreateメソッドを実行することで作成されます。ステートフル・セッションBeanおよびエンティティBeanでもこのショートカットを使用できますが、これらのBeanには引数なしのcreateメソッドが必要であり、ない場合はルックアップ時に例外がスローされます。

どちらの場合も、EJBビジネス・インタフェースへの参照の取得で使用される構文は、ビジネス・インタフェースがローカルとリモートのどちらであるかに依存しません。リモート・アクセスの場合、参照されるEnterprise BeanおよびEJBコンテナの実際の場所は、一般にBeanのリモート・ビジネス・インタフェースを使用しているクライアントに対して透過的です。

EJB 3.0を使用している場合は、リソース・インジェクション(「アノテーションの使用方法」を参照)またはInitialContext「初期コンテキストの使用方法」を参照)を使用してEnterprise Beanをルックアップできます。

別の方法として、OC4J固有のアノテーションまたはデプロイXMLを使用してEJB 3.0への環境参照を定義できます(「EJB環境参照」を参照)。

アノテーションの使用方法

例29-3に、アノテーションおよび依存性注入を使用してEJBクライアントからEJB 3.0 Enterprise Beanにアクセスする方法を示します。

例29-3    EJB 3.0 EJBクライアントでのEJB 3.0 Enterprise Beanの注入

@EJB AdminService bean;

    public void privilegedTask() {
        bean.adminTask();
    }

 

初期コンテキストの使用方法

この項の内容は次のとおりです。

詳細は、「初期コンテキスト・ファクトリの構成」を参照してください。

ejb-refを使用したEJB 3.0 Enterprise Beanのリモート・インタフェースのルックアップ

ejb-refを使用してEnterprise Beanのリモート・インタフェースをルックアップするには、次のようにします。

  1. ejb-jar.xmlファイルでEnterprise Beanのejb-ref要素を定義します。

    例29-4    ejb-ref要素のejb-jar.xml

    <ejb-ref>
        <ejb-ref-name>ejb/Test</ejb-ref-name>
        <ejb-ref-type>Session</ejb-ref-type>
        <local>Test</local>
    </ejb-ref>

     

    詳細は、「リモートEJBへの環境参照の構成: クラスタ化または結合されたWeb層およびEJB層」を参照してください。

  2. 接頭辞が必要かどうかを判断します(「EJB参照の選択」を参照)。

  3. ejb-ref-name要素および適切な接頭辞(必要な場合)を使用してEnterprise Beanをルックアップします。

    例29-5    初期コンテキストを使用したEJB 3.0 EJBクライアントでのejb-refを使用したルックアップ

    InitialContext ic = new InitialContext();
    Cart cart = (Cart)ic.lookup("java:comp/env/ejb/Test");

     

    詳細は、「初期コンテキスト・ファクトリの構成」を参照してください。

locationを使用したEJB 3.0 Enterprise Beanのリモート・インタフェースのルックアップ

locationを使用してEJBのリモート・インタフェースをルックアップするには、次のようにします。

  1. orion-ejb-jar.xmlファイル内のentity-deployment要素のlocation属性を定義します。

    例29-6    location属性のorion-ejb-jar.xml

    <entity-deployment
        name="Test"
        location="app/Test"
        ...
    >
    ...
    </entity-deployment>
    
    

     

    location属性のデフォルト値は、entity-deploymentの属性nameの値です。

  2. 接頭辞が必要かどうかを判断します(「EJB参照の選択」を参照)。

  3. locationを使用してEnterprise Beanをルックアップします。

例29-7    初期コンテキストを使用したEJB 3.0 EJBクライアントでのlocationを使用したルックアップ

InitialContext ic = new InitialContext();
Cart cart = (Cart)ic.lookup("java:comp/env/app/Test");

 

詳細は、「初期コンテキスト・ファクトリの構成」を参照してください。

local-refを使用したEJB 3.0 Enterprise Beanのローカル・インタフェースのルックアップ

ejb-local-refを使用してEJBのリモート・インタフェースをルックアップするには、次のようにします。

  1. ejb-jar.xmlファイルでEnterprise Beanのejb-local-ref要素を定義します。

例29-8    ejb-local-ref要素のejb-jar.xml

<ejb-local-ref>
    <ejb-ref-name>ejb/Test</ejb-ref-name>
    <ejb-ref-type>Session</ejb-ref-type>
    <local>Test</local>
</ejb-local-ref>

 

詳細は、「ローカルEJBへの環境参照の構成」を参照してください。

  • 接頭辞が必要かどうかを判断します(「EJB参照の選択」を参照)。

  • ejb-ref-nameおよび適切な接頭辞(必要な場合)を使用してEnterprise Beanをルックアップします。

    例29-9    初期コンテキストを使用したEJB 3.0 EJBクライアントでのlocal-refを使用したルックアップ

    InitialContext ic = new InitialContext();
    Cart cart = (Cart)ctx.lookup("java:comp/env/ejb/Test");

     

    詳細は、「初期コンテキスト・ファクトリの構成」を参照してください。

    local-locationを使用したEJB 3.0 Enterprise Beanのローカル・インタフェースのルックアップ

    local-locationを使用してEJBのローカル・インタフェースをルックアップするには、次のようにします。

    1. orion-ejb-jar.xmlファイル内のentity-deployment要素のlocal-location属性を定義します。

    例29-10    local-location属性のorion-ejb-jar.xml

    <entity-deployment
        name="Test"
        local-location="app/Test"
        ...
    >
    ...
    </entity-deployment>
    
    

     

    local-locationのデフォルト値は、entity-deploymentの属性nameの値です。

  • 接頭辞が必要かどうかを判断します(「EJB参照の選択」を参照)。

  • local-locationを使用してEnterprise Beanをルックアップします。

    例29-11    初期コンテキストを使用したEJB 3.0 EJBクライアントでのlocal-locationを使用したルックアップ

    InitialContext ic = new InitialContext();
    Cart cart = (Cart)ctx.lookup("java:comp/env/app/Test");

     

    詳細は、「初期コンテキスト・ファクトリの構成」を参照してください。

    別のアプリケーションのEJB 3.0 Enterprise Beanへのアクセス

    通常、Enterprise Beanは、複数のEARファイル間、つまり異なるEARファイルにデプロイされたアプリケーション間で通信を行うことはできません。あるEnterprise Beanが、異なるEARファイルにデプロイされているEnterprise Beanにアクセスする唯一の方法は、Enterprise Beanをクライアントの親として宣言することです。子のみが親の中でメソッドを起動できます。

    たとえば、SalesおよびInventoryという2つのEnterprise Beanがあり、それぞれ別のEARファイル内にデプロイされているとします。Sales Enterprise Beanは、Inventory Enterprise Beanを起動して十分なウィジェットが使用可能かどうかをチェックする必要があります。この2つのEnterprise Beanは異なるEARファイルにデプロイされているため、Sales Enterprise BeanでInventory Enterprise Beanを親として定義しないかぎり、Sales Enterprise BeanはInventory Enterprise Bean内でメソッドを起動できません。したがって、Inventory Enterprise BeanをSales Enterprise Beanの親として定義すると、Sales Enterprise Beanは親の中でメソッドを起動できるようになります。

    親を定義できるのは、デプロイ・ウィザードを使用してデプロイを行うときのみです。Beanの親アプリケーションの定義方法については、『Oracle Containers for J2EE構成および管理ガイド』の「admin.jarユーティリティの使用方法」の章の「アプリケーションのデプロイ/アンデプロイ」を参照してください。

    EntityManagerを使用したJPAエンティティへのアクセス

    EJB 3.0アプリケーションでは、javax.persistence.EntityManagerはエンティティの永続化およびデータベースからのエンティティのロードを行うためのランタイム・アクセス・ポイントです。

    この項の内容は次のとおりです。

    詳細は、「JPAエンティティの問合せ方法」を参照してください。


    注意

    JPAエンティティ・マネージャのコード例は、http://www.oracle.com/technology/tech/java/oc4j/ejb3/
    howtos-ejb3/howtoejb30entitymanager/doc/
    how-to-ejb30-entitymanager.htmlからダウンロードできます。 


    EntityManagerの取得

    EntityManagerを使用する前に、EntityManagerインスタンスを取得する必要があります。エンティティ・マネージャの取得方法は、クライアント・タイプによって決まります
    「使用しているクライアントのタイプ」を参照)。

    エンティティ・マネージャを取得するときに、永続性ユニットを指定します。永続性ユニットでは、使用するファクトリ、エンティティ・マネージャが管理できる永続管理クラス、使用するオブジェクト・リレーショナル・マッピング・メタデータなどの詳細を含む、エンティティ・マネージャの構成を定義します。クライアントが永続性ユニットの有効範囲内にある場合は、特定の永続性ユニットのエンティティ・マネージャのみ取得できます。詳細は、
    「persistence.xmlファイルとは」を参照してください。

    次の方法でエンティティ・マネージャを取得できます。

    OC4Jのデフォルト・エンティティ・マネージャの取得

    @PersistenceContextアノテーションを使用して、EJB 3.0セッションBeanクライアント(ステートフルまたはステートレス・セッションBean、メッセージドリブンBean、サーブレットなど)でEntityManagerを注入できます。例29-12に示すように、unitName属性を指定せずに@PersistenceContextを使用して、OC4Jのデフォルト永続性ユニットを使用できます。

    例29-12    OC4Jのデフォルト永続性ユニットでの@PersistenceContextの使用方法

    @Stateless
    public class EmployeeDemoSessionEJB implements EmployeeDemoSession {

        @PersistenceContext protected EntityManager entityManager;

        public void createEmployee(String fName, String lName) {
            Employee employee = new Employee();
            employee.setFirstName(fName);
            employee.setLastName(lName);
            entityManager.persist(employee);
        }
    ...
    }

     

    詳細は、「OC4Jの永続性ユニットのデフォルトについて」を参照してください。

    名前付きエンティティ・マネージャの取得

    @PersistenceContextアノテーションを使用して、EJB 3.0セッションBeanクライアント(ステートフルまたはステートレス・セッションBean、メッセージドリブンBean、サーブレットなど)でEntityManagerを注入できます。例29-13に示すように、@PersistenceContextの属性unitNameを使用して、永続性ユニットを名前で指定できます。この場合は、persistence.xmlファイルで永続性ユニットを構成する必要があります。

    例29-13    名前付き永続性ユニットでの@PersistenceContextの使用方法

    @Stateless
    public class EmployeeDemoSessionEJB implements EmployeeDemoSession {

        @PersistenceContext(unitName="myPersistenceUnit") protected EntityManager entityManager;

        public void createEmployee(String fName, String lName) {
            Employee employee = new Employee();
            employee.setFirstName(fName);
            employee.setLastName(lName);
            entityManager.persist(employee);
        }
    ...
    }

     

    詳細は、次を参照してください。

    JNDIを使用したエンティティ・マネージャの取得

    別の方法として、例29-14に示すように、アノテーションを使用して永続性コンテキストを注入し、JNDIを使用してエンティティ・マネージャをルックアップできます。この場合は、persistence.xmlファイルで永続性ユニットを定義する必要があります。

    例29-14    初期コンテキストを使用した、ステートレス・セッションBeanでのEntityManagerのルックアップ

    @PersistenceContext(
        name="persistence/InventoryAppMgr",
        unitName=InventoryManagement // defined in a persistence.xml file
    )
    @Stateless
    public class InventoryManagerBean implements InventoryManager {

        EJBContext ejbContext;
        public void updateInventory(...) {
            ...
            // obtain the initial JNDI context
            Context initCtx = new InitialContext();
            // perform JNDI lookup to obtain container-managed entity manager
            javax.persistence.EntityManager entityManager = (javax.persistence.EntityManager)
                initCtx.lookup("java:comp/env/persistence/InventoryAppMgr");
            ...
        }
    }

     

    詳細は、次を参照してください。

    Webクライアントでのエンティティ・マネージャの取得

    このリリースでは、例29-15に示すように、@PersistenceContextアノテーションを使用してサーブレットなどのWebクライアントにEntityManagerを注入できます。この例では、デフォルトのEntityManagerを注入していますが、例29-13のように名前付きエンティティ・マネージャを注入することもできます。詳細は、「Web層でのアノテーション」を参照してください。

    例29-15    @PersistenceContextを使用したサーブレットへのEntityManagerの注入

        @Resource
        UserTransaction ut;
        @PersistenceContext
        EntityManager entityManager;
        ...
        try {
            ut.begin();

            Employee employee = new Employee();
            employee.setEmpNo(empId);
            employee.setEname(name);
            employee.setSal(sal);

            entityManager.persist(employee);
            ut.commit();

            this.getServletContext().getRequestDispatcher(
                "/jsp/success.jsp").forward(request, response);
        }
        catch(Exception e) {
        ...
        }

     

    ヘルパー・クラスでのエンティティ・マネージャの取得

    アノテーションと注入をサポートしないクラス、つまりヘルパー・クラスでエンティティ・マネージャを取得するには、次の処理を行う必要があります。

    1. persistence.xmlファイルで永続性ユニットを定義します。

      詳細は、次を参照してください。

    2. ヘルパー・クラスを利用する各Java EEコンポーネントで、この永続性ユニットに対する参照をクラス・レベルで宣言します。永続性ユニットは、Java EEコンポーネントの環境(java:comp/env)に出現します。

      これを行うには、次のいずれかの方法を使用します。

      1. 次のように、ヘルパー・クラスを利用するJava EEコンポーネントで@PersistenceContextアノテーションを使用します。

        @PersistenceContext(name="helperPC", unitName="HelperPU")
        @Stateless
        public class EmployeeDemoSessionEJB implements EmployeeDemoSession {
            import com.acme.Helper;
            ...
            void doSomething() {
                Helper.createNewEmployee();
            }
        }
        
        

        @PersistenceContextアノテーションで、次のものを指定します。

        • name: 永続性コンテキストのルックアップに使用する名前

        • unitName: 返されたエンティティ・マネージャの特性を定義する、手順1で作成した永続性ユニットの名前

      2. ヘルパー・クラスを利用するJava EEコンポーネント用の適切なデプロイメント・ディスクリプタ・ファイルでpersistence-context-refを使用します
        「永続性コンテキストへの環境参照の構成」を参照)。

        persistence-context-refで、次のものを指定します。

        • persistence-context-ref: 永続性コンテキストのルックアップに使用する名前

        • persistence-unit-name: 返されたエンティティ・マネージャの特性を定義する、手順1で作成した永続性ユニットの名前

    3. ヘルパー・クラスで、定義した永続性ユニット名を使用して、JNDIを通じてエンティティ・マネージャをルックアップします。

      public class Helper {
          ...
          int createNewEmployee()
          {
              UserTransaction ut = null;
              ...
              try {
                  Context initCtx = new InitialContext();
      
                  ut = (UserTransaction)initCtx.lookup("java:comp/UserTransaction");  
                  ut.begin();  
      
                  Employee employee = new Employee();
                  employee.setEmpNo(empId);
      
                  // obtain the initial JNDI context
                  Context initCtx = new InitialContext();
                  javax.persistence.EntityManager entityManager =
                      (javax.persistence.EntityManager)initCtx.lookup(
                          "java:comp/env/helperPC"
                      );
      
                  entityManager.persist(employee);
      
                  ut.commit();
              }
              catch(Exception e) {
                  ...
              }
          }
      }
      
      


      注意

      ヘルパー・クラスでEntityManagerを使用する場合、トランザクション内でEntityManagerを使用する必要があるため、UserTransaction APIを使用してトランザクションの境界を手動で設定する必要があります。  


    詳細は、「初期コンテキスト・ファクトリの構成」を参照してください。

    新規エンティティ・インスタンスの作成

    EntityManagerの取得後に(「EntityManagerの取得」を参照)、新規エンティティ・インスタンスを作成するには、例29-16に示すように、エンティティObjectを渡すEntityManagerのメソッドpersistを使用します。このメソッドをコールすると、メソッドは新規インスタンスにデータベースへの挿入をマークします。このメソッドは、渡したインスタンスと同じインスタンスを返します。

    このメソッドは、トランザクション・コンテキスト内でコールする必要があります。


    注意

    新規エンティティでは、EntityManagerのメソッドpersistのみ使用します。既存のエンティティに変更を加えた場合、それらの変更は現在のトランザクションのコミット時にデータベースに書き込まれます
    「フラッシュの使用方法」も参照)。 


    例29-16    EntityManagerでのエンティティの作成

    @Stateless
    public class EmployeeDemoSessionEJB implements EmployeeDemoSession {

        @PersistenceContext protected EntityManager entityManager;
    ...
        public void createEmployee(String fName, String lName) {
            Employee employee = new Employee();
            employee.setFirstName(fName);
            employee.setLastName(lName);
            entityManager.persist(employee);
        }
    ...
    }

    EntityManagerを使用したJPAエンティティの問合せ

    この項では、次のようにEntityManagerを使用してEJB 3.0エンティティを問い合せる方法について説明します。

    詳細は、次を参照してください。

    エンティティ・マネージャを使用した主キーによるエンティティの検索

    例29-17に示すように、主キーがわかっている場合は、EntityManagerのメソッドfindを使用して、問合せを作成しなくても、対応するエンティティをデータベースから取得できます。

    例29-17    EntityManagerを使用した主キーによるエンティティの検索

    @Stateless
    public class EmployeeDemoSessionEJB implements EmployeeDemoSession {
    ...
    public void removeEmployee(Integer employeeId) {
            Employee employee = (Employee)entityManager.find("Employee", employeeId);
            ...
            entityManager.remove(employee);
        }
    ...
    }

     

    EntityManagerでの名前付き問合せの作成

    例29-18EntityManagerでの名前付き問合せの作成」に示すように、名前付き問合せ
    「JPA名前付き問合せの実装」を参照)を実装した後で、EntityManagerのメソッドcreateNamedQueryを使用して実行時にその問合せを取得できます。名前付き問合せがパラメータを受け取る場合は、QueryのメソッドsetParameterを使用してこれらのパラメータを設定します。

    例29-18    EntityManagerでの名前付き問合せの作成

    Query queryEmployeesByFirstName = entityManager.createNamedQuery(
        "findAllEmployeesByFirstName"
    );
    queryEmployeeByFirstName.setParameter("firstName", "John");
    Collection employees = queryEmployessByFirstName.getResultList();

     

    オプションで、問合せヒントで問合せを構成し、JPA永続性プロバイダのベンダー拡張を使用できます(「JPA問合せでのTopLink問合せヒントの構成」を参照)。

    EntityManagerでの動的Java永続性問合せ言語の問合せの作成

    例29-19に、EntityManagerのメソッドcreateQueryを使用して実行時に非定型EJB QL問合せを作成する方法を示します。

    例29-19    EntityManagerを使用した動的問合せの作成

    Query queryEmployees = entityManager.createQuery(
        "SELECT OBJECT(employee) FROM Employee employee"
    );

     

    例29-20に、EntityManagerのメソッドcreateQueryを使用してfirstnameという名前のパラメータを受け取る非定型問合せを作成する方法を示します。パラメータは、QueryのメソッドsetParameterを使用して設定します。

    例29-20    EntityManagerを使用したパラメータ付き動的Java永続性問合せ言語の問合せの作成

    Query queryEmployees = entityManager.createQuery(
        "SELECT OBJECT(emp) FROM Employee emp WHERE emp.firstName = :firstname"
    );
    queryEmployeeByFirstName.setParameter("firstName", "John");
    
    

     

    オプションで、問合せヒントで問合せを構成し、JPA永続性プロバイダのベンダー拡張を使用できます(「JPA問合せでのTopLink問合せヒントの構成」を参照)。

    EntityManagerを使用した動的TopLink式問合せの作成

    例29-21に示すように、oracle.toplink.ejb.cmp3.EntityManagerのメソッドcreateQuery(Expression expression, Class resultType)を使用して、TopLink Expressionに基づいて問合せを作成できます。

    オプションで、問合せヒントで問合せを構成し、JPA永続性プロバイダのベンダー拡張を使用できます(「JPA問合せでのTopLink問合せヒントの構成」を参照)。

    詳細は、『Oracle TopLink開発者ガイド』のTopLinkの式の理解に関する項を参照してください。

    例29-21    エンティティ・マネージャを使用した動的TopLink式問合せの作成

    @Stateless
    public class EmployeeDemoSessionEJB implements EmployeeDemoSession {
    ...
        public Collection findManyProjectsByQuery(Vector params) {
            ExpressionBuilder builder = new ExpressionBuilder();
            Query query = ((oracle.toplink.ejb.cmp3.EntityManager)em).createQuery(
                builder.get("name").equals(builder.getParameter("projectName")),
                Project.class);
            query.setParameter("projectName", params.firstElement());
            Collection projects = query.getResultList();
            return projects;
        }
    ...
    }

     

    EntityManagerを使用した動的ネイティブSQL問合せの作成

    例29-22に示すようにEntityManagerのメソッドcreateNativeQuery(String sqlString)またはcreateNativeQuery(String sqlString, Class resultType)を使用して、指定するネイティブSQL文字列に基づいて問合せを作成できます。

    例29-22    EntityManagerを使用した動的ネイティブSQL問合せの作成

    Query queryEmployees = entityManager.createNativeQuery(
        "Select * from EMP_TABLE where Salary < 50000", Employee.class
    );

     

    例29-23に、EntityManagerのメソッドcreateNativeQuer(String sqlString, Class resultClass)を使用してsalaryという名前のパラメータを受け取る非定型ネイティブSQL問合せを作成する方法を示します。パラメータは、QueryのメソッドsetParameterを使用して設定します。

    例29-23    EntityManagerを使用したパラメータ付き動的ネイティブSQL問合せの作成

    Query queryEmployees = entityManager.createNativeQuery(
        "Select * from EMP_TABLE where Salary < #salary", Employee.class
    );
    queryEmployeeByFirstName.setParameter("salary", 50000);
    
    

     

    オプションで、問合せヒントで問合せを構成し、JPA永続性プロバイダのベンダー拡張を使用できます(「JPA問合せでのTopLink問合せヒントの構成」を参照)。

    問合せの実行

    例29-24に示すように、複数の結果を返す問合せを実行するには、QueryのメソッドgetResultListを使用します。このメソッドは、java.util.Listを返します。

    例29-24    複数の結果を返す問合せの実行

    Collection employees = queryEmployees.getResultList();

     

    例29-25に示すように、1つの結果を返す問合せを実行するには、QueryのメソッドgetSingleResultを使用します。このメソッドは、java.lang.Objectを返します。

    例29-25    1つの結果を返す問合せの実行

    Object obj = query.getSingleResult();

     

    例29-26に示すように、エンティティを更新(変更または削除)する問合せを実行するには、QueryのメソッドexecuteUpdateを使用します。このメソッドは、影響を受ける(更新または削除される)行数をintとして返します。

    例29-26    更新問合せの実行

    Query queryRenameCity = entityManager.createQuery(
        "UPDATE Address add SET add.city = 'Ottawa' WHERE add.city = 'Nepean'");
    int rowCount = queryRenameCity.executeUpdate();

     

    エンティティ・インスタンスの変更

    エンティティ・インスタンスは、次のいずれかの方法で変更できます。

    これらの操作は、トランザクション・コンテキスト内で実行する必要があります。現在のトランザクションのコミット時に、更新はデータベースにコミットされます。

    コミット前に、トランザクション内でデータベースに更新を送信することもできます
    「フラッシュの使用方法」を参照)。

    更新問合せの使用方法

    更新問合せ(「EntityManagerでの名前付き問合せの作成」または「EntityManagerでの動的Java永続性問合せ言語の問合せの作成」を参照)を作成し、EntityManagerを使用して問合せを実行します(「問合せの実行」を参照)。

    エンティティのパブリックAPIの使用方法

    EntityManagerを使用して、エンティティの検索または問合せを行います(「EntityManagerを使用したJPAエンティティの問合せ」を参照)。

    エンティティのパブリックAPIを使用して、永続状態を変更します。

    データベースからのリフレッシュ

    例29-27に示すように、EntityManagerのメソッドrefreshを使用して、エンティティ・インスタンスの現在の状態を、データベースからの現在コミットされている状態で上書きできます。

    例29-27    データベースからのエンティティのリフレッシュ

    @Stateless
    public class EmployeeDemoSessionEJB implements EmployeeDemoSession {
    ...
        public void undoUpdateEmployee(Integer employeeId) {
            Employee employee = (Employee)entityManager.find("Employee", employeeId);
            em.refresh(employee);
        }
    ...
    }

     

    エンティティの削除

    例29-28に示すように、EntityManagerのメソッドremoveを使用して、データベースからエンティティを削除できます。

    例29-28    エンティティの削除

    @Stateless
    public class EmployeeDemoSessionEJB implements EmployeeDemoSession {
    ...
        public void removeEmployee(Integer employeeId) {
            Employee employee = (Employee)entityManager.find("Employee", employeeId);
            ...
            entityManager.remove(employee);
        }
    ...
    }

     

    フラッシュの使用方法

    例29-29に示すように、EntityManagerのメソッドflushを使用して、トランザクションがコミットされる前にトランザクション内で更新をデータベースに送信できます。同じトランザクション内の後続の問合せでは、更新されたデータが返されます。この機能は、特定のトランザクションが複数の操作にまたがる場合に便利です。

    例29-29    トランザクション内でのデータベースへの更新の送信

    @Stateless
    public class EmployeeDemoSessionEJB implements EmployeeDemoSession {
    ...
        public void terminateEmployee(Integer employeeId, Date endDate) {
            Employee employee = (Employee) entityManager.find("Employee", employeeId);
            employee.getPeriod().setEndDate(endDate);
            entityManager.flush();
        }
    ...
    }

     

    エンティティBeanインスタンスの連結解除およびマージ

    EntityManagerは、永続性コンテキストを持つと言われます。EntityManagerインスタンスを使用してエンティティを作成(「新規エンティティ・インスタンスの作成」を参照)または検索(「EntityManagerを使用したJPAエンティティの問合せ」を参照)する場合、エンティティはそのEntityManagerの永続性コンテキストの一部であると言われます。

    エンティティはEntityManagerの永続性コンテキストの一部ですが、これは永続性エンティティであると言われます。

    エンティティがこの永続性コンテキストの一部でなくなった場合は、連結解除されたエンティティであると言われます。

    エンティティは、永続性コンテキストの終了時または(たとえば、別のアプリケーション層への)エンティティのシリアライズ時に、永続性コンテキストから連結解除されます。

    例29-30に示すように、EntityManagerのメソッドmergeを使用して、連結解除されたエンティティの状態をEntityManagerの現在の永続性コンテキストにマージできます。

    例29-30    EntityManagerの永続性コンテキストへのエンティティのマージ

    @Stateless
    public class EmployeeDemoSessionEJB implements EmployeeDemoSession {
    ...
        public void updateAddress(Address addressExample) {
            entityManager.merge(addressExample);
        }
    ...
    }

     

    永続性コンテキストの詳細は、次を参照してください。

    EJB 3.0を使用したJMS宛先へのメッセージの送信

    クライアントは、MDBに直接にはアクセスしません。かわりに、クライアントはMDBに関連付けられているJMS宛先(キューまたはトピック)を通じてメッセージを送信することによりMDBにアクセスします。

    EJB 3.0を使用してJMS宛先にメッセージを送信するには、次のようにします。

    1. JMS宛先(キューまたはトピック)とそのコネクション・ファクトリの両方を注入します。

      これらのリソースは、事前定義の論理名またはJMSプロバイダの構成時に定義した明示的なJNDI名を使用して注入できます。この手順および例で示すように、論理名を使用することをお薦めします。

      詳細は、次を参照してください。

    2. コネクション・ファクトリを使用して接続を作成します。

      キューに対するメッセージを受信している場合は、接続を開始します。

    3. 接続を使用してセッションを作成します。

    4. 取得したJMS宛先を使用して、キューのセンダーまたはトピックのパブリッシャを作成します。

    5. メッセージを作成します。

    6. キューのセンダーまたはトピックのパブリッシャのいずれかを使用して、メッセージを送信します。

    7. キュー・セッションを閉じます。

    8. 接続を閉じます。

    例29-31に、サーブレット・クライアントがキューにメッセージを送信する方法を示します。

    例29-31    クライアントがメッセージをキューに送信するサーブレット

    public final class testResourceProvider extends HttpServlet {

      private String resProvider = "myResProvider";
      private HashMap msgMap = new HashMap();

      // 1a. Rely on Servlet container to inject queue connection factory
      @Resource(name=resProvider+"QueueConnectionFactories/myQCF")
      private QueueConnectionFactory qcf;

      // 1b. Rely on Servlet container to inject queue
      @Resource(name=resProvider+"/Queues/rpTestQueue")
      private Queue queue;
    
    
      public void doGet(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {
        doPost(req, res);
    }

      public void doPost(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {
       // Retrieve the name of the JMS provider from the request,
       // which is to be used in creating the JNDI string for retrieval
        String rp = req.getParameter ("provider");
        if (rp != null) resProvider = rp;

        try {
          // 2a. Create queue connection using the connection factory
          QueueConnection qconn = qcf.createQueueConnection();
          // 2b. You are receiving messages, so start the connection
          qconn.start();

          // 3. Create a session over the queue connection
          QueueSession sess = qconn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

           // 4. Since this is for a queue, create a sender on top of the session
           // This is used to send out the message over the queue
          QueueSender snd = sess.createSender (q);

        drainQueue (sess, q);
        TextMessage msg = null;

        // Send messages to queue
        for (int i = 0; i < 3; i++) {
          // 5. Create message
          msg = sess.createTextMessage();
          msg.setText ("TestMessage:" + i);

          // Set property of the recipient to be the MDB
          // and set the reply destination.
          msg.setStringProperty ("RECIPIENT", "MDB");
          msg.setJMSReplyTo(q);
          
          // 6. Send the message using the sender
          snd.send (msg);

          // You can store the messages IDs and sent-time  in a map (msgMap),
          // so that when messages are received, you can verify if you
          // *only* received those messages that you were
          // expecting. See receiveFromMDB() method where msgMap gets used
          msgMap.put( msg.getJMSMessageID(), new Long (msg.getJMSTimestamp()));
        }

        // receive a reply from the MDB
        receiveFromMDB (sess, q);

         // 7. Close sender, session, and connection for queue
         snd.close();
         sess.close();
         qconn.close();
        }
        catch (Exception e) {
          System.err.println ("** TEST FAILED **"+ e.toString());
          e.printStackTrace();
        }
        finally {
        }
    }

      // Receive any messages sent to you through the MDB
      private void receiveFromMDB (QueueSession sess, Queue q)
        throws Exception {
        // The MDB sends out a message (as a reply) to this client. The MDB sets
        // the receipient as CLIENT. Thus, You will only receive messages that have
        // RECIPIENT set to 'CLIENT'
        QueueReceiver rcv = sess.createReceiver (q, "RECIPIENT = 'CLIENT'");

        int nrcvd = 0;
        long trtimes = 0L;
        long tctimes = 0L;
        // First message needs to come from MDB.
        // May take  a little while receiving messages
        for (Message msg = rcv.receive (30000); msg != null; msg = rcv.receive (30000)) {
          nrcvd++;
          String rcp = msg.getStringProperty ("RECIPIENT");

          // Verify if message is in message Map  
          // Check the msgMap to see if this is the message that you are expecting
          String corrid = msg.getJMSCorrelationID();
          if (msgMap.containsKey(corrid)) {
            msgMap.remove(corrid);
          }
          else {
            System.err.println ("** received unexpected message [" + corrid + "] **");
          }
        }
        rcv.close();
      }

      // Drain messages from queue
      private int drainQueue (QueueSession sess, Queue q)
        throws Exception {
        QueueReceiver rcv = sess.createReceiver (q);
        int nrcvd = 0;

        // First drain any old messages from queue
        for (Message msg = rcv.receive(1000); msg != null; msg = rcv.receive(1000))
          nrcvd++;

        rcv.close();

        return nrcvd;
      }
    }

     

    EJB 3.0 EJBContextへのアクセス

    EJB 3.0セッションおよびメッセージドリブンBeanの場合は、OC4Jで提供されるEJBContextにアクセスできます(「リソース・インジェクションの使用方法」を参照)。

    詳細は、次を参照してください。

    リソース・インジェクションの使用方法

    EJB 3.0 EJBクライアントでは、例29-32に示すように、@Resource注入を使用してEJBContextにアクセスできます。

    例29-32    @Resourceを使用したEJBContextへのアクセス

    @Resource SessionContext ctx;

     

    EJB 2.1 Enterprise Beanへのアクセス

    この項の内容は次のとおりです。

    EJB 2.1 Enterprise Beanへのリモート・アクセス

    あるサーバーで実行されているサーブレットが別のサーバーのEnterprise Beanに接続して通信する場合は、リモート複数層の状況になります。サーブレットとEnterprise Beanは、両方とも同じアプリケーションに含まれています。アプリケーションを2つの異なるサーバーにデプロイすると、通常、サーブレットはローカルEnterprise Beanを最初に検索します。

    図29-1では、HelloBeanアプリケーションがサーバー1と2の両方にデプロイされています。サーバー1のサーブレットからサーバー2のEnterprise Beanへのコールのみを行うには、アプリケーションを両方のサーバーにデプロイする前に、アプリケーションでremote属性を適切に設定する必要があります。

    図29-1    複数層の例


    画像の説明

    EJBモジュールのorion-application.xmlにおける<ejb-module>要素のremote属性は、このアプリケーションのEnterprise Beanがデプロイされているかどうかを示します。

    1. サーバー1では、orion-application.xmlファイルの<ejb-module>要素でremote=trueを設定してから、アプリケーションをデプロイする必要があります。アプリケーション内のEJBモジュールはデプロイされません。したがって、サーブレットはローカルでEnterprise Beanを検索しませんが、EJBリクエストに対してリモート・サーバーにアクセスします。

    2. サーバー2では、orion-application.xmlファイルの<ejb-module>要素でremote=falseを設定してから、アプリケーションをデプロイする必要があります。EJBモジュールも含めて、アプリケーションは通常どおりデプロイされます。remote属性のデフォルトはfalseです。したがって、remote属性がtrueでないことを確認し、アプリケーションを再度デプロイします。

    3. RMIオプションの構成

      • スタンドアロンOC4Jでは、RMI構成ファイルrmi.xmlでRMIサーバー・データを指定します。このファイルの場所は、OC4J構成ファイルserver.xmlで指定します。デフォルトでは、この両方のファイルは<ORACLE_HOME>/j2ee/home/configにインストールされます。

        詳細は、『Oracle Containers for J2EEサービス・ガイド』の「スタンドアロンOC4Jインストール環境でのRMIの構成」を参照してください。

      • Oracle Application Server環境では、opmn.xmlファイルを編集して、このローカルRMIサーバーがRMIリクエストをリスニングするポート範囲を指定する必要があります。Oracle Application Server環境の構成ファイルへの手動変更は、各OC4Jインスタンスで手動で更新する必要があります。

        詳細は、『Oracle Containers for J2EEサービス・ガイド』の「Oracle Application Server環境でのRMIの構成」を参照してください。

    4. JNDIのプロパティjava.naming.provider.urlおよびjava.naming.factory.initialを設定します。

      詳細は、次を参照してください。

    5. リモートEnterprise Beanをルックアップします。

      複数のリモート・サーバーが構成されている場合、OC4Jはすべてのリモート・サーバーで目的のEJBアプリケーションを検索します。

    詳細は、『Oracle Containers for J2EEサービス・ガイド』の「OC4JでのRemote Method Invocationの使用方法」を参照してください。

    EJB 2.1 Enterprise Beanへのローカル・アクセス

    ローカル複数層の状況は、サーブレットとEnterprise Beanの両方が同じアプリケーションに含まれ、同じサーバーにデプロイされる場合に存在します。

    EJBモジュールのorion-application.xmlにおける<ejb-module>要素のremote属性は、このアプリケーションのEnterprise Beanがデプロイされているかどうかを示します。

    1. アプリケーションをデプロイするサーバーでは、orion-application.xmlファイルの<ejb-module>要素でremote=falseを設定してから、アプリケーションをデプロイする必要があります。EJBモジュールも含めて、アプリケーションは通常どおりデプロイされます。remote属性のデフォルトはfalseです。

    2. JNDIのプロパティjava.naming.provider.urlおよびjava.naming.factory.initialを設定します。

      詳細は、次を参照してください。

    3. ローカルEJBをルックアップします。

    RMIを使用した、スタンドアロンJavaクライアントからのEJB 2.1 Enterprise Beanへのアクセス

    例29-33に、RMIポートを指定しなくても、OC4JでデプロイされるEnterprise BeanをルックアップするためにこのリリースでスタンドアロンJavaクライアント(「スタンドアロンJavaクライアント」を参照)から使用できるルックアップのタイプを示します。
    例29-33では、ホストmyServerで実行されているoc4j_inst1という名前のOC4JインスタンスにデプロイされるJava EEアプリケーションejbsamplesで、MyCartという名前のEnterprise Beanをルックアップする方法を示します。

    例29-33    RMIを使用した、スタンドアロンJavaクライアントからのEJB 2.1 Enterprise Beanへのアクセス

    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY,"oracle.j2ee.rmi.RMIInitialContextFactory");
    env.put(Context.SECURITY_PRINCIPAL, "oc4jadmin");
    env.put(Context.SECURITY_CREDENTIALS, "password");
    env.put(Context.PROVIDER_URL,"opmn:ormi://myServer:oc4j_inst1/ejbsamples");
    
    
    Context context = new InitialContext(env);

    Object homeObject = context.lookup("MyCart");
    CartHome home = (CartHome)PortableRemoteObject.narrow(homeObject,CartHome.class);

     

    詳細は、次を参照してください。

    EJB 3.0クライアントからのEJB 2.1 Enterprise Beanへのアクセス

    EJB 3.0クライアントからEJB 2.1 Enterprise Beanにアクセスするには、次のようにします。

    1. 例29-34に示すように、EJB 2.1 Enterprise Beanのホームおよびリモート・インタフェースへの環境参照を作成します。

      この例では、EJB 2.1 Scheduler Beanのホームおよびリモート・インタフェースへの環境参照を構成します。ジョブ・スケジューラの詳細は、『Oracle Containers for J2EEジョブ・スケジューラ開発者ガイド』を参照してください。

      例29-34    EJB 2.1 Enterprise Beanのホームおよびリモート・インタフェースへの環境参照の作成

      <ejb-ref>
          <ejb-ref-name>ejb/scheduler</ejb-ref-name>
          <ejb-ref-type>Session</ejb-ref-type>
          <home>oracle.ias.scheduler.SchedulerHome</home>
          <remote>oracle.ias.scheduler.SchedulerRemote</remote>
      </ejb-ref>
      
      

      詳細は、第19章「JNDIサービスの構成」を参照してください。

    2. EJB 3.0クライアントからEJB 2.1 Enterprise Beanにアクセスします。

      EJB 3.0クライアントは、次のように様々な方法でEJB 2.1 Enterprise Beanにアクセスできます(これらの方法に限定されるわけではありません)。

      1. 例29-35に示すように、@EJBアノテーションを使用してEJB 2.1ホーム・インタフェースを注入します。

        この例では、@EJBアノテーションのname属性をEJB 2.1 Enterprise Beanの<ejb-ref-name>に設定します。

        例29-35    @EJBを使用したEJB 2.1ホーム・インタフェースの注入

        ...
        public class MyEJB30Client {
        
            @EJB(name="ejb/scheduler")
            SchedulerHome home;
        
            public void bar() {
                home.create();
                ...
            }
        }
        

      2. デプロイXMLの<injection-target>要素を使用してEJB 2.1ホーム・インタフェースを注入します。

        例29-36に、<injection-target>要素をデプロイXMLに追加して、EJB 2.1ホーム・インタフェースをhomeというインスタンス変数に関連付ける方法を示します。例29-37に示すように、EJB 3.0クライアントのインスタンス変数homeは、デプロイ時にOC4Jによって適切に初期化されます。

        例29-36    デプロイXMLへの<injection-target>の追加

        <ejb-ref>
            <ejb-ref-name>ejb/scheduler</ejb-ref-name>
            <ejb-ref-type>Session</ejb-ref-type>
            <home>oracle.ias.scheduler.SchedulerHome</home>
            <remote>oracle.ias.scheduler.SchedulerRemote</remote>
            <injection-target>
                <injection-target-name>home</injection-target-name>
            </injection-target>
        </ejb-ref>
        
        

        例29-37    インスタンス変数へのEJB 2.1ホーム・インタフェースの注入

        ... public class MyEJB30Client {     SchedulerHome home;     public void bar() {         home.create();         ...     } }
      3. 例29-38に示すように、JNDIを使用してEJB 2.1ホーム・インタフェースをルックアップします。

        この例では、EJB 2.1 Enterprise Beanのjava:comp/env/という接頭辞付きの<ejb-ref-name>をルックアップします。

        例29-38   

        ...
        public class MyEJB30Client {
        
            SchedulerHome home;
        
            public void bar() {
                InitalContext ic = new InitialContext();
                home = ic.lookup("java:comp/env/ejb/scheduler");
                home.create();
                ...
            }
        }
        
        

    別のアプリケーションのEJB 2.1 Enterprise Beanへのアクセス

    通常、Enterprise Beanは、複数のEARファイル間、つまり異なるEARファイルにデプロイされたアプリケーション間で通信を行うことはできません。あるEnterprise Beanが、異なるEARファイルにデプロイされているEnterprise Beanにアクセスする唯一の方法は、Enterprise Beanをクライアントの親として宣言することです。子のみが親の中でメソッドを起動できます。

    たとえば、SalesおよびInventoryという2つのEnterprise Beanがあり、それぞれ別のEARファイル内にデプロイされているとします。Sales Enterprise Beanは、Inventory Enterprise Beanを起動して十分なウィジェットが使用可能かどうかをチェックする必要があります。この2つのEnterprise Beanは異なるEARファイルにデプロイされているため、Sales Enterprise BeanでInventory Enterprise Beanを親として定義しないかぎり、Sales Enterprise BeanはInventory Enterprise Bean内でメソッドを起動できません。したがって、Inventory Enterprise BeanをSales Enterprise Beanの親として定義すると、Sales Enterprise Beanは親の中でメソッドを起動できるようになります。

    親を定義できるのは、デプロイ・ウィザードを使用してデプロイを行うときのみです。Beanの親アプリケーションの定義方法については、『Oracle Containers for J2EE構成および管理ガイド』の「admin.jarユーティリティの使用方法」の章の「アプリケーションのデプロイ/アンデプロイ」を参照してください。

    EJB 2.1を使用したJMS宛先へのメッセージの送信

    クライアントは、MDBに直接にはアクセスしません。かわりに、クライアントはMDBに関連付けられているJMS宛先(キューまたはトピック)を通じてメッセージを送信することによりMDBにアクセスします。

    EJB 2.1を使用してJMS宛先にメッセージを送信するには、次のようにします。

    1. JMS宛先(キューまたはトピック)とそのコネクション・ファクトリの両方をルックアップします。

      これらのリソースは、事前定義の論理名またはJMSプロバイダの構成時に定義した明示的なJNDI名を使用してルックアップできます。この手順および例で示すように、論理名を使用することをお薦めします。

      詳細は、次を参照してください。

    2. コネクション・ファクトリを使用して接続を作成します。

      キューに対するメッセージを受信している場合は、接続を開始します。

    3. 接続を使用してセッションを作成します。

    4. 取得したJMS宛先を使用して、キューのセンダーまたはトピックのパブリッシャを作成します。

    5. メッセージを作成します。

    6. キューのセンダーまたはトピックのパブリッシャのいずれかを使用して、メッセージを送信します。

    7. キュー・セッションを閉じます。

    8. 接続を閉じます。

    例29-39に、サーブレット・クライアントがキューにメッセージを送信する方法を示します。

    例29-39    クライアントがメッセージをキューに送信するサーブレット

    public final class testResourceProvider extends HttpServlet {

      private String resProvider = "myResProvider";
      private HashMap msgMap = new HashMap();
      Context ctx = new InitialContext();

      public void doGet(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {
        doPost(req, res);
      }

      public void doPost(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {
       // Retrieve the name of the JMS provider from the request,
       // which is to be used in creating the JNDI string for retrieval
        String rp = req.getParameter ("provider");
        if (rp != null) resProvider = rp;

        try {
          // 1a. Look up the Queue Connection Factory
          QueueConnectionFactory qcf = (QueueConnectionFactory)
              ctx.lookup("java:comp/resource/" + resProvider +
                          "/QueueConnectionFactories/myQCF");
          // 1b. Lookup the Queue
          Queue queue = (Queue)ctx.lookup("java:comp/resource/" +
                                resProvider + "/Queues/rpTestQueue");
          
          // 2a. Create queue connection using the connection factory
          QueueConnection qconn = qcf.createQueueConnection();
          // 2a. You are receiving messages, so start the connection
          qconn.start();

          // 3. Create a session over the queue connection
          QueueSession sess = qconn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

           // 4. Since this is for a queue, create a sender on top of the session
           //This is used to send out the message over the queue
          QueueSender snd = sess.createSender (q);

        drainQueue (sess, q);
        TextMessage msg = null;

        // Send msgs to queue
        for (int i = 0; i < 3; i++) {
          // 5. Create message
          msg = sess.createTextMessage();
          msg.setText ("TestMessage:" + i);

          // Set property of the recipient to be the MDB
          // and set the reply destination
          msg.setStringProperty ("RECIPIENT", "MDB");
          msg.setJMSReplyTo(q);
          
          //6. Send the message using the sender
          snd.send (msg);

          // You can store the messages IDs and sent-time  in a map (msgMap),
          // so that when messages are received, you can verify if you
          // *only* received those messages that you were
          // expecting. See receiveFromMDB() method where msgMap gets used
          msgMap.put( msg.getJMSMessageID(), new Long (msg.getJMSTimestamp()));
        }

        // receive a reply from the MDB
        receiveFromMDB (sess, q);

         // 7. Close sender, session, and connection for queue
         snd.close();
         sess.close();
         qconn.close();
        }
        catch (Exception e) {
          System.err.println ("** TEST FAILED **"+ e.toString());
          e.printStackTrace();
        }
        finally {
        }
    }

      // Receive any messages sent through the MDB
      private void receiveFromMDB (QueueSession sess, Queue q)
        throws Exception {
        // The MDB sends out a message (as a reply) to this client. The MDB sets
        // the receipient as CLIENT. Thus, you will only receive messages that have
        // RECIPIENT set to 'CLIENT'
        QueueReceiver rcv = sess.createReceiver (q, "RECIPIENT = 'CLIENT'");

        int nrcvd = 0;
        long trtimes = 0L;
        long tctimes = 0L;
        // First message needs to come from MDB. May take
        // a while receiving messages
        for (Message msg = rcv.receive (30000); msg != null; msg = rcv.receive (30000)) {
          nrcvd++;
          String rcp = msg.getStringProperty ("RECIPIENT");

          // Verify if messages in message Map  
          // Check the msgMap to see if this is the message that you are expecting
          String corrid = msg.getJMSCorrelationID();
          if (msgMap.containsKey(corrid)) {
            msgMap.remove(corrid);
          }
          else {
            System.err.println ("** received unexpected message [" + corrid + "] **");
          }
        }
        rcv.close();
      }

      // Drain messages from queue
      private int drainQueue (QueueSession sess, Queue q)
        throws Exception {
        QueueReceiver rcv = sess.createReceiver (q);
        int nrcvd = 0;

        // First drain any old messages from queue
        for (Message msg = rcv.receive(1000); msg != null; msg = rcv.receive(1000))
          nrcvd++;

        rcv.close();

        return nrcvd;
      }
    }

     

    EJB 2.1 EJBContextへのアクセス

    EJB 2.1セッション、エンティティおよびメッセージドリブンBeanの場合は、Beanの実装時に適切なgetterおよびsetterメソッドを提供することにより、OC4Jで提供されるEJBContextにアクセスできます。

    詳細は、次を参照してください。

    パラメータの処理

    この項の内容は次のとおりです。

    Enterprise Beanへのパラメータ情報の受渡し

    Enterprise Beanを実装する場合、またはEJBメソッドをコールするクライアント・コードを作成する場合、Enterprise Beanで使用されるパラメータの受渡し規則に注意する必要があります。

    Beanメソッドに渡すパラメータ(またはBeanメソッドからの戻り値)には、シリアライズ可能なすべてのJavaタイプを使用可能です。intdoubleなど、Javaのプリミティブ型は、シリアライズ可能です。java.io.Serializableインタフェースを実装する非リモート・オブジェクトは、すべて受渡し可能です。パラメータとしてBeanに渡されるかBeanから返される非リモート・オブジェクトは、参照渡しではなく、値渡しされます。たとえば、次のようにBeanメソッドをコールしたとします。

    public class theNumber {
       int x;
    }
    ...
    bean.method1(theNumber);
    
    

     

    この場合、Bean内のmethod1()は、theNumberのコピーを受信します。BeanによってサーバーのtheNumberオブジェクトの値が変更されても、値渡しのセマンティクスを使用しているため、クライアントにはこの変更は反映されません。

    非リモート・オブジェクトが複合的である場合(複数のフィールドが含まれているクラスなど)、非静的で非一時的なフィールドのみコピーされます。

    リモート・オブジェクトをパラメータとして渡す場合、リモート・オブジェクトのスタブが渡されます。パラメータとして渡されるリモート・オブジェクトは、リモート・インタフェースを拡張する必要があります。

    次の項では、Beanへのパラメータの受渡しと、戻り値としてのリモート・オブジェクトについて説明します。

    Enterprise Beanから返されるパラメータの処理

    EmployeeBeanのメソッドgetEmployeeEmpRecordオブジェクトを返すため、このオブジェクトをアプリケーション内で定義しておく必要があります。この例では、EmpRecordクラスは、EJBインタフェースと同じパッケージに含まれています。

    クラスはpublicとして宣言されており、シリアライズされたリモート・オブジェクトとしてクライアントに値を返せるよう、java.io.Serializableインタフェースを実装する必要があります。次のように宣言します。

    package employee;
    
    public class EmpRecord implements java.io.Serializable {
      public String ename;
      public int empno;
      public double sal;
    }
    


    注意

    java.io.Serializableインタフェースではメソッドを指定しません。クラスがシリアライズ可能であることのみ示します。そのため、EmpRecordクラスで他のメソッドを実装する必要はありません。 


    例外の処理

    この項の内容は次のとおりです。

    リモートEnterprise Beanへのアクセス中に発生するNamingExceptionからのリカバリ

    Enterprise Beanにリモートでアクセスしようとし、javax.naming.NamingExceptionエラーが発生する場合、JNDIプロパティが正しく初期化されていない可能性があります。リモート・オブジェクトまたはリモート・サーブレットからEnterprise BeanにアクセスするときのJNDIプロパティの設定に関する説明は、「ロード・バランシング」を参照してください。

    リモートEnterprise Beanへのアクセス中に発生するNullPointerExceptionからのリカバリ

    WebアプリケーションからリモートEnterprise Beanにアクセスするときに、「java.lang.NullPointerException: domain was null」というエラーが表示されます。この場合、dedicated.rmicontexttrueに設定されているEnterprise Beanにアクセスするときは、環境プロパティをクライアントに設定する必要があります。

    次の例は、この追加環境プロパティを使用する方法を示しています。

    Hashtable env = new Hashtable( );
    env.put (Context.INITIAL_CONTEXT_FACTORY,
      "oracle.j2ee.rmi.RMIInitialContextFactory");
    env.put (Context.SECURITY_PRINCIPAL, "oc4jadmin");
    env.put (Context.SECURITY_CREDENTIALS, "oc4jadmin");
    env.put (Context.PROVIDER_URL, "ormi://myhost-us/ejbsamples");
    env.put ("dedicated.rmicontext", "true"); // for 9.0.2.1 and later
    Context context = new InitialContext (env);
    
    

     

    dedicated.rmicontextの詳細は、「ロード・バランシング」を参照してください。

    デッドロック状態からのリカバリ

    デッドロックの原因が複数のBeanのコール・シーケンスにある場合、OC4Jはデッドロック状態を検出し、違反しているBeanの1つにあるデッドロック状態の詳細を示すRemote例外をスローします。


  • 戻る 次へ
    Oracle
    Copyright © 2002, 2008 Oracle Corporation.

    All Rights Reserved.
    目次
    目次
    索引
    索引