レベル: 中級 馬場 剛, WebSphereテクニカル・セールス,
IBM
2003年 12月 22日 EJB開発に携わる際に必要な理屈と手順を詳しく説明します。実際に自分の手で作って動かせて、応用の利く情報を連載します。第2回はCMPを作ってみます。
はじめに
前回の記事はいかがでしたか?
説明ばかりでちょっと退屈だったかもしれませんが、これからの記事を理解してアプリケーションを作成していくのに必要な知識です。忘れてしまった方は適宜復習しておいて下さいね。
さて今回は、前回お約束しました通り、CMP Beanを作って動かしてみましょう。
まずはテスト環境を作りましょう
まずは作るための環境を構成しましょう。
前回の記事を書き終えてからWebSphere StudioとDB2 Universal DatabaseとOracle 9i Databaseでいろいろ試していたのですが、どの組み合わせでもきちんと動きそうなところまで確認できました。そこで、WebSphereとDB2を組み合わせる方法は弊社のWebサイトやマニュアルのあちこちにありますので、今回はWebSphere
Studio Application Developer V5.1(以下WebSphere Studioまたは単にStudio)とOracle
9i Database(9.2.0.3)(以下Oracle 9iまたは単にOracle)の組み合わせでアプリケーションを作っていこうと思います。
とはいえ、DBMSが何であるかを意識するのはデータ・ソースを作成するところまでで、あとはDBMSを気にする必要はありません。これを書いている今の時点では連載の1~2回先で使用するアプリケーションを作成しているのですが、実際、DBMSが何であったかはすでに忘却の彼方となっています。このように、バックエンドの仕組みを隠蔽・抽象化し、意識せずに利用できるのがJDBCなりJ2EEのいいところなんですよね。
そうそう、StudioはInterim Fixが001から003までリリースされています。これも適用しておきましょう。Studioのインストール後、FixをWebSphere Studio Application Developerのサポートページ(US)より入手し、適用して下さい。
Oracle
9iのインストール
OracleのインストールはUniversal Installerの指示に従うだけですので、細かい説明は必要ないと思います。SID
(※) だけはあとでJDBCの設定に使用しますので、どんな名前をつけたか記録しておいて下さい。
これからの記事では、インストール・パスはデフォルト(C:\oracle\ora92)を仮定します。何かの都合でインストール・パスを変更した場合は、適宜読み替えて下さい。
(※) 私はSIDにwebsphereとつけたかったのですが、SIDは8文字以内なのでwebspherになってしまいました。ちょっとなさけないのですが、データソースのJNDI名をjdbc/websphereにしてしまえばSIDのことは忘れてよいのでがまんがまん。
|
WebSphere
Studioのインストール
こちらもウィザードに従うだけです。特に難しい点はないと思います。
WebSphere
Studioの起動
インストールが済んだらWebSphere Studioを起動します。
スタート -> プログラム -> WebSphere Studio -> Application Developer
5.1を選択すればOKです。
Interim Fixの適用もここで行っておくとよいでしょう。
プロジェクトの作成
「さぁて、いよいよEJBを作るぞー」といきたいところですが、まずはこれから作成するアプリケーションの入れ物となるプロジェクトを作成しておきます。
エンタープライズ・アプリケーションを作成し、その中にEJBプロジェクトとWebプロジェクトを一つずつ作ります。以下の手順に従って下さい。
1. エンタープライズ・アプリケーション・プロジェクトの作成
J2EE階層ビュー エンタープライズ・アプリケーション・プロジェクト

上の図を参考にして「エンタープライズ・アプリケーション」を右クリックし、「エンタープライズ・アプリケーション・プロジェクト」を選択して下さい。
「J2EEの仕様バージョン」はJ2EE 1.3です。プロジェクト名は何でもいいのですが、ここではWSDDdemoとしておきます。「EARモジュール・プロジェクト」は何も選択せずに「終了」をクリックします。
J2EE階層ツリーの「エンタープライズ・アプリケーション」を展開し、WSDDdemoプロジェクトが表示されていればOKです。
2. EJBプロジェクトの作成
1.で作成したエンタープライズ・アプリケーション・プロジェクトの中に、EJBプロジェクトを作成します。WSDDdemoプロジェクトを右クリックして、「新規」
-> 「EJBプロジェクト」を選択します。
「EJBのバージョンの選択」は2.0です。
プロジェクト名はWSDDdemoEJBとしましょう。「EARプロジェクト」に、1.で作成したWSDDdemoプロジェクトを選択するのを忘れないようにして下さい。
「モジュール依存関係」はそのままで「終了」をクリックします。
新規EJBプロジェクト

