S2JMSを使ってみる〜インバウンド通信編〜
今日も引き続きSun Generic Resource Adapter for JMSと IBM WebSphere MQの組合わせで。
受信データをある項目でスライシングして並行処理をし、かつスライスされた各ブロックでは順番を保障するというアプリケーションを実現してみます。
リソースアダプタの設定
アウトバウンド同様WmqResourceAdapterDeployerを使用。上記のようなアプリケーションを実現するにはセッションプールは1にしてリソースアダプタを並行処理する数だけ用意するしかなさそう。
メッセージエンドポイントの設定
S2JMS - コンフィグレーション - インバウンド情報に出ている例の通りで大体良さそうですが、Topicを使う場合は「キュー名」の部分の設定をBaseQueueNameからBaseTopicNameに変更する必要があります。またセレクタの設定は以下のような感じでOKでした。
<initMethod name="setProperty"> <arg>"messageSelector"</arg> <arg>"key=value"</arg> </initMethod>
実行結果
リソースアダプタとメッセージエンドポイントの設定ファイルを4つ作ってそれをjms.diconでインクルードして実行してみました。コードは以下のような感じ
送信側
private JmsService jmsService; public void testSend(){ SingletonS2ContainerFactory.init(); final S2Container container = SingletonS2ContainerFactory .getContainer(); jmsService = (JmsService) container.getComponent(JmsService.class); for (int i = 0; i < 100; i++) { jmsService.hoge(i + 1); } }
private MessageSender messageSender; public void hoge(int hoge) { final Map<String, Object> payload = new HashMap<String, Object>(); final Map<String, Object> property = new HashMap<String, Object>(); payload.put("hoge", "" + hoge); payload.put("fuga", "ふが"); property.put("intKey", Integer.valueOf(hoge % 4)); messageSender.send("" + hoge, property); }
受信側
@JMSProperty private int intKey; @JMSPayload private String hoge; @JMSPayload private String fuga; public void onMessage() { final Logger logger = Logger.getLogger(this.getClass()); logger.info("メッセージ:" + hoge + "|プロパティ:" + intKey); }
これを実行すると
2007/08/03 20:15:53 com.sun.genericra.inbound.EndpointConsumer _start
情報: Generic resource adapter started consumption
2007/08/03 20:15:53 com.sun.genericra.inbound.EndpointConsumer _start
情報: Generic resource adapter started consumption
2007/08/03 20:15:54 com.sun.genericra.inbound.EndpointConsumer _start
情報: Generic resource adapter started consumption
2007/08/03 20:15:55 com.sun.genericra.inbound.EndpointConsumer _start
情報: Generic resource adapter started consumption
INFO 2007-08-03 20:15:56,285 [main] Running on [ENV]product, [DEPLOY MODE]Cool Deploy
INFO 2007-08-03 20:15:56,879 [pool-1-thread-1] メッセージ:1|プロパティ:1
INFO 2007-08-03 20:15:56,942 [pool-1-thread-1] メッセージ:5|プロパティ:1
INFO 2007-08-03 20:15:57,020 [pool-1-thread-1] メッセージ:9|プロパティ:1
・・・(省略)・・・
INFO 2007-08-03 20:15:58,973 [pool-1-thread-1] メッセージ:89|プロパティ:1
INFO 2007-08-03 20:15:59,051 [pool-1-thread-1] メッセージ:93|プロパティ:1
INFO 2007-08-03 20:15:59,301 [pool-1-thread-1] メッセージ:97|プロパティ:1
と1ブロックだけ処理して終了してしまいました。どうやらmainスレッドが終わるとリスナーも終了するようなのでデバッガでブレークポイントを置いて全部処理するまで待ってみます。
・・・(省略)・・・
INFO 2007-08-03 20:20:42,082 [pool-1-thread-1] メッセージ:97|プロパティ:1
INFO 2007-08-03 20:20:47,879 [pool-2-thread-1] メッセージ:2|プロパティ:2
INFO 2007-08-03 20:20:48,067 [pool-3-thread-1] メッセージ:3|プロパティ:3
INFO 2007-08-03 20:20:48,176 [pool-4-thread-1] メッセージ:4|プロパティ:0
・・・(省略)・・・
一応全部処理できましたが、なぜかpool-1-thread-1スレッドの処理が終わってから4秒後くらいに他のスレッドの処理が始まっています。今度は送信処理開始前にもブレークポイントを置いて5秒ほど待ってから開始してみると
・・・(省略)・・・
INFO 2007-08-03 20:25:38,817 [pool-1-thread-1] メッセージ:1|プロパティ:1
INFO 2007-08-03 20:25:38,973 [pool-2-thread-1] メッセージ:2|プロパティ:2
INFO 2007-08-03 20:25:39,473 [pool-3-thread-1] メッセージ:3|プロパティ:3
INFO 2007-08-03 20:25:39,879 [pool-4-thread-1] メッセージ:4|プロパティ:0
・・・(省略)・・・
ちゃんと同時に処理が始まりました。Consumerは起動しているのに何で処理開始が遅いのでしょう?しかも2〜4個目は同時に処理が始まるので非常になぞです。
S2JMSを使ってみる〜アウトバウンド通信編〜
1.0.0-M2リリースとともにドキュメントが充実してきたので使ってみました(今までは使い方が分からずに断念してました)。Sun Generic Resource Adapter for JMSと IBM WebSphere MQの組合わせです。
リソースアダプタの設定
WmqResourceAdapterDeployerというのが用意されていたので使ってみました。S2JMS - コンフィグレーション - リソースアダプタ情報には
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd"> <components> <include path="j2ee.dicon"/> <component class="org.seasar.jca.deploy.impl.WmqResourceAdapterDeployer"> <!-- スレッドプールのスレッド数 --> <arg>10</arg> <!-- Generic JMS ResourceAdapterへのパス --> <property name="path"> "ra/genericra-1.5.rar" </property> </component> </components>
という例が出てたのですが、WmqResourceAdapterDeployerにはスレッドプールのスレッド数を引数にもつコンストラクタは存在しないようで・・・。そのせいかBootstrapContextを設定しないと起動できませんでした。
マネージドコネクションファクトリの設定
S2JMS - コンフィグレーション - アウトバウンド情報の例ではリソースアダプタ固有のプロパティ値としてQueueManagerしか指定されてませんが実際にはもっといろいろ指定する必要がある場合が多いのではないでしょうか。その場合はカンマ区切りで
<arg>"connectionFactoryProperties"</arg> <arg>"HostName=hoge,QueueManager=fuga,Port=1234,TransportType=1"</arg>
のように指定すればOKでした。
接続系のその他の設定
S2JMS - コンフィグレーション - アウトバウンド情報の例ではセッションファクトリ(SessionFactoryImpl)のパッケージ名が間違ってました(実際にはorg.seasar.jms.core.session.impl)。あとコネクションファクトリの設定ではkijimunaの警告が。。。
送信
TextMessageオブジェクトの送信は出来ました。非JMSとの通信(単なる文字列の送信)はまだ出来てません。というか出来ないかも!?
受信
SessionFactoryImpl#operateSessionの
connection.close();
の部分で例外が発生してしまいます。エラー内容は
Conncetion.stop() cannot be called on non-ACC clients
ん〜、なんのことやら・・・。
HotDeployが効かない!?
HOT deployを開始します
クラス(hogehoge.web.hoge.FugaPage[hoge_fugaPage])のコンポーネント定義を登録します
HOT deployを終了しました
ってログが出ているのに実際には変更が反映されないという現象に遭遇。原因を突き止めるのにえらく苦労しましたが、ようやくわかりました。
mavenのtomcatプラグインで「tomacat:undeploy」するとファイルがロックされていて削除に失敗してしまうようなので、tomcatのcontext.xmlを
<Context antiJARLocking="true" antiResourceLocking="true">
のように書き換えてたのですが、これが原因でした。なんでこれが原因で変更が反映されなくなるのかは全く分かりませんが・・・。
■
ここ最近は開発環境構築の準備をしていました。実は以前にsubversionとapacheの連携の時点で躓いていて、そんなときにtrac月という非常に便利なものを発見してしまい、trac月があるという理由だけでサーバーをWindowsにしちゃいました。そもそもtracを使おうと思ったのもtrac月がきっかけだったりします。
そんな訳で基本はtrac月をインストールするだけでできちゃうので非常に簡単なのですが、ちょっとだけ苦労した点をメモ。
Continuum
サービスの起動に失敗するのでログを見てみると
Unable to execute Java command. 指定されたファイルが見つかりません。 (0x2)
"%JAVA_HOME%\bin\java" -Dclassworlds.conf=・・・(以下略)
JAVA_HOMEという環境変数が設定されていないように見えたので確認してみたもののちゃんと設定されていたので、wrapper.confの
という部分を具体的なパスに書き換えたら無事に起動しました。
よくよく考えるとJAVA_HOMEが設定されていたのがユーザー環境変数だったというオチが・・・。
trac
権限とかチケットタイプとかの設定を各プロジェクトに対して手作業でやるのがかなり面倒なので、新規作成した時点でカスタマイズされたものを作れないかと思ってまずやったのがcreate-projectからカスタマイズのバッチをキックする方法。ところがカスタマイズ用バッチでtrac-adminを何回か実行すると「文字列が大きすぎます」とか言われて途中で実行できなくなってしまいました。一回このエラーがでるともうtrac-adminは実行できなくなるけど、コマンドプロンプトを立ち上げ直すとまた復活するという変な状態。そこでtrac-adminを見てみると
SET PATH=%TRAC_PACK_ROOT%\python;%TRAC_PACK_ROOT%\subversion\bin;%TRAC_PACK_ROOT%\apache2\bin;%PATH%
これでPATHが実行する度に肥大化してしまっていたようです。なのでtrac-adminを使わないで直接
を実行すればよさそう。
でもinstallフォルダにあるdbinit.sqlを編集した方が簡単そうだということに気が付きました。
初期設定はdbinit.sql、メンバーの入れ替わりとかで頻繁に発生しそうな権限の付け替えだけはバッチ化しておくってのがよさそうです。
forEachのId
forEachのIdはデフォルトでは各行が同じIdになってしまいます。ユニークなIdにするためにはteedaCustomize.diconの
<component class="org.seasar.teeda.core.render.DefaultComponentIdLookupStrategy" />
を
<component class="org.seasar.teeda.core.render.JsfSpecComponentIdLookupStrategy" />
にすればOK。
・・・なのですが、layout機能を使うとidが全く出なくなります。