MQ Java デザインのポイント ISE Web & Transaction System 2003年7月
by user
Comments
Transcript
MQ Java デザインのポイント ISE Web & Transaction System 2003年7月
MQ Java デザインのポイント ISE Web & Transaction System 2003年7月 <MQ Java デザインのポイント> トピック Web環境でのメッセージング処理パターン 一方向型 要求/応答型 デザインのポイント 一方向型処理で使用される機能 要求/応答型処理で使用される機能 その他の機能 Base JavaとJMSの機能比較 ! 当資料内の情報には、ISEによるテスト結果を基にしたものが含まれています。これらの情報は、マニュ アルには記載されておらず、今後、変更される可能性があります。 ! 当資料内のコーディング・イメージは、アプリケーションとして使用されることを想定していません。(エラー 処理等は省いています) 従って、そのまま使用し、正常に稼動することは保証していません。 2 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> メッセージング処理パターン 3 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> トピック Web環境でのメッセージング処理パターン(1) 一方向型 一方向型処理のデザイン " " 複数メッセージ処理 1対N通信 Web環境でのメッセージング処理パターン(2) 要求/応答型 要求/応答型と一方向型との混在 要求/応答型処理のデザイン " " " " 応答メッセージの返却先 要求メッセージと応答メッセージの紐付け サーバ・アプリケーションの起動方法 UOWの設定 4 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> Web環境でのメッセージング処理パターン(1) 一方向型 1対1、1対Nのデータ送信 送信側アプリケーション " " ブラウザーからのリクエストでデータを送信する 論理的な宛先を意識してデータを送信(最終送信先は知らなくて良い) 例)キュー名、トピック名、ポート名 など 受信側アプリケーション 1. 2. " ブラウザーからのリクエストでデータを受信する or サーバ・アプリケーションとして起動され、メッセージを受信、処理する 論理的な宛先を意識してデータを受信(送信元は意識しなくて良い) 例)キュー名、トピック名、ポート名 など MQPUT MQGET 受信側アプリケーション(1) MQGET 送信側アプリケーション 受信側アプリケーション(2) 5 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 一方向型処理のデザイン 複数メッセージをグループとして処理する場合 扱うデータが大きい場合には、複数メッセージに分割して送受信する " ファイル転送、イメージ・データ転送など 送信側/受信側アプリケーションは、複数メッセージを1UOWとする 複数メッセージ間の紐付け、順序管理を行なう " " MQ論理メッセージ、グループ・メッセージ機能を利用 MsgID、CorrelIdを利用してグループ化を行なう MQPUT : : MQCMIT : : 送信側アプリケーション MQGET : : MQCMIT 受信側アプリケーション 6 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 一方向型処理のデザイン 全てのメッセージが届いてから、メッセージ受信するためには… 論理メッセージ機能を利用 " MQGET時のオプションにMQGMO_ALL_MSGS_AVALABLEを指定 制御用キューとデータ用キューを利用 " " データ用キューに複数メッセージ送信後、制御用キューに制御メッセージを送信 制御メッセージが届けば、データ・メッセージはすべてキューに到着済 制御メッセージとデータ・メッセージの紐付けはCorrelIDを利用 MDBで複数メッセージを処理するためには.. MDBは起動時には1メッセージしか受信しない #起動後、ユーザロジック内で複数メッセージを受信する 制御用キューとデータ用キューを利用 " " 制御用キューをリスナー・ポートとして設定 onMessage() 内で、データ用キュー内のメッセージを受信する MQPUT : : MQCMIT : データ用キュー MQGET : MDB : リスナー ポート 送信側アプリケーション EJBコンテナ 制御用キュー 7 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 一方向型処理のデザイン “1対N通信 = Pub/Subモデル“とは限らない Pub/Subモデルが適しているケース " " 送信側(パブリッシャー)は、宛先を意識しない 受信側(サブスクライバー)が欲しいデータを、能動的に登録/取り消しする場合 PTPモデルが適しているケース " " " 複数宛先を送信側で決定したい場合 送信側は、宛先を意識しないが、管理者が宛先を登録、変更する場合 受信側が、受け取るデータを登録しない場合 Pub/Subモデル利用時の考慮点 Pub/Sub用のブローカーが必要(次のいづれか1つ) " " " " " WebSphere MQ Event Broker WAS V5に付属の Broker 機能 WebSphere MQ Integrator に付属の Broker 機能 WebSphere Business Integration Message Brokers のEvent Broker 機能 サポート・パック:MA0C MQSeries Publish/Subscribe http://www-3.ibm.com/software/integration/support/supportpacs/individual/ma0c.html " それぞれ機能が異なるので注意 ブローカーの運用、管理、バックアップ サブスクライバーが受信データを登録する際、セキュリティ・チェックが必要 8 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> Web環境でのメッセージング処理パターン(2) 要求/応答型(同期型) 1対1のデータ通信 クライアント・アプリケーション(要求側) " " ブラウザーからのリクエストで、要求メッセージを論理的な宛先に送信 応答メッセージの到着を、指定した宛先で待つ サーバ・アプリケーション(応答側) " " 要求メッセージを待ち、処理、応答メッセージを返す常駐アプリケーション(Javaアプリ) メッセージが届いたら、起動されデータを受信、処理、応答を返す(MDB) UOWは次の3つに分割される " " " 要求メッセージの送信 要求メッセージの受信、処理、応答メッセージの送信 応答メッセージの受信 MQPUT MQGET INSERT MQPUT MQGET クライアント・ アプリケーション サーバ・アプリケーション 9 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> Web環境でのメッセージング処理パターン 要求/応答型と一方向型との混在 クライアント・アプリケーション(要求側) 1. ブラウザーからのリクエストで要求メッセージを論理的な宛先に送信 ブラウザーに受付IDなどを返す 2. ブラウザーから受付IDを受け取り、応答キューからメッセージを受信する サーバ・アプリケーション(応答側) " " 要求メッセージを待ち、処理、応答メッセージを返す常駐アプリケーション(Javaアプリ) メッセージが届いたら、起動されデータを受信、処理、応答を返す(MDB) MQPUT MQGET INSERT MQPUT ID クライアント・アプリケーション(1) ID サーバ・アプリケーション MQGET クライアント・アプリケーション(2) 10 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 要求/応答型処理のデザイン 応答メッセージの返却先 クライアント・アプリケーションが、要求メッセージ内に応答先を指定 " " MQMDのReplyToQに応答キュー名を指定 RepylToQMgrは自動的に設定される サーバ・アプリケーションは、指定された応答先に応答メッセージを返す " " " 要求メッセージ内のReplyToQ、ReplyToQmgr を指定してキューをオープンし、応答を送 信 キュー・マネージャー名がリモートであれば、同名のトランスミッション・キューがオープンされる リモート・キュー定義は不要 QM1(キュー・マネージャー名) RQMNAME(QM2) RQMNAME(QM2) RNAME(LQ2) RNAME(LQ2) QM2(キュー・マネージャー名) LQ2(ローカル・キュー) MQOPEN RQ2 クライアント・ アプリケーション RQ2(リモートキュー) MQOPEN QM1 、LQ1 MQチャネル QM1( (XMITQ) LQ1(ローカル・キュー) サーバ・ アプリケーション トランスミッション・キュー(XMITQ)は、接続相手の キュー・マネージャーと同一名称に設定する 11 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 要求/応答型処理のデザイン 要求メッセージと応答メッセージの紐付け メッセージID(MsgID)、相関ID(CorrelId)を利用して対応させる クライアント・アプリケーション " " MQMDのMsgIDを設定:MQに採番させても良い JMSはMsgIDをユーザ設定できないので、MQに採番させる CorrelID=要求メッセージのMsgID で、メッセージを選択して応答キューを待つ サーバ・アプリケーションは、要求メッセージのMsgIDを応答メッセージのCorrelIDに設 定し返す 複数クライアントで1つの応答キューを共有することが可能 その他 クライアント・アプリケーションは、応答キューを待つタイムアウト値を設定 " WaitInterval指定 照会型のメッセージには、有効期限を設定 " Expiry クライアント・アプリケーション MQPUT MsgID=MQMI_NONE : MQGET CorrelID=要求メッセージのMsgID サーバ・アプリケーション MQGET : MQPUT CorrelID=要求メッセージのMsgID 12 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 要求/応答型処理のデザイン サーバ・アプリケーションの起動方法 常駐Javaアプリケーション " トランザクションを開始して、要求キューにメッセージが来るのを待ち受ける MDB " リクエスト・メッセージが到着したら、起動されるMDBを作成 UOWの設定 クライアント・アプリケーションの、メッセージ送信と受信のUOWは分かれる " 同期を取らないと、要求メッセージが送信されないから サーバ・アプリケーションは、要求メッセージと応答メッセージまでを1つのUOWに設定 " MDBの場合、トランザクションは、コンテナ管理(CMT)と設定する UOW MQPUT MQGET INSERT MQPUT UOW MQGET クライアント・ アプリケーション UOW サーバ・アプリケーション 13 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> デザインのポイント 14 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> トピック デザインのポイント 一方向型処理で使用される機能 " グループ化/セグメント化 応答/要求型処理で使用される機能 " " 要求/応答メッセージの紐付け 応答先の指定/応答先への送信 その他の機能 " " " " " " " " クライアント接続 Browse機能 メッセージの永続性 同期点処理 グローバル・トランザクション コネクション・プーリング エラー処理 トレース機能 JMSでコーディングする際の注意点 機能比較 15 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 一方向型処理で使用される機能 グループ化/セグメント化 大きなデータを複数のメッセージに分割して送信 " ファイル転送、イメージ・データ転送 受信側は、複数メッセージを組み立て、1つのデータとして処理 メッセージの順序性が保証される 同じサーバ・インスタンスで処理される グループ化 アプリケーションがメッセージの分割/組み立てを行なう " メッセージは、MQMDのグループID(GroupId)と順序番号(MsgSeqNumber)で関連づけられる 受信アプリケーション 送信アプリケーション pmo.options = MQPMO_LOGICAL_ORDER MQPUT (MQMF_MSG_IN_GROUP) MQPUT (MQMF_MSG_IN_GROUP) MQPUT (MQMF_LAST_MSG_IN_GROUP) gmo.options = MQGMO_LOGICAL_ORDER While(GroupStatus == MQGS_MSG_IN_GROUP) { MQGET } GrpID=1 順序番号=1 GrpID=1 順序番号=2 GrpID=1 順序番号=3 16 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 一方向型処理で使用される機能 セグメント化 キュー・マネージャーがメッセージの分割/組み立てを行なう " " キュー・マネージャーもしくはキューの最大メッセージ長(MaxMsgLength)より大きいメッセージを PUTしたときのみセグメント化が行なわれる メッセージは、MQMDのグループID(GroupId)、順序番号(MsgSeqNumber)、オフセット (Offset)で関連づけられる アプリケーションは、メッセージの分割/組み立てを行なう必要はない " PUT/GET時にセグメント化を意識したオプションを設定する必要はある $ PUT時は、MQMF_SEGMENTATION_ALLOWEDを指定 $ GET時は、MQGMO_COMPLETE_MSGを指定 送信アプリケーション MQPUT (MQMF_SEGMENTATION_ALLOWED ) キュー・マネージャー GrpID=1 順序番号=1 Offset=0 受信アプリケーション GrpID=1 順序番号=1 Offset=10 gmo.options = MQGMO_COMPLETE_MSG MQGET GrpID=1 順序番号=1 Offset=20 17 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> グループ化/セグメント化 比較 Base Java JMS グループ化 ◎(MQIと同等の設定が可能) ・キュー・マネージャーによるIDの自動採番 ・全てのMSGが揃ってからGETすることが可能 △ ・ユーザがグループIDや順序番号を設定 ・MQGMO_LOGICAL_ORDERの指定はできない ・MQGMO_ALL_MSGS_AVAILABLEの指定はでき ない セグメント化 ◎(MQIと同等の設定が可能) ×(利用不可) 注:MQ z/OS版では、セグメント化機能はサポートされていない 18 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> BJ グループ化(BaseJava) MQIと同様のオプションを指定できる 送信アプリケーション MQPutMessageOptionsオブジェクトのoptionsに、 MQC.MQPMO_LOGICAL_ORDERを指定 " 自動的にグループIDおよび順序番号がセットされる pmo.options = MQC.MQPMO_LOGICAL_ORDER; MQMessageオブジェクトのmessageFlagsに、 MQC.MQMF_MSG_IN_GROUPを指定しながら複数メッセージを送信 msg.messageFlags = MQC.MQMF_MSG_IN_GROUP; " グループ最後のメッセージには、MQC.MQMF_LAST_MSG_IN_GROUPを指定 msg.messageFlags = MQC.MQMF_LAST_MSG_IN_GROUP; 19 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> BJ グループ化(BaseJava) 受信アプリケーション MQGetMessageOptionsオブジェクトのoptionsに、 MQC.MQGMO_LOGICAL_ORDERを指定 " メッセージを論理順序で取得することができる gmo.options = MQC.MQGMO_LOGICAL_ORDER; " MQGetMessageOptionsオブジェクトのoptionsに、MQC.MQGMO_ALL_MSGS_AVAILABLEを 指定するとグループ内の全てのメッセージが到着してからメッセージをGETできる gmo.options = MQC.MQGMO_ALL_MSGS_AVAILABLE; MQGetMessageOptionsオブジェクトのgroupStatusが MQC.MQGS_LAST_MSG_IN_GROUPになるまでGETを繰り返す " GET後のgroupStatusには、以下のいずれかの値(char型)がセットされる $ MQC.MQGS_NOT_IN_GROUP(グループ内のメッセージではない場合) $ MQC.MQGS_MSG_IN_GROUP(グループ内のメッセージの場合) $ MQC.MQGS_LAST_MSG_IN_GROUP(グループ内の最後のメッセージの場合) 20 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ ≪ノート≫ BJ 送信アプリケーション 3件のグループ・メッセージを送信する場合 (省略) q = qMgr.accessQueue(qName, openOptions); pmo = new MQPutMessageOptions(); pmo.options |= MQC.MQPMO_LOGICAL_ORDER; msg.messageFlags = MQC.MQMF_MSG_IN_GROUP; msg.write(アプリケーション・データ1); q.put(msg, pmo); msg.clearMessage(); msg.messageFlags = MQC.MQMF_MSG_IN_GROUP; msg.write(アプリケーション・データ2); q.put(msg, pmo); msg.clearMessage(); msg.messageFlags = MQC.MQMF_LAST_MSG_IN_GROUP; msg.write(アプリケーション・データ3); q.put(msg, pmo); msg.clearMessage(); (省略) 21 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ ≪ノート≫ BJ 受信アプリケーション グループ内の最後のメッセージが到着してから、グループ・メッセージを順番に最後まで受 信する場合 (省略) gmo.options |= MQC.MQGMO_LOGICAL_ORDER; gmo.options |= MQC.MQGMO_ALL_MSGS_AVAILABLE; do{ msg = new MQMessage(); q.get(msg, gmo); : (メッセージ処理) : }while(gmo.groupStatus != MQC.MQGS_LAST_MSG_IN_GROUP); (省略) 22 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS グループ化(JMS) 送信アプリケーション MQPMO_LOGICAL_ORDERの指定ができない " " 複数メッセージをMQのグループ・メッセージとして送信することはできる ユーザーがグループIDや順序番号を設定する必要がある JMSプロパティーのJMSXGroupIDに一意の文字列(String)を指定 " " MQMDのGroupIdに指定した値がセットされる 内部的に、MQMDのmessageFlagsにMQMF_MSG_IN_GROUPがセットされる msg.setStringProperty(“JMSXGroupID”, “001”); JMSプロパティーのJMSXGroupSeqに値(int)を指定しながら複数メッセージを送信 " " " MQMDのMsgSeqNumberに指定した値がセットされる グループの最初のメッセージは、この値が“1”でなければならない 後続メッセージには前のメッセージの値に“1”を加えた値を指定 msg.setIntProperty(“JMSXGroupSeq”, 1); グループの最後のメッセージには、JMS_IBM_Last_Msg_In_Groupに true(boolean値)を指定 " 内部的に、MQMDのmessageFlagsにMQMF_LAST_MSG_IN_GROUPがセットされる msg.setBooleanProperty(“JMS_IBM_Last_Msg_In_Group”, true); 23 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> グループ化(JMS) ≪ノート≫ JMS JMSXプロパティ ”JMSX”をPrefixに持つJMSプロパティはJMSの仕様だが、実装は義務付けられていな い " JMSXGroupID、JMSXGroupSeqなど JMSXプロパティを用いてメッセージのグループ化を行なっているJMSアプリケーションのポー タビリティは保証されない プロバイダーがサポートしているJMSXプロパティは、ConnectionMetaDataオブジェクトの getJMSXPropertyNamesメソッドを使用して調べることが可能 MQConnectionMetaData meta = new MQConnectionMetaData(); java.util.Enumeration enu = meta.getJMSXPropertyNames(); while(enu.hasMoreElements()){ System.out.println("JMSXPropaty : " + enu.nextElement()); } MQがサポートするJMSXプロパティ " " " " " JMSXUserID JMSXAppID JMSXDeliveryCount JMSXGroupID JMSXGroupSeq 24 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS グループ化(JMS) 末 受信アプリケーション MQGMO_LOGICAL_ORDERおよびMQGMO_ALL_MSGS_AVAILABLEの指定が できない " " " グループ内の全てのメッセージが到着したことをアプリケーションは確認する必要がある ⇒セレクターを使ってグループ最後のメッセージを指定して受信待ち アプリケーションが受信メッセージの関連性と順序性を確認する必要がある ⇒JMSプロパティーのJMSXGroupID/JMSXGroupSeq/JMS_IBM_Last_Msg_In_Groupの 値から判別 JMSプロパティーをJMSセレクターを使用して検索することになるので、メッセージの滞留数が パフォーマンスに影響(p49参照) JMSでMQグループ・メッセージの受信アプリケーションを作成するのは困難 グループ化をMQの機能を利用しないで行なう場合 " " メッセージIDと相関IDでグループ化を行ない、制御メッセージを使用する方法(p7参照) $ 制御メッセージでグループ最後のメッセージが到着したことを確認できる $ メッセージIDと相関IDをキーにセレクターで受信するので滞留数によるパフォーマンスの劣 化がない(p49参照) 送信側もJMSの場合は、メッセージIDを自由に使えないので、相関IDにグループIDを指定し、 順序番号は他のプロパティを使うことになる 25 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ ≪ノート≫ JMS 送信アプリケーション グループIDを”001”として、3件のグループ・メッセージを送信する場合 (省略) TextMessage msg1 = session.createTextMessage(ユーザ・データ1); msg1.setStringProperty(“JMSXGroupID”, “001”); msg1.setIntProperty(“JMSXGroupSeq”, 1); sender.send(msg1); TextMessage msg2 = session.createTextMessage(ユーザ・データ2); msg2.setStringProperty(“JMSXGroupID”, “001”); msg2.setIntProperty(“JMSXGroupSeq”, 2); sender.send(msg2); TextMessage msg3 = session.createTextMessage(ユーザ・データ3); msg3.setStringProperty(“JMSXGroupID”, “001”); msg3.setIntProperty(“JMSXGroupSeq”, 3); msg3.setBooleanProperty(“JMS_IBM_Last_Msg_In_Group”, true); sender.send(msg3); (省略) 26 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> BJ セグメント化(BaseJava) MQIと同様のオプションを指定できる 送信アプリケーション MQMessageオブジェクトのmessageFlagsに、 MQC.MQMF_SEGMENTATION_ALLOWEDを指定 " キュー・マネージャーが自動的にメッセージを分割 msg.messageFlags = MQC.MQMF_SEGMENTATION_ALLOWED; 受信アプリケーション MQGetMessageOptionsオブジェクトのoptionsに、 MQC.MQGMO_COMPLETE_MSGを指定 " " キュー・マネージャーが自動的にセグメント化されたメッセージを組み立てて、 アプリケーションに渡す セグメント化されていないメッセージを受信することも可能 gmo.options = MQC.MQGMO_COMPLETE_MSG; 27 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ ≪ノート≫ BJ 送信アプリケーション 10MBのデータをファイル(10MG.dat)から読み取り、セグメント化されることを許可して メッセージを送信する場合 " キュー・マネージャーもしくはキューの最大メッセージ長が10MBより小さい場合、 メッセージはセグメント化される (省略) msg.messageFlags = MQC.MQMF_SEGMENTATION_ALLOWED; FileInputStream fis = new FileInputStream("10MB.dat"); byte b[] = new byte[10000000]; fis.read(b); msg.write(b); queue.put(msg, pmo); (省略) 28 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ ≪ノート≫ BJ 受信アプリケーション セグメント化されているメッセージを受信する場合 (省略) gmo.options |= MQC.MQGMO_COMPLETE_MSG; queue.get(msg, gmo); (省略) 29 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(Base Java) ≪ノート≫ BJ BaseJavaの一方向型送信アプリケーション String QMgr_Name = "QM1"; String Q_Name = "Q1"; String Message = “This is a test message"; MQQueueManager MQQueue MQPutMessageOptions MQMessage int openOptions = 0; qMgr = null; queue = null; pmo = null; msg = null; qMgr = new MQQueueManager(QMgr_Name); openOptions |= MQC.MQOO_OUTPUT; queue = qMgr.accessQueue(Q_Name, openOptions); msg = new MQMessage(); msg.writeString(Message); pmo = new MQPutMessageOptions(); queue.put(msg, pmo); queue.close(); qMgr.disconnect(); 30 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(Base Java) ≪ノート≫ BJ BaseJavaの一方向型受信アプリケーション String QMgr_Name = "QM1"; String Q_Name = "Q1"; MQQueueManager MQQueue MQGetMessageOptions MQMessage int openOptions = 0; qMgr = null; queue = null; gmo = null; msg = null; qMgr = new MQQueueManager(QMgr_Name); openOptions |= MQC.MQOO_INPUT_AS_Q_DEF; queue = qMgr.accessQueue(Q_Name, openOptions); msg = new MQMessage(); gmo = new MQGetMessageOptions(); gmo.options |= MQC.MQGMO_FAIL_IF_QUIESCING; gmo.options |= MQC.MQGMO_WAIT; gmo.waitInterval |= MQC.MQWI_UNLIMITED; queue.get(msg, pmo); queue.close(); qMgr.disconnect(); 31 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(JMS) ≪ノート≫ JMS JMSの一方向型送信アプリケーション String QMgr_Name = "QM1"; String Q_Name = "Q1"; String Message = "This is a test message"; MQQueueConnectionFactory qcf = null; MQQueue queue = null; QueueConnection qc = null; QueueSession session = null; QueueSender sender = null; TextMessage msg = null; qcf = new MQQueueConnectionFactory(); qcf.setQueueManager(QMgr_Name); queue = new MQQueue(Q_Name); qc = qcf.createQueueConnection(); qc.start(); session = qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); msg = session.createTextMessage(Message); sender = session.createSender(requestQ); sender.send(msg); sender.close(); session.close(); qc.close(); qc = null; 32 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(JMS) ≪ノート≫ JMS JMSの一方向型受信アプリケーション String QMgr_Name = "QM1"; String Q_Name = "Q1"; MQQueueConnectionFactory qcf = null; MQQueue queue = null; QueueConnection qc = null; QueueSession session = null; QueueReceiver receiver = null; TextMessage msg = null; qcf = new MQQueueConnectionFactory(); qcf.setQueueManager(Qmgr_Name); MQQueue requestQ = new MQQueue(Q_Name); qc = qcf.createQueueConnection(); qc.start(); session = qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); receiver = session.createReceiver(queue); msg = receiver.receive(10000); receiver.close(); session.close(); qc.close(); qc = null; 33 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 要求/応答型処理で使用される機能 要求/応答メッセージの紐付け メッセージID/相関IDを使用して要求メッセージと応答メッセージを紐づける 相関ID指定の受信 応答先の指定/応答先への送信 クライアント側は、要求メッセージに応答先キュー名/キュー・マネージャー名を指定 サーバ側は、指定された応答先へ応答メッセージを送信 クライアント・アプリケーション メッセージID=AAA PUT サーバ・アプリケーション GET 要求メッセージ メッセージID=AAA 要求キュー ユニークなメッセージ IDをセット 応答先をセット GET wait (相関ID=AAA) 要求メッセージの メッセージID⇒相関ID PUT 応答キュー 応答メッセージのメッ セージIDが相関IDに セットされている メッセージを受信 34 応答メッセージ 相関ID=AAA 要求メッセージのメッセー ジIDを応答メッセージの 相関IDにセットし、 応答先にPUT Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 要求/応答型処理で使用される機能 比較 Base Java JMS 要求/応答メッ セージの紐付け ◎(MQIと同等の設定が可能) ○ ・メッセージIDを自由に設定できない (キュー・マネージャーが自動的に設定する) 応答先の指定 /応答先への 送信 ◎( MQIと同等の設定が可能) ◎ 35 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 要求/応答メッセージの紐付け(BaseJava) BJ クライアント・アプリケーション 要求メッセージのメッセージIDにユニークな値を指定して送信 " " 要求メッセージ(MQMessage)のmessageIdに任意のバイト配列をセット MQMI_NONE(デフォルト値)もしくは、MQPMOのoptionsにMQPMO_NEW_MSG_IDを指定して いる場合は、キュー・マネージャーによって自動的にユニークな値がセットされる requestMsg.messageId = MQC.MQMI_NONE; 要求メッセージのメッセージID値が相関IDにセットされている応答メッセージを受信 " " GMOのmatchOptionsにMQMO_MATCH_CORREL_IDをセット 応答メッセージ(MQMessage)のcorrelationIdに要求メッセージのmessageIdをセット gmo.matchOptions = MQC.MQMO_MATCH_CORREL_ID; replyMsg.correlationId = requestMsg.messageId; replyQ.get(replyMsg, gmo); 36 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 要求/応答メッセージの紐付け(BaseJava) BJ サーバ・アプリケーション 受信した要求メッセージのメッセージIDを応答メッセージの相関IDに設定し、送信 " 受信用MQMessageのmessageIdを、送信用MQMessageのcorrelationIdに設定 replyMsg.correlationId = requestMsg.messageId; replyQ.put(replyMsg, pmo); 37 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 応答先の指定/応答先への送信(BaseJava) BJ クライアント・アプリケーション 要求メッセージに応答先キュー名を指定して送信 " MQMessageのreplyToQueueNameに設定 requestMsg.replyToQueueName = “REP_Q”; 応答先キュー・マネージャー名は自動的に自分の接続しているキュー・マネージャー名が セットされる " replyToQueueManagerNameに値を設定する必要はない 38 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 応答先の指定/応答先への送信(BaseJava) BJ サーバ・アプリケーション 受信した要求メッセージから応答先キュー名と応答先キュー・マネージャー名を取得し、 キューをオープン " 受信用MQMessageのreplyToQueueNameとreplyToQueueManagerNameを MQQueueManagerのaccessQueueメソッドの引き数に設定 オープンしたキューに対し、応答メッセージをPUT String repQ = requestMsg.replyToQueueName; String repQMgr = requestMsg.replyToQueueManagerName; replyQ = qMgr.accessQueue(repQ, openOptions, repQMgr, “”, “” ); replyQ.put(replyMsg, pmo); 39 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(Base Java) ≪ノート≫ BJ クライアント・アプリケーション (省略) String QMgr_Name = "QM1"; String requestQ_Name = "RQ1"; String replyQ_Name = "Q2"; String requestMsgText = “This is a request message"; MQQueueManager qMgr = new MQQueueManager(QMgr_Name); int openOptions |= MQC.MQOO_OUTPUT; MQQueue requestQ = qMgr.accessQueue(requestQ_Name, openOptions); MQPutMessageOptions pmo = new MQPutMessageOptions(); MQMessage requestMsg = new MQMessage(); requestMsg.messageId = MQC.MQMI_NONE; requestMsg.replyToQueueName = replyQ_Name; requestMsg.writeString(requestMsgText); requestQ.put(requestMsg, pmo); : : 40 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(Base Java) ≪ノート≫ BJ クライアント・アプリケーション(続き) : : int openOptions2 |= MQC.MQOO_INPUT_AS_Q_DEF; MQQueue replyQ = qMgr.accessQueue(replyQ_Name, openOptions2); MQGetMessageOptions gmo = new MQGetMessageOptions(); gmo.options |= MQC.MQGMO_FAIL_IF_QUIESCING; gmo.options |= MQC.MQGMO_WAIT; gmo.matchOptions |= MQC.MQMO_MATCH_CORREL_ID; gmo.waitInterval |= MQC.MQWI_UNLIMITED; MQMessage replyMsg = new MQMessage(); replyMsg.correlationId = requestMsg.messageId; replyQ.get(replyMsg, gmo); requestQ.close(); replyQ.close(); qMgr.disconnect(); (省略) 41 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(Base Java) ≪ノート≫ BJ サーバ・アプリケーション (省略) String QMgr_Name = "QM2"; String requestQ_Name = "Q1"; MQQueueManager qMgr = new MQQueueManager(qMgrName); int openOptions |= MQC.MQOO_INPUT_AS_Q_DEF; MQQueue requestQ = qMgr.accessQueue(requestQ_Name, openOptions); MQMessage requestMsg = new MQMessage(); MQGetMessageOptions gmo = new MQGetMessageOptions(); gmo.options |= MQC.MQGMO_WAIT; gmo.waitInterval |= MQC.MQWI_UNLIMITED; gmo.options |= MQC.MQGMO_FAIL_IF_QUIESCING; gmo.options |= MQC.MQGMO_SYNCPOINT; requestQ.get(requestMsg, gmo); : : 42 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(Base Java) ≪ノート≫ BJ サーバ・アプリケーション(続き) : : String replyQMgr_Name = requestMsg.replyToQueueManagerName; String replyQ_Name = requestMsg.replyToQueueName; int openOptions2 |= MQC.MQOO_OUTPUT; replyQ = qMgr.accessQueue(replyQ_Name, openOptions2, QMgr_Name, "", ""); replyMsg = new MQMessage(); replyMsg.writeString(“This is a reply messge"); replyMsg.correlationId = requestMsg.messageId; MQPutMessageOptions pmo = new MQPutMessageOptions(); pmo.options |= MQC.MQPMO_SYNCPOINT; replyQ.put(replyMsg, pmo); qMgr.commit(); requestQ.close(); replyQ.close(); qMgr.disconnect(); (省略) 43 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS 要求/応答メッセージの紐付け(JMS) クライアント・アプリケーション 要求メッセージにメッセージIDの設定はせずに送信 " " " JMSの場合、アプリケーションが任意のメッセージIDを設定することができない キュー・マネージャーがPUT時にユニークなIDをセット PUT後のメッセージ・オブジェクトからキュー・マネージャーのセットしたメッセージIDを取得 JMSのセレクター機能を使用し、相関IDを指定して受信 " " " 要求メッセージのメッセージIDが相関IDにセットされている応答メッセージを受信 MessageのgetJMSMessgeIDメソッドにて要求メッセージのメッセージIDを文字列として取得 セレクター(String)に文字列”JMSCorrelationID=‘要求メッセージのメッセージID’ ”を設定 (省略) sender.send(requestMsg); String msgId = requestMsg.getJMSMessageID(); String selector = "JMSCorrelationID='" + msgId + "'"; QueueReceiver receiver = session.createReceiver(replyQ, selector); Message replyMsg = receiver.receive(); (省略) 44 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS 要求/応答メッセージの紐付け(JMS) サーバ・アプリケーション 要求メッセージのメッセージIDを取得し、応答メッセージの相関IDに設定 " 要求メッセージのgetJMSMessageIDメソッドで、メッセージIDを取得し、その値を 応答メッセージのsetJMSCorrelationIDメソッドで応答メッセージに設定 replyMsg.setJMSCorrelationID(requestMsg.getJMSMessageID()); 45 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMSのセレクター機能 ≪ノート≫ JMS JMSヘッダ、JMSプロパティの属性の値を指定して受信する機能 セレクター(文字列)に「属性名=値」の形式で指定 " String selector = “JMSCorrelationID=XXXXX”; QueueReceiverに対しセレクターは1つのみ設定でき、設定後の変更は不可 " QueueSessionのcreateQueueReceiverメソッドの第二引き数にセレクターをセット 該当メッセージを見つけるまでキュー内のメッセージをBrowseするので、滞留数がパフォー マンスに影響 JMSMessageIDおよびJMSCorrelationIDを指定して受信する場合のみ、以下のように セレクターを指定することでMQの検索機能を使うことができる " " キュー内のメッセージをBrowseして検索しないので、パフォーマンスは滞留数にほとんど影響され ない 指定方法 $ MQMDのMsgIdおよびCorrelIDにセットされた値の16進数表記にPrefixとして「ID:」を付け てセレクターに指定 例えば、MQMDのMsgIDに 414D5120514D31202020202020202020D848DD3E20000401 と設定されているメッセージをセレクターで受信する場合、セレクターの設定は以下のようにする selector = “JMSMessageID=‘ID:414D5120514D31202020202020202020D848DD3E20000401’ “ 46 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMSMessageID ≪ノート≫ JMS JMSメッセージのメッセージID(JMSMessageID) アプリケーションが任意の値を設定することはできない PUT時にキュー・マネージャーがMQMDのmessageIdに割り当てた値がJMSMessageIDに セットされる " " " " MQのメッセージIDは、24バイトのバイナリ・データ JMSMessageIDは、文字列(String) Prefixとして「ID:」が付く 例えば、キュー・マネージャーがMQMDのmessageIdに以下の値を割り当てた場合 414D5120514D31202020202020202020D848DD3E20000401 (バイナリ・データ) PUT後のMessageオブジェクトのJMSMessageIDには、以下の値がセットされる ID: 414D5120514D31202020202020202020D848DD3E20000401(文字列) アプリケーションは、PUT後、getJMSMessageIDメソッドでメッセージIDを取得可能 " " メソッドの戻り値には、「ID:」が付加された文字列が返る セレクターにセットする場合、戻り値をそのまま設定すると、MQの検索機能が使える 47 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMSCorrelationID ≪ノート≫ JMS JMSメッセージの相関ID(JMSCorrelationID) アプリケーションから任意の値を設定可能(設定方法は以下の3通り) 1. 2. 3. 文字列を設定 $ 相手がJMSアプリケーションであるときに使用 $ message.setJMSCorrelationID("12345"); $ MQMDのCorrelIdとMQRFH2ヘッダのCidにセットされる 16進数表記の文字列(Prefixとして「ID:」を付加)を設定 $ 受信メッセージのメッセージIDを送信メッセージの相関IDに設定する場合に使用 $ replyMsg.setJMSCorrelationID(requestMsg.getJMSMessageID()); $ MQMDのCorrelIdにのみセットされる バイト配列を設定 $ message.setJMSCorrelationIDAsBytes(b); $ MQMDのCorrelIdにのみセットされる 値の取得は以下のメソッドを使用 " " getJMSCorrelationID() $ MQRFH2のCidに値がセットされている場合は、その文字列が返る $ MQMDのCorrelIdにのみ値がセットされている場合は、バイナリ・データの16進数表記に 「ID:」が付加された文字列が返る getJMSCorrelationIDAsBytes() $ MQMDのCorrelIdにセットされているバイナリ・データのバイト配列が返る 48 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMSメッセージとMQメッセージ ≪ノート≫ JMS JMSメッセージとMQメッセージの関係(メッセージID/相関ID) アプリケーション Message msg = new Message(); キュー・マネージャー PUT前の PUT前のJMS 前のJMSメッセージ JMSメッセージ JMSMessageID msg.setJMSCorrelationID("12345"); MQメッセージ メッセージ キュー・マネージャー MQ が生成 MQMD.MessageID JMSCorrelationID "12345" 414534A32……. sender.send(msg) MQMD.CorrelID 3132333435……. PUT後の PUT後のJMS 後のJMSメッセージ JMSメッセージ JMSMessageID MQRFH2.CrlID "ID:414534A32....." "12345" JMSCorrelationID msgID = msg.getJMSMessageID(); "12345" correlID = msg.getJMSCorrelationID(); 49 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 応答先の指定/応答先への送信(JMS) JMS クライアント・アプリケーション 応答先が設定されたQueueオブジェクトをJNDIから取得 InitialContext ic = new InitialContext(); Queue replyQ = (Queue)ic.lookup("java:comp/env/jms/ReplyQ"); " JNDIを使用しない場合は、MQQueueオブジェクトを作成し、応答キュー名とキューマネージャー 名を設定 MQQueue replyQ = new MQQueue(replyQ_Name); replyQ.setBaseQueueManagerName(replyQMgr_Name); Queueオブジェクトを要求メッセージに設定 " MessageオブジェクトのsetJMSReplyToメソッドで設定 requestMsg.setJMSReplyTo(replyQ); 50 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 応答先の指定/応答先への送信(JMS) JMS サーバ・アプリケーション 要求メッセージからgetJMSReplyToメソッドでQueueオブジェクトを取得し、 そのオブジェクトをもとにQueueSenderを作成 " オブジェクトには、クライアント側でセットされた応答キュー名とキュー・マネージャー名が設定され ている sender = session.createSender((Queue)requestMsg.getJMSReplyTo()); 51 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(JMS) ≪ノート≫ JMS クライアント・アプリケーション (省略) String requestMsgText = “This is a request message"; String QMgr_Name = "QM1"; String requestQ_Name = “Q1”; String replyQ_Name = “Q2”; MQQueueConnectionFactory qcf = new MQQueueConnectionFactory(); qcf.setQueueManager(QMgr_Name); MQQueue requestQ = new MQQueue(requestQ_Name); MQQueue replyQ = new MQQueue(replyQ_Name); QueueConnection qc = qcf.createQueueConnection(); qc.start(); QueueSession session = qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); QueueSender sender = session.createSender(requestQ); TextMessage requestMsg = session.createTextMessage(requestMsgText); Destination destination = session.createQueue("queue://QM1/Q2"); requestMsg.setJMSReplyTo(destination); sender.send(requestMsg); : : 52 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(JMS) ≪ノート≫ JMS クライアント・アプリケーション(続き) : : String msgId = requestMsg.getJMSMessageID(); String selector = "JMSCorrelationID='" + msgId + "'"; QueueReceiver receiver = session.createReceiver(replyQ, selector); Message replyMsg = receiver.receive(); getMsg = ((TextMessage)inMsg).getText(); sender.close(); receiver.close(); session.close(); qc.close(); qc = null; (省略) 53 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(JMS) ≪ノート≫ JMS サーバ・アプリケーション (省略) String putMsg = null; String getMsg = null; String QMgr_Name = "QM1"; String requestQ_Name = "Q1"; MQQueueConnectionFactory qcf = new MQQueueConnectionFactory(); qcf.setQueueManager(Qmgr_Name); MQQueue requestQ = new MQQueue(requestQ_Name); QueueConnection qc = qcf.createQueueConnection(); qc.start(); QueueSession session = qc.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); QueueReceiver receiver = session.createReceiver(requestQ); Message requestMsg = receiver.receive(10000); : : 54 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(JMS) ≪ノート≫ JMS サーバ・アプリケーション(続き) : : QueueSender sender = session.createSender((Queue)requestMsg.getJMSReplyTo()); TextMessage replyMsg = session.createTextMessage(“This is a reply message"); replyMsg.setJMSCorrelationID(requestMsg.getJMSMessageID()); sender.send(outMsg); Session.commit(); sender.close(); receiver.close(); session.close(); qc.close(); qc = null; (省略) 55 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> クライアント接続 MQIでクライアント接続を行なう場合 クライアント接続のための設定が必要 " " キュー・マネージャー側にサーバ接続チャネルを用意 クライアント側にクライアント接続チャネルを用意 $ MQSERVER環境変数 $ チャネル定義ファイル コードはローカル接続のときと同じでよい " クライアント接続用ライブラリー(MQICライブラリー)のリンクが必要 $ ローカル接続のときは、MQIライブラリーをリンク 56 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> MQ Javaでのクライアント接続 MQ Javaクライアントと通常のMQクライアントの違い TCP/IPのみサポート クライアント側の設定は全てJavaオブジェクトに行なう " " チャネル定義ファイルは使用できない $ 自動再接続の機能は使用できない 環境変数は使用できない $ MQSERVER、MQCCSID、MQCHLLIB、MQCHLTAB、、、 比較 Base Java クライアント接続 JMS ○ ・チャネル定義ファイルは使用できない ・環境変数は使用できない 57 ○ ・チャネル定義ファイルは使用できない ・環境変数は使用できない Copyright ISE Co., Ltd. <MQ Java デザインのポイント> MQ Javaでのクライアント接続(BaseJava) BJ BaseJavaでクライアント接続を行なう場合 MQEnvironmentの以下の変数に設定 " " " " " hostname(必須) $ サーバ・マシンのホスト名(IPアドレス) channel(必須) $ チャネル名(サーバ接続チャネルと同一名) port $ ポート番号(デフォルトは、1414) userID $ ユーザーID $ ここで、指定したIDでMQにアクセスする CCSID $ デフォルトでは、819がセットされるのでDBCSのCCSIDを持つQMGRと接続できない $ 明示的にDBCSのCCSID(932、943、、、)を設定する必要がある エラーはMQExceptionで指定したログに出力される " デフォルトは、コンソール 58 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(BaseJava) ≪ノート≫ BJ BaseJavaでクライアント接続を行なう場合 (省略) MQEnvironment.hostname = "9.170.X.XXX"; MQEnvironment.channel = "SYSTEM.DEF.SVRCON"; MQEnvironment.port = 1414; MQEnvironment.CCSID = 932; qMgr = new MQQueueManager(qMgrName) (省略) 59 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> MQ Javaでのクライアント接続(JMS) JMS JMSでクライアント接続を行なう場合 QueueConnectionFactoryの以下の属性に設定(WASコンソール、JMSAdminを使用) " " " " " TRANSPORT(必須) $ ”CLIENT”を指定 HOSTNAME(必須) $ サーバ・マシンのホスト名(IPアドレス) CHANNEL(必須) $ チャネル名(サーバ接続チャネルと同一名) PORT $ ポート番号(デフォルトは、1414) CCSID $ デフォルトでは、819がセットされるのでDBCSのCCSIDを持つQMGRと接続できない $ 明示的にDBCSのCCSID(932、943、、、)を設定する必要がある コード内で設定する場合は、QueueConnectionFactoryの上記属性に対応したメソッド を使用 " TRANSPORT属性に指定する値は、"JMSC.MQJMS_TP_CLIENT_MQ_TCPIP"を指定 60 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(JMS) ≪ノート≫ JMS JMSでクライアント接続を行なう場合 コード内で設定する場合 (省略) qcf.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP); qcf.setHostName("9.170.X.XXX"); qcf.setChannel("SYSTEM.DEF.SVRCONN"); qcf.setPort(1414); qcf.setCCSID(932); QueueConnection qc = qcf.createQueueConnection(); (省略) 61 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> アクセス・ユーザー ≪ノート≫ MQ Javaでクライアント接続するときのアクセス・ユーザーID 優先順位 設定 1 サーバー接続チャネル(SVRCONN)のMCAUSER MCAUSER属性に設定したユーザーID MCAUSER 2 ・BaseJavaの場合、プログラム内のMQEnvironmentオブジェクトのuserID userID属性に設定したユーザーID userID (password属性の設定は無効) ・JMSの場合、createQueueConnection("username","password")メソッドで指定したユーザーID (passwordの設定は無効) 3 チャネルの起動ユーザー i) inetdを使用する場合は、inetd.confに指定した起動ユーザーID inetd.confの例) QM1 stream tcp nowait mqm /usr/lpp/mqm/bin/amqcrsta amqcrsta -m QM1 ii) リスナーを使用する場合は、リスナー起動ユーザー 62 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> Browse機能 MQのBrowse機能 キュー内のメッセージを削除せずに参照のみ行なう " メッセージの中身を確認してからGETするかしないかを判断できる Browseでメッセージを待つことができる " MQGMO_WAITを使用 ロックをかけて他のアプリケーションがBrowseしたメッセージをGETできなくすることができる " MQGMO_LOCKを使用 カーサーが指しているメッセージをGETすることができる " MQGMO_MSG_UNDER_CURSERを使用 受信アプリケーション カーサー MQOPEN MQOO_BROWSE MQGET (MQGMO_BROWSE_FIRST) Message 1 MQGET (MQGMO_BROWSE_NEXT) Message 2 MQGET (MQGMO_BROWSE_NEXT) Message 3 MQGET (MQGMO_MSG_UNDER_CURSER) Message 4 63 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> Browse機能 比較 Base Java Browse機能 JMS ◎(MQIと同等の設定が可能) ・GET待ちが可能 ・ロックをかけることができる ・カーサーの指すメッセージをGETできる 64 △ ・GET待ちができない ・ロックがかけられない ・カーサーを使用したメッセージのGETができない Copyright ISE Co., Ltd. <MQ Java デザインのポイント> BJ Browse機能(Base Java) MQIと同じオプションを指定できる MQQueueオブジェクト作成時のaccessQueueメソッドの第二引数(オープン・オプション) にMQC.MQOO_BROWSEをセット openOptions = MQC.MQOO_BROWSE; queue = qMgr.accessQueue(qName, openOptions); 最初のGET時には、MQGetMessageOptionsのoptionsに MQC.MQGMO_BROWSE_FIRSTを指定してGET " カーサーがキュー内の最初のメッセージにセットされる gmo.options = MQC.MQGMO_BROWSE_FIRST; 2回目以降のGET時には、 MQC.MQGMO_BROWSE_NEXTを指定してGET " カーサーがキュー内の次のメッセージに移動する gmo.options = MQC.MQGMO_BROWSE_NEXT; BrowseしたメッセージをGET(キューから削除)する場合は、 MQC.MQGMO_MSG_UNDER_CURSORを指定してGET " カーサーが現在、指しているメッセージをGET gmo.options = MQC.MQGMO_MSG_UNDER_CURSOR; 65 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ(BaseJava) ≪ノート≫ BJ BaseJavaでBrowseを行なう場合 (省略) openOptions |= MQC.MQOO_INPUT_AS_Q_DEF; openOptions |= MQC.MQOO_BROWSE; queue = qMgr.accessQueue(qName, openOptions); for( int s = 0; s < browseCount; s++){ msg = new MQMessage(); gmo = new MQGetMessageOptions(); if(s == 0){ gmo.options |= MQC.MQGMO_BROWSE_FIRST; }else{ gmo.options |= MQC.MQGMO_BROWSE_NEXT; } q.get(msg, gmo); } (省略) 66 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS Browse機能(JMS) JMSのBrowse機能 QueueSessionのcreateBrowserメソッドでQueueBrowserを作成 QueueBrowser browser = (QueueBrowser)session.createBrowser(queue); QueueBrowserのgetEnumerationメソッドでjava.util.Enumerationオブジェクトを取得 " 内部的には、このタイミングでMQOO_BROWSEオプション付きでMQOPENだけを行なう java.util.Enumeration enu = (java.util.Enumeration)browser.getEnumeration(); EnumerationオブジェクトのnextElementメソッドでメッセージを参照 " 内部的には、MQGMO_BROWSE_FIRST/MQGMO_BROWSE_NEXTオプション付きで MQGET Message message = (Message)enu.nextElement(); EnumerationオブジェクトのhasMoreElementsメソッドの戻り値で次のメッセージがあるか を判別 " " true:メッセージあり false:メッセージなし enu.hasMoreElements(); 67 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS Browse機能(JMS) 考慮点 キューにメッセージがないときに、nextElementメソッドを発行するとエラーが発生する " 事前に、hasMoreElementsメソッドでメッセージがあることを確認すること Browse待ちができないので、アプリケーションからポーリングを行なう場合は、 定期的にhasMoreElementsメソッドでメッセージがあるか確認する (省略) for(int i = 0; i < 100; i++){ if(enu.hasMoreElements()){ Message inMsg = (Message)enu.nextElement(); System.out.println("message : " + ((TextMessage)inMsg).getText()); }else{ System.out.println("no message"); Thread.sleep(1000); } } (省略) 68 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ ≪ノート≫ JMS JMSでBrowseを行なう場合 (省略) QueueSession session = qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); QueueBrowser browser = (QueueBrowser)session.createBrowser(queue); java.util.Enumeration enu = (java.util.Enumeration)browser.getEnumeration(); while(enu.hasMoreElements()){ Message inMsg = (Message)enu.nextElement(); if(inMsg instanceof TextMessage){ getMsg = ((TextMessage)inMsg).getText(); System.out.println(“message : " + getMsg); }else{ System.out.println(“message : not text message"); } } (省略) 69 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> メッセージの永続性 ノン・パーシステント・メッセージ キュー・マネージャーの再起動後、メッセージは消失 ログへの書き込みない パーシステント・メッセージと比べ、パフォーマンスはよい パーシステント・メッセージ キュー・マネージャーの再起動を跨って、メッセージを保持 ログへの書き込みあり ノン・パーシステント・メッセージと比べ、パフォーマンスは劣る 比較 Base Java メッセージの永続性 JMS ◎(MQIと同等の設定が可能) ◎ ・デフォルト値がBaseJavaと異なる 70 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> BJ メッセージの永続性(BaseJava) MQIと同様のオプションを指定できる MQMessageオブジェクトのpersistenceに以下の値を設定 " " " MQC.MQPER_PERSISTENCE_AS_Q_DEF:宛先キューの設定に依存(デフォルト) MQC.MQPER_NOT_PERSISTENT:ノン・パーシステント・メッセージ MQC.MQPER_PERSISTENT:パーシステント・メッセージ requestMsg.persistence = MQC.MQPER_PERSISTENT; 71 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS メッセージの永続性(JMS) 以下の2つのオブジェクトに設定可能 Queueオブジェクト " " " JNDIネームスペースに登録している場合は、管理ツールJMSAdminもしくはWASの管理コンソー ルから設定 アプリケーション内で作成している場合は、setPersistenceメソッドで設定 以下のいづれかの値を設定 $ JMSC.MQJMS_PER_APP:QueueSenderの設定に依存(デフォルト値) $ JMSC.MQJMS_PER_QDEF:キューの設定に依存 $ JMSC.MQJMS_PER_PER:パーシステント・メッセージ $ JMSC.MQJMS_PER_NON:ノン・パーシステント・メッセージ QueueSenderオブジェクト " setDeliveryModeメソッドで以下のいづれかの値を指定 $ DeliveryMode.PERSISTENT(デフォルト値) $ DeliveryMode.NON_PERSISTENT sender.setDeliveryMode(DeliveryMode.NON_PERSISTENT); " sendメソッドの引き数に指定することも可能 $ send(Message message, int deliveryMode, int priority, long timeToLive) 72 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> メッセージの永続性(JMS) JMS Queueオブジェクトの設定が優先される " " QueueSenderオブジェクト作成後のMQQueueオブジェクトの設定変更も有効 MQQueueオブジェクトがMQJMS_PER_APPの場合にのみ、QueueSenderでの設定が有効 73 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コード変換 MQのコード変換機能 メッセージのユーザ・データ部分を指定したCCSIDのコードに変換することができる データが全て文字データの場合(MQFMT_STRING)のみ使用可能 " バイナリ・データが混在する場合は、ユーザExitを組み込むことも可能 変換は、以下の2ヶ所で可能(いづれかを選択) " " アプリケーションが受信するとき(通常の方法) $ MQGMO_CONVERTを指定してGET $ GET時にMQMDのCodedCharSetIdに指定したCCSIDのコードに変換される 送信チャネルがメッセージを送信するとき $ 送信チャネルのCONVERT属性をYESに設定 $ 接続先のキュー・マネージャーのCCSID属性に設定されたコードに変換される BaseJavaは、使用可能 JMSは使用不可 キュー・マネージャー 受信アプリケーション MQMD.Format= MQFMT_STRING MQMD.CCSID=5026 5026 ⇒ 943 74 gmo.options = MQGMO_CONVERT msg.CodedCharSetId=943 MQGET Copyright ISE Co., Ltd. <MQ Java デザインのポイント> Java環境でのコード変換 Java環境でのコード変換 Java環境では、文字データ(String)はUnicodeで扱われる " アプリケーション内の文字データとMQメッセージ内の文字データとの間で、 必ず、to/from Unicode変換が行なわれる MQのコード変換機能を使用する必要はない " 使用すると2度コード変換が行なわれることになる BaseJava、JMSとも、文字データをUnicodeから指定したCCSIDに変換してメッセージに セットするメソッドを提供 " 受信後の文字データ取得用のメソッドでは、MQMDのCodedCharSetIdに設定されている CCSIDからUnicodeに変換される Javaアプリケーション キュー・マネージャー Javaアプリケーション 文字データ MQのメソッドによる コード変換 ”あいうえお”(Unicode) BaseJava/JMSメッセージ PUT ”あいうえお”(CCSID:943) MQメッセージ ”あいうえお”(CCSID:943) BaseJava/JMSメッセージ ”あいうえお”(CCSID:943) 文字データ ”あいうえお”(Unicode) 75 GET MQのメソッドによる コード変換 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コード変換 比較 Base Java MQのコード変換 機能(※1) メソッドによる Unicode変換 JMS ◎(MQIと同等の設定が可能) × ・CONVERTオプションの指定ができない ◎ ◎ ※1 Java環境では、MQのコード変換機能は使用しなくてよい 76 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> BJ コード変換(BaseJava) メッセージ作成時のコード変換(Unicode ⇒ 指定CCISD) MQMessageオブジェクトのcharacterSetに変換先のCCSIDを設定し、 writeStringメソッドで文字データをメッセージ・バッファーにセット " " 注意 " 文字データは、Unicodeから指定したCCSIDにコード変換される 設定できるCCSID $ マニュアル「Using Java」のChapter9. The WebSphere MQ base Java classes and interfacesのMQMessageクラスの記述を参照 $ マニュアルには943は出ていないが使用可能 デフォルト値が819となってしまうので、必ず明示的にCCSIDを設定すること msg = new MQMessage(); msg.characterSet = 943; msg.writeString("あいうえお"); writeUTFメソッドを使用するとcharacterSetの値に関係なくUTF(CCSID:1208)に変換 される " " " 先頭に2バイトのLengthを付加したUTF Stringを書き込む writeStringでCCSID 1208を使用した場合はLengthは付加されない writeUTFで作成されたメッセージはreadUTFで取得しないと例外が発生する writeCharsメソッドを使用するとCCSIDの設定に関係なくUnicode(CCSID:1200)に変 換される 77 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コード変換(JMS) JMS メッセージ作成時のコード変換(Unicode ⇒ 指定CCSID) TextMessageオブジェクトのJMS_IBM_Character_SetかQueueオブジェクトのsetCCSID メソッドで変換先のCCSIDを指定し、setTextメソッドで文字データを設定 " " " " 文字データは、Unicodeから指定したCCSIDにコード変換される TextMessageオブジェクトの設定が優先される 指定可能なCCSIDは、BaseJavaと同じ どちらにも設定しないと、デフォルトで、1208(UTF-8)がセットされる message.setStringProperty("JMS_IBM_Character_Set", "943"); message.setText("テストメッセージ"); " " " MQMDのCodedCharSetIdの値は、送信メッセージにMQRFH2が付加されるかどうかで変わる MQRFH2ヘッダ付きメッセージの場合 $ MQMDのCodedCharSetIdは819で固定、MQRFH2のCodedCharSetIdに指定した CCISDがセットされる MQRFH2ヘッダなしメッセージの場合 $ MQMDのCodedCharSetIdに指定したCCSIDがセットされる MapMessageの場合、setStringメソッドでコード変換される StreamMessageの場合、writeStringメソッドでコード変換される 78 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コード変換 注意点 BaseJavaやJMSでCCSIDに指定した値と、実際の変換時に使われる変換テーブルの 紐付けは非公開 " " 例えば、MQMessageオブジェクトのcharacterSetに943を指定した場合、変換にCp943が使用 されるのか、Cp943Cが使用されるのかは公開されていない 幕張のテスト結果では、、 charaterSetの値 使用される変換テーブル 932 SJIS 943 Cp943 930 Cp930 939 Cp939 注意すべきは、943を指定したとき " " Windows上のブラウザからJavaアプリケーションに文字データが入ってきたときは、WASのデフォル ト設定で通常「Cp943C」の変換テーブルが使用される そのデータをMQのメッセージとして送信する場合、943を指定すると「Cp943」が使われ、Java環 境へのインとアウトで異なる変換テーブルを使用することになる 対策および詳細は、ISE NotesDB「ザ・技術」から 「OLTP/MQ Technical Updates 2003 #1」ワークショップ の資料「WAS-MQ連携文字コード」を参照 文字化け 79 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 同期点処理 メッセージのPUT/GET処理に対し同期を取る 1つのキュー・マネージャーへの接続(コネクション・ハンドル)の範囲でUOWを設定 メッセージ処理をUOWに入れるかどうかはPUT/GET時に指定 " MQxMO_SYNCPOINTを設定 MQCMIT/MQBACKで同期点調整 MQPUT (MQPMO_SYNCPOINT) MQGET (MQGMO_SYNCPOINT) MQPUT (MQPMO_SYNCPOINT) MQCMIT MQPUT (MQPMO_SYNCPOINT) MQCMIT MQBACK 比較 Base Java 同期点処理 ◎(MQIと同等の設定が可能) JMS ○ ・PUT/GET単位でUOWに入れるかどうか指定できない ・ MQGMO_SYNCPOINT_IF_PERSISTENTの指定不可 80 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> BJ 同期点処理(BaseJava) MQIと同様のオプションを指定できる メッセージのPUT/GET時に同期点処理を行なうかどうかを指定 PUT/GET単位で指定ができる PUTの場合 " MQPutMessageOptionsオブジェクトのoptionsに以下のいずれかの値を設定 $ MQC.MQPMO_NO_SYNCPOINT:同期点処理なし $ MQC.MQPMO_SYNCPOINT:同期点処理あり pmo.options = MQC.MQPMO_SYNCPOINT; GETの場合 " MQGetMessageOptionsオブジェクトのoptionsに以下のいずれかの値を設定 $ MQC.MQGMO_NO_SYNCPOINT:同期点処理なし $ MQC.MQGMO_SYNCPOINT:同期点処理あり $ MQC.MQGMO_SYNCPOINT_IF_PERSISTENT :パーシステントメッセージの場合は同期点処理ありで受信 gmo.options = MQC.MQGMO_SYNCPOINT; 81 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 同期点処理(BaseJava) BJ 同期点調整 コミット " MQQueueManagerオブジェクトのcommitメソッドを使用 qMgr.commit(); バックアウト " MQQueueManagerオブジェクトのbackoutメソッドを使用 qMgr.backout(); 82 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ ≪ノート≫ BJ BaseJavaでの同期点処理 (省略) MQPutMessageOptions pmo = new MQPutMessageOptions(); pmo.options = MQC.MQPMO_SYNCPOINT; requestQ.put(requestMsg, pmo); : qMgr.commit(); (省略) 83 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS 同期点処理(JMS) QueueSessionに対し同期点処理を行なうかどうかを指定 1メッセージ単位での同期点の指定ができない " " 同期点を指定したQueueSessionを使用するPUT/GET処理は全て1つのUOWに入る MQGMO_SYNCPOINT_IF_PERSISTENTの指定もできない QueueConnectionのcreateQueueSessionメソッドの第一引数にBoolean値を指定 " " true:同期点処理を行なう false:同期点処理を行なわない session = qc.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); 同期点調整 コミット " QueueSessionのcommitメソッドを使用 session.commit(); ロールバック " QueueSessionのrollbackメソッドを使用 session.rollback(); 84 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ ≪ノート≫ JMS JMSでの同期点処理 (省略) QueueSession session = qc.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); QueueReceiver receiver = session.createReceiver(queue); Message inMsg = receiver.receive(); : session.commit(); (省略) 85 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS 同期点処理(JMS) 同期点付きのPUT/GET処理の間に同期点なしの処理を行なう場合は、 QueueSessionオブジェクトを分ける必要がある 同期点付きのQueueSessionと同期点なしのQueueSessionを作成し、処理に応じ使い 分ける (省略) QueueSession qs = qc.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); //同期点付き QueueReceiver receiver = qs.createReceiver(queue1); QueueSender sender = qs.createSender(queue3); QueueSession qsNoSync = qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); //同期点なし QueueSender senderNoSync = qsNoSync.createSender(queue2); Message getMsg = receiver.receiver(); // ①同期点付きのGET senderNoSync.send(getMsg); // ②同期点なしのPUT sender.send(getMsg); // ③同期点付きのPUT session.commit(); (省略) 上の例の場合、③のPUTが失敗すると①でGETしたメッセージはキューにバックアウトされ るが②の処理は正常に処理される 86 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS Message Acknowledge JMSの仕様で規定しているメッセージ受信処理に対する同期点処理 受信したメッセージに対しアプリケーションがAcknowledgeすると、メッセージはキューから 削除される QueueSession作成時、トランザクション属性(createQueueSessionメソッドの第一引 数)をfalseにして、第二引数に以下の3つのオプションのいづれかを指定 " " " Session.AUTO_ACKNOWLEDGE $ アプリケーションがGETした時点で、自動的にAcknowledgeされる Session.CLIENT_ACKNOWLEDGE $ アプリケーションが明示的にAcknowledgeする必要がある $ 受信したMessageオブジェクトのacknowledgeメソッドを発行することでAcknowledgeする $ acknowledgeメソッドを発行したタイミングでメッセージはキューから削除される $ Acknowledgeせずに複数のメッセージを受信している場合、1つのメッセージに対し acknowledgeメソッドを発行するとすべてのメッセージがAcknowledgeされる Session.DUPS_OK_ACKNOWLEDGE $ 2重受信を防ぐためのQueueSessionの処理を軽減させる $ 障害時、2重受信の可能性がある トランザクション属性をtrueとしている場合は、上記オプションに関係なく、コミットした時点 で自動的にAcknowledgeされる 同じQueueSessionで行なわれるPUT処理は、受信メッセージのAcknowledgeに関係な く、処理される 87 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS Message Acknowledge CLIENT_ACKNOWLEDGEの場合のコーディング・イメージ QueueSession session = qc.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE); QueueReceiver receiver = session.createReceiver(queue); Message inMsg = receiver.receive(); : inMsg.acknowledge(); MQでは、内部的にMQの同期点処理機能で実装 AUTO_ACKNOWLEDGE/DUPS_OK_AKNOWLEDGEで受信するときは、内部的には MQGMO_NO_SYNCPOINTオプションでMQGETを発行 CLIENT_ACKNOWLEDGEのときは、MQGMO_SYNCPOINTオプションでMQGETを発行 " acknowledgeメソッド発行時に、内部的にMQCMITを発行 88 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> グローバル・トランザクションへの参加 外部リソース(DB2、Oracleなど)の更新処理とPUT/GETを同一UOWに入れる 2フェーズ・コミットを実施 BaseJavaとJMSとでトランザクション・コーディネーターとなる製品が異なる BaseJavaの場合 " " WebSphere MQ がコーディネーター MQのデータベース・コーディネーション機能を利用可能 JMSの場合 " " WebSphere Application Server がコーディネーター MQのデータベース・コーディネーション機能は利用不可 $ MQはコーディネーターになれない 比較 Base Java グローバル・ トランザクション JMS ◎(MQIと同等の設定が可能) ・MQがコーディネーター ◎ ・WASがコーディネーター 89 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> グローバル・トランザクションへの参加(BaseJava) BJ BaseJavaでグローバル・トランザクションに参加する場合 ※コーディング上の注意点のみ記述 設定、構成面での必要事項は、「システム構成」セッションの資料を参考 MQQueueManagerオブジェクトのメソッドを使用してデータベースとのコネクションを取得 " " " " getJDBCConnection(XADataSource xads, String dbuserId, String dbuserPW) 戻り値は、java.sql.Connection XADataSourceオブジェクトの取得方法は、各データベース製品に依存 DB2の場合 COM.ibm.db2.jdbc.DB2XADataSource xads = new DB2XADataSource(); xads.setDatabaseName("XADB"); Connection dbcon = qmgr.getJDBCConnection(xads, "DB2userID", "DB2userPW"); トランザクションの開始/終了は、MQQueueManagerオブジェクトのメソッドを使用 " " " 開始:beginメソッド コミット:commitメソッド バックアウト:backoutメソッド qMgr.begin(); : qMgr.commit(); 90 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コーディング・イメージ ≪ノート≫ BJ BaseJavaでグローバル・トランザクションに参加する場合 //省略 MQQueueManager qmgr = new MQQueueManager("QMgrName"); COM.ibm.db2.jdbc.DB2XADataSource xads = new DB2XADataSource(); xads.setDatabaseName("XADB"); Connection dbcon = qmgr.getJDBCConnection(xads, "DB2userID", "DB2userPW"); qmgr.begin(); MQQueue q = qmgr.accessQueue(qName, openOptions); MQMessage msg = new MQMessage(); msg.writeUTF("メッセージ"); q.put(msg, putMsgOption); Statement stmt = dbcon.createStatement(); stmt.executeUpdate("<SQL文>'"); qmgr.commit(); //省略 91 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> グローバル・トランザクションへの参加(JMS) JMS JMSでグローバル・トランザクションに参加する場合 ※コーディング上の注意点のみ記述 設定、構成面での必要事項は、「システム構成」セッションの資料を参考 コンテナー管理トランザクションの場合(EJB、MDB) " " " コンテナーがトランザクションを管理 JNDIからXA用のQueueConnectionFactoryを取得 $ このQCFを使用したPUT/GETは自動的にコンテナー管理のグローバル・トランザクション に参加 アプリケーションは、トランザクションを意識したコーディングをする必要はない $ JNDIから取得するQCFは通常通りQueueConnectionFactory型にキャスト $ JMSのオブジェクト作成時やPUT/GET時も特別な指定、コーディングは必要ない $ トランザクションのBegin/Commit/Backoutの指示も必要なし 92 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> グローバル・トランザクションへの参加(JMS) JMS JMSでグローバル・トランザクションに参加する場合(続き) ビーン管理トランザクションの場合(Servlet、EJB、MDB) " " JNDIからXA用のQueueConnectionFactoryを取得 $ JMSWrapXAQueueConnectionFactory $ このQCFを使用したPUT/GETはグローバル・トランザクションに参加できる トランザクションの開始/終了は、アプリケーションが指示 $ javax.jta.UserTransactionのメソッドを使用(オブジェクトはJNDIから取得) $ 開始:beginメソッド $ コミット:commitメソッド $ バックアウト:rollbackメソッド InitialContext ic = new InitialContext(); UserTransaction ut = (UserTransaction)ic.lookup("java:comp/UserTransaction"); ut.begin(); : トランザクション処理 : ut.commit(); 注意:アプリケーション・クライアント(Javaアプリケーション)はグローバル・トランザクションに参加できない 93 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS コーディング・イメージ JMSでグローバル・トランザクションに参加する場合 (省略) InitialContext ic = new InitialContext(); UserTransaction ut = (UserTransaction)ic.lookup("java:comp/UserTransaction"); DataSource ds = (DataSource)ic.lookup("java:comp/env/jdbc/XADS"); QueueConnectionFactory qcf = (QueueConnectionFactory)ic.lookup("java:comp/env/jms/XAQCF"); ut.begin(); //トランザクション開始 QueueConnection qc = qcf.createQueueConnection(); qc.start(); QueueSession session = qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); QueueReceiver receiver = session.createReceiver(requestQ); QueueSender sender = session.createSender(replyQ); java.sql.Connection conn = ds.getConnection(); TextMessage inMsg = (TextMessage)receiver.receive(); //メッセージ受信 String tmp = inMsg.getText(); java.sql.PreparedStatement pst = conn.prepareStatement(sql); int flag = pst.executeUpdate(); //データベース更新 sender.send(inMsg); //メッセージ送信 conn.close(); qc.close(); ut.commit(); //コミット (省略) 94 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コネクション・プーリング MQ Javaが内部的に独自のコネクション・プーリング機能を提供 BaseJava、JMSともに同じ仕組みのプーリングを使用 " 使用方法は若干異なる 使用しなくなった(アプリケーションがDisconnectした)コネクションを切断せずに プールし、再利用する " 事前に指定した数のコネクションをプールする仕組みではない コネクションの保持時間と最大保持数を指定可能 " " 保持時間を超えたコネクションは消去 最大保持数を超える場合、一番古いコネクションから消去 コネクション・プール 保持時間:5分 最大保持数:10個 ②検索 アプリケーション ①MQCONN MQOPEN MQPUT : MQCLOSE ④MQDISC ③取得 キュー・マネージャー ⑤返却 95 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> コネクション・プーリング デフォルト・コネクション・マネージャーを提供 " 保持時間および最大保持数が固定されている 保持時間:5分 最大保持数:10個 独自のコネクション・マネージャーを作成することも可能 " " 保持時間および最大保持数を任意に指定できる 作成したものをデフォルトのコネクション・マネージャーとしてセットできる プールのスコープはコネクション・マネージャー " デフォルトのコネクション・マネージャーを使用している場合は、プロセスごとに1つ ローカル/クライアント接続とも使用可能 比較 Base Java コネクション・ プーリング JMS ◎ ◎ ・BaseJavaの機能を内部的に利用 96 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> BaseJavaのコネクション・プーリング BJ 使用方法は以下の3通り 方法1.デフォルト・コネクション・マネージャーを使用する 方法2.独自のコネクション・マネージャーを作成する 方法3.独自のコネクション・マネージャーを作成し、 デフォルト・コネクション・マネージャーとして使用する 97 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 方法1 BJ 方法1.デフォルト・コネクション・マネージャーを使用 使用方法 ⇒トークン(MQPoolToken)をMQEnvironmentに登録 " MQEnvironmentのaddConnectonPoolTokenメソッドを発行 MQPoolToken token = MQEnvironment.addConnectionPoolToken(); 停止方法 ⇒トークンをMQEnvironmentから削除 " " MQEnvironmentクラスのremoveConnectionPoolTokenメソッドを発行 使用開始時に作成したトークンを引き数に渡す MQEnvironment.removeConnectionPoolToken(token); 複数のスレッドからトークンの登録/削除を行なっている場合、ひとつでもトークンが登録 されている間は、プールは存続 トークンが全て削除されると、プール内のコネクションは全て切断される コネクションの保持時間と最大保持数の設定はできない 98 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> BJ 方法2 方法2.独自のコネクション・マネージャーを作成 使用方法 1. MQSimpleConnectionManagerのインスタンスを作成 MQSimpleConnectionManager mySCM = new MQSimpleConnectionManager(); 2. コネクションの保持時間/最大保持数を設定 % 保持時間:setTimeoutメソッド(ミリ秒) % 保持数 :setHighThresholdメソッド mySCM.setTimeout(3600000); //1時間 mySCM.setHighThreshold(50); //50個 3. プーリングの活動化 setActiveメソッドの引き数に以下の値を指定 MQSimpleConnectionManager.MODE_ACTIVE mySCM.setActive(MQSimpelConnectionManager.MODE_ACTIVE); 4. MQSimpleConnectionManagerをMQQueueManagerのコンストラクタに引き数として渡す MQQueueManager qmgr = new MQQueueManager(“My_QMGR”, mySCM); 99 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 方法2 BJ 停止方法 ⇒プーリングの非活動化 " setActiveメソッドの引き数に以下の値を指定 MQSimpleConnectionManager.MODE_INACTIVE mySCM.setActive(MQSimpelConnectionManager.MODE_INACTIVE); 100 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> BJ 方法3 方法3.独自のコネクション・マネージャーを作成し、 デフォルト・コネクション・マネージャーとして使用 使用方法 1. MQSimpleConnectionManagerのインスタンスを作成 MQSimpleConnectionManager mySCM = new MQSimpleConnectionManager(); 2. コネクションの保持時間/最大保持数を設定 % 保持時間:setTimeoutメソッド(ミリ秒) % 保持数 :setHighThresholdメソッド mySCM.setTimeout(3600000); //1時間 mySCM.setHighThreshold(50); //50個 3. 自動モードに設定 setActiveメソッドの引き数に以下の値を指定 MQSimpleConnectionManager.MODE_AUTO mySCM.setActive(MQSimpelConnectionManager.MODE_AUTO); 4. デフォルトのコネクション・プーリングとしてセット MQEnvironmentのsetDefaultConnectionManagerメソッドの引き数に渡す MQEnvironment.setDefaultConnectionManager(mySCM); 101 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> BJ 方法3 使用方法(続き) 5. トークンの登録 MQEnvironmentのaddConnectonPoolTokenメソッドを発行 MQPoolToken token = MQEnvironment.addConnectionPoolToken(); 停止方法 " トークンの削除 MQEnvironmentクラスのremoveConnectionPoolTokenメソッドを発行 使用開始時に作成したトークンを引き数に渡す MQEnvironment.removeConnectionPoolToken(token); 102 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS JMSのコネクション・プーリング JMSのコネクション・プーリング BaseJavaのコネクション・プーリングを内部的に使用 デフォルト設定のままで、アプリケーションは意識することなく使用できる " " " ただし、キュー・マネージャーと接続されたコネクションが1つでもないと、プール自体がなくなる MQEnvironmentにMQTokenを登録してプーリングの永続化ができる $ BaseJavaの方法1を使用 MQSimpleConnectionManagerを使用してプーリングの設定を行なうこともできる $ BaseJavaの方法3を使用 $ 方法2は使用できない 103 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> BJ エラー処理(BaseJava) BaseJavaのエラー処理 BaseJavaのメソッドは処理が異常終了した場合、MQExceptionをthrowする " 理由コード、完了コードのどちらか1つでも0以外の値の場合、例外がthrowされる 理由コード、完了コードはMQExceptionの変数として定義される " " 理由コード:MQException.reasonCode 完了コード:MQException.completionCode コール毎のエラー・チェックは不要 → 複数コールのエラーをまとめてチェック可能 " try~catchによりMQExceptionをcatchし、その変数を調べることで理由コード、完了コードを取 得 コーディング例 try{ queueA.put(messageA,putMessageOptionsA); queueB.put(messageB,putMessageOptionsB); } catch(MQException ex){ System.out.printIn("An Error occured ;" + "CC =" + ex.completionCode + "RC =" + ex.reasonCode); } 104 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS エラー処理(JMS) JMSのエラー処理 JMSのメソッドは処理が異常終了した場合、JMSExceptionをthrowする " " 内部的にMQExceptionを含む場合がある getLinkedExceptionメソッドでMQExceptionを取得可能 コール毎のエラー・チェックは不要 → 複数コールのエラーをまとめてチェック可能 " " try~catchによりJMSExceptionをcatchし、内容を出力 MQExceptionがリンクされている場合は、理由コード、完了コードを取得 例 try{ : (JMS処理) : } catch(JMSException je){ System.out.printIn("An Error occured :" + je); Exception e = je.getLinkedException(); if(e != null){ System.out.println("linked exception :"); System.out.println(" CC =" + e.completionCode); System.out.println(" RC =" + e.reasonCode); } } 105 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS エラー処理(JMS) 注意点 JMSでは、No_WaitかWait_Interval指定でGETしたとき、キューにメッセージがなくても 例外をthrowせず、正常終了する " " BaseJavaの場合は、MQRC_NO_MSG_AVAILABLE(MQRC:2033)の例外が発生 後続の処理で受信メッセージのオブジェクトに対し操作を行なうと、そのタイミングで例外が発生 してしまう 受信後のメッセージ処理前には、MessageオブジェクトのNullチェックを行なう Message inMsg = receiver.receiveNoWait(); if(inMsg == null){ System.out.println("No message !"); }else{ : メッセージ処理 : } 106 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> トレース機能(BaseJava) BJ トレースの指定は、コード内に記述 MQEnvironmentクラスのメソッドを使用 enableTracing(n) n:トレース・レベル 1から5まで設定可能 " " " " " 1:Entry、Exit、Exception 2:1+パラメーター情報 3:2+MQSeriesヘッダー、データ・ブロック 4:3+ユーザー・データ 5:4+JVMのメソッド・トレース disableTracing()でトレース終了 レベル5のトレースを取得するには、java_g、appletviewer_gでアプリケーションを実行する デフォルトではjavaコンソールに出力される(System.err) " Streamを使用して出力先を指定することも可能 設定例 レベル4のトレースをjmstrace.txtファイルに出力させる場合 FileOutputStream traceFile = new FileOutputStream("jmstrace.txt"); MQEnvironment.enableTracing(4, traceFile); 107 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS トレース機能(JMS) トレースの指定は、JVMの起動パラメータに設定 パラメータ"MQJMS_TRACE_LEVEL"に以下のいづれかの値をセット " " on :MQ JMSレベルのトレース base:MQ base Javaレベルのトレース 出力先ファイル名:mqjms.trc(固定) 出力ディレクトリ:デフォルトでは、コマンド実行ディレクトリに出力 " "MQJMS_TRACE_DIR"で変更可能 設定例 MyJMSProgプログラムのトレースをMQ base Javaレベルで/tmp/jmstrcディレクトリに出 力させる場合 java -DMQJMS_TRACE_LEVEL=base -DMQJMS_TRACE_DIR=/tmp/jmstrc MyJMSProg コーディング内でBaseJavaのトレース機能を利用することも可能 MQEnvironmentのenableTracingメソッドを使用 " BaseJavaレベルのトレースしか取れない 108 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> トレース機能 比較 Base Java トレース機能 JMS ◎ ・コード内に記述する必要がある ・細かいレベル設定が可能 ◎ ・コード内に記述する必要はない ・細かいレベルの設定ができない ・ただし、BaseJavaの機能を利用すれば、 BaseJavaと同じ設定が可能 109 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMSでコーディングする際の注意点 110 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS FAIL_IF_QUIESCING PUT/GET時にFail_If_Quiescingがデフォルトで設定される MQ5.2以前は、設定されていなかった MQQueueConnectionFactoryのsetFailIfQuiesceメソッドに以下の値を渡すことで設定 を変更可能 " " " JMSC.MQJMS_FIQ_YES: Fail_If_Quiescingあり(デフォルト) JMSC.MQJMS_FIQ_NO : Fail_If_Quiescingなし WASのコンソールからは設定できない ただし、テスト(2003.6実施)では JMSC.MQJMS_FIQ_NOの設定は有効ではない " " " " JMSC.MQJMS_FIQ_NOを設定しても、、、 トレース上は、Fail_If_Quiescingが有効になっている アプリケーションがGetWait状態のとき、endmqm( i オプションなし)でキュー・マネージャーは終了 アプリケーションには、即時に、以下の例外が発生 javax.jms.JMSException: MQJMS2002: MQ キューからメッセージを取得できませんでした 補足:MQxMO_FAIL_IF_QUIESCINGオプション " PUT/GET時にキュー・マネージャーが終了中だと、処理を失敗させ、アプリケーションにエラーを 返す 111 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMS JMSのデフォルト値 JMSでは、MQI/BaseJavaでコーディングしたときとデフォルトの設定が異なる Priorityのデフォルト値は、4 " MQI/BaseJavaでは、0 永続性のデフォルト値は、パーシステント " MQI/BaseJavaでは、キューの属性に依存( AS_Q_DEF ) $ キューのデフォルト属性はノン・パーシステントなのでMQI/BaseJavaのデフォルトは、 ノン・パーシステント 112 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 機能比較 BaseJavaとJMSの機能比較表 機能 Base Java JMS仕様 に準拠 JMS グループ化 ◎(MQIと同等の設定が可能) ・キュー・マネージャーによるIDの自動採番 ・全てのMSGが揃ってからGETすることが可能 △ ・ユーザがグループIDや順序番号を設定 ・MQGMO_LOGICAL_ORDERの指定はできない ・MQGMO_ALL_MSGS_AVAILABLEの指定はできない △ セグメント化 ◎(MQIと同等の設定が可能) ×(利用不可) N/A 要求/応答メッセージ の紐付け ◎(MQIと同等の設定が可能) ○ ・メッセージIDを自由に設定できない ○ 応答先の指定/ 応答先への送信 ◎( MQIと同等の設定が可能) ◎ ○ クライアント接続 ○ ・チャネル定義ファイルは使用できない ・環境変数は使用できない ○ ・チャネル定義ファイルは使用できない ・環境変数は使用できない ○ ◎(MQIと同等の設定が可能) ・GET待ちが可能 ・ロックをかけることができる ・現カーサーの指すメッセージをGETできる △ ・GET待ちができない ・ロックがかけられない ・カーサーを使用したメッセージのGETができない ○ メッセージの永続性 ◎(MQIと同等の設定が可能) ◎ ○ MQのコード変換機能 ◎(MQIと同等の設定が可能) × ・CONVERTオプションの指定ができない N/A ◎ ◎ ○ Browse機能 メソッドによる Unicode変換 113 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> 機能比較 BaseJavaとJMSの機能比較表(つづき) 機能 JMS Base Java JMS仕様 に準拠 同期点処理 ◎(MQIと同等の設定が可能) ○ ・PUT/GET単位でUOWに入れるかどうか指定できない ○ グローバル・ トランザクション ◎(MQIと同等の設定が可能) ・MQがコーディネーター ◎ ・WASがコーディネーター ○ コネクション・ プーリング ◎ ◎ ・BaseJavaの機能を内部的に利用 ○(※2) トレース機能 ◎ ・コード内に記述する必要がある ・細かいレベル設定が可能 ◎ ・コード内に記述する必要はない ・細かいレベルの設定ができない N/A Priortyの設定(※1) ◎(MQIと同等の設定が可能) ◎ ・デフォルト値は4に設定される ○ Report機能(※1) ◎(MQIと同等の設定が可能) ◎ × クラスター環境での BINDオプションの設定 (※1) ◎(MQIと同等の設定が可能) △ ・オプションの設定は不可 ・MQBIND_AS_Q_DEFが採用される N/A コンテキストの設定(※1) ◎(MQIと同等の設定が可能) × ・コンテキスト関連のオプションの設定ができない N/A ※1 これらの機能は、当資料で詳細な説明をしていません ※2 BaseJavaのクラスを使用した場合は、JMSの仕様からは外れます 114 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMSヘッダ/プロパティとMQMDの対応 JMS JMSヘッダ/プロパティとMQMDの対応表 JMSヘッダ MQMD JMSDestination MQRFH2 備考 jms.Dst Send Method JMSDeliveryMode Persistence jms.Dlv Send Method JMSExpiration Expiry jms.Exp Send Method JMSPriority Priority jms.Pri Send Method JMSMessageID MessageID - Send Method JMSTimestamp PutDate/PutTime - Send Method JMSCorrelationID CorrelId jms.Cid Message Object JMSReplyTo ReplyToQ/ReplyToQMgr jms.Rto Message Object mcd.Type Message Object - Receive-Only JMSType JMSRedelivered BackoutCount JMSプロパティ MQMD MQRFH2 備考 JMSXUserID UserIdentifier - Send Method JMSXAppID PutApplName - Send Method JMSXDeliveryCount BackoutCount - Receive-Only JMSXGroupID GroupId jms.Gid Message Object JMSXGroupSeq MsgSeqNumber jms.Seq Message Object 115 Copyright ISE Co., Ltd. <MQ Java デザインのポイント> JMSヘッダ/プロパティとMQMDの対応 JMS JMSヘッダ/プロパティとMQMDの対応表 プロバイダ固有JMSプロパティ MQMD MQRFH2 備考 JMS_IBM_Report_Exception Report - Message Object JMS_IBM_Report_Expiration Report - Message Object JMS_IBM_Report_COA Report - Message Object JMS_IBM_Report_COD Report - Message Object JMS_IBM_Report_PAN Report - Message Object JMS_IBM_Report_NAN Report - Message Object JMS_IBM_Report_Pass_Msg_ID Report - Message Object JMS_IBM_Report_Pass_Correl_ID Report - Message Object JMS_IBM_Report_Discard_Msg Report - Message Object JMS_IBM_MsgType MsgType - Message Object JMS_IBM_Feedback Feedback - Message Object JMS_IBM_Format Format - Message Object JMS_IBM_PutApplType PutApplType - Send Method JMS_IBM_Encoding Encoding - Message Object JMS_IBM_Character_Set CodedCharacterSetId - Message Object JMS_IBM_PutDate PutDate - Send Method JMS_IBM_PutTime PutTime - Send Method JMS_IBM_Last_Msg_In_Group MsgFlags - Message Object 116 Copyright ISE Co., Ltd.