3. 動的Webプロジェクトの作成
WSDDdemoプロジェクトを右クリックして、「新規」 -> 「動的Webプロジェクト」を選択します。
プロジェクト名はWSDDdemoWebとしましょう。「J2EE設定ページ」「フィーチャー・ページ」はそのままで「次へ」をクリックします。「Webサイトのページ・テンプレートの選択」もそのままで「終了」をクリックします。
これで今回の記事で使用するプロジェクトがすべて作成されました。
何を作ろうかな?
さて、どんなCMP Beanを作るかですが、今回はOracleのサンプル・データベースのEMP表を用いて、社員検索システムを作ってみようと思います。
まずはSQL Plusを使って、どんな表かを確認してみましょう。スタート -> プログラム -> Oracle-OraHome92
-> Application Development -> SQL Plusで起動できます。ユーザー名はscott、パスワードはtigerです。SQL>
プロンプトが現れたら、次のSQL文を入力します。
select * from emp;
EMPNO(社員番号)、ENAME(社員氏名)、JOB(職種)、MGR(所属長社員番号)、HIREDATE(採用日)、SAL(給与)、COMM(コミッション)、DEPTNO(部門番号)の8列が定義された社員リストが表示されましたね。
まずはこの表にアクセスするCMP Beanを作成し、そのEJBに対してセッションBeanを経由してサーブレットからアクセスし、検索と結果の表示を行うことにしましょう。
社員検索システム作成の構成図

このアーキテクチャーを絵にしたものが上の図です。
ようやくCMP
Beanを作る
さて、ようやく最初のEJB、CMPエンティティーBeanを作成します。
プロジェクト・ナビゲーター・ビューに切り替えてから、WSDDdemoEJBプロジェクトを展開します。ejbModuleを右クリックして「新規」
-> 「パッケージ」を選択します。
プロジェクト・ナビゲーター・ビュー

パッケージ名はcom.ibm.wsdd.ejb.cmpとしましょう。
パッケージができたら、いよいよCMP Beanの作成開始です。
J2EE階層ビュー(「プロジェクト・ナビゲーター」タブの隣のタブをクリック)に戻り、WSDDdemoEJBプロジェクトを展開します。Entity
Beanを右クリックして「新規」 -> 「CMP Bean」を選択します。「EJBプロジェクト」はWSDDdemoEJBです。「2.0
Enterprise Beanの作成」では、「コンテナー管理パーシスタンス(CMP)フィールドをもつEntity Bean」「CMP
2.0 Bean」を選択します。
Bean名はEmpとし、デフォルト・パッケージにはブラウズボタンをクリックして、先ほど作成したcom.ibm.wsdd.ejb.cmpを選択しましょう。
パッケージの選択

次ページ「Enterprise Beanの詳細」では「CMP属性」以外の項目はそのままでOKです。ローカル・クライアント・ビューとリモート・クライアント・ビューについては後で説明します。
CMP属性については前回の記事で説明しました。「エンティティーBeanのフィールド変数(CMP Beanの場合はCMPフィールド(またはCMP属性))=データベースの表のカラム」でしたね。ということは、ここでCMP属性に、先ほどSQL
Plusで確認しておいたデータベースの表のカラムを設定することになるわけです。
SQL Plusから
desc emp;
として各カラムの型を調べておきましょう。また、
select * from user_cons_columns where table_name=’EMP’;
として、キーとなっている列(CMPのキー・フィールドとなる)を調べておきましょう。EMPNOが主キー、DEPTNOが外部キーであることが確認できると思います。
Studioに戻ります。CMP属性の欄の「追加」をクリックします。
データベースの最初のカラムはEMPNO(社員番号)でしたので、名前にempNoと入力します。DB上の型はNUMBER(4)ですので、対応するJavaの型としてintを選びます。社員番号EMPNOは主キーでしたので「キー・フィールド」にチェックを入れて「適用」をクリックします。これで社員番号を表すCMPフィールドを一つ定義することができました。
CMP属性の作成

EMP表のカラムは他に7つあったはずです。これらを表すCMPフィールドを続けて定義していきます。下の表に従って定義を進めて下さい。
| 名前 | 型 | キー・フィールド |
|---|
| empNo | int | チェックする |
|---|
| eName | java.lang.String | |
|---|
| job | java.lang.String | |
|---|
| mgr | int | |
|---|
| hireDate | ava.util.Date | |
|---|
| sal | int | |
|---|
| comm | int | |
|---|
| deptNo | int | |
|---|
上の表にないパラメーターはデフォルトのままでOKです。また、java.util.Dateはプルダウン・メニューにありませんので、直接入力するか「ブラウズ」ボタンをクリックして検索します。すべてのフィールドを作成し終わったら、「閉じる」「次へ」の順にクリックします。「EJB
Javaクラスの詳細」ではそのまま「終了」をクリックします。
ローカル・クライアント・ビューとリモート・クライアント・ビュー
先ほど、あとで説明しますと書きました、「ローカル・クライアント・ビュー」と「リモート・クライアント・ビュー」についての説明をここでしておきましょう。
いよいよEJBを作る!

