I think I finally figured out how to do this ... here is a brief description of the steps. If you need more information, let me know.
Pre-Reqs : WebSphere MQ Server installed (at least v 8.0.0.2) Configure QM, SSL and non-SSL channels, create Qs and everything you need. Needless to say, you need Websphere MQ banks. Be aware of any licensing restrictions.
Step 1 Get a direct connection without SSL, without JNDI. You will need to use these beans to configure your JMS listeners based on spring and JMS templates, etc.
<bean id="mq-jms-cf-sandbox" class="org.springframework.jms.connection.SingleConnectionFactory"> <property name="targetConnectionFactory"> <ref bean="mqQueueConnectionFactory" /> </property> </bean> <bean id="mqQueueConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory"> <property name="hostName" value="localhost" /> <property name="port" value="1414" /> <property name="queueManager" value="QM_SANDBOX" /> <property name="transportType" value="1" /> <property name="channel" value="NON_SSL_CHANNEL" /> </bean> <bean id="jms-destination-sandbox" class="com.ibm.mq.jms.MQQueue"> <constructor-arg value="SANDBOX_Q" /> <property name="baseQueueManagerName"> <value>QM_SANDBOX</value> </property> <property name="baseQueueName"> <value>SANDBOX_Q</value> </property> </bean>
Step 2 Get a direct connection to SSL, without JNDI. I found this to be a bit complicated.
2a . Since I used a non-IBM JRE, I had to make sure that the specifications for ciphers and cipher suites needed to be configured according to the mappings listed here: http://www-01.ibm.com/support/docview.wss?uid=swg1IV66840
This obviously means that at least we should upgrade our Websphere MQ to 8.0.0.2. In my case, I used ECDHE_RSA_AES_256_GCM_SHA384 on the SSL channel and configured jms beans in the application to use TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, for example:
<bean id="mq-jms-cf-sandbox" class="org.springframework.jms.connection.SingleConnectionFactory"> <property name="targetConnectionFactory"> <ref bean="mqQueueConnectionFactory" /> </property> </bean> <bean id="mqQueueConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory"> <property name="hostName" value="localhost" /> <property name="port" value="1414" /> <property name="queueManager" value="QM_SANDBOX" /> <property name="transportType" value="1" /> <property name="channel" value="SSL_CHANNEL" /> <property name="SSLCipherSuite" value="TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"/> </bean> <bean id="jms-destination-sandbox" class="com.ibm.mq.jms.MQQueue"> <constructor-arg value="SANDBOX_Q" /> <property name="baseQueueManagerName"> <value>QM_SANDBOX</value> </property> <property name="baseQueueName"> <value>SANDBOX_Q</value> </property> </bean>
2b . Create certificates, key stores (kdbs), certificates of exchange, etc. There are many ways to do this. But remember that you will need to store passwords, the key label for the queue manager should be "ibmwebspheremqqmgr" - everything is lowercase, without spaces (without quotes), the key label should be like "ibmwebspheremquserid" - everything is lowercase, no spaces ( without quotes), where userid is the identifier of the user who runs tomcat. If you need detailed information on how I did this using self-signed certificates, let me know.
2s Now you should get a JVM that runs tomcat to read your keystores. There are many ways, but here's how I did it: Create a setenv.bat file in the tomcat bin folder with the following contents (SSL debugging is optional)
set JAVA_OPTS="-Djavax.net.ssl.trustStore=C:\path-to-keystore\key.jks" "-Djavax.net.ssl.trustStorePassword=topsecret" "-Djavax.net.ssl.keyStore=C:\path-to-keystore\key.jks" "-Djavax.net.ssl.keyStorePassword=topsecret" "-Djavax.net.debug=ssl" "-Dcom.ibm.mq.cfg.useIBMCipherMappings=false"
2d . Launch tomcat using the following command:
catalina.bat run > ..\logs\tomcat.log 2>&1
To stop, just press ctrl + c (on windows). Whichever way you do this, make sure setenv.bat is used at startup. Or use JAVA_OPTS to set the keystore properties.
2e . Verify that using the SSL channel works.
Step 3 Get a JNDI connection working with non-SSL, JNDI Many had to create JNDI on tomcat. Here's how I did it: inside the web application, create a META-INF / Context.xml file with the following contents:
<Resource name="jms/qcf_sandbox" auth="Container" type="com.ibm.mq.jms.MQQueueConnectionFactory" factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory" description="JMS Queue Connection Factory for sending messages" HOST="localhost" PORT="1414" CHAN="NON_SSL_CHANNEL" TRAN="1" QMGR="QM_SANDBOX"/> <Resource name="jms/SandboxQ" auth="Container" type="com.ibm.mq.jms.MQQueue" factory="com.ibm.mq.jms.MQQueueFactory" description="JMS Queue" QU="SANDBOX_Q"/>
Now in the spring configuration, instead of direct configurations, you only need:
<jee:jndi-lookup id="mq-jms-cf-sandbox" jndi-name="java:/comp/env/jms/qcf_sandbox" resource-ref="false" /> <jee:jndi-lookup id="jms-destination-sandbox" jndi-name="java:/comp/env/jms/SandboxQ" resource-ref="false" />
Note that for brevity, I simply did not use resource links. In case you do this, a few more steps that go straight.
Step 4 Now the last step is to use the SSL channel and JNDI. Assuming you have done step 2, this is easy. Modify META-INF / Context.xml with the following contents:
<Resource name="jms/qcf_sandbox" auth="Container" type="com.ibm.mq.jms.MQQueueConnectionFactory" factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory" description="JMS Queue Connection Factory for sending messages" HOST="localhost" PORT="1414" CHAN="SSL_CHANNEL" TRAN="1" QMGR="QM_SANDBOX" SCPHS="TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"/> <Resource name="jms/SandboxQ" auth="Container" type="com.ibm.mq.jms.MQQueue" factory="com.ibm.mq.jms.MQQueueFactory" description="JMS Queue" QU="SANDBOX_Q"/>
Note the line with SCPHS = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384". If you need to set other such parameters, see the "Short form" column in this link: https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.ref.dev.doc/q111800_ .htm% 23jm10910_? lang = en
Hope all this works for you. Good luck
Once this configuration works, sending messages is pretty simple. But you can listen to the message in the queue using spring JMS Link: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/jms.html
Step 1 Use spring DefaultMessageListenerContainer and configure your beans in an XML file, for example: spring - beans.xml):
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <bean id="messageListener" class="jmsexample.ExampleListener" /> <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="mq-jms-cf-sandbox"/> <property name="destination" ref="jms-destination-sandbox"/> <property name="messageListener" ref="messageListener" /> </bean> </beans>
Step 2 Add this to your web.xml
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/context/spring-beans.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
Step 3 : write the listener class this way:
import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; public class ExampleListener implements MessageListener { public void onMessage(Message message) { if (message instanceof TextMessage) { try { System.out.println(((TextMessage) message).getText()); } catch (JMSException ex) { throw new RuntimeException(ex); } } else { throw new IllegalArgumentException("Message must be of type TextMessage"); } } }
Alternatively, instead of step 3, if you use spring integration, you can do something like this:
<int:channel id="jms-inbound"/> <int-jms:message-driven-channel-adapter id="jms-inbound-adapter" container="jmsContainer" channel="jms-inbound" extract-payload="true" acknowledge="transacted" message-converter="messagingMessageConverter" /> <beans:bean id="messagingMessageConverter" class="org.springframework.jms.support.converter.MessagingMessageConverter"> </beans:bean>