I tried to call an Enterprise MQ in Spring Boot 2.5 using javax.jms
MQ dependencies. The connection is being successfully made. Below is my pom.xml
and code. I am using an App ID credentials to connect to the queue which I have set in the UserCredentialsProvider class.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>com.ibm.mq.allclient</artifactId>
<version>0.0.0.3</version>
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>javax.jms-api</artifactId>
<version>2.0.1</version>
</dependency>
Code -
@Bean
public MQQueueConnectionFactory mqQueueConnectionFactory() {
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
mqQueueConnectionFactory.setHostName(host);
try {
mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
mqQueueConnectionFactory.setCCSID(1208);
mqQueueConnectionFactory.setChannel(channel);
mqQueueConnectionFactory.setPort(port);
mqQueueConnectionFactory.setQueueManager(queueManager);
} catch (Exception e) {
e.printStackTrace();
}
return mqQueueConnectionFactory;
}
@Bean
UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter(MQQueueConnectionFactory mqQueueConnectionFactory) {
UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter = new UserCredentialsConnectionFactoryAdapter();
userCredentialsConnectionFactoryAdapter.setUsername(username);
userCredentialsConnectionFactoryAdapter.setPassword(password);
userCredentialsConnectionFactoryAdapter.setTargetConnectionFactory(mqQueueConnectionFactory);
return userCredentialsConnectionFactoryAdapter;
}
@Bean
@Primary
public CachingConnectionFactory cachingConnectionFactory(UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter) {
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
cachingConnectionFactory.setTargetConnectionFactory(userCredentialsConnectionFactoryAdapter);
cachingConnectionFactory.setSessionCacheSize(500);
cachingConnectionFactory.setReconnectOnException(true);
return cachingConnectionFactory;
}
@Bean
public PlatformTransactionManager jmsTransactionManager(CachingConnectionFactory cachingConnectionFactory) {
JmsTransactionManager jmsTransactionManager = new JmsTransactionManager();
jmsTransactionManager.setConnectionFactory(cachingConnectionFactory);
return jmsTransactionManager;
}
@Bean
public JmsOperations jmsOperations(CachingConnectionFactory cachingConnectionFactory) throws JMSException {
JmsTemplate jmsTemplate = new JmsTemplate(cachingConnectionFactory);
jmsTemplate.setReceiveTimeout(receiveTimeout);
Connection c = jmsTemplate.getConnectionFactory().createConnection();
System.out.println(c.getMetaData()); //the connection is established successfully
return jmsTemplate;
}
Now, what I did was that I tried to migrate to Spring Boot 3.1.1. I had to change my MQ dependencies in POM to use jakarta
in place of javax
package. Below is my updated POM:
<dependency>
<groupId>jakarta.jms</groupId>
<artifactId>jakarta.jms-api</artifactId>
</dependency>
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>com.ibm.mq.jakarta.client</artifactId>
<version>9.3.0.0</version>
</dependency>
I updated the above code to use jakarta Connection Factory instead of JMS , but now I am getting MQRC_NOT_AUTHORIZED(2035) error.
What modifications do I have to perform in order for this to work in Spring Boot 3.1 with com.ibm.mq.jakarta.client.jar 9.3?
In 9.3 the default for MQ authentication in Java and JMS classes changed from compatibility mode to MQCSP. This is why you are now getting a 2035. To get the connection working again you need to switch back to compatibility mode.
There are a few methods to set it back to compatibility mode, two of them are:
JmsConstants.USER_AUTHENTICATION_MQCSP
to false
com.ibm.mq.cfg.jmqi.useMQCSPauthentication
to N
.System.setProperty("com.ibm.mq.cfg.jmqi.useMQCSPauthentication", "N")
-Dcom.ibm.mq.cfg.jmqi.useMQCSPauthentication=N
For more details see Connection authentication with the Java client.
9.3 breaking it likely means one of three things:
CONNAUTH
configured with ADOPTCTX(NO)
.You can test if it is #3 by turning on compatibility mode and intentionally sending a incorrect password. If it works then you know it is #3.
You can test if it is #2 by turning off compatibility mode, sending the correct password and specifying -Duser.name=username
, if this works then it is likely #2.
If both of the above fail then it is likely #1.