「いよいよEJBを作る!(上図)」の拡大図 (PDF:43KB)
「ローカル」や「リモート」というのは、EJBの呼び出し元(EJBクライアント、今回のアプリケーションでは後で作成するセッションBean)から見て、呼び出し先のEJBが同一のJVM内にあるか別のJVM内にあるかの違いを表しています。
リモート呼び出しの場合、EJBにパラメーターを渡すには、渡すパラメーターの複製を作り、それをネットワークに載せて送る必要があります。Javaのオブジェクトをネットワークに載せたりDBに書き出したりするには、オブジェクトのSerialize(直列化)が必要です。受け取った側でもSerializeされたオブジェクトを元に戻すDe-serializeが必要です。このSerialize/De-serializeはCPUから見て重い処理であるため、頻繁に発生するとパフォーマンスの低下を引き起こします。以前のEJB
1.xではリモート呼び出ししかなかったため、実際に別のJVM上のEJBを呼び出すときはもちろん、同じJVM上で稼動するEJBを呼び出す時にもリモート呼び出しを行っていました。これが以前、「EJBは重くて使いものにならない」と言われた理由の一つです。
ローカル・クライアント・ビューとリモート・クライアント・ビュー

「ローカル・クライアント・ビューとリモート・クライアント・ビュー(上図)」の拡大図 (PDF:53KB)
EJB 2.0で新しく導入されたローカル呼び出しではEJBにパラメーターを渡すのに、複製した実体を渡す代わりに参照(リファレンス)だけを渡すことにしています。これによって、オブジェクトの複製とSerialize/De-serializeにかかるパフォーマンスの低下がなくなり、リモート呼び出しと比較して高速に処理を行うことができるようになりました。もちろん、異なるJVM上のEJBを呼び出す際は、従来通りリモート呼び出しを使用します。
前回の記事で、リモート呼び出しの際にはホーム・インターフェースとリモート・インターフェースが使用されることを説明しました。ローカル呼び出しの場合はそれぞれ、ローカル・ホーム・インターフェース(命名はXXXLocalHome.java(.class))とローカル・インターフェース(XXXLocal.java(.class))を使用することになります。
で、何ができたの?
さて、ウィザードに従って作業を行って確かにEmp CMP Beanができたわけですが、実際、プロジェクト内には何が生成されたのでしょうか?一般ユーザーであればとっとと次へ進みたいところですが、これを読んで下さっている方々の多くは開発者、ディベロッパーであるはずです(何たって、WebSphere
Developer Domainの記事ですから)。どこに何ができたのか、きちんと確認しておくことにしましょう。
J2EE階層ビューでWSDDdemoEJB-Entity Beanの下にできたEmpを展開します。
マークのついているのがCMPフィールドです。
empNoには鍵のマークがついていますが、これはキー・フィールドですね。
その下にはローカル・ホーム・インターフェースEmpLocalHome、ローカル・インターフェースEmpLocal、エンタープライズBeanのEmpBean、そしてプライマリ・キー・クラスのEmpKeyが生成されています。
プライマリ・キー・クラスとはEJBコンテナーがプライマリ・キーを管理する際に使用されるもので、hashCode()とequals()を実装するようにEJB
2.0仕様で規定されています。
EmpKeyをダブルクリックして内容を見てみると、int型の社員番号を引数に取るコンストラクターがあることがわかります。

エンタープライズBeanの中を見る
EmpBeanの内容も同様に見てみましょう。
パッケージ宣言に続いて冒頭のクラス宣言です。
public abstract class EmpBean implements javax.ejb.EntityBean
となっており、ここで生成されたEmpBeanは抽象クラスであることがわかります。実装クラス(デプロイメント・コード)を生成させる作業は後で行います。
先頭から3つのメソッド、setEntityContext(), getEntityContext(), unsetEntityContext()は名前の通り、エンティティーBeanのランタイム・コンテキストを取り扱うものです。続いてejbCreate()からejbStore()までのライフサイクル・メソッド
(※) が並んでいます。その後に続くsetXXX()やgetXXX()は、先に定義したCMPフィールドに対するアクセサ・メソッドです。これも名前を見ると、何をするメソッドかは見当がつきますね。アクセサも抽象メソッドになっており、ここには実装はありません。
アクセサが抽象メソッドということは、アクセス対象のCMPフィールドも、ここではなくどこか別のところで宣言されているはず・・・、と気づいたあなたは鋭いですね。確かにEmpBeanのコードにはCMPフィールドの宣言がありません。
(※) EJBのライフサイクルについては、次回以降の記事で取り扱う・・・かもしれません。
|
EJB-DDの中を見る
では、J2EE階層ビューでキー・フィールドのempNoをダブルクリックしてみましょう。「EJBデプロイメント・ディスクリプター」というタイトルのウィンドウが開きます。
これはStudioの便利な機能の一つで、各種のデプロイメント・ディスクリプター(DD)をGUIで編集できるDDエディターです。DDはxml形式のファイルですが、DDエディターを使用すると内容をGUIで直感的に確認・編集することができます。ここで開いたのはEJBのDDであるejb-jar.xmlです。
左側のBeanリストではEmpが選択されており、右側のCMPフィールド・リストでは先に定義したCMPフィールドが表示されています。つまり、EJB
2.0ではCMPフィールドはEJB-DD内で定義されているわけです。
Bean 内容の確認

