6.1.2. Non-MDB HA-JMS Clients

6.1.2. Non-MDB HA-JMS Clients

The HA-JMS client is different from regular JMS clients in two important aspects.

<resource-ref>
	 <res-ref-name>jms/ConnectionFactory</res-ref-name>
	 <res-type>javax.jms.QueueConnectionFactory</res-type>
	 <res-auth>Container</res-auth>
</resource-ref>
	 
<resource-ref>
	 <res-ref-name>jms/Queue</res-ref-name>
	 <res-type>javax.jms.Queue</res-type>
	 <res-auth>Container</res-auth>
</resource-ref>

And in the JBoss-specific descriptor (jboss.xml or jboss-web.xml):

 
<resource-ref>
 	<res-ref-name>jms/ConnectionFactory</res-ref-name>
	<!-- Use the JMS Resource Adapter, let it deal
	 with knowing where the JMS server is -->
	<jndi-name>java:/JmsXA</jndi-name>
 </resource-ref>
 
<resource-ref>
	 <res-ref-name>jms/Queue</res-ref-name>
	 <!-- Use HA-JNDI so we can find the queue on any node -->
	 <jndi-name>jnp://localhost:1100/queue/A</jndi-name>
</resource-ref>
package com.test.hajms.client;

import javax.naming.InitialContext;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.Connection;
import javax.jms.Session;
import javax.jms.MessageProducer;
import javax.jms.Message;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.DeliveryMode;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
 
public class FailoverJMSClient
{
private static final Log log = LogFactory.getLog(FailoverJMSClient.class);

public static final int NUM_RETRIES = 3;

volatile boolean doSend = true;
ConnectionFactory connectionFactory;
Destination queue;
Connection connection;
Session session;
MessageProducer producer;


public static void main(String[] args) throws Exception
{
FailoverJMSClient jmsClient = new FailoverJMSClient();
jmsClient.setUpJMS();
jmsClient.sendMessages();
}


public boolean setUpJMS()
{
InitialContext ic;
try
{
// assume jndi.properties is configured for HA-JNDI
ic = new InitialContext();
connectionFactory = (ConnectionFactory)ic.lookup("ConnectionFactory");
queue = (Destination)ic.lookup("queue/FailoverTestQueue");
connection = connectionFactory.createConnection();
try
{
log.debug("Connection created ...");

// KEY - register for exception callbacks
connection.setExceptionListener(new ExceptionListenerImpl());

session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
log.debug("Session created ...");
producer = session.createProducer(queue);

producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
log.debug("Producer created ...");

return true;
}
catch (Exception e)
{
// We failed so close the connection
try
{
connection.close();
}
catch (JMSException ignored)
{
// Pointless
}
// Rethrow the initial problem to where we will log it
throw e;
} 
finally
{
// And close the initial context
// We don't want to wait for the garbage collector to close it
// otherwise we'll have useless hanging network connections
ic.close();
}
}
catch (Exception e)
{
log.error("Error setting up JMS", e);
return false;
}
}

public void sendMessages()
{
int cnt = 0;
while(doSend)
{
try
{
Thread.sleep(100);

Message m = session.createObjectMessage(new Integer(cnt++));
producer.send(m);

log.trace("message " + cnt + " sent");

}
catch(Exception e)
{
cnt--;
log.error(e.getMessage());
}
}
}



private class ExceptionListenerImpl implements ExceptionListener
{
public void onException(JMSException e)
{
			 
for(int i = 0; i < NUM_RETRIES; i++)
	    {
	    log.warn("Connection has problems, trying to re-create it, attempt " +
	    (i + 1) + " ...");
	    
	    try 
	    {
	    connection.close();  // unregisters the ExceptionListener
	    }
	    catch(Exception e2) {
	    // I will get an Exception anyway, since the connection to the                     
	    //server is broken, but close() frees up resources associated 
	    // with the connection
	    }
	    
	    boolean setupOK = setUpJMS();
	    
	    if (setupOK)
	    {
	    log.info("Connection re-established");
	    return;
	    }
	    else
	    {
	    log.warn("Re-creating connection failed, retrying ...");
	   }
	    }
	    
	    log.error("Cannot re-establish connection, giving up ...");
	    doSend = false;
	    }
	    }
}