1. この記事について
この記事は、IBM MQに関するハンズオン資料シリーズの一部です。
まだ「はじめに」の記事をご覧になっていない方は、まずそちらからご確認ください。
この章の位置付け
この章では、IBM webSphere Libertyを使用してコンテナでwebアプリを立ち上げ、アプリからMQへメッセージの送受信を行います。
- このハンズオンによってできるようになること
- IBM webSphere Libertyでアプリを実行する
- JMSでIBM MQとwebアプリを接続する
- アプリ上からメッセージの送受信を行う
- このハンズオンの目的
- IBM MQとwebアプリを接続し、メッセージを送受信するイメージを掴む
- 対象者の前提条件
- IBM MQの基礎を知っていること
- IBM webSphere Libertyの基礎を知っていること
- 初級編を実施し、QM1とQM2の接続を完了していること
前提となる環境
本資料では、以下の内容を前提の環境としています。
本資料の環境 | バージョン |
---|---|
podman | version 5.3.1 (homebrew) |
java(JDK)(IBM Semeru)Java17 | openjdk 17.0.13 |
git | version 2.46.0 |
maven | Apache Maven 3.9.9 |
Visual Studio Code | 1.100.0 |
make (Apple Silicon (Arm64)のmacユーザーの場合) | version 4.4.1 (homebrew) |
以下の環境についてはすでに初級編で構築済みです。
まだ初級編を実施していない方は、先にそちらの手順を完了させてください。
2. 初級編 MQの基本操作(GUI版)
2. 初級編 MQの基本操作(CLI版)
- カスタムネットワークの作成
- QM1の作成
- QM2の作成
- QM1にリモートキュー作成
- QM1にトランスミッションキュー作成
- QM1とQM2でチャネルの作成
2. ハンズオンの全体像
3. リソースアダプターのインストール
IBM WebSphere LibertyとIBM MQの接続にはリソースアダプターが必要です。
まずはリソースアダプターをインストールします。
リソースアダプターの取得
公式ガイドを元に、リソースアダプターの取得を行います。
まずは以下のリンクにアクセスします。
https://www.ibm.com/links?url=https%3A%2F%2Fibm.biz%2Fmq94JRA
表示された選択可能なフィックスのリストから、使用しているバージョンのIBM MQ用のリソース・アダプターを見つけます。
今回は9.4.2.1-IBM-MQ-Java-InstallRAを選択し、次へ進むをクリックします。
ダウンロード・オプションを選択します。
今回は「ブラウザー (HTTPS) を使用したダウンロード」を選択し、次へ進むをクリックします。
x.x.x.x-IBM-MQ-Java-InstallRA.jar
というファイル名をクリックし、ファイルをダウンロードします。
インストールの実行
コマンドプロンプトまたはターミナルを開き、以下のコマンドを実行します。
ファイル名は、自分がダウンロードした名前に合わせて適宜変更してください。
$ cd <path-to-your-installer-directory>
$ java -jar 9.4.2.1-IBM-MQ-Java-InstallRA.jar
インストーラーの指示に従い、インストールを完了してください。
インストールが完了すると、wmq
というファイルが生成されます。
このファイルは後ほど使用します。
4. Liberty環境での実装手順
今回使用するソースコードリポジトリは以下の通りです。
こちらのリポジトリをgit cloneすることで、本ページ手順4の「ビルドとデプロイ」から実行することも可能です。
https://github.com/ktgrryt/mqapp-jms
ただし、初めてLibertyを触る方や、自分で手を動かしてアプリケーションの中身を確認したい方は以下の手順を順番に実行することを推奨します。
開発環境の準備
OpenLibertyを以下のURLからダウンロードします。
以下の項目を記入し、Generate Projectをクリックします。
- Artifact:
mqapp
- Java SE Version:
17
- Java EE/Jakarta EE Version:
9.1
- MicroProfile Version:
None
mqapp
というzipファイルがダウンロードされるので、zipファイルを解凍してお好みのディレクトリに保管します。
ここまでの準備が完了したら、コードエディタでmqappのフォルダを開きます。
ここから、このプロジェクトにコードを追加していきます。
server.xmlの編集
mq-app/src/main/liberty/config/
にあるserver.xml
の9行目以降に以下の項目を追加します。
<featureManager>
<feature>jakartaee-9.1</feature>
</featureManager>
<resourceAdapter id="wmqjmsra" location="/config/wmq.jakarta.jmsra.rar"/>
<jmsConnectionFactory jndiName="jms/wmqCF" connectionManagerRef="ConMgr">
<properties.wmqjmsra
channel="DEV.APP.SVRCONN"
hostName="QM1"
port="1414"
userName="app"
password="passw0rd"
queueManager="QM1"
transportType="CLIENT"
/>
</jmsConnectionFactory>
<connectionManager id="ConMgr" maxPoolSize="10"/>
<jmsQueue id="jms/queue1" jndiName="jms/queue1">
<properties.wmqjmsra baseQueueName="DEV.QUEUE.1" />
</jmsQueue>
<jmsQueue id="jms/remote1" jndiName="jms/remote1">
<properties.wmqjmsra baseQueueName="REMOTE.Q.1" />
</jmsQueue>
加えて、httpsのポート番号を以下のように9445に変更します。
<httpEndpoint id="defaultHttpEndpoint"
httpPort="9080"
httpsPort="9445" />
また、ssl id
は以下のようにコメントアウトします。
<!-- <ssl id="defaultSSLConfig" trustDefaultCerts="true" /> -->
フロントエンドの実装
次に、フロントエンドの実装を行います。
今回はhtml, javascript, cssを使用します。
まずは、mqapp/src/main
にwebapp
というフォルダを作成します。
webapp
フォルダの中に、index.html
というファイルを作成します。
index.html
ファイルに以下のコードを追加します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Send and Receive Message</title>
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<h1>MQによるメッセージの送受信</h1>
<div class="forms-container">
<!-- メッセージ送信フォーム -->
<div id="send-container">
<form id="sendForm">
<h2>メッセージ送信</h2>
<label for="queueSelectSend">送信先キューを選択:</label>
<select id="queueSelectSend" required>
<option value="/mqapp/api/sendlocal">ローカルキュー(DEV.QUEUE.1)</option>
<option value="/mqapp/api/sendremote">リモートキュー(REMOTE.Q.1)</option>
</select>
<label for="messageInput">メッセージ:</label>
<input type="text" id="messageInput" name="msg" required>
<button type="button" onclick="sendMessage()">送信</button>
</form>
</div>
<!-- メッセージ受信フォーム -->
<div id="receive-container">
<form id="recvForm">
<h2>メッセージ受信</h2>
<label for="queueSelectRecv">受信するキューを選択:</label>
<select id="queueSelectRecv" required>
<option value="/mqapp/api/recv">ローカルキュー(DEV.QUEUE.1)</option>
</select>
<button type="button" onclick="receiveMessage()">受信</button>
</form>
</div>
</div>
<!-- メッセージ履歴 -->
<div id="history-container">
<div id="messages">
<div id="messages-header">
<h2>メッセージ送受信の履歴:</h2>
</div>
<div id="messages-list">
<!-- メッセージがここに追加される -->
</div>
</div>
</div>
<script src="js/send.js"></script>
<script src="js/receive.js"></script>
<script src="js/history.js"></script>
</body>
</html>
次に、webapp
フォルダ内にjs
, css
というフォルダを作成します。
js
フォルダの中に、以下の3つのファイルを作成します。
send.js
function sendMessage() {
const queueEndpoint = document.getElementById('queueSelectSend').value;
const message = document.getElementById('messageInput').value;
if (!message) {
alert("メッセージを入力してください");
return;
}
// リクエスト実行メッセージを履歴に追加 (グレー表示)
addMessageToHistory("メッセージの送信処理を開始しました", 'request');
fetch(queueEndpoint, {
method: 'POST',
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
},
body: new URLSearchParams({ msg: message })
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTPエラー: ${response.status}`);
}
return response.json();
})
.then(parsedData => {
addMessageToHistory(`送信: ${parsedData.message}`, 'response', parsedData.headers);
messageInput.value = ''; // フォームをクリア
})
.catch(error => {
addMessageToHistory("送信エラー: " + error.message, 'error');
});
}
receive.js
function receiveMessage() {
const queueEndpoint = document.getElementById('queueSelectRecv').value;
// リクエスト実行メッセージを履歴に追加 (グレー表示)
addMessageToHistory("メッセージの受信処理を開始しました", 'request');
fetch(queueEndpoint)
.then(response => {
if (!response.ok) {
throw new Error(`HTTPエラー: ${response.status}`);
}
return response.json();
})
.then(parsedData => {
addMessageToHistory(`受信: ${parsedData.message}`, 'response', parsedData.headers);
})
.catch(error => {
addMessageToHistory("受信エラー: " + error.message, 'error');
});
}
history.js
function addMessageToHistory(message, type = 'default', headers = null) {
const messagesDiv = document.getElementById('messages-list');
const newMessageDiv = document.createElement('div');
newMessageDiv.classList.add('message');
// メッセージの種類に応じてクラスを追加
if (type === 'request') {
newMessageDiv.classList.add('message-request');
} else if (type === 'response') {
newMessageDiv.classList.add('message-response');
} else if (type === 'error') {
newMessageDiv.classList.add('message-error');
}
// メッセージ内容
const messageText = document.createElement('span');
messageText.textContent = message;
newMessageDiv.appendChild(messageText);
// タイムスタンプを作成
const timestamp = document.createElement('span');
timestamp.classList.add('timestamp');
const now = new Date();
// ミリ秒まで表示するためのフォーマット作成
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
const seconds = now.getSeconds().toString().padStart(2, '0');
const milliseconds = now.getMilliseconds().toString().padStart(3, '0');
// フォーマット例: HH:mm:ss.SSS
timestamp.textContent = `${hours}:${minutes}:${seconds}.${milliseconds}`;
newMessageDiv.appendChild(timestamp); // タイムスタンプをメッセージに追加
// ヘッダーがある場合の処理
if (headers) {
const headerDiv = document.createElement('div');
headerDiv.classList.add('message-headers');
headerDiv.style.display = 'none'; // 初期は非表示
Object.entries(headers).forEach(([key, value]) => {
const headerItem = document.createElement('p');
headerItem.innerHTML = `<strong>${key}:</strong> ${value}`;
headerDiv.appendChild(headerItem);
});
newMessageDiv.appendChild(headerDiv);
newMessageDiv.addEventListener('click', () => {
headerDiv.style.display = headerDiv.style.display === 'none' ? 'block' : 'none';
});
}
messagesDiv.insertBefore(newMessageDiv, messagesDiv.firstChild); // 新しいメッセージを上に追加
}
styles.css
css
フォルダの中に、次のファイルを追加します。
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f4f4f4;
color: #333;
margin: 0;
padding: 0;
line-height: 1.6;
}
h1 {
color: #333;
text-align: center;
margin-top: 20px;
font-size: 2rem;
}
.forms-container {
display: flex;
flex-wrap: wrap; /* レスポンシブ対応:小さい画面で折り返す */
justify-content: center; /* 中央揃え */
gap: 20px; /* フォーム間のスペースを広げる */
margin: 20px auto;
padding: 20px;
max-width: 1200px; /* 全体の最大幅を設定 */
box-sizing: border-box; /* パディングを含めて幅を計算 */
}
form {
padding: 20px;
background-color: #ffffff;
border: 1px solid #e0e0e0;
border-radius: 10px; /* 角をより丸く */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
flex: 1 1 300px; /* レスポンシブ対応:最低幅300px */
width: 400px; /* フォームの最大幅を指定 */
box-sizing: border-box;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #555;
}
input[type="text"], select {
width: 100%;
padding: 12px;
margin-bottom: 20px;
border: 1px solid #ccc;
border-radius: 6px;
box-sizing: border-box;
font-size: 1rem;
transition: border-color 0.3s, box-shadow 0.3s; /* フォーカス時のアニメーション */
}
input[type="text"]:focus, select:focus {
border-color: #007BFF; /* フォーカス時のボーダー色 */
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5); /* フォーカス時の影 */
outline: none; /* デフォルトのアウトラインを削除 */
}
button {
background-color: #007BFF;
color: #ffffff;
border: none;
padding: 12px 24px;
border-radius: 6px;
cursor: pointer;
font-size: 1rem;
font-weight: 600; /* ボタンの文字を強調 */
transition: background-color 0.3s, transform 0.2s;
}
button:hover {
background-color: #0056b3;
transform: translateY(-2px); /* ホバー時に少し浮き上がるアニメーション */
}
button:active {
background-color: #003d80; /* クリック時の色 */
transform: translateY(0); /* クリック時は元の位置に戻る */
}
#messages {
margin: 20px auto;
padding: 20px;
background-color: #ffffff;
border: 1px solid #e0e0e0;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
max-width: 820px; /* メッセージコンテナの最大幅を指定 */
box-sizing: border-box;
}
.message {
margin-bottom: 10px;
padding: 15px; /* パディングを広げる */
border: 1px solid #ddd;
border-radius: 6px; /* 角を少し丸く */
background-color: #f9f9f9;
font-size: 0.95rem; /* フォントサイズを調整 */
color: #555;
line-height: 1.4; /* 行間を広げる */
position: relative; /* タイムスタンプを絶対位置で配置するために必要 */
}
.timestamp {
position: absolute;
top: 5px;
right: 10px;
font-size: 12px;
color: #999;
}
.message-request {
color: #888; /* グレー表示 */
background-color: #f5f5f5; /* 薄い背景色 */
border-left: 4px solid #ccc; /* 左にアクセントライン */
}
.message-response {
color: #007BFF; /* 青色で強調 */
background-color: #eef6ff; /* 薄い青の背景色 */
border-left: 4px solid #007BFF; /* 左にアクセントライン */
}
.message-error {
color: #ff0000; /* 赤色の文字 */
background-color: #ffe6e6; /* 薄い赤色の背景 */
border-left: 4px solid #ff0000; /* 左に赤色のアクセントライン */
}
/* メッセージ履歴ヘッダーのスタイル */
#messages-header {
position: relative;
padding: 10px;
border-bottom: 1px solid #ddd;
}
.message-headers {
margin-top: 10px;
padding: 10px;
background-color: #f1f1f1;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 0.9rem;
color: #555;
line-height: 1.4;
}
/* レスポンシブ対応 */
@media (max-width: 860px) {
#messages {
max-width: 400px; /* 横幅の最大値を400pxに制限 */
width: 100%; /* 幅を100%に設定 */
}
}
以上でフロントエンドの実装は完了です。
webapp
フォルダ内が以下の構成になっていることを確認してください。
また、作成したファイルが保存されていることを確認してください。
バックエンドの実装
次に、バックエンドの実装を行います。
mqapp/src/main/java/com/demo/rest
フォルダにMessageApi.java
というファイルを追加します。
MessageApi.java
package com.demo.rest;
import jakarta.ejb.Stateless;
import jakarta.inject.Inject;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import com.demo.messaging.MQConsumer;
import com.demo.messaging.MQProducer;
@Stateless
@Path("/")
public class MessageApi {
@Inject
MQProducer producer;
@Inject
MQConsumer consumer;
@POST
@Path("/sendlocal")
public Response sendLocal(@FormParam("msg") String message) {
try {
String result = producer.sendLocalMessage(message);
return Response.ok(result).build(); // HTTP 200 OK を返す
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("ローカルキューへの送信に失敗しました: " + e.getMessage())
.build(); // HTTP 500 Internal Server Error を返す
}
}
@POST
@Path("/sendremote")
public Response sendRemote(@FormParam("msg") String message) {
try {
String result = producer.sendRemoteMessage(message);
return Response.ok(result).build(); // HTTP 200 OK を返す
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("リモートキューへの送信に失敗しました: " + e.getMessage())
.build(); // HTTP 500 Internal Server Error を返す
}
}
@GET
@Path("/recv")
public Response recv() {
try {
String result = consumer.recvMessage();
return Response.ok(result).build(); // HTTP 200 OK を返す
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Error: " + e.getMessage())
.build(); // HTTP 500 Internal Server Error を返す
}
}
}
次に、mqapp/src/main/java/com/demo
にmessaging
というフォルダを追加し、以下の2つのファイルを追加します。
MQConsumer.java
package com.demo.messaging;
import jakarta.annotation.Resource;
import jakarta.ejb.Stateless;
import jakarta.inject.Inject;
import jakarta.jms.JMSConnectionFactory;
import jakarta.jms.JMSContext;
import jakarta.jms.JMSConsumer;
import jakarta.jms.Destination;
import jakarta.jms.Message;
import jakarta.jms.TextMessage;
import jakarta.json.Json;
import jakarta.json.JsonObject;
@Stateless
public class MQConsumer {
@Inject
@JMSConnectionFactory("jms/wmqCF")
JMSContext context;
@Resource(lookup = "jms/queue1")
Destination dest;
// タイムアウト時間(ミリ秒単位)
private static final long RECEIVE_TIMEOUT = 5000; // 例: 5秒
public String recvMessage() throws Exception {
try {
JMSConsumer consumer = context.createConsumer(dest);
// タイムアウト付きで受信
Message message = consumer.receive(RECEIVE_TIMEOUT);
if (message == null) {
throw new Exception("メッセージ受信タイムアウト");
}
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
// JMS ヘッダー情報を取得
JsonObject headers = Json.createObjectBuilder()
.add("JMSMessageID", textMessage.getJMSMessageID())
.add("JMSTimestamp", textMessage.getJMSTimestamp())
.add("JMSCorrelationID", textMessage.getJMSCorrelationID() != null ? textMessage.getJMSCorrelationID() : "")
.add("JMSDestination", textMessage.getJMSDestination() != null ? textMessage.getJMSDestination().toString() : "")
.add("JMSDeliveryMode", textMessage.getJMSDeliveryMode())
.add("JMSExpiration", textMessage.getJMSExpiration())
.add("JMSPriority", textMessage.getJMSPriority())
.add("JMSReplyTo", textMessage.getJMSReplyTo() != null ? textMessage.getJMSReplyTo().toString() : "")
.add("JMSType", textMessage.getJMSType() != null ? textMessage.getJMSType() : "")
.build();
// メッセージとヘッダー情報をJSON形式で返す
return Json.createObjectBuilder()
.add("message", textMessage.getText())
.add("headers", headers)
.build()
.toString();
} else {
throw new Exception("受信したメッセージがテキスト形式ではありません");
}
} catch (Exception e) {
throw new Exception("メッセージの受信に失敗しました " + e.getMessage(), e);
}
}
}
MQProducer.java
package com.demo.messaging;
import jakarta.annotation.Resource;
import jakarta.ejb.Stateless;
import jakarta.inject.Inject;
import jakarta.jms.JMSConnectionFactory;
import jakarta.jms.JMSContext;
import jakarta.jms.Queue;
import jakarta.jms.TextMessage;
import jakarta.json.Json;
import jakarta.json.JsonObject;
@Stateless
public class MQProducer {
@Inject
@JMSConnectionFactory("jms/wmqCF")
JMSContext context;
@Resource(lookup = "jms/queue1")
Queue queue;
@Resource(lookup = "jms/remote1")
Queue remoteQueue;
// ローカルキューにメッセージを送信するメソッド
public String sendLocalMessage(String message) throws Exception {
try {
TextMessage textMessage = context.createTextMessage();
textMessage.setText(message);
context.createProducer().send(queue, textMessage);
// JMS ヘッダー情報を取得
JsonObject headers = Json.createObjectBuilder()
.add("JMSMessageID", textMessage.getJMSMessageID())
.add("JMSTimestamp", textMessage.getJMSTimestamp())
.add("JMSCorrelationID", textMessage.getJMSCorrelationID() != null ? textMessage.getJMSCorrelationID() : "")
.add("JMSDestination", textMessage.getJMSDestination() != null ? textMessage.getJMSDestination().toString() : "")
.add("JMSDeliveryMode", textMessage.getJMSDeliveryMode())
.add("JMSExpiration", textMessage.getJMSExpiration())
.add("JMSPriority", textMessage.getJMSPriority())
.add("JMSReplyTo", textMessage.getJMSReplyTo() != null ? textMessage.getJMSReplyTo().toString() : "")
.add("JMSType", textMessage.getJMSType() != null ? textMessage.getJMSType() : "")
.build();
// メッセージとヘッダー情報をJSON形式で返す
return Json.createObjectBuilder()
.add("message", message)
.add("headers", headers)
.build()
.toString();
} catch (Exception e) {
throw new Exception("ローカルキューへの送信に失敗しました " + e.getMessage(), e);
}
}
// リモートキューにメッセージを送信するメソッド
public String sendRemoteMessage(String message) throws Exception {
try {
TextMessage textMessage = context.createTextMessage();
textMessage.setText(message);
context.createProducer().send(remoteQueue, textMessage);
// JMS ヘッダー情報を取得
JsonObject headers = Json.createObjectBuilder()
.add("JMSMessageID", textMessage.getJMSMessageID())
.add("JMSTimestamp", textMessage.getJMSTimestamp())
.add("JMSCorrelationID", textMessage.getJMSCorrelationID() != null ? textMessage.getJMSCorrelationID() : "")
.add("JMSDestination", textMessage.getJMSDestination() != null ? textMessage.getJMSDestination().toString() : "")
.add("JMSDeliveryMode", textMessage.getJMSDeliveryMode())
.add("JMSExpiration", textMessage.getJMSExpiration())
.add("JMSPriority", textMessage.getJMSPriority())
.add("JMSReplyTo", textMessage.getJMSReplyTo() != null ? textMessage.getJMSReplyTo().toString() : "")
.add("JMSType", textMessage.getJMSType() != null ? textMessage.getJMSType() : "")
.build();
// メッセージとヘッダー情報をJSON形式で返す
return Json.createObjectBuilder()
.add("message", message)
.add("headers", headers)
.build()
.toString();
} catch (Exception e) {
throw new Exception("リモートキューへの送信に失敗しました " + e.getMessage(), e);
}
}
}
以上でバックエンドの実装は完了です。
フォルダ内が以下のようになっていることを確認してください。また、作成したファイルが保存されていることを確認してください。
リソースアダプターの配置
mqapp
フォルダの直下にibm
というフォルダを作成します。
ibm
フォルダ内に、本章のセクション3. リソースアダプターのインストールでインストールしたwmq
というフォルダ内のwmq.jakarta.jmsra.rar
というファイルを配置してください。
Dockerfileの編集
Dockerfile
を以下の内容に変更してください。
FROM icr.io/appcafe/open-liberty:kernel-slim-java17-openj9-ubi
COPY --chown=1001:0 /src/main/liberty/config /config
COPY --chown=1001:0 ibm/wmq.jakarta.jmsra.rar /config
RUN features.sh
COPY --chown=1001:0 target/*.war /config/apps
RUN configure.sh
以上でLiberty環境の構築は完了です。
ビルドとデプロイ
それでは作成したアプリケーションをビルドし、デプロイしましょう。
ターミナルを開き、Libertyのプロジェクトがあるディレクトリに移動します。
cd <path-to-liberty-project>
以下のコマンドを実行してプロジェクトをビルドします。BUILD SUCCESSという表記が出ることを確認してください。
mvn package
コンテナイメージを作成します。
podman build . --platform linux/x86_64 -t mqapp:1
イメージが正常に作成されたことを確認します。
podman images
以下のように、mqappというイメージが作成されていることを確認してください。
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/mqapp 1 37d2f05da9dc 4 minutes ago 903 MB
コンテナを起動します。
podman run --name mqapp -d -p 9080:9080 -p 9445:9445 --network mq-network mqapp:1
アプリケーションにアクセスします。以下のURLにアクセスしてください。
5. Libertyアプリケーションの操作
ローカルキューへの送信
このアプリケーションでは、ブラウザ上からキューマネージャーに対してメッセージの送受信を行うことが可能です。
送信先キューがDEV.QUEUE.1になっていることを確認し、メッセージを入力します。今回は試しにliberty
と入力し、送信を押します。
送信に成功すると、画面下部の「メッセージ送受信の履歴」に送信したメッセージの内容が表示されているのが確認できます。
履歴の表示の右上には、処理が実行された時刻が表示されます。
ブラウザ上で送信処理が実行されてから、実際にメッセージが送信されるまでの間にわずかに時間があるのが確認できます。
同様に、メッセージの内容を変えていくつかメッセージをローカルキューに送信してみましょう。
ローカルキューからの受信
次に、ローカルキューに保存されているメッセージを受信してみましょう。
受信するキューがローカルキューになっているのを確認し、受信ボタンをクリックします。
受信に成功すると、ローカルキューに入っているメッセージを取り出すことができているのを確認することができます。
ローカルキューに入っているメッセージを全て受信してみましょう。
これ以上取り出すことのできるメッセージがない状態で受信ボタンを押すと、エラーが表示されます。
このタイムアウトエラーは、mqapp内のMQConsumer.javaで5秒に設定してあります。
送信と受信を何度か行い、メッセージがFirst In First Outの順番で取り出されることを確認してください。
リモートキューへの送信
次に、リモートキューへメッセージを送信し、QM1からQM2へメッセージを飛ばしてみましょう。
送信先キューをリモートキュー(REMOTE.Q.1)に設定し、適当なメッセージを入力してから送信ボタンを押してください。
しかし、結果はエラーになってしまいます。
原因は、リモートキューに対して権限の設定を実施していないためです。
それでは、QM1にアクセスして権限の設定を行います。
以下のURLにアクセスしてください。
https://localhost:9443/ibmmq/console
ユーザー名にadmin
、パスワードにpassw0rd
と入力してログインします。
QM1の管理をクリックします。
キュータブをクリックし、REMOTE.Q.1の3点リーダーから構成の表示をクリックします。
ユーザー名にapp
と入力し、「管理アクセス権限」から書き込みにチェックをして、追加をクリックします。
それでは、再度リモートキューにメッセージを送信してみましょう。
Libertyのアプリの画面に戻り、送信先キューをリモートキュー(REMOTE.Q.1)に設定し、適当なメッセージを入力してから送信ボタンを押してください。
送信されたメッセージは、初級編で作成したチャネルを通ってQM2へと伝送されます。
以下のURLからQM2のコンソールにアクセスしてください。
https://localhost:9444/ibmmq/console
ユーザー名にadmin
、パスワードにpassw0rd
と入力してログインします。
もしメッセージがQM2に送信されていない場合、MQネットワークタブのキュー・マネージャー・チャネルから、QM1toQM2が実行中になっているか確認してください。
6.コンテナの停止
次に、QM2のコンテナを停止した状態でREMOTE.Q.1にメッセージを送信してみましょう。
まずはQM2を停止します。ターミナルで以下のコマンドを入力してください。
podman stop QM2
mqappを開き、送信先キューをリモートキューにして適当なメッセージを入力し、送信ボタンを押します。
QM2のコンテナは停止しているので、QM2のwebコンソールにはアクセスできません。
QM1のwebコンソールにアクセスし、キュータブからTRANS.Q.1をクリックします。
QM2への伝送に失敗したメッセージが、TRANS.Q.1に保管されていることを確認します。
停止したコンテナを再起動します。
podman start QM2
7.JMSのヘッダー情報を確認する
JMSには、MQIと同様に、メッセージヘッダーに様々な情報が格納されています。このセクションでは、送信したメッセージのヘッダー情報を確認します。
mqappを開き、ローカルキューに対して適当な内容のメッセージを送信してください。
メッセージ送受信の履歴の中から送信したメッセージをクリックすると、JMSのヘッダー情報を確認する事ができます。
受信ボタンをクリックして、先ほど送信したメッセージが受信されるまで受信を行います。
受信したメッセージについても同様に、ヘッダー情報を確認する事ができます。
送信したメッセージと受信したメッセージを比較して、対応するメッセージはJMSMessageIDが同じであることを確認してください。
8. 環境の削除
ハンズオンをやり直す場合やここで終了する場合など、今回作成した環境を削除したい場合は、以下の手順を実行してください。
コンテナIDの確認
podman ps
コンテナの停止
podman stop <container id>
コンテナの消去
podman rm <container id>
イメージの確認
podman images
イメージの消去
podman rmi <image id>
マウントされているボリュームの確認
podman volume ls
マウントされているボリュームの消去
podman volume rm <volume name>
カスタムネットワークの確認
podman network rm
カスタムネットワークの消去
podman network rm mq-network
加えて、Libertyのアプリケーション(mqapp
)も別途削除してください。
9. ハンズオン資料リンク
3. 中級編 Libertyアプリによるメッセージの送受信(本記事)
さらに詳しい情報をお探しの方へ
IBMの最新情報、イベント情報、さらに役立つ資料は、以下のIBM Communityでも発信・格納されています。
最新のトレンドや有益な情報をチェックするために、ぜひご覧ください!
- WebSphere: IBM Community - WebSphere
WebSphere関連の最新情報やディスカッション、イベント情報、技術資料を公開中!
- ELM (Engineering Lifecycle Management): IBM Community - ELM
ELMに関する最新のイベント情報、ナレッジ共有、便利なドキュメントをチェック!
- Integration: IBM Community - Integration
Integrationに関する最新のイベント情報、ナレッジ共有、便利なドキュメントをチェック!