Configure MQ Call for local testing Jetty - jms

I was successful in making MQ call on my websphere server. But I am having hard time to make the same work on local jetty server. I am not even bale to start my server locally because of jms error.
I have two jndi name configured on websphere server as:
ConnectionFactory- jms/connectionFactory
Queue- jms/cardAcquireQueue
Below is code for bean entry:-
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<jee:jndi-lookup jndi-name="jms/connectionFactory"/>
</property>
<property name="defaultDestinationName">
<jee:jndi-lookup jndi-name="jms/cardAcquireQueue"/>
</property>
<property name="pubSubDomain" value="true" />
</bean>
The above works fine on server. But for jetty I have following code in jetty:-
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<New class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jms/connectionFactory</Arg>
<Arg>
<New class="org.apache.activemq.ActiveMQConnectionFactory">
<Arg>vm://localhost?broker.persistent=false</Arg>
</New>
</Arg>
</New>
<New class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jms/cardAcquireQueue</Arg>
<Arg>
------I dont know What needs to be done here -----
</Arg>
</New>
</Configure>
I am not getting error from jms/ConnectionFactory but with jms/cardAcquireQueue I get returned null error.
Can you help how to configure jndi name for jms queue.

Related

Jetty 9 XML Connector Configuration error

I am attempting to run jetty 9.3.8. I had to change over my Jetty 8 configuration, which was working, but I am now receiving a Config error which prints out the whole XML connector configuration line.
Here is what Jetty doesn't like - jetty.xml
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.nio.SelecChannelConnector">
<Set name="host">
<Property name="jetty.host" default="localhost"/>
</Set>
<Set name="port">
<Property name="jetty.port" default="7080"/>
</Set>
<Set name="maxIdleTime">60000</Set>
<Set name="Acceptors">2</Set>
<Set name="statsOn">false</Set>
<Set name="lowResourcesConnections">20000</Set>
<Set name="confidentialPort">7443</Set>
</New>
</Arg>
</Call>
Any ideas are great.
You have a typo in SelecChannelConnector => SelectChannelConnector.
Anyway, for Jetty 9 you should prefer the use of org.eclipse.jetty.server.ServerConnector as quoted in Jetty's own documentation:
Prior to Jetty 9, the type of the connector specified both the protocol and the implementation used; for example, selector-based non blocking I/O vs blocking I/O, or SSL connector vs non-SSL connector. Jetty 9 has a single selector-based non-blocking I/O connector, and a collection of ConnectionFactories now configure the protocol on the connector.
Configuring Jetty Connectors

Spring Configuration for JMS (Websphere MQ - SSL, Tomcat, JNDI, Non IBM JRE)

