Ejb-quick-guide

提供:Dev Guides
移動先:案内検索

EJB-概要

EJBは Enterprise Java Beans の略です。 EJBは、J2EEプラットフォームの重要な部分です。 J2EEプラットフォームにはコンポーネントベースのアーキテクチャがあり、多層、分散、高度なトランザクション機能をエンタープライズレベルのアプリケーションに提供します。

EJBは、堅牢性、高いスケーラビリティ、および高いパフォーマンスを考慮したコンポーネントベースのエンタープライズアプリケーションを開発および展開するためのアーキテクチャを提供します。 EJBアプリケーションは、J2EE 1.3標準仕様に準拠した任意のアプリケーションサーバーにデプロイできます。

このチュートリアルでは、EJB 3.0について詳しく説明します。

タイプ

EJBは主に3つのカテゴリに分類されます。次の表は、簡単な説明とその名前を示しています-

S.No Type & Description
1

Session Bean

セッションBeanは、単一セッションの特定のユーザーのデータを保存します。 link:/ejb/ejb_stateful_beans [ stateful ]またはlink:/ejb/ejb_stateless_beans [ stateless ]にすることができます。 エンティティBeanと比較して、リソースをあまり消費しません。 セッションBeanは、ユーザーセッションが終了するとすぐに破棄されます。

2

Entity Bean

  • link:/ejb/ejb_persistence [エンティティBean]* は永続的なデータストレージを表します。 ユーザーデータは、エンティティBeanを介してデータベースに保存でき、後でエンティティBeanのデータベースから取得できます。
3

Message Driven Bean

  • link:/ejb/ejb_message_driven_beans [メッセージ駆動型Bean]* は、JMS(Java Messaging Service)のコンテキストで使用されます。 メッセージ駆動型Beanは、外部エンティティからのJMSメッセージを消費し、それに応じて動作できます。

利点

EJBの重要な利点は次のとおりです-

  • 大規模なエンタープライズレベルアプリケーションの開発の簡素化。
  • Application Server/EJBコンテナは、トランザクション処理、ロギング、負荷分散、永続化メカニズム、例外処理などのほとんどのシステムレベルのサービスを提供します。 開発者は、アプリケーションのビジネスロジックのみに集中する必要があります。
  • EJBコンテナはEJBインスタンスのライフサイクルを管理するため、開発者はいつEJBオブジェクトを作成/削除するかを心配する必要はありません。

EJB-環境設定

EJBはJavaのフレームワークなので、最初の要件は* J ava D evelopment K * it(JDK)をマシンにインストールすることです。

システム要件

JDK 1.5 or above.
Memory no minimum requirement.
Disk Space no minimum requirement.
Operating System no minimum requirement.

ステップ1-システムでのJavaインストールの検証

コンソールを開き、次の java コマンドを実行します。

OS Task Command
Windows Open Command Console c:\> java -version
Linux Open Command Terminal $ java -version
Mac Open Terminal machine:~ joseph$ java -version

すべてのオペレーティングシステムの出力を確認しましょう-

OS Output
Windows

java version "1.6.0_21"

Java(TM)SEランタイム環境(ビルド1.6.0_21-b11)

Java HotSpot(TM)64ビットサーバーVM(ビルド23.21-b01、混合モード)

Linux

java version "1.6.0_21"

Java(TM)SEランタイム環境(ビルド1.6.0_21-b11)

Java HotSpot(TM)64ビットサーバーVM(ビルド23.21-b01、混合モード)

Mac

java version "1.6.0_21"

Java(TM)SEランタイム環境(ビルド1.6.0_21-b11)

Java HotSpot(TM)64ビットサーバーVM(ビルド23.21-b01、混合モード)

Javaをインストールしていない場合は、https://www.oracle.com/technetwork/java/javase/downloads/indexl [www.oracle.com]からJava Software Development Kit(SDK)をインストールしてください。 このチュートリアルのインストールバージョンとしてJava 1.6.0_21を想定しています。

ステップ2 – JAVA環境の設定

*JAVA_HOME* 環境変数を設定して、システムにJavaがインストールされているベースディレクトリの場所を指定します。 例えば、
OS Output
Windows Set the environment variable JAVA_HOME to C:\Program Files\Java\jdk1.6.0_21
Linux export JAVA_HOME=/usr/local/java-current
Mac export JAVA_HOME=/Library/Java/Home

Javaコンパイラの場所をシステムパスに追加します。

OS Output
Windows Append the string ;C:\Program Files\Java\jdk1.6.0_21\bin to the end of the system variable, Path.
Linux export PATH=$PATH:$JAVA_HOME/bin/
Mac not required

上記の java -version コマンドを使用してJavaインストールを確認します。

ステップ3 – NetBeans IDEのダウンロードとインストール

netbeans.orgからNetBeans IDEの最新バージョンをダウンロードします。 このチュートリアルを書いているときに、JDK 1.7にバンドルされている_Netbeans 7.3_を次のリンクを使用してダウンロードしました。https://www.oracle.com/technetwork/java/javase/downloads/indexl [www.oracle.com]

OS Installer name
Windows Netbeans 7.3
Linux Netbeans 7.3
Mac Netbeans 7.3

ステップ4 – JBoss Application Serverのセットアップ

JBoss Serverの最新バージョンはhttps://www.jboss.org/jbossas/downloads/[www.jboss.org]からダウンロードできます。 プラットフォームごとにアーカイブをダウンロードします。 Jbossをマシンの任意の場所に抽出します。

OS File name
Windows jboss-5.1.0.GA-jdk6.zip
Linux jboss-5.1.0.GA-src.tar.gz
Mac jboss-5.1.0.GA-src.tar.gz

ステップ5-NetBeansへのJEEプラグインの構成

[ツール]> [プラグイン]を使用して、[プラグイン]ウィンドウを開きます。 [利用可能なプラグイン]タブを開き、[Java Web and EE]カテゴリで[Java EE Base]と[EJB and EAR]を選択します。 インストールボタンをクリックします。 Netbeansは、それぞれのプラグインをダウンロードしてインストールします。 「インストール済み」タブを使用してプラグインのインストールを確認します(下の画像を参照)。

インストールされているプラ​​グイン

ステップ6-NetbeansでJBossサーバーを設定する

[サービス]タブに移動し、サーバーを右クリックして新しいサーバーを追加します。

サーバーの追加

サーバーインスタンスの追加ウィザードが開きます。 JBossを選択し、次のステップで関連する詳細を入力して、netbeansでサーバーを構成します。

サーバーの選択

すべての設定が完了すると、次の画面が表示されます。

インストールされているサーバー

手順7-データベースサーバーのインストール(PostGreSql)

www.postgresql.orgからPostGreSqlデータベースサーバーの最新バージョンをダウンロードします。 このチュートリアルを書いている時点で、_PostGreSql 9.2_をダウンロードしました

OS Installer name
Windows PostGreSql 9.2
Linux PostGreSql 9.2
Mac PostGreSql 9.2

EJB-アプリケーションの作成

単純なEJBモジュールを作成するには、NetBeansの「新規プロジェクト」ウィザードを使用します。 以下の例では、Componentという名前のEJBモジュールプロジェクトを作成します。

プロジェクトを作成

NetBeans IDEで、「ファイル」>「新規プロジェクト」> *を選択します。 次の画面が表示されます

新しいプロジェクトウィザードのステップ1

カテゴリ Java EE でプロジェクトタイプを選択し、プロジェクトタイプとして* EJBモジュール*を選択します。 Next> ボタンをクリックします。 次の画面が表示されます。

新しいプロジェクトウィザードのステップ2

プロジェクト名と場所を入力します。 Next> ボタンをクリックします。 次の画面が表示されます。

新しいプロジェクトウィザードのステップ3

*JBoss Application Server* としてサーバーを選択します。 [完了]ボタンをクリックします。 NetBeansによって作成された次のプロジェクトが表示されます。

プロジェクトエクスプローラ

サンプルEJBを作成する

単純なEJBを作成するには、NetBeansの「新規」ウィザードを使用します。 以下の例では、EjbComponentプロジェクトの下にlibrarySessionBeanという名前のステートレスEJBクラスを作成します。

プロジェクトエクスプローラーウィンドウでプロジェクトEjbComponentを選択し、右クリックします。 New> Session Bean を選択します。 New Session Bean ウィザードが表示されます。

新しいセッションBeanウィザード

セッションBean名とパッケージ名を入力します。 [完了]ボタンをクリックします。 NetBeansによって作成された次のEJBクラスが表示されます。

  • LibrarySessionBean -ステートレスセッションBean
  • LibrarySessionBeanLocal -セッションBeanのローカルインターフェイス

コンソールベースのアプリケーションでEJBにアクセスするため、ローカルインターフェースをリモートインターフェースに変更しています。 リモート/ローカルインターフェイスは、EJBが実装する必要があるビジネスメソッドを公開するために使用されます。

LibrarySessionBeanLocalはLibrarySessionBeanRemoteに名前が変更され、LibrarySessionBeanはLibrarySessionBeanRemoteインターフェースを実装します。

LibrarySessionBeanRemote

package com.finddevguides.stateless;

import java.util.List;
import javax.ejb.Remote;

@Remote
public interface LibrarySessionBeanRemote {
   void addBook(String bookName);
   List getBooks();
}

LibrarySessionBean

package com.finddevguides.stateless;

import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;

@Stateless
public class LibrarySessionBean implements LibrarySessionBeanRemote {

   List<String> bookShelf;

   public LibrarySessionBean() {
      bookShelf = new ArrayList<String>();
   }

   public void addBook(String bookName) {
      bookShelf.add(bookName);
   }

   public List<String> getBooks() {
      return bookShelf;
   }
}

プロジェクトを構築する

  • Project ExplorerウィンドウでEjbComponentプロジェクトを選択します。
  • 右クリックしてコンテキストメニューを開きます。
  • クリーンおよびビルドを選択します。

NetBeansコンソールの出力に次の出力が表示されます。

ant -f C:\\EJB\\EjbComponent clean dist
init:
undeploy-clean:
deps-clean:
Deleting directory C:\EJB\EjbComponent\build
Deleting directory C:\EJB\EjbComponent\dist
clean:
init:
deps-jar:
Created dir: C:\EJB\EjbComponent\build\classes
Copying 3 files to C:\EJB\EjbComponent\build\classes\META-INF
Created dir: C:\EJB\EjbComponent\build\empty
Created dir: C:\EJB\EjbComponent\build\generated-sources\ap-source-output
Compiling 2 source files to C:\EJB\EjbComponent\build\classes
warning: [options] bootstrap class path not set in conjunction with -source 1.6
Note: C:\EJB\EjbComponent\src\java\com\finddevguides\stateless
\LibraryPersistentBean.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 warning
compile:
library-inclusion-in-archive:
Created dir: C:\EJB\EjbComponent\dist
Building jar: C:\EJB\EjbComponent\dist\EjbComponent.jar
dist:
BUILD SUCCESSFUL (total time: 3 seconds)

アプリケーションサーバーを起動する

  • [サービス]ウィンドウの[サーバー]でJBossアプリケーションサーバーを選択します。
  • 右クリックしてコンテキストメニューを開きます。
  • 開始を選択します。

NetBeansでは、JBoss Application Serverの下に次の出力が表示されます。

Calling C:\jboss-5.1.0.GA\bin\run.conf.bat
=========================================================================

   JBoss Bootstrap Environment

   JBOSS_HOME: C:\jboss-5.1.0.GA

   JAVA: C:\Program Files (x86)\Java\jdk1.6.0_21\bin\java

   JAVA_OPTS: -Dprogram.name=run.bat -Xms128m -Xmx512m -server

   CLASSPATH: C:\jboss-5.1.0.GA\bin\run.jar

=========================================================================

16:25:50,062 INFO  [ServerImpl] Starting JBoss (Microcontainer)...
16:25:50,062 INFO  [ServerImpl] Release ID: JBoss
   [The Oracle] 5.1.0.GA (build: SVNTag=JBoss_5_1_0_GA date=200905221634)
...

16:26:40,420 INFO  [TomcatDeployment] deploy, ctxPath=/admin-console
16:26:40,485 INFO  [config] Initializing Mojarra (1.2_12-b01-FCS) for context '/admin-console'
16:26:42,362 INFO  [TomcatDeployment] deploy, ctxPath=/
16:26:42,406 INFO  [TomcatDeployment] deploy, ctxPath=/jmx-console
16:26:42,471 INFO  [Http11Protocol] Starting Coyote HTTP/1.1 on http-127.0.0.1-8080
16:26:42,487 INFO  [AjpProtocol] Starting Coyote AJP/1.3 on ajp-127.0.0.1-8009
16:26:42,493 INFO  [ServerImpl] JBoss (Microcontainer)
   [5.1.0.GA (build: SVNTag=JBoss_5_1_0_GA date=200905221634)] Started in 52s:427ms

プロジェクトを展開する

  • Project ExplorerウィンドウでEjbComponentプロジェクトを選択します。
  • 右クリックしてコンテキストメニューを開きます。
  • デプロイを選択します。

NetBeansコンソールの出力に次の出力が表示されます。

ant -f C:\\EJB\\EjbComponent -DforceRedeploy=true -Ddirectory.deployment.supported=false -Dnb.wait.for.caches=true run
init:
deps-jar:
compile:
library-inclusion-in-archive:
Building jar: C:\EJB\EjbComponent\dist\EjbComponent.jar
dist-directory-deploy:
pre-run-deploy:
Checking data source definitions for missing JDBC drivers...
Distributing C:\EJB\EjbComponent\dist\EjbComponent.jar to [org.jboss.deployment.spi.LocalhostTarget@1e4f84ee]
Deploying C:\EJB\EjbComponent\dist\EjbComponent.jar
Application Deployed
Operation start started
Operation start completed
post-run-deploy:
run-deploy:
run:
BUILD SUCCESSFUL (total time: 2 seconds)

JBoss Application Serverのログ出力

16:30:00,963 INFO  [DeployHandler] Begin start, [EjbComponent.jar]
...
16:30:01,233 INFO  [Ejb3DependenciesDeployer] Encountered deployment AbstractVFSDeploymentContext@12038795{vfszip:/C:/jboss-5.1.0.GA/server/default/deploy/EjbComponent.jar/}
...
16:30:01,281 INFO  [JBossASKernel]    jndi:LibrarySessionBean/remote-com.finddevguides.stateless.LibrarySessionBeanRemote
16:30:01,281 INFO  [JBossASKernel]    Class:com.finddevguides.stateless.LibrarySessionBeanRemote
16:30:01,281 INFO  [JBossASKernel]    jndi:LibrarySessionBean/remote
16:30:01,281 INFO  [JBossASKernel]  Added bean(jboss.j2ee:jar=EjbComponent.jar,name=
LibrarySessionBean,service=EJB3) to KernelDeployment of: EjbComponent.jar
16:30:01,282 INFO  [JBossASKernel] installing bean: jboss.j2ee:jar=EjbComponent.jar,name=BookMessageHandler,service=EJB3
16:30:01,282 INFO  [JBossASKernel]   with dependencies:
16:30:01,282 INFO  [JBossASKernel]   and demands:
16:30:01,282 INFO  [JBossASKernel]    jboss.ejb:service=EJBTimerService
...
16:30:01,283 INFO  [EJB3EndpointDeployer] Deploy
AbstractBeanMetaData@5497cb{name=jboss.j2ee:jar=EjbComponent.jar,
name=LibrarySessionBean, service=EJB3_endpoint bean=org.jboss.ejb3.endpoint.deployers.impl.EndpointImpl properties=[container] constructor=null autowireCandidate=true}
...
16:30:01,394 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibrarySessionBean,service=EJB3
16:30:01,395 INFO  [EJBContainer] STARTED EJB: com.finddevguides.stateless.LibrarySessionBean ejbName: LibrarySessionBean
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibrarySessionBean/remote - EJB3.x Default Remote Business Interface
   LibrarySessionBean/remote-com.finddevguides.stateless.LibrarySessionBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibrarySessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.stateless.LibrarySessionBean ejbName: LibrarySessionBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

   LibrarySessionBean/remote - EJB3.x Default Remote Business Interface
   LibrarySessionBean/remote-com.finddevguides.stateless.LibrarySessionBeanRemote - EJB3.x Remote Business Interface

