[MQ学習②]javaアプリからMQI Client経由でIBM MQにエンキュー/デキュー

# はじめに

IBM MQの公式チュートリアルを引き続き進める。今回は以下の記事、javaアプリからMQI Client経由でIBM MQにエンキュー/デキューする手順をやってみる。

https://developer.ibm.com/learningpaths/ibm-mq-badge/write-run-first-mq-app/

環境は前回作ったコンテナ環境を引き続き利用する。

https://qiita.com/alphajinsei/items/cdbd82b7ac097f15ea57

完成イメージは以下。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523824/f6ee04d9-8bbc-ad35-18b7-3e9701a9ff54.png)


### 補足 : MQIチャネルでの接続について

https://www.ibm.com/docs/ja/ibm-mq/9.2?topic=types-channels#q003220___title__4


MQのキューのやり取りの方式は、

* メッセージチャネル
    * ２つのMQキューマネージャー同士が接続。
    * 単方向チャネル。
    * 送信元キューマネージャーからチャネル開始・終了する
    * [MQ虎の巻](https://community.ibm.com/community/user/integration/viewdocument/mq-mq-v7)でいうところの「キューマネージャー接続」に相当
* MQIチャネル
    * アプリケーションがMQIclientを介して、１つのMQキューマネージャーと接続。
    * 双方向チャネル。
    * アプリケーション側からコネクションを確立・切断する
    * [MQ虎の巻](https://community.ibm.com/community/user/integration/viewdocument/mq-mq-v7)でいうところの「MQクライアント接続」に相当

の主に２つが存在するが、今回は後者に相当する。双方向チャネルということで、Javaアプリ始動でキューマネージャーとの間にMQIチャネルを作り、その接続の中でエンキューとデキューを続けざまに行うことを目指す。コネクション確立・切断がどちらもjavaアプリ側始動であるさまも同時に確認する。


↓公式のMQIチャネルの図。（左右逆だが）これが今回想定する接続形式。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523824/80b456e1-8786-260b-ad6f-75c239769816.png)

↓MQ虎の巻より「MQクライアント接続」の図。本来はこういう（クライアントAが入れて、クライアントBが取る）使い方と思うが、今回は検証用途でエンキューもデキューも同一アプリから行う。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523824/5f34eaa3-9595-fe38-4080-f62586dc98ee.png)


# MQの構築
この手順は、公式チュートリアルに従ってMQコンテナを立てていれば不要。
公式手順をそのまま実施すると、コンテナ起動時に、デフォルトでキューマネージャ・リスナ・サーバ接続チャネル・ローカルキューが作成されているため。

ここでは、勉強目的として一部手動で環境構築する手順を記載する。

### MQコンテナの起動