Background:
I have a relatively old application that uses Websphere MQ for messaging. It runs on WAS (Websphere Application Server) and uses MDBs (Message Driven Beans). I was successfully able to replace all MDBs using Spring Integration - JMS. My next step is try to see if I can port it out of WAS so that it can run on any other servlet container with a non-IBM JRE (I am trying: apache tomcat). Note that securing channels using SSL is a requirement. I prefer using JNDI.
End Goal:
To decouple my application from the application server (WAS) and other infrastructure like messaging (MQ). But taking this out of WAS onto tomcat is the first step. Next comes the task of updating my messaging infrastructure with something more scalable. This allows me to update individual components of the infrastructure that my app relies on, one thing at a time (app server, messaging layer, datastore) without disrupting my application too much, as I go.
Question:
Now, my challenge is to define JNDI resources on tomcat that can access Websphere MQ. I have made some progress on this using non-SSL channels that I defined in the context.xml file like so:
<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="CHANNEL_SANDBOX"
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"/>
My next step is to get this to work with SSL channels. I understand the part that involves setting up the keystores (kdb file and cert generation and exchanging), configuring the SSL channels on the QM etc. I have all that working already. How do I get tomcat to use my keystore, cipher suite etc? Pointers or a working example would be great!
Note: I am using Spring Integration 4.2, Websphere MQ v8, Tomcat v9, currently.
I must add that I did try everything without the JNDI first. So here's my spring jms non-ssl config without the JNDI, that works:
<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="CHANNEL_SANDBOX" />
</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>
I think I finally figured out how to pull this off... here's a brief description of the steps. If you need more details let me know.
Pre-reqs:
Websphere MQ Server installed (at least v 8.0.0.2)
Configure the QM, SSL and non-SSL channels, create Qs and all that good stuff you need.
Needless to say, you need the Websphere MQ jars. Be mindful of any licensing restrictions.
Step 1: Get the direct connection working with no SSL, no JNDI. You will need to use these beans to configure your spring based JMS listeners 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 the direct connection working with SSL, no JNDI. I found setting this up a little tricky.
2a. Since I was using a non-IBM JRE, I had to make sure the cipher specs & cipher suites needed to be configured according to the mappings specified here:
http://www-01.ibm.com/support/docview.wss?uid=swg1IV66840
This obviously means that we at least have to have our Websphere MQ upgraded to 8.0.0.2. In my case I used ECDHE_RSA_AES_256_GCM_SHA384 on the SSL channel and configured the jms beans within application to use TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, like so:
<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 certs, keystores (kdbs), exchange certs etc. There are many ways to do this. But be mindful that you will need to stash passwords, the key label for the queue manager must be ‘ibmwebspheremqqmgr’ – all in lower case, no spaces, (without quotes), the key label must be like ‘ibmwebspheremquserid’ – all in lower case, no spaces, (without quotes) where userid is the userid that runs tomcat. If you need more details on exactly how I did it using self signed certs, let me know.
2c. Now you have to get the JVM that tomcat runs, 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 (debugging SSL 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. Start 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 it, make sure that setenv.bat is used during start up. Or use JAVA_OPTS to set the keystore properties.
2e. Verify that the using the SSL channel works.
Step 3: Get a JNDI connection working with non-SSL, JNDI
There are many was to set up JNDI on tomcat. Here's how I did it: Within the web application create a file 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="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 your spring config, instead of the direct configurations, all you have to do is:
<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 just didn't use resource references. In case you do, there a few additional steps which are straight forward.
Step 4: Now the final step is to use an SSL channel and JNDI. Assuming you have done step 2, this is easy. Modify the 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
Hopefully all this works for you. Good luck!
Once this configuration works, sending messages is pretty straight forward. But this is how you can listen for a message on a queue using Spring JMS
Reference: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/jms.html
Step 1: Use Spring's DefaultMessageListenerContainer and configure your beans in an xml file like so (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">
<!-- this is the Message Driven POJO (MDP) -->
<bean id="messageListener" class="jmsexample.ExampleListener" />
<!-- and this is the message listener container -->
<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 a Message Listener class like so:
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 are using spring integration, you can do something like so:
<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>

Use ActiveMQ in Travis CI

My build in Travis CI failed after add configuration on Active MQ.
The log of Travis CI shows:
Caused by: javax.jms.JMSException: Could not connect to broker URL: tcp://localhost:61616. Reason: java.net.ConnectException: Connection refused
at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:36)
at org.apache.activemq.ActiveMQConnectionFactory.createActiveMQConnection(ActiveMQConnectionFactory.java:360)
at org.apache.activemq.ActiveMQConnectionFactory.createActiveMQConnection(ActiveMQConnectionFactory.java:305)
at org.apache.activemq.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:245)
at org.springframework.jms.connection.SingleConnectionFactory.doCreateConnection(SingleConnectionFactory.java:365)
at org.springframework.jms.connection.SingleConnectionFactory.initConnection(SingleConnectionFactory.java:305)
at org.springframework.jms.connection.SingleConnectionFactory.getConnection(SingleConnectionFactory.java:283)
at org.springframework.jms.connection.SingleConnectionFactory.createConnection(SingleConnectionFactory.java:224)
at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:180)
at org.springframework.jms.listener.AbstractJmsListeningContainer.createSharedConnection(AbstractJmsListeningContainer.java:413)
at org.springframework.jms.listener.AbstractJmsListeningContainer.establishSharedConnection(AbstractJmsListeningContainer.java:381)
at org.springframework.jms.listener.AbstractJmsListeningContainer.doStart(AbstractJmsListeningContainer.java:285)
at org.springframework.jms.listener.SimpleMessageListenerContainer.doStart(SimpleMessageListenerContainer.java:209)
at org.springframework.jms.listener.AbstractJmsListeningContainer.start(AbstractJmsListeningContainer.java:270)
... 44 more
I'm using Spring MVC, here's the configuration for testing:
<beans "Some DTDs here">
<!-- Base Components -->
<context:annotation-config />
<context:component-scan base-package="com.trunkshell.voj" />
<!-- Some other configuration for JDBC and other service -->
<!-- Message Service -->
<bean id="amqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<constructor-arg index="0" value="tcp://localhost:61616"/>
</bean>
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="amqConnectionFactory" />
</bean>
<bean id="defaultDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0" value="vojMessageQueue"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="defaultDestination" ref="defaultDestination" />
</bean>
<bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destinationName" value="vojMessageQueue" />
<property name="messageListener" ref="messageReceiver" />
</bean>
<bean id="messageSender" class="com.trunkshell.voj.util.MessageSender"></bean>
<bean id="messageReceiver" class="com.trunkshell.voj.util.MessageReceiver"></bean>
</beans>
I also noticed that Travis CI only support RabbitMQ and ZeroMQ.
Here's the reference: link
So what should I do to fix the error in Travis CI?
Or how to skip this problem in Travis CI.
I don't see that you actually start an ActiveMQ broker at port 61616. Either, do that, or preferably use the VM transport during the integration tests. I.e. change tcp://localhost:61616 to vm://localhost?broker.persistent=false
Of course, you have to be able to change that ActiveMQ URL when you deploy to a production environment. Maybe you can use spring property placeholders?

