それなら、とJavaEE 5 SDKを使ってみることにした。
だって、各アプリケーションサーバのJNDIのセッティング方法を調べるのが面倒なんだもん!
#実際、プラットフォームがごちゃごちゃな環境では、各APサーバごとに管理方法が異なるため、厄介な話なのだ。
(注意事項)
2008/3/21現在、JavaEE 5 SDK Update 4 は、英語版のみです。
日本語を含めた多言語をサポートした最新バージョンはJava EE 5 SDK Update 3です。
以下のインストール手順はJavaEE 5 SDK Update 4のスナップショットです。
ダウンロードするときは、くれぐれも間違えないように。
1.前提
・JDK 1.6がインストールされていること。
・Windows環境であること。
2.ダウンロード
JavaEEのSDKは以下のリンクからダウンロードする。
※ダウンロードには、SunDeveloperCenterのユーザアカウントが必要です。
http://sdc.sun.co.jp/java/javaee/downloads/index.html
日本語対応の多言語版は、ページの下のほうにあるので、注意してください。
3.インストール
2.でダウンロードした、「java_ee_sdk-5_04-windows-nojdk.exe」を起動する。
Step1. Welcome
「Next」を押す

Step2. Agreement
「Yes」を選択して、「Next」を押す

Step3.インストールディレクトリの指定
例ではC:\Sun\SDKとしている。お好きなところで。

Step4.JDKインストールディレクトリの指定
JDKをインストールしたディレクトリを指定する

Step5. 管理用の設定
・管理者のユーザ名、パスワードを設定する。
・管理機能を呼び出すごとにユーザ名・パスワードを求められるのは面倒なので、
「Don't Prompt for Admin User Name and Password」を選択する。
・ポートはデフォルトのままにしておく。

Step6. インストールオプションの設定
- 「Upgrade from Previous Version」
- 前バージョンからの設定ファイルの移行は無いので、チェックを外す
- 「Enable Updatechecker Client」
- 勝手にバージョンチェックされるのも嫌なので、チェックを外す
- 「Create Desktop Shortcut to Autodeploy Directory」
- 便利だけど、これ以上デスクトップを汚したくないので、チェックを外す
- 「Add bin directory to PATH」
- パスは追加しておかないとね
- 「Create Windows Service」
- 手動でサーバ起動・停止を行うので、チェックは外しておく

Step7. インストール内容の確認
「Next」を押す

Step8. インストール中
しばし待たれよ

Step9. ユーザ登録
登録しておくとパッチの情報とか貰えるらしいけど、
ちょこっと使うだけなので、「Skip Registration」を選択する。

Step10. インストール完了
サーバの起動は別途手動で行うので、
ここでは「Finish」を押して、インストールを完了する。

----------[インストール完了]-----------------
(おまけ)
3'. アンインストール
「プログラムの追加と削除」から「Java Platform, Enterprise Edition 5 SDK」を選択して、削除する。
一部のディレクトリは削除されないので、手動で削除。
4.サーバを起動する
JavaEE5SDKをインストールすると、漏れなく
- Sun Java System Message Queue 4.1
- Sun Java System Application Server 9.1
Sun Java System Application Serverは、GlassFishをベースとしたAPサーバです。
IBMがGeronimoをベースとしてWAS-CEを作っているのと似ている。
今回使ってみて思ったけど、やっぱり標準サポートのSDKであり、日本語対応がされているという点は大きい。学習用にはもってこい。何よりJNDIの設定が簡単!
話が逸れましたが、サーバを起動するためには、
[スタートメニュー]→[Sun Microsystems]→[JavaEE SDK]→[Start Default Server]をクリックするか、
コマンドプロンプトにて、以下のコマンドを実行する。
asadmin start-domain
サーバが起動するので、ブラウザを使って管理コンソールにアクセスする。
URLは以下のとおり。
(インストール時に管理用コンソールのポートを別の番号にした場合は、そのポート番号を指定する)
http://localhost:4848/login.jsf

ユーザ名、パスワードは、インストール中に指定したものを入力する。
ログインすると、ユーザ登録がどうたら、と聞かれるので、
「Never Register」をクリックする。

で、いろいろとメニュー項目を眺めたりするんだけど、全部英語だYO!
まぁダウンロードするときにEnglishしか選べなかったので、わかっていたことですが。
そういえばJ2EE 1.4のSDKを使っていたときは日本語だったなぁ、と思い出して、調べたら多言語版があったよorz
というわけで、多言語版をインストールし直し・・・。
でもでも、日本語でConnectionFactoryを接続ファクトリと言われてもピンと来なくて、微妙だったりする(笑)
5.JMSの設定を行う
普通ならここでHelloWorld的なWebアプリケーションを作って終わるところだけど、
そんなこたぁ、どうでもいいんです!ルックアップがしたいのですよ!
まずは接続ファクトリの設定から。
管理コンソール画面の、左側にある共通操作ペインから、[リソース]→[JMSリソース]→[接続ファクトリ]を選択して、「新しいJMS接続ファクトリ」作成画面を開く。