EJBにアクセスするクライアントを作成する

 *NetBeans IDEで、「ファイル」>「新規プロジェクト」>* を選択します。
* カテゴリ *Java* の下のプロジェクトタイプを選択し、プロジェクトタイプとして* Javaアプリケーション*を選択します。 [次へ>]ボタンをクリックします
 *プロジェクト名と場所を入力します。* 完了> *ボタンをクリックします。 EjbTesterとして名前を選択しました。
 *Project Explorerウィンドウでプロジェクト名を右クリックします。* properties *を選択します。
* *compile* タブの *Add Project* ボタンを使用して、ライブラリの下に以前に作成されたEJBコンポーネントプロジェクトを追加します。
* *compile* タブの *Add jar/folder* ボタンを使用してjbossライブラリを追加します。 Jbossライブラリは、<jbossインストールフォルダー>>クライアントフォルダーにあります。

EjbTesterというプロジェクトの下にjndi.propertiesを作成します。

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost

その下にパッケージcom.finddevguides.testおよびEJBTester.javaクラスを作成します。

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.stateless.LibrarySessionBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;


public class EJBTester {
   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testStatelessEjb();
   }
   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testStatelessEjb() {
      try {
         int choice = 1;
         LibrarySessionBeanRemote libraryBean =
         (LibrarySessionBeanRemote)ctx.lookup("LibrarySessionBean/remote");
         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               libraryBean.addBook(bookName);
            }else if (choice == 2) {
               break;
            }
         }
         List<String> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " + booksList.size());
         for (int i = 0; i < booksList.size(); ++i) {
            System.out.println((i+1)+". " + booksList.get(i));
         }
         LibrarySessionBeanRemote libraryBean1 =
         (LibrarySessionBeanRemote)ctx.lookup("LibrarySessionBean/remote");
         List<String> booksList1 = libraryBean1.getBooks();
         System.out.println(
            "***Using second lookup to get library stateless object***");
         System.out.println(
            "Book(s) entered so far: " + booksList1.size());
         for (int i = 0; i < booksList1.size(); ++i) {
            System.out.println((i+1)+". " + booksList1.get(i));
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      } finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 1
1. Learn Java
***Using second lookup to get library stateless object***
Book(s) entered so far: 0
BUILD SUCCESSFUL (total time: 13 seconds)

次の章では、この完全なEJBアプリケーションの複数の側面について説明します。

EJB-ステートレスBean

ステートレスセッションBeanは、通常、独立した操作を実行するために使用されるエンタープライズBeanの一種です。 その名前のとおりのステートレスセッションBeanには、関連付けられたクライアント状態はありませんが、インスタンス状態は保持されます。 EJBコンテナは通常、少数のステートレスBeanのオブジェクトのプールを作成し、これらのオブジェクトを使用してクライアントの要求を処理します。 プールのため、インスタンス変数値はルックアップ/メソッド呼び出し全体で同じであるとは限りません。

ステートレスEJBを作成する手順

ステートレスEJBを作成するために必要な手順は次のとおりです-

  • ビジネスメソッドを公開するリモート/ローカルインターフェイスを作成します。
  • このインターフェイスは、EJBクライアントアプリケーションによって使用されます。
  • EJBクライアントがEJBセッションBeanがデプロイされるのと同じ環境にある場合は、@ Localアノテーションを使用します。
  • EJBクライアントがEJBセッションBeanがデプロイされる異なる環境にある場合は、@ Remoteアノテーションを使用します。
  • 上記のインターフェースを実装して、ステートレスセッションBeanを作成します。 *@Statelessアノテーションを使用して、ステートレスBeanであることを示します。 EJBコンテナは、デプロイメント中にこのアノテーションを読み取ることで必要な関連する構成またはインターフェースを自動的に作成します。

リモートインターフェース

import javax.ejb.Remote;

@Remote
public interface LibrarySessionBeanRemote {
  //add business method declarations
}

ステートレスEJB

@Stateless
public class LibrarySessionBean implements LibrarySessionBeanRemote {
  //implement business method
}

応用例

テストEJBアプリケーションを作成して、ステートレスEJBをテストしましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.stateless as explained in the EJB - Create Application chapter. You can also use the project created in EJB - Create Application chapter as such for this chapter to understand stateless EJB concepts.
2 Create LibrarySessionBean.java and LibrarySessionBeanRemote as explained in the EJB - Create Application chapter. Keep rest of the files unchanged.
3 Clean and Build the application to make sure business logic is working as per the requirements.
4 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
5 Now create the EJB client, a console based application in the same way as explained in the EJB - Create Application chapter under topic* Create Client to access EJB*.

EJBComponent(EJBモジュール)

LibrarySessionBeanRemote.java

package com.finddevguides.stateless;

import java.util.List;
import javax.ejb.Remote;

@Remote
public interface LibrarySessionBeanRemote {
   void addBook(String bookName);
   List getBooks();
}

LibrarySessionBean.java

package com.finddevguides.stateless;

import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;

@Stateless
public class LibrarySessionBean implements LibrarySessionBeanRemote {

   List<String> bookShelf;

   public LibrarySessionBean() {
      bookShelf = new ArrayList<String>();
   }

   public void addBook(String bookName) {
      bookShelf.add(bookName);
   }

   public List<String> getBooks() {
      return bookShelf;
   }
}
  • EjbComponentプロジェクトをJBOSSにデプロイするとすぐに、jbossログに注目してください。
  • JBossは、セッションBeanのJNDIエントリ- LibrarySessionBean/remote を自動的に作成しました。
  • このルックアップ文字列を使用して、タイプのリモートビジネスオブジェクトを取得します- com.finddevguides.stateless.LibrarySessionBeanRemote

JBoss Application Serverのログ出力

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibrarySessionBean/remote - EJB3.x Default Remote Business Interface
   LibrarySessionBean/remote-com.finddevguides.stateless.LibrarySessionBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibrarySessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.stateless.LibrarySessionBeanRemote ejbName: LibrarySessionBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

   LibrarySessionBean/remote - EJB3.x Default Remote Business Interface
   LibrarySessionBean/remote-com.finddevguides.stateless.LibrarySessionBeanRemote - EJB3.x Remote Business Interface
...

EJBTester(EJBクライアント)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • これらのプロパティは、JavaネームサービスのInitialContextオブジェクトを初期化するために使用されます。
  • InitialContextオブジェクトは、ステートレスセッションBeanのルックアップに使用されます。

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.stateful.LibrarySessionBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testStatelessEjb();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testStatelessEjb() {

      try {
         int choice = 1;

         LibrarySessionBeanRemote libraryBean =
         LibrarySessionBeanRemote)ctx.lookup("LibrarySessionBean/remote");

         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);
            } else if (choice == 2) {
               break;
            }
         }

         List<Book> booksList = libraryBean.getBooks();

         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }
         LibrarySessionBeanRemote libraryBean1 =
            (LibrarySessionBeanRemote)ctx.lookup("LibrarySessionBean/remote");
         List<String> booksList1 = libraryBean1.getBooks();
         System.out.println(
            "***Using second lookup to get library stateless object***");
         System.out.println(
            "Book(s) entered so far: " + booksList1.size());
         for (int i = 0; i < booksList1.size(); ++i) {
            System.out.println((i+1)+". " + booksList1.get(i));
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTesterは次のタスクを実行します-

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testStatelessEjb()メソッドでは、jndiルックアップが名前-"LibrarySessionBean/remote"で実行され、リモートビジネスオブジェクト(ステートレスejb)が取得されます。
  • 次に、ユーザーにライブラリストアのユーザーインターフェイスが表示され、選択を入力するように求められます。
  • ユーザーが1を入力すると、システムはブック名を要求し、ステートレスセッションBeanのaddBook()メソッドを使用してブックを保存します。 セッションBeanは、ブックをそのインスタンス変数に保存しています。
  • ユーザーが2を入力すると、システムはステートレスセッションBeanのgetBooks()メソッドを使用して本を取得し、終了します。
  • 次に、「LibrarySessionBean/remote」という名前で別のjndiルックアップが実行されて、リモートビジネスオブジェクト(ステートレスEJB)が再度取得され、ブックのリストが作成されます。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 1
1. Learn Java
***Using second lookup to get library stateless object***
Book(s) entered so far: 0
BUILD SUCCESSFUL (total time: 13 seconds)

EJBにアクセスするためのクライアントの再実行

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 0
***Using second lookup to get library stateless object***
Book(s) entered so far: 1
1. Learn Java
BUILD SUCCESSFUL (total time: 12 seconds)
  • 上記の出力は、JBossが保持しているステートレスEJBオブジェクトの数によって異なる場合があります。
  • 単一のステートレスEJBオブジェクトが保持されている場合、各ルックアップ後に同じブックのリストが表示される場合があります。
  • EJBコンテナは、ルックアップごとに同じステートレスEJBオブジェクトを返す場合があります。
  • ステートレスEJB Beanは、サーバーが再起動されない限り、インスタンス変数の値を保持しています。

EJB-ステートフルBean

ステートフルセッションBeanは、エンタープライズBeanの一種であり、クライアントとの会話状態を保持します。 その名前のとおりのステートフルセッションBeanは、そのインスタンス変数に関連付けられたクライアント状態を保持します。 EJBコンテナは、クライアントの各リクエストを処理するために別個のステートフルセッションBeanを作成します。 要求のスコープが終了するとすぐに、ステートフルセッションBeanは破棄されます。

ステートフルEJBを作成する手順

以下は、ステートフルEJBを作成するために必要な手順です-

  • ビジネスメソッドを公開するリモート/ローカルインターフェイスを作成します。
  • このインターフェイスは、EJBクライアントアプリケーションによって使用されます。
  • EJBクライアントがEJBセッションBeanをデプロイする必要がある同じ環境にある場合は、@ Localアノテーションを使用します。
  • EJBクライアントが、EJBセッションBeanをデプロイする必要がある異なる環境にある場合は、@ Remoteアノテーションを使用します。
  • 上記のインターフェースを実装して、ステートフルセッションBeanを作成します。 *@Statefulアノテーションを使用して、ステートフルBeanであることを示します。 EJBコンテナは、デプロイメント中にこのアノテーションを読み取ることで必要な関連する構成またはインターフェースを自動的に作成します。

リモートインターフェース

import javax.ejb.Remote;

@Remote
public interface LibraryStatefulSessionBeanRemote {
  //add business method declarations
}

ステートフルEJB

@Stateful
public class LibraryStatefulSessionBean implements LibraryStatefulSessionBeanRemote {
  //implement business method
}

応用例

テストEJBアプリケーションを作成して、ステートフルEJBをテストしましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.stateful as explained in the EJB − Create Application chapter. You can also use the project created in EJB - Create Application chapter as such for this chapter to understand stateful EJB concepts.
2 Create LibraryStatefulSessionBean.java and LibraryStatefulSessionBeanRemote as explained in the EJB − Create Application chapter. Keep rest of the files unchanged.
3 Clean and Build the application to make sure business logic is working as per the requirements.
4 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
5 Now create the EJB client, a console based application in the same way as explained in the EJB - Create Application chapter under topic* Create Client to access EJB*.

EJBComponent(EJBモジュール)

LibraryStatefulSessionBeanRemote.java

package com.finddevguides.stateful;

import java.util.List;
import javax.ejb.Remote;

@Remote
public interface LibraryStatefulSessionBeanRemote {
   void addBook(String bookName);
   List getBooks();
}

LibraryStatefulSessionBean.java

package com.finddevguides.stateful;

import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateful;

@Stateful
public class LibraryStatefulSessionBean implements LibraryStatefulSessionBeanRemote {

   List<String> bookShelf;

   public LibraryStatefulSessionBean() {
      bookShelf = new ArrayList<String>();
   }

   public void addBook(String bookName) {
      bookShelf.add(bookName);
   }

   public List<String> getBooks() {
      return bookShelf;
   }
}
  • EjbComponentプロジェクトをJBOSSにデプロイするとすぐに、jbossログに注目してください。
  • JBossは、セッションBeanのJNDIエントリを自動的に作成しました- LibraryStatefulSessionBean/remote
  • このルックアップ文字列を使用して、タイプのリモートビジネスオブジェクトを取得します- com.finddevguides.stateful.LibraryStatefulSessionBeanRemote

JBoss Application Serverのログ出力

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryStatefulSessionBean/remote - EJB3.x Default Remote Business Interface
   LibraryStatefulSessionBean/remote-com.finddevguides.stateful.LibraryStatefulSessionBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryStatefulSessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.stateful.LibraryStatefulSessionBeanRemote ejbName: LibraryStatefulSessionBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

   LibraryStatefulSessionBean/remote - EJB3.x Default Remote Business Interface
   LibraryStatefulSessionBean/remote-com.finddevguides.stateful.LibraryStatefulSessionBeanRemote - EJB3.x Remote Business Interface
...

EJBTester(EJBクライアント)

jndi.properties

java.naming.factory.initial = org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs = org.jboss.naming:org.jnp.interfaces
java.naming.provider.url = localhost
  • これらのプロパティは、JavaネームサービスのInitialContextオブジェクトを初期化するために使用されます。
  • InitialContextオブジェクトは、ステートフルセッションBeanのルックアップに使用されます。

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.stateful.LibraryStatefulSessionBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testStatelessEjb();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testStatelessEjb() {

      try {
         int choice = 1;

         LibraryStatefulSessionBeanRemote libraryBean =
         LibraryStatefulSessionBeanRemote)ctx.lookup("LibraryStatefulSessionBean/remote");

         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);
            } else if (choice == 2) {
               break;
            }
         }

         List<Book> booksList = libraryBean.getBooks();

         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }
         LibraryStatefulSessionBeanRemote libraryBean1 =
            (LibraryStatefulSessionBeanRemote)ctx.lookup("LibraryStatefulSessionBean/remote");
         List<String> booksList1 = libraryBean1.getBooks();
         System.out.println(
            "***Using second lookup to get library stateful object***");
         System.out.println(
            "Book(s) entered so far: " + booksList1.size());
         for (int i = 0; i < booksList1.size(); ++i) {
            System.out.println((i+1)+". " + booksList1.get(i));
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTesterは次のタスクを実行します-

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testStatefulEjb()メソッドでは、jndiルックアップが名前-"LibraryStatefulSessionBean/remote"で実行され、リモートビジネスオブジェクト(ステートフルejb)が取得されます。
  • 次に、ユーザーにライブラリストアのユーザーインターフェイスが表示され、選択肢を入力するように求められます。
  • ユーザーが1を入力すると、システムはブック名を要求し、ステートフルセッションBeanのaddBook()メソッドを使用してブックを保存します。 セッションBeanは、ブックをそのインスタンス変数に保存しています。
  • ユーザーが2を入力すると、システムはステートフルセッションBeanのgetBooks()メソッドを使用して本を取得し、終了します。
  • 次に、「LibraryStatefulSessionBean/remote」という名前で別のjndiルックアップが行われ、リモートビジネスオブジェクト(ステートフルEJB)が再度取得され、書籍のリストが作成されます。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します-

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 1
1. Learn Java
***Using second lookup to get library stateful object***
Book(s) entered so far: 0
BUILD SUCCESSFUL (total time: 13 seconds)

EJBにアクセスするためのクライアントの再実行

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 0
***Using second lookup to get library stateful object***
Book(s) entered so far: 0
BUILD SUCCESSFUL (total time: 12 seconds)
  • 上記の出力は、ルックアップごとに、異なるステートフルEJBインスタンスを示しています が返されます。
  • ステートフルEJBオブジェクトは、単一セッションのみの価値を保持しています。 2回目の実行のように、 本の価値を得ていません。

EJB-永続性

EJB 2.0で使用されるエンティティBeanであるEJB 3.0は、永続化メカニズムにほぼ置き換えられています。 エンティティBeanは、テーブルとのマッピングを持つ単純なPOJOです。

以下は、永続化APIの主要なアクターです-

  • エンティティ-データストアレコードを表す永続オブジェクト。 シリアル化できるのは良いことです。
  • EntityManager -永続オブジェクト(エンティティ)の追加/削除/更新/検索などのデータ操作を行う永続インターフェイス。 また、 Query インターフェイスを使用してクエリを実行するのにも役立ちます。
  • {ブランク}
  • 持続性ユニット(persistence.xml)-持続性ユニットは、持続性メカニズムのプロパティを記述します。
  • {ブランク}
  • データソース( ds.xml)*-データソースは、接続URLなどのデータストア関連のプロパティを記述します。 ユーザー名、パスワードなど

EJBの永続化メカニズムを実証するには、次のタスクを実行する必要があります-

  • *ステップ1 *-データベースにテーブルを作成します。
  • *ステップ2 *-テーブルに対応するEntityクラスを作成します。
  • *ステップ3 *-データソースと永続性ユニットを作成します。
  • *ステップ4 *-EntityManagerインスタンスを持つステートレスEJBを作成します。
  • *ステップ5 *-ステートレスEJBを更新します。 エンティティマネージャーを介してレコードを追加し、データベースからレコードを取得するメソッドを追加します。
  • *ステップ6 *-コンソールベースのアプリケーションクライアントは、ステートレスEJBにアクセスしてデータベースにデータを保持します。

テーブルを作成

デフォルトのデータベース postgres にテーブル books を作成します。

CREATE TABLE books (
   id     integer PRIMARY KEY,
   name   varchar(50)
);

エンティティクラスを作成する

//mark it entity using Entity annotation
//map table name using Table annotation
@Entity
@Table(name="books")
public class Book implements Serializable{

   private int id;
   private String name;

   public Book() {
   }

  //mark id as primary key with autogenerated value
  //map database column id with id field
   @Id
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="id")
   public int getId() {
      return id;
   }
   ...
}

