The following code sample illustrates good coding practices for handling exceptions during a failover. It is designed to send non-transacted, persistent messages forever and to handle JMSExceptions when a failover occurs. The program is able to handle either a true or false setting for the imqReconnectEnabled property. To run the program enter one of the following commands.
java dura.example.FailoverProducer
java -DimqReconnectEnabled=true dura.example.FailoverProducer
/*
* @(#)FailoverProducer.java 1.1 06/06/09
* Copyright 2006 Sun Microsystems, Inc. All Rights Reserved
* SUN PROPRIETARY/CONFIDENTIAL
* Use is subject to license terms. */
package dura.example;
import javax.jms.*;
import com.sun.messaging.ConnectionConfiguration;
import java.util.*;
public class FailoverProducer implements ExceptionListener {
//connection factory
private com.sun.messaging.TopicConnectionFactory factory;
//connection
private TopicConnection pconn = null;
//session
private TopicSession psession = null;
//publisher
private TopicPublisher publisher = null;
//topic
private Topic topic = null;
//This flag indicates whether this test client is closed.
private boolean isClosed = false;
//auto reconnection flag
private boolean autoReconnect = false;
//destination name for this example.
private static final String DURA_TEST_TOPIC = "DuraTestTopic";
//the message counter property name
public static final String MESSAGE_COUNTER = "MESSAGE_COUNTER";
//the message in-doubt-bit property name
public static final String MESSAGE_IN_DOUBT = "MESSAGE_IN_DOUBT";
/**
* Constructor. Get imqReconnectEnabled property value from
* System property.
*/
public FailoverProducer () {
try {
autoReconnect =
Boolean.getBoolean(ConnectionConfiguration.imqReconnectEnabled);
} catch (Exception e) {
this.printException(e);
}
}
/**
* Connection is broken if this handler is called.
* If autoReconnect flag is true, this is called only
* if no more retries from MQ.
*/
public void onException (JMSException jmse) {
this.printException (jmse);
}
/**
* create MQ connection factory.
* @throws JMSException
*/
private void initFactory() throws JMSException {
//get connection factory
factory = new com.sun.messaging.TopicConnectionFactory();
}
/**
* JMS setup. Create a Connection,Session, and Producer.
*
* If any of the JMS object creation fails (due to system failure),
* it retries until it succeeds.
*
*/
private void initProducer() {
boolean isConnected = false;
while ( isClosed == false && isConnected == false ) {
try {
println("producer client creating connection ...");
//create connection
pconn = factory.createTopicConnection();
//set connection exception listener
pconn.setExceptionListener(this);
//create topic session
psession = pconn.createTopicSession(false,
Session.CLIENT_ACKNOWLEDGE);
//get destination
topic = psession.createTopic(DURA_TEST_TOPIC);
//publisher
publisher = psession.createPublisher(topic);
//set flag to true
isConnected = true;
println("producer ready.");
}
catch (Exception e) {
println("*** connect failed ... sleep for 5 secs.");
try {
//close resources.
if ( pconn != null ) {
pconn.close();
}
//pause 5 secs.
Thread.sleep(5000);
} catch (Exception e1) {
;
}
}
}
}
/**
* Start test. This sends JMS messages in a loop (forever).
*/
public void run () {
try {
//create MQ connection factory.
initFactory();
//create JMS connection,session, and producer
initProducer();
//send messages forever.
sendMessages();
} catch (Exception e) {
this.printException(e);
}
}
/**
* Send persistent messages to a topic forever. This shows how
* to handle failover for a message producer.
*/
private void sendMessages() {
//this is set to true if send failed.
boolean messageInDoubt = false;
//message to be sent
TextMessage m = null;
//msg counter
long msgcount = 0;
while (isClosed == false) {
try {
/**
* create a text message
*/
m = psession.createTextMessage();
/**
* the MESSAGE_IN_DOUBT bit is set to true if
* you get an exception for the last message.
*/
if ( messageInDoubt == true ) {
m.setBooleanProperty (MESSAGE_IN_DOUBT, true);
messageInDoubt = false;
println("MESSAGE_IN_DOUBT bit is set to true
for msg: " + msgcount);
} else {
m.setBooleanProperty (MESSAGE_IN_DOUBT, false);
}
//set message counter
m.setLongProperty(MESSAGE_COUNTER, msgcount);
//set message body
m.setText("msg: " + msgcount);
//send the msg
publisher.send(m, DeliveryMode.PERSISTENT, 4, 0);
println("sent msg: " + msgcount);
/**
* reset counetr if reached max long value.
*/
if (msgcount == Long.MAX_VALUE) {
msgcount = 0;
println ("Reset message counter to 0.");
}
//increase counter
msgcount ++;
Thread.sleep(1000);
} catch (Exception e) {
if ( isClosed == false ) {
//set in doubt bit to true.
messageInDoubt = true;
this.printException(e);
//init producer only if auto reconnect is false.
if ( autoReconnect == false ) {
this.initProducer();
}
}
}
}
}
/**
* Close this example program.
*/
public synchronized void close() {
try {
isClosed = true;
pconn.close();
notifyAll();
} catch (Exception e) {
this.printException(e);
}
}
/**
* print the specified exception.
* @param e the exception to be printed.
*/
private void printException (Exception e) {
System.out.println(new Date().toString());
e.printStackTrace();
}
/**
* print the specified message.
* @param msg the message to be printed.
*/
private void println (String msg) {
System.out.println(new Date() + ": " + msg);
}
/**
* Main program to start this example.
*/
public static void main (String args[]) {
FailoverProducer fp = new FailoverProducer();
fp.run();
}
}