MQ Javaデザインのポイント2
Document Sample


MQ Java
デザインのポイント
ISE Web & Transaction System
2003年7月
<MQ Java デザインのポイント>
トピック
Web環境でのメッセージング処理パターン
一方向型
要求/応答型
デザインのポイント
一方向型処理で使用される機能
要求/応答型処理で使用される機能
その他の機能
Base JavaとJMSの機能比較
! 当資料内の情報には、ISEによるテスト結果を基にしたものが含まれています。これらの情報は、マニュ
アルには記載されておらず、今後、変更される可能性があります。
! 当資料内のコーディング・イメージは、アプリケーションとして使用されることを想定していません。(エラー
処理等は省いています) 従って、そのまま使用し、正常に稼動することは保証していません。
Copyright ISE Co., Ltd.
2
<MQ Java デザインのポイント>
メッセージング処理パターン
Copyright ISE Co., Ltd.
3
<MQ Java デザインのポイント>
トピック
Web環境でのメッセージング処理パターン(1)
一方向型
一方向型処理のデザイン
" 複数メッセージ処理
" 1対N通信
Web環境でのメッセージング処理パターン(2)
要求/応答型
要求/応答型と一方向型との混在
要求/応答型処理のデザイン
" 応答メッセージの返却先
" 要求メッセージと応答メッセージの紐付け
" サーバ・アプリケーションの起動方法
" UOWの設定
Copyright ISE Co., Ltd.
4
<MQ Java デザインのポイント>
Web環境でのメッセージング処理パターン(1)
一方向型
1対1、1対Nのデータ送信
送信側アプリケーション
" ブラウザーからのリクエストでデータを送信する
" 論理的な宛先を意識してデータを送信(最終送信先は知らなくて良い)
例)キュー名、トピック名、ポート名 など
受信側アプリケーション
1. ブラウザーからのリクエストでデータを受信する
or
2. サーバ・アプリケーションとして起動され、メッセージを受信、処理する
" 論理的な宛先を意識してデータを受信(送信元は意識しなくて良い)
例)キュー名、トピック名、ポート名 など
MQPUT MQGET
受信側アプリケーション(1)
MQGET
送信側アプリケーション
受信側アプリケーション(2)
Copyright ISE Co., Ltd.
5
<MQ Java デザインのポイント>
一方向型処理のデザイン
複数メッセージをグループとして処理する場合
扱うデータが大きい場合には、複数メッセージに分割して送受信する
" ファイル転送、イメージ・データ転送など
送信側/受信側アプリケーションは、複数メッセージを1UOWとする
複数メッセージ間の紐付け、順序管理を行なう
" MQ論理メッセージ、グループ・メッセージ機能を利用
" MsgID、CorrelIdを利用してグループ化を行なう
MQPUT MQGET
: : :
: : :
MQCMIT MQCMIT
送信側アプリケーション 受信側アプリケーション
Copyright ISE Co., Ltd.
6
<MQ Java デザインのポイント>
一方向型処理のデザイン
全てのメッセージが届いてから、メッセージ受信するためには…
論理メッセージ機能を利用
" MQGET時のオプションにMQGMO_ALL_MSGS_AVALABLEを指定
制御用キューとデータ用キューを利用
" データ用キューに複数メッセージ送信後、制御用キューに制御メッセージを送信
制御メッセージが届けば、データ・メッセージはすべてキューに到着済
" 制御メッセージとデータ・メッセージの紐付けはCorrelIDを利用
MDBで複数メッセージを処理するためには..
MDBは起動時には1メッセージしか受信しない
#起動後、ユーザロジック内で複数メッセージを受信する
制御用キューとデータ用キューを利用
" 制御用キューをリスナー・ポートとして設定
" onMessage() 内で、データ用キュー内のメッセージを受信する
MQPUT MQGET
: : データ用キュー : :
: MDB
MQCMIT
EJBコンテナ
送信側アプリケーション
制御用キュー
Copyright ISE Co., Ltd.
7
<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
" それぞれ機能が異なるので注意
ブローカーの運用、管理、バックアップ
サブスクライバーが受信データを登録する際、セキュリティ・チェックが必要
Copyright ISE Co., Ltd.
8
<MQ Java デザインのポイント>
Web環境でのメッセージング処理パターン(2)
要求/応答型(同期型)
1対1のデータ通信
クライアント・アプリケーション(要求側)
" ブラウザーからのリクエストで、要求メッセージを論理的な宛先に送信
" 応答メッセージの到着を、指定した宛先で待つ
サーバ・アプリケーション(応答側)
" 要求メッセージを待ち、処理、応答メッセージを返す常駐アプリケーション(Javaアプリ)
" メッセージが届いたら、起動されデータを受信、処理、応答を返す(MDB)
UOWは次の3つに分割される
" 要求メッセージの送信
" 要求メッセージの受信、処理、応答メッセージの送信
" 応答メッセージの受信
MQPUT MQGET
INSERT
MQPUT
MQGET
クライアント・
アプリケーション サーバ・アプリケーション
Copyright ISE Co., Ltd.
9
<MQ Java デザインのポイント>
Web環境でのメッセージング処理パターン
要求/応答型と一方向型との混在
クライアント・アプリケーション(要求側)
1. ブラウザーからのリクエストで要求メッセージを論理的な宛先に送信
ブラウザーに受付IDなどを返す
2. ブラウザーから受付IDを受け取り、応答キューからメッセージを受信する
サーバ・アプリケーション(応答側)
" 要求メッセージを待ち、処理、応答メッセージを返す常駐アプリケーション(Javaアプリ)
" メッセージが届いたら、起動されデータを受信、処理、応答を返す(MDB)
MQPUT MQGET
ID INSERT
MQPUT
クライアント・アプリケーション(1)
ID
MQGET サーバ・アプリケーション
クライアント・アプリケーション(2)
Copyright ISE Co., Ltd.
10
<MQ Java デザインのポイント>
要求/応答型処理のデザイン
応答メッセージの返却先
クライアント・アプリケーションが、要求メッセージ内に応答先を指定
" MQMDのReplyToQに応答キュー名を指定
" RepylToQMgrは自動的に設定される
サーバ・アプリケーションは、指定された応答先に応答メッセージを返す
" 要求メッセージ内のReplyToQ、ReplyToQmgr を指定してキューをオープンし、応答を送
信
" キュー・マネージャー名がリモートであれば、同名のトランスミッション・キューがオープンされる
" リモート・キュー定義は不要
RQMNAME(QM2)
RQMNAME(QM2)
QM1(キュー・マネージャー名) RNAME(LQ2) QM2(キュー・マネージャー名)
RNAME(LQ2)
LQ2(ローカル・キュー)
MQOPEN
RQ2 RQ2(リモートキュー) MQチャネル MQOPEN
QM1 、LQ1
クライアント・ (
QM1(XMITQ) サーバ・
アプリケーション LQ1(ローカル・キュー) アプリケーション
トランスミッション・キュー(XMITQ)は、接続相手の
キュー・マネージャーと同一名称に設定する
Copyright ISE Co., Ltd.
11
<MQ Java デザインのポイント>
要求/応答型処理のデザイン
要求メッセージと応答メッセージの紐付け
メッセージID(MsgID)、相関ID(CorrelId)を利用して対応させる
クライアント・アプリケーション
" MQMDのMsgIDを設定:MQに採番させても良い
JMSはMsgIDをユーザ設定できないので、MQに採番させる
" CorrelID=要求メッセージのMsgID で、メッセージを選択して応答キューを待つ
サーバ・アプリケーションは、要求メッセージのMsgIDを応答メッセージのCorrelIDに設
定し返す
複数クライアントで1つの応答キューを共有することが可能
その他
クライアント・アプリケーションは、応答キューを待つタイムアウト値を設定
" WaitInterval指定
照会型のメッセージには、有効期限を設定
" Expiry
クライアント・アプリケーション サーバ・アプリケーション
MQPUT MQGET
MsgID=MQMI_NONE
:
: MQPUT
MQGET CorrelID=要求メッセージのMsgID
CorrelID=要求メッセージのMsgID
Copyright ISE Co., Ltd.
12
<MQ Java デザインのポイント>
要求/応答型処理のデザイン
サーバ・アプリケーションの起動方法
常駐Javaアプリケーション
" トランザクションを開始して、要求キューにメッセージが来るのを待ち受ける
MDB
" リクエスト・メッセージが到着したら、起動されるMDBを作成
UOWの設定
クライアント・アプリケーションの、メッセージ送信と受信のUOWは分かれる
" 同期を取らないと、要求メッセージが送信されないから
サーバ・アプリケーションは、要求メッセージと応答メッセージまでを1つのUOWに設定
" MDBの場合、トランザクションは、コンテナ管理(CMT)と設定する
UOW
MQPUT MQGET
INSERT UOW
MQPUT
MQGET
クライアント・ UOW
アプリケーション サーバ・アプリケーション
Copyright ISE Co., Ltd.
13
<MQ Java デザインのポイント>
デザインのポイント
Copyright ISE Co., Ltd.
14
<MQ Java デザインのポイント>
トピック
デザインのポイント
一方向型処理で使用される機能
" グループ化/セグメント化
応答/要求型処理で使用される機能
" 要求/応答メッセージの紐付け
" 応答先の指定/応答先への送信
その他の機能
" クライアント接続
" Browse機能
" メッセージの永続性
" 同期点処理
" グローバル・トランザクション
" コネクション・プーリング
" エラー処理
" トレース機能
JMSでコーディングする際の注意点
機能比較
Copyright ISE Co., Ltd.
15
<MQ Java デザインのポイント>
一方向型処理で使用される機能
グループ化/セグメント化
大きなデータを複数のメッセージに分割して送信
" ファイル転送、イメージ・データ転送
受信側は、複数メッセージを組み立て、1つのデータとして処理
メッセージの順序性が保証される
同じサーバ・インスタンスで処理される
グループ化
アプリケーションがメッセージの分割/組み立てを行なう
" メッセージは、MQMDのグループID(GroupId)と順序番号(MsgSeqNumber)で関連づけられる
送信アプリケーション 受信アプリケーション
pmo.options gmo.options
= MQPMO_LOGICAL_ORDER GrpID=1
順序番号=1 = MQGMO_LOGICAL_ORDER
MQPUT While(GroupStatus
(MQMF_MSG_IN_GROUP) GrpID=1
順序番号=2 == MQGS_MSG_IN_GROUP)
MQPUT {
(MQMF_MSG_IN_GROUP) GrpID=1
順序番号=3 MQGET
MQPUT }
(MQMF_LAST_MSG_IN_GROUP)
Copyright ISE Co., Ltd.
16
<MQ Java デザインのポイント>
一方向型処理で使用される機能
セグメント化
キュー・マネージャーがメッセージの分割/組み立てを行なう
" キュー・マネージャーもしくはキューの最大メッセージ長(MaxMsgLength)より大きいメッセージを
PUTしたときのみセグメント化が行なわれる
" メッセージは、MQMDのグループID(GroupId)、順序番号(MsgSeqNumber)、オフセット
(Offset)で関連づけられる
アプリケーションは、メッセージの分割/組み立てを行なう必要はない
" PUT/GET時にセグメント化を意識したオプションを設定する必要はある
$ PUT時は、MQMF_SEGMENTATION_ALLOWEDを指定
$ GET時は、MQGMO_COMPLETE_MSGを指定
送信アプリケーション キュー・マネージャー
GrpID=1
順序番号=1 受信アプリケーション
Offset=0
MQPUT
(MQMF_SEGMENTATION_ALLOWED GrpID=1 gmo.options
) 順序番号=1
= MQGMO_COMPLETE_MSG
Offset=10
MQGET
GrpID=1
順序番号=1
Offset=20
Copyright ISE Co., Ltd.
17
<MQ Java デザインのポイント>
グループ化/セグメント化
比較
Base Java JMS
グループ化 ◎(MQIと同等の設定が可能) △
・キュー・マネージャーによるIDの自動採番 ・ユーザがグループIDや順序番号を設定
・全てのMSGが揃ってからGETすることが可能 ・MQGMO_LOGICAL_ORDERの指定はできない
・MQGMO_ALL_MSGS_AVAILABLEの指定はでき
ない
セグメント化 ◎(MQIと同等の設定が可能) ×(利用不可)
注:MQ z/OS版では、セグメント化機能はサポートされていない
Copyright ISE Co., Ltd.
18
<MQ Java デザインのポイント>
グループ化(BaseJava) BJ
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;
Copyright ISE Co., Ltd.
19
<MQ Java デザインのポイント>
グループ化(BaseJava) BJ
受信アプリケーション
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(グループ内の最後のメッセージの場合)
Copyright ISE Co., Ltd.
20
<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();
(省略)
Copyright ISE Co., Ltd.
21
<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);
(省略)
Copyright ISE Co., Ltd.
22
<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);
Copyright ISE Co., Ltd.
23
<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
Copyright ISE Co., Ltd.
24
<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を指定し、
順序番号は他のプロパティを使うことになる
Copyright ISE Co., Ltd.
25
<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);
(省略)
Copyright ISE Co., Ltd.
26
<MQ Java デザインのポイント>
セグメント化(BaseJava) BJ
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;
Copyright ISE Co., Ltd.
27
<MQ Java デザインのポイント>
コーディング・イメージ ≪ノート≫
BJ
送信アプリケーション
10MBのデータをファイル(10MG.dat)から読み取り、セグメント化されることを許可して
メッセージを送信する場合
" キュー・マネージャーもしくはキューの最大メッセージ長が10MBより小さい場合、
メッセージはセグメント化される
(省略)
msg.messageFlags = MQC.MQMF_SEGMENTATION_ALLOWED;
FileInputStream fis = new FileInputStream("10MB.dat");
fis.read(b);
msg.write(b);
queue.put(msg, pmo);
(省略)
Copyright ISE Co., Ltd.
28
<MQ Java デザインのポイント>
コーディング・イメージ ≪ノート≫
BJ
受信アプリケーション
セグメント化されているメッセージを受信する場合
(省略)
gmo.options |= MQC.MQGMO_COMPLETE_MSG;
queue.get(msg, gmo);
(省略)
Copyright ISE Co., Ltd.
29
<MQ Java デザインのポイント>
コーディング・イメージ(Base Java) ≪ノート≫
BJ
BaseJavaの一方向型送信アプリケーション
String QMgr_Name = "QM1";
String Q_Name = "Q1";
String Message = “This is a test message";
MQQueueManager qMgr = null;
MQQueue queue = null;
MQPutMessageOptions pmo = null;
MQMessage msg = null;
int openOptions = 0;
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();
Copyright ISE Co., Ltd.
30
<MQ Java デザインのポイント>
コーディング・イメージ(Base Java) ≪ノート≫
BJ
BaseJavaの一方向型受信アプリケーション
String QMgr_Name = "QM1";
String Q_Name = "Q1";
MQQueueManager qMgr = null;
MQQueue queue = null;
MQGetMessageOptions gmo = null;
MQMessage msg = null;
int openOptions = 0;
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();
Copyright ISE Co., Ltd.
31
<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;
Copyright ISE Co., Ltd.
32
<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;
Copyright ISE Co., Ltd.
33
<MQ Java デザインのポイント>
要求/応答型処理で使用される機能
要求/応答メッセージの紐付け
メッセージID/相関IDを使用して要求メッセージと応答メッセージを紐づける
相関ID指定の受信
応答先の指定/応答先への送信
クライアント側は、要求メッセージに応答先キュー名/キュー・マネージャー名を指定
サーバ側は、指定された応答先へ応答メッセージを送信
クライアント・アプリケーション サーバ・アプリケーション
メッセージID=AAA
PUT GET
要求メッセージ
メッセージID=AAA 要求キュー
ユニークなメッセージ
IDをセット 要求メッセージの
応答先をセット メッセージID⇒相関ID
GET wait PUT
応答メッセージ 要求メッセージのメッセー
(相関ID=AAA) 応答キュー 相関ID=AAA ジIDを応答メッセージの
相関IDにセットし、
応答メッセージのメッ 応答先にPUT
セージIDが相関IDに
セットされている
メッセージを受信
Copyright ISE Co., Ltd.
34
<MQ Java デザインのポイント>
要求/応答型処理で使用される機能
比較
Base Java JMS
要求/応答メッ ◎(MQIと同等の設定が可能) ○
セージの紐付け ・メッセージIDを自由に設定できない
(キュー・マネージャーが自動的に設定する)
応答先の指定 ◎( MQIと同等の設定が可能) ◎
/応答先への
送信
Copyright ISE Co., Ltd.
35
<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);
Copyright ISE Co., Ltd.
36
<MQ Java デザインのポイント>
要求/応答メッセージの紐付け(BaseJava) BJ
サーバ・アプリケーション
受信した要求メッセージのメッセージIDを応答メッセージの相関IDに設定し、送信
" 受信用MQMessageのmessageIdを、送信用MQMessageのcorrelationIdに設定
replyMsg.correlationId = requestMsg.messageId;
replyQ.put(replyMsg, pmo);
Copyright ISE Co., Ltd.
37
<MQ Java デザインのポイント>
応答先の指定/応答先への送信(BaseJava) BJ
クライアント・アプリケーション
要求メッセージに応答先キュー名を指定して送信
" MQMessageのreplyToQueueNameに設定
requestMsg.replyToQueueName = “REP_Q”;
応答先キュー・マネージャー名は自動的に自分の接続しているキュー・マネージャー名が
セットされる
" replyToQueueManagerNameに値を設定する必要はない
Copyright ISE Co., Ltd.
38
<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);
Copyright ISE Co., Ltd.
39
<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);
:
:
Copyright ISE Co., Ltd.
40
<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();
(省略)
Copyright ISE Co., Ltd.
41
<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);
:
:
Copyright ISE Co., Ltd.
42
<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();
(省略)
Copyright ISE Co., Ltd.
43
<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();
(省略)
Copyright ISE Co., Ltd.
44
<MQ Java デザインのポイント>
要求/応答メッセージの紐付け(JMS) JMS
サーバ・アプリケーション
要求メッセージのメッセージIDを取得し、応答メッセージの相関IDに設定
" 要求メッセージのgetJMSMessageIDメソッドで、メッセージIDを取得し、その値を
応答メッセージのsetJMSCorrelationIDメソッドで応答メッセージに設定
replyMsg.setJMSCorrelationID(requestMsg.getJMSMessageID());
Copyright ISE Co., Ltd.
45
<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’ “
Copyright ISE Co., Ltd.
46
<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の検索機能が使える
Copyright ISE Co., Ltd.
47
<MQ Java デザインのポイント>
JMSCorrelationID ≪ノート≫
JMS
JMSメッセージの相関ID(JMSCorrelationID)
アプリケーションから任意の値を設定可能(設定方法は以下の3通り)
1. 文字列を設定
$ 相手がJMSアプリケーションであるときに使用
$ message.setJMSCorrelationID("12345");
$ MQMDのCorrelIdとMQRFH2ヘッダのCidにセットされる
2. 16進数表記の文字列(Prefixとして「ID:」を付加)を設定
$ 受信メッセージのメッセージIDを送信メッセージの相関IDに設定する場合に使用
$ replyMsg.setJMSCorrelationID(requestMsg.getJMSMessageID());
$ MQMDのCorrelIdにのみセットされる
3. バイト配列を設定
$ message.setJMSCorrelationIDAsBytes(b);
$ MQMDのCorrelIdにのみセットされる
値の取得は以下のメソッドを使用
" getJMSCorrelationID()
$ MQRFH2のCidに値がセットされている場合は、その文字列が返る
$ MQMDのCorrelIdにのみ値がセットされている場合は、バイナリ・データの16進数表記に
「ID:」が付加された文字列が返る
" getJMSCorrelationIDAsBytes()
$ MQMDのCorrelIdにセットされているバイナリ・データのバイト配列が返る
Copyright ISE Co., Ltd.
48
<MQ Java デザインのポイント>
JMSメッセージとMQメッセージ ≪ノート≫
JMS
JMSメッセージとMQメッセージの関係(メッセージID/相関ID)
アプリケーション キュー・マネージャー
PUT前のJMSメッセージ
PUT前のJMSメッセージ
前のJMS
Message msg = new Message();
JMSMessageID
msg.setJMSCorrelationID("12345");
MQメッセージ
キュー・マネージャー MQメッセージ
JMSCorrelationID
が生成 MQMD.MessageID
"12345"
414534A32…….
sender.send(msg) MQMD.CorrelID
PUT後のJMSメッセージ
PUT後のJMSメッセージ
後のJMS 3132333435…….
JMSMessageID MQRFH2.CrlID
"ID:414534A32....." "12345"
JMSCorrelationID
msgID = msg.getJMSMessageID(); "12345"
correlID = msg.getJMSCorrelationID();
Copyright ISE Co., Ltd.
49
<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);
Copyright ISE Co., Ltd.
50
<MQ Java デザインのポイント>
応答先の指定/応答先への送信(JMS) JMS
サーバ・アプリケーション
要求メッセージからgetJMSReplyToメソッドでQueueオブジェクトを取得し、
そのオブジェクトをもとにQueueSenderを作成
" オブジェクトには、クライアント側でセットされた応答キュー名とキュー・マネージャー名が設定され
ている
sender = session.createSender((Queue)requestMsg.getJMSReplyTo());
Copyright ISE Co., Ltd.
51
<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);
:
:
Copyright ISE Co., Ltd.
52
<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;
(省略)
Copyright ISE Co., Ltd.
53
<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);
:
:
Copyright ISE Co., Ltd.
54
<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;
(省略)
Copyright ISE Co., Ltd.
55
<MQ Java デザインのポイント>
クライアント接続
MQIでクライアント接続を行なう場合
クライアント接続のための設定が必要
" キュー・マネージャー側にサーバ接続チャネルを用意
" クライアント側にクライアント接続チャネルを用意
$ MQSERVER環境変数
$ チャネル定義ファイル
コードはローカル接続のときと同じでよい
" クライアント接続用ライブラリー(MQICライブラリー)のリンクが必要
$ ローカル接続のときは、MQIライブラリーをリンク
Copyright ISE Co., Ltd.
56
<MQ Java デザインのポイント>
MQ Javaでのクライアント接続
MQ Javaクライアントと通常のMQクライアントの違い
TCP/IPのみサポート
クライアント側の設定は全てJavaオブジェクトに行なう
" チャネル定義ファイルは使用できない
$ 自動再接続の機能は使用できない
" 環境変数は使用できない
$ MQSERVER、MQCCSID、MQCHLLIB、MQCHLTAB、、、
比較
Base Java JMS
クライアント接続 ○ ○
・チャネル定義ファイルは使用できない ・チャネル定義ファイルは使用できない
・環境変数は使用できない ・環境変数は使用できない
Copyright ISE Co., Ltd.
57
<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で指定したログに出力される
" デフォルトは、コンソール
Copyright ISE Co., Ltd.
58
<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)
(省略)
Copyright ISE Co., Ltd.
59
<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"を指定
Copyright ISE Co., Ltd.
60
<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();
(省略)
Copyright ISE Co., Ltd.
61
<MQ Java デザインのポイント>
アクセス・ユーザー ≪ノート≫
MQ Javaでクライアント接続するときのアクセス・ユーザーID
優先順位 設定
1 MCAUSER属性に設定したユーザーID
サーバー接続チャネル(SVRCONN)のMCAUSER
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) リスナーを使用する場合は、リスナー起動ユーザー
Copyright ISE Co., Ltd.
62
<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
Copyright ISE Co., Ltd.
63
<MQ Java デザインのポイント>
Browse機能
比較
Base Java JMS
Browse機能 ◎(MQIと同等の設定が可能) △
・GET待ちが可能 ・GET待ちができない
・ロックをかけることができる ・ロックがかけられない
・カーサーの指すメッセージをGETできる ・カーサーを使用したメッセージのGETができない
Copyright ISE Co., Ltd.
64
<MQ Java デザインのポイント>
Browse機能(Base Java) BJ
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;
Copyright ISE Co., Ltd.
65
<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);
}
(省略)
Copyright ISE Co., Ltd.
66
<MQ Java デザインのポイント>
Browse機能(JMS) 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();
Copyright ISE Co., Ltd.
67
<MQ Java デザインのポイント>
Browse機能(JMS) 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);
}
}
(省略)
Copyright ISE Co., Ltd.
68
<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");
}
}
(省略)
Copyright ISE Co., Ltd.
69
<MQ Java デザインのポイント>
メッセージの永続性
ノン・パーシステント・メッセージ
キュー・マネージャーの再起動後、メッセージは消失
ログへの書き込みない
パーシステント・メッセージと比べ、パフォーマンスはよい
パーシステント・メッセージ
キュー・マネージャーの再起動を跨って、メッセージを保持
ログへの書き込みあり
ノン・パーシステント・メッセージと比べ、パフォーマンスは劣る
比較
Base Java JMS
メッセージの永続性 ◎(MQIと同等の設定が可能) ◎
・デフォルト値がBaseJavaと異なる
Copyright ISE Co., Ltd.
70
<MQ Java デザインのポイント>
メッセージの永続性(BaseJava) BJ
MQIと同様のオプションを指定できる
MQMessageオブジェクトのpersistenceに以下の値を設定
" MQC.MQPER_PERSISTENCE_AS_Q_DEF:宛先キューの設定に依存(デフォルト)
" MQC.MQPER_NOT_PERSISTENT:ノン・パーシステント・メッセージ
" MQC.MQPER_PERSISTENT:パーシステント・メッセージ
requestMsg.persistence = MQC.MQPER_PERSISTENT;
Copyright ISE Co., Ltd.
71
<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)
Copyright ISE Co., Ltd.
72
<MQ Java デザインのポイント>
メッセージの永続性(JMS) JMS
Queueオブジェクトの設定が優先される
" QueueSenderオブジェクト作成後のMQQueueオブジェクトの設定変更も有効
" MQQueueオブジェクトがMQJMS_PER_APPの場合にのみ、QueueSenderでの設定が有効
Copyright ISE Co., Ltd.
73
<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 gmo.options
= MQGMO_CONVERT
msg.CodedCharSetId=943
MQGET
5026 ⇒ 943
Copyright ISE Co., Ltd.
74
<MQ Java デザインのポイント>
Java環境でのコード変換
Java環境でのコード変換
Java環境では、文字データ(String)はUnicodeで扱われる
" アプリケーション内の文字データとMQメッセージ内の文字データとの間で、
必ず、to/from Unicode変換が行なわれる
MQのコード変換機能を使用する必要はない
" 使用すると2度コード変換が行なわれることになる
BaseJava、JMSとも、文字データをUnicodeから指定したCCSIDに変換してメッセージに
セットするメソッドを提供
" 受信後の文字データ取得用のメソッドでは、MQMDのCodedCharSetIdに設定されている
CCSIDからUnicodeに変換される
Javaアプリケーション キュー・マネージャー Javaアプリケーション
文字データ
”あいうえお”(Unicode)
MQのメソッドによる
コード変換
BaseJava/JMSメッセージ MQメッセージ BaseJava/JMSメッセージ
PUT ”あいうえお”(CCSID:943) ”あいうえお”(CCSID:943) ”あいうえお”(CCSID:943) GET
文字データ MQのメソッドによる
コード変換
”あいうえお”(Unicode)
Copyright ISE Co., Ltd.
75
<MQ Java デザインのポイント>
コード変換
比較
Base Java JMS
MQのコード変換 ◎(MQIと同等の設定が可能) ×
機能(※1) ・CONVERTオプションの指定ができない
メソッドによる ◎ ◎
Unicode変換
※1 Java環境では、MQのコード変換機能は使用しなくてよい
Copyright ISE Co., Ltd.
76
<MQ Java デザインのポイント>
コード変換(BaseJava) BJ
メッセージ作成時のコード変換(Unicode ⇒ 指定CCISD)
MQMessageオブジェクトのcharacterSetに変換先のCCSIDを設定し、
writeStringメソッドで文字データをメッセージ・バッファーにセット
" 文字データは、Unicodeから指定したCCSIDにコード変換される
" 設定できるCCSID
$ マニュアル「Using Java」のChapter9. The WebSphere MQ base Java classes and
interfacesのMQMessageクラスの記述を参照
$ マニュアルには943は出ていないが使用可能
注意 " デフォルト値が819となってしまうので、必ず明示的にCCSIDを設定すること
writeUTFメソッドを使用するとcharacterSetの値に関係なくUTF(CCSID:1208)に変換
される
" 先頭に2バイトのLengthを付加したUTF Stringを書き込む
" writeStringでCCSID 1208を使用した場合はLengthは付加されない
" writeUTFで作成されたメッセージはreadUTFで取得しないと例外が発生する
writeCharsメソッドを使用するとCCSIDの設定に関係なくUnicode(CCSID:1200)に変
換される
Copyright ISE Co., Ltd.
77
<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メソッドでコード変換される
Copyright ISE Co., Ltd.
78
<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連携文字コード」を参照
Copyright ISE Co., Ltd.
79
<MQ Java デザインのポイント>
同期点処理
メッセージのPUT/GET処理に対し同期を取る
1つのキュー・マネージャーへの接続(コネクション・ハンドル)の範囲でUOWを設定
メッセージ処理をUOWに入れるかどうかはPUT/GET時に指定
" MQxMO_SYNCPOINTを設定
MQCMIT/MQBACKで同期点調整
MQPUT
(MQPMO_SYNCPOINT) MQGET
(MQGMO_SYNCPOINT)
MQCMIT MQPUT
(MQPMO_SYNCPOINT)
MQPUT
(MQPMO_SYNCPOINT) MQCMIT
MQBACK
比較
Base Java JMS
同期点処理 ◎(MQIと同等の設定が可能) ○
・PUT/GET単位でUOWに入れるかどうか指定できない
・ MQGMO_SYNCPOINT_IF_PERSISTENTの指定不可
Copyright ISE Co., Ltd.
80
<MQ Java デザインのポイント>
同期点処理(BaseJava) BJ
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;
Copyright ISE Co., Ltd.
81
<MQ Java デザインのポイント>
同期点処理(BaseJava) BJ
同期点調整
コミット
" MQQueueManagerオブジェクトのcommitメソッドを使用
qMgr.commit();
バックアウト
" MQQueueManagerオブジェクトのbackoutメソッドを使用
qMgr.backout();
Copyright ISE Co., Ltd.
82
<MQ Java デザインのポイント>
コーディング・イメージ ≪ノート≫
BJ
BaseJavaでの同期点処理
(省略)
MQPutMessageOptions pmo = new MQPutMessageOptions();
pmo.options = MQC.MQPMO_SYNCPOINT;
requestQ.put(requestMsg, pmo);
:
qMgr.commit();
(省略)
Copyright ISE Co., Ltd.
83
<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();
Copyright ISE Co., Ltd.
84
<MQ Java デザインのポイント>
コーディング・イメージ ≪ノート≫
JMS
JMSでの同期点処理
(省略)
QueueSession session = qc.createQueueSession(true, Session.AUTO_ACKNOWLEDGE);
QueueReceiver receiver = session.createReceiver(queue);
Message inMsg = receiver.receive();
:
session.commit();
(省略)
Copyright ISE Co., Ltd.
85
<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したメッセージはキューにバックアウトされ
るが②の処理は正常に処理される
Copyright ISE Co., Ltd.
86
<MQ Java デザインのポイント>
Message Acknowledge JMS
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に関係な
く、処理される
Copyright ISE Co., Ltd.
87
<MQ Java デザインのポイント>
Message Acknowledge JMS
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を発行
Copyright ISE Co., Ltd.
88
<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がコーディネーター
Copyright ISE Co., Ltd.
89
<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();
Copyright ISE Co., Ltd.
90
<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();
//省略
Copyright ISE Co., Ltd.
91
<MQ Java デザインのポイント>
グローバル・トランザクションへの参加(JMS) JMS
JMSでグローバル・トランザクションに参加する場合
※コーディング上の注意点のみ記述
設定、構成面での必要事項は、「システム構成」セッションの資料を参考
コンテナー管理トランザクションの場合(EJB、MDB)
" コンテナーがトランザクションを管理
" JNDIからXA用のQueueConnectionFactoryを取得
$ このQCFを使用したPUT/GETは自動的にコンテナー管理のグローバル・トランザクション
に参加
" アプリケーションは、トランザクションを意識したコーディングをする必要はない
$ JNDIから取得するQCFは通常通りQueueConnectionFactory型にキャスト
$ JMSのオブジェクト作成時やPUT/GET時も特別な指定、コーディングは必要ない
$ トランザクションのBegin/Commit/Backoutの指示も必要なし
Copyright ISE Co., Ltd.
92
<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アプリケーション)はグローバル・トランザクションに参加できない
Copyright ISE Co., Ltd.
93
<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(); //コミット
(省略)
Copyright ISE Co., Ltd.
94
<MQ Java デザインのポイント>
コネクション・プーリング
MQ Javaが内部的に独自のコネクション・プーリング機能を提供
BaseJava、JMSともに同じ仕組みのプーリングを使用
" 使用方法は若干異なる
使用しなくなった(アプリケーションがDisconnectした)コネクションを切断せずに
プールし、再利用する
" 事前に指定した数のコネクションをプールする仕組みではない
コネクションの保持時間と最大保持数を指定可能
" 保持時間を超えたコネクションは消去
" 最大保持数を超える場合、一番古いコネクションから消去
コネクション・プール
保持時間:5分
最大保持数:10個
②検索
アプリケーション
③取得 キュー・マネージャー
①MQCONN ⑤返却
MQOPEN
MQPUT
:
MQCLOSE
④MQDISC
Copyright ISE Co., Ltd.
95
<MQ Java デザインのポイント>
コネクション・プーリング
デフォルト・コネクション・マネージャーを提供
" 保持時間および最大保持数が固定されている
保持時間:5分
最大保持数:10個
独自のコネクション・マネージャーを作成することも可能
" 保持時間および最大保持数を任意に指定できる
" 作成したものをデフォルトのコネクション・マネージャーとしてセットできる
プールのスコープはコネクション・マネージャー
" デフォルトのコネクション・マネージャーを使用している場合は、プロセスごとに1つ
ローカル/クライアント接続とも使用可能
比較
Base Java JMS
コネクション・ ◎ ◎
プーリング ・BaseJavaの機能を内部的に利用
Copyright ISE Co., Ltd.
96
<MQ Java デザインのポイント>
BaseJavaのコネクション・プーリング BJ
使用方法は以下の3通り
方法1.デフォルト・コネクション・マネージャーを使用する
方法2.独自のコネクション・マネージャーを作成する
方法3.独自のコネクション・マネージャーを作成し、
デフォルト・コネクション・マネージャーとして使用する
Copyright ISE Co., Ltd.
97
<MQ Java デザインのポイント>
方法1 BJ
方法1.デフォルト・コネクション・マネージャーを使用
使用方法 ⇒トークン(MQPoolToken)をMQEnvironmentに登録
" MQEnvironmentのaddConnectonPoolTokenメソッドを発行
MQPoolToken token = MQEnvironment.addConnectionPoolToken();
停止方法 ⇒トークンをMQEnvironmentから削除
" MQEnvironmentクラスのremoveConnectionPoolTokenメソッドを発行
" 使用開始時に作成したトークンを引き数に渡す
MQEnvironment.removeConnectionPoolToken(token);
複数のスレッドからトークンの登録/削除を行なっている場合、ひとつでもトークンが登録
されている間は、プールは存続
トークンが全て削除されると、プール内のコネクションは全て切断される
コネクションの保持時間と最大保持数の設定はできない
Copyright ISE Co., Ltd.
98
<MQ Java デザインのポイント>
方法2 BJ
方法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);
Copyright ISE Co., Ltd.
99
<MQ Java デザインのポイント>
方法2 BJ
停止方法 ⇒プーリングの非活動化
" setActiveメソッドの引き数に以下の値を指定
MQSimpleConnectionManager.MODE_INACTIVE
mySCM.setActive(MQSimpelConnectionManager.MODE_INACTIVE);
Copyright ISE Co., Ltd.
100
<MQ Java デザインのポイント>
方法3 BJ
方法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);
Copyright ISE Co., Ltd.
101
<MQ Java デザインのポイント>
方法3 BJ
使用方法(続き)
5. トークンの登録
MQEnvironmentのaddConnectonPoolTokenメソッドを発行
MQPoolToken token = MQEnvironment.addConnectionPoolToken();
停止方法
" トークンの削除
MQEnvironmentクラスのremoveConnectionPoolTokenメソッドを発行
使用開始時に作成したトークンを引き数に渡す
MQEnvironment.removeConnectionPoolToken(token);
Copyright ISE Co., Ltd.
102
<MQ Java デザインのポイント>
JMSのコネクション・プーリング JMS
JMSのコネクション・プーリング
BaseJavaのコネクション・プーリングを内部的に使用
デフォルト設定のままで、アプリケーションは意識することなく使用できる
" ただし、キュー・マネージャーと接続されたコネクションが1つでもないと、プール自体がなくなる
" MQEnvironmentにMQTokenを登録してプーリングの永続化ができる
$ BaseJavaの方法1を使用
" MQSimpleConnectionManagerを使用してプーリングの設定を行なうこともできる
$ BaseJavaの方法3を使用
$ 方法2は使用できない
Copyright ISE Co., Ltd.
103
<MQ Java デザインのポイント>
エラー処理(BaseJava) BJ
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);
}
Copyright ISE Co., Ltd.
104
<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);
}
}
Copyright ISE Co., Ltd.
105
<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{
:
メッセージ処理
:
}
Copyright ISE Co., Ltd.
106
<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);
Copyright ISE Co., Ltd.
107
<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レベルのトレースしか取れない
Copyright ISE Co., Ltd.
108
<MQ Java デザインのポイント>
トレース機能
比較
Base Java JMS
トレース機能 ◎ ◎
・コード内に記述する必要がある ・コード内に記述する必要はない
・細かいレベル設定が可能 ・細かいレベルの設定ができない
・ただし、BaseJavaの機能を利用すれば、
BaseJavaと同じ設定が可能
Copyright ISE Co., Ltd.
109
<MQ Java デザインのポイント>
JMSでコーディングする際の注意点
Copyright ISE Co., Ltd.
110
<MQ Java デザインのポイント>
FAIL_IF_QUIESCING JMS
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時にキュー・マネージャーが終了中だと、処理を失敗させ、アプリケーションにエラーを
返す
Copyright ISE Co., Ltd.
111
<MQ Java デザインのポイント>
JMSのデフォルト値 JMS
JMSでは、MQI/BaseJavaでコーディングしたときとデフォルトの設定が異なる
Priorityのデフォルト値は、4
" MQI/BaseJavaでは、0
永続性のデフォルト値は、パーシステント
" MQI/BaseJavaでは、キューの属性に依存( AS_Q_DEF )
$ キューのデフォルト属性はノン・パーシステントなのでMQI/BaseJavaのデフォルトは、
ノン・パーシステント
Copyright ISE Co., Ltd.
112
<MQ Java デザインのポイント>
機能比較
BaseJavaとJMSの機能比較表
機能 Base Java JMS JMS仕様
に準拠
グループ化 ◎(MQIと同等の設定が可能) △ △
・キュー・マネージャーによるIDの自動採番 ・ユーザがグループIDや順序番号を設定
・全てのMSGが揃ってからGETすることが可能 ・MQGMO_LOGICAL_ORDERの指定はできない
・MQGMO_ALL_MSGS_AVAILABLEの指定はできない
セグメント化 ◎(MQIと同等の設定が可能) ×(利用不可) N/A
要求/応答メッセージ ◎(MQIと同等の設定が可能) ○ ○
の紐付け ・メッセージIDを自由に設定できない
応答先の指定/ ◎( MQIと同等の設定が可能) ◎ ○
応答先への送信
クライアント接続 ○ ○ ○
・チャネル定義ファイルは使用できない ・チャネル定義ファイルは使用できない
・環境変数は使用できない ・環境変数は使用できない
Browse機能 ◎(MQIと同等の設定が可能) △ ○
・GET待ちが可能 ・GET待ちができない
・ロックをかけることができる ・ロックがかけられない
・現カーサーの指すメッセージをGETできる ・カーサーを使用したメッセージのGETができない
メッセージの永続性 ◎(MQIと同等の設定が可能) ◎ ○
MQのコード変換機能 ◎(MQIと同等の設定が可能) × N/A
・CONVERTオプションの指定ができない
メソッドによる ◎ ◎ ○
Unicode変換
Copyright ISE Co., Ltd.
113
<MQ Java デザインのポイント>
機能比較
BaseJavaとJMSの機能比較表(つづき)
機能 Base Java JMS JMS仕様
に準拠
同期点処理 ◎(MQIと同等の設定が可能) ○ ○
・PUT/GET単位でUOWに入れるかどうか指定できない
グローバル・ ◎(MQIと同等の設定が可能) ◎ ○
トランザクション ・MQがコーディネーター ・WASがコーディネーター
コネクション・ ◎ ◎ ○(※2)
プーリング ・BaseJavaの機能を内部的に利用
トレース機能 ◎ ◎ N/A
・コード内に記述する必要がある ・コード内に記述する必要はない
・細かいレベル設定が可能 ・細かいレベルの設定ができない
Priortyの設定(※1) ◎(MQIと同等の設定が可能) ◎ ○
・デフォルト値は4に設定される
Report機能(※1) ◎(MQIと同等の設定が可能) ◎ ×
クラスター環境での ◎(MQIと同等の設定が可能) △ N/A
BINDオプションの設定 ・オプションの設定は不可
(※1) ・MQBIND_AS_Q_DEFが採用される
コンテキストの設定(※1) ◎(MQIと同等の設定が可能) × N/A
・コンテキスト関連のオプションの設定ができない
※1 これらの機能は、当資料で詳細な説明をしていません
※2 BaseJavaのクラスを使用した場合は、JMSの仕様からは外れます
Copyright ISE Co., Ltd.
114
<MQ Java デザインのポイント>
JMSヘッダ/プロパティとMQMDの対応 JMS
JMSヘッダ/プロパティとMQMDの対応表
JMSヘッダ MQMD MQRFH2 備考
JMSDestination 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
JMSType mcd.Type Message Object
JMSRedelivered BackoutCount - Receive-Only
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
Copyright ISE Co., Ltd.
115
<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
Copyright ISE Co., Ltd.
116
Get documents about "