データソースと永続性ユニットの作成

データソース(jboss-ds.xml)

<?xml version = "1.0" encoding = "UTF-8"?>
<datasources>
   <local-tx-datasource>
      <jndi-name>PostgresDS</jndi-name>
      <connection-url>jdbc:postgresql://localhost:5432/postgres</connection-url>
      <driver-class>org.postgresql.driver</driver-class>
      <user-name>sa</user-name>
      <password>sa</password>
      <min-pool-size>5</min-pool-size>
      <max-pool-size>20</max-pool-size>
      <idle-timeout-minutes>5</idle-timeout-minutes>
   </local-tx-datasource>
</datasources>

永続性ユニット(persistence.xml)

<persistence version = "1.0" 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_1_0.xsd">

   <persistence-unit name = "EjbComponentPU" transaction-type = "JTA">
      <jta-data-source>java:/PostgresDS</jta-data-source>
      <exclude-unlisted-classes>false</exclude-unlisted-classes>
      <properties/>
   </persistence-unit>

   <persistence-unit name = "EjbComponentPU2" transaction-type = "JTA">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <jta-data-source>java:/PostgresDS</jta-data-source>
      <exclude-unlisted-classes>false</exclude-unlisted-classes>

      <properties>
         <property name="hibernate.hbm2ddl.auto" value="update"/>
      </properties>
   </persistence-unit>

</persistence>

EntityManagerインスタンスを持つステートレスEJBを作成する

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

  //pass persistence unit to entityManager.
   @PersistenceContext(unitName="EjbComponentPU")
   private EntityManager entityManager;

   public void addBook(Book book) {
      entityManager.persist(book);
   }

   public List<Book> getBooks() {
      return entityManager.createQuery("From Books").getResultList();
   }
   ...
}

EJBモジュールをビルドしたら、次のセクションで作成するステートレスBeanにアクセスするためのクライアントが必要です。

応用例

EJB永続性メカニズムをテストするためのテストEJBアプリケーションを作成しましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.entity as explained in the EJB - Create Application chapter. You can also use the project created in EJB - Create Application chapter as such for this chapter to understand EJB persistence concepts.
2 Create Book.java under package com.finddevguides.entity and modify it as shown below.
3 Create LibraryPersistentBean.java and LibraryPersistentBeanRemote as explained in the EJB - Create Application chapters and modify them as shown below.
4 Create jboss-ds.xml in EjbComponent > setup *folder and persistence.xml in EjbComponent > src > conf *folder. These folders can be seen in files tab in Netbeans. Modify these files as shown above.
5 Clean and Build the application to make sure business logic is working as per the requirements.
6 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
7 Now create the EJB client, a console based application in the same way as explained in the EJB - Create Application chapter under topic* Create Client to access EJB*. Modify it as shown below.

EJBComponent(EJBモジュール)

Book.java

package com.finddevguides.entity;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="books")
public class Book implements Serializable{

   private int id;
   private String name;

   public Book() {
   }

   @Id
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="id")
   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

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

LibraryPersistentBeanRemote.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Remote;

@Remote
public interface LibraryPersistentBeanRemote {

   void addBook(Book bookName);

   List<Book> getBooks();

}

LibraryPersistentBean.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

   public LibraryPersistentBean() {
   }

   @PersistenceContext(unitName="EjbComponentPU")
   private EntityManager entityManager;

   public void addBook(Book book) {
      entityManager.persist(book);
   }

   public List<Book> getBooks() {
      return entityManager.createQuery("From Book").getResultList();
   }
}
  • EjbComponentプロジェクトをJBOSSにデプロイするとすぐに、jbossログに注目してください。
  • JBossは、セッションBeanのJNDIエントリ- LibraryPersistentBean/remote を自動的に作成しました。
  • このルックアップ文字列を使用して、タイプ- com.finddevguides.stateless.LibraryPersistentBeanRemote のリモートビジネスオブジェクトを取得します。

JBoss Application Serverのログ出力

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBeanRemote,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.stateless.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...

EJBTester(EJBクライアント)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • これらのプロパティは、JavaネームサービスのInitialContextオブジェクトを初期化するために使用されます。
  • InitialContextオブジェクトは、ステートレスセッションBeanのルックアップに使用されます。

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.stateless.LibraryPersistentBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testEntityEjb();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testEntityEjb() {

      try {
         int choice = 1;

         LibraryPersistentBeanRemote libraryBean =
         LibraryPersistentBeanRemote)ctx.lookup("LibraryPersistentBean/remote");

         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);
            } else if (choice == 2) {
               break;
            }
         }

         List<Book> booksList = libraryBean.getBooks();

         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTesterは次のタスクを実行します。

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testStatefulEjb()メソッドでは、jndiルックアップが名前-"LibraryStatefulSessionBean/remote"で実行され、リモートビジネスオブジェクト(ステートフルejb)が取得されます。
  • 次に、ユーザーにライブラリストアのユーザーインターフェイスが表示され、選択を入力するように求められます。
  • ユーザーが1を入力すると、システムはブック名を要求し、ステートレスセッションBeanのaddBook()メソッドを使用してブックを保存します。 セッションBeanは、EntityManager呼び出しを介してデータベースに本を保持しています。
  • ユーザーが2を入力すると、システムはステートフルセッションBeanのgetBooks()メソッドを使用して本を取得し、終了します。
  • その後、別のjndiルックアップが「LibraryStatelessSessionBean/remote」という名前で実行され、リモートビジネスオブジェクト(ステートレスEJB)が再度取得され、書籍のリストが作成されます。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します-

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 1
1. learn java
BUILD SUCCESSFUL (total time: 15 seconds)

EJBにアクセスするためのクライアントの再実行

EJBにアクセスする前にJBossを再起動します。

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: Learn Spring
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 2
1. learn java
2. Learn Spring
BUILD SUCCESSFUL (total time: 15 seconds)

上記の出力は、書籍が永続ストレージに保存され、データベースから取得されることを示しています。

EJB-メッセージ駆動型Bean

メッセージ駆動型BeanはエンタープライズBeanの一種で、EJBコンテナがキューまたはトピックからメッセージを受信したときに呼び出されます。 メッセージ駆動型BeanはステートレスBeanであり、タスクを非同期的に実行するために使用されます。

メッセージ駆動型Beanの使用方法を示すために、EJB永続性の章を利用し、次のタスクを実行する必要があります-

  • *ステップ1 *-データベースにテーブルを作成します(_EJB-Persistence_の章を参照)。
  • *ステップ2 *-テーブルに対応するEntityクラスを作成します(_EJB-Persistence_の章を参照)。
  • *ステップ3 *-データソースと永続性ユニットを作成します(_EJB-Persistence_の章を参照)。
  • *ステップ4 *-EntityManagerインスタンスを持つステートレスEJBを作成します(_EJB-Persistence_の章を参照)。
  • *ステップ5 *-ステートレスejb.Addメソッドを更新してレコードを追加し、エンティティマネージャーを介してデータベースからレコードを取得します(_EJB-Persistence_の章を参照)。
  • ステップ6 *-JBoss *default アプリケーションディレクトリに BookQueue という名前のキューを作成します。
  • *ステップ7 *-コンソールベースのアプリケーションクライアントは、このキューにメッセージを送信します。
  • *ステップ8 *-ステートレスBeanを使用してクライアントデータを永続化するメッセージ駆動型Beanを作成します。
  • *ステップ9 *-jbossのEJBコンテナは上記のメッセージ駆動型Beanを呼び出し、クライアントが送信するメッセージを渡します。

キューを作成

*<JBoss Installation Folder>> server> default> deploy* フォルダーにjbossmq-destinations-service.xmlという名前のファイルが存在しない場合は作成します。

ここでは、BookQueueという名前のキューを作成しています-

jbossmq-destinations-service.xml

<mbean code="org.jboss.mq.server.jmx.Queue"
   name="jboss.mq.destination:service=Queue,name=BookQueue">
   <depends optional-attribute-name="DestinationManager">
      jboss.mq:service=DestinationManager
   </depends>
</mbean>

JBossを起動すると、jbossログに同様のエントリが表示されます。

...
10:37:06,167 INFO  [QueueService] Queue[/queue/BookQueue] started, fullSize=200000, pageSize=2000, downCacheSize=2000
...

メッセージ駆動型Beanを作成する

@MessageDriven(
   name = "BookMessageHandler",
   activationConfig = {
      @ActivationConfigProperty( propertyName = "destinationType",
                                 propertyValue = "javax.jms.Queue"),
      @ActivationConfigProperty( propertyName = "destination",
                                 propertyValue ="/queue/BookQueue")
   }
)
public class LibraryMessageBean implements MessageListener {

   @Resource
   private MessageDrivenContext mdctx;

   @EJB
   LibraryPersistentBeanRemote libraryBean;

   public LibraryMessageBean() {
   }

   public void onMessage(Message message) {
   }
}
  • LibraryMessageBeanには@MessageDrivenアノテーションが付けられ、メッセージ駆動型Beanとしてマークされます。
  • そのプロパティは、destinationType-Queueおよびdestination-/queue/BookQueueとして定義されています。
  • onMessageメソッドを公開するMessageListenerインターフェイスを実装します。
  • リソースとしてMessgeDrivenContextがあります。 *LibraryPersistentBeanRemoteステートレスBeanは、永続化のためにこのBeanに注入されます。

EjbComponentプロジェクトをビルドし、JBossにデプロイします。 EJBモジュールを構築してデプロイした後、jbossキューにメッセージを送信するクライアントが必要です。

応用例

テストEJBアプリケーションを作成して、メッセージ駆動型Beanをテストしましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.entity as explained in the EJB - Create Application chapter. You can also use the project created in EJB - Create Application chapter as such for this chapter to understand EJB persistence concepts.
2 Create Book.java under package com.finddevguides.entity as created in EJB-Persistence chapter.
3 Create LibraryPersistentBean.java and LibraryPersistentBeanRemote as created in EJB-Persistence chapter.
4 Create jboss-ds.xml in* EjbComponent > setup folder and persistence.xml in EjbComponent > src > conf *folder. These folders can be seen in files tab in Netbeans as created in EJB-Persistence chapter.
5 Create LibraryMessageBean.java under a package com.finddevguides.messagebean and modify it as shown below.
6 Create BookQueue queue in Jboss as described above.
7 Clean and Build the application to make sure business logic is working as per the requirements.
8 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
9 Now create the EJB client, a console based application in the same way as explained in the EJB - Create Application chapter under topic* Create Client to access EJB*. Modify it as shown below.

EJBComponent(EJBモジュール)

LibraryMessageBean.java

package com.finddevguides.messagebean;

import com.finddevguides.entity.Book;
import com.finddevguides.stateless.LibraryPersistentBeanRemote;
import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.EJB;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;

@MessageDriven(
   name = "BookMessageHandler",
   activationConfig = {
      @ActivationConfigProperty( propertyName = "destinationType",
                                 propertyValue = "javax.jms.Queue"),
      @ActivationConfigProperty( propertyName = "destination",
                                 propertyValue ="/queue/BookQueue")
   }
)
public class LibraryMessageBean implements MessageListener {

   @Resource
   private MessageDrivenContext mdctx;

   @EJB
   LibraryPersistentBeanRemote libraryBean;

   public LibraryMessageBean() {
   }

   public void onMessage(Message message) {
      ObjectMessage objectMessage = null;
      try {
         objectMessage = (ObjectMessage) message;
         Book book = (Book) objectMessage.getObject();
         libraryBean.addBook(book);

      } catch (JMSException ex) {
         mdctx.setRollbackOnly();
      }
   }
}

