JMS connection pooling with IBM MQ Client - jms

We are using MQIPT 9.2 between our IBM MQ 9.x server and IBM MQ clients. We're also using the IBM MQ client jar in Java to connect to the queue manager to push and receive messages which is working fine. However connection creation is taking time and every time it will take time if we create connection just in time.
How we can implement JMS connection pooling for IBM MQ?
The following depicts our connectivity:
[][1
Is there any standard way so that we can implement connection pooling?
Used Code below
System.out.println("<<<<<<<<<Starting test for push messages>>>>>>>>>>");
try {
// Create a keystore object for the truststore
KeyStore trustStore = KeyStore.getInstance("JKS");
char[] keyPassphrase = "*******".toCharArray();
trustStore.load(new FileInputStream(
"JKS File path"),
keyPassphrase);
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
System.out.println("SSL certificates loaded in message sending");
// Create default MQ connection factory
MQQueueConnectionFactory factory = new MQQueueConnectionFactory();
factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
factory.setQueueManager(QMGRNAME);
factory.setHostName(HOSTNAME);
factory.setChannel(CHANNEL);
factory.setPort(1414);
factory.setSSLFipsRequired(false);
factory.setSSLSocketFactory(sslSocketFactory);
factory.setClientReconnectTimeout(100);
factory.setStringProperty(WMQConstants.USERID, user);
factory.setStringProperty(WMQConstants.PASSWORD, password);
factory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
factory.setStringProperty(WMQConstants.WMQ_SSL_CIPHER_SUITE, "cipher suite");
mqConnection = (MQQueueConnection) factory.createQueueConnection();
MQQueueSession session = (MQQueueSession) mqConnection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
// Start the connection
System.out.println("Connection starting while sending message");
mqConnection.start();
System.out.println("Connection started while sending message");
for (int i = 0; i <50; i++) {
System.out.println("Preparing message before sending");
long uniqueNumber = System.currentTimeMillis() % 1000;
JMSTextMessage message = (JMSTextMessage) session
.createTextMessage("SimplePTP - msg" + uniqueNumber);
System.out.println("message prepared while sending , text: " + message.getText());
Destination destination = session.createQueue(destinationName);
MQMessageProducer producer = (MQMessageProducer) session.createProducer(destination);
// And, send the message
producer.send(message);
System.out.println("Sent message****************:\n" + message);
}
/*
* if (connection != null) { System.out.
* println("*************connection closing after message sent********************"
* ); connection.close(); System.out.
* println("*************connection closed after message sent********************"
* ); }
*/
System.out.println("<<<<<<<<<<Test ended>>>>>>>>>>>>");
} catch (JMSException j) {
j.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("finally block after message sent************ ");
if (mqConnection != null) {
try {
mqConnection.close();
System.out.println("connection closed after message sent in finally block\n");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("<<<<<<<<<<Test ended from finally >>>>>>>>>>>>");
}
When using the above code connection creation takes time and it's creating and closing a connection for each messsage. This is a bad practice so I created a list and added connection into it which works well. However, I want to use a proper connection pool instead.

You can use:
<bean class="org.apache.activemq.jms.pool.PooledConnectionFactory"
id="source.pooledConnectionFactory" primary="true">
<property name="maxConnections" value="1"/>
<property name="idleTimeout" value="0"/>
<property name="connectionFactory" ref="factory"/>
</bean>
(sorry for the XML when you posted Java DSL, but you get the idea). Basically, wrap your connection factory with the ActiveMQ JMS pooled connection factory.
Alternatively, you can use:
<dependency>
<groupId>org.messaginghub</groupId>
<artifactId>pooled-jms</artifactId>
<version>1.1.0</version>
</dependency>
JmsPoolConnectionFactory pooledCF = new JmsPoolConnectionFactory();
pooledCF.setConnectionFactory(connectionFactory());
pooledCF.setMaxConnections(1);
The org.messaginghub project is a branch of the ActiveMQ code and has no ActiveMQ dependencies.

Related

MQ MessageConsumer does not respond to receive() method

I have a java program I run to write messages to Mid-Tier IBM MQ's to test functionality before attaching our main programs to them. The write method looks like the following below:
private static void sendSingleMessage(ConnectionFactory connectionFactory,
String[] messages, String destination) throws Exception {
Connection connection = null;
try {
connection = connectionFactory.createConnection();
for (String payload : messages) {
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue(destination);
MessageProducer producer = session.createProducer(queue);
Message msg = session.createTextMessage(payload);
System.out.println("Sending text '" + payload + "'");
producer.send(msg);
session.close();
System.out.println("Message sent");
}
} finally {
if (connection != null) {
connection.close();
}
}
}
The connectionFactory is setup before this method executes, but within that method I set the MQConncetionFactory properties(host,port,channel,queuemanager, etc...) This send method works and I can see the queue depth increasing on my IBM MQ Explorer when I call it from my main method.
When I run a similar readSingleMessage method, the code gets stuck on the consumer.receive() and never finishes executing. See below:
private static void readSingleMessage(ConnectionFactory connectionFactory,
String[] messages, String destination) throws Exception {
Connection connection = null;
try {
connection = connectionFactory.createConnection();
for (String payload : messages) {
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue(destination);
MessageConsumer consumer = session.createConsumer(queue);
System.out.println("Recieving text '" + payload + "'");
consumer.receive();
session.close();
System.out.println("Received message");
}
} finally {
if (connection != null) {
connection.close();
}
}
}
Is there anyway I can further debug this, or find why I am able to write to the queue, but unable to read a message off of it?
You have to start the JMS Connection by calling the start() method on it. You cannot receive any messages until the connection is started. This is noted in the JMS Specification and Javadoc.
As an aside, if you use the JMS 2.0 "simplified" API and create a JMSContext object (an object which is essentially a combined Connection and Session) you do not need to call start to receive messages. A consumer crated from it can be used to receive messages without being explicitly started.

Ibm mq Connection through standalone server]

I am trying to connection to a ibm mq queue through standalone server.
(i am using 7.0.3 ibmmq jar)
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, "dcc");
cf.setIntProperty(WMQConstants.WMQ_PORT, 14321);
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, "dfds");
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, "dw");
cf.setStringProperty(WMQConstants.USERID, "ww");
cf.setStringProperty(WMQConstants.PASSWORD, "vw");
i have set all these properties in connection Factory.
Conenction is made successfully but i am unable to open queue. getting the following error.
**MQJE001: Completion Code '2', Reason '6114'.**
FAILED: Queueconnection
com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ2008: Failed to open MQ queue 'US.0732931.NGEN.MANIFEST.LOADS'.
JMS attempted to perform an MQOPEN, but WebSphere MQ reported an error.
Use the linked exception to determine the cause of this error. Check that the specified queue and queue manager are defined correctly.
at com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:585)
at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:221)
You really don't provide enough information.
What connection factory are you using?
The error happens on the MQOPEN but you do NOT show the code for your createQueue method which is the important
Here's sample code:
private void putMessage()
{
JmsConnectionFactory cf = null;
Connection connection = null;
Session session = null;
Destination reqQ = null;
MessageProducer producer = null;
try
{
// Create a connection factory
JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
cf = ff.createConnectionFactory();
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, "MY_QMGR_NAME");
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, "MY_TEST_CHL");
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, "some_remote_server");
cf.setIntProperty(WMQConstants.WMQ_PORT, 1414);
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
cf.setStringProperty(WMQConstants.USERID, "my_uid");
cf.setStringProperty(WMQConstants.PASSWORD, "my_pwd");
// Create JMS objects
connection = cf.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
/**
* Create destination to send requests
* - MQA1 is the queue manager name
* - TEST.Q1 is the queue name
*/
reqQ = session.createQueue("queue://MQA1/TEST.Q1");
// Create producer
producer = session.createProducer(reqQ);
// Create a message
Message myMsg = session.createTextMessage("This is a test message.");
// Send it
producer.send(myMsg);
}
catch(Exception ex)
{
System.err.println(ex.getLocalizedMessage());
}
finally
{
try
{
session.close();
}
catch (Exception ex)
{
System.err.println("session.close() : " + ex.getLocalizedMessage());
}
try
{
connection.close();
}
catch (Exception ex)
{
System.err.println("connection.close() : " + ex.getLocalizedMessage());
}
}
}