Embedded databases in Jetty

What I want is when Jetty starts, it creates a database which can be used by my webapps. My goal is to be able to deploy my webapps on every computer to display my application.
I need a way to declare my HSQLDB database (I've SQL-files for all my databases to set up the structure and to fill it with datas) in the Jetty configuration. Those parameters just have to be set one time and won't change in the future.
I feel like I've looked for it everywhere and tried everything but nothing wants to work :( I'm using Jetty 9 by the way.
This is one of the option I've tried and which seems to be close to my solution to me. I added this code to jetty/etc/jetty.xml
<New id="toto" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/toto</Arg>
<Arg>
<New class="org.apache.commons.dbcp.BasicDataSource">
<Set name="DriverClassName">org.hsqldb.jdbc.jdbcDataSource</Set>
<Set name="Url">jdbc:hsqldb:hsql://localhost:9015/toto</Set>
<Set name="Username">toto</Set>
<Set name="Password">toto</Set>
</New>
</Arg>
</New>
and this one to jett/etc/webdefault.xml
<resource-ref>
<res-ref-name>jdbc/toto</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Merry Christmas to anyone who can help me :)
Edit 26/12/2013 :
Another option I tried is to configure the database through spring in Eclipse. Each webapp matches a project (maven architecture) and use its own database. Thus, for one project I did this :
*conf/common/resources/applicationContext.xml (Project)
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:toto"/>
<property name="username" value="toto"/>
<property name="password" value="toto"/>
</bean>
*conf/dev/WEB-INF/web.xml (Project)
<resource-ref>
<res-ref-name>jdbc/toto</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
*conf/dev/WEB-INF/jetty-web.xml (Project)
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
<New id="square" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref id="wac" /></Arg>
<Arg>jdbc/square</Arg>
<Arg>
<New class="org.hsqldb.jdbc.jdbcDataSource">
<Set name="Database">file:square</Set>
<Set name="User">${database.connection.username}</Set>
<Set name="Password">${database.connection.password}</Set>
</New>
</Arg>
</New>
</Configure>
*jetty/start.ini (Jetty) : Uncomment these lines
OPTIONS=jndi
OPTIONS=plus
etc/jetty-plus.xml
With all that, I get this exception :
java.lang.ExceptionInInitializerError
at org.apache.jasper.servlet.JspServlet.init(JspServlet.java:159)
at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:540)
at org.eclipse.jetty.servlet.ServletHolder.initialize(ServletHolder.java:349)
at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:812)
at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:288)
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1322)
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:732)
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:490)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:118)
at org.eclipse.jetty.util.component.ContainerLifeCycle.addBean(ContainerLifeCycle.java:282)
at org.eclipse.jetty.util.component.ContainerLifeCycle.addBean(ContainerLifeCycle.java:214)
at org.eclipse.jetty.util.component.ContainerLifeCycle.updateBeans(ContainerLifeCycle.java:764)
at org.eclipse.jetty.server.handler.HandlerCollection.setHandlers(HandlerCollection.java:89)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.setHandlers(ContextHandlerCollection.java:145)
at org.eclipse.jetty.server.handler.HandlerCollection.addHandler(HandlerCollection.java:155)
at org.eclipse.jetty.deploy.bindings.StandardDeployer.processBinding(StandardDeployer.java:41)
at org.eclipse.jetty.deploy.AppLifeCycle.runBindings(AppLifeCycle.java:186)
at org.eclipse.jetty.deploy.DeploymentManager.requestAppGoal(DeploymentManager.java:495)
at org.eclipse.jetty.deploy.DeploymentManager.addApp(DeploymentManager.java:146)
at org.eclipse.jetty.deploy.providers.ScanningAppProvider.fileAdded(ScanningAppProvider.java:175)
at org.eclipse.jetty.deploy.providers.ScanningAppProvider$1.fileAdded(ScanningAppProvider.java:64)
at org.eclipse.jetty.util.Scanner.reportAddition(Scanner.java:605)
at org.eclipse.jetty.util.Scanner.reportDifferences(Scanner.java:528)
at org.eclipse.jetty.util.Scanner.scan(Scanner.java:391)
at org.eclipse.jetty.util.Scanner$1.run(Scanner.java:329)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
EDIT 07/01/2014
I gave up on that path but I succeeded to do what I want here: Connect databases to HSQLDB Server
It looks like you are using your HSQLDB as an embedded database, but are trying to connect to it in the server mode. Please check out the following documentation for the correct JDBC connection string when running HSQLDB in the embedded mode:
http://hsqldb.org/doc/guide/running-chapt.html#rgc_inprocess