EJBTester(EJBクライアント)

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.entity.Book;
import com.finddevguides.stateless.LibraryPersistentBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testMessageBeanEjb();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testMessageBeanEjb() {

      try {
         int choice = 1;
         Queue queue = (Queue) ctx.lookup("/queue/BookQueue");
         QueueConnectionFactory factory =
         (QueueConnectionFactory) ctx.lookup("ConnectionFactory");
         QueueConnection connection =  factory.createQueueConnection();
         QueueSession session =
         connection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
         QueueSender sender = session.createSender(queue);

         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               ObjectMessage objectMessage =
                  session.createObjectMessage(book);
               sender.send(objectMessage);
            } else if (choice == 2) {
               break;
            }
         }

         LibraryPersistentBeanRemote libraryBean =
         (LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");

         List<Book> booksList = libraryBean.getBooks();

         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTesterは次のタスクを実行します-

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testStatefulEjb()メソッドでは、jndiルックアップは名前-"/queue/BookQueue"で実行され、Jbossで利用可能なキューの参照を取得します。 次に、キューセッションを使用して送信者が作成されます。
  • 次に、ユーザーにライブラリストアのユーザーインターフェイスが表示され、選択を入力するように求められます。
  • ユーザーが1を入力すると、システムは書籍名を要求し、送信者は書籍名をキューに送信します。 JBossコンテナがキューでこのメッセージを受信すると、メッセージ駆動型BeanのonMessageメソッドを呼び出します。 メッセージ駆動型Beanは、ステートフルセッションBeanのaddBook()メソッドを使用して本を保存します。 セッションBeanは、EntityManager呼び出しを介してデータベースに本を保持しています。
  • ユーザーが2を入力すると、「LibraryStatefulSessionBean/remote」という名前で別のjndiルックアップが行われ、リモートビジネスオブジェクト(ステートフルEJB)が再度取得され、書籍のリストが作成されます。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します-

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: Learn EJB
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 2
1. learn java
1. learn EJB
BUILD SUCCESSFUL (total time: 15 seconds)

上記の出力は、メッセージ駆動型Beanがメッセージを受信し、ブックを永続ストレージに保存していること、およびブックがデータベースから取得されたことを示しています。

EJB-注釈

注釈はJava 5.0で導入されました。 注釈を付ける目的は、ソースコード内のクラスまたはクラスのメタデータに追加情報を添付することです。 EJB 3.0では、アノテーションを使用してEJBクラスの構成メタデータを記述します。 この方法により、EJB 3.0では、構成XMLファイルで構成データを記述する必要がなくなります。

EJBコンテナは、コンパイラツールを使用して、これらの注釈を読み取ることにより、インターフェイスやデプロイメント記述子などの必要なアーティファクトを生成します。 以下は、一般的に使用される注釈のリストです。

Sr.no Name Description
1 javax.ejb.Stateless

Specifies that a given EJB class is a stateless session bean.

属性

  • name -セッションBeanの名前を指定するために使用されます。
  • mappedName -セッションBeanのJNDI名を指定するために使用されます。
  • description -セッションBeanの説明を提供するために使用されます。
2 javax.ejb.Stateful

Specifies that a given EJB class is a stateful session bean.

属性

  • name -セッションBeanの名前を指定するために使用されます。
  • mappedName -セッションBeanのJNDI名を指定するために使用されます。
  • description -セッションBeanの説明を提供するために使用されます。
3 javax.ejb.MessageDrivenBean

Specifies that a given EJB class is a message driven bean.

属性

  • name -メッセージ駆動型Beanの名前を指定するために使用されます。
  • messageListenerInterface -メッセージ駆動型Beanのメッセージリスナーインターフェイスを指定するために使用されます。
  • activationConfig -メッセージ駆動型Beanの動作環境でメッセージ駆動型Beanの構成の詳細を指定するために使用されます。
  • mappedName -セッションBeanのJNDI名を指定するために使用されます。
  • description -セッションBeanの説明を提供するために使用されます。
4 javax.ejb.EJB

Used to specify or inject a dependency as EJB instance into another EJB.

属性

  • name -環境内で参照されるBeanを見つけるために使用される名前を指定するために使用されます。
  • beanInterface -参照されるBeanのインターフェースタイプを指定するために使用されます。
  • beanName -参照されるBeanの名前を提供するために使用されます。
  • mappedName -参照されるBeanのJNDI名を指定するために使用されます。
  • description -参照されるBeanの説明を提供するために使用されます。
5 javax.ejb.Local

Used to specify Local interface(s) of a session bean. This local interface states the business methods of the session bean (which can be stateless or stateful).

このインターフェイスは、EJBと同じデプロイメント/アプリケーションで実行されているローカルクライアントにビジネスメソッドを公開するために使用されます。

属性

  • -インターフェースの配列としてローカルインターフェースのリストを指定するために使用されます。
6 javax.ejb.Remote

Used to specify Remote interface(s) of a session bean. This remote interface states the business methods of the session bean (which can be stateless or stateful).

このインターフェイスは、EJBとして異なるデプロイメント/アプリケーションで実行されているリモートクライアントにビジネスメソッドを公開するために使用されます。

属性

  • -リモートインターフェイスのリストをインターフェイスの配列として指定するために使用されます。
7 javax.ejb.Activation ConfigProperty

Used to specify properties required for a message driven bean. For example, end point, destination, message selector etc.

この注釈は、パラメーターとしてjavax.ejb.MessageDrivenBean注釈のactivationConfig属性に渡されます。

属性

  • propertyName -プロパティの名前。
  • propertyValue -プロパティの値。
8 javax.ejb.PostActivate

Used to specify callback method of EJB lifecycle. This method will be called when EJB container just activated/reactivated the bean instance.

このインターフェイスは、EJBと同じデプロイメント/アプリケーションで実行されているローカルクライアントにビジネスメソッドを公開するために使用されます。

EJB-コールバック

コールバックは、エンタープライズBeanのライフサイクルを傍受できるメカニズムです。 EJB 3.0仕様では、コールバックハンドラメソッドが作成されるコールバックが指定されています。 EJBコンテナはこれらのコールバックを呼び出します。 EJBクラス自体または別のクラスでコールバックメソッドを定義できます。 EJB 3.0は、コールバック用の多くの注釈を提供しています。

以下は、ステートレスBeanのコールバックアノテーションのリストです-

Annotation Description
@PostConstruct Invoked when a bean is created for the first time.
@PreDestroy Invoked when a bean is removed from the bean pool or is destroyed.

以下は、ステートフルBeanのコールバックアノテーションのリストです-

Annotation Description
@PostConstruct Invoked when a bean is created for the first time.
@PreDestroy Invoked when a bean is removed from the bean pool or is destroyed.
@PostActivate Invoked when a bean is loaded to be used.
@PrePassivate Invoked when a bean is put back to bean pool.

以下は、メッセージ駆動型Beanのコールバックアノテーションのリストです-

Annotation Description
@PostConstruct Invoked when a bean is created for the first time.
@PreDestroy Invoked when a bean is removed from the bean pool or is destroyed.

以下は、エンティティBeanのコールバックアノテーションのリストです-

Annotation Description
@PrePersist Invoked when an entity is created in database.
@PostPersist Invoked after an entity is created in database.
@PreRemove Invoked when an entity is deleted from the database.
@PostRemove Invoked after an entity is deleted from the database.
@PreUpdate Invoked before an entity is to be updated in the database.
@PostLoad Invoked when a record is fetched from database and loaded into the entity.

応用例

テストEJBアプリケーションを作成して、EJBのさまざまなコールバックをテストしましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.stateless as explained in the EJB - Create Application chapter. You can also use the project created in EJB - Persistence chapter as such for this chapter to add various callbacks to EJB.
2 Create LibrarySessionBean.java and LibrarySessionBeanRemote as explained in the EJB - Create Application chapter. Keep rest of the files unchanged.
3 Use Beans created in the EJB - Persistence chapter. Add callback methods as shown below. Keep rest of the files unchanged.
4 Create a java class BookCallbackListener under package com.finddevguides.callback. This class will demonstrates the separation of callback methods.
5 Clean and Build the application to make sure business logic is working as per the requirements.
6 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
7 Now create the EJB client, a console based application in the same way as explained in the EJB - Create Application chapter under topic Create Client to access EJB.

EJBComponent(EJBモジュール)

BookCallbackListener.java

package com.finddevguides.callback;

import javax.persistence.PrePersist;
import javax.persistence.PostLoad;
import javax.persistence.PostPersist;
import javax.persistence.PostRemove;
import javax.persistence.PostUpdate;
import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;

import com.finddevguides.entity.Book;

public class BookCallbackListener {

   @PrePersist
   public void prePersist(Book book) {
      System.out.println("BookCallbackListener.prePersist:"
         + "Book to be created with book id: "+book.getId());
   }

   @PostPersist
   public void postPersist(Object book) {
      System.out.println("BookCallbackListener.postPersist::"
         + "Book created with book id: "+((Book)book).getId());
   }

   @PreRemove
   public void preRemove(Book book) {
      System.out.println("BookCallbackListener.preRemove:"
         + " About to delete Book: " + book.getId());
   }

   @PostRemove
   public void postRemove(Book book) {
      System.out.println("BookCallbackListener.postRemove::"
         + " Deleted Book: " + book.getId());
   }

   @PreUpdate
   public void preUpdate(Book book) {
      System.out.println("BookCallbackListener.preUpdate::"
         + " About to update Book: " + book.getId());
   }

   @PostUpdate
   public void postUpdate(Book book) {
      System.out.println("BookCallbackListener.postUpdate::"
         + " Updated Book: " + book.getId());
   }

   @PostLoad
   public void postLoad(Book book) {
      System.out.println("BookCallbackListener.postLoad::"
         + " Loaded Book: " + book.getId());
   }
}

Book.java

package com.finddevguides.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="books")
public class Book implements Serializable{

   private int id;
   private String name;

   public Book() {
   }

   @Id
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="id")
   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

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

LibraryStatefulSessionBean.java

package com.finddevguides.stateful;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.ejb.Stateful;

@Stateful
public class LibraryStatefulSessionBean
   implements LibraryStatefulSessionBeanRemote {
   List<String> bookShelf;

   public LibraryStatefulSessionBean() {
      bookShelf = new ArrayList<String>();
   }

   public void addBook(String bookName) {
      bookShelf.add(bookName);
   }

   public List<String> getBooks() {
      return bookShelf;
   }

   @PostConstruct
   public void postConstruct() {
      System.out.println("LibraryStatefulSessionBean.postConstruct::"
         + " bean created.");
   }

   @PreDestroy
   public void preDestroy() {
      System.out.println("LibraryStatefulSessionBean.preDestroy:"
         + " bean removed.");
   }

   @PostActivate
   public void postActivate() {
      System.out.println("LibraryStatefulSessionBean.postActivate:"
         + " bean activated.");
   }

   @PrePassivate
   public void prePassivate() {
      System.out.println("LibraryStatefulSessionBean.prePassivate:"
         + " bean passivated.");
   }
}

LibraryStatefulSessionBeanRemote.java

package com.finddevguides.stateful;

import java.util.List;
import javax.ejb.Remote;

@Remote
public interface LibraryStatefulSessionBeanRemote {
   void addBook(String bookName);
   List getBooks();
}

LibraryPersistentBean.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class LibraryPersistentBean
   implements LibraryPersistentBeanRemote {

   public LibraryPersistentBean() {}

   @PersistenceContext(unitName="EntityEjbPU")
   private EntityManager entityManager;

   public void addBook(Book book) {
      entityManager.persist(book);
   }

   public List<Book> getBooks() {
      return entityManager.createQuery("From Book")
         .getResultList();
   }

   @PostConstruct
   public void postConstruct() {
      System.out.println("postConstruct:: LibraryPersistentBean session bean"
         + " created with entity Manager object: ");
   }

   @PreDestroy
   public void preDestroy() {
      System.out.println("preDestroy: LibraryPersistentBean session"
      + " bean is removed ");
   }
}

LibraryPersistentBeanRemote.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Remote;

@Remote
public interface LibraryPersistentBeanRemote {

   void addBook(Book bookName);

   List<Book> getBooks();

}
  • EjbComponentプロジェクトをJBOSSにデプロイするとすぐに、jbossログに注目してください。
  • JBossは、セッションBeanのJNDIエントリ- LibraryPersistentBean/remote を自動的に作成しました。
  • この検索文字列を使用して、タイプのリモートビジネスオブジェクトを取得します- com.finddevguides.stateless.LibraryPersistentBeanRemote

JBoss Application Serverのログ出力

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.stateless.LibrarySessionBeanRemote ejbName: LibraryPersistentBean
...

EJBTester(EJBクライアント)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • これらのプロパティは、JavaネームサービスのInitialContextオブジェクトを初期化するために使用されます。
  • InitialContextオブジェクトは、ステートレスセッションBeanのルックアップに使用されます。

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.stateful.LibrarySessionBeanRemote;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import java.util.List;
import java.util.Properties;

