S2JMS 開発記 S2JMS-Core
S2JMS の最大目標は MDB 的な非同期メッセージ受信アプリケーションのお手軽なプラットフォームを提供することですが,例えば Web コンテナ上のアプリケーションから非同期メッセージを送信する場合に便利なクラスなども S2JMS-Core として提供します.
そんなわけで (どんなわけで?),S2JMS-Core について簡単に紹介.
S2JMS-Core を使ってメッセージを送信するには
org.seasar.jms.core.MessageSender
というインタフェースを使います.実装クラスはこれ.
org.seasar.jms.core.impl.MessageSenderImpl
こいつには単純にデータを送信するために次のメソッドがあります.
-
void send(String)
void send(byte[])
void send(Serializable)
void send(Map<String, Object>)
それぞれ,TextMessage
,BytesMessage
,ObjectMessage
,MapMessage
を作成して送信します.
OracleAQ の PayloadMessage
など非標準のメッセージを送信するとか,メッセージのヘッダやプロパティを設定したい場合は
-
<MSGTYPE extends Message> void send(MessageFactory<MSGTYPE>)
を使います.引数の
org.seasar.jms.core.message.MessageFactory<MSGTYPE>
は送信するメッセージを作成するもので,メソッド
-
MSGTYPE createMessage(Session)
が返すメッセージがそのまま送信されます.
標準の実装クラスとして
org.seasar.jms.core.message.impl.TextMessageFactory
org.seasar.jms.core.message.impl.BytesMessageFactory
org.seasar.jms.core.message.impl.ObjectMessageFactory
org.seasar.jms.core.message.impl.MapMessageFactory
を用意しています.
メッセージを送信先は MessageSenderImpl
のプロパティ
-
void setConnectionFactory(ConnectionFactory)
void setDestinationFactory(DestinationFactory)
で設定します.
ConnectionFactory
は JMS 標準のインタフェース.
S2JCA と S2JMS-Connector によるコネクションプーリングを使うことができます.これは当然 JTA 管理のトランザクションと連携します.
org.seasar.jms.core.destination.DestinationFactory
は送信先の javax.jms.Destination
を提供するもので,以下の実装クラスを用意しています.
org.seasar.jms.core.destination.QueueFactory
org.seasar.jms.core.destination.TopicFactory
org.seasar.jms.core.destination.SimpleDestinationFactory
org.seasar.jms.core.destination.JndiDestinationFactory
org.seasar.jms.core.destination.ReplyToDestinationFactory
QueueFactory
と TopicFactory
はそれぞれ QueueSession#createQueue(String)
,TopicSession#createTopic(String)
で Destination
を作成します.
SimpleDestinationFactory
は単にプロパティに設定された Queue
や Tipic
のインスタンスを宛先とします.Queue
なんかを JavaBeans として使える場合これがよいかと.
JndiDestinationFactory
は文字通り JNDI から Queue
なんかをルックアップします.Tomcat 上などで 宛先を JNDI で管理したい場合に使えるかもしれませんが,あまり使わないと思う.OracleAQ で必要になるかも? って感じ.
ReplyToDestinationFactory
は返信用で,プロパティに設定された Message
の getJMSReplyTo()
の戻り値を宛先とします.
メッセージの受信も似ていて,
org.seasar.jms.core.MessageReceiver
というインタフェースを使います.実装クラスはこれ.
org.seasar.jms.core.impl.MessageReceiverImpl
こいつには単純にメッセージを受信するために次のメソッドがあります.
-
String receiveText()
byte[] receiveBytes()
Serializable receiveObject()
Map receiveMap()
それぞれ,TextMessage
,BytesMessage
,ObjectMessage
,MapMessage
を受信してそのボディを返します.期待と異なるメッセージを受信するとキャストできずに例外が吹っ飛びます.たぶん.
プロパティの
-
void setTimeout(long)
でタイムアウト時間を設定することができます.
不特定あるいは非標準のメッセージを受信するとか,受信したメッセージのヘッダやプロパティも扱いたい場合は
-
<MSGTYPE extends Message, T> T receive(MessageHandler<MSGTYPE, T>)
を使います.引数の
MessageHandler<MSGTYPE extends Message, T>
は受信したメッセージを処理するもので,こいつのメソッド
-
T handleMessage(MSGTYPE)
にメッセージが渡されます.標準の実装として
org.seasar.jms.core.message.impl.TextMessageHandler
org.seasar.jms.core.message.impl.BytesMessageHandler
org.seasar.jms.core.message.impl.ObjectMessageHandler
org.seasar.jms.core.message.impl.MapMessageHandler
を用意しています.
ということで,簡単な非同期メッセージの送受信は
public class Hoge { private MessageSender sender; private MessageReceiver receiver; public String requestReply(String text) { sender.send(text); return receiver.receiveText(); } ・・・ }
って感じでできちゃいます.たぶん.
ただし,上記のコードはトランザクショナルなコネクションではうまくいかないはず.
トランザクションをコミットするまで送信は完結しないので,その返信が返ってくるはずがないという.
S2JMS-Core は AOP でメッセージを送信するためのインターセプタも提供します.
org.seasar.jms.core.interceptor.SendMessageInterceptor
これは MessageSenderImpl
を継承したクラスで,任意のメソッドに適用するとそのメソッドが正常終了した後にメッセージを送信します.どんなメッセージを送信するかはプロパティに設定された MessageFactory
次第.
こいつを既存の Web アプリケーションに適用することで,普通の Web アプリがサクッと非同期メッセージングアプリケーションに.
当然,S2JMS-Container 上のアプリケーションに対して SendMessageInterceptor
を適用することもできます.
それにより,JMS API を使うことなく,要求メッセージを受信して応答メッセージを返すアプリケーションを作成することも可能になります.
という感じです>こもりさん
TextMessage
をサポートするクラスとして,Velocity を使って文字列を編集するクラスがあります.
org.seasar.jms.core.message.text.VelocityTextFormatter
こいつの
-
void setTemplateText(String)
にテンプレート文字列を設定すると,編集結果を
-
String getText()
から得ることができます.テンプレート文字列中の変数は S2 コンテナ中のコンポーネントとして解釈されます.
なので,
<component name="sendInterceptor" class="org.seasar.jms.core.interceptor.SendMessageInterceptor"> <component class="org.seasar.jms.core.message.impl.TextMessageFactory"/> <component class="org.seasar.jms.core.message.text.VelocityTextFormatter"> <property name="templateText">$employeeDto.empno $employeeDto.ename</property> </component>
って感じの dicon を用意すると,SendMessageInterceptor
を適用したメソッドが終了するたびに VelocityTextFormatter
が編集したテキストが送信されます.
以下業務連絡.
ぼうず (id:bowez) さんにお願いです.
テンプレートを dicon に文字列として書くバージョンに加えて,外部のファイル (.vm ファイルっていうの?) のパスを指定するバージョンをお願いします.
あと,Velocity って 2004 年の春に 1.4 がリリースされているのに 1.3.1 を使っているのは何か理由があるのですか?