rewritten connector

This commit is contained in:
Radek Davidek 2026-03-17 15:27:50 +01:00
parent 579246d772
commit 0833bcff06
2 changed files with 369 additions and 370 deletions

View File

@ -24,14 +24,13 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
/** /**
* IBM MQ connector using JMS client with Jakarta JMS API. * IBM MQ connector using JMS client with Jakarta JMS API. Supports
* Supports multi-instance Queue Manager, SSL/TLS, and multiple message formats. * multi-instance Queue Manager, SSL/TLS, and multiple message formats.
* <p> * <p>
* Supported formats: * Supported formats: - JSON: JMS TextMessage with plain JSON string (default) -
* - JSON: JMS TextMessage with plain JSON string (default) * XML: JMS TextMessage with XML string - UTF-8 (CCSID 1208): JMS BytesMessage
* - XML: JMS TextMessage with XML string * with UTF-8 encoding - EBCDIC (CCSID 870): JMS BytesMessage with EBCDIC
* - UTF-8 (CCSID 1208): JMS BytesMessage with UTF-8 encoding * IBM-870 encoding
* - EBCDIC (CCSID 870): JMS BytesMessage with EBCDIC IBM-870 encoding
*/ */
public class IbmMqConnector implements Connector { public class IbmMqConnector implements Connector {
@ -46,58 +45,60 @@ public class IbmMqConnector implements Connector {
private final MQConnectionFactory connectionFactory; private final MQConnectionFactory connectionFactory;
private JMSContext jmsContext; private JMSContext jmsContext;
private final String queueManager; private final String queueManager;
private final String user;
private final String password;
/** /**
* Constructor with multi-instance Queue Manager support. * Constructor with multi-instance Queue Manager support.
* *
* @param connectionNameList Connection name list in format "host1(port1),host2(port2)" * @param connectionNameList Connection name list in format
* "host1(port1),host2(port2)"
* @param channel MQ channel name * @param channel MQ channel name
* @param queueManager Queue Manager name * @param queueManager Queue Manager name
* @param user Username for authentication * @param user Username for authentication
* @param password Password for authentication * @param password Password for authentication
* @param keystorePath Path to SSL keystore (can be null for non-SSL) * @param keystorePath Path to SSL keystore (can be null for non-SSL)
* @param keystorePassword Password for SSL keystore * @param keystorePassword Password for SSL keystore
* @param sslCipherSuite SSL cipher suite to use (e.g., "TLS_RSA_WITH_AES_256_CBC_SHA256") * @param sslCipherSuite SSL cipher suite to use (e.g.,
* "TLS_RSA_WITH_AES_256_CBC_SHA256")
*/ */
public IbmMqConnector(String connectionNameList, String channel, String queueManager, public IbmMqConnector(String connectionNameList, String channel, String queueManager, String user, String password,
String user, String password,
String keystorePath, String keystorePassword, String sslCipherSuite) { String keystorePath, String keystorePassword, String sslCipherSuite) {
this.queueManager = queueManager; this.queueManager = queueManager;
this.user = user;
this.password = password;
try { try {
MQConnectionFactory cf = new MQConnectionFactory(); if (keystorePath != null && !keystorePath.isBlank()) {
// Set connection name list for multi-instance QMGR
cf.setChannel(channel);
cf.setQueueManager(queueManager);
cf.setConnectionNameList(connectionNameList);
cf.setTransportType(WMQConstants.WMQ_CM_CLIENT);
// Set authentication
cf.setStringProperty(WMQConstants.USERID, user);
cf.setStringProperty(WMQConstants.PASSWORD, password);
// SSL configuration if keystore is provided
if (StringUtils.isNotBlank(keystorePath)) {
System.setProperty("javax.net.ssl.keyStore", keystorePath); System.setProperty("javax.net.ssl.keyStore", keystorePath);
System.setProperty("javax.net.ssl.trustStore", keystorePath); System.setProperty("javax.net.ssl.trustStore", keystorePath);
if (StringUtils.isNotBlank(keystorePassword)) { if (keystorePassword != null) {
System.setProperty("javax.net.ssl.keyStorePassword", keystorePassword); System.setProperty("javax.net.ssl.keyStorePassword", keystorePassword);
System.setProperty("javax.net.ssl.trustStorePassword", keystorePassword); System.setProperty("javax.net.ssl.trustStorePassword", keystorePassword);
} }
if (StringUtils.isNotBlank(sslCipherSuite)) {
cf.setSSLCipherSuite(sslCipherSuite);
}
} }
this.connectionFactory = cf; connectionFactory = new MQConnectionFactory();
connectionFactory.setConnectionNameList(connectionNameList);
connectionFactory.setQueueManager(queueManager);
connectionFactory.setChannel(channel);
connectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
if (user != null && !user.isBlank()) {
connectionFactory.setStringProperty(WMQConstants.USERID, user);
}
if (password != null && !password.isBlank()) {
connectionFactory.setStringProperty(WMQConstants.PASSWORD, password);
}
if (sslCipherSuite != null && !sslCipherSuite.isBlank()) {
connectionFactory.setSSLCipherSuite(sslCipherSuite);
}
// Initialize JMS context // Initialize JMS context
connect(); connect();
} catch (Exception e) { } catch (Exception e) {
throw new MessagingConnectionException( throw new MessagingConnectionException("Failed to create IBM MQ connection to " + queueManager, e);
"Failed to create IBM MQ connection to " + queueManager, e);
} }
} }
@ -106,7 +107,7 @@ public class IbmMqConnector implements Connector {
*/ */
private void connect() { private void connect() {
try { try {
this.jmsContext = connectionFactory.createContext(); this.jmsContext = connectionFactory.createContext(user, password, JMSContext.AUTO_ACKNOWLEDGE);
this.jmsContext.start(); this.jmsContext.start();
LOG.info("Connected to IBM MQ: {}", queueManager); LOG.info("Connected to IBM MQ: {}", queueManager);
} catch (Exception e) { } catch (Exception e) {
@ -145,8 +146,8 @@ public class IbmMqConnector implements Connector {
/** /**
* Send a message as BytesMessage with specific encoding and CCSID. * Send a message as BytesMessage with specific encoding and CCSID.
*/ */
private void sendBytesMessage(String queueName, String payload, Charset charset, private void sendBytesMessage(String queueName, String payload, Charset charset, int ccsid,
int ccsid, Map<String, String> properties) { Map<String, String> properties) {
javax.jms.Queue queue = getQueue(queueName); javax.jms.Queue queue = getQueue(queueName);
BytesMessage message = jmsContext.createBytesMessage(); BytesMessage message = jmsContext.createBytesMessage();
@ -187,8 +188,7 @@ public class IbmMqConnector implements Connector {
* @param format Message format (JSON, XML, EBCDIC_870, UTF8_1208) * @param format Message format (JSON, XML, EBCDIC_870, UTF8_1208)
* @param properties JMS properties to set * @param properties JMS properties to set
*/ */
public void send(String queueName, String payload, MqMessageFormat format, public void send(String queueName, String payload, MqMessageFormat format, Map<String, String> properties) {
Map<String, String> properties) {
switch (format) { switch (format) {
case JSON, XML -> sendTextMessage(queueName, payload, properties); case JSON, XML -> sendTextMessage(queueName, payload, properties);
case EBCDIC_870 -> sendBytesMessage(queueName, payload, EBCDIC_870, 870, properties); case EBCDIC_870 -> sendBytesMessage(queueName, payload, EBCDIC_870, 870, properties);
@ -205,8 +205,8 @@ public class IbmMqConnector implements Connector {
* @param timeout Timeout duration * @param timeout Timeout duration
* @return Received message * @return Received message
*/ */
public ReceivedMessage receive(String queueName, String messageSelector, public ReceivedMessage receive(String queueName, String messageSelector, MqMessageFormat format,
MqMessageFormat format, java.time.Duration timeout) { java.time.Duration timeout) {
long timeoutMs = timeout.toMillis(); long timeoutMs = timeout.toMillis();
javax.jms.Queue queue = getQueue(queueName); javax.jms.Queue queue = getQueue(queueName);
@ -235,9 +235,8 @@ public class IbmMqConnector implements Connector {
} }
if (received == null) { if (received == null) {
throw new MessagingTimeoutException( throw new MessagingTimeoutException("No message matching filter found on queue '" + queueName
"No message matching filter found on queue '" + queueName + + "' within " + timeout.toMillis() + "ms");
"' within " + timeout.toMillis() + "ms");
} }
return received; return received;
@ -264,8 +263,8 @@ public class IbmMqConnector implements Connector {
* @param maxMessages Maximum number of messages to browse * @param maxMessages Maximum number of messages to browse
* @return List of received messages * @return List of received messages
*/ */
public List<ReceivedMessage> browse(String queueName, String messageSelector, public List<ReceivedMessage> browse(String queueName, String messageSelector, MqMessageFormat format,
MqMessageFormat format, int maxMessages) { int maxMessages) {
List<ReceivedMessage> messages = new ArrayList<>(); List<ReceivedMessage> messages = new ArrayList<>();
javax.jms.Queue queue = getQueue(queueName); javax.jms.Queue queue = getQueue(queueName);
@ -391,8 +390,8 @@ public class IbmMqConnector implements Connector {
headers.put("JMSType", ""); headers.put("JMSType", "");
} }
try { try {
headers.put("JMSDestination", message.getJMSDestination() != null ? headers.put("JMSDestination",
message.getJMSDestination().toString() : ""); message.getJMSDestination() != null ? message.getJMSDestination().toString() : "");
} catch (JMSException e) { } catch (JMSException e) {
headers.put("JMSDestination", ""); headers.put("JMSDestination", "");
} }

View File

@ -51,8 +51,8 @@ public class ImqFirstVisionEndpoint implements Endpoint {
//Credentials credentials = loadCredentialsFromVault(vaultPath); //Credentials credentials = loadCredentialsFromVault(vaultPath);
// SSL configuration (optional) // SSL configuration (optional)
String keystorePath = null; String keystorePath = "/home/kamma/aa/mq-docker/truststore.jks";
String keystorePassword = null; String keystorePassword = "changeit";
try { try {
this.connector = new IbmMqConnector( this.connector = new IbmMqConnector(