import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testEntityEjb();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testEntityEjb() {
      try {
      int choice = 1;

      LibraryPersistentBeanRemote libraryBean =
      (LibraryPersistentBeanRemote)
      ctx.lookup("LibraryPersistentBean/remote");

      while (choice != 2) {
         String bookName;
         showGUI();
         String strChoice = brConsoleReader.readLine();
         choice = Integer.parseInt(strChoice);
         if (choice == 1) {
            System.out.print("Enter book name: ");
            bookName = brConsoleReader.readLine();
            Book book = new Book();
            book.setName(bookName);
            libraryBean.addBook(book);
         } else if (choice == 2) {
            break;
         }
      }

      List<Book> booksList = libraryBean.getBooks();

      System.out.println("Book(s) entered so far: " + booksList.size());
      int i = 0;
      for (Book book:booksList) {
         System.out.println((i+1)+". " + book.getName());
         i++;
      }

      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTesterは次のタスクを実行します-

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testStatelessEjb()メソッドでは、jndiルックアップが「LibrarySessionBean/remote」という名前で実行され、リモートビジネスオブジェクト(ステートレスEJB)が取得されます。
  • 次に、ユーザーにライブラリストアのユーザーインターフェイスが表示され、ユーザーは選択肢を入力するよう求められます。
  • ユーザーが1を入力すると、システムはブック名を要求し、ステートレスセッションBeanのaddBook()メソッドを使用してブックを保存します。 セッションBeanはデータベースに本を保存しています。
  • ユーザーが2を入力すると、システムはステートレスセッションBeanのgetBooks()メソッドを使用して本を取得し、終了します。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 1
1. Learn Java
BUILD SUCCESSFUL (total time: 13 seconds)

JBoss Application Serverのログ出力

JBossログで次のコールバックエントリを見つけることができます

14:08:34,293 INFO  [STDOUT] postConstruct:: LibraryPersistentBean session bean created with entity Manager object
...
16:39:09,484 INFO  [STDOUT] BookCallbackListener.prePersist:: Book to be created with book id: 0
16:39:09,531 INFO  [STDOUT] BookCallbackListener.postPersist:: Book created with book id: 1
16:39:09,900 INFO  [STDOUT] BookCallbackListener.postLoad:: Loaded Book: 1
...

EJB-タイマーサービス

タイマーサービスは、スケジュールされたアプリケーションを構築できるメカニズムです。 たとえば、毎月1日の給与明細生成。 EJB 3.0仕様では、@ Timeoutアノテーションが指定されています。これは、ステートレスBeanまたはメッセージ駆動型BeanでEJBサービスをプログラミングするのに役立ちます。 EJBコンテナは、@ Timeoutで注釈が付けられたメソッドを呼び出します。

EJBタイマーサービスは、EJBコンテナーによって提供されるサービスです。これは、タイマーの作成と、タイマーの期限が切れたときのコールバックのスケジュールに役立ちます。

タイマーを作成する手順

@Resourceアノテーションを使用してBeanにSessionContextを注入します-

@Stateless
public class TimerSessionBean {

   @Resource
   private SessionContext context;
   ...
}

SessionContextオブジェクトを使用して、TimerServiceを取得し、タイマーを作成します。 ミリ秒単位の時間とメッセージを渡します。

public void createTimer(long duration) {
   context.getTimerService().createTimer(duration, "Hello World!");
}

タイマーを使用する手順

メソッドに@Timeoutアノテーションを使用します。 戻り値の型はvoidで、Timer型のパラメーターを渡す必要があります。 最初の実行後にタイマーをキャンセルします。そうしないと、修正間隔の後も実行を続けます。

@Timeout
public void timeOutHandler(Timer timer) {
   System.out.println("timeoutHandler : " + timer.getInfo());
   timer.cancel();
}

応用例

EJBでタイマーサービスをテストするためのテストEJBアプリケーションを作成しましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.timer as explained in the EJB - Create Application chapter.
2 Create TimerSessionBean.java and TimerSessionBeanRemote as explained in the EJB - Create Application chapter. Keep rest of the files unchanged.
3 Clean and Build the application to make sure business logic is working as per the requirements.
4 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
5 Now create the EJB client, a console based application in the same way as explained in the EJB - Create Application chapter under topic Create Client to access EJB.

EJBComponent(EJBモジュール)

TimerSessionBean.java

package com.finddevguides.timer;

import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Timer;
import javax.ejb.Stateless;
import javax.ejb.Timeout;

@Stateless
public class TimerSessionBean implements TimerSessionBeanRemote {

   @Resource
   private SessionContext context;

   public void createTimer(long duration) {
      context.getTimerService().createTimer(duration, "Hello World!");
   }

   @Timeout
   public void timeOutHandler(Timer timer) {
      System.out.println("timeoutHandler : " + timer.getInfo());
      timer.cancel();
   }
}

TimerSessionBeanRemote.java

package com.finddevguides.timer;

import javax.ejb.Remote;

@Remote
public interface TimerSessionBeanRemote {
   public void createTimer(long milliseconds);
}
  • EjbComponentプロジェクトをJBOSSにデプロイするとすぐに、jbossログに注目してください。
  • JBossは、セッションBeanのJNDIエントリを自動的に作成しました- TimerSessionBean/remote
  • このルックアップ文字列を使用して、タイプのリモートビジネスオブジェクトを取得します- com.finddevguides.timer.TimerSessionBeanRemote

JBoss Application Serverのログ出力

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   TimerSessionBean/remote - EJB3.x Default Remote Business Interface
   TimerSessionBean/remote-com.finddevguides.timer.TimerSessionBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=TimerSessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.timer.TimerSessionBeanRemote ejbName: TimerSessionBean
...

EJBTester(EJBクライアント)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • これらのプロパティは、JavaネームサービスのInitialContextオブジェクトを初期化するために使用されます。
  • InitialContextオブジェクトは、ステートレスセッションBeanのルックアップに使用されます。

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.stateful.TimerSessionBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testTimerService();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testTimerService() {
      try {
         TimerSessionBeanRemote timerServiceBean = (TimerSessionBeanRemote)ctx.lookup("TimerSessionBean/remote");

         System.out.println("["+(new Date()).toString()+ "]" + "timer created.");
         timerServiceBean.createTimer(2000);

      } catch (NamingException ex) {
         ex.printStackTrace();
      }
   }
}

EJBTesterは次のタスクを実行しています。

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testTimerService()メソッドでは、jndiルックアップが名前-"TimerSessionBean/remote"で実行され、リモートビジネスオブジェクト(タイマーステートレスEJB)が取得されます。
  • 次に、スケジュール時間として2000ミリ秒を渡してcreateTimerが呼び出されます。
  • EJBコンテナは2秒後にtimeoutHandlerメソッドを呼び出します。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
[Wed Jun 19 11:35:47 IST 2013]timer created.
BUILD SUCCESSFUL (total time: 0 seconds)

JBoss Application Serverのログ出力

JBossログで次のコールバックエントリを見つけることができます

...
11:35:49,555 INFO  [STDOUT] timeoutHandler : Hello World!
...

EJB-依存性注入

EJB 3.0仕様は、フィールドまたはセッターメソッドに適用して依存関係を注入できる注釈を提供します。 EJBコンテナは、グローバルJNDIレジストリを使用して依存関係を見つけます。 EJB 3.0では、依存性注入のために次の注釈が使用されます。

  • @ EJB -他のEJB参照を注入するために使用されます。
  • @ Resource -sessionContext、timerServiceなどのデータソースまたはシングルトンサービスの注入に使用

@EJBを使用する手順

@EJBは、次の方法でフィールドまたはメソッドで使用することができます-

public class LibraryMessageBean implements MessageListener {
  //dependency injection on field.
   @EJB
   LibraryPersistentBeanRemote libraryBean;
   ...
}
public class LibraryMessageBean implements MessageListener {

   LibraryPersistentBeanRemote libraryBean;

  //dependency injection on method.
   @EJB(beanName="com.finddevguides.stateless.LibraryPersistentBean")
   public void setLibraryPersistentBean(
   LibraryPersistentBeanRemote libraryBean)
   {
      this.libraryBean = libraryBean;
   }
   ...
}

@Resourceを使用する手順

@Resourceは通常、EJBコンテナが提供するシングルトンを注入するために使用されます。

public class LibraryMessageBean implements MessageListener {
   @Resource
   private MessageDrivenContext mdctx;
   ...
}

応用例

EJBでDependency InjectionサービスをテストするテストEJBアプリケーションを作成しましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.timer as explained in the EJB - Create Application chapter.
2 Use Beans created in the EJB - Message Driven Bean chapter. Keep rest of the files unchanged.
3 Clean and Build the application to make sure business logic is working as per the requirements.
4 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
5 Now create the EJB client, a console based application in the same way as explained in the EJB - Create Application chapter under topic Create Client to access EJB.

EJBComponent(EJBモジュール)

LibraryMessageBean.java

package com.tuturialspoint.messagebean;

import com.finddevguides.entity.Book;
import com.finddevguides.stateless.LibraryPersistentBeanRemote;
import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.EJB;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;

@MessageDriven(
   name = "BookMessageHandler",
   activationConfig = {
      @ActivationConfigProperty( propertyName = "destinationType",
                                 propertyValue = "javax.jms.Queue"),
      @ActivationConfigProperty( propertyName = "destination",
                                 propertyValue ="/queue/BookQueue")
   }
)
public class LibraryMessageBean implements MessageListener {

   @Resource
   private MessageDrivenContext mdctx;

   @EJB
   LibraryPersistentBeanRemote libraryBean;

   public LibraryMessageBean() {
   }

   public void onMessage(Message message) {
      ObjectMessage objectMessage = null;
      try {
         objectMessage = (ObjectMessage) message;
         Book book = (Book) objectMessage.getObject();
         libraryBean.addBook(book);

      }catch (JMSException ex) {
         mdctx.setRollbackOnly();
      }
   }
}

EJBTester(EJBクライアント)

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.entity.Book;
import com.finddevguides.stateless.LibraryPersistentBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testMessageBeanEjb();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testMessageBeanEjb() {

      try {
         int choice = 1;
         Queue queue = (Queue) ctx.lookup("/queue/BookQueue");
         QueueConnectionFactory factory =
         (QueueConnectionFactory) ctx.lookup("ConnectionFactory");
         QueueConnection connection =  factory.createQueueConnection();
         QueueSession session = connection.createQueueSession(
         false, QueueSession.AUTO_ACKNOWLEDGE);
         QueueSender sender = session.createSender(queue);

         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               ObjectMessage objectMessage =
               session.createObjectMessage(book);
               sender.send(objectMessage);
            } else if (choice == 2) {
               break;
            }
         }

         LibraryPersistentBeanRemote libraryBean =
         (LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");

         List<Book> booksList = libraryBean.getBooks();

         System.out.println("Book(s) entered so far: "
         + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTesterは次のタスクを実行します-

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testStatefulEjb()メソッドでは、jndiルックアップは名前-"/queue/BookQueue"で実行され、Jbossで利用可能なキューの参照を取得します。 次に、キューセッションを使用して送信者が作成されます。
  • 次に、ユーザーにライブラリストアのユーザーインターフェイスが表示され、選択肢を入力するように求められます。
  • ユーザーが1を入力すると、システムは書籍名を要求し、送信者は書籍名をキューに送信します。 JBossコンテナがキューでこのメッセージを受信すると、メッセージ駆動型BeanのonMessageメソッドを呼び出します。 メッセージ駆動型Beanは、ステートフルセッションBeanのaddBook()メソッドを使用して本を保存します。 セッションBeanは、EntityManager呼び出しを介してデータベースに本を保持しています。
  • ユーザーが2を入力すると、「LibraryStatefulSessionBean/remote」という名前で別のjndiルックアップが行われ、リモートビジネスオブジェクト(ステートフルEJB)が再度取得され、書籍のリストが作成されます。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: Learn EJB
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 2
1. learn java
1. learn EJB
BUILD SUCCESSFUL (total time: 15 seconds)

上記の出力は、メッセージ駆動型Beanがメッセージを受信して​​永続ストレージに本を保存し、本がデータベースから取得されることを示しています。

メッセージ駆動型Beanは、@ EJBアノテーションを使用して注入されたLibraryPersistentBeanを使用しており、例外の場合、MessageDrivenContextのオブジェクトがトランザクションのロールバックに使用されます。

EJB-インターセプター

EJB 3.0は、@ AroundInvokeアノテーションが付けられたメソッドを使用してビジネスメソッド呼び出しをインターセプトする仕様を提供します。 インターセプターメソッドは、ビジネスメソッドがインターセプトする前にejbContainerによって呼び出されます。 以下は、インターセプターメソッドのサンプルシグネチャです。

@AroundInvoke
public Object methodInterceptor(InvocationContext ctx) throws Exception {
   System.out.println("*** Intercepting call to LibraryBean method: "
   + ctx.getMethod().getName());
   return ctx.proceed();
}

インターセプターメソッドは、3つのレベルで適用またはバインドできます。

  • デフォルト-デプロイメント内のすべてのBeanに対してデフォルトのインターセプターが呼び出されます。デフォルトのインターセプターは、xml(ejb-jar.xml)を介してのみ適用できます。
  • Class -Beanのすべてのメソッドに対してクラスレベルのインターセプターが呼び出されます。 クラスレベルのインターセプターは、xml(ejb-jar.xml)を介した注釈によって両方に適用できます。
  • メソッド-Beanの特定のメソッドに対してメソッドレベルのインターセプターが呼び出されます。 メソッドレベルのインターセプターは、xml(ejb-jar.xml)を介したアノテーションによって適用できます。

ここでは、クラスレベルのインターセプターについて説明します。

インターセプタークラス

package com.finddevguides.interceptor;

import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

public class BusinessInterceptor {
   @AroundInvoke
   public Object methodInterceptor(InvocationContext ctx) throws Exception {
      System.out.println("** *Intercepting call to LibraryBean method: "
      + ctx.getMethod().getName());
      return ctx.proceed();
   }
}

リモートインターフェース

import javax.ejb.Remote;

@Remote
public interface LibraryBeanRemote {
  //add business method declarations
}

インターセプトされたステートレスEJB

@Interceptors ({BusinessInterceptor.class})
@Stateless
public class LibraryBean implements LibraryBeanRemote {
  //implement business method
}

応用例

テストEJBアプリケーションを作成して、インターセプトされたステートレスEJBをテストしましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.interceptor as explained in the EJB - Create Application chapter. You can also use the project created in EJB - Create Application chapter as such for this chapter to understand intercepted EJB concepts.
2 Create LibraryBean.java and LibraryBeanRemote under package com.finddevguides.interceptor as explained in the EJB - Create Application chapter. Keep rest of the files unchanged.
3 Clean and Build the application to make sure business logic is working as per the requirements.
4 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
5 Now create the ejb client, a console based application in the same way as explained in the EJB - Create Application chapter under topic* Create Client to access EJB*.

EJBComponent(EJBモジュール)

LibraryBeanRemote.java

package com.finddevguides.interceptor;

import java.util.List;
import javax.ejb.Remote;

@Remote
public interface LibraryBeanRemote {
   void addBook(String bookName);
   List getBooks();
}

LibraryBean.java

package com.finddevguides.interceptor;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.interceptor.Interceptors;

@Interceptors ({BusinessInterceptor.class})
@Stateless
public class LibraryBean implements LibraryBeanRemote {

   List<String> bookShelf;

   public LibraryBean() {
      bookShelf = new ArrayList<String>();
   }

   public void addBook(String bookName) {
      bookShelf.add(bookName);
   }

   public List<String> getBooks() {
      return bookShelf;
   }
}
  • EjbComponentプロジェクトをJBOSSにデプロイするとすぐに、jbossログに注目してください。
  • JBossは、セッションBeanのJNDIエントリを自動的に作成しました- LibraryBean/remote
  • このルックアップ文字列を使用して、タイプのリモートビジネスオブジェクトを取得します- com.finddevguides.interceptor.LibraryBeanRemote

JBoss Application Serverのログ出力

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryBean/remote - EJB3.x Default Remote Business Interface
   LibraryBean/remote-com.finddevguides.interceptor.LibraryBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.interceptor.LibraryBeanRemote ejbName: LibraryBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

   LibraryBean/remote - EJB3.x Default Remote Business Interface
   LibraryBean/remote-com.finddevguides.interceptor.LibraryBeanRemote - EJB3.x Remote Business Interface
...

EJBTester(EJBクライアント)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • これらのプロパティは、JavaネームサービスのInitialContextオブジェクトを初期化するために使用されます。
  • InitialContextオブジェクトは、ステートレスセッションBeanのルックアップに使用されます。

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.stateful.LibraryBeanRemote;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import java.util.List;
import java.util.Properties;

import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testInterceptedEjb();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testInterceptedEjb() {

      try {
         int choice = 1;

         LibraryBeanRemote libraryBean =
         LibraryBeanRemote)ctx.lookup("LibraryBean/remote");

         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);
            } else if (choice == 2) {
               break;
            }
         }

         List<Book> booksList = libraryBean.getBooks();

         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTesterは次のタスクを実行します-

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testInterceptedEjb()メソッドでは、jndiルックアップが「LibraryBean/remote」という名前で実行され、リモートビジネスオブジェクト(ステートレスEJB)が取得されます。
  • 次に、ユーザーにライブラリストアのユーザーインターフェイスが表示され、ユーザーは選択肢を入力するよう求められます。
  • ユーザーが1を入力すると、システムはブック名を要求し、ステートレスセッションBeanのaddBook()メソッドを使用してブックを保存します。 セッションBeanは、ブックをそのインスタンス変数に保存しています。
  • ユーザーが2を入力すると、システムはステートレスセッションBeanのgetBooks()メソッドを使用して本を取得し、終了します。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 1
1. Learn Java
BUILD SUCCESSFUL (total time: 13 seconds)

JBoss Application Serverのログ出力

JBoss Application Serverのログ出力で次の出力を確認します。

....
09:55:40,741情報[STDOUT] ** *LibraryBeanメソッドの呼び出しをインターセプト:addBook 09:55:43,661 INFO [STDOUT]* ** LibraryBeanメソッドの呼び出しをインターセプト:getBooks

EJB-埋め込み可能なオブジェクト

EJB 3.0は、JAVA POJO(Plain Old Java Object)をエンティティBeanに埋め込むオプションを提供し、埋め込みPOJOクラスのメソッドを使用して列名をマッピングできます。 埋め込まれるJava POJOには、@ Embeddableとして注釈を付ける必要があります。

@Embeddable
public class Publisher implements Serializable{
   private String name;
   private String address;
   ...
}

上記のクラスは、@ Embeddedアノテーションを使用して埋め込むことができます。

@Entity
public class Book implements Serializable{
   private int id;
   private String name;
   private Publisher publisher;
   ...
   @Embedded
   @AttributeOverrides({
      @AttributeOverride(name = "name",
                      column = @Column(name = "PUBLISHER")),
      @AttributeOverride(name = "address",
                      column = @Column(name = "PUBLISHER_ADDRESS"))
   })
   public Publisher getPublisher() {
      return publisher;
   }
   ...
}

応用例

テストEJBアプリケーションを作成して、EJB 3.0の埋め込みオブジェクトをテストしましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.entity as explained in the EJB - Create Application chapter. Please use the project created in EJB - Persistence chapter as such for this chapter to understand embedded objects in EJB concepts.
2 Create Publisher.java under package com.finddevguides.entity as explained in the EJB - Create Application chapter. Keep rest of the files unchanged.
3 Create Book.java under package com.finddevguides.entity. Use EJB - Persistence chapter as reference. Keep rest of the files unchanged.
4 Clean and Build the application to make sure business logic is working as per the requirements.
5 Finally, deploy the application in the form of a jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
6 Now create the EJB client, a console based application in the same way as explained in the EJB - Create Application chapter under topic Create Client to access EJB.

ブックテーブルの作成/変更

CREATE TABLE book (
   id     integer PRIMARY KEY,
   name   varchar(50)
);
Alter table book add publisher varchar(100);
Alter table book add publisher_address varchar(200);

EJBComponent(EJBモジュール)

Publisher.java

package com.finddevguides.entity;

import java.io.Serializable;
import javax.persistence.Embeddable;

@Embeddable
public class Publisher implements Serializable{

   private String name;
   private String address;

   public Publisher() {}

   public Publisher(String name, String address) {
      this.name = name;
      this.address = address;
   }

   public String getName() {
      return name;
   }

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

   public String getAddress() {
      return address;
   }

   public void setAddress(String address) {
      this.address = address;
   }

   public String toString() {
      return name + "," + address;
   }
}

Book.java

package com.finddevguides.entity;

import com.finddevguides.callback.BookCallbackListener;
import java.io.Serializable;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="book")
public class Book implements Serializable{

   private int id;
   private String name;
   private Publisher publisher;

   public Book() {
   }

   @Id
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="id")
   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

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


   @Embedded
   @AttributeOverrides({
      @AttributeOverride(name = "name",
         column = @Column(name = "PUBLISHER")),
      @AttributeOverride(name = "address",
         column = @Column(name = "PUBLISHER_ADDRESS"))
   })
   public Publisher getPublisher() {
      return publisher;
   }

   public void setPublisher(Publisher publisher) {
      this.publisher = publisher;
   }
}

LibraryPersistentBeanRemote.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Remote;

@Remote
public interface LibraryPersistentBeanRemote {

   void addBook(Book bookName);

   List<Book> getBooks();

}

LibraryPersistentBean.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Stateless;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

   public LibraryPersistentBean() {
   }

   @PersistenceContext(unitName="EjbComponentPU")
   private EntityManager entityManager;

   public void addBook(Book book) {
      entityManager.persist(book);
   }

   public List<Book> getBooks() {
      return entityManager.createQuery("From Book").getResultList();
   }
}
  • EjbComponentプロジェクトをJBOSSにデプロイするとすぐに、jbossログに注目してください。
  • JBossは、セッションBeanのJNDIエントリを自動的に作成しました- LibraryPersistentBean/remote
  • このルックアップ文字列を使用して、タイプのリモートビジネスオブジェクトを取得します- com.finddevguides.interceptor.LibraryPersistentBeanRemote