「ソース」タブをクリックすると、実際のejb-jar.xmlの内容を確認することができます。確かに<cmp-field>タグに囲まれてCMPフィールドが定義されています。ただ、フィールドの型は定義されていません。EmpBeanのコード内で、アクセサ・メソッドの引数や戻り値の型として示されています。
ローカル・ホーム・インターフェースとローカル・インターフェースの中も見る
同様にして、EmpLocalHomeとEmpLocalの内容も確認しておきましょう。
EmpLocalHomeではcreate()とfindByPrimaryKey()が定義されています。create()は新しいEJBインスタンスを作成します。findByPrimaryKey()は既存のEJBインスタンスを、プライマリ・キーを引数にして検索します。
EmpLocalにはEmpBeanと同じメソッドが書かれています。ただし、EmpBeanにあったメソッドのうち、エンティティー・コンテキストとライフサイクルに関するものは入っていません。これらのメソッドはEJBコンテナが使用するもので、EJBクライアントから呼び出す必要はないからです。
結果、EmpLocalにはキー・フィールドを除くCMPフィールドのアクセサ・メソッドだけが残っています。これはCMPフィールドを定義した際に「ローカル・インターフェースへのgetterメソッドとsetterメソッドのプロモート」にデフォルトでチェックが入っていたためです。
CMP属性

CMP
Beanとデータベースをマッピングする
さて、説明が長くなりました。そろそろ退屈する人も多そうなので、EJB作成の続きを行います。
ここまでのウィザードを使った作業で、EJBそのものはほぼ完成しています。あとはCMPフィールドとデータベースの表のカラムをマッピングし、デプロイメント・コードを生成すれば動かせる状態になるはずです。
マッピングを始めるには、J2EE階層ビューでWSDDdemoEJBを右クリックし「生成」 -> 「EJBからRDBへのマッピング」を選択します。まずはDBへ接続するための情報をウィザードで設定していきます。
「EJBからRDBへのマッピング」ではそのままで「次へ」をクリックします。DBへの接続を行うのは初めてなので、新規のバックエンド・フォルダーを作成します。
「新規EJB/RDBマッピングの作成」では "Meet-In-The-Middle" を選択して「次へ」をクリックします。このページで何を行ったのかについては、後で説明します。
「データベース接続」では、図のように (※) 入力します。接続名はここではwebsphereとしていますが、何でも構いません。パスワードはtigerですね。クラス・ロケーションも図では切れてしまっているので書いておきますと、
C:\oracle\ora92\jdbc\lib\classes\classes12.zipです。デフォルトでこのようになっているはずですが、インストール・パスを変更した場合には適切に書き換えて下さい。
データベース接続

「データベースの選択インポート」では、スキーマSCOTTのSCOTT.EMP表だけにチェックを入れて「次へ」をクリックします。
「Meet-In-The-Middleマッピング・オプションの選択」では「なし」を選択して「終了」をクリックします。これでマッピング・エディターが開いて、CMPフィールドとデータベースのカラムをマッピングするための準備ができました。
マッピング・エディター内で、Enterprise BeanビューのEmp Beanと、テーブル・ビューのEMP表をそれぞれ展開します。CMPフィールドと表のカラムがそれぞれ表示されます。ここでEmp
Beanをクリックして選択し、EMP表を右クリックして「名前で突き合わせ」を選択します。
マッピング・エディター