How to configure jms on WebSphere MQ using java

I'm trying to configure Jms and WebSphere using java and using Jboss 6.3 in remote system.But am getting ClassNotFoundException in creation of MQQueueConnection Class.Here I please fine code.
Actually M not getting proper steps that what to do,I took help from IBM Knowledge Center but that is not helpful for me.
Please anyone who knows about it guide me and for below code Which jar files is required?
try {
MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
// Config
cf.setHostName("167.190.249.202");
cf.setPort(1422);
cf.setTransportType(WMQConstants.WMQ_CM_CLIENT);
cf.setQueueManager("QM.EMPIRE");
cf.setChannel("EMPIRE.CONN");
MQQueueConnection connection = (MQQueueConnection) cf.createQueueConnection();
MQQueueSession session = (MQQueueSession) connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
MQQueue queue = (MQQueue) session.createQueue("queue:///Q1");
MQQueueSender sender = (MQQueueSender) session.createSender(queue);
MQQueueReceiver receiver = (MQQueueReceiver) session.createReceiver(queue);
long uniqueNumber = System.currentTimeMillis() % 1000;
JMSTextMessage message = (JMSTextMessage) session.createTextMessage("SimplePTP "+ uniqueNumber);
// Start the connection
connection.start();
sender.send(message);
System.out.println("Sent message:\\n" + message);
JMSMessage receivedMessage = (JMSMessage) receiver.receive(10000);
System.out.println("\\nReceived message:\\n" + receivedMessage);
sender.close();
receiver.close();
session.close();
connection.close();
System.out.println("\\nSUCCESS\\n");
}
catch (JMSException jmsex) {
System.out.println(jmsex);
System.out.println("\\nFAILURE\\n");
}
catch (Exception ex) {
System.out.println(ex);
System.out.println("\\nFAILURE\\n");
}
}
}
It is far better to point your CLASSPATH to where the MQ JAR files are installed rather than copy the MQ JAR files (i.e. you won't get the 'ClassNotFoundException' error).
But if you do copy the MQ JAR files then for an MQ JMS application, you pretty much need all of them:
com.ibm.mq.jar
com.ibm.mq.commonservices.jar
com.ibm.mq.headers.jar
com.ibm.mq.jmqi.jar
com.ibm.mq.pcf.jar
com.ibm.mqjms.jar
connector.jar
fscontext.jar
jms.jar
jndi.jar
jta.jar
ldap.jar
providerutil.jar

Retry to establish a JMS connection while ActiveMQ broker is not available

Here is my scenario. I have few ActiveMQ (JBoss-AMQ) producers and consumers installed as services. In a server restart, what is the best practice of handling such a situation where a producer or a consumer service starts before the ActiveMQ broker service. In that case producer/client cannot establish a connection and starts to hang on as it is even after the broker service starts.
here's my code snippet of connection creation:
try {
connection = connectionFactory.createConnection();
connection.start();
LOGGER.info(STARTED_CONNECTION_WITH_THE_DESTINATION + destinationName);
session = createSession();
destination = session.createQueue(destinationName);
LOGGER.info(CREATED_QUEUE_IN_DESTINATION + destinationName);
if (isImageProcAgent) {
consumer = createConsumer();
LOGGER.info(CONSUMER_HAS_BEEN_INITIALIZED);
} else {
producer = session.createProducer(destination);
LOGGER.info(PRODUCER_HAS_BEEN_INITIALIZE);
}
} catch (MessagingException e) {
LOGGER.error(e);
} catch (JMSException e) {
LOGGER.error(e);
}
I'm new to JMS so appreciate your support.
This can be achieved by configuring a failover as this document explains.
according to my code snippet, the change I required it:
destination = session.createQueue("failover:"+destinationName);
producer = session.createProducer("failover:"+destination);

jms sending message on any server

I want to write generic code for sending message on any jms server. so for that i thought if i have jndi.properties file then we can place server configuration in this file and we can access this file through the code but i am able to do this only for 'ActiveMQ Server'. Now i am facing problems to send the message on any other server like glassfish server or jboss server. can somebody help me to do this task.
Here is my code :
public class Producer
{
public Producer() throws JMSException, NamingException,IOException
{
InputStream is = getClass().getResourceAsStream("my.jndi.properties");
Properties jndiParamaters = new Properties();
jndiParamaters.load(is);
Context jndi = new InitialContext(jndiParamaters);
ConnectionFactory conFactory = (ConnectionFactory) jndi.lookup("connectionFactory");
Connection connection;
connection = conFactory.createConnection();
try
{
connection.start();
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
Destination destination = (Destination) jndi.lookup("Myqueue");
MessageProducer producer = session.createProducer(destination);
TextMessage message = session.createTextMessage("Hello World!");
producer.send(message);
System.out.println("Sent message '" + message.getText() + "'");
}
finally
{
connection.close();
}
}
public static void main(String[] args) throws JMSException
{
try
{
BasicConfigurator.configure();
new Producer();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
thanks
Have you tried using the Spring JMS Template? http://static.springsource.org/spring/docs/2.0.x/reference/jms.html
It provides an abstraction layer to JMS and could probably help you when your implementation changes.

Resources