JBoss Application Serverのログ出力

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.interceptor.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.interceptor.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.interceptor.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...

EJBTester(EJBクライアント)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • これらのプロパティは、JavaネームサービスのInitialContextオブジェクトを初期化するために使用されます。
  • InitialContextオブジェクトは、ステートレスセッションBeanのルックアップに使用されます。

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.stateful.LibraryBeanRemote;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import java.util.List;
import java.util.Properties;

import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testEmbeddedObjects();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testEmbeddedObjects() {

      try {
         int choice = 1;

         LibraryPersistentBeanRemote libraryBean =
        (LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");

         while (choice != 2) {
            String bookName;
            String publisherName;
            String publisherAddress;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               System.out.print("Enter publisher name: ");
               publisherName = brConsoleReader.readLine();
               System.out.print("Enter publisher address: ");
               publisherAddress = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               book.setPublisher
              (new Publisher(publisherName,publisherAddress));

               libraryBean.addBook(book);
            } else if (choice == 2) {
               break;
            }
         }

         List<Book> booksList = libraryBean.getBooks();

         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            System.out.println("Publication: "+book.getPublisher());
            i++;
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTesterは次のタスクを実行します-

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testInterceptedEjb()メソッドでは、jndiルックアップが「LibraryPersistenceBean/remote」という名前で実行され、リモートビジネスオブジェクト(ステートレスEJB)が取得されます。
  • 次に、ユーザーにライブラリストアのユーザーインターフェイスが表示され、ユーザーは 選択。
  • ユーザーが1を入力すると、システムはブック名を要求し、ステートレスセッションBeanのaddBook()メソッドを使用してブックを保存します。 セッションBeanはデータベースに本を保存しています。
  • ユーザーが2を入力すると、システムはステートレスセッションBeanのgetBooks()メソッドを使用して本を取得し、終了します。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: learn html5
Enter publisher name: SAMS
Enter publisher address: DELHI
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 1
1. learn html5
Publication: SAMS,DELHI
BUILD SUCCESSFUL (total time: 21 seconds)

EJB-塊/塊

EJB 3.0は、@ Lobアノテーションを使用してBlobおよびClobタイプをサポートします。 次のJavaタイプは、@ Lobアノテーションを使用してマップできます。

  • java.sql.Blob
  • java.sql.Clob
  • バイト[]
  • ひも *シリアライズ可能なオブジェクト
@Entity
@Table(name="books")
@EntityListeners(BookCallbackListener.class)
public class Book implements Serializable{
   ...
   private byte[] image;

   @Lob @Basic(fetch= FetchType.EAGER)
   public byte[] getImage() {
      return image;
   }
   ...
}

応用例

EJB 3.0でblob/clobサポートをテストするテストEJBアプリケーションを作成しましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.entity as explained in the EJB - Create Application chapter. Please use the project created in EJB - Persistence chapter as such for this chapter to understand clob/blob objects in ejb concepts.
2 Create Book.java under package com.finddevguides.entity. Use EJB - Persistence chapter as reference. Keep rest of the files unchanged.
3 Clean and Build the application to make sure business logic is working as per the requirements.
4 Finally, deploy the application in the form of a jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
5 Now create the EJB client, a console based application in the same way as explained in the EJB - Create Application chapter under topic* Create Client to access EJB*.

ブックテーブルの作成/変更

CREATE TABLE book (
   id     integer PRIMARY KEY,
   name   varchar(50)
);
Alter table book add image bytea;
Alter table book add xml text;

EJBComponent(EJBモジュール)

Book.java

package com.finddevguides.entity;

import com.finddevguides.callback.BookCallbackListener;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;

@Entity
@Table(name="book")
public class Book implements Serializable{

   private int id;
   private String name;
   private byte[] image;
   private String xml;

   public Book() {
   }

   @Id
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="id")
   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

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

   @Lob @Basic(fetch= FetchType.EAGER)
   public byte[] getImage() {
      return image;
   }

   public void setImage(byte[] image) {
      this.image = image;
   }

   @Lob @Basic(fetch= FetchType.EAGER)
   public String getXml() {
      return xml;
   }

   public void setXml(String xml) {
      this.xml = xml;
   }
}

LibraryPersistentBeanRemote.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Remote;

@Remote
public interface LibraryPersistentBeanRemote {

   void addBook(Book bookName);

   List<Book> getBooks();

}

LibraryPersistentBean.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

   public LibraryPersistentBean() {
   }

   @PersistenceContext(unitName="EjbComponentPU")
   private EntityManager entityManager;

   public void addBook(Book book) {
      entityManager.persist(book);
   }

   public List<Book> getBooks() {
      return entityManager.createQuery("From Book").getResultList();
   }
}
  • EjbComponentプロジェクトをJBOSSにデプロイするとすぐに、jbossログに注目してください。
  • JBossは、セッションBeanのJNDIエントリ- LibraryPersistentBean/remote を自動的に作成しました。
  • この検索文字列を使用して、タイプのリモートビジネスオブジェクトを取得します- com.finddevguides.interceptor.LibraryPersistentBeanRemote

JBoss Application Serverのログ出力

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.interceptor.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.interceptor.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.interceptor.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...

EJBTester(EJBクライアント)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • これらのプロパティは、JavaネームサービスのInitialContextオブジェクトを初期化するために使用されます。
  • InitialContextオブジェクトは、ステートレスセッションBeanのルックアップに使用されます。

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.stateful.LibraryBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testBlobClob();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testBlobClob() {

      try {
         int choice = 1;

         LibraryPersistentBeanRemote libraryBean =
        (LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");

         while (choice != 2) {
            String bookName;
            String publisherName;
            String publisherAddress;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               String xml = "<book><name>"+bookName+"</name></book>";
               Book book = new Book();
               book.setName(bookName);
               byte[] imageBytes = {0x32, 0x32,0x32, 0x32,0x32,
               0x32,0x32, 0x32,
               0x32, 0x32,0x32, 0x32,0x32, 0x32,0x32, 0x32,
               0x32, 0x32,0x32, 0x32,0x32, 0x32,0x32, 0x32
               };
               book.setImage(imageBytes);
               book.setXml(xml);

               libraryBean.addBook(book);
            } else if (choice == 2) {
               break;
            }
         }

         List<Book> booksList = libraryBean.getBooks();

         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            byte[] imageByts = book.getImage();
            if(imageByts != null) {
               System.out.print("image bytes: [");
               for(int j = 0; j < imageByts.length ; j++) {
                  System.out.print("0x"
                  + String.format("%x", imageByts[j]) +" ");
               }
               System.out.println("]");
            }
            System.out.println(book.getXml());
            i++;
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTesterは次のタスクを実行します。

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testInterceptedEjb()メソッドでは、jndiルックアップが名前-"LibraryPersistenceBean/remote"で実行され、リモートビジネスオブジェクト(ステートレスEJB)が取得されます。
  • 次に、ユーザーにライブラリストアのユーザーインターフェイスが表示され、選択肢を入力するように求められます。
  • ユーザーが1を入力すると、システムはブック名を要求し、ステートレスセッションBeanのaddBook()メソッドを使用してブックを保存します。 セッションBeanはデータベースに本を保存しています。
  • ユーザーが2を入力すると、システムはステートレスセッションBeanのgetBooks()メソッドを使用して本を取得し、終了します。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: learn testing
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 1
1. learn testing
image bytes: [
   0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 ]
<book><name>learn testing</name></book>
BUILD SUCCESSFUL (total time: 20 seconds)

EJB-トランザクション

トランザクションは、ACIDプロパティに従う作業アイテムの単一ユニットです。 ACIDは、Atomic、Consistent、Isolated、Durableの略です。

  • アトミック-ワークアイテムのいずれかが失敗した場合、ユニット全体が失敗したと見なされます。 成功とは、すべてのアイテムが正常に実行されることを意味します。
  • 一貫性-トランザクションは、システムを一貫した状態に保つ必要があります。
  • 分離-各トランザクションは、他のトランザクションとは無関係に実行されます。
  • 耐久性-トランザクションは、実行またはコミットされた場合、システム障害に耐える必要があります。

EJBコンテナ/サーバーはトランザクションサーバーであり、トランザクションコンテキストの伝播と分散トランザクションを処理します。 トランザクションは、コンテナまたはBeanのコードのカスタムコード処理によって管理できます。

  • Container Managed Transactions -このタイプでは、コンテナーがトランザクションの状態を管理します。
  • * Bean Managed Transactions-このタイプでは、開発者はトランザクション状態のライフサイクルを管理します。

コンテナ管理トランザクション

EJB 3.0は、EJBコンテナが実装するトランザクションの次の属性を指定しました-

  • 必須-ビジネスメソッドをトランザクション内で実行する必要があることを示します。そうしないと、そのメソッドに対して新しいトランザクションが開始されます。
  • REQUIRES_NEW -新しいトランザクションがビジネスメソッドに対して開始されることを示します。
  • SUPPORTS -ビジネスメソッドがトランザクションの一部として実行されることを示します。
  • NOT_SUPPORTED -ビジネスメソッドをトランザクションの一部として実行しないことを示します。
  • 必須-ビジネスメソッドがトランザクションの一部として実行されることを示し、そうでない場合は例外がスローされます。
  • NEVER -ビジネスメソッドがトランザクションの一部として実行される場合、例外がスローされます。

package com.finddevguides.txn.required;

import javax.ejb.*

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class UserDetailBean implements UserDetailRemote {

   private UserDetail;

   @TransactionAttribute(TransactionAttributeType.REQUIRED)
   public void createUserDetail() {
     //create user details object
   }
}

createUserDetail()ビジネスメソッドは、Requiredアノテーションを使用してRequiredになります。

package com.finddevguides.txn.required;

import javax.ejb.*

@Stateless
public class UserSessionBean implements UserRemote {

   private User;

   @EJB
   private UserDetailRemote userDetail;

   public void createUser() {
     //create user
     //...
     //create user details
      userDetail.createUserDetail();
   }
}

createUser()ビジネスメソッドはcreateUserDetail()を使用しています。 createUser()呼び出し中に例外が発生し、Userオブジェクトが作成されない場合、UserDetailオブジェクトも作成されません。

Bean管理トランザクション

Bean Managed Transactionsでは、アプリケーションレベルで例外を処理することでトランザクションを管理できます。

考慮すべき重要な点は次のとおりです-

  • 開始-ビジネスメソッドでいつトランザクションを開始するか。
  • 成功-トランザクションをコミットするときの成功シナリオを特定します。
  • Failed -トランザクションをロールバックする場合の障害シナリオを特定します。

package com.finddevguides.txn.bmt;

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.transaction.UserTransaction;

@Stateless
@TransactionManagement(value=TransactionManagementType.BEAN)
public class AccountBean implements AccountBeanLocal {

   @Resource
   private UserTransaction userTransaction;

   public void transferFund(Account fromAccount, double fund ,
      Account toAccount) throws Exception{

      try{
         userTransaction.begin();

         confirmAccountDetail(fromAccount);
         withdrawAmount(fromAccount,fund);

         confirmAccountDetail(toAccount);
         depositAmount(toAccount,fund);

         userTransaction.commit();
      }catch (InvalidAccountException exception) {
         userTransaction.rollback();
      }catch (InsufficientFundException exception) {
         userTransaction.rollback();
      }catch (PaymentException exception) {
         userTransaction.rollback();
      }
   }

   private void confirmAccountDetail(Account account)
      throws InvalidAccountException {
   }

   private void withdrawAmount() throws InsufficientFundException {
   }

   private void depositAmount() throws PaymentException{
   }
}

この例では、 UserTransaction インターフェイスを使用して、* userTransaction.begin()メソッド呼び出しを使用してトランザクションの開始をマークしました。 * userTransaction.commit()*メソッドを使用してトランザクションの完了をマークし、トランザクション中に例外が発生した場合は、 userTransaction.rollback()*メソッド呼び出しを使用してトランザクション全体をロールバックします。

EJB-セキュリティ

セキュリティは、エンタープライズレベルのアプリケーションの主要な関心事です。 これには、アプリケーションにアクセスするユーザーまたはシステムの識別が含まれます。 識別に基づいて、アプリケーション内のリソースへのアクセスを許可または拒否します。 EJBコンテナは、標準のセキュリティ上の問題を管理します。または、特定のセキュリティ上の問題を処理するためにカスタマイズできます。

セキュリティの重要な条件

  • 認証-これは、システムまたはアプリケーションにアクセスするユーザーが本物であることを確認するプロセスです。
  • 承認-これは、本物のユーザーがシステムリソースにアクセスするための正しいレベルの権限を持つことを保証するプロセスです。
  • ユーザー-ユーザーは、アプリケーションにアクセスするクライアントまたはシステムを表します。
  • ユーザーグループ-ユーザーは、特定の権限を持つグループの一部である場合があります(管理者グループなど)。
  • ユーザーロール-ロールは、システムリソースにアクセスするための権限、ユーザーの権限、またはアクセス許可のレベルを定義します。

コンテナ管理セキュリティ

EJB 3.0は、EJBコンテナが実装するセキュリティの以下の属性/注釈を指定しています。

  • DeclareRoles -クラスが宣言されたロールを受け入れることを示します。 注釈はクラスレベルで適用されます。
  • RolesAllowed -指定されたロールのユーザーがメソッドにアクセスできることを示します。 クラスのすべてのメソッドにアクセスできるクラスレベルで適用でき、指定されたロールのユーザーを購入できます。
  • PermitAll -ビジネスメソッドがすべてにアクセス可能であることを示します。 クラスおよびメソッドレベルで適用できます。
  • DenyAll -クラスまたはメソッドレベルで指定されたユーザーがビジネスメソッドにアクセスできないことを示します。

package com.finddevguides.security.required;

import javax.ejb.*

@Stateless
@DeclareRoles({"student" "librarian"})
public class LibraryBean implements LibraryRemote {

   @RolesAllowed({"librarian"})
   public void delete(Book book) {
     //delete book
   }

   @PermitAll
   public void viewBook(Book book) {
     //view book
   }

   @DenyAll
   public void deleteAll() {
     //delete all books
   }
}

セキュリティ構成

構成ファイルにグループ化されたロールとユーザーをマップします。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 EJB 3.0//EN" "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_3_0-0.dtd">
<ejb-jar>
   <security-role-mapping>
      <role-name>student</role-name>
      <group-name>student-group</group-name>
   </security-role-mapping>
   <security-role-mapping>
      <role-name>librarian</role-name>
      <group-name>librarian-group</group-name>
   </security-role-mapping>
   <enterprise-beans/>
</ejb-jar>

EJB-JNDIバインディング

JNDIは、Java Naming and Directory Interfaceの略です。 これは、APIおよびサービスインターフェイスのセットです。 Javaベースのアプリケーションは、ネーミングおよびディレクトリサービスにJNDIを使用します。 EJBのコンテキストでは、2つの用語があります。

  • Binding -これは、後で使用できるEJBオブジェクトに名前を割り当てることを指します。
  • ルックアップ-これは、EJBのオブジェクトをルックアップして取得することを指します。

Jbossでは、セッションBeanはデフォルトで次の形式でJNDIにバインドされます。

  • local -EJB-name/local
  • remote -EJB-name/remote

場合には、EJBは<application-name> .earファイルにバンドルされており、デフォルトのフォーマットは次のとおりです-

  • local -application-name/ejb-name/local
  • リモート-アプリケーション名/EJB名/リモート

デフォルトのバインドの例

_EJB-アプリケーションの作成_の章のJBossコンソール出力を参照してください。

JBoss Application Serverのログ出力

...
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibrarySessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.stateless.LibrarySessionBean ejbName: LibrarySessionBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

   LibrarySessionBean/remote - EJB3.x Default Remote Business Interface
   LibrarySessionBean/remote-com.finddevguides.stateless.LibrarySessionBeanRemote - EJB3.x Remote Business Interface
...

カスタマイズされたバインディング

次の注釈を使用して、デフォルトのJNDIバインディングをカスタマイズできます-

  • local -org.jboss.ejb3.LocalBinding
  • リモート-org.jboss.ejb3.RemoteBindings

LibrarySessionBean.javaを更新します。 _EJB-アプリケーションの作成_の章を参照してください。

LibrarySessionBean

package com.finddevguides.stateless;

import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;

@Stateless
@LocalBinding(jndiBinding="finddevguides/librarySession")
public class LibrarySessionBean implements LibrarySessionBeanLocal {

    List<String> bookShelf;

    public LibrarySessionBean() {
       bookShelf = new ArrayList<String>();
    }

    public void addBook(String bookName) {
       bookShelf.add(bookName);
    }

    public List<String> getBooks() {
        return bookShelf;
    }
}

LibrarySessionBeanLocal

package com.finddevguides.stateless;

import java.util.List;
import javax.ejb.Local;

@Local
public interface LibrarySessionBeanLocal {

    void addBook(String bookName);

    List getBooks();

}

プロジェクトをビルドし、Jbossにアプリケーションをデプロイし、Jbossコンソールで次の出力を確認します-

...
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibrarySessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.stateless.LibrarySessionBean ejbName: LibrarySessionBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

   finddevguides/librarySession - EJB3.x Default Local Business Interface
   finddevguides/librarySession-com.finddevguides.stateless.LibrarySessionBeanLocal - EJB3.x Local Business Interface
...

EJB-エンティティの関係

EJB 3.0は、1対1、1対多、多対1、多対多などのデータベースエンティティの関係/マッピングを定義するオプションを提供します。

以下は関連する注釈です-

  • 1対1 -オブジェクトには1対1の関係があります。 たとえば、乗客は一度に1つのチケットを使用して旅行できます。
  • * 1対多*-オブジェクトには1対多の関係があります。 たとえば、父親は複数の子供を持つことができます。
  • 多対一-オブジェクトには多対1の関係があります。 たとえば、シングルマザーを持つ複数の子供。
  • 多対多-オブジェクトには多対多の関係があります。 たとえば、本には複数の著者がいて、著者は複数の本を書くことができます。

ここでは、ManyToManyマッピングの使用方法を示します。 ManyToMany関係を表すには、次の3つの表が必要です-

  • Book -書籍の記録がある書籍テーブル。
  • Author -著者のレコードを持つ著者テーブル。
  • Book_Author -上記のBookとAuthorテーブルのリンクを持つBook Authorテーブル。

テーブルを作成する

デフォルトのデータベース postgres にテーブル book authorbook_author を作成します。

CREATE TABLE book (
   book_id     integer,
   name   varchar(50)
);

CREATE TABLE author (
   author_id   integer,
   name   varchar(50)
);

CREATE TABLE book_author (
   book_id     integer,
   author_id   integer
);

エンティティクラスを作成する

@Entity
@Table(name="author")
public class Author implements Serializable{
   private int id;
   private String name;
   ...
}

@Entity
@Table(name="book")
public class Book implements Serializable{
   private int id;
   private String title;
   private Set<Author> authors;
   ...
}

Book EntityでManyToManyアノテーションを使用します。

@Entity
public class Book implements Serializable{
   ...
   @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}
      , fetch = FetchType.EAGER)
   @JoinTable(table = @Table(name = "book_author"),
      joinColumns = {@JoinColumn(name = "book_id")},
      inverseJoinColumns = {@JoinColumn(name = "author_id")})
   public Set<Author> getAuthors() {
      return authors;
   }
   ...
}