SSL Java Client for WebSphere MQ

I try to develop a test client (Java web application) for WebSphere MQ via Spring.
I've enabled the SSL security mechanism for the channel, queue manager and connection factory, using the NULL_MD5 cipher spec.
This is my Spring configuration file:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<context:annotation-config/>
<context:property-placeholder location="classpath:jms.properties"/>
<bean id="jmsFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName" value="${queue_hostname}"/>
<property name="queueManager" value="${queue_manager}"/>
<property name="channel" value="${queue_channel}"/>
<property name="port" value="${queue_port}"/>
<property name="transportType" value="1"/>
<property name="SSLCipherSuite" value="SSL_RSA_WITH_NULL_MD5"/>
</bean>
<bean id="sendDestination" class="com.ibm.mq.jms.MQQueue">
<property name="baseQueueName">
<value>queue.inbound</value>
</property>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<bean class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory">
<ref local="jmsFactory" />
</property>
</bean>
</property>
<property name="defaultDestination">
<ref bean="sendDestination" />
</property>
</bean>
<bean id="messageListener" class="com.test.MessageListener" />
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory">
<bean class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory">
<ref local="jmsFactory" />
</property>
</bean>
</property>
<property name="destination" ref="sendDestination" />
<property name="messageListener" ref="messageListener" />
</bean>
</beans>
The problem is when I try to connect to the WebSphere MQ an exception raises:
Caused by: org.springframework.context.ApplicationContextException: Failed to start bean 'jmsContainer'; nested exception is java.lang.AssertionError
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:170)
at org.springframework.context.support.DefaultLifecycleProcessor.access$1(DefaultLifecycleProcessor.java:154)
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:339)
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:143)
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:108)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:926)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:467)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:103)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1)
at org.springframework.test.context.support.DelegatingSmartContextLoader.loadContext(DelegatingSmartContextLoader.java:228)
at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124)
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)
... 27 more
Caused by: java.lang.AssertionError
at com.ibm.mq.jmqi.internal.CipherSpec.<init>(CipherSpec.java:53)
at com.ibm.mq.jmqi.JmqiUtils.toCipherSuite(JmqiUtils.java:325)
at com.ibm.mq.jmqi.remote.impl.RemoteTCPConnection.parseCipherSpec(RemoteTCPConnection.java:1984)
at com.ibm.mq.jmqi.remote.impl.RemoteTCPConnection.makeSocketSecure(RemoteTCPConnection.java:1838)
at com.ibm.mq.jmqi.remote.impl.RemoteTCPConnection.connnectUsingLocalAddress(RemoteTCPConnection.java:810)
at com.ibm.mq.jmqi.remote.impl.RemoteTCPConnection.protocolConnect(RemoteTCPConnection.java:1130)
at com.ibm.mq.jmqi.remote.impl.RemoteConnection.connect(RemoteConnection.java:710)
at com.ibm.mq.jmqi.remote.impl.RemoteConnectionSpecification.getSessionFromNewConnection(RemoteConnectionSpecification.java:400)
at com.ibm.mq.jmqi.remote.impl.RemoteConnectionSpecification.getSession(RemoteConnectionSpecification.java:299)
at com.ibm.mq.jmqi.remote.impl.RemoteConnectionPool.getSession(RemoteConnectionPool.java:164)
at com.ibm.mq.jmqi.remote.api.RemoteFAP.jmqiConnect(RemoteFAP.java:1595)
at com.ibm.mq.jmqi.remote.api.RemoteFAP.jmqiConnect(RemoteFAP.java:1223)
at com.ibm.mq.ese.jmqi.InterceptedJmqiImpl.jmqiConnect(InterceptedJmqiImpl.java:311)
at com.ibm.mq.ese.jmqi.ESEJMQI.jmqiConnect(ESEJMQI.java:337)
at com.ibm.msg.client.wmq.internal.WMQConnection.<init>(WMQConnection.java:346)
at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createV7ProviderConnection(WMQConnectionFactory.java:6876)
at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createProviderConnection(WMQConnectionFactory.java:6254)
at com.ibm.msg.client.jms.admin.JmsConnectionFactoryImpl.createConnection(JmsConnectionFactoryImpl.java:285)
at com.ibm.mq.jms.MQConnectionFactory.createCommonConnection(MQConnectionFactory.java:6189)
at com.ibm.mq.jms.MQQueueConnectionFactory.createQueueConnection(MQQueueConnectionFactory.java:120)
at com.ibm.mq.jms.MQQueueConnectionFactory.createConnection(MQQueueConnectionFactory.java:203)
at org.springframework.jms.connection.SingleConnectionFactory.doCreateConnection(SingleConnectionFactory.java:342)
at org.springframework.jms.connection.SingleConnectionFactory.initConnection(SingleConnectionFactory.java:288)
at org.springframework.jms.connection.SingleConnectionFactory.createConnection(SingleConnectionFactory.java:225)
at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:184)
at org.springframework.jms.listener.AbstractJmsListeningContainer.createSharedConnection(AbstractJmsListeningContainer.java:403)
at org.springframework.jms.listener.AbstractJmsListeningContainer.establishSharedConnection(AbstractJmsListeningContainer.java:371)
at org.springframework.jms.listener.DefaultMessageListenerContainer.establishSharedConnection(DefaultMessageListenerContainer.java:750)
at org.springframework.jms.listener.AbstractJmsListeningContainer.doStart(AbstractJmsListeningContainer.java:278)
at org.springframework.jms.listener.AbstractJmsListeningContainer.start(AbstractJmsListeningContainer.java:263)
at org.springframework.jms.listener.DefaultMessageListenerContainer.start(DefaultMessageListenerContainer.java:556)
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:167)
... 38 more
It is strange that even though I set the SSLCipherSuite property it tries to get the cipher suite by the cipher spec...
Can someone please suggest how to fix this?
This bug is acknowledged here: http://www-01.ibm.com/support/docview.wss?uid=swg1IV36662
And marked as fixed in Websphere MQ fix pack 7.1.0.3.
The recommended (but not entirely satisfactory) workaround is to disable assertions in the JRE command line, with either "-disableassertions" or "-da".
Well, after some research it appeared that the problem is in the assertion mechanism. If assertions are disabled everything works fine. It is strange that you can have a completely working code even if assertions fail... And it is rather pity that I can't find a way to set the cipher spec - only the cipher suite setter is provided by the MQQueueConnectionFactory class.
In case of the weblogic server, there is a parameter named 'debugFlag' that is verified in the WLS_HOME/user_projects/domains/local-domain-name/bin/setDomainEnv.cmd (.sh). If you have it set to 'true' the application would fail. Or you can add the following JAVA_OPTION: -da:com.ibm.mq... at the end of the setDomainEnv.cmd (.sh) file. This way you can leave the debug enabled.
Of cource, it is not a preferrable way to fix the problem, but for now it is the only way I could fix it.

Resources