[前回の手順](https://qiita.com/alphajinsei/items/cdbd82b7ac097f15ea57)とほぼ同様だが、
`--env MQ_DEV=false`とすることで、デフォルト作成されるオブジェクトが作成されないようにする。

https://github.com/ibm-messaging/mq-container/blob/master/docs/developer-config.md#details-of-the-default-configuration

```bash
docker pull icr.io/ibm-messaging/mq:9.2.4.0-r1

docker volume create qm1data

docker run \
--name QM1 \
--detach \
--rm \
--volume qm1data:/mnt/mqm \
--publish 1414:1414 \
--publish 9443:9443 \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
--env MQ_DEV=false \          #★
--env MQ_APP_USER=app \
--env MQ_APP_PASSWORD=passw0rd \
--env MQ_ADMIN_USER=admin \
--env MQ_ADMIN_PASSWORD=passw0rd \
icr.io/ibm-messaging/mq:9.2.4.0-r1

# コンテナにログイン
docker exec -it QM1 bash
```

### キューマネージャ・リスナの存在確認

デフォルト作成抑止しても、それでもキューマネージャ・リスナは作成される。
リスナを新規作成するとしてポート転送等がまた面倒なため今回は作成確認のみとする。

```bash
# キューマネージャー存在、起動中を確認
bash-4.4$ dspmq
QMNAME(QM1)                        STATUS(Running)

# リスナ存在、起動中を確認
bash-4.4$ echo "DISPLAY LSSTATUS(*) ALL" | runmqsc QM1
5724-H72 (C) Copyright IBM Corp. 1994, 2021.
Starting MQSC for queue manager QM1.


     1 : DISPLAY LSSTATUS(*) ALL
AMQ8631I: Display listener status details.
   LISTENER(SYSTEM.LISTENER.TCP.1)         STATUS(RUNNING)
   PID(316)                                STARTDA(2024-12-14)
   STARTTI(12.24.11)                       DESCR( )
   TRPTYPE(TCP)                            CONTROL(QMGR)
   IPADDR(*)                               PORT(1414)
   BACKLOG(100)
One MQSC command read.
No commands have a syntax error.
All valid MQSC commands were processed.
```

### キュー・チャネルの作成

```bash
bash-4.4$ runmqsc QM1
5724-H72 (C) Copyright IBM Corp. 1994, 2021.
Starting MQSC for queue manager QM1.

# ローカルキュー作成
define qlocal(DEV.QUEUE.1)
     1 : define qlocal(DEV.QUEUE.1)
AMQ8006I: IBM MQ queue created.

# ローカルキュー作成確認 
display qlocal(DEV*) ALL
     2 : display qlocal(DEV*) ALL
AMQ8409I: Display Queue details.
   QUEUE(DEV.QUEUE.1)                      TYPE(QLOCAL)
   ACCTQ(QMGR)                             ALTDATE(2024-12-14)
   ALTTIME(12.25.43)                       BOQNAME( )
   BOTHRESH(0)                             CLUSNL( )
   CLUSTER( )                              CLCHNAME( )
   CLWLPRTY(0)                             CLWLRANK(0)
   CLWLUSEQ(QMGR)                          CRDATE(2024-12-14)
   CRTIME(12.25.43)                        CURDEPTH(0)
   CUSTOM( )                               DEFBIND(OPEN)
   DEFPRTY(0)                              DEFPSIST(NO)
   DEFPRESP(SYNC)                          DEFREADA(NO)
   DEFSOPT(SHARED)                         DEFTYPE(PREDEFINED)
   DESCR( )                                DISTL(NO)
   GET(ENABLED)                            HARDENBO
   IMGRCOVQ(QMGR)                          INITQ( )
   IPPROCS(0)                              MAXDEPTH(5000)
   MAXMSGL(4194304)                        MAXFSIZE(DEFAULT)
   MONQ(QMGR)                              MSGDLVSQ(PRIORITY)
   NOTRIGGER                               NPMCLASS(NORMAL)
   OPPROCS(0)                              PROCESS( )
   PUT(ENABLED)                            PROPCTL(COMPAT)
   QDEPTHHI(80)                            QDEPTHLO(20)
   QDPHIEV(DISABLED)                       QDPLOEV(DISABLED)
   QDPMAXEV(ENABLED)                       QSVCIEV(NONE)
   QSVCINT(999999999)                      RETINTVL(999999999)
   SCOPE(QMGR)                             SHARE
   STATQ(QMGR)                             STREAMQ( )
   STRMQOS(BESTEF)                         TRIGDATA( )
   TRIGDPTH(1)                             TRIGMPRI(0)
   TRIGTYPE(FIRST)                         USAGE(NORMAL)

# サーバ接続チャネル作成
define channel(DEV.APP.SVRCONN) chltype(svrconn) MCAUSER(app) replace
     3 : define channel(DEV.APP.SVRCONN) chltype(svrconn) MCAUSER(app) replace
AMQ8014I: IBM MQ channel created.

# サーバ接続チャネル作成確認
display channel(DEV*) all
     4 : display channel(DEV*) all
AMQ8414I: Display Channel details.
   CHANNEL(DEV.APP.SVRCONN)                CHLTYPE(SVRCONN)
   ALTDATE(2024-12-14)                     ALTTIME(12.26.14)
   CERTLABL( )                             COMPHDR(NONE)
   COMPMSG(NONE)                           DESCR( )
   DISCINT(0)                              HBINT(300)
   KAINT(AUTO)                             MAXINST(999999999)
   MAXINSTC(999999999)                     MAXMSGL(4194304)
   MCAUSER(APP)                            MONCHL(QMGR)
   RCVDATA( )                              RCVEXIT( )
   SCYDATA( )                              SCYEXIT( )
   SENDDATA( )                             SENDEXIT( )
   SHARECNV(10)                            SSLCAUTH(REQUIRED)
   SSLCIPH( )                              SSLPEER( )
   TRPTYPE(TCP)
```


### ユーザに権限を追加

appユーザが、キューマネージャに接続、キューにput,get する権限を追加する。
※ユーザー自体はコンテナ構築時に作成されている模様？ただどこに作成されているのわからず。

```bash
# appユーザがキューマネージャに接続する権限を追加
bash-4.4$ setmqaut -m QM1 -t qmgr -p app +inq +connect
The setmqaut command completed successfully.

# 想定通りQM1に対してconnectする権限が追加されたことを確認
bash-4.4$ dspmqaut -m QM1 -t qmgr -p app
Entity app has the following authorizations for object QM1:
        inq
        connect

# appユーザがキューを操作する権限を追加
bash-4.4$ setmqaut -m QM1 -t queue -n DEV.QUEUE.1 -p app +get +browse +put +inq
The setmqaut command completed successfully.

# 想定通りキュー操作権限がついたことを確認。
bash-4.4$ dspmqaut -m QM1 -t queue -n DEV.QUEUE.1 -p app
Entity app has the following authorizations for object DEV.QUEUE.1:
        get
        browse
        put
        inq
```



# javaアプリの実装

ここからが本題。

### jdkのインストール

jdk11が必要とのことで、以下を参考に導入する。

https://qiita.com/dingtianhongjie/items/7d56dfd264c36d1c024d



せっかくなのでjdkの取得元は、チュートリアル内でIBMから紹介されているIBM Semeru を利用。

https://developer.ibm.com/languages/java/semeru-runtimes/downloads/?version=11



```bash
# IBM semaru のtarをwgetして展開
[root@my-instance ~]# mkdir /usr/java
[root@my-instance ~]# cd /usr/java
[root@my-instance java]# wget https://github.com/ibmruntimes/semeru11-binaries/releases/download/jdk-11.0.25%2B9_openj9-0.48.0/ibm-semeru-open-jdk_x64_linux_11.0.25_9_openj9-0.48.0.tar.gz
[root@my-instance java]# tar zxvf ibm-semeru-open-jdk_x64_linux_11.0.25_9_openj9-0.48.0.tar.gz

# bashrc に以下を記載
[root@my-instance tmp]# cat ~/.bashrc  | tail -3
export JAVA_HOME=/usr/java/jdk-11.0.25+9/
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib

[root@my-instance ~]# source .bashrc
[root@my-instance ~]# java --version
openjdk 11.0.25 2024-10-15
IBM Semeru Runtime Open Edition 11.0.25.0 (build 11.0.25+9)
Eclipse OpenJ9 VM 11.0.25.0 (build openj9-0.48.0, JRE 11 Linux amd64-64-Bit Compressed References 20241107_1233 (JIT enabled, AOT enabled)
OpenJ9   - 1d5831436e
OMR      - d10a4d553
JCL      - edded3f65c based on jdk-11.0.25+9)

```



### 資材のダウンロード

```bash
[root@my-instance ~]# mkdir MQClient
[root@my-instance ~]# cd MQClient

# 資材のDL。MQのclient、JMSのAPIと、後で使うのであろうjsonのライブラリをダウンロード
[root@my-instance MQClient]#  curl -o com.ibm.mq.allclient-9.3.0.0.jar https://repo1.maven.org/maven2/com/ibm/mq/com.ibm.mq.allclient/9.3.0.0/com.ibm.mq.allclient-9.3.0.0.jar
[root@my-instance MQClient]#  curl -o javax.jms-api-2.0.1.jar https://repo1.maven.org/maven2/javax/jms/javax.jms-api/2.0.1/javax.jms-api-2.0.1.jar
[root@my-instance MQClient]#  curl -o json-20220320.jar https://repo1.maven.org/maven2/org/json/json/20220320/json-20220320.jar
```

資材をDLする。
* `com.ibm.mq.allclient-9.3.0.0.jar `がくだんのIBM MQ MQI Clientと思われる。
* `javax.jms-api-2.0.1.jar`はJMS(java messaging service) なるメッセージングサービスを利用するための標準API。


JMSの仕様に沿ったメッセージングAPIの実装の一つとして(?)MQI Clientがある、という立ち位置。

先に↓のサンプルコードの一部を抜粋すると、
最初に以下のようにJMSの引数にMQI Client(`WMQConstants.WMQ_PROVIDER`)を与える形でJMSのコネクションを作成し、
```java
// Create a connection factory
JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
JmsConnectionFactory cf = ff.createConnectionFactory();
```

以降はJMSのAPIを叩く形で通信できる。
```java
// Create JMS objects
context = cf.createContext();
destination = context.createQueue("queue:///" + QUEUE_NAME);
(略)
//メッセージをエンキュー
producer = context.createProducer();
producer.send(destination, message);
```

 ### サンプルコードのダウンロード

```bash
[root@my-instance MQClient]# mkdir -p com/ibm/mq/samples/jms
[root@my-instance MQClient]#  cd com/ibm/mq/samples/jms
[root@my-instance jms]# pwd
/root/MQClient/com/ibm/mq/samples/jms

# サンプルコードのDL
[root@my-instance jms]#  curl -o JmsPutGet.java https://raw.githubusercontent.com/ibm-messaging/mq-dev-samples/master/gettingStarted/jms/com/ibm/mq/samples/jms/JmsPutGet.java
```

コードの詳細は以下を参照。

https://github.com/ibm-messaging/mq-dev-samples/blob/master/gettingStarted/jms/com/ibm/mq/samples/jms/JmsPutGet.java

main関数内だけ抜粋したものが以下。対象キューに「Your lucky number today is XXX」というメッセージをPUTして、その後すぐGETする処理。putされた直後、デキュー→チャネル切断される前のキューとチャネルの状態が見たいので、★箇所のみ追記している

```java
        public static void main(String[] args) {
                // Sanity check main() arguments and warn user
                if (args.length > 0) {
                        System.out.println("\n!!!! WARNING: You have provided arguments to the Java main() function. JVM arguments (such as -Djavax.net.ssl.trustStore) must be passed before the main class or .jar you wish to run.\n\n");
                        Console c = System.console();
                        System.out.println("Press the Enter key to continue");
                        c.readLine();
                }

                // Variables
                JMSContext context = null;
                Destination destination = null;
                JMSProducer producer = null;
                JMSConsumer consumer = null;



                try {
                        // Create a connection factory
                        // JMSの引数にMQIClientを渡し、JMSのconnection factoryを生成する
                        JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
                        JmsConnectionFactory cf = ff.createConnectionFactory();

                        // Set the properties
                        cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, HOST);
                        cf.setIntProperty(WMQConstants.WMQ_PORT, PORT);
                        cf.setStringProperty(WMQConstants.WMQ_CHANNEL, CHANNEL);
                        cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
                        cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, QMGR);
                        cf.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "JmsPutGet (JMS)");
                        cf.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
                        cf.setStringProperty(WMQConstants.USERID, APP_USER);
                        cf.setStringProperty(WMQConstants.PASSWORD, APP_PASSWORD);
                        //cf.setStringProperty(WMQConstants.WMQ_SSL_CIPHER_SUITE, "*TLS12ORHIGHER");

                        // Create JMS objects
                        // JMS経由でキューマネージャーと接続。
                        // この時点で、javaアプリ(これ)側からMQIチャネルが確立されるものと思われる
                        context = cf.createContext();  
                        destination = context.createQueue("queue:///" + QUEUE_NAME);

                        long uniqueNumber = System.currentTimeMillis() % 1000;
                        TextMessage message = context.createTextMessage("Your lucky number today is " + uniqueNumber);

                        // メッセージをエンキュー
                        producer = context.createProducer();
                        producer.send(destination, message);
                        System.out.println("Sent message:\n" + message);

                        // エンキュー後、コネクション確立中の状態を確認したいので1分sleepを追記
                        try {
                                System.out.println("60秒停止します");
                                Thread.sleep(60000); 
                                System.out.println("一時停止を解除しました。");
                        } catch (InterruptedException e){
                                e.printStackTrace();
                        }

                        // デキュー操作
                        consumer = context.createConsumer(destination); // autoclosable
                        String receivedMessage = consumer.receiveBody(String.class, 15000); // in ms or 15 seconds

                        System.out.println("\nReceived message:\n" + receivedMessage);

                        // チャネルをクローズ。今回もjavaアプリからMQIチャネルを切断
                        context.close();

                        recordSuccess();
                } catch (JMSException jmsex) {
                        recordFailure(jmsex);
                }

                System.exit(status);

        } 
```



接続情報のみ修正する。

```java
[root@my-instance jms]# cat JmsPutGet.java
(略)
        // Create variables for the connection to MQ
        private static final String HOST = "localhost"; // Host name or IP address
        private static final int PORT = 1414; // Listener port for your queue manager
        private static final String CHANNEL = "DEV.APP.SVRCONN"; // Channel name
        private static final String QMGR = "QM1"; // Queue manager name
        private static final String APP_USER = "app"; // User name that application uses to connect to MQ
        private static final String APP_PASSWORD = "passw0rd"; // Password that the application uses to connect to MQ
        private static final String QUEUE_NAME = "DEV.QUEUE.1"; // Queue that the application uses to put and get messages to and from
```





# コンパイル・実行

先ほどの資材をクラスパスに指定してコンパイル・実行。
期待通りエンキュー・デキューが実行できた。

```bash
[root@my-instance MQClient]# cd /root/MQClient/
[root@my-instance MQClient]# ll
合計 8284
drwxr-xr-x. 3 root root      17 12月  8 05:48 com
-rw-r--r--. 1 root root 8339503 12月  8 05:45 com.ibm.mq.allclient-9.3.0.0.jar
-rw-r--r--. 1 root root   64009 12月  8 05:45 javax.jms-api-2.0.1.jar
-rw-r--r--. 1 root root   70939 12月  8 05:45 json-20220320.jar

# コンパイル
[root@my-instance MQClient]# javac -cp ./com.ibm.mq.allclient-9.3.0.0.jar:./javax.jms-api-2.0.1.jar:./json-20220320.jar com/ibm/mq/samples/jms/JmsPutGet.java

[root@my-instance MQClient]# ll com/ibm/mq/samples/jms/
合計 24
-rw-r--r--. 1 root root 4450 12月  8 06:00 JmsPutGet.class   #classファイルが生成されている
-rw-r--r--. 1 root root 5726 12月  8 05:55 JmsPutGet.java
-rw-r--r--. 1 root root 5738 12月  8 05:48 JmsPutGet.java_bk

# 実行。期待通りエンキュー・デキューが実行できた。
[root@my-instance MQClient]# java -cp ./com.ibm.mq.allclient-9.3.0.0.jar:./javax.jms-api-2.0.1.jar:./json-20220320.jar:. com.ibm.mq.samples.jms.JmsPutGet
Sent message:

  JMSMessage class: jms_text
  JMSType:          null
  JMSDeliveryMode:  2
  JMSDeliveryDelay: 0
  JMSDeliveryTime:  1733606825651
  JMSExpiration:    0
  JMSPriority:      4
  JMSMessageID:     ID:414d5120514d312020202020202020203b6a5467016a0240
  JMSTimestamp:     1733606825651
  JMSCorrelationID: null
  JMSDestination:   queue:///DEV.QUEUE.1
  JMSReplyTo:       null
  JMSRedelivered:   false
    JMSXAppID: JmsPutGet (JMS)
    JMSXDeliveryCount: 0
    JMSXUserID: app
    JMS_IBM_PutApplType: 28
    JMS_IBM_PutDate: 20241207
    JMS_IBM_PutTime: 21270581
Your lucky number today is 513　　　★送信成功
60秒停止します　　　　　　　　　　　　　　★この間にチャネル状態・滞留メッセージの内容を確認
一時停止を解除しました。

Received message:
Your lucky number today is 513　　★同メッセージの受信も成功
SUCCESS
```



### エンキュー直後のキュー・チャネルの状態

エンキュー直後、60秒の停止中に確認したキューの状態が以下。

期待通り「Your lucky number today is 513」のメッセージがエンキューされている様子がわかる。

![image-20241208062743007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523824/c84c0ae3-1168-d49f-5308-7b1a2011bd4f.png)



この時、チャネルの状態を確認すると、MQI clientから接続を確立されたことで、キューマネージャー側から見ても接続が実行中の状態になっている。

![image-20241208062726613.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523824/acdd8dfa-7bf9-6c44-832d-3c530e15d11b.png)

### デキューまで完了した後のキュー・チャネルの状態

デキューしたのでメッセージは想定通りなくなっている

![image-20241208063522426.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523824/5e206fad-b3b5-f697-daf7-d65d32e9932e.png)


チャネル状態は再度非アクティブ状態に。`context.close();` でMQI client側からチャネルをクローズしたことを契機に非アクティブ状態になるものと思われる。

![image-20241208063338505.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523824/a38ed539-82be-8482-8e02-b330e9b21c4a.png)




# 補足

エラーは主に以下から確認できる。以下はappユーザーへ権限付与する前に疎通しようとして出力されたエラー。

```bash
# appユーザーへ権限付与する前に疎通しようとして認証エラー。
[root@my-instance MQClient]# java -cp ./com.ibm.mq.allclient-9.3.0.0.jar:./javax.jms-api-2.0.1.jar:./json-20220320.jar:. com.ibm.mq.samples.jms.JmsPutGet
Exception in thread "main" com.ibm.msg.client.jms.DetailedJMSSecurityRuntimeException: JMSWMQ2013: 接続モード 'Client' およびホスト名 'localhost(1414)' のキュー・マネージャー 'QM1' に指定されたセキュリティー認証は無効でした。
指定したユーザー名およびパスワードが接続先のキュー・マネージャー上で正しいかどうかを確認してください。  詳しくは、キュー・マネージャーのエラー・ログ、および IBM 資料内の「Securing IBM MQ」トピックを参照してください。
        at com.ibm.msg.client.jms.DetailedJMSSecurityException.getUnchecked(DetailedJMSSecurityException.java:270)
        at com.ibm.msg.client.jms.internal.JmsErrorUtils.convertJMSException(JmsErrorUtils.java:173)
        at com.ibm.msg.client.jms.admin.JmsConnectionFactoryImpl.createContext(JmsConnectionFactoryImpl.java:515)
        at com.ibm.mq.samples.jms.JmsPutGet.main(JmsPutGet.java:106)
Caused by: com.ibm.mq.MQException: JMSCMQ0001: IBM MQ 呼び出しは完了コード '2' ('MQCC_FAILED')、理由 '2035' ('MQRC_NOT_AUTHORIZED') で失敗しました。
        at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:203)
        at com.ibm.msg.client.wmq.internal.WMQConnection.<init>(WMQConnection.java:458)
        at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createV7ProviderConnection(WMQConnectionFactory.java:8683)
        at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createProviderConnection(WMQConnectionFactory.java:8023)
        at com.ibm.msg.client.jms.admin.JmsConnectionFactoryImpl._createConnection(JmsConnectionFactoryImpl.java:322)
        at com.ibm.msg.client.jms.admin.JmsConnectionFactoryImpl.createContext(JmsConnectionFactoryImpl.java:481)
        ... 1 more

# コンテナのログにも認証エラーのむねが出力されていた
[root@my-instance MQClient]# docker logs QM1 | tail
2024-12-14T12:31:33.455Z AMQ8077W: Entity 'app' has insufficient authority to access object QM1 [qmgr]. [CommentInsert1(app), CommentInsert2(QM1 [qmgr]), CommentInsert3(connect)]
2024-12-14T12:31:33.465Z AMQ9557E: Queue Manager User ID initialization failed for 'app'. [ArithInsert1(2), ArithInsert2(2035), CommentInsert1(app), CommentInsert2(app), CommentInsert3(app)]

# コンテナにログイン
[root@my-instance MQClient]# docker exec -it QM1 bash

# キューマネージャのエラーログに認証エラーのむね詳しく出力されていた
bash-4.4$ ll /var/mqm/qmgrs/QM1/errors/AMQERR01.LOG
-rw-rw----. 1 1001 root 50226 Dec 14 12:31 /var/mqm/qmgrs/QM1/errors/AMQERR01.LOG


12/14/24 12:31:33 - Process(285.17) User(mqm) Program(amqzlaa0)
                    Host(326e7b5e7739) Installation(Installation1)
                    VRMF(9.2.4.0) QMgr(QM1)
                    Time(2024-12-14T12:31:33.455Z)
                    CommentInsert1(app)
                    CommentInsert2(QM1 [qmgr])
                    CommentInsert3(connect)

AMQ8077W: Entity 'app' has insufficient authority to access object QM1 [qmgr].

EXPLANATION:
The specified entity is not authorized to access the required object. The
following requested permissions are unauthorized: connect
ACTION:
Ensure that the correct level of authority has been set for this entity against
the required object, or ensure that the entity is a member of a privileged
group.
----- amqzfubx.c : 1640 -------------------------------------------------------
12/14/24 12:31:33 - Process(440.5) User(mqm) Program(amqrmppa)
                    Host(326e7b5e7739) Installation(Installation1)
                    VRMF(9.2.4.0) QMgr(QM1)
                    Time(2024-12-14T12:31:33.465Z)
                    ArithInsert1(2) ArithInsert2(2035)
                    CommentInsert1(app)
                    CommentInsert2(app)
                    CommentInsert3(app)

AMQ9557E: Queue Manager User ID initialization failed for 'app'.

EXPLANATION:
The call to initialize the User ID 'app' failed with CompCode 2 and Reason
2035. If an MQCSP block was used, the User ID in the MQCSP block was 'app'. If
a userID flow was used, the User ID in the UID header was 'app' and any CHLAUTH
rules applied prior to user adoption were evaluated case-sensitively against
this value.
ACTION:
Correct the error and try again.
----- cmqxrsrv.c : 2595 -------------------------------------------------------


# こちらは起動時の出力のみだったためあまり参考にならず
bash-4.4$ ll /var/mqm/errors/AMQERR01.LOG
-rw-rw-r--. 1 1001 root 1813 Dec 14 12:24 /var/mqm/errors/AMQERR01.LOG

```

# おわりに

MQIクライアント接続でのMQ操作を行った。
次回は、もう一つの接続形態である、メッセージチャネルを経由したキューの伝搬を確認する。

https://qiita.com/alphajinsei/items/a56d1ee0adfd5cb04130