応用例

EJB 3.0でエンティティ関係オブジェクトをテストするテストEJBアプリケーションを作成しましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.entity as explained in the EJB - Create Application chapter. Please use the project created in EJB - Persistence chapter as such for this chapter to understand embedded objects in EJB concepts.
2 Create Author.java under package com.finddevguides.entity as explained in the EJB - Create Application chapter. Keep rest of the files unchanged.
3 Create Book.java under package com.finddevguides.entity. Use EJB - Persistence chapter as reference. Keep rest of the files unchanged.
4 Clean and Build the application to make sure business logic is working as per the requirements.
5 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
6 Now create the EJB client, a console based application in the same way as explained in the EJB - Create Application chapter under topic Create Client to access EJB.

EJBComponent(EJBモジュール)

Author.java

package com.finddevguides.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="author")
public class Author implements Serializable{

   private int id;
   private String name;

   public Author() {}

   public Author(int id, String name) {
      this.id = id;
      this.name = name;
   }

   @Id
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="author_id")
   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

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

   public String toString() {
      return id + "," + name;
   }
}

Book.java

package com.finddevguides.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;

@Entity
@Table(name="book")
public class Book implements Serializable{

   private int id;
   private String name;
   private Set<Author> authors;

   public Book() {
   }

   @Id
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="book_id")
   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

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

   public void setAuthors(Set<Author> authors) {
      this.authors = authors;
   }

   @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}
      , fetch = FetchType.EAGER)
   @JoinTable(table = @Table(name = "book_author"),
      joinColumns = {@JoinColumn(name = "book_id")},
      inverseJoinColumns = {@JoinColumn(name = "author_id")})
   public Set<Author> getAuthors() {
      return authors;
   }
}

LibraryPersistentBeanRemote.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Remote;

@Remote
public interface LibraryPersistentBeanRemote {

   void addBook(Book bookName);

   List<Book> getBooks();

}

LibraryPersistentBean.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Stateless;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

   public LibraryPersistentBean() {
   }

   @PersistenceContext(unitName="EjbComponentPU")
   private EntityManager entityManager;

   public void addBook(Book book) {
      entityManager.persist(book);
   }

   public List<Book> getBooks() {
      return entityManager.createQuery("From Book").getResultList();
   }
}
  • EjbComponentプロジェクトをJBOSSにデプロイするとすぐに、jbossログに注目してください。
  • JBossは、セッションBeanのJNDIエントリを自動的に作成しました- LibraryPersistentBean/remote
  • このルックアップ文字列を使用して、タイプのリモートビジネスオブジェクトを取得します- com.finddevguides.interceptor.LibraryPersistentBeanRemote

JBoss Application Serverのログ出力

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.interceptor.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.interceptor.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.interceptor.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...

EJBTester(EJBクライアント)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • これらのプロパティは、JavaネームサービスのInitialContextオブジェクトを初期化するために使用されます。
  • InitialContextオブジェクトは、ステートレスセッションBeanのルックアップに使用されます。

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.stateful.LibraryBeanRemote;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import java.util.*;

import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testEmbeddedObjects();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testEmbeddedObjects() {

      try {
         int choice = 1;

         LibraryPersistentBeanRemote libraryBean =
         (LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");

         while (choice != 2) {
            String bookName;
            String authorName;

            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               System.out.print("Enter author name: ");
               authorName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               Author author = new Author();
               author.setName(authorName);
               Set<Author> authors = new HashSet<Author>();
               authors.add(author);
               book.setAuthors(authors);

               libraryBean.addBook(book);
            } else if (choice == 2) {
               break;
            }
         }

         List<Book> booksList = libraryBean.getBooks();

         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            System.out.print("Author: ");
            Author[] authors = (Author[])books.getAuthors().toArray();
            for(int j=0;j<authors.length;j++) {
               System.out.println(authors[j]);
            }
            i++;
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTesterは次のタスクを実行します-

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testInterceptedEjb()メソッドでは、jndiルックアップが名前-"LibraryPersistenceBean/remote"で実行され、リモートビジネスオブジェクト(ステートレスEJB)が取得されます。
  • 次に、ユーザーにライブラリストアのユーザーインターフェイスが表示され、選択肢を入力するように求められます。
  • ユーザーが1を入力すると、システムはブック名を要求し、ステートレスセッションBeanのaddBook()メソッドを使用してブックを保存します。 セッションBeanはデータベースに本を保存しています。
  • ユーザーが2を入力すると、システムはステートレスセッションBeanのgetBooks()メソッドを使用して本を取得し、終了します。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: learn html5
Enter Author name: Robert
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 1
1. learn html5
Author: Robert
BUILD SUCCESSFUL (total time: 21 seconds)

EJB-Accessデータベース

EJB 3.0では、永続性メカニズムを使用して、コンテナがデータベース関連の操作を管理するデータベースにアクセスします。 開発者は、JDBC API呼び出しを使用してEJBビジネスメソッドでデータベースに直接アクセスできます。

EJBでのデータベースアクセスを実証するには、次のタスクを実行する必要があります-

  • *ステップ1 *-データベースにテーブルを作成します。
  • *ステップ2 *-ビジネスミーを持つステートレスEJBを作成します。
  • *ステップ3 *-ステートレスEJBを更新します。 エンティティマネージャーを介してレコードを追加し、データベースからレコードを取得するメソッドを追加します。
  • *ステップ4 *-コンソールベースのアプリケーションクライアントは、ステートレスEJBにアクセスしてデータベースにデータを保持します。

テーブルを作成

デフォルトのデータベース postgres にテーブル books を作成します。

CREATE TABLE books (
   id     integer PRIMARY KEY,
   name   varchar(50)
);

モデルクラスを作成する

public class Book implements Serializable{

   private int id;
   private String name;

   public Book() {
   }

   public int getId() {
      return id;
   }
   ...
}

ステートレスEJBを作成する

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

   public void addBook(Book book) {
    //persist book using jdbc calls
   }

   public List<Book> getBooks() {
    //get books using jdbc calls
   }
   ...
}

EJBモジュールをビルドしたら、次のセクションで作成するステートレスBeanにアクセスするためのクライアントが必要です。

応用例

テストEJBアプリケーションを作成して、EJBデータベースアクセスメカニズムをテストしましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.entity as explained in the EJB - Create Application chapter. You can also use the project created in EJB - Create Application chapter as such for this chapter to understand EJB data access concepts.
2 Create Book.java under package com.finddevguides.entity and modify it as shown below.
3 Create LibraryPersistentBean.java and LibraryPersistentBeanRemote as explained in the EJB - Create Application chapter and modify them as shown below.
4 Clean and Build the application to make sure business logic is working as per the requirements.
5 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
6 Now create the EJB client, a console based application in the same way as explained in the EJB - Create Application chapter under topic Create Client to access EJB. Modify it as shown below.

EJBComponent(EJBモジュール)

Book.java

package com.finddevguides.entity;

import java.io.Serializable;

public class Book implements Serializable{

   private int id;
   private String name;

   public Book() {
   }

   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

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

LibraryPersistentBeanRemote.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Remote;

@Remote
public interface LibraryPersistentBeanRemote {

   void addBook(Book bookName);

   List<Book> getBooks();

}

LibraryPersistentBean.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

   public LibraryPersistentBean() {
   }

   public void addBook(Book book) {
      Connection con = null;
      String url = "jdbc:postgresql://localhost:5432/postgres";
      String driver = "org.postgresql.driver";

      String userName = "sa";
      String password = "sa";
      List<Book> books = new ArrayList<Book>();
      try {

         Class.forName(driver).newInstance();
         con = DriverManager.getConnection(url , userName, password);

         PreparedStatement st =
         con.prepareStatement("insert into book(name) values(?)");
         st.setString(1,book.getName());

         int result = st.executeUpdate();

      } catch (SQLException ex) {
         ex.printStackTrace();
      } catch (InstantiationException ex) {
         ex.printStackTrace();
      } catch (IllegalAccessException ex) {
         ex.printStackTrace();
      } catch (ClassNotFoundException ex) {
         ex.printStackTrace();
      }
   }

   public List<Book> getBooks() {
      Connection con = null;
      String url = "jdbc:postgresql://localhost:5432/postgres";
      String driver = "org.postgresql.driver";

      String userName = "sa";
      String password = "sa";
      List<Book> books = new ArrayList<Book>();
      try {

         Class.forName(driver).newInstance();
         con = DriverManager.getConnection(url , userName, password);

         Statement st = con.createStatement();
         ResultSet rs = st.executeQuery("select * from book");

         Book book;
         while (rs.next()) {
            book = new Book();
            book.setId(rs.getInt(1));
            book.setName(rs.getString(2));
            books.add(book);
         }
      } catch (SQLException ex) {
         ex.printStackTrace();
      } catch (InstantiationException ex) {
         ex.printStackTrace();
      } catch (IllegalAccessException ex) {
         ex.printStackTrace();
      } catch (ClassNotFoundException ex) {
         ex.printStackTrace();
      }
      return books;
   }
}
  • EjbComponentプロジェクトをJBOSSにデプロイするとすぐに、jbossログに注目してください。
  • JBossは、セッションBeanのJNDIエントリ- LibraryPersistentBean/remote を自動的に作成しました。
  • このルックアップ文字列を使用して、タイプのリモートビジネスオブジェクトを取得します- com.finddevguides.stateless.LibraryPersistentBeanRemote

JBoss Application Serverのログ出力

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBeanRemote,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.stateless.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...

EJBTester(EJBクライアント)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • これらのプロパティは、JavaネームサービスのInitialContextオブジェクトを初期化するために使用されます。
  • InitialContextオブジェクトは、ステートレスセッションBeanのルックアップに使用されます。

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.stateless.LibraryPersistentBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testEntityEjb();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testEntityEjb() {

      try {
         int choice = 1;

         LibraryPersistentBeanRemote libraryBean =
         LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");

         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);
            } else if (choice == 2) {
               break;
            }
         }

         List<Book> booksList = libraryBean.getBooks();

         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTesterは次のタスクを実行します-

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testStatefulEjb()メソッドでは、jndiルックアップが「LibraryStatelessSessionBean/remote」という名前で実行され、リモートビジネスオブジェクト(ステートフルEJB)が取得されます。
  • 次に、ユーザーにライブラリストアのユーザーインターフェイスが表示され、ユーザーは選択肢を入力するよう求められます。
  • ユーザーが1を入力すると、システムはブック名を要求し、ステートレスセッションBeanのaddBook()メソッドを使用してブックを保存します。 セッションBeanは、EntityManager呼び出しを介してデータベースに本を保持しています。
  • ユーザーが2を入力すると、システムはステートレスセッションBeanのgetBooks()メソッドを使用して本を取得し、終了します。
  • 次に、「LibraryStatelessSessionBean/remote」という名前で別のjndiルックアップが行われ、リモートビジネスオブジェクト(ステートフルEJB)が再度取得され、書籍のリストが作成されます。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 1
1. learn java
BUILD SUCCESSFUL (total time: 15 seconds)

EJB-クエリ言語

  • EJBクエリ言語*は、基になるデータベースの詳細を気にせずにカスタムクエリを記述するのに非常に便利です。 これは、休止状態のクエリ言語であるHQLと非常によく似ており、多くの場合EJBQLという名前で呼ばれます。

EJBでEJBQLを示すために、次のタスクを実行します-

  • *ステップ1 *-データベースにテーブルを作成します。
  • *ステップ2 *-ビジネスミーを持つステートレスEJBを作成します。
  • *ステップ3 *-ステートレスEJBを更新します。 エンティティマネージャーを介してレコードを追加し、データベースからレコードを取得するメソッドを追加します。
  • *ステップ4 *-コンソールベースのアプリケーションクライアントは、ステートレスEJBにアクセスしてデータベースにデータを保持します。

テーブルを作成

デフォルトのデータベース postgres にテーブル books を作成します。

CREATE TABLE books (
   id     integer PRIMARY KEY,
   name   varchar(50)
);

モデルクラスを作成する

public class Book implements Serializable{

   private int id;
   private String name;

   public Book() {
   }

   public int getId() {
      return id;
   }
   ...
}

ステートレスEJBを作成する

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

   public void addBook(Book book) {
    //persist book using entity manager
   }

   public List<Book> getBooks() {
    //get books using entity manager
   }
   ...
}

EJBモジュールをビルドしたら、次のセクションで作成するステートレスBeanにアクセスするためのクライアントが必要です。

応用例

テストEJBアプリケーションを作成して、EJBデータベースアクセスメカニズムをテストしましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.entity as explained in the EJB - Create Application chapter. You can also use the project created in EJB - Create Application chapter as such for this chapter to understand EJB data access concepts.
2 Create Book.java under package com.finddevguides.entity and modify it as shown below.
3 Create LibraryPersistentBean.java and LibraryPersistentBeanRemote as explained in the EJB - Create Application chapter and modify them as shown below.
4 Clean and Build the application to make sure business logic is working as per the requirements.
5 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
6 Now create the EJB client, a console based application in the same way as explained in the EJB - Create Application chapter under topic Create Client to access EJB. Modify it as shown below.

