3
votes

I've got a Spring Integration flow which uses an inbound gateway to get messages from an IBM MQ queue:

<int-jms:inbound-gateway id="InputGateway"  
   request-destination="RequestQueue"  
         request-channel="RequestChannel"
         reply-channel="ReplyChannel"     
         />

However I'm not capable of assigning security settings. In particular, I need an username, password and userAuthenticationMQCSP = false (for reasons beyond the scope of this post, I won't get into details but my broker will throw a MQRC = 2009 otherwise).

I've followed the IBM guide to connect with jmsTemplate and works just fine. This uses the official Spring boot starter from IBM MQ which will kindly create a connection factory and will autoconfigure it with some defaults from application.properties:

ibm.mq.queueManager=myQMName
ibm.mq.channel=myChannel
ibm.mq.connName=myhostname(myPort)
ibm.mq.user=username
ibm.mq.password=*******
ibm.mq.userAuthenticationMQCSP=false

Now, back to the Spring Integration case. According to the int-jms:inbound-gateway spec, a connectionFactory will be injected to the gateway, by name (attribute: connection-factory) which is set up to be "jmsConnectionFactory" by default

By default, all of the JMS adapters that require a reference to the ConnectionFactory automatically look for a bean named jmsConnectionFactory. That is why you do not see a connection-factory attribute in many of the examples. However, if your JMS ConnectionFactory has a different bean name, you need to provide that attribute.

I don't see any way to set up a predictable name for the connection factory that I can plug into the int-jms:inbound-gateway.

Now, taking a different approach, as per this example I've created my connectionFactory with an adecuate name:

<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
     <property name="transportType" value="1"/>
     <property name="queueManager" value="myQMName"/>
     <property name="hostName" value="myhostname"/>
     <property name="port" value="myPort" />
     <property name="channel" value="myChannel"/>
</bean>

But now I need somewhere to put the credentials and the security parameters. Looking at the example above, it looks like I need to plug something like:

<bean id="secureJmsConnectionAdapter" class="**yourpackages.SecureJMSConnectionAdapter**">
    <property name="targetConnectionFactory" ref="${jms.mq.connection.factory}" />
    <property name="userName" value="${jms.username}"/>
    <property name="pwdAlias" value="${jms.alias}"/>
</bean>

However it is unclear to me how to implement this SecureJMSConnectionAdapter.

Additionally, if I set up my own connection factory, I will lose all of MQ boot starter automagic thanks to this annotation on the MQAutoConfiguration class:

@ConditionalOnMissingBean(value=javax.jms.ConnectionFactory.class)

Any ideas on how to put these pieces together?

EDIT: Just to avoid any possible red herrings to anyone, the MQRC2009 was irrelevant to ibm.mq.userAuthenticationMQCSP=false.

1

1 Answers

2
votes

Some of my old projects I used a bean like this:

<bean id="jmsQueueConnectionFactory"
      class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
    <property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
    <property name="username" value="${jms.username}"/>
    <property name="password" value="${jms.alias}"/>
</bean>

Should work well as a wrapper for your com.ibm.mq.jms.MQQueueConnectionFactory, but you have to use this jmsQueueConnectionFactory in the target components.

Although it looks like the mentioned IBM MQ JMS Spring doesn't that for us properly exposing a jmsConnectionFactory bean. You can rely on the default from Spring Integration in this case or use that jmsConnectionFactory explicitly for the connection-factory.

Also with Spring Boot you should consider to go away from XML configuration and give a chance for Spring Integration Java DSL: https://docs.spring.io/spring-integration/docs/5.1.7.RELEASE/reference/html/#java-dsl