Enterprise BeanビューのCMPフィールドとテーブル・ビューのカラム名にそれぞれ青と赤の小さな矢印がつきます。この矢印はCMPフィールドやDB表のカラムがマッピングされていることを表します。どのフィールドとどのカラムがマッピングされているかは、その下の概要ビューで確認できます。ここで左右に並んでいるフィールドとカラムがマッピングされています。
すべてのフィールドとカラムが正しくマッピングされていることが確認できたらCtrl+Sを押して、マッピング結果を保存します。マッピング・エディターは閉じても構いません。
(※) ここで「データベース」の欄に入力しているのが8文字制限のためにwebspherになってしまったSID名です。もうしばらくこれでがまん・・・。
|
CMPとDBのマッピング・アプローチ
さて、「新規EJB/RDBマッピング」で "Meet-In-The-Middle" を選んで作業を行いましたが、これはいったい何のことだったのでしょうか?
他に「ボトムアップ」「トップダウン」があってあわせて3種類のマッピング・アプローチですが、これはこのようなことを意味しています。
CMPフィールドとDBのマッピング
ボトムアップ・アプローチはパーシスタントとして使用したいDBの表が先にある場合に、エンティティーBeanに表の各カラムを表現するフィールドを自動的に生成してくれます。
トップダウン・アプローチはその逆で、既存のエンティティーBeanのフィールドを表すカラムを持つDB表のスキーマを自動的に作成してくれます。スキーマをDBMSに与えて表を作成すれば、それをパーシスタントとして使用できるわけです。
今回採用したMeet-In-The-Middleアプローチはこれらの中間、つまり、既存のエンティティーBeanのフィールドと既存のDB表のカラムを一つ一つ手動でマッピング
(※) していく方法です。
え?「だったら、今回はDBが先に存在したんだから、ボトムアップでCMP Beanを自動生成すれば早かったんじゃないの?」ですって?
確かにおっしゃる通りなのですが、ではなぜMeet-In-The-Middleを使ったかというと、私が個人的に他のマッピング・アプローチが嫌いだからです。もちろん、嫌いなのには理由があります。
(※) 「名前で」または「名前と型で」自動的にマッピングを作成させることはできます。
|
やってることは一緒でも、「自動的」だったり「勝手」だったり・・・?
例えば、Oracle DB上の社員番号EMPNOはNUMBER(4)型で、これとマップされるCMPフィールドempNoを作成した際には型をintとしました。アプリケーション作成者が、NUMBER(4)型は小数部を持たず、社員番号は「自然数(正の整数)」であることを知っていて、適切な型を割り当てたわけです。
ところが、もともとのOracleのNUMBER型の定義 (※1) は「実数」です。では、ボトムアップ・アプローチを使用してEMPNOを表すCMPフィールドを自動生成した場合、そのフィールドのJavaの型は何になるのでしょうか?
・・・私も知りませんので実験してみますと、なんとjava.math.BigDecimal型になりました。ちなみに他のOracleデータ型に対するCMPフィールドの型はどうなったかといいますと、VARCHAR2はjava.lang.Stringに(これはまぁいいでしょう)、DATEはjava.sql.Dateになりました。NUMBER型のカラムはNUMBER(4)のEMPNOの他にNUMBER(7,2)のSALがあるのですが、これもjava.math.BigDecimalとなりました。
実験の結果、ボトムアップ・アプローチを使用すると、DB表のいくつかのカラムが思わぬJava型のフィールドにマップされました。が、このように「やってみないと挙動がわからないものを作る」「自分の知らないうちに勝手に型変換が発生している」のって、開発者としてはとても気持ち悪くありませんか?ある程度のプログラミング(Javaに限らず)経験をお持ちの方であれば、暗黙的型変換の結果、思わぬバグが発生し、そのバグを発見するのがまた大変だった思い出がきっとあるのではないかと思います。
もちろん、暗黙的型変換も「わかっていて」使う分には便利なこともあります 。ですが、ボトムアップ・アプローチを使用した時に、どのDBMSのどのデータ型がJavaのどの型にマップされるかなどは、J2EE仕様やEJB仕様のどこにも書いてありません(IDEの機能ですから当たり前です)。つまり、何の保証をされた動作でもないのです。
以上はボトムアップのお話ですが、トップダウンでも同様の問題が発生するはずです。
これが、私がMeet-In-The-Middle以外のマッピング・アプローチを嫌いである理由です。
Javaに限らずプログラムを書く時、データベースの設計・運用をする時には、変数・引き数・戻り値の型、オブジェクト指向言語であればオブジェクトの型
(※2) 、DBの各カラムのデータ型が何であるかを常に意識し、注意を払うことは、キャストに伴うバグの発生を未然に防ぐ上で大切なことだと思います。
さらに横道に逸れますが、エンジニアたる者、「自動的に」という説明を読んだら「勝手に」と読み替えて、その裏で何が起こるのかを確認する心構えが必要だと思います。「自動的に」
(※3) というのはとても耳あたりのよい言葉ではあるのですが、お客様に「自動的に」とご説明する時には、裏で何が起こるのかを必要な範囲で理解してからするべきだと思うのですが、いかがでしょうか・・・?
|
(※1) 詳しくは下のPDFの121ページ(ガイドの3-9ページ)をご参照下さい。
Oracle9/アプリケーション開発者ガイド -基礎編-
- この手の「とりあえず動くけど結果がおかしい」バグって一般に面倒ですよね。「いっそエラー吐いてくれ~」とよく思いました・・・。
- 厳密にはNUMBER(4)とintのマッピングも型変換が発生するはずですが、もちろん、今回は挙動をわかった上でこのようにしています。
(※2) この議論を始めると「そもそも(オブジェクト指向言語の)Javaでプリミティブ型ってどうよ?」という話になったりするのですが、それはそれで便利なので私はためらわず使っています。
(※3) 類義語として「簡単に」があります。「自動的に」「簡単に」が頻繁に出てくる資料や説明は、個人的には怪しいと思っています。 |
デプロイメント・コードの生成
さて、青^H成年の主張 (※1) はこのくらいにして、いよいよデプロイメント・コードの生成です。この作業でEJBの作成は完了です。
作業そのものはとても簡単です。J2EE階層ビューでEmpを右クリックし、「デプロイメント・コードの生成」を選択するだけです。
何が生成されたのか気になりますか?気になる方はJ2EE階層ビューからプロジェクト・ナビゲーター・ビューに切り替えて、WSDDdemoEJB
- ejbModule - com.ibm.wsdd.ejb.cmp以下のパッケージ(3つあります)内の新しくできた*.javaファイルを読んでみて下さい。
ここではデプロイメント・コードの詳しい説明はしませんが、一つだけ、パッケージcom.ibm.wsdd.ejb.cmp.websphere_deploy.ORACLE_V9_1内のEmpBeanFunctionSet_xxxxxxxxx.javaを開いてみましょう。例えば20行目
(※2) 、Create()メソッド内にprepareStatementがあり、INSERT文が書かれているのがわかります。前回の記事で、CMP
Beanのインスタンスを新しく作るとデータベースに1行挿入されることを説明しましたが、まさにそのためのコードが生成されたわけです。同様にRemove()メソッド内の133行目にはDELETE文が、findByPrimaryKey()メソッド内の441行目にはSELECT文があります。
このようにCMP BeanではDBMSに応じたSQL文を自動的に生成することにより、アプリケーション開発者からDBMSの差異を隠蔽してくれるのです。もちろん、DB2を使用していればDB2用のSQL文が生成されます。従って、JDBC
2.0に対応したDBMSを使用する限り、CMP Beanから見ればDBMSは何でもいいわけです。
(※1) 「青年」というには厳しい歳なもので・・・。
(※2) Javaエディターに行番号を表示させるには、Studioのメニュー・バーからウィンドウ -> 設定を選択し、ナビゲーション・ペインでJava
-> エディターを選択します。右側のプロパティー・エディターで「行番号を表示」にチェックを入れ、OKボタンをクリックします。
|
いよいよ動かすぞ~の前にテスト・サーバーの設定
さて、これでCMP Beanそのものは完成です。
あとは作ったEJBを動かしてテストするために、テスト・サーバーの設定を行います。
WebSphere Studioは単体テスト用のサーバーを内蔵しているため、作ったらすぐその場でテストを行うことができます。別にテスト用のサーバー環境を構築しておく必要はありません。
また、EJBはサーバーサイドのコンポーネントですので、テストを行うためには通常はテスト用のクライアントも開発者が作成する必要があります。ところが、WebSphere
Studioでは汎用テスト・クライアントを内蔵しているため、テスト用のクライアントを書く必要がありません。
このため、WebSphere StudioでEJBのテストを行うのは非常に簡単です。お客様からもご評価の高い機能の一つです。
サーバーとサーバー構成を作成する
ではさっそく、テスト用のサーバーとサーバー構成を作成しましょう。
J2EE階層ビューで、「サーバー」を右クリックして「新規」 -> 「サーバーとサーバー構成」を選択します。
J2EE階層ビュー サーバーとサーバー構成
サーバー名はWSDDdemoServerとしましょう。サーバー型は「テスト環境」を選択し「次へ」をクリックします。デフォルト・ポートは9080のままでOKです。
「終了」をクリックします。
J2EE階層ビューでサーバーを展開すると、いま作成したWSDDdemoServerが現れます。WSDDdemoServerを右クリックして「プロジェクトの追加と除去」を選択します。使用可能なプロジェクトからWSDDdemoを選択して「追加」をクリックし、続けて「終了」をクリックします。これでWSDDdemoエンタープライズ・アプリケーションがWSDDdemoServerに公開されるようになります。
JDBCプロバイダーとデータ・ソースを作成する
次に、EJBからデータベースにアクセスするために、データ・ソースを作成します。
このデータ・ソースを使用することにより実際のDBMSが何であるかを問わず、同じ取り扱いでEJBの作成や実行が可能になるわけです。
まずはOracle 9iの提供するJDBCドライバの場所を設定します。
J2EE階層ビューでWSDDdemoServerをダブルクリックします。サーバーのプロパティー・エディターが開きますので「変数」タブをクリックします。ノード設定内の「定義済み変数」表からORACLE_JDBC_DRIVER_PATHを選択し「編集」をクリックします。ポップアップの「値」の欄にC:/oracle/ora92/jdbc/libと入力してOKをクリックします。
置換変数 ノード設定
次に、データベースへアクセスする際のユーザー名とパスワードを設定します。
「セキュリティー」タブをクリックします。「JAAS認証エントリー」の右隣の「追加」をクリックします。別名とユーザーIDの両方にscott、パスワードにtigerを入力してOKをクリックします。
次にJDBCプロバイダーの設定を行います。
「データ・ソース」タブをクリックします。JDBCプロバイダーにはデフォルトでCloudscape用とDB2用のものが設定されています。ここにOracle
9i用のJDBCプロバイダーを追加します。JDBCプロバイダー・リストの右隣の「追加」をクリックします。
データ・ソース サーバー設定
「データベース・タイプ」からOracleを選択します。「JDBCプロバイダー・タイプ」からOracle JDBC Driverを選択して「次へ」をクリックします。
名前はOracle JDBC Providerとしておきましょう。実装クラス名はデフォルトのままでOKです。クラス・パスにnls_charset12.zipを追加
(※1) します。「パスの追加」をクリックし、ポップアップ・ウィンドウに
${ORACLE_JDBC_DRIVER_PATH}/nls_charset12.zipと入力してOKをクリックします。JDBCプロバイダーの作成ウィンドウに戻りますので「終了」をクリックします。
次に、データ・ソースの追加を行います。
いま作成したOracle JDBC Driverをクリックして選択し、「上で選択されたJDBCプロバイダーで定義されているデータ・ソース」の右隣の「追加」をクリックします。
データ・ソースの追加
「データ・ソースの作成」ではデフォルトのままで「次へ」をクリックします。
次の「データ・ソースの変更」では、名前にwebsphere、JNDI名にjdbc/websphereと入力します。コンテナー管理下認証別名でプルダウン・メニューを開き、先ほど作成したJAAS認証エントリーのscottを選択して「次へ」をクリックします。
データ・ソースの変更
「リソース・プロパティーの作成」ではリソース・プロパティーの一覧からURLを選択し、値にjdbc:oracle:thin:@localhost:1521:webspher(最後にeをつけないように注意)と入力して「終了」をクリックします。
これでデータ・ソースの作成は完了 (※2) です。Ctrl+Sを押して設定内容を保存します。プロパティー・エディターは閉じても構いません。
(※1) 今回使用するサンプル・データベースは英語のみですので、この作業は飛ばしても構いません。ですが、日本語を使用するデータベースの場合はこの作業を行わないと、データ・ソース経由で日本語を扱えなくなってしまいます。ここで作業を練習しておきましょう。
(※2) これでSID名8文字制限のために苦しめられたwebspherのことは忘れてOKです。
|
CMP接続ファクトリーの設定
さて、サーバー側でデータ・ソースの設定が完了しましたので、CMP Beanが作成したデータ・ソースを使用するように設定を行います。
J2EE階層ビューでEJBモジュールを展開し、WSDDdemoEJBをダブルクリックします。EJB-DDエディターが開きますので、Beanタブをクリックします。
左側のBean一覧(といってもBeanは一つしかありませんが)からEmpを選択します。右側のプロパティー・ペインを下へスクロールさせていくと「WebSphereバインディング」というセクションがあります。ここの「CMP接続ファクトリーJNDI名」に、先ほど作成しましたデータ・ソースのJNDI名、即ちjdbc/websphereを記入します。コンテナー許可型はプルダウン・メニューからContainerを選択して下さい。
Bean WebSphereバインディング
以上で、Emp BeanがOracle9i上のSID名 webspherのDBをパーシスタントとして使用するようになります。
Ctrl+Sを押して設定を保存します。EJB-DDエディターは閉じても構いません。
サーバーを開始する
サーバーを起動しましょう。
右下のウィンドウの「サーバー」タブをクリックします。WSDDdemoServerをクリックして選択し、人が走っている形をした「サーバーの開始」ボタンをクリックします。
自動的にプロジェクトとテスト・クライアントがサーバーに公開され、コンソール・ビューに切り替わります。サーバーの起動にはやや時間がかかります。コンソールの最下行に「e-businessのためにサーバーserver1がオープンされました」と表示されてスクロールが止まったら、テスト・サーバーの起動は完了です。
Emp
CMP Beanをテストする
では、いよいよEmp CMP Beanのテストです。
J2EE階層ビューでEJBモジュール -> WSDDdemoEJB -> Entity Beanの順に展開します。Empを右クリックして「サーバーで実行」を選択します。
J2EE階層ビュー サーバーで実行
「サーバーの選択」では「既存のサーバーを使用」「WSDDdemoServer 構成済み」が選択されていることを確認します。「サーバーをプロジェクト・デフォルトとして設定」をチェックしておくと、次回以降のテストの際に起動するサーバーを聞いてこなくなりますので、チェックしておきましょう。
「次へ」ボタンを押すと、デプロイ・コードの生成をいま行うかどうかの選択が出てきます。デプロイ・コードの生成は先ほど済ませましたので、チェックせずに「終了」をクリックします(チェックしてあっても構いません)。
テスト・クライアントが起動します。テスト・クライアントはウィンドウが小さいと使いづらいので、「テスト・クライアント」タブをダブルクリックして最大化しておきます。もう一度、「テスト・クライアント」タブをダブルクリックすると、元の表示に戻ります。
EJBのテストってどうやるんだろう・・・??
さて、テスト・クライアントは起動したものの、Emp CMP Beanのテストを行うにはどうすればよいのでしょう・・・?
ここで思い出していただきたいのが、前回の記事の最後近く、「EJBが動くまで」の節です。
EJBクライアントからEJBへの呼び出しを行うには、
- InitialContextを取得し、lookup()メソッドでHome(ローカル呼び出しの場合はLocalHome)インターフェースを検索して取得する。
- 入手したHome(またはLocalHome)インターフェースを使用して、create()で新規EJBインスタンスを作成したり、findByPrimaryKey()メソッドで既存のEJBインスタンスを検索したりする。同時に、EJBインスタンスに対応するRemote(ローカル呼び出しの場合はLocal)インターフェースを入手する。
- 2.で入手したRemote(またはLocal)インターフェースのメソッドをプロキシとして、エンタープライズBeanのメソッドを起動する。
のが大まかな手順でした。今回のEmp CMP Beanはローカル・クライアント・ビューのみを持ちますので、1.ではLocalHomeインターフェースを、2.と3.ではLocalインターフェースを使用します。
この1.~3.の操作を、テスト・クライアントから行ってやればよいわけです。ただし、テスト・クライアントの起動を前の節の方法で行った場合は、1.のHome(またはLocalHome)インターフェースはすでに取得されており、テスト・クライアント上に表示されています。
ようやくEJBのテスト本番!
では、おさらいが終わったところでテストを始めます。
まずはテスト・クライアントの「参照」ビューでEJB参照 -> EmpLocalの順に展開します。EmpLocalHomeが現れましたか?さらにEmpLocalHomeを展開すると、create(),
findByPrimaryKey(), remove()の3つのメソッドが現れます。
今回は「社員検索システム」を作ることにしたはずですので、findByPrimaryKey()を使用して (※1) 社員を表現するCMP
Beanインスタンスを検索 (※2) します。
findByPrimaryKey(EmpKey)をクリックすると、右側のパラメーター・ペインに引数のEmpKeyを生成するためのツールが表示されます。キー・クラスEmpKeyはコンストラクターにint型の社員番号を取るようになっていましたね。ですので「コンストラクター」メニューをプルダウンして、EmpKey(int)を選択します。
テスト・クライアント
「パラメーター」欄のEmpKey:の左側にある+マークをクリックします。Constructor: EmpKey: が現れますので、その左側の+マークもクリックします。すると、値が0に設定されているパラメーターintが現れます。
ここに検索したい社員番号を入力します。EMP表にどんな社員番号が載っていたか忘れてしまった方はSQL Plusから確認しておきましょう。例えば、SCOTTの社員番号7788を入力して、起動ボタンを押してみます。
起動ボタンの下にEmpLocalが表示されたでしょうか。これでEmpLocalHomeのfindByPrimaryKey()を用いて、プライマリ・キー(社員番号)が7788であるEmpBeanのインスタンスが検索され、そのインスタンスに対応するEmpLocalを取得することができました。
次はこのEmpBeanのインスタンスをテストしますので、取得したEmpLocalを使用します。ですので、結果の下にある「オブジェクトの使用」ボタンをクリックします。
パラメーター
すると左側の参照ビューに、いま検索してきたEmpLocalが追加されます。このインスタンスのgetEName()を起動すれば、社員番号7788の社員の名前、つまりSCOTTが返るはずです。String
getEName()をクリックし、パラメーター・ビューの起動ボタンを押してみましょう。
いかがですか?結果の欄にSCOTTが表示されましたか?
社員番号で検索
同様に、他のgetterメソッドも起動してみましょう。SQL Plusで確認したEMP表の、EMPNOが7788の行と同じ内容が返ってきましたね。
EmpLocalHomeのfindByPrimaryKey()を再び起動し、別の社員番号でもテストを行ってみましょう。また、存在しない社員番号で検索した場合、どのような例外がthrowされるかも見ておくとよいでしょう。
これで作成したCMP Beanのテストは成功です。社員検索システムの骨組みが出来上がりました。
(※1) 勘のよい方はお気づきかもしれません。create()はemp表に社員を追加、remove()は社員を削除するのに使用するわけですね。
(※2)つまり、DBから社員を表現する行を検索することになります。
|
こんな社員検索システムってアリ??
え、何ですか?「こんな社員検索システムは使い物にならない」?
そうですか?・・・そうですよねぇ。
何でって、普通は、
「社員の名前で検索したいに決まってるでしょ!」
はい、聞こえました。おっしゃる通りだと思います。そうですよねぇ・・・。
ということは、あとは何を作ればいいかというと、EmpLocalHomeにfindByEName()みたいなメソッドがあればできそうですね。
ということで、今回の記事はここまで、次回はEJBQLのお話に決定です。
では、次回の記事もお楽しみに!
参考文献
著者について  | |  | 馬場 剛, WebSphereテクニカル・セールス, IBM |
記事の評価
|