EJBComponent(EJBモジュール)

Book.java

package com.finddevguides.entity;

import java.io.Serializable;

public class Book implements Serializable{

   private int id;
   private String name;

   public Book() {
   }

   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

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

LibraryPersistentBeanRemote.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Remote;

@Remote
public interface LibraryPersistentBeanRemote {
   void addBook(Book bookName);
   List<Book> getBooks();
}

LibraryPersistentBean.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

   public LibraryPersistentBean() {
   }

   @PersistenceContext(unitName="EntityEjbPU")
   private EntityManager entityManager;

   public void addBook(Book book) {
      entityManager.persist(book);
   }

   public List<Book> getBooks() {
     //create an ejbql expression
      String ejbQL = "From Book b where b.name like ?1";
     //create query
      Query query = entityManager.createQuery(ejbQL);
     //substitute parameter.
      query.setParameter(1, "%test%");
     //execute the query
      return query.getResultList();
   }
}
  • EjbComponentプロジェクトをJBOSSにデプロイするとすぐに、jbossログに注目してください。
  • JBossは、セッションBeanのJNDIエントリを自動的に作成しました- LibraryPersistentBean/remote
  • このルックアップ文字列を使用して、タイプのリモートビジネスオブジェクトを取得します- com.finddevguides.stateless.LibraryPersistentBeanRemote

JBoss Application Serverのログ出力

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBeanRemote,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.finddevguides.stateless.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.finddevguides.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...

EJBTester(EJBクライアント)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • これらのプロパティは、JavaネームサービスのInitialContextオブジェクトを初期化するために使用されます。
  • InitialContextオブジェクトは、ステートレスセッションBeanのルックアップに使用されます。

EJBTester.java

package com.finddevguides.test;

import com.finddevguides.stateless.LibraryPersistentBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBTester {

   BufferedReader brConsoleReader = null;
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader =
      new BufferedReader(new InputStreamReader(System.in));
   }

   public static void main(String[] args) {

      EJBTester ejbTester = new EJBTester();

      ejbTester.testEntityEjb();
   }

   private void showGUI() {
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }

   private void testEntityEjb() {

      try {
         int choice = 1;

         LibraryPersistentBeanRemote libraryBean =
         LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");

         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);
            } else if (choice == 2) {
               break;
            }
         }

         List<Book> booksList = libraryBean.getBooks();

         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null) {
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTesterは次のタスクを実行します-

  • jndi.propertiesからプロパティをロードし、InitialContextオブジェクトを初期化します。
  • testStatefulEjb()メソッドでは、jndiルックアップが「LibraryStatelessSessionBean/remote」という名前で実行され、リモートビジネスオブジェクト(ステートフルejb)が取得されます。
  • 次に、ユーザーにライブラリストアのユーザーインターフェイスが表示され、ユーザーは選択肢を入力するよう求められます。
  • ユーザーが1を入力すると、システムはブック名を要求し、ステートレスセッションBeanのaddBook()メソッドを使用してブックを保存します。 セッションBeanは、EntityManager呼び出しを介してデータベースに本を保持しています。
  • ユーザーが2を入力すると、システムはステートレスセッションBeanのgetBooks()メソッドを使用して本を取得し、終了します。
  • 次に、「LibraryStatelessSessionBean/remote」という名前で別のjndiルックアップが実行され、リモートビジネスオブジェクト(ステートフルEJB)が再度取得され、書籍のリストが作成されます。

クライアントを実行してEJBにアクセスする

プロジェクトエクスプローラーでEJBTester.javaを見つけます。 EJBTesterクラスを右クリックして、 run file を選択します。

Netbeansコンソールで次の出力を確認します。

run:
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: Learn Testing
**********************
Welcome to Book Store
**********************
Options
1. Add Book
2. Exit
Enter Choice: 2
Book(s) entered so far: 1
1. learn Testing
BUILD SUCCESSFUL (total time: 15 seconds)

EJB-例外処理

EJBは、通常分散環境に基づいているエンタープライズアプリケーションの一部です。 そのため、発生する可能性のある通常の例外とは別に、通信障害、セキュリティ許可、サーバー停止などの例外が発生する可能性があります。

EJBコンテナは、2つの方法で例外を考慮します-

  • アプリケーション例外-ビジネスルールの違反またはビジネスロジックの実行中に例外が発生した場合。
  • システム例外-ビジネスロジックまたはビジネスコードが原因ではない例外。 RuntimeException、RemoteExceptionはSystemExceptionです。 たとえば、EJBルックアップ中のエラー。 RuntimeException、RemoteExceptionはSystemExceptionです。

EJBコンテナはどのように例外を処理しますか?

*Application Exception* が発生すると、EJBコンテナは例外をインターセプトしますが、そのままクライアントに返します。 EJBContext.setRollBackOnly()メソッドによってコードで指定されていない限り、トランザクションはロールバックされません。 EJBコンテナは、アプリケーション例外の場合に例外をラップしません。
  • システム例外*が発生すると、EJBコンテナは例外をインターセプトし、トランザクションをロールバックし、クリーンアップタスクを開始します。 例外をRemoteExceptionにラップし、クライアントにスローします。

アプリケーション例外の処理

通常、アプリケーション例外はセッションEJBメソッドでスローされます。これらはビジネスロジックの実行を担当するメソッドであるためです。 アプリケーション例外は、ビジネスメソッドのthrows句で宣言し、ビジネスロジックが失敗した場合にスローする必要があります。

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

   ...

   public List<Book> getBooks() throws NoBookAvailableException {
      List<Book> books =
         entityManager.createQuery("From Books").getResultList();
      if(books.size == 0)
        throw NoBookAvailableException
           ("No Book available in library.");
      return books;
   }
   ...
}

システム例外の処理

システムの例外は、名前の検索が失敗したり、データの取得中にSQLエラーが発生したりするなど、いつでも発生する可能性があります。 そのような場合、そのような例外はEJBExceptionでラップされ、クライアントにスローされる必要があります。

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

   ...

   public List<Book> getBooks() {
      try {
         List<Book> books =
            entityManager.createQuery("From Books").getResultList();
      } catch (CreateException ce) {
         throw (EJBException) new EJBException(ce).initCause(ce);
      } catch (SqlException se) {
         throw (EJBException) new EJBException(se).initCause(se);
      }
      return books;
   }
   ...
}

クライアント側で、EJBExceptionを処理します。

public class EJBTester {
   private void testEntityEjb() {
   ...
   try{
      LibraryPersistentBeanRemote libraryBean =
      LibraryPersistentBeanRemote)ctx.lookup("LibraryPersistentBean/remote");

      List<Book> booksList = libraryBean.getBooks();
   } catch(EJBException e) {
      Exception ne = (Exception) e.getCause();
      if(ne.getClass().getName().equals("SqlException")) {
         System.out.println("Database error: "+ e.getMessage());
      }
   }
   ...
   }
}

EJB-Webサービス

EJB 3.0は、セッションEJBをWebサービスとして公開するオプションを提供します。 @WebService注釈は、クラスをWebサービスのエンドポイントとしてマークするために使用され、@ WebMethodは、メソッドをWebメソッドとしてクライアントに公開するために使用されます。

@Stateless
@WebService(serviceName="LibraryService")
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

   ...
   @WebMethod(operationName="getBooks")
   public List<Book> getBooks()  {
      return entityManager.createQuery("From Books").getResultList();
   }
   ...
}

応用例

EJB 3.0でblob/clobサポートをテストするテストEJBアプリケーションを作成しましょう。

Step Description
1 Create a project with a name EjbComponent under a package com.finddevguides.entity as explained in the EJB - Create Application chapter. Please use the project created in EJB - Persistence chapter as such for this chapter to understand clob/blob objects in EJB concepts.
2 Create LibraryPersistentBean.java under package com.finddevguides.stateless. Use EJB - Persistence chapter as reference. Keep rest of the files unchanged.
3 Clean and Build the application to make sure business logic is working as per the requirements.
4 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.

LibraryPersistentBean.java

package com.finddevguides.stateless;

import com.finddevguides.entity.Book;
import java.util.List;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
@WebService(serviceName="LibraryService")
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {

   public LibraryPersistentBean() {
   }

   @PersistenceContext(unitName="EjbComponentPU")
   private EntityManager entityManager;

   public void addBook(Book book) {
      entityManager.persist(book);
   }

   @WebMethod(operationName="getBooks")
   public List <Book> getBooks() {
      return entityManager.createQuery("From Book").getResultList();
   }
}

JBoss Application Serverのログ出力

10:51:37,271 INFO  [EJBContainer] STARTED EJB: com.finddevguides.stateless.LibraryPersistentBean ejbName: LibraryPersistentBean
10:51:37,287 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

    LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
    LibraryPersistentBean/remote-com.finddevguides.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface

10:51:37,349 INFO  [EJBContainer] STARTED EJB: com.tuturialspoint.messagebean.LibraryMessageBean ejbName: BookMessageHandler
10:51:37,443 INFO  [DefaultEndpointRegistry] register: jboss.ws:context=EjbComponent,endpoint=LibraryPersistentBean
10:51:38,191 INFO  [WSDLFilePublisher] WSDL published to: file:/D:/Jboss-5.0.1/server/default/data/wsdl/EjbComponent.jar/
LibraryService3853081455302946642.wsdl

WebサービスとしてEJBにアクセスするクライアントを作成する

NetBeans IDEで、「、ファイル」>「新規プロジェクト」> *を選択します。カテゴリ「 *Java 」の下のプロジェクトタイプを選択し、プロジェクトタイプとして「* Javaアプリケーション*」を選択します。 Next> ボタンをクリックします。プロジェクト名と場所を入力します。 *完了> *ボタンをクリックします。 EJBWebServiceClientとして名前を選択しました。

[プロジェクトエクスプローラ]ウィンドウでプロジェクト名を右クリックします。 *新規> WebServiceクライアント*を選択します。

WSDLクライアント

[コンパイル]タブの[プロジェクトの追加]ボタンを使用して、WSDLおよびクライアントの場所の下で作成したEJBコンポーネントプロジェクトのLibraryPersistentBeanを追加します。

WebサービスBean

[完了]ボタンをクリックします。 プロジェクトエクスプローラーで次の構造を確認します。

WebサービスBean

EJBWebServiceClient.javaを作成します

package ejbwebserviceclient;

public class EJBWebServiceClient {
   public static void main(String[] args) {
   }
}

次の図に示すように、WebサービスのgetBooks Webメソッドを選択し、EJBWebServiceClientのコードウィンドウにドラッグします。

Webサービスメソッドのドラッグ

次のような出力が表示されます。

ドラッグされたWebサービスメソッド

このメソッドを使用するには、EJBWebServiceClientコードを更新します。

package ejbwebserviceclient;

public class EJBWebServiceClient {

   public static void main(String[] args) {
      for(com.finddevguides.stateless.Book book:getBooks()) {
         System.out.println(book.getName());
      }
   }

   private static java.util.List
   <com.finddevguides.stateless.Book> getBooks() {
      com.finddevguides.stateless.LibraryService service =
         new com.finddevguides.stateless.LibraryService();
      com.finddevguides.stateless.LibraryPersistentBean port =
         service.getLibraryPersistentBeanPort();
      return port.getBooks();
   }
}

クライアントを実行する

[プロジェクトエクスプローラ]ウィンドウでプロジェクト名を右クリックします。 [実行]を選択します。 Netbeansはクライアントをビルドして実行します。 次の出力を確認します。

ant -f D:\\SVN\\EJBWebServiceClient run
init:
Deleting: D:\SVN\EJBWebServiceClient\build\built-jar.properties
deps-jar:
Updating property file: D:\SVN\EJBWebServiceClient\build\built-jar.properties
wsimport-init:
wsimport-client-LibraryPersistentBean:
files are up to date
classLoader = java.net.URLClassLoader@4ce46c
SharedSecrets.getJavaNetAccess()=java.net.URLClassLoader$7@182cdac
wsimport-client-generate:
Compiling 1 source file to D:\SVN\EJBWebServiceClient\build\classes
compile:
run:
learn java
Learn Spring
learn JSF
Learn HTML
Learn JBoss
Learn EJB
Learn Hibernate
Learn IBatis
Times Now
learn html5
Learn images
Learn Testing
Forbes
test1
BUILD SUCCESSFUL (total time: 1 second)

EJB-アプリケーションのパッケージ化

EJB 3.0を使用したパッケージアプリケーションの要件は、J2EEプラットフォームの要件と同様です。 EJBコンポーネントは、jarファイルとしてモジュールにパッケージ化され、earファイルとしてアプリケーションエンタープライズアーカイブにパッケージ化されます。

エンタープライズアプリケーションには、主に3つのコンポーネントがあります-

  • jar -EJBモジュール、EJBクライアントモジュール、およびユーティリティモジュールを含むJavaアプリケーションaRchive。
  • war -Webモジュールを含むWebアプリケーションaRchive。
  • ear -jarおよびwarモジュールを含むエンタープライズアプリケーションaRchive。

EAR

NetBeansでは、J2EEアプリケーションの作成、開発、パッケージ化、およびデプロイが非常に簡単です。

NetBeans IDEで、「ファイル」>「新規プロジェクト」> *を選択します。カテゴリ「 *Java EE 」の下のプロジェクトタイプを選択し、プロジェクトタイプとして「エンタープライズアプリケーション」を選択します。 Next> ボタンをクリックします。 プロジェクト名と場所を入力します。 *完了> *ボタンをクリックします。 EnterpriseApplicatonとして名前を選択しました。

[サーバーと設定]を選択します。 * EJBモジュールの作成*および* Webアプリケーションモジュールの作成*をデフォルトの名前でオンのままにします。 終了ボタンをクリックします。 NetBeansは、プロジェクトウィンドウに次の構造を作成します。

EARプロジェクト

プロジェクトエクスプローラーでプロジェクト*エンタープライズアプリケーション*を右クリックし、[ビルド]を選択します。

ant -f D:\\SVN\\EnterpriseApplication dist
pre-init:
init-private:
init-userdir:
init-user:
init-project:
do-init:
post-init:
init-check:
init:
deps-jar:
deps-j2ee-archive:
EnterpriseApplication-ejb.init:
EnterpriseApplication-ejb.deps-jar:
EnterpriseApplication-ejb.compile:
EnterpriseApplication-ejb.library-inclusion-in-manifest:

Building jar: D:\SVN\EnterpriseApplication\EnterpriseApplication-ejb\dist\EnterpriseApplication-ejb.jar

EnterpriseApplication-ejb.dist-ear:
EnterpriseApplication-war.init:
EnterpriseApplication-war.deps-module-jar:
EnterpriseApplication-war.deps-ear-jar:
EnterpriseApplication-ejb.init:
EnterpriseApplication-ejb.deps-jar:
EnterpriseApplication-ejb.compile:
EnterpriseApplication-ejb.library-inclusion-in-manifest:
EnterpriseApplication-ejb.dist-ear:
EnterpriseApplication-war.deps-jar:
EnterpriseApplication-war.library-inclusion-in-archive:
EnterpriseApplication-war.library-inclusion-in-manifest:
EnterpriseApplication-war.compile:
EnterpriseApplication-war.compile-jsps:
EnterpriseApplication-war.do-ear-dist:

Building jar: D:\SVN\EnterpriseApplication\EnterpriseApplication-war\dist\EnterpriseApplication-war.war

EnterpriseApplication-war.dist-ear:
pre-pre-compile:
pre-compile:
Copying 1 file to D:\SVN\EnterpriseApplication\build
Copying 1 file to D:\SVN\EnterpriseApplication\build
do-compile:
post-compile:
compile:
pre-dist:
do-dist-without-manifest:
do-dist-with-manifest:

Building jar: D:\SVN\EnterpriseApplication\dist\EnterpriseApplication.ear

post-dist:
dist:
BUILD SUCCESSFUL (total time: 1 second)

ここでは、Netbeansが最初にJarを準備し、次にWarを準備し、最後にjarとwarを含むearファイルを準備することがわかります。 各jar、war、およびearファイルには、 meta-inf フォルダーが含まれており、J2EE仕様に従ってメタデータを保持しています。