「JNDI名」を「jms/QueueConnectionFactory」とする。
「リソースタイプ」を「javax.jms.QueueConnectionFactory」とする。
他の設定はデフォルトのまま、「了解」ボタンを押して登録する。
なんて簡単なんだ!
続いて、キューの設定を行う。
先ほどと同様に、管理画面左側のペインから、
[リソース]→[JMSリソース]→[接続リソース]を選択して、「新しい接続先リソース」作成画面を開く。
「JNDI名」は「jms/MyQueue」とする。
「物理送信先名」は「MyQueue」とする。(これは送信先リソースのNameプロパティの値になる)
「リソースタイプ」は「javax.jms.Queue」とする。
続いて、キューを作成する。
ここでの操作は、Sun Java System Message Queue 4.1に反映される。
今度は[構成]→[Javaメッセージサービス]→[JMSホスト]→[物理送信先]を選択する。
「新規」ボタンを押して、以下の設定でキューを作成する。
名前:MyQueue
タイプ:javax.jms.Queue
6.ルックアップを行う
スタンドアロンのアプリからメッセージをputしたい。
やり方は2つ。
まず1つ目は、JMSプロバイダが提供する接続ファクトリとキューを生成して、
宛先名やらキュー名やらを設定する方法。
2つ目は、JNDIでConnectionFactoryとQueueをルックアップして取得する方法がある。
1つ目の方法だと、JMSプロバイダガ提供する独自のクラスを生成する必要があり、
ソースコードの移植性が落ちる。
そこで2つ目の方法を使う。
JNDIを使うためには、まずInitialContextに環境定義を渡す必要がある。
InitialContextのAPIを見ると分かるが、やり方は
- プロパティを渡す
- jndi.propertiesファイルに設定しておく
APサーバ上で実行されるAP(Webアプリケーション等)は、APサーバが環境定義を把握しているので、勝手にプロパティを読み込まれる。そのため、AP実装時に、InitialContextのコンストラクタに引数を渡す必要がない。
では、APサーバ上で実行しないAPはどうなるのか。
この場合、自前でプロパティを渡すしかない。
つまり、ソースコードにプロパティを記述して、それをInitialContextのコンストラクタ引数に渡すか、
クラスパス上にjndi.propertiesファイルを作成するか、だ。
以下、Sun Java Application Server上で、先ほど設定したQueueConnectionFactoryをJNDIで取得するためのサンプルだ。
import java.util.Properties;
import javax.jms.Queue;
import javax.jms.QueueConnectionFactory;
import javax.naming.Context;
import javax.naming.InitialContext;
public class JmsSender {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.enterprise.naming.SerialInitContextFactory");
InitialContext context = new InitialContext(props);
System.out.println("context ok");
QueueConnectionFactory factory = (QueueConnectionFactory)context.lookup("jms/QueueConnectionFactory");
System.out.println("factory ok");
Queue queue = (Queue)context.lookup("jms/MyQueue");
System.out.println("queue ok");
}
}
Propertiesを生成して、値を自前で設定している。
put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.enterprise.naming.SerialInitContextFactory");
Context.INITIAL_CONTEXT_FACTORYは、実際には「java.naming.factory.initial」という値である。
したがって、jndi.propertiesファイルを用意する場合は、
java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory
という定義を記述すればよい。これでソースファイルの環境依存性が無くなる。
ただし、厄介なのがこのプロパティ。今回は、「com.sun.enterprise.naming.SerialInitContextFactory」というコンテキストファクトリを指定したが、
これは今回に限った話で、JNDIプロバイダが異なれば、設定が変わってくる。
しかも、どの値を設定していいのか、よく分からない。
実は、「com.sun.enterprise.naming.SerialInitContextFactory」という値を取得するために、
一度、Webアプリケーションを作成して、その上でInitialContextを生成して、
そこから環境定義を取得している。
これによってInitialContextの実体クラスを把握できたのだ。
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
Context context = null;
PrintWriter pw = res.getWriter();
context = new InitialContext();
pw.println("get InitialContext: ok");
Hashtable table = context.getEnvironment(); // コンテキストの環境定義を取得する
pw.println(table.toString());
}
今回はJMSプロバイダとAPは同じホスト上で実行した。
そのため、本来指定しなければならない、Context.PROVIDER_URLの値(JNDIプロバイダのURL)は指定せずに済んだ(※)。
(※指定せずに済んだのは、コンテキストがSerialInitContextFactoryだったからというのもある)
このURLの指定も、APサーバの設定で異なる。
rmiregistryだったらrmi://localhostとか、LDAPを使うなら、ldap://ldapserver:900/o=myObjectsとか、ファイルシステムだったら、file:///C:/tempとか、
ActiveMQが提供するファクトリクラスなら、tcp://localhostだってOKだし、
CosNamingならiiop://とか。
とにかくJNDIを使うのは骨が折れるのだ。
JNDIは自前でbindを行ってしまえば、それで使える。
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
props.put(Context.PROVIDER_URL, "rmi://localhost");
InitialContext context = new InitialContext(props);
context.rebind(JNDI名,オブジェクト);
こうすればコンテキストの生成時に、自分で把握しているプロパティを渡せるので、
今回のようにいちいち調べなくてもよくなる。
ただし、こうなるとAPサーバの管理コンソールに頼れなくなり、管理を全て自前で行う必要がある。
7.まとめ
Sun Java System Application Serverは無償ながら、
多言語にも対応しており、リソースの設定が楽。だけど・・・
JNDIプロバイダ(大抵はAPサーバ)ごとに、以下の情報が異なる。
- イニシャルコンテキストのファクトリークラス
- プロバイダーURL
Sun Java System Application Serverにもメニュー項目からそれが見当たらなかったので、また旅に出ます。
とにかくスタンドアロンのJNDIクライアントには厳しい世界です。