From f59383e06d678ed89716a7c831b727f88a01433d Mon Sep 17 00:00:00 2001 From: Stuti Uniyal Date: Fri, 4 Jul 2025 14:03:51 +0530 Subject: [PATCH 1/8] add base java samples --- base-java/Readme.md | 124 ++++++++++++++++ base-java/pom.xml | 55 ++++++++ .../com/ibm/mq/samples/java/BasicGet.java | 133 ++++++++++++++++++ .../com/ibm/mq/samples/java/BasicPub.java | 128 +++++++++++++++++ .../com/ibm/mq/samples/java/BasicPut.java | 122 ++++++++++++++++ .../com/ibm/mq/samples/java/BasicRequest.java | 123 ++++++++++++++++ .../ibm/mq/samples/java/BasicResponse.java | 121 ++++++++++++++++ .../com/ibm/mq/samples/java/BasicSub.java | 133 ++++++++++++++++++ 8 files changed, 939 insertions(+) create mode 100644 base-java/Readme.md create mode 100644 base-java/pom.xml create mode 100644 base-java/src/main/java/com/ibm/mq/samples/java/BasicGet.java create mode 100644 base-java/src/main/java/com/ibm/mq/samples/java/BasicPub.java create mode 100644 base-java/src/main/java/com/ibm/mq/samples/java/BasicPut.java create mode 100644 base-java/src/main/java/com/ibm/mq/samples/java/BasicRequest.java create mode 100644 base-java/src/main/java/com/ibm/mq/samples/java/BasicResponse.java create mode 100644 base-java/src/main/java/com/ibm/mq/samples/java/BasicSub.java diff --git a/base-java/Readme.md b/base-java/Readme.md new file mode 100644 index 00000000..3fd7bb90 --- /dev/null +++ b/base-java/Readme.md @@ -0,0 +1,124 @@ +# IBM MQ Base Java Samples + +This project provides a set of base Java samples for interacting with IBM MQ using the IBM MQ classes for Java (non-JMS). These include basic examples for put/get, publish/subscribe, and request/response messaging patterns. + +## Samples Included + +Each sample is located under: + +``` +src/main/java/com/ibm/mq/samples/java/ +``` + +- `BasicPut.java` – Puts a message onto a queue +- `BasicGet.java` – Gets a message from a queue +- `BasicPub.java` – Publishes a message to a topic +- `BasicSub.java` – Subscribes and receives messages from a topic +- `BasicRequest.java` – Sends a message with a dynamic reply-to queue +- `BasicResponse.java` – Responds to requests received from a queue + +## Prerequisites + +- Java 8 or higher +- Apache Maven +- IBM MQ installed and running (locally or remotely) + +## Project Setup + +This is a standard Maven project. All dependencies and build instructions are managed through `pom.xml`. + +### Building the Project + +To build the project and download dependencies: + +```bash +mvn clean package +``` +## Running the Samples + +Ensure that your environment configuration file (`env.json`) is properly set up. Example: + +```json +{ + "MQ_ENDPOINTS": [ + { + "QMGR": "QM1", + "HOST": "localhost", + "PORT": 1414, + "CHANNEL": "DEV.APP.SVRCONN", + "APP_USER": "app", + "APP_PASSWORD": "passw0rd", + "QUEUE_NAME": "DEV.QUEUE.1", + "BACKOUT_QUEUE": "DEV.QUEUE.2", + "MODEL_QUEUE_NAME": "DEV.APP.MODEL.QUEUE", + "DYNAMIC_QUEUE_PREFIX": "APP.REPLIES.*", + "TOPIC_NAME": "dev/" + } + ] +} +``` +## Using a CCDT File + +Instead of manually specifying connection parameters in `env.json`, you can use a **Client Channel Definition Table (CCDT)** JSON file to define connection configurations. This is useful when connecting to IBM MQ instances in cloud or enterprise environments. + +Set the environment variable `MQCCDTURL` to point to the CCDT file: + +```bash +export MQCCDTURL=file:/absolute/path/to/ccdt.json +``` + +> **Note (Windows):** Use `set` instead of `export`: +> +> ```cmd +> set MQCCDTURL=file:C:\path\to\ccdt.json +> ``` + +The sample will detect `MQCCDTURL` and automatically use it for connection settings. When `MQCCDTURL` is set and starts with `file://`, the program prioritizes CCDT-based configuration and skips `host`, `channel`, and `port` in `env.json`. + +Make sure your CCDT file defines the appropriate connection information such as **channel name**, **queue manager**, and **connection name list**. + + +## Run Instructions + +### Put/Get + +```bash +mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicPut" -Dexec.args="env.json" +mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicGet" -Dexec.args="env.json" +``` + +### Publish/Subscribe + +In the **first terminal (subscriber)**: + +```bash +mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicSub" -Dexec.args="env.json" +``` + +In the **second terminal (publisher)**: + +```bash +mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicPub" -Dexec.args="env.json" +``` + +### Request/Response + +In the **first terminal (response)**: + +```bash +mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicResponse" -Dexec.args="env.json" +``` + +In the **second terminal (request)**: + +```bash +mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicRequest" -Dexec.args="env.json" +``` + +## Notes + +- The environment can be configured using either `env.json` or a CCDT file via the `MQCCDTURL` environment variable. +- Each sample reads from the provided `env.json` to extract connection information for the queue manager. +- Samples like `BasicResponse` and `BasicSub` are long-running and wait for messages indefinitely until stopped. +- Make sure all relevant queues and topics are pre-created in your IBM MQ queue manager. + diff --git a/base-java/pom.xml b/base-java/pom.xml new file mode 100644 index 00000000..7932c5d4 --- /dev/null +++ b/base-java/pom.xml @@ -0,0 +1,55 @@ + + 4.0.0 + + com.ibm.mq.samples + mq-java-base-consumer + 1.0.0 + jar + + + 1.8 + 1.8 + + + + + + com.ibm.mq + com.ibm.mq.allclient + 9.4.3.0 + + + + + org.json + json + 20240303 + + + + + + + maven-compiler-plugin + 3.8.1 + + 1.8 + + + + + + + + + + + + + + + + diff --git a/base-java/src/main/java/com/ibm/mq/samples/java/BasicGet.java b/base-java/src/main/java/com/ibm/mq/samples/java/BasicGet.java new file mode 100644 index 00000000..e7a77783 --- /dev/null +++ b/base-java/src/main/java/com/ibm/mq/samples/java/BasicGet.java @@ -0,0 +1,133 @@ +package com.ibm.mq.samples.java; + +import com.ibm.mq.*; +import com.ibm.mq.constants.MQConstants; +import org.json.*; + +import java.io.FileReader; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Hashtable; + +public class BasicGet { + + private static class MQDetails { + String QMGR; + String QUEUE_NAME; + String HOST; + String PORT; + String CHANNEL; + String USER; + String PASSWORD; + String KEY_REPOSITORY; + String CIPHER; + } + + private static JSONArray endpoints; + + public static void main(String[] args) { + loadEnv("env.json"); + + for (int i = 0; i < endpoints.length(); i++) { + System.out.println("Processing endpoint " + i); + JSONObject point = endpoints.getJSONObject(i); + MQDetails details = buildMQDetails(point); + processEndpoint(details); + } + + System.out.println("Sample MQ GET application ending"); + } + + private static void loadEnv(String path) { + try { + String content = new String(Files.readAllBytes(Paths.get(path))); + JSONObject env = new JSONObject(content); + endpoints = env.getJSONArray("MQ_ENDPOINTS"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static MQDetails buildMQDetails(JSONObject endpoint) { + MQDetails mq = new MQDetails(); + mq.QMGR = endpoint.getString("QMGR"); + mq.QUEUE_NAME = endpoint.getString("QUEUE_NAME"); + mq.HOST = endpoint.getString("HOST"); + mq.PORT = String.valueOf(endpoint.getInt("PORT")); + mq.CHANNEL = endpoint.getString("CHANNEL"); + mq.USER = endpoint.getString("APP_USER"); + mq.PASSWORD = endpoint.getString("APP_PASSWORD"); + mq.KEY_REPOSITORY = endpoint.optString("KEY_REPOSITORY", ""); + mq.CIPHER = endpoint.optString("CIPHER", ""); + return mq; + } + + private static void processEndpoint(MQDetails details) { + MQQueueManager qMgr = null; + MQQueue queue = null; + + try { + Hashtable props = new Hashtable<>(); + String ccdtUrl = System.getenv("MQCCDTURL"); + + if (ccdtUrl != null && ccdtUrl.startsWith("file://")) { + String ccdtPath = ccdtUrl.replace("file://", ""); + System.setProperty("MQCCDTURL", ccdtPath); + System.out.println("Using CCDT at: " + ccdtPath); + } else { + props.put(MQConstants.HOST_NAME_PROPERTY, details.HOST); + props.put(MQConstants.PORT_PROPERTY, Integer.parseInt(details.PORT)); + props.put(MQConstants.CHANNEL_PROPERTY, details.CHANNEL); + } + + props.put(MQConstants.USER_ID_PROPERTY, details.USER); + props.put(MQConstants.PASSWORD_PROPERTY, details.PASSWORD); + props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); + + if (!details.KEY_REPOSITORY.isEmpty()) { + props.put(MQConstants.SSL_CIPHER_SUITE_PROPERTY, details.CIPHER); + System.setProperty("com.ibm.mq.ssl.keyStore", details.KEY_REPOSITORY); + System.setProperty("com.ibm.mq.ssl.keyStorePassword", ""); + } + + qMgr = new MQQueueManager(details.QMGR, props); + System.out.println("Connected to queue manager: " + details.QMGR); + + int openOptions = MQConstants.MQOO_INPUT_AS_Q_DEF; + queue = qMgr.accessQueue(details.QUEUE_NAME, openOptions); + + boolean keepReading = true; + while (keepReading) { + MQMessage msg = new MQMessage(); + MQGetMessageOptions gmo = new MQGetMessageOptions(); + gmo.options = MQConstants.MQGMO_NO_WAIT | + MQConstants.MQGMO_CONVERT | + MQConstants.MQGMO_FAIL_IF_QUIESCING; + + try { + queue.get(msg, gmo); + String str = msg.readStringOfByteLength(msg.getDataLength()); + System.out.println("Received message: " + str); + } catch (MQException mqe) { + if (mqe.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) { + keepReading = false; + System.out.println("No more messages."); + } else { + System.err.println("Error retrieving message: " + mqe); + keepReading = false; + } + } + } + + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (queue != null) queue.close(); + if (qMgr != null) qMgr.disconnect(); + } catch (MQException me) { + me.printStackTrace(); + } + } + } +} diff --git a/base-java/src/main/java/com/ibm/mq/samples/java/BasicPub.java b/base-java/src/main/java/com/ibm/mq/samples/java/BasicPub.java new file mode 100644 index 00000000..d0748ba7 --- /dev/null +++ b/base-java/src/main/java/com/ibm/mq/samples/java/BasicPub.java @@ -0,0 +1,128 @@ +package com.ibm.mq.samples.java; +import com.ibm.mq.*; +import com.ibm.mq.constants.MQConstants; +import org.json.*; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Hashtable; + +public class BasicPub { + + private static class MQDetails { + String QMGR; + String TOPIC_NAME; + String HOST; + String PORT; + String CHANNEL; + String USER; + String PASSWORD; + String KEY_REPOSITORY; + String CIPHER; + } + + private static MQDetails mqDetails; + + public static void main(String[] args) { + loadEnv("env.json"); + publishToTopic(mqDetails); + System.out.println("Sample MQ PUB application ending"); + } + + private static void loadEnv(String path) { + try { + String content = new String(Files.readAllBytes(Paths.get(path))); + JSONObject env = new JSONObject(content); + JSONObject endpoint = env.getJSONArray("MQ_ENDPOINTS").getJSONObject(0); + + mqDetails = new MQDetails(); + mqDetails.QMGR = endpoint.getString("QMGR"); + mqDetails.TOPIC_NAME = endpoint.getString("TOPIC_NAME"); + mqDetails.HOST = endpoint.getString("HOST"); + mqDetails.PORT = String.valueOf(endpoint.getInt("PORT")); + mqDetails.CHANNEL = endpoint.getString("CHANNEL"); + mqDetails.USER = endpoint.getString("APP_USER"); + mqDetails.PASSWORD = endpoint.getString("APP_PASSWORD"); + mqDetails.KEY_REPOSITORY = endpoint.optString("KEY_REPOSITORY", ""); + mqDetails.CIPHER = endpoint.optString("CIPHER", ""); + + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void publishToTopic(MQDetails d) { + MQQueueManager qMgr = null; + MQTopic topic = null; + + try { + Hashtable props = new Hashtable<>(); + + String ccdtUrl = System.getenv("MQCCDTURL"); + if (ccdtUrl != null && ccdtUrl.startsWith("file://")) { + String ccdtPath = ccdtUrl.replace("file://", ""); + System.setProperty("MQCCDTURL", ccdtPath); + System.out.println("Using CCDT at: " + ccdtPath); + } else { + props.put(MQConstants.HOST_NAME_PROPERTY, d.HOST); + props.put(MQConstants.PORT_PROPERTY, Integer.parseInt(d.PORT)); + props.put(MQConstants.CHANNEL_PROPERTY, d.CHANNEL); + } + + props.put(MQConstants.USER_ID_PROPERTY, d.USER); + props.put(MQConstants.PASSWORD_PROPERTY, d.PASSWORD); + props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); + + if (!d.KEY_REPOSITORY.isEmpty()) { + props.put(MQConstants.SSL_CIPHER_SUITE_PROPERTY, d.CIPHER); + System.setProperty("com.ibm.mq.ssl.keyStore", d.KEY_REPOSITORY); + System.setProperty("com.ibm.mq.ssl.keyStorePassword", ""); + } + + qMgr = new MQQueueManager(d.QMGR, props); + System.out.println("Connected to queue manager: " + d.QMGR); + + // Access using topic object name, not just string + topic = qMgr.accessTopic( + d.TOPIC_NAME, + null, // Topic Object defined in MQ + MQConstants.MQTOPIC_OPEN_AS_PUBLICATION, + MQConstants.MQOO_OUTPUT + ); + + MQMessage msg = new MQMessage(); + msg.format = MQConstants.MQFMT_STRING; + + String payload = "{\"Greeting\": \"Hello from Java publisher at " + java.time.Instant.now() + "\"}"; + msg.writeString(payload); + + MQPutMessageOptions pmo = new MQPutMessageOptions(); + pmo.options = MQConstants.MQPMO_NO_SYNCPOINT | + MQConstants.MQPMO_NEW_MSG_ID | + MQConstants.MQPMO_NEW_CORREL_ID | + MQConstants.MQPMO_WARN_IF_NO_SUBS_MATCHED; + + topic.put(msg, pmo); + + //System.out.println("Published message to topic object: DEV.BASE.TOPIC"); + System.out.println("Message content: " + payload); + + } catch (MQException mqe) { + if (mqe.reasonCode == MQConstants.MQRC_NO_SUBS_MATCHED) { + System.out.println("Warning: No subscribers matched the topic."); + } else { + mqe.printStackTrace(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (topic != null) topic.close(); + if (qMgr != null) qMgr.disconnect(); + } catch (MQException me) { + me.printStackTrace(); + } + } + } +} diff --git a/base-java/src/main/java/com/ibm/mq/samples/java/BasicPut.java b/base-java/src/main/java/com/ibm/mq/samples/java/BasicPut.java new file mode 100644 index 00000000..c87bcb0a --- /dev/null +++ b/base-java/src/main/java/com/ibm/mq/samples/java/BasicPut.java @@ -0,0 +1,122 @@ +package com.ibm.mq.samples.java; +import com.ibm.mq.*; +import com.ibm.mq.constants.MQConstants; +import org.json.*; + +import java.io.FileReader; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Hashtable; + +public class BasicPut { + + private static class MQDetails { + String QMGR; + String QUEUE_NAME; + String HOST; + String PORT; + String CHANNEL; + String USER; + String PASSWORD; + String KEY_REPOSITORY; + String CIPHER; + } + + private static JSONArray endpoints; + + public static void main(String[] args) { + loadEnv("env.json"); + + for (int i = 0; i < endpoints.length(); i++) { + System.out.println("Processing endpoint " + i); + JSONObject point = endpoints.getJSONObject(i); + MQDetails details = buildMQDetails(point); + processEndpoint(details); + } + + System.out.println("Sample MQ PUT application ending"); + System.exit(0); + } + + private static void loadEnv(String path) { + try { + String content = new String(Files.readAllBytes(Paths.get(path))); + JSONObject env = new JSONObject(content); + endpoints = env.getJSONArray("MQ_ENDPOINTS"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static MQDetails buildMQDetails(JSONObject endpoint) { + MQDetails mq = new MQDetails(); + mq.QMGR = endpoint.getString("QMGR"); + mq.QUEUE_NAME = endpoint.getString("QUEUE_NAME"); + mq.HOST = endpoint.getString("HOST"); + mq.PORT = String.valueOf(endpoint.getInt("PORT")); + mq.CHANNEL = endpoint.getString("CHANNEL"); + mq.USER = endpoint.getString("APP_USER"); + mq.PASSWORD = endpoint.getString("APP_PASSWORD"); + mq.KEY_REPOSITORY = endpoint.optString("KEY_REPOSITORY", ""); + mq.CIPHER = endpoint.optString("CIPHER", ""); + return mq; + } + + private static void processEndpoint(MQDetails details) { + MQQueueManager qMgr = null; + MQQueue queue = null; + + try { + Hashtable props = new Hashtable<>(); + String ccdtUrl = System.getenv("MQCCDTURL"); + + if (ccdtUrl != null && ccdtUrl.startsWith("file://")) { + String ccdtPath = ccdtUrl.replace("file://", ""); + System.setProperty("MQCCDTURL", ccdtPath); + System.out.println("Using CCDT at: " + ccdtPath); + } else { + props.put(MQConstants.HOST_NAME_PROPERTY, details.HOST); + props.put(MQConstants.PORT_PROPERTY, Integer.parseInt(details.PORT)); + props.put(MQConstants.CHANNEL_PROPERTY, details.CHANNEL); + } + + props.put(MQConstants.USER_ID_PROPERTY, details.USER); + props.put(MQConstants.PASSWORD_PROPERTY, details.PASSWORD); + props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); + + if (!details.KEY_REPOSITORY.isEmpty()) { + props.put(MQConstants.SSL_CIPHER_SUITE_PROPERTY, details.CIPHER); + System.setProperty("com.ibm.mq.ssl.keyStore", details.KEY_REPOSITORY); + System.setProperty("com.ibm.mq.ssl.keyStorePassword", ""); + } + + qMgr = new MQQueueManager(details.QMGR, props); + System.out.println("Connected to queue manager: " + details.QMGR); + + int openOptions = MQConstants.MQOO_OUTPUT; + queue = qMgr.accessQueue(details.QUEUE_NAME, openOptions); + + MQMessage msg = new MQMessage(); + msg.format = MQConstants.MQFMT_STRING; + + // Hardcoded message body for simplicity + String payload = "{\"greeting\": \"Hello from BasicPut.java\"}"; + msg.writeString(payload); + + MQPutMessageOptions pmo = new MQPutMessageOptions(); + queue.put(msg, pmo); + + System.out.println("Message put successfully: " + payload); + + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (queue != null) queue.close(); + if (qMgr != null) qMgr.disconnect(); + } catch (MQException me) { + me.printStackTrace(); + } + } + } +} diff --git a/base-java/src/main/java/com/ibm/mq/samples/java/BasicRequest.java b/base-java/src/main/java/com/ibm/mq/samples/java/BasicRequest.java new file mode 100644 index 00000000..3b458cab --- /dev/null +++ b/base-java/src/main/java/com/ibm/mq/samples/java/BasicRequest.java @@ -0,0 +1,123 @@ +package com.ibm.mq.samples.java; +import com.ibm.mq.*; +import com.ibm.mq.constants.MQConstants; +import org.json.JSONObject; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.Instant; +import java.util.Hashtable; + +public class BasicRequest { + + static class MQDetails { + String QMGR; + String HOST; + int PORT; + String CHANNEL; + String APP_USER; + String APP_PASSWORD; + String QUEUE_NAME; + String MODEL_QUEUE_NAME; + String DYNAMIC_QUEUE_PREFIX; + } + + static MQDetails mqDetails; + + public static void main(String[] args) { + loadEnv("env.json"); + sendRequestAndReceiveReply(mqDetails); + System.out.println("Sample MQ requester application ending"); + } + + private static void loadEnv(String path) { + try { + String content = new String(Files.readAllBytes(Paths.get(path))); + JSONObject endpoint = new JSONObject(content) + .getJSONArray("MQ_ENDPOINTS").getJSONObject(0); + + mqDetails = new MQDetails(); + mqDetails.QMGR = endpoint.getString("QMGR"); + mqDetails.HOST = endpoint.getString("HOST"); + mqDetails.PORT = endpoint.getInt("PORT"); + mqDetails.CHANNEL = endpoint.getString("CHANNEL"); + mqDetails.APP_USER = endpoint.getString("APP_USER"); + mqDetails.APP_PASSWORD = endpoint.getString("APP_PASSWORD"); + mqDetails.QUEUE_NAME = endpoint.getString("QUEUE_NAME"); + mqDetails.MODEL_QUEUE_NAME = endpoint.getString("MODEL_QUEUE_NAME"); + mqDetails.DYNAMIC_QUEUE_PREFIX = endpoint.getString("DYNAMIC_QUEUE_PREFIX"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void sendRequestAndReceiveReply(MQDetails d) { + MQQueueManager qMgr = null; + MQQueue requestQueue = null; + MQQueue replyQueue = null; + + try { + Hashtable props = new Hashtable<>(); + props.put(MQConstants.HOST_NAME_PROPERTY, d.HOST); + props.put(MQConstants.PORT_PROPERTY, d.PORT); + props.put(MQConstants.CHANNEL_PROPERTY, d.CHANNEL); + props.put(MQConstants.USER_ID_PROPERTY, d.APP_USER); + props.put(MQConstants.PASSWORD_PROPERTY, d.APP_PASSWORD); + props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); + + qMgr = new MQQueueManager(d.QMGR, props); + System.out.println("Connected to queue manager: " + d.QMGR); + + replyQueue = qMgr.accessQueue( + d.MODEL_QUEUE_NAME, + MQConstants.MQOO_INPUT_EXCLUSIVE, + null, + d.DYNAMIC_QUEUE_PREFIX, + null + ); + String dynamicReplyQueueName = replyQueue.getName(); + System.out.println("Opened dynamic reply-to queue: " + dynamicReplyQueueName); + + requestQueue = qMgr.accessQueue(d.QUEUE_NAME, MQConstants.MQOO_OUTPUT); + + MQMessage request = new MQMessage(); + request.format = MQConstants.MQFMT_STRING; + request.replyToQueueName = dynamicReplyQueueName; + request.messageType = MQConstants.MQMT_REQUEST; + + String payload = "{\"Greeting\": \"Hello from Java Requester at " + Instant.now() + "\"}"; + request.writeString(payload); + + MQPutMessageOptions pmo = new MQPutMessageOptions(); + pmo.options = MQConstants.MQPMO_NO_SYNCPOINT; + + requestQueue.put(request, pmo); + System.out.println("Sent request message to queue: " + d.QUEUE_NAME); + System.out.println("Waiting for reply on: " + dynamicReplyQueueName); + + MQMessage response = new MQMessage(); + MQGetMessageOptions gmo = new MQGetMessageOptions(); + gmo.options = MQConstants.MQGMO_WAIT | MQConstants.MQGMO_CONVERT; + gmo.waitInterval = 10000; + + replyQueue.get(response, gmo); + String replyText = response.readStringOfByteLength(response.getDataLength()); + System.out.println("Received reply: " + replyText); + + } catch (MQException mqe) { + System.err.println("MQ Error - Completion Code: " + mqe.completionCode + + " Reason Code: " + mqe.reasonCode); + mqe.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (requestQueue != null) requestQueue.close(); + if (replyQueue != null) replyQueue.close(); + if (qMgr != null) qMgr.disconnect(); + } catch (MQException e) { + e.printStackTrace(); + } + } + } +} diff --git a/base-java/src/main/java/com/ibm/mq/samples/java/BasicResponse.java b/base-java/src/main/java/com/ibm/mq/samples/java/BasicResponse.java new file mode 100644 index 00000000..81234635 --- /dev/null +++ b/base-java/src/main/java/com/ibm/mq/samples/java/BasicResponse.java @@ -0,0 +1,121 @@ +package com.ibm.mq.samples.java; +import com.ibm.mq.*; +import com.ibm.mq.constants.MQConstants; +import org.json.JSONObject; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Hashtable; + +public class BasicResponse { + + static class MQDetails { + String QMGR; + String HOST; + int PORT; + String CHANNEL; + String APP_USER; + String APP_PASSWORD; + String QUEUE_NAME; + } + + static MQDetails mqDetails; + + public static void main(String[] args) { + loadEnv("env.json"); + listenAndRespond(mqDetails); + System.out.println("Sample MQ responder application ending"); + } + + private static void loadEnv(String path) { + try { + String content = new String(Files.readAllBytes(Paths.get(path))); + JSONObject endpoint = new JSONObject(content) + .getJSONArray("MQ_ENDPOINTS").getJSONObject(0); + + mqDetails = new MQDetails(); + mqDetails.QMGR = endpoint.getString("QMGR"); + mqDetails.HOST = endpoint.getString("HOST"); + mqDetails.PORT = endpoint.getInt("PORT"); + mqDetails.CHANNEL = endpoint.getString("CHANNEL"); + mqDetails.APP_USER = endpoint.getString("APP_USER"); + mqDetails.APP_PASSWORD = endpoint.getString("APP_PASSWORD"); + mqDetails.QUEUE_NAME = endpoint.getString("QUEUE_NAME"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void listenAndRespond(MQDetails d) { + MQQueueManager qMgr = null; + MQQueue requestQueue = null; + + try { + Hashtable props = new Hashtable<>(); + props.put(MQConstants.HOST_NAME_PROPERTY, d.HOST); + props.put(MQConstants.PORT_PROPERTY, d.PORT); + props.put(MQConstants.CHANNEL_PROPERTY, d.CHANNEL); + props.put(MQConstants.USER_ID_PROPERTY, d.APP_USER); + props.put(MQConstants.PASSWORD_PROPERTY, d.APP_PASSWORD); + props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); + + qMgr = new MQQueueManager(d.QMGR, props); + System.out.println("Connected to queue manager: " + d.QMGR); + + requestQueue = qMgr.accessQueue( + d.QUEUE_NAME, + MQConstants.MQOO_INPUT_AS_Q_DEF | MQConstants.MQOO_OUTPUT + ); + + MQGetMessageOptions gmo = new MQGetMessageOptions(); + gmo.options = MQConstants.MQGMO_WAIT | MQConstants.MQGMO_CONVERT; + gmo.waitInterval = 10000; + + while (true) { + MQMessage request = new MQMessage(); + try { + requestQueue.get(request, gmo); + String msgText = request.readStringOfByteLength(request.getDataLength()); + System.out.println("Received request: " + msgText); + + String replyToQueueName = request.replyToQueueName; + if (replyToQueueName != null && !replyToQueueName.isEmpty()) { + MQQueue replyQueue = qMgr.accessQueue(replyToQueueName, MQConstants.MQOO_OUTPUT); + + MQMessage reply = new MQMessage(); + reply.format = MQConstants.MQFMT_STRING; + reply.correlationId = request.messageId; + + JSONObject replyJson = new JSONObject(); + replyJson.put("Response", "Hello from Java Responder!"); + reply.writeString(replyJson.toString()); + + MQPutMessageOptions pmo = new MQPutMessageOptions(); + pmo.options = MQConstants.MQPMO_NO_SYNCPOINT; + + replyQueue.put(reply, pmo); + System.out.println("Sent reply to: " + replyToQueueName); + replyQueue.close(); + } + } catch (MQException mqe) { + if (mqe.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) { + System.out.println("No message received. Exiting."); + break; + } else { + throw mqe; + } + } + } + + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (requestQueue != null) requestQueue.close(); + if (qMgr != null) qMgr.disconnect(); + } catch (MQException e) { + e.printStackTrace(); + } + } + } +} diff --git a/base-java/src/main/java/com/ibm/mq/samples/java/BasicSub.java b/base-java/src/main/java/com/ibm/mq/samples/java/BasicSub.java new file mode 100644 index 00000000..b517a6b1 --- /dev/null +++ b/base-java/src/main/java/com/ibm/mq/samples/java/BasicSub.java @@ -0,0 +1,133 @@ +package com.ibm.mq.samples.java; +import com.ibm.mq.*; +import com.ibm.mq.constants.MQConstants; +import org.json.*; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Hashtable; + +public class BasicSub { + + private static class MQDetails { + String QMGR; + String SUB_NAME; + String QUEUE_NAME; + String HOST; + String PORT; + String CHANNEL; + String USER; + String PASSWORD; + String KEY_REPOSITORY; + String CIPHER; + } + + private static MQDetails mqDetails; + + public static void main(String[] args) { + loadEnv("env.json"); + subscribeToQueue(mqDetails); + System.out.println("Sample MQ durable SUB application ending"); + } + + private static void loadEnv(String path) { + try { + String content = new String(Files.readAllBytes(Paths.get(path))); + JSONObject env = new JSONObject(content); + JSONObject endpoint = env.getJSONArray("MQ_ENDPOINTS").getJSONObject(0); + + mqDetails = new MQDetails(); + mqDetails.QMGR = endpoint.getString("QMGR"); + mqDetails.SUB_NAME = endpoint.getString("SUB_NAME"); + mqDetails.QUEUE_NAME = endpoint.getString("QUEUE_NAME"); // ✅ Fix + mqDetails.HOST = endpoint.getString("HOST"); + mqDetails.PORT = String.valueOf(endpoint.getInt("PORT")); + mqDetails.CHANNEL = endpoint.getString("CHANNEL"); + mqDetails.USER = endpoint.getString("APP_USER"); + mqDetails.PASSWORD = endpoint.getString("APP_PASSWORD"); + mqDetails.KEY_REPOSITORY = endpoint.optString("KEY_REPOSITORY", ""); + mqDetails.CIPHER = endpoint.optString("CIPHER", ""); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void subscribeToQueue(MQDetails d) { + MQQueueManager qMgr = null; + MQQueue queue = null; + + try { + Hashtable props = new Hashtable<>(); + + String ccdtUrl = System.getenv("MQCCDTURL"); + if (ccdtUrl != null && ccdtUrl.startsWith("file://")) { + String ccdtPath = ccdtUrl.replace("file://", ""); + System.setProperty("MQCCDTURL", ccdtPath); + System.out.println("Using CCDT at: " + ccdtPath); + } else { + props.put(MQConstants.HOST_NAME_PROPERTY, d.HOST); + props.put(MQConstants.PORT_PROPERTY, Integer.parseInt(d.PORT)); + props.put(MQConstants.CHANNEL_PROPERTY, d.CHANNEL); + } + + props.put(MQConstants.USER_ID_PROPERTY, d.USER); + props.put(MQConstants.PASSWORD_PROPERTY, d.PASSWORD); + props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); + + if (!d.KEY_REPOSITORY.isEmpty()) { + props.put(MQConstants.SSL_CIPHER_SUITE_PROPERTY, d.CIPHER); + System.setProperty("com.ibm.mq.ssl.keyStore", d.KEY_REPOSITORY); + System.setProperty("com.ibm.mq.ssl.keyStorePassword", ""); + } + + qMgr = new MQQueueManager(d.QMGR, props); + System.out.println("Connected to queue manager: " + d.QMGR); + + int openOptions = MQConstants.MQOO_INPUT_AS_Q_DEF | MQConstants.MQOO_FAIL_IF_QUIESCING; + queue = qMgr.accessQueue(d.QUEUE_NAME, openOptions); + + receiveMessages(queue); + + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (queue != null) queue.close(); + if (qMgr != null) qMgr.disconnect(); + } catch (MQException e) { + e.printStackTrace(); + } + } + } + + private static void receiveMessages(MQQueue queue) { + try { + MQMessage msg = new MQMessage(); + MQGetMessageOptions gmo = new MQGetMessageOptions(); + gmo.options = MQConstants.MQGMO_NO_SYNCPOINT | + MQConstants.MQGMO_WAIT | + MQConstants.MQGMO_CONVERT | + MQConstants.MQGMO_FAIL_IF_QUIESCING; + gmo.waitInterval = 10000; + + System.out.println("Waiting for messages from durable subscription queue..."); + while (true) { + msg.clearMessage(); + try { + queue.get(msg, gmo); + String received = msg.readStringOfByteLength(msg.getDataLength()); + System.out.println("Received: " + received); + } catch (MQException mqe) { + if (mqe.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) { + System.out.println("No messages. Exiting."); + break; + } else { + throw mqe; + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} From 6a413051afa878877e61cd8ac8fa28d43ae66658 Mon Sep 17 00:00:00 2001 From: Stuti Uniyal Date: Fri, 4 Jul 2025 14:14:00 +0530 Subject: [PATCH 2/8] updated readme --- base-java/Readme.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/base-java/Readme.md b/base-java/Readme.md index 3fd7bb90..b889cb9d 100644 --- a/base-java/Readme.md +++ b/base-java/Readme.md @@ -114,7 +114,25 @@ In the **second terminal (request)**: ```bash mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicRequest" -Dexec.args="env.json" ``` +### Terminal 1: Run the Request Sample +1. **Compile** the `BasicRequest.java` file using the required JAR dependencies. +2. **Run** the `BasicRequest` class. +3. The requester sends a message and waits for a response. +4. If `REPLY_QUEUE_NAME` is set, that queue is used for replies; otherwise, a temporary queue is created. +5. Optionally, set the `REQUEST_MESSAGE_EXPIRY` environment variable to define how long the request is valid. + +--- + +### Terminal 2: Run the Response Sample + +1. **Compile** the `BasicResponse.java` file with the same JAR dependencies. +2. **Run** the `BasicResponse` class. +3. The responder listens on a queue, processes incoming messages, and sends replies to the specified reply-to queue. +4. It continues running until manually stopped or it times out. +5. You can set the `RESPONDER_INACTIVITY_TIMEOUT` environment variable to control how long it waits for new messages before exiting. + +--- ## Notes - The environment can be configured using either `env.json` or a CCDT file via the `MQCCDTURL` environment variable. From 5507019744ed396072f66b3693f3773a155eeec5 Mon Sep 17 00:00:00 2001 From: Stuti Uniyal Date: Thu, 10 Jul 2025 01:20:45 +0530 Subject: [PATCH 3/8] address review comments --- Java-MQ/Readme.md | 148 ++++++++++++++++++ Java-MQ/pom.xml | 73 +++++++++ .../ibm/mq/samples/java/BasicConsumer.java | 69 ++++++++ .../mq/samples/java/BasicConsumerWrapper.java | 73 +++++++++ .../com/ibm/mq/samples/java/BasicGet.java | 25 +++ .../ibm/mq/samples/java/BasicProducer.java | 85 ++++++++++ .../mq/samples/java/BasicProducerWrapper.java | 78 +++++++++ .../com/ibm/mq/samples/java/BasicPub.java | 25 +++ .../ibm/mq/samples/java/BasicPubWrapper.java | 82 ++++++++++ .../com/ibm/mq/samples/java/BasicPut.java | 24 +++ .../com/ibm/mq/samples/java/BasicRequest.java | 24 +++ .../mq/samples/java/BasicRequestWrapper.java | 93 +++++++++++ .../ibm/mq/samples/java/BasicResponse.java | 25 +++ .../mq/samples/java/BasicResponseWrapper.java | 110 +++++++++++++ .../com/ibm/mq/samples/java/BasicSub.java | 24 +++ .../ibm/mq/samples/java/BasicSubWrapper.java | 71 +++++++++ .../com/ibm/mq/samples/java/MQDetails.java | 101 ++++++++++++ .../ibm/mq/samples/java/SampleEnvSetter.java | 108 +++++++++++++ 18 files changed, 1238 insertions(+) create mode 100644 Java-MQ/Readme.md create mode 100644 Java-MQ/pom.xml create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicConsumer.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicConsumerWrapper.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicGet.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicProducer.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicProducerWrapper.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicPub.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicPubWrapper.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicPut.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicRequest.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicRequestWrapper.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicResponse.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicResponseWrapper.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicSub.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicSubWrapper.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/MQDetails.java create mode 100644 Java-MQ/src/main/java/com/ibm/mq/samples/java/SampleEnvSetter.java diff --git a/Java-MQ/Readme.md b/Java-MQ/Readme.md new file mode 100644 index 00000000..85ca2f7d --- /dev/null +++ b/Java-MQ/Readme.md @@ -0,0 +1,148 @@ +# IBM Java-MQ Samples + +This project provides a set of base Java samples for interacting with IBM MQ using the IBM MQ classes for Java (non-JMS). These include basic examples for put/get, publish/subscribe, and request/response messaging patterns. + +## Samples Included + +Each sample is located under: + +``` +src/main/java/com/ibm/mq/samples/java/ +``` + +- `BasicPut.java` – Puts a message onto a queue +- `BasicGet.java` – Gets a message from a queue +- `BasicPub.java` – Publishes a message to a queue (persisted publish) +- `BasicSub.java` – Subscribes and receives messages from a queue +- `BasicRequest.java` – Sends a message with a dynamic reply-to queue +- `BasicResponse.java` – Responds to requests received from a queue +- `BasicProducer.java` – Produces a message to a queue (used by request wrappers) +- `BasicConsumer.java` – Consumes a message from a queue (used by request/response logic) +- `MQDetails.java` – POJO to hold MQ connection configuration +- `SampleEnvSetter.java` – Utility to parse `env.json` and load MQ endpoint configurations +- Wrapper Classes (used internally for iterating over endpoints): + - `BasicPutWrapper.java` + - `BasicGetWrapper.java` + - `BasicPubWrapper.java` + - `BasicSubWrapper.java` + - `BasicRequestWrapper.java` + - `BasicResponseWrapper.java` + +> **Note**: Wrapper classes are utility helpers and should not be run directly. + +## Prerequisites + +- Java 8 or higher +- Apache Maven +- IBM MQ installed and running (locally or remotely) + +## Project Setup + +This is a standard Maven project. All dependencies and build instructions are managed through `pom.xml`. + +### Building the Project + +To build the project and download dependencies: + +```bash +mvn clean package +``` + +## Running the Samples + +Ensure that your environment configuration file (`env.json`) is properly set up. + +## Using a CCDT File + +Instead of manually specifying connection parameters in `env.json`, you can use a **Client Channel Definition Table (CCDT)** JSON file to define connection configurations. This is useful when connecting to IBM MQ instances in cloud or enterprise environments. + +Set the environment variable `MQCCDTURL` to point to the CCDT file: + +```bash +export MQCCDTURL=file:/absolute/path/to/ccdt.json +``` + +> **Note (Windows):** Use `set` instead of `export`: +> +> ```cmd +> set MQCCDTURL=file:C:\path\to\ccdt.json +> ``` + +The sample will detect `MQCCDTURL` and automatically use it for connection settings. When `MQCCDTURL` is set and starts with `file://`, the program prioritizes CCDT-based configuration and skips `host`, `channel`, and `port` in `env.json`. + +Make sure your CCDT file defines the appropriate connection information such as **channel name**, **queue manager**, and **connection name list**. + +## Run Instructions + +All samples should be run using the following format: + +```bash +mvn exec:java \ + -Dexec.mainClass="com.ibm.mq.samples.java." \ + -Dexec.args="-Dcom.ibm.mq.cfg.jmqiDisableAsyncThreads=true" \ + -Dexec.jvmArgs="-DENV_FILE=./env.json" +``` + +### Put + +```bash +mvn exec:java \ + -Dexec.mainClass="com.ibm.mq.samples.java.BasicPut" \ + -Dexec.args="-Dcom.ibm.mq.cfg.jmqiDisableAsyncThreads=true" \ + -Dexec.jvmArgs="-DENV_FILE=./env.json" +``` +### Get + +```bash +mvn exec:java \ + -Dexec.mainClass="com.ibm.mq.samples.java.BasicGet" \ + -Dexec.args="-Dcom.ibm.mq.cfg.jmqiDisableAsyncThreads=true" \ + -Dexec.jvmArgs="-DENV_FILE=./env.json" +``` + +### Publish/Subscribe + +**First terminal (subscriber):** + +```bash +mvn exec:java \ + -Dexec.mainClass="com.ibm.mq.samples.java.BasicSub" \ + -Dexec.args="-Dcom.ibm.mq.cfg.jmqiDisableAsyncThreads=true" \ + -Dexec.jvmArgs="-DENV_FILE=./env.json" +``` + +**Second terminal (publisher):** + +```bash +mvn exec:java \ + -Dexec.mainClass="com.ibm.mq.samples.java.BasicPub" \ + -Dexec.args="-Dcom.ibm.mq.cfg.jmqiDisableAsyncThreads=true" \ + -Dexec.jvmArgs="-DENV_FILE=./env.json" +``` + +### Request/Response + +**First terminal (response):** + +```bash +mvn exec:java \ + -Dexec.mainClass="com.ibm.mq.samples.java.BasicResponse" \ + -Dexec.args="-Dcom.ibm.mq.cfg.jmqiDisableAsyncThreads=true" \ + -Dexec.jvmArgs="-DENV_FILE=./env.json" +``` + +**Second terminal (request):** + +```bash +mvn exec:java \ + -Dexec.mainClass="com.ibm.mq.samples.java.BasicRequest" \ + -Dexec.args="-Dcom.ibm.mq.cfg.jmqiDisableAsyncThreads=true" \ + -Dexec.jvmArgs="-DENV_FILE=./env.json" +``` + +## Notes + +- The environment can be configured using either `env.json` or a CCDT file via the `MQCCDTURL` environment variable. +- Samples like `BasicResponse` and `BasicSub` are long-running and wait for messages until terminated or a timeout occurs. +- **Wrapper classes** are designed to iterate over all endpoints in `env.json`, but are not meant to be executed directly from the command line. +- Make sure all relevant queues and topics are pre-created in your IBM MQ queue manager. diff --git a/Java-MQ/pom.xml b/Java-MQ/pom.xml new file mode 100644 index 00000000..d8a8e2bb --- /dev/null +++ b/Java-MQ/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + com.ibm.mq.samples + base-mq-java + 1.0.0 + jar + + + 1.8 + 1.8 + + + + + + com.ibm.mq + com.ibm.mq.allclient + 9.4.3.0 + + + + + org.json + json + 20240303 + + + + + + + maven-compiler-plugin + 3.8.1 + + 1.8 + + + + + + + + + + + + + + + + diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicConsumer.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicConsumer.java new file mode 100644 index 00000000..7073be53 --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicConsumer.java @@ -0,0 +1,69 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +import com.ibm.mq.*; +import com.ibm.mq.constants.MQConstants; + +import java.io.IOException; +import java.util.Hashtable; + +public class BasicConsumer { + + public static final String CONSUMER_GET = "queue"; + public static final String CONSUMER_SUB = "topic"; + public static final String CONSUMER_REQUEST = "model_queue"; + + public Boolean getMessage(MQDetails details, Hashtable props, MQQueue queue, String mode) { + + MQMessage msg = new MQMessage(); + MQGetMessageOptions gmo = new MQGetMessageOptions(); + + if (mode.equals(CONSUMER_GET)) { + gmo.options = MQConstants.MQGMO_NO_WAIT | + MQConstants.MQGMO_CONVERT | + MQConstants.MQGMO_FAIL_IF_QUIESCING; + } else if (mode.equals(CONSUMER_SUB)) { + gmo.options = MQConstants.MQGMO_NO_SYNCPOINT | + MQConstants.MQGMO_WAIT | + MQConstants.MQGMO_CONVERT | + MQConstants.MQGMO_FAIL_IF_QUIESCING; + gmo.waitInterval = 10000; + } else if (mode.equals(CONSUMER_REQUEST)) { + gmo.options = MQConstants.MQGMO_WAIT | MQConstants.MQGMO_CONVERT; + gmo.waitInterval = 10000; + } + + try { + queue.get(msg, gmo); + String str = msg.readStringOfByteLength(msg.getDataLength()); + System.out.println("Received message: " + str); + } catch (MQException mqe) { + if (mqe.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) { + System.out.println("No more messages."); + return false; + } else { + System.err.println("Error retrieving message: " + mqe); + return false; + } + } catch (IOException e) { + e.printStackTrace(); + return false; + } + + return true; + } +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicConsumerWrapper.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicConsumerWrapper.java new file mode 100644 index 00000000..93d382d5 --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicConsumerWrapper.java @@ -0,0 +1,73 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +import com.ibm.mq.constants.MQConstants; + +import java.util.Hashtable; + +import com.ibm.mq.*; + +public class BasicConsumerWrapper { + + MQQueueManager qMgr = null; + MQQueue queue = null; + + public void sendMessage() { + + SampleEnvSetter envSetter = new SampleEnvSetter(); + envSetter.setEnvValues(); + + // iterate for every endpoint in env.json + int length = envSetter.getDetails().size(); + System.out.println(length); + + for (int i = 0; i < length; i++) { + MQDetails details = envSetter.getDetails().get(i); + Hashtable props = envSetter.getProps().get(i); + System.out.println("Wrapper: "+props); + + System.out.println("Wrapper QMGR: "+props); + try { + qMgr = new MQQueueManager(details.getQMGR(), props); + System.out.println("Connected to queue manager: " + details.getQMGR()); + + int openOptions = MQConstants.MQOO_INPUT_AS_Q_DEF; + queue = qMgr.accessQueue(details.getQUEUE_NAME(), openOptions); + + System.out.println("Wrapper Queue: "+queue); + + boolean keepReading = true; + BasicConsumer bc = new BasicConsumer(); + while (keepReading) { + keepReading = bc.getMessage(details, props, queue,BasicConsumer.CONSUMER_GET); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (queue != null) + queue.close(); + if (qMgr != null) + qMgr.disconnect(); + } catch (MQException me) { + me.printStackTrace(); + } + } + } + } + +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicGet.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicGet.java new file mode 100644 index 00000000..5e8a0062 --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicGet.java @@ -0,0 +1,25 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +public class BasicGet { + + public static void main(String[] args) { + BasicConsumerWrapper wrapper = new BasicConsumerWrapper(); + wrapper.sendMessage(); + } + +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicProducer.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicProducer.java new file mode 100644 index 00000000..50a93a4a --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicProducer.java @@ -0,0 +1,85 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +import com.ibm.mq.*; +import com.ibm.mq.constants.MQConstants; + +import java.io.IOException; +import java.util.Hashtable; + +public class BasicProducer { + + public static final String PRODUCER_PUT = "queue"; + public static final String PRODUCER_PUBLISH = "topic"; + public static final String PRODUCER_RESPONSE = "model_queue"; + + public Boolean putMessage(MQDetails details, Hashtable props, MQDestination destination, String mode, String message, String replyToQueueName) { + + MQMessage mqMessage = new MQMessage(); + MQPutMessageOptions pmo = new MQPutMessageOptions(); + + try { + // Write the payload + mqMessage.writeString(message); + + // Set common message properties + mqMessage.format = MQConstants.MQFMT_STRING; + + switch (mode) { + case PRODUCER_PUT: + mqMessage.persistence = MQConstants.MQPER_PERSISTENT; + break; + + case PRODUCER_PUBLISH: + mqMessage.persistence = MQConstants.MQPER_PERSISTENT; + break; + + case PRODUCER_RESPONSE: + mqMessage.persistence = MQConstants.MQPER_NOT_PERSISTENT; + if (replyToQueueName != null && !replyToQueueName.isEmpty()) { + mqMessage.replyToQueueName = replyToQueueName; + } + break; + + default: + System.err.println("Invalid producer mode."); + return false; + } + + // Send message + if (destination instanceof MQQueue) { + ((MQQueue) destination).put(mqMessage, pmo); + } else if (destination instanceof MQTopic) { + ((MQTopic) destination).put(mqMessage, pmo); + } else { + System.err.println("Unsupported MQDestination type."); + return false; + } + + System.out.println("Message sent: " + message); + return true; + + } catch (MQException mqe) { + System.err.println("MQException during put: " + mqe.getMessage()); + return false; + + } catch (IOException ioe) { + System.err.println("IOException during put: " + ioe.getMessage()); + return false; + } + } +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicProducerWrapper.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicProducerWrapper.java new file mode 100644 index 00000000..c79f7c8f --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicProducerWrapper.java @@ -0,0 +1,78 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +import com.ibm.mq.*; +import com.ibm.mq.constants.MQConstants; + +import java.util.Hashtable; + +public class BasicProducerWrapper { + + MQQueueManager qMgr = null; + MQQueue queue = null; + + public void sendMessage() { + + SampleEnvSetter envSetter = new SampleEnvSetter(); + envSetter.setEnvValues(); + + int length = envSetter.getDetails().size(); + System.out.println("Total MQ endpoints: " + length); + + for (int i = 0; i < length; i++) { + MQDetails details = envSetter.getDetails().get(i); + Hashtable props = envSetter.getProps().get(i); + System.out.println("ProducerWrapper Properties: " + props); + + try { + // Connect to Queue Manager + qMgr = new MQQueueManager(details.getQMGR(), props); + System.out.println("Connected to queue manager: " + details.getQMGR()); + + // Open queue for output + int openOptions = MQConstants.MQOO_OUTPUT | MQConstants.MQOO_FAIL_IF_QUIESCING; + queue = qMgr.accessQueue(details.getQUEUE_NAME(), openOptions); + System.out.println("Opened queue: " + details.getQUEUE_NAME()); + + // Send message + BasicProducer producer = new BasicProducer(); + String sampleMessage = "Hello from BasicProducerWrapper!"; + boolean status = producer.putMessage(details, props, queue, BasicProducer.PRODUCER_PUT, sampleMessage, null); + + if (status) { + System.out.println("Message successfully sent."); + } else { + System.err.println("Message sending failed."); + } + + } catch (Exception e) { + System.err.println("Error during message send:"); + e.printStackTrace(); + } finally { + try { + if (queue != null) + queue.close(); + if (qMgr != null) + qMgr.disconnect(); + } catch (MQException me) { + System.err.println("Error closing MQ resources:"); + me.printStackTrace(); + } + } + } + } +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicPub.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicPub.java new file mode 100644 index 00000000..c49d3c46 --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicPub.java @@ -0,0 +1,25 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +public class BasicPub { + + public static void main(String[] args) { + BasicPubWrapper wrapper = new BasicPubWrapper(); + wrapper.sendMessage(); + System.out.println("Sample MQ PUB application ending"); + } +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicPubWrapper.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicPubWrapper.java new file mode 100644 index 00000000..71248179 --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicPubWrapper.java @@ -0,0 +1,82 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +import com.ibm.mq.*; +import com.ibm.mq.constants.MQConstants; + +import java.time.Instant; +import java.util.Hashtable; + +public class BasicPubWrapper { + + MQQueueManager qMgr = null; + MQQueue queue = null; + + public void sendMessage() { + + SampleEnvSetter envSetter = new SampleEnvSetter(); + envSetter.setEnvValues(); + + int length = envSetter.getDetails().size(); + System.out.println("Total endpoints: " + length); + + for (int i = 0; i < length; i++) { + MQDetails details = envSetter.getDetails().get(i); + Hashtable props = envSetter.getProps().get(i); + + try { + qMgr = new MQQueueManager(details.getQMGR(), props); + System.out.println("Connected to queue manager: " + details.getQMGR()); + + queue = qMgr.accessQueue( + details.getQUEUE_NAME(), + MQConstants.MQOO_OUTPUT | MQConstants.MQOO_FAIL_IF_QUIESCING + ); + + MQMessage msg = new MQMessage(); + msg.format = MQConstants.MQFMT_STRING; + msg.persistence = MQConstants.MQPER_PERSISTENT; + + String payload = "{\"Greeting\": \"Hello from Java publisher at " + Instant.now() + "\"}"; + msg.writeString(payload); + + MQPutMessageOptions pmo = new MQPutMessageOptions(); + pmo.options = MQConstants.MQPMO_NO_SYNCPOINT | + MQConstants.MQPMO_NEW_MSG_ID | + MQConstants.MQPMO_NEW_CORREL_ID; + + queue.put(msg, pmo); + + System.out.println("Published message to queue: " + details.getQUEUE_NAME()); + System.out.println("Message content: " + payload); + + } catch (MQException mqe) { + System.err.println("MQ error publishing message: " + mqe.getMessage()); + mqe.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (queue != null) queue.close(); + if (qMgr != null) qMgr.disconnect(); + } catch (MQException me) { + me.printStackTrace(); + } + } + } + } +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicPut.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicPut.java new file mode 100644 index 00000000..0d00637d --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicPut.java @@ -0,0 +1,24 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +public class BasicPut { + + public static void main(String[] args) { + BasicProducerWrapper wrapper = new BasicProducerWrapper(); + wrapper.sendMessage(); + } +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicRequest.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicRequest.java new file mode 100644 index 00000000..3736550e --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicRequest.java @@ -0,0 +1,24 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; +public class BasicRequest { + + public static void main(String[] args) { + BasicRequestWrapper wrapper = new BasicRequestWrapper(); + wrapper.sendMessage(); + System.exit(0); + } +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicRequestWrapper.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicRequestWrapper.java new file mode 100644 index 00000000..e7a5d4ae --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicRequestWrapper.java @@ -0,0 +1,93 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +import java.time.Instant; +import java.util.Hashtable; + +import com.ibm.mq.constants.MQConstants; + +import com.ibm.mq.*; + +public class BasicRequestWrapper { + + MQQueueManager qMgr = null; + MQQueue queue = null; + + public void sendMessage() { + + SampleEnvSetter envSetter = new SampleEnvSetter(); + envSetter.setEnvValues(); + + // iterate for every endpoint in env.json + int length = envSetter.getDetails().size(); + System.out.println(length); + + for (int i = 0; i < length; i++) { + MQDetails details = envSetter.getDetails().get(i); + Hashtable props = envSetter.getProps().get(i); + try { + qMgr = new MQQueueManager(details.getQMGR(), props); + System.out.println("Connected to queue manager: " + details.getQMGR()); + + MQQueue replyQueue = qMgr.accessQueue( + details.getMODEL_QUEUE_NAME(), + MQConstants.MQOO_INPUT_EXCLUSIVE, + null, + details.getDYNAMIC_QUEUE_PREFIX(), + null); + + String dynamicReplyQueueName = replyQueue.getName(); + System.out.println("Opened dynamic reply-to queue: " + dynamicReplyQueueName); + + MQQueue requestQueue = qMgr.accessQueue(details.getQUEUE_NAME(), MQConstants.MQOO_OUTPUT); + + MQMessage request = new MQMessage(); + request.format = MQConstants.MQFMT_STRING; + request.replyToQueueName = dynamicReplyQueueName; + request.messageType = MQConstants.MQMT_REQUEST; + + String payload = "{\"Greeting\": \"Hello from Java Requester at " + Instant.now() + "\"}"; + request.writeString(payload); + + MQPutMessageOptions pmo = new MQPutMessageOptions(); + pmo.options = MQConstants.MQPMO_NO_SYNCPOINT; + + requestQueue.put(request, pmo); + System.out.println("Sent request message to queue: " + details.getQUEUE_NAME()); + System.out.println("Waiting for reply on: " + dynamicReplyQueueName); + + boolean keepReading = true; + BasicConsumer bc = new BasicConsumer(); + while (keepReading) { + keepReading = bc.getMessage(details, props, replyQueue, BasicConsumer.CONSUMER_REQUEST); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (queue != null) + queue.close(); + if (qMgr != null) + qMgr.disconnect(); + } catch (MQException me) { + me.printStackTrace(); + } + } + } + } + +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicResponse.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicResponse.java new file mode 100644 index 00000000..b4d1d9f1 --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicResponse.java @@ -0,0 +1,25 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +public class BasicResponse { + + public static void main(String[] args) { + BasicResponseWrapper wrapper = new BasicResponseWrapper(); + wrapper.respondToMessages(); + System.exit(0); + } +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicResponseWrapper.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicResponseWrapper.java new file mode 100644 index 00000000..00bf8386 --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicResponseWrapper.java @@ -0,0 +1,110 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +import com.ibm.mq.*; +import com.ibm.mq.constants.MQConstants; + +import java.util.Hashtable; + +public class BasicResponseWrapper { + + MQQueueManager qMgr = null; + MQQueue queue = null; + + public void respondToMessages() { + + SampleEnvSetter envSetter = new SampleEnvSetter(); + envSetter.setEnvValues(); + + int length = envSetter.getDetails().size(); + System.out.println("Total endpoints: " + length); + + for (int i = 0; i < length; i++) { + MQDetails details = envSetter.getDetails().get(i); + Hashtable props = envSetter.getProps().get(i); + + try { + qMgr = new MQQueueManager(details.getQMGR(), props); + System.out.println("Connected to queue manager: " + details.getQMGR()); + + queue = qMgr.accessQueue( + details.getQUEUE_NAME(), + MQConstants.MQOO_INPUT_AS_Q_DEF | MQConstants.MQOO_OUTPUT | MQConstants.MQOO_INQUIRE + ); + + boolean keepRunning = true; + while (keepRunning) { + MQMessage requestMsg = new MQMessage(); + MQGetMessageOptions gmo = new MQGetMessageOptions(); + gmo.options = MQConstants.MQGMO_WAIT | MQConstants.MQGMO_CONVERT; + gmo.waitInterval = 10000; // wait 10 seconds + + try { + queue.get(requestMsg, gmo); + String body = requestMsg.readStringOfByteLength(requestMsg.getDataLength()); + System.out.println("Received request: " + body); + + // Get reply-to queue name + String replyToQueue = requestMsg.replyToQueueName; + if (replyToQueue == null || replyToQueue.isEmpty()) { + System.out.println("No reply-to queue specified. Skipping response."); + continue; + } + + // Create a response message + MQMessage responseMsg = new MQMessage(); + responseMsg.format = MQConstants.MQFMT_STRING; + responseMsg.messageType = MQConstants.MQMT_REPLY; + String replyPayload = "{\"Response\": \"Reply to message: " + body + "\"}"; + responseMsg.writeString(replyPayload); + + MQPutMessageOptions pmo = new MQPutMessageOptions(); + pmo.options = MQConstants.MQPMO_NO_SYNCPOINT; + + // Put the message to the dynamic reply queue + MQQueue replyQueue = qMgr.accessQueue(replyToQueue, MQConstants.MQOO_OUTPUT); + replyQueue.put(responseMsg, pmo); + replyQueue.close(); + + System.out.println("Sent reply to: " + replyToQueue); + System.out.println("Reply payload: " + replyPayload); + + } catch (MQException mqe) { + if (mqe.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) { + System.out.println("No more messages. Exiting..."); + keepRunning = false; + } else { + System.err.println("MQ error getting/putting message: " + mqe.getMessage()); + } + } + } + + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (queue != null) + queue.close(); + if (qMgr != null) + qMgr.disconnect(); + } catch (MQException me) { + me.printStackTrace(); + } + } + } + } +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicSub.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicSub.java new file mode 100644 index 00000000..d602080c --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicSub.java @@ -0,0 +1,24 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +public class BasicSub { + + public static void main(String[] args) { + BasicSubWrapper wrapper = new BasicSubWrapper(); + wrapper.sendMessage(); + } +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicSubWrapper.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicSubWrapper.java new file mode 100644 index 00000000..46d16f02 --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/BasicSubWrapper.java @@ -0,0 +1,71 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +import java.util.Hashtable; + +import com.ibm.mq.MQException; +import com.ibm.mq.constants.MQConstants; + +import com.ibm.mq.*; + +public class BasicSubWrapper { + + MQQueueManager qMgr = null; + MQQueue queue = null; + + public void sendMessage() { + + SampleEnvSetter envSetter = new SampleEnvSetter(); + envSetter.setEnvValues(); + + // iterate for every endpoint in env.json + int length = envSetter.getDetails().size(); + System.out.println(length); + + for (int i = 0; i < length; i++) { + MQDetails details = envSetter.getDetails().get(i); + Hashtable props = envSetter.getProps().get(i); + try { + qMgr = new MQQueueManager(details.getQMGR(), props); + System.out.println("Connected to queue manager: " + details.getQMGR()); + + int openOptions = MQConstants.MQOO_INPUT_AS_Q_DEF; + queue = qMgr.accessQueue(details.getQUEUE_NAME(), openOptions); + + System.out.println("Wrapper Queue: " + queue); + + boolean keepReading = true; + BasicConsumer bc = new BasicConsumer(); + while (keepReading) { + keepReading = bc.getMessage(details, props, queue, BasicConsumer.CONSUMER_SUB); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (queue != null) + queue.close(); + if (qMgr != null) + qMgr.disconnect(); + } catch (MQException me) { + me.printStackTrace(); + } + } + } + } + +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/MQDetails.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/MQDetails.java new file mode 100644 index 00000000..25519e3a --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/MQDetails.java @@ -0,0 +1,101 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +import org.json.JSONObject; + +public class MQDetails { + + private String QMGR; + private String QUEUE_NAME; + private String HOST; + private String PORT; + private String CHANNEL; + private String USER; + private String PASSWORD; + private String KEY_REPOSITORY; + private String CIPHER; + private String MODEL_QUEUE_NAME; + private String DYNAMIC_QUEUE_PREFIX; + + public MQDetails buildMQDetails(JSONObject endpoint) { + this.QMGR = endpoint.getString("QMGR"); + this.QUEUE_NAME = endpoint.getString("QUEUE_NAME"); + this.HOST = endpoint.getString("HOST"); + this.PORT = String.valueOf(endpoint.getInt("PORT")); + this.CHANNEL = endpoint.getString("CHANNEL"); + this.USER = endpoint.getString("APP_USER"); + this.PASSWORD = endpoint.getString("APP_PASSWORD"); + this.KEY_REPOSITORY = endpoint.optString("KEY_REPOSITORY", ""); + this.CIPHER = endpoint.optString("CIPHER", ""); + this.MODEL_QUEUE_NAME = endpoint.optString("MODEL_QUEUE_NAME", ""); + this.DYNAMIC_QUEUE_PREFIX = endpoint.optString("DYNAMIC_QUEUE_PREFIX", ""); + + return this; + } + + public String getQMGR() { + return QMGR; + } + + public String getQUEUE_NAME() { + return QUEUE_NAME; + } + + public String getHOST() { + return HOST; + } + + public String getPORT() { + return PORT; + } + + public String getCHANNEL() { + return CHANNEL; + } + + public String getUSER() { + return USER; + } + + public String getPASSWORD() { + return PASSWORD; + } + + public String getKEY_REPOSITORY() { + return KEY_REPOSITORY; + } + + public String getCIPHER() { + return CIPHER; + } + + public String getMODEL_QUEUE_NAME() { + return MODEL_QUEUE_NAME; + } + + public String getDYNAMIC_QUEUE_PREFIX() { + return DYNAMIC_QUEUE_PREFIX; + } + + @Override + public String toString() { + return "MQDetails [QMGR=" + QMGR + ", QUEUE_NAME=" + QUEUE_NAME + ", HOST=" + HOST + ", PORT=" + PORT + + ", CHANNEL=" + CHANNEL + ", USER=" + USER + ", PASSWORD=" + PASSWORD + ", KEY_REPOSITORY=" + + KEY_REPOSITORY + ", CIPHER=" + CIPHER + ", MODEL_QUEUE_NAME=" + MODEL_QUEUE_NAME + + ", DYNAMIC_QUEUE_PREFIX=" + DYNAMIC_QUEUE_PREFIX + "]"; + } +} diff --git a/Java-MQ/src/main/java/com/ibm/mq/samples/java/SampleEnvSetter.java b/Java-MQ/src/main/java/com/ibm/mq/samples/java/SampleEnvSetter.java new file mode 100644 index 00000000..1045248e --- /dev/null +++ b/Java-MQ/src/main/java/com/ibm/mq/samples/java/SampleEnvSetter.java @@ -0,0 +1,108 @@ +/* +* (c) Copyright IBM Corporation 2025 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.ibm.mq.samples.java; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONObject; + +import com.ibm.mq.constants.MQConstants; + +public class SampleEnvSetter { + + private JSONArray endpoints; + private List details; + private List> props; + + public SampleEnvSetter() { + this.details = new ArrayList<>(); + this.props = new ArrayList<>(); + } + + public void setEnvValues() { + + loadEnv("env.json"); + + for (int i = 0; i < endpoints.length(); i++) { + System.out.println("Processing endpoint " + i); + JSONObject point = endpoints.getJSONObject(i); + MQDetails details = new MQDetails(); + this.details.add(details.buildMQDetails(point)); + this.props.add(getEnvValues(details)); + } + + System.out.println("Sample MQ GET application ending"); + + } + + private void loadEnv(String path) { + try { + String content = new String(Files.readAllBytes(Paths.get(path))); + JSONObject env = new JSONObject(content); + this.endpoints = env.getJSONArray("MQ_ENDPOINTS"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private Hashtable getEnvValues(MQDetails details) { + + System.out.println(details); + + Hashtable props = new Hashtable<>(); + String ccdtUrl = System.getenv("MQCCDTURL"); + + if (ccdtUrl != null && ccdtUrl.startsWith("file://")) { + String ccdtPath = ccdtUrl.replace("file://", ""); + System.setProperty("MQCCDTURL", ccdtPath); + System.out.println("Using CCDT at: " + ccdtPath); + } else { + props.put(MQConstants.HOST_NAME_PROPERTY, details.getHOST()); + props.put(MQConstants.PORT_PROPERTY, Integer.parseInt(details.getPORT())); + props.put(MQConstants.CHANNEL_PROPERTY, details.getCHANNEL()); + } + + props.put(MQConstants.USER_ID_PROPERTY, details.getUSER()); + props.put(MQConstants.PASSWORD_PROPERTY, details.getPASSWORD()); + props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); + + if (!details.getKEY_REPOSITORY().isEmpty()) { + props.put(MQConstants.SSL_CIPHER_SUITE_PROPERTY, details.getCIPHER()); + System.setProperty("com.ibm.mq.ssl.keyStore", details.getKEY_REPOSITORY()); + System.setProperty("com.ibm.mq.ssl.keyStorePassword", ""); + } + return props; + } + + public List getDetails() { + return details; + } + + public List> getProps() { + return props; + } + + @Override + public String toString() { + return "SampleEnvSetter [details=" + details.size() + ", props=" + props.size() + "]"; + } + +} From c3938d90e49a074bbf93697a056ce9f44548a848 Mon Sep 17 00:00:00 2001 From: Stuti Uniyal Date: Thu, 10 Jul 2025 01:27:02 +0530 Subject: [PATCH 4/8] Deleted outdated samples --- README.md | 293 ------------------ base-java/Readme.md | 142 --------- base-java/pom.xml | 55 ---- .../com/ibm/mq/samples/java/BasicGet.java | 133 -------- .../com/ibm/mq/samples/java/BasicPub.java | 128 -------- .../com/ibm/mq/samples/java/BasicPut.java | 122 -------- .../com/ibm/mq/samples/java/BasicRequest.java | 123 -------- .../ibm/mq/samples/java/BasicResponse.java | 121 -------- .../com/ibm/mq/samples/java/BasicSub.java | 133 -------- env.json | 70 ++--- 10 files changed, 23 insertions(+), 1297 deletions(-) delete mode 100644 README.md delete mode 100644 base-java/Readme.md delete mode 100644 base-java/pom.xml delete mode 100644 base-java/src/main/java/com/ibm/mq/samples/java/BasicGet.java delete mode 100644 base-java/src/main/java/com/ibm/mq/samples/java/BasicPub.java delete mode 100644 base-java/src/main/java/com/ibm/mq/samples/java/BasicPut.java delete mode 100644 base-java/src/main/java/com/ibm/mq/samples/java/BasicRequest.java delete mode 100644 base-java/src/main/java/com/ibm/mq/samples/java/BasicResponse.java delete mode 100644 base-java/src/main/java/com/ibm/mq/samples/java/BasicSub.java diff --git a/README.md b/README.md deleted file mode 100644 index 65fd47ad..00000000 --- a/README.md +++ /dev/null @@ -1,293 +0,0 @@ -## Issue Support - -The code in this repository, is provided and maintained on a community basis, and is not covered by any IBM commercial -support agreement or warranty. - -For issues and fixes please just raise an issue against this repository. - -## IBM MQ samples and patterns - -When your application needs messaging, you don't want to spend countless hours learning the basics, you want to jump -straight in and play, see how things work. - -We have taken parts that make up the current set of our IBM MQ samples and built applications that you can use to do -just that. - -You'll find `put/get`, `pub/sub`, `request/response` samples that you can run in the same language or you can try mixing -things up and do a `put` in Java, `get` with Go etc. - -There is a [README for each language](#readme-docs) that helps you with the initial setup. - -You need an MQ server with a queue or topic to run these samples against. To find out more about what MQ is and how it -works, start from [LearnMQ](http://ibm.biz/mq-badge). - -To get your MQ server set up, check out [Ready, Set, Connect](https://developer.ibm.com/series/mq-ready-set-connect/). - -You can use your own MQ server, you'll just have to adjust the MQ objects accordingly so they match on both the server -and the client side. The samples in this repository inspect the following environment variables for their Queue Manager -and messaging configuration. These values can also be provided via a `env.json` file. - -* **HOST** - Host name or IP address of your queue manager -* **PORT** - Listener port for your queue manager -* **CHANNEL** - MQ channel name -* **QMGR** - Queue manager name -* **APP_USER** - User name that application uses to connect to MQ -* **APP_PASSWORD** - Password that the application uses to connect to MQ -* **QUEUE_NAME** - Queue name for `put/get`, `request/response` -* **TOPIC_NAME** - Topic for `publish/subscribe` -* **MODEL_QUEUE_NAME** - Model Queue used as template to base dynamic queues on for `request/response` -* **DYNAMIC_QUEUE_PREFIX** - Prefix for dynamically created reply queue - you don't need to create this -* **CIPHER_SUITE** - If present in the `env,json`, TLS Cipher specification to use -* **KEY_REPOSITORY** - Path to the `keystore` `.kbd` and `.sth` files. If running on Apple Silicon then this will the path to the queue manager's exported `.pem`. If present in the `env.json`, TLS is enabled - this is on the app side. - -If instead you choose to provide a client channel definition table (CCDT) file, then the **Host**, **PORT**, **Channel** -and **Cipher** are provided by the CCDT and you can leave them out of the `env.json`. All the samples check if the -environment variable `MQCCDTURL` is set and that the file it is pointing at exists. If it does then the logic sets the -connection definition or connection factory to for CCDT processing. For example - -``` -export MQCCDTURL=file:///Users/xyz/Documents/dev/mqsamples/mq-dev-patterns/ccdt.json -``` - -We give you a sample `ccdt.json` from which you can base your own. - -If you use our MQ server for developers in Docker, Linux or Windows, with the default config, you'll have the following -MQ objects on the MQ server: - -~~~Text -Host - localhost -Port - 1414 - Non TLS -Channel - DEV.APP.SVRCONN -Queue manager - QM1 -App user - app (member of mqclient group) -App password - passw0rd (you can set your own when running the Docker container, MQ_APP_PASSWORD) -Queue - DEV.QUEUE.1 -Topic - dev/ -Cipher suite - TLS_RSA_WITH_AES_128_CBC_SHA256 -~~~ - - -### Model queue and MQ container image -The default configuration for MQ objects that you get with our Docker container does not include a model queue. - -We use a model queue in the `request/response` pattern as a template for the request application to create a temporary -reply queue. - -You can use the MQ Web Console to create the model queue. Access the MQ Web Console for your MQ running as a container -at [https://localhost:9443/ibmmq/console/](https://localhost:9443/ibmmq/console/). You can log in with the -[default admin details](https://github.com/ibm-messaging/mq-container/blob/4d4051312eb9d95a086e2ead76482d1f1616d149/docs/developer-config.md#web-console) -or your own, if you made changes. - -## Environment variables - -All the samples make use of the same environment variables to define MQ connection settings - these match the default -developer config objects on the MQ server. This separates configuration and credentials details from the code, and -conforms to standard configuration injection mechanisms used in Cloud and DevOps environments. - -With so many many environment variables needed, we've tried to make this easier by providing one `env.json` file in the -main `samples` directory, that all the samples use for default configuration setting. Default values specfied in the -`env.json` file are overridden by environment variables. - -### env.json format - -```JSON -{ - "MQ_ENDPOINTS": [{ - "HOST":"localhost", - "PORT":"1414", - "CHANNEL":"DEV.APP.SVRCONN", - "QMGR":"QM1", - "APP_USER":"app", - "APP_PASSWORD":"passw0rd", - "QUEUE_NAME":"DEV.QUEUE.1", - "MODEL_QUEUE_NAME":"DEV.APP.MODEL.QUEUE", - "TOPIC_NAME":"dev/", - "CIPHER_SUITE":"TLS_RSA_WITH_AES_128_CBC_SHA256", - "KEY_REPOSITORY": "./keys/clientkey" - }] -} -``` -### JWT - -Use the following environment variables for the JWT enabled samples. These applications use this endpoint to request and retrieve a token. [JWT README](jwt-jwks-docs/README.md) - -```JSON -"JWT_ISSUER" : { - "JWT_TOKEN_ENDPOINT":"https:///realms/master/protocol/openid-connect/token", - "JWT_TOKEN_USERNAME":"app", - "JWT_TOKEN_PWD":"passw0rd", - "JWT_TOKEN_CLIENTID":"admin-cli" -} -``` -The `"JWT_TOKEN_ENDPOINT"` points your sample to a keycloak server(token issuer), which could be running in a container. -The `"JWT_TOKEN_USERNAME"` and `"JWT_TOKEN_PWD"` come from your keycloak "app" user credentials, that you would have configured via the keycloak console. - -### IBM Z Xplore -If you are running these samples on IBM Z Xplore then you can use the `env-zbindings.json` file. Simply rename the -`env-zbindings.json` to `env.json` - -You can use the `env.json` file to 'switch on' or 'switch off' parts of the code. - -### Endpoints Array -Having the endpoints in the `env.json` defined as an array allows us to define multiple endpoints for the sample -applications to use. - -## TLS - -For example, removing the CIPHER_SUITE and KEY_REPOSITORY lines (don't forget to remove the comma from the last line in -the json) will mean the sample will connect without using TLS. - -If you have two docker containers, one with TLS and one without, changing the port number in the `env.json` allows you -to switch between them. - -### Apple Silicon - -The IBM MQ Client Toolkit on Apple Silicon (ARM64) made use of OpenSSL libraries for TLS before version 9.4.1. For the -MQI based samples in this repository, this means that `KEY_REPOSITORY` in the `env.json` file or environment variable -`KEY_REPOSITORY` be set to the path for the queue manager's exported `.pem` file. eg. If you have exported the -`qmgrcert.pem` file to the root directory of this repository, then set `KEY_REPOSITORY` to `../qmgrcert.pem`. - -From 9.4.1, the toolkit uses the same keystore formats (`p12` or `kdb`) as Linux. - -### Using port forwarding to run a multiple containers - -Let's say you're already running MQ in a Docker container without TLS having set it up by following the -[Ready, Set, Connect](https://developer.ibm.com/series/mq-ready-set-connect/) tutorial. - -Now you want to run the second Docker container to try the samples with TLS switched on. - -You can have the same MQ objects set up in both, and switch between them by using the host port forwarding to make the -non TLS queue manager available on port 1414 and the TLS one on port 1415. - -### Creating self signed certificates by using `openssl` - -Do this in a directory you'll easily remember as you'll have to copy the server certificates over into a temporary -folder each time you need to run MQ with TLS in a Docker container. - -You'll also have to point to the client keystore location from the `env.json` file so that if you want to run samples -with TLS, the sample knows where to look. - -1. Create a new directory. Navigate inside this and generate a self-signed server key and certificate - - `openssl req -newkey rsa:2048 -nodes -keyout key.key -x509 -days 365 -out key.crt` - - An RSA private key will be generated and you'll need to complete information that will go inside the self signed certificate. - - **IMPORTANT: this directory should initially be empty.** - -2. Verify that the certificate has been created successfully - - `openssl x509 -text -noout -in key.crt` - - When done, you'll see the certificate data output. - -3. Create a client keystore. - -- For **JMS and XMS** based clients, create a .jks client keystore and create and verify a keystore password: - - `keytool -keystore clientkey.jks -storetype jks -importcert -file key.crt -alias server-certificate` - -- For MQI based Clients (**Node, Python, Go**) - - Create a key database, a stash file. You will need to have installed the MQI client, so that you can run the - runmqakm tool: - - `runmqakm -keydb -create -db clientkey.kdb -pw tru5tpassw0rd -type pkcs12 -expire 1000 -stash` - -- Import the server's public key certificate into the client key database - - `runmqakm -cert -add -label QM1.cert -db clientkey.kdb -pw tru5tpassw0rd -trust enable -file key.crt` - -4. Move the client keystore - -- Move the client keystore somewhere you will remember. Ensure the only files in the current directory are the `key.key` - and `key.crt` files, as IBM MQ will use the contents of this directory to configure security inside the container. - -5. Run the new docker container - -- Give it a name, for example `mqtls` so you can differentiate it from your other MQ container when you `docker ps`, - and point it at the location where you copied the server certificate. - -``` - docker run --name mqtls --env LICENSE=accept \ - --env MQ_QMGR_NAME=QM1 \ - --env MQ_APP_PASSWORD=passw0rd \ - --volume ___PATH TO SERVER_KEY/CERTIFICATE DIRECTORY___:/etc/mqm/pki/keys/mykey \ - --publish 1415:1414 \ - --publish 9444:9443 \ - --detach \ - icr.io/ibm-messaging/mq:latest -``` - -- Remember to use a secure password for `MQ_APP_PASSWORD`. - -You should be able to open the MQ Web console for this TLS container on https://localhost:9444/ibmmq/console. - -If you choose to stop the container, check the ID or name of the TLS container that was running previously with: - -`docker ps -a` - -then run - -`docker start ` - -to start the container again. - -## MQI Paths -The MQI samples; `Node.js`, `Python`, `Go`, require the MQI Client Toolkit to have been installed and the paths -`MQ_INSTALLATION_PATH` and `DYLD_LIBRARY_PATH` (MacOS) or `LD_LIBRARY_PATH` (Windows or Linux) set. - -If you have installed the MQI client manually, ensure that `MQ_INSTALLATION_PATH` is set to the root directory of your -MQI Client installation and `DYLD_LIBRARY_PATH` or `LD_LIBRARY_PATH` is set to `$MQ_INSTALLATION_PATH/lib64`. - -Do not install any application requirements until `MQ_INSTALLATION_PATH` and `DYLD_LIBRARY_PATH` or `LD_LIBRARY_PATH` -are set and exported (see language README docs for more info). - -## README docs - -### Language based MQI / JMS / XMS samples -#### [Node.js](/Node.js/README.md) -#### [JMS](/JMS/README.md) -#### [Python](/Python/README.md) -#### [C# .Net](/dotnet/README.md) -#### [Go](/Go/README.md) -#### [C](/C/README.md) - -### REST samples -#### [Rust](/Rust-REST/README.md) -#### [Swift](/Swift-REST/README.md) -#### [react.js](/reactjs/README.md) - -### AMQP samples -#### [Go](/amqp/Go/README.md) -#### [C# .Net](/amqp/dotnet/README.md) -#### [QPID](/amqp-qpid/README.md) - -### Transaction samples -#### [JMS](/transactions/JMS/SE/README.md) -#### [Spring](/transactions/JMS/Spring/README.md) - -### Framework samples -#### [Spring](/Spring-JMS/README.md) -#### [Transactions on Spring](/transactions/JMS/Spring/README.md) -#### [Quarkus](/amqp-qpid/qpid-quarkus/README.md) - -### Reactive samples -#### [Vert.x](/reactive-amqp/amqp-vertx/README.md) - -### Serverless samples -#### [AWS Lambda](/serverless/aws-lambda-rest/README.md) -#### [Azure Functions](/serverless/azure-functions-rest-http-trigger/README.md) -#### [Code Engine](/serverless/codeengine/README.md) -#### [OpenWhisk Cloud Functions](/serverless/openwhisk/README.md) - -### Showcase app -#### [Showcase](/ibm-messaging-mq-cloud-showcase-app/README.md) - -### Kubernetes samples -#### [Scaling with Keda](Go-K8s/README.md) - -### MQ container deployment examples -#### [compose](/container/queuemanager/compose/README.md) -#### [compose](/container/queuemanager/terraform-aws/README.md) - diff --git a/base-java/Readme.md b/base-java/Readme.md deleted file mode 100644 index b889cb9d..00000000 --- a/base-java/Readme.md +++ /dev/null @@ -1,142 +0,0 @@ -# IBM MQ Base Java Samples - -This project provides a set of base Java samples for interacting with IBM MQ using the IBM MQ classes for Java (non-JMS). These include basic examples for put/get, publish/subscribe, and request/response messaging patterns. - -## Samples Included - -Each sample is located under: - -``` -src/main/java/com/ibm/mq/samples/java/ -``` - -- `BasicPut.java` – Puts a message onto a queue -- `BasicGet.java` – Gets a message from a queue -- `BasicPub.java` – Publishes a message to a topic -- `BasicSub.java` – Subscribes and receives messages from a topic -- `BasicRequest.java` – Sends a message with a dynamic reply-to queue -- `BasicResponse.java` – Responds to requests received from a queue - -## Prerequisites - -- Java 8 or higher -- Apache Maven -- IBM MQ installed and running (locally or remotely) - -## Project Setup - -This is a standard Maven project. All dependencies and build instructions are managed through `pom.xml`. - -### Building the Project - -To build the project and download dependencies: - -```bash -mvn clean package -``` -## Running the Samples - -Ensure that your environment configuration file (`env.json`) is properly set up. Example: - -```json -{ - "MQ_ENDPOINTS": [ - { - "QMGR": "QM1", - "HOST": "localhost", - "PORT": 1414, - "CHANNEL": "DEV.APP.SVRCONN", - "APP_USER": "app", - "APP_PASSWORD": "passw0rd", - "QUEUE_NAME": "DEV.QUEUE.1", - "BACKOUT_QUEUE": "DEV.QUEUE.2", - "MODEL_QUEUE_NAME": "DEV.APP.MODEL.QUEUE", - "DYNAMIC_QUEUE_PREFIX": "APP.REPLIES.*", - "TOPIC_NAME": "dev/" - } - ] -} -``` -## Using a CCDT File - -Instead of manually specifying connection parameters in `env.json`, you can use a **Client Channel Definition Table (CCDT)** JSON file to define connection configurations. This is useful when connecting to IBM MQ instances in cloud or enterprise environments. - -Set the environment variable `MQCCDTURL` to point to the CCDT file: - -```bash -export MQCCDTURL=file:/absolute/path/to/ccdt.json -``` - -> **Note (Windows):** Use `set` instead of `export`: -> -> ```cmd -> set MQCCDTURL=file:C:\path\to\ccdt.json -> ``` - -The sample will detect `MQCCDTURL` and automatically use it for connection settings. When `MQCCDTURL` is set and starts with `file://`, the program prioritizes CCDT-based configuration and skips `host`, `channel`, and `port` in `env.json`. - -Make sure your CCDT file defines the appropriate connection information such as **channel name**, **queue manager**, and **connection name list**. - - -## Run Instructions - -### Put/Get - -```bash -mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicPut" -Dexec.args="env.json" -mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicGet" -Dexec.args="env.json" -``` - -### Publish/Subscribe - -In the **first terminal (subscriber)**: - -```bash -mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicSub" -Dexec.args="env.json" -``` - -In the **second terminal (publisher)**: - -```bash -mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicPub" -Dexec.args="env.json" -``` - -### Request/Response - -In the **first terminal (response)**: - -```bash -mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicResponse" -Dexec.args="env.json" -``` - -In the **second terminal (request)**: - -```bash -mvn exec:java -Dexec.mainClass="com.ibm.mq.samples.java.BasicRequest" -Dexec.args="env.json" -``` -### Terminal 1: Run the Request Sample - -1. **Compile** the `BasicRequest.java` file using the required JAR dependencies. -2. **Run** the `BasicRequest` class. -3. The requester sends a message and waits for a response. -4. If `REPLY_QUEUE_NAME` is set, that queue is used for replies; otherwise, a temporary queue is created. -5. Optionally, set the `REQUEST_MESSAGE_EXPIRY` environment variable to define how long the request is valid. - ---- - -### Terminal 2: Run the Response Sample - -1. **Compile** the `BasicResponse.java` file with the same JAR dependencies. -2. **Run** the `BasicResponse` class. -3. The responder listens on a queue, processes incoming messages, and sends replies to the specified reply-to queue. -4. It continues running until manually stopped or it times out. -5. You can set the `RESPONDER_INACTIVITY_TIMEOUT` environment variable to control how long it waits for new messages before exiting. - ---- -## Notes - -- The environment can be configured using either `env.json` or a CCDT file via the `MQCCDTURL` environment variable. -- Each sample reads from the provided `env.json` to extract connection information for the queue manager. -- Samples like `BasicResponse` and `BasicSub` are long-running and wait for messages indefinitely until stopped. -- Make sure all relevant queues and topics are pre-created in your IBM MQ queue manager. - diff --git a/base-java/pom.xml b/base-java/pom.xml deleted file mode 100644 index 7932c5d4..00000000 --- a/base-java/pom.xml +++ /dev/null @@ -1,55 +0,0 @@ - - 4.0.0 - - com.ibm.mq.samples - mq-java-base-consumer - 1.0.0 - jar - - - 1.8 - 1.8 - - - - - - com.ibm.mq - com.ibm.mq.allclient - 9.4.3.0 - - - - - org.json - json - 20240303 - - - - - - - maven-compiler-plugin - 3.8.1 - - 1.8 - - - - - - - - - - - - - - - - diff --git a/base-java/src/main/java/com/ibm/mq/samples/java/BasicGet.java b/base-java/src/main/java/com/ibm/mq/samples/java/BasicGet.java deleted file mode 100644 index e7a77783..00000000 --- a/base-java/src/main/java/com/ibm/mq/samples/java/BasicGet.java +++ /dev/null @@ -1,133 +0,0 @@ -package com.ibm.mq.samples.java; - -import com.ibm.mq.*; -import com.ibm.mq.constants.MQConstants; -import org.json.*; - -import java.io.FileReader; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Hashtable; - -public class BasicGet { - - private static class MQDetails { - String QMGR; - String QUEUE_NAME; - String HOST; - String PORT; - String CHANNEL; - String USER; - String PASSWORD; - String KEY_REPOSITORY; - String CIPHER; - } - - private static JSONArray endpoints; - - public static void main(String[] args) { - loadEnv("env.json"); - - for (int i = 0; i < endpoints.length(); i++) { - System.out.println("Processing endpoint " + i); - JSONObject point = endpoints.getJSONObject(i); - MQDetails details = buildMQDetails(point); - processEndpoint(details); - } - - System.out.println("Sample MQ GET application ending"); - } - - private static void loadEnv(String path) { - try { - String content = new String(Files.readAllBytes(Paths.get(path))); - JSONObject env = new JSONObject(content); - endpoints = env.getJSONArray("MQ_ENDPOINTS"); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static MQDetails buildMQDetails(JSONObject endpoint) { - MQDetails mq = new MQDetails(); - mq.QMGR = endpoint.getString("QMGR"); - mq.QUEUE_NAME = endpoint.getString("QUEUE_NAME"); - mq.HOST = endpoint.getString("HOST"); - mq.PORT = String.valueOf(endpoint.getInt("PORT")); - mq.CHANNEL = endpoint.getString("CHANNEL"); - mq.USER = endpoint.getString("APP_USER"); - mq.PASSWORD = endpoint.getString("APP_PASSWORD"); - mq.KEY_REPOSITORY = endpoint.optString("KEY_REPOSITORY", ""); - mq.CIPHER = endpoint.optString("CIPHER", ""); - return mq; - } - - private static void processEndpoint(MQDetails details) { - MQQueueManager qMgr = null; - MQQueue queue = null; - - try { - Hashtable props = new Hashtable<>(); - String ccdtUrl = System.getenv("MQCCDTURL"); - - if (ccdtUrl != null && ccdtUrl.startsWith("file://")) { - String ccdtPath = ccdtUrl.replace("file://", ""); - System.setProperty("MQCCDTURL", ccdtPath); - System.out.println("Using CCDT at: " + ccdtPath); - } else { - props.put(MQConstants.HOST_NAME_PROPERTY, details.HOST); - props.put(MQConstants.PORT_PROPERTY, Integer.parseInt(details.PORT)); - props.put(MQConstants.CHANNEL_PROPERTY, details.CHANNEL); - } - - props.put(MQConstants.USER_ID_PROPERTY, details.USER); - props.put(MQConstants.PASSWORD_PROPERTY, details.PASSWORD); - props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); - - if (!details.KEY_REPOSITORY.isEmpty()) { - props.put(MQConstants.SSL_CIPHER_SUITE_PROPERTY, details.CIPHER); - System.setProperty("com.ibm.mq.ssl.keyStore", details.KEY_REPOSITORY); - System.setProperty("com.ibm.mq.ssl.keyStorePassword", ""); - } - - qMgr = new MQQueueManager(details.QMGR, props); - System.out.println("Connected to queue manager: " + details.QMGR); - - int openOptions = MQConstants.MQOO_INPUT_AS_Q_DEF; - queue = qMgr.accessQueue(details.QUEUE_NAME, openOptions); - - boolean keepReading = true; - while (keepReading) { - MQMessage msg = new MQMessage(); - MQGetMessageOptions gmo = new MQGetMessageOptions(); - gmo.options = MQConstants.MQGMO_NO_WAIT | - MQConstants.MQGMO_CONVERT | - MQConstants.MQGMO_FAIL_IF_QUIESCING; - - try { - queue.get(msg, gmo); - String str = msg.readStringOfByteLength(msg.getDataLength()); - System.out.println("Received message: " + str); - } catch (MQException mqe) { - if (mqe.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) { - keepReading = false; - System.out.println("No more messages."); - } else { - System.err.println("Error retrieving message: " + mqe); - keepReading = false; - } - } - } - - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (queue != null) queue.close(); - if (qMgr != null) qMgr.disconnect(); - } catch (MQException me) { - me.printStackTrace(); - } - } - } -} diff --git a/base-java/src/main/java/com/ibm/mq/samples/java/BasicPub.java b/base-java/src/main/java/com/ibm/mq/samples/java/BasicPub.java deleted file mode 100644 index d0748ba7..00000000 --- a/base-java/src/main/java/com/ibm/mq/samples/java/BasicPub.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.ibm.mq.samples.java; -import com.ibm.mq.*; -import com.ibm.mq.constants.MQConstants; -import org.json.*; - -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Hashtable; - -public class BasicPub { - - private static class MQDetails { - String QMGR; - String TOPIC_NAME; - String HOST; - String PORT; - String CHANNEL; - String USER; - String PASSWORD; - String KEY_REPOSITORY; - String CIPHER; - } - - private static MQDetails mqDetails; - - public static void main(String[] args) { - loadEnv("env.json"); - publishToTopic(mqDetails); - System.out.println("Sample MQ PUB application ending"); - } - - private static void loadEnv(String path) { - try { - String content = new String(Files.readAllBytes(Paths.get(path))); - JSONObject env = new JSONObject(content); - JSONObject endpoint = env.getJSONArray("MQ_ENDPOINTS").getJSONObject(0); - - mqDetails = new MQDetails(); - mqDetails.QMGR = endpoint.getString("QMGR"); - mqDetails.TOPIC_NAME = endpoint.getString("TOPIC_NAME"); - mqDetails.HOST = endpoint.getString("HOST"); - mqDetails.PORT = String.valueOf(endpoint.getInt("PORT")); - mqDetails.CHANNEL = endpoint.getString("CHANNEL"); - mqDetails.USER = endpoint.getString("APP_USER"); - mqDetails.PASSWORD = endpoint.getString("APP_PASSWORD"); - mqDetails.KEY_REPOSITORY = endpoint.optString("KEY_REPOSITORY", ""); - mqDetails.CIPHER = endpoint.optString("CIPHER", ""); - - - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static void publishToTopic(MQDetails d) { - MQQueueManager qMgr = null; - MQTopic topic = null; - - try { - Hashtable props = new Hashtable<>(); - - String ccdtUrl = System.getenv("MQCCDTURL"); - if (ccdtUrl != null && ccdtUrl.startsWith("file://")) { - String ccdtPath = ccdtUrl.replace("file://", ""); - System.setProperty("MQCCDTURL", ccdtPath); - System.out.println("Using CCDT at: " + ccdtPath); - } else { - props.put(MQConstants.HOST_NAME_PROPERTY, d.HOST); - props.put(MQConstants.PORT_PROPERTY, Integer.parseInt(d.PORT)); - props.put(MQConstants.CHANNEL_PROPERTY, d.CHANNEL); - } - - props.put(MQConstants.USER_ID_PROPERTY, d.USER); - props.put(MQConstants.PASSWORD_PROPERTY, d.PASSWORD); - props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); - - if (!d.KEY_REPOSITORY.isEmpty()) { - props.put(MQConstants.SSL_CIPHER_SUITE_PROPERTY, d.CIPHER); - System.setProperty("com.ibm.mq.ssl.keyStore", d.KEY_REPOSITORY); - System.setProperty("com.ibm.mq.ssl.keyStorePassword", ""); - } - - qMgr = new MQQueueManager(d.QMGR, props); - System.out.println("Connected to queue manager: " + d.QMGR); - - // Access using topic object name, not just string - topic = qMgr.accessTopic( - d.TOPIC_NAME, - null, // Topic Object defined in MQ - MQConstants.MQTOPIC_OPEN_AS_PUBLICATION, - MQConstants.MQOO_OUTPUT - ); - - MQMessage msg = new MQMessage(); - msg.format = MQConstants.MQFMT_STRING; - - String payload = "{\"Greeting\": \"Hello from Java publisher at " + java.time.Instant.now() + "\"}"; - msg.writeString(payload); - - MQPutMessageOptions pmo = new MQPutMessageOptions(); - pmo.options = MQConstants.MQPMO_NO_SYNCPOINT | - MQConstants.MQPMO_NEW_MSG_ID | - MQConstants.MQPMO_NEW_CORREL_ID | - MQConstants.MQPMO_WARN_IF_NO_SUBS_MATCHED; - - topic.put(msg, pmo); - - //System.out.println("Published message to topic object: DEV.BASE.TOPIC"); - System.out.println("Message content: " + payload); - - } catch (MQException mqe) { - if (mqe.reasonCode == MQConstants.MQRC_NO_SUBS_MATCHED) { - System.out.println("Warning: No subscribers matched the topic."); - } else { - mqe.printStackTrace(); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (topic != null) topic.close(); - if (qMgr != null) qMgr.disconnect(); - } catch (MQException me) { - me.printStackTrace(); - } - } - } -} diff --git a/base-java/src/main/java/com/ibm/mq/samples/java/BasicPut.java b/base-java/src/main/java/com/ibm/mq/samples/java/BasicPut.java deleted file mode 100644 index c87bcb0a..00000000 --- a/base-java/src/main/java/com/ibm/mq/samples/java/BasicPut.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.ibm.mq.samples.java; -import com.ibm.mq.*; -import com.ibm.mq.constants.MQConstants; -import org.json.*; - -import java.io.FileReader; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Hashtable; - -public class BasicPut { - - private static class MQDetails { - String QMGR; - String QUEUE_NAME; - String HOST; - String PORT; - String CHANNEL; - String USER; - String PASSWORD; - String KEY_REPOSITORY; - String CIPHER; - } - - private static JSONArray endpoints; - - public static void main(String[] args) { - loadEnv("env.json"); - - for (int i = 0; i < endpoints.length(); i++) { - System.out.println("Processing endpoint " + i); - JSONObject point = endpoints.getJSONObject(i); - MQDetails details = buildMQDetails(point); - processEndpoint(details); - } - - System.out.println("Sample MQ PUT application ending"); - System.exit(0); - } - - private static void loadEnv(String path) { - try { - String content = new String(Files.readAllBytes(Paths.get(path))); - JSONObject env = new JSONObject(content); - endpoints = env.getJSONArray("MQ_ENDPOINTS"); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static MQDetails buildMQDetails(JSONObject endpoint) { - MQDetails mq = new MQDetails(); - mq.QMGR = endpoint.getString("QMGR"); - mq.QUEUE_NAME = endpoint.getString("QUEUE_NAME"); - mq.HOST = endpoint.getString("HOST"); - mq.PORT = String.valueOf(endpoint.getInt("PORT")); - mq.CHANNEL = endpoint.getString("CHANNEL"); - mq.USER = endpoint.getString("APP_USER"); - mq.PASSWORD = endpoint.getString("APP_PASSWORD"); - mq.KEY_REPOSITORY = endpoint.optString("KEY_REPOSITORY", ""); - mq.CIPHER = endpoint.optString("CIPHER", ""); - return mq; - } - - private static void processEndpoint(MQDetails details) { - MQQueueManager qMgr = null; - MQQueue queue = null; - - try { - Hashtable props = new Hashtable<>(); - String ccdtUrl = System.getenv("MQCCDTURL"); - - if (ccdtUrl != null && ccdtUrl.startsWith("file://")) { - String ccdtPath = ccdtUrl.replace("file://", ""); - System.setProperty("MQCCDTURL", ccdtPath); - System.out.println("Using CCDT at: " + ccdtPath); - } else { - props.put(MQConstants.HOST_NAME_PROPERTY, details.HOST); - props.put(MQConstants.PORT_PROPERTY, Integer.parseInt(details.PORT)); - props.put(MQConstants.CHANNEL_PROPERTY, details.CHANNEL); - } - - props.put(MQConstants.USER_ID_PROPERTY, details.USER); - props.put(MQConstants.PASSWORD_PROPERTY, details.PASSWORD); - props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); - - if (!details.KEY_REPOSITORY.isEmpty()) { - props.put(MQConstants.SSL_CIPHER_SUITE_PROPERTY, details.CIPHER); - System.setProperty("com.ibm.mq.ssl.keyStore", details.KEY_REPOSITORY); - System.setProperty("com.ibm.mq.ssl.keyStorePassword", ""); - } - - qMgr = new MQQueueManager(details.QMGR, props); - System.out.println("Connected to queue manager: " + details.QMGR); - - int openOptions = MQConstants.MQOO_OUTPUT; - queue = qMgr.accessQueue(details.QUEUE_NAME, openOptions); - - MQMessage msg = new MQMessage(); - msg.format = MQConstants.MQFMT_STRING; - - // Hardcoded message body for simplicity - String payload = "{\"greeting\": \"Hello from BasicPut.java\"}"; - msg.writeString(payload); - - MQPutMessageOptions pmo = new MQPutMessageOptions(); - queue.put(msg, pmo); - - System.out.println("Message put successfully: " + payload); - - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (queue != null) queue.close(); - if (qMgr != null) qMgr.disconnect(); - } catch (MQException me) { - me.printStackTrace(); - } - } - } -} diff --git a/base-java/src/main/java/com/ibm/mq/samples/java/BasicRequest.java b/base-java/src/main/java/com/ibm/mq/samples/java/BasicRequest.java deleted file mode 100644 index 3b458cab..00000000 --- a/base-java/src/main/java/com/ibm/mq/samples/java/BasicRequest.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.ibm.mq.samples.java; -import com.ibm.mq.*; -import com.ibm.mq.constants.MQConstants; -import org.json.JSONObject; - -import java.nio.file.Files; -import java.nio.file.Paths; -import java.time.Instant; -import java.util.Hashtable; - -public class BasicRequest { - - static class MQDetails { - String QMGR; - String HOST; - int PORT; - String CHANNEL; - String APP_USER; - String APP_PASSWORD; - String QUEUE_NAME; - String MODEL_QUEUE_NAME; - String DYNAMIC_QUEUE_PREFIX; - } - - static MQDetails mqDetails; - - public static void main(String[] args) { - loadEnv("env.json"); - sendRequestAndReceiveReply(mqDetails); - System.out.println("Sample MQ requester application ending"); - } - - private static void loadEnv(String path) { - try { - String content = new String(Files.readAllBytes(Paths.get(path))); - JSONObject endpoint = new JSONObject(content) - .getJSONArray("MQ_ENDPOINTS").getJSONObject(0); - - mqDetails = new MQDetails(); - mqDetails.QMGR = endpoint.getString("QMGR"); - mqDetails.HOST = endpoint.getString("HOST"); - mqDetails.PORT = endpoint.getInt("PORT"); - mqDetails.CHANNEL = endpoint.getString("CHANNEL"); - mqDetails.APP_USER = endpoint.getString("APP_USER"); - mqDetails.APP_PASSWORD = endpoint.getString("APP_PASSWORD"); - mqDetails.QUEUE_NAME = endpoint.getString("QUEUE_NAME"); - mqDetails.MODEL_QUEUE_NAME = endpoint.getString("MODEL_QUEUE_NAME"); - mqDetails.DYNAMIC_QUEUE_PREFIX = endpoint.getString("DYNAMIC_QUEUE_PREFIX"); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static void sendRequestAndReceiveReply(MQDetails d) { - MQQueueManager qMgr = null; - MQQueue requestQueue = null; - MQQueue replyQueue = null; - - try { - Hashtable props = new Hashtable<>(); - props.put(MQConstants.HOST_NAME_PROPERTY, d.HOST); - props.put(MQConstants.PORT_PROPERTY, d.PORT); - props.put(MQConstants.CHANNEL_PROPERTY, d.CHANNEL); - props.put(MQConstants.USER_ID_PROPERTY, d.APP_USER); - props.put(MQConstants.PASSWORD_PROPERTY, d.APP_PASSWORD); - props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); - - qMgr = new MQQueueManager(d.QMGR, props); - System.out.println("Connected to queue manager: " + d.QMGR); - - replyQueue = qMgr.accessQueue( - d.MODEL_QUEUE_NAME, - MQConstants.MQOO_INPUT_EXCLUSIVE, - null, - d.DYNAMIC_QUEUE_PREFIX, - null - ); - String dynamicReplyQueueName = replyQueue.getName(); - System.out.println("Opened dynamic reply-to queue: " + dynamicReplyQueueName); - - requestQueue = qMgr.accessQueue(d.QUEUE_NAME, MQConstants.MQOO_OUTPUT); - - MQMessage request = new MQMessage(); - request.format = MQConstants.MQFMT_STRING; - request.replyToQueueName = dynamicReplyQueueName; - request.messageType = MQConstants.MQMT_REQUEST; - - String payload = "{\"Greeting\": \"Hello from Java Requester at " + Instant.now() + "\"}"; - request.writeString(payload); - - MQPutMessageOptions pmo = new MQPutMessageOptions(); - pmo.options = MQConstants.MQPMO_NO_SYNCPOINT; - - requestQueue.put(request, pmo); - System.out.println("Sent request message to queue: " + d.QUEUE_NAME); - System.out.println("Waiting for reply on: " + dynamicReplyQueueName); - - MQMessage response = new MQMessage(); - MQGetMessageOptions gmo = new MQGetMessageOptions(); - gmo.options = MQConstants.MQGMO_WAIT | MQConstants.MQGMO_CONVERT; - gmo.waitInterval = 10000; - - replyQueue.get(response, gmo); - String replyText = response.readStringOfByteLength(response.getDataLength()); - System.out.println("Received reply: " + replyText); - - } catch (MQException mqe) { - System.err.println("MQ Error - Completion Code: " + mqe.completionCode + - " Reason Code: " + mqe.reasonCode); - mqe.printStackTrace(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (requestQueue != null) requestQueue.close(); - if (replyQueue != null) replyQueue.close(); - if (qMgr != null) qMgr.disconnect(); - } catch (MQException e) { - e.printStackTrace(); - } - } - } -} diff --git a/base-java/src/main/java/com/ibm/mq/samples/java/BasicResponse.java b/base-java/src/main/java/com/ibm/mq/samples/java/BasicResponse.java deleted file mode 100644 index 81234635..00000000 --- a/base-java/src/main/java/com/ibm/mq/samples/java/BasicResponse.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.ibm.mq.samples.java; -import com.ibm.mq.*; -import com.ibm.mq.constants.MQConstants; -import org.json.JSONObject; - -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Hashtable; - -public class BasicResponse { - - static class MQDetails { - String QMGR; - String HOST; - int PORT; - String CHANNEL; - String APP_USER; - String APP_PASSWORD; - String QUEUE_NAME; - } - - static MQDetails mqDetails; - - public static void main(String[] args) { - loadEnv("env.json"); - listenAndRespond(mqDetails); - System.out.println("Sample MQ responder application ending"); - } - - private static void loadEnv(String path) { - try { - String content = new String(Files.readAllBytes(Paths.get(path))); - JSONObject endpoint = new JSONObject(content) - .getJSONArray("MQ_ENDPOINTS").getJSONObject(0); - - mqDetails = new MQDetails(); - mqDetails.QMGR = endpoint.getString("QMGR"); - mqDetails.HOST = endpoint.getString("HOST"); - mqDetails.PORT = endpoint.getInt("PORT"); - mqDetails.CHANNEL = endpoint.getString("CHANNEL"); - mqDetails.APP_USER = endpoint.getString("APP_USER"); - mqDetails.APP_PASSWORD = endpoint.getString("APP_PASSWORD"); - mqDetails.QUEUE_NAME = endpoint.getString("QUEUE_NAME"); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static void listenAndRespond(MQDetails d) { - MQQueueManager qMgr = null; - MQQueue requestQueue = null; - - try { - Hashtable props = new Hashtable<>(); - props.put(MQConstants.HOST_NAME_PROPERTY, d.HOST); - props.put(MQConstants.PORT_PROPERTY, d.PORT); - props.put(MQConstants.CHANNEL_PROPERTY, d.CHANNEL); - props.put(MQConstants.USER_ID_PROPERTY, d.APP_USER); - props.put(MQConstants.PASSWORD_PROPERTY, d.APP_PASSWORD); - props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); - - qMgr = new MQQueueManager(d.QMGR, props); - System.out.println("Connected to queue manager: " + d.QMGR); - - requestQueue = qMgr.accessQueue( - d.QUEUE_NAME, - MQConstants.MQOO_INPUT_AS_Q_DEF | MQConstants.MQOO_OUTPUT - ); - - MQGetMessageOptions gmo = new MQGetMessageOptions(); - gmo.options = MQConstants.MQGMO_WAIT | MQConstants.MQGMO_CONVERT; - gmo.waitInterval = 10000; - - while (true) { - MQMessage request = new MQMessage(); - try { - requestQueue.get(request, gmo); - String msgText = request.readStringOfByteLength(request.getDataLength()); - System.out.println("Received request: " + msgText); - - String replyToQueueName = request.replyToQueueName; - if (replyToQueueName != null && !replyToQueueName.isEmpty()) { - MQQueue replyQueue = qMgr.accessQueue(replyToQueueName, MQConstants.MQOO_OUTPUT); - - MQMessage reply = new MQMessage(); - reply.format = MQConstants.MQFMT_STRING; - reply.correlationId = request.messageId; - - JSONObject replyJson = new JSONObject(); - replyJson.put("Response", "Hello from Java Responder!"); - reply.writeString(replyJson.toString()); - - MQPutMessageOptions pmo = new MQPutMessageOptions(); - pmo.options = MQConstants.MQPMO_NO_SYNCPOINT; - - replyQueue.put(reply, pmo); - System.out.println("Sent reply to: " + replyToQueueName); - replyQueue.close(); - } - } catch (MQException mqe) { - if (mqe.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) { - System.out.println("No message received. Exiting."); - break; - } else { - throw mqe; - } - } - } - - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (requestQueue != null) requestQueue.close(); - if (qMgr != null) qMgr.disconnect(); - } catch (MQException e) { - e.printStackTrace(); - } - } - } -} diff --git a/base-java/src/main/java/com/ibm/mq/samples/java/BasicSub.java b/base-java/src/main/java/com/ibm/mq/samples/java/BasicSub.java deleted file mode 100644 index b517a6b1..00000000 --- a/base-java/src/main/java/com/ibm/mq/samples/java/BasicSub.java +++ /dev/null @@ -1,133 +0,0 @@ -package com.ibm.mq.samples.java; -import com.ibm.mq.*; -import com.ibm.mq.constants.MQConstants; -import org.json.*; - -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Hashtable; - -public class BasicSub { - - private static class MQDetails { - String QMGR; - String SUB_NAME; - String QUEUE_NAME; - String HOST; - String PORT; - String CHANNEL; - String USER; - String PASSWORD; - String KEY_REPOSITORY; - String CIPHER; - } - - private static MQDetails mqDetails; - - public static void main(String[] args) { - loadEnv("env.json"); - subscribeToQueue(mqDetails); - System.out.println("Sample MQ durable SUB application ending"); - } - - private static void loadEnv(String path) { - try { - String content = new String(Files.readAllBytes(Paths.get(path))); - JSONObject env = new JSONObject(content); - JSONObject endpoint = env.getJSONArray("MQ_ENDPOINTS").getJSONObject(0); - - mqDetails = new MQDetails(); - mqDetails.QMGR = endpoint.getString("QMGR"); - mqDetails.SUB_NAME = endpoint.getString("SUB_NAME"); - mqDetails.QUEUE_NAME = endpoint.getString("QUEUE_NAME"); // ✅ Fix - mqDetails.HOST = endpoint.getString("HOST"); - mqDetails.PORT = String.valueOf(endpoint.getInt("PORT")); - mqDetails.CHANNEL = endpoint.getString("CHANNEL"); - mqDetails.USER = endpoint.getString("APP_USER"); - mqDetails.PASSWORD = endpoint.getString("APP_PASSWORD"); - mqDetails.KEY_REPOSITORY = endpoint.optString("KEY_REPOSITORY", ""); - mqDetails.CIPHER = endpoint.optString("CIPHER", ""); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static void subscribeToQueue(MQDetails d) { - MQQueueManager qMgr = null; - MQQueue queue = null; - - try { - Hashtable props = new Hashtable<>(); - - String ccdtUrl = System.getenv("MQCCDTURL"); - if (ccdtUrl != null && ccdtUrl.startsWith("file://")) { - String ccdtPath = ccdtUrl.replace("file://", ""); - System.setProperty("MQCCDTURL", ccdtPath); - System.out.println("Using CCDT at: " + ccdtPath); - } else { - props.put(MQConstants.HOST_NAME_PROPERTY, d.HOST); - props.put(MQConstants.PORT_PROPERTY, Integer.parseInt(d.PORT)); - props.put(MQConstants.CHANNEL_PROPERTY, d.CHANNEL); - } - - props.put(MQConstants.USER_ID_PROPERTY, d.USER); - props.put(MQConstants.PASSWORD_PROPERTY, d.PASSWORD); - props.put(MQConstants.TRANSPORT_PROPERTY, MQConstants.TRANSPORT_MQSERIES_CLIENT); - - if (!d.KEY_REPOSITORY.isEmpty()) { - props.put(MQConstants.SSL_CIPHER_SUITE_PROPERTY, d.CIPHER); - System.setProperty("com.ibm.mq.ssl.keyStore", d.KEY_REPOSITORY); - System.setProperty("com.ibm.mq.ssl.keyStorePassword", ""); - } - - qMgr = new MQQueueManager(d.QMGR, props); - System.out.println("Connected to queue manager: " + d.QMGR); - - int openOptions = MQConstants.MQOO_INPUT_AS_Q_DEF | MQConstants.MQOO_FAIL_IF_QUIESCING; - queue = qMgr.accessQueue(d.QUEUE_NAME, openOptions); - - receiveMessages(queue); - - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (queue != null) queue.close(); - if (qMgr != null) qMgr.disconnect(); - } catch (MQException e) { - e.printStackTrace(); - } - } - } - - private static void receiveMessages(MQQueue queue) { - try { - MQMessage msg = new MQMessage(); - MQGetMessageOptions gmo = new MQGetMessageOptions(); - gmo.options = MQConstants.MQGMO_NO_SYNCPOINT | - MQConstants.MQGMO_WAIT | - MQConstants.MQGMO_CONVERT | - MQConstants.MQGMO_FAIL_IF_QUIESCING; - gmo.waitInterval = 10000; - - System.out.println("Waiting for messages from durable subscription queue..."); - while (true) { - msg.clearMessage(); - try { - queue.get(msg, gmo); - String received = msg.readStringOfByteLength(msg.getDataLength()); - System.out.println("Received: " + received); - } catch (MQException mqe) { - if (mqe.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) { - System.out.println("No messages. Exiting."); - break; - } else { - throw mqe; - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/env.json b/env.json index a58cb19c..d0fc11ff 100644 --- a/env.json +++ b/env.json @@ -1,48 +1,24 @@ { - "MQ_ENDPOINTS": [{ - "HOST": "127.0.0.1", - "PORT": "1415", - "CHANNEL": "DEV.APP.SVRCONN", - "QMGR": "*QM1TLS", - "APP_USER": "app", - "APP_PASSWORD": "passw0rd", - "QUEUE_NAME": "DEV.QUEUE.1", - "BACKOUT_QUEUE": "DEV.QUEUE.2", - "MODEL_QUEUE_NAME": "DEV.APP.MODEL.QUEUE", - "DYNAMIC_QUEUE_PREFIX": "APP.REPLIES.*", - "TOPIC_NAME": "dev/", - "CIPHER": "TLS_RSA_WITH_AES_128_CBC_SHA256", - "CIPHER_SUITE": "TLS_RSA_WITH_AES_128_CBC_SHA256", - "KEY_REPOSITORY": "../keys/clientkey" - },{ - "HOST": "127.0.0.1", - "PORT": "1414", - "CHANNEL": "DEV.APP.SVRCONN", - "QMGR": "*QMGroupA", - "APP_USER": "app", - "APP_PASSWORD": "passw0rd", - "QUEUE_NAME": "DEV.QUEUE.1", - "BACKOUT_QUEUE": "DEV.QUEUE.2", - "MODEL_QUEUE_NAME": "DEV.APP.MODEL.QUEUE", - "DYNAMIC_QUEUE_PREFIX": "APP.REPLIES.*", - "TOPIC_NAME": "dev/" - },{ - "HOST": "127.0.0.1", - "PORT": "1416", - "CHANNEL": "DEV.APP.SVRCONN", - "QMGR": "*QMGroupB", - "APP_USER": "app", - "APP_PASSWORD": "passw0rd", - "QUEUE_NAME": "DEV.QUEUE.1", - "BACKOUT_QUEUE": "DEV.QUEUE.2", - "MODEL_QUEUE_NAME": "DEV.APP.MODEL.QUEUE", - "DYNAMIC_QUEUE_PREFIX": "APP.REPLIES.*", - "TOPIC_NAME": "dev/" - }], - "JWT_ISSUER" : { - "JWT_TOKEN_ENDPOINT":"https:///realms/master/protocol/openid-connect/token", - "JWT_TOKEN_USERNAME":"app", - "JWT_TOKEN_PWD":"passw0rd", - "JWT_TOKEN_CLIENTID":"admin-cli" - } -} \ No newline at end of file + "MQ_ENDPOINTS": [ + { + "QMGR": "QM1", + "HOST": "localhost", + "PORT": 1414, + "CHANNEL": "DEV.APP.SVRCONN", + "APP_USER": "app", + "APP_PASSWORD": "passw0rd", + "QUEUE_NAME": "DEV.QUEUE.1", + "BACKOUT_QUEUE": "DEV.QUEUE.2", + "MODEL_QUEUE_NAME": "DEV.APP.MODEL.QUEUE", + "DYNAMIC_QUEUE_PREFIX": "APP.REPLIES.*", + "TOPIC_NAME": "dev/", + "SUB_NAME": "MY.SUB" + } + ] +} + + + + + + From 66d12e1416e81d0332ddef78ee174e59862ce6db Mon Sep 17 00:00:00 2001 From: Stuti Uniyal Date: Thu, 10 Jul 2025 01:31:06 +0530 Subject: [PATCH 5/8] Deleted outdated samples --- env.json | 71 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/env.json b/env.json index d0fc11ff..33e3053f 100644 --- a/env.json +++ b/env.json @@ -1,24 +1,49 @@ -{ - "MQ_ENDPOINTS": [ - { - "QMGR": "QM1", - "HOST": "localhost", - "PORT": 1414, - "CHANNEL": "DEV.APP.SVRCONN", - "APP_USER": "app", - "APP_PASSWORD": "passw0rd", - "QUEUE_NAME": "DEV.QUEUE.1", - "BACKOUT_QUEUE": "DEV.QUEUE.2", - "MODEL_QUEUE_NAME": "DEV.APP.MODEL.QUEUE", - "DYNAMIC_QUEUE_PREFIX": "APP.REPLIES.*", - "TOPIC_NAME": "dev/", - "SUB_NAME": "MY.SUB" - } - ] -} - - - - - +{ + "MQ_ENDPOINTS": [{ + "HOST": "127.0.0.1", + "PORT": "1415", + "CHANNEL": "DEV.APP.SVRCONN", + "QMGR": "*QM1TLS", + "APP_USER": "app", + "APP_PASSWORD": "passw0rd", + "QUEUE_NAME": "DEV.QUEUE.1", + "BACKOUT_QUEUE": "DEV.QUEUE.2", + "MODEL_QUEUE_NAME": "DEV.APP.MODEL.QUEUE", + "DYNAMIC_QUEUE_PREFIX": "APP.REPLIES.*", + "TOPIC_NAME": "dev/", + "CIPHER": "TLS_RSA_WITH_AES_128_CBC_SHA256", + "CIPHER_SUITE": "TLS_RSA_WITH_AES_128_CBC_SHA256", + "KEY_REPOSITORY": "../keys/clientkey" + },{ + "HOST": "127.0.0.1", + "PORT": "1414", + "CHANNEL": "DEV.APP.SVRCONN", + "QMGR": "*QMGroupA", + "APP_USER": "app", + "APP_PASSWORD": "passw0rd", + "QUEUE_NAME": "DEV.QUEUE.1", + "BACKOUT_QUEUE": "DEV.QUEUE.2", + "MODEL_QUEUE_NAME": "DEV.APP.MODEL.QUEUE", + "DYNAMIC_QUEUE_PREFIX": "APP.REPLIES.*", + "TOPIC_NAME": "dev/" + },{ + "HOST": "127.0.0.1", + "PORT": "1416", + "CHANNEL": "DEV.APP.SVRCONN", + "QMGR": "*QMGroupB", + "APP_USER": "app", + "APP_PASSWORD": "passw0rd", + "QUEUE_NAME": "DEV.QUEUE.1", + "BACKOUT_QUEUE": "DEV.QUEUE.2", + "MODEL_QUEUE_NAME": "DEV.APP.MODEL.QUEUE", + "DYNAMIC_QUEUE_PREFIX": "APP.REPLIES.*", + "TOPIC_NAME": "dev/" + }], + "JWT_ISSUER" : { + "JWT_TOKEN_ENDPOINT":"https:///realms/master/protocol/openid-connect/token", + "JWT_TOKEN_USERNAME":"app", + "JWT_TOKEN_PWD":"passw0rd", + "JWT_TOKEN_CLIENTID":"admin-cli" + } +} \ No newline at end of file From 0125416d093fa30a4c4f05a97e197e5d7a73434b Mon Sep 17 00:00:00 2001 From: Stuti Uniyal Date: Thu, 10 Jul 2025 01:34:23 +0530 Subject: [PATCH 6/8] updated env config for base java mq samples --- env.json | 1 - 1 file changed, 1 deletion(-) diff --git a/env.json b/env.json index 33e3053f..a58cb19c 100644 --- a/env.json +++ b/env.json @@ -1,4 +1,3 @@ - { "MQ_ENDPOINTS": [{ "HOST": "127.0.0.1", From 608037780ecb51b9aa4e77ad7f18a7b027178011 Mon Sep 17 00:00:00 2001 From: Stuti Uniyal Date: Thu, 10 Jul 2025 01:48:06 +0530 Subject: [PATCH 7/8] added Java-MQ sample link to README --- README.md | 293 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..b7e21f03 --- /dev/null +++ b/README.md @@ -0,0 +1,293 @@ +## Issue Support + +The code in this repository, is provided and maintained on a community basis, and is not covered by any IBM commercial +support agreement or warranty. + +For issues and fixes please just raise an issue against this repository. + +## IBM MQ samples and patterns + +When your application needs messaging, you don't want to spend countless hours learning the basics, you want to jump +straight in and play, see how things work. + +We have taken parts that make up the current set of our IBM MQ samples and built applications that you can use to do +just that. + +You'll find `put/get`, `pub/sub`, `request/response` samples that you can run in the same language or you can try mixing +things up and do a `put` in Java, `get` with Go etc. + +There is a [README for each language](#readme-docs) that helps you with the initial setup. + +You need an MQ server with a queue or topic to run these samples against. To find out more about what MQ is and how it +works, start from [LearnMQ](http://ibm.biz/mq-badge). + +To get your MQ server set up, check out [Ready, Set, Connect](https://developer.ibm.com/series/mq-ready-set-connect/). + +You can use your own MQ server, you'll just have to adjust the MQ objects accordingly so they match on both the server +and the client side. The samples in this repository inspect the following environment variables for their Queue Manager +and messaging configuration. These values can also be provided via a `env.json` file. + +* **HOST** - Host name or IP address of your queue manager +* **PORT** - Listener port for your queue manager +* **CHANNEL** - MQ channel name +* **QMGR** - Queue manager name +* **APP_USER** - User name that application uses to connect to MQ +* **APP_PASSWORD** - Password that the application uses to connect to MQ +* **QUEUE_NAME** - Queue name for `put/get`, `request/response` +* **TOPIC_NAME** - Topic for `publish/subscribe` +* **MODEL_QUEUE_NAME** - Model Queue used as template to base dynamic queues on for `request/response` +* **DYNAMIC_QUEUE_PREFIX** - Prefix for dynamically created reply queue - you don't need to create this +* **CIPHER_SUITE** - If present in the `env,json`, TLS Cipher specification to use +* **KEY_REPOSITORY** - Path to the `keystore` `.kbd` and `.sth` files. If running on Apple Silicon then this will the path to the queue manager's exported `.pem`. If present in the `env.json`, TLS is enabled - this is on the app side. + +If instead you choose to provide a client channel definition table (CCDT) file, then the **Host**, **PORT**, **Channel** +and **Cipher** are provided by the CCDT and you can leave them out of the `env.json`. All the samples check if the +environment variable `MQCCDTURL` is set and that the file it is pointing at exists. If it does then the logic sets the +connection definition or connection factory to for CCDT processing. For example + +``` +export MQCCDTURL=file:///Users/xyz/Documents/dev/mqsamples/mq-dev-patterns/ccdt.json +``` + +We give you a sample `ccdt.json` from which you can base your own. + +If you use our MQ server for developers in Docker, Linux or Windows, with the default config, you'll have the following +MQ objects on the MQ server: + +~~~Text +Host - localhost +Port - 1414 - Non TLS +Channel - DEV.APP.SVRCONN +Queue manager - QM1 +App user - app (member of mqclient group) +App password - passw0rd (you can set your own when running the Docker container, MQ_APP_PASSWORD) +Queue - DEV.QUEUE.1 +Topic - dev/ +Cipher suite - TLS_RSA_WITH_AES_128_CBC_SHA256 +~~~ + + +### Model queue and MQ container image +The default configuration for MQ objects that you get with our Docker container does not include a model queue. + +We use a model queue in the `request/response` pattern as a template for the request application to create a temporary +reply queue. + +You can use the MQ Web Console to create the model queue. Access the MQ Web Console for your MQ running as a container +at [https://localhost:9443/ibmmq/console/](https://localhost:9443/ibmmq/console/). You can log in with the +[default admin details](https://github.com/ibm-messaging/mq-container/blob/4d4051312eb9d95a086e2ead76482d1f1616d149/docs/developer-config.md#web-console) +or your own, if you made changes. + +## Environment variables + +All the samples make use of the same environment variables to define MQ connection settings - these match the default +developer config objects on the MQ server. This separates configuration and credentials details from the code, and +conforms to standard configuration injection mechanisms used in Cloud and DevOps environments. + +With so many many environment variables needed, we've tried to make this easier by providing one `env.json` file in the +main `samples` directory, that all the samples use for default configuration setting. Default values specfied in the +`env.json` file are overridden by environment variables. + +### env.json format + +```JSON +{ + "MQ_ENDPOINTS": [{ + "HOST":"localhost", + "PORT":"1414", + "CHANNEL":"DEV.APP.SVRCONN", + "QMGR":"QM1", + "APP_USER":"app", + "APP_PASSWORD":"passw0rd", + "QUEUE_NAME":"DEV.QUEUE.1", + "MODEL_QUEUE_NAME":"DEV.APP.MODEL.QUEUE", + "TOPIC_NAME":"dev/", + "CIPHER_SUITE":"TLS_RSA_WITH_AES_128_CBC_SHA256", + "KEY_REPOSITORY": "./keys/clientkey" + }] +} +``` +### JWT + +Use the following environment variables for the JWT enabled samples. These applications use this endpoint to request and retrieve a token. [JWT README](jwt-jwks-docs/README.md) + +```JSON +"JWT_ISSUER" : { + "JWT_TOKEN_ENDPOINT":"https:///realms/master/protocol/openid-connect/token", + "JWT_TOKEN_USERNAME":"app", + "JWT_TOKEN_PWD":"passw0rd", + "JWT_TOKEN_CLIENTID":"admin-cli" +} +``` +The `"JWT_TOKEN_ENDPOINT"` points your sample to a keycloak server(token issuer), which could be running in a container. +The `"JWT_TOKEN_USERNAME"` and `"JWT_TOKEN_PWD"` come from your keycloak "app" user credentials, that you would have configured via the keycloak console. + +### IBM Z Xplore +If you are running these samples on IBM Z Xplore then you can use the `env-zbindings.json` file. Simply rename the +`env-zbindings.json` to `env.json` + +You can use the `env.json` file to 'switch on' or 'switch off' parts of the code. + +### Endpoints Array +Having the endpoints in the `env.json` defined as an array allows us to define multiple endpoints for the sample +applications to use. + +## TLS + +For example, removing the CIPHER_SUITE and KEY_REPOSITORY lines (don't forget to remove the comma from the last line in +the json) will mean the sample will connect without using TLS. + +If you have two docker containers, one with TLS and one without, changing the port number in the `env.json` allows you +to switch between them. + +### Apple Silicon + +The IBM MQ Client Toolkit on Apple Silicon (ARM64) made use of OpenSSL libraries for TLS before version 9.4.1. For the +MQI based samples in this repository, this means that `KEY_REPOSITORY` in the `env.json` file or environment variable +`KEY_REPOSITORY` be set to the path for the queue manager's exported `.pem` file. eg. If you have exported the +`qmgrcert.pem` file to the root directory of this repository, then set `KEY_REPOSITORY` to `../qmgrcert.pem`. + +From 9.4.1, the toolkit uses the same keystore formats (`p12` or `kdb`) as Linux. + +### Using port forwarding to run a multiple containers + +Let's say you're already running MQ in a Docker container without TLS having set it up by following the +[Ready, Set, Connect](https://developer.ibm.com/series/mq-ready-set-connect/) tutorial. + +Now you want to run the second Docker container to try the samples with TLS switched on. + +You can have the same MQ objects set up in both, and switch between them by using the host port forwarding to make the +non TLS queue manager available on port 1414 and the TLS one on port 1415. + +### Creating self signed certificates by using `openssl` + +Do this in a directory you'll easily remember as you'll have to copy the server certificates over into a temporary +folder each time you need to run MQ with TLS in a Docker container. + +You'll also have to point to the client keystore location from the `env.json` file so that if you want to run samples +with TLS, the sample knows where to look. + +1. Create a new directory. Navigate inside this and generate a self-signed server key and certificate + + `openssl req -newkey rsa:2048 -nodes -keyout key.key -x509 -days 365 -out key.crt` + + An RSA private key will be generated and you'll need to complete information that will go inside the self signed certificate. + + **IMPORTANT: this directory should initially be empty.** + +2. Verify that the certificate has been created successfully + + `openssl x509 -text -noout -in key.crt` + + When done, you'll see the certificate data output. + +3. Create a client keystore. + +- For **JMS and XMS** based clients, create a .jks client keystore and create and verify a keystore password: + + `keytool -keystore clientkey.jks -storetype jks -importcert -file key.crt -alias server-certificate` + +- For MQI based Clients (**Node, Python, Go**) + + Create a key database, a stash file. You will need to have installed the MQI client, so that you can run the + runmqakm tool: + + `runmqakm -keydb -create -db clientkey.kdb -pw tru5tpassw0rd -type pkcs12 -expire 1000 -stash` + +- Import the server's public key certificate into the client key database + + `runmqakm -cert -add -label QM1.cert -db clientkey.kdb -pw tru5tpassw0rd -trust enable -file key.crt` + +4. Move the client keystore + +- Move the client keystore somewhere you will remember. Ensure the only files in the current directory are the `key.key` + and `key.crt` files, as IBM MQ will use the contents of this directory to configure security inside the container. + +5. Run the new docker container + +- Give it a name, for example `mqtls` so you can differentiate it from your other MQ container when you `docker ps`, + and point it at the location where you copied the server certificate. + +``` + docker run --name mqtls --env LICENSE=accept \ + --env MQ_QMGR_NAME=QM1 \ + --env MQ_APP_PASSWORD=passw0rd \ + --volume ___PATH TO SERVER_KEY/CERTIFICATE DIRECTORY___:/etc/mqm/pki/keys/mykey \ + --publish 1415:1414 \ + --publish 9444:9443 \ + --detach \ + icr.io/ibm-messaging/mq:latest +``` + +- Remember to use a secure password for `MQ_APP_PASSWORD`. + +You should be able to open the MQ Web console for this TLS container on https://localhost:9444/ibmmq/console. + +If you choose to stop the container, check the ID or name of the TLS container that was running previously with: + +`docker ps -a` + +then run + +`docker start ` + +to start the container again. + +## MQI Paths +The MQI samples; `Node.js`, `Python`, `Go`, require the MQI Client Toolkit to have been installed and the paths +`MQ_INSTALLATION_PATH` and `DYLD_LIBRARY_PATH` (MacOS) or `LD_LIBRARY_PATH` (Windows or Linux) set. + +If you have installed the MQI client manually, ensure that `MQ_INSTALLATION_PATH` is set to the root directory of your +MQI Client installation and `DYLD_LIBRARY_PATH` or `LD_LIBRARY_PATH` is set to `$MQ_INSTALLATION_PATH/lib64`. + +Do not install any application requirements until `MQ_INSTALLATION_PATH` and `DYLD_LIBRARY_PATH` or `LD_LIBRARY_PATH` +are set and exported (see language README docs for more info). + +## README docs + +### Language based MQI / JMS / XMS samples +#### [Node.js](/Node.js/README.md) +#### [JMS](/JMS/README.md) +#### [Java-MQ](/Java-MQ/README.md) +#### [Python](/Python/README.md) +#### [C# .Net](/dotnet/README.md) +#### [Go](/Go/README.md) +#### [C](/C/README.md) + +### REST samples +#### [Rust](/Rust-REST/README.md) +#### [Swift](/Swift-REST/README.md) +#### [react.js](/reactjs/README.md) + +### AMQP samples +#### [Go](/amqp/Go/README.md) +#### [C# .Net](/amqp/dotnet/README.md) +#### [QPID](/amqp-qpid/README.md) + +### Transaction samples +#### [JMS](/transactions/JMS/SE/README.md) +#### [Spring](/transactions/JMS/Spring/README.md) + +### Framework samples +#### [Spring](/Spring-JMS/README.md) +#### [Transactions on Spring](/transactions/JMS/Spring/README.md) +#### [Quarkus](/amqp-qpid/qpid-quarkus/README.md) + +### Reactive samples +#### [Vert.x](/reactive-amqp/amqp-vertx/README.md) + +### Serverless samples +#### [AWS Lambda](/serverless/aws-lambda-rest/README.md) +#### [Azure Functions](/serverless/azure-functions-rest-http-trigger/README.md) +#### [Code Engine](/serverless/codeengine/README.md) +#### [OpenWhisk Cloud Functions](/serverless/openwhisk/README.md) + +### Showcase app +#### [Showcase](/ibm-messaging-mq-cloud-showcase-app/README.md) + +### Kubernetes samples +#### [Scaling with Keda](Go-K8s/README.md) + +### MQ container deployment examples +#### [compose](/container/queuemanager/compose/README.md) +#### [compose](/container/queuemanager/terraform-aws/README.md) \ No newline at end of file From bc54ec2db82b80ac42efbe6f905312086bfed46a Mon Sep 17 00:00:00 2001 From: stuti uniyal <100413549+stutiuneyal@users.noreply.github.com> Date: Thu, 10 Jul 2025 01:50:04 +0530 Subject: [PATCH 8/8] Rename Readme.md to README.md --- Java-MQ/{Readme.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Java-MQ/{Readme.md => README.md} (100%) diff --git a/Java-MQ/Readme.md b/Java-MQ/README.md similarity index 100% rename from Java-MQ/Readme.md rename to Java-MQ/README.md