/*******************************************************************************
$Source: /cvs/repositories/openii3/project/java/source/org/openeai/jms/producer/PointToPointProducer.java,v $
$Revision: 1.24 $
*******************************************************************************/
/**********************************************************************
This file is part of the OpenEAI Application Foundation or
OpenEAI Message Object API created by Tod Jackson
(tod@openeai.org) and Steve Wheat (steve@openeai.org) at
the University of Illinois Urbana-Champaign.
Copyright (C) 2002 The OpenEAI Software Foundation
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For specific licensing details and examples of how this software
can be used to build commercial integration software or to implement
integrations for your enterprise, visit http://www.OpenEai.org/licensing.
*/
package org.openeai.jms.producer;
// JNDI Stuff
import javax.naming.*;
import javax.naming.directory.*;
// Java Messaging Service
import javax.jms.*;
import javax.jms.Queue;
// General
import java.io.*;
import java.util.*;
// JDOM
import org.jdom.Document;
import org.jdom.output.XMLOutputter;
import org.openeai.config.*;
import org.openeai.moa.ActionableEnterpriseObject;
import org.openeai.moa.XmlEnterpriseObject;
import org.openeai.transport.RequestService;
import org.openeai.transport.ProducerId;
import org.openeai.transport.TransportException;
import org.openeai.xml.XmlDocumentReader;
import org.openeai.xml.XmlDocumentReaderException;
/**
* The PointToPointProducer produces messages to a Queue. If the method being called
* to produce the message is 'produceRequest' the Producer will use the QueueRequestor object
* to produce the message and wait for a response from the consuming application. If the method
* called is 'produceMessage' it will not wait for a response.
* <P>
* @author Tod Jackson (tod@openeai.org)
* @author Steve Wheat (steve@openeai.org)
* @version 3.0 - 4 February 2003
* @see PubSubProducer
* @see org.openeai.jms.consumer.PointToPointConsumer
*/
public class PointToPointProducer
extends MessageProducer implements RequestService {
private QueueConnectionFactory m_qcf = null;
private Queue m_queue = null;
private QueueConnection m_queueConnection;
private QueueSession m_queueSession;
private QueueSender m_queueSender;
private org.openeai.jms.producer.QueueRequestor m_queueRequestor;
private boolean m_monitorRunning = false;
private int m_tempQueuePoolSize = 0;
private int m_requestTimeoutInterval = 0;
private int m_defaultTimeoutInterval = 10000; // Default (10 seconds), eventually, this will be
// configurable via the Producer creating this requestor
// and it's ProducerConfig. Currently, it can be set by
// an application making a request if they know the resposne
// time is going to be more than ten seconds.
public PointToPointProducer() {
setAppName("Point2Point Producer v1.0");
}
/**
* As AppConfig reads through an application's deployment document, it will build a
* ProducerConfig Java object and pass that object to this constructor. Then
* this producer will have all the information it needs to initialize itself which.
* <P>
* @param pConfig org.openeai.config.ProducerConfig
* @see org.openeai.config.ProducerConfig
* @see org.openeai.jms.producer.PubSubProducer
**/
public PointToPointProducer(ProducerConfig pConfig) throws IOException, JMSException {
setAppName("Point2Point Producer v1.0");
init(pConfig.getProperties());
if (getStartOnInitialization()) {
startProducer();
}
}
/**
* Invokes MessageProducer.init(Properties). Additionally, since this is a PointToPointProducer
* it sets the default "request timeout interval" and the TempPoolSize based on
* information found in the deployment document for this Producer.
* <P>
* @param props Properties
* @throws IOException
* @see MessageProducer#init(Properties)
**/
protected void init(Properties props) throws IOException {
super.init(props);
setRequestTimeoutInterval(getDefaultTimeoutInterval()); // set default timeout interval.
setTempQueuePoolSize(Integer.parseInt(props.getProperty("tempQueuePoolSize", "5")));
Runtime.getRuntime().addShutdownHook(new ProducerShutdownHook());
}
// StartGetter/Setters
private int getTempQueuePoolSize() {
return m_tempQueuePoolSize;
}
private void setTempQueuePoolSize(int size) {
m_tempQueuePoolSize = size;
}
private int getDefaultTimeoutInterval() {
return m_defaultTimeoutInterval;
}
private void setDefaultTimeoutInterval(int timeout) {
m_defaultTimeoutInterval = timeout;
}
/**
* Returns the request timeout interval that will be used by this producer to determine
* when a timeout occurrs. The default value is 10000 or 10 seconds. This is how
* long the producer will wait on a response to a request it makes. If the response
* takes longer than this, it will catch a 'Timeout' exception from the QueueRequestor
* and try the request again. If the second attempt fails, it will throw a JMSException that
* will be caught by the requesting application.
*
* @return int timeout interval in milliseconds.
*
*/
public final int getRequestTimeoutInterval() {
return m_requestTimeoutInterval;
}
/**
* Sets the request timeout interval that will be used by this producer to determine
* when a timeout occurrs. The default value is 10000 or 10 seconds. This is how
* long the producer will wait on a response to a request it makes. If the response
* takes longer than this, it will catch a 'Timeout' exception from the QueueRequestor
* and try the request again. If the second attempt fails, it will throw a JMSException that
* will be caught by the requesting application. This method can be called at runtime prior to sending
* a request if an application needs to use something larger than the default.
*
* @param timeout int timeout interval in milliseconds.
*
*/
public final void setRequestTimeoutInterval(int timeout) {
m_requestTimeoutInterval = timeout;
}
/**
* Returns the Producers's QueueConnectionFactory object.
* <P>
* See the JMS Specification to learn more about JMS objects.
* <P>
* @return javax.jms.QueueConnectionFactory
**/
public final QueueConnectionFactory getQueueConnectionFactory() {
return m_qcf;
}
/**
* Sets the Producers's QueueConnectionFactory object.
* <P>
* See the JMS Specification to learn more about JMS objects.
* <P>
* @param qcf javax.jms.QueueConnectionFactory
**/
public final void setQueueConnectionFactory(QueueConnectionFactory qcf) {
m_qcf = qcf;
}
/**
* Returns the Producers's Queue object.
* <P>
* See the JMS Specification to learn more about JMS objects.
* <P>
* @return javax.jms.Queue
**/
public final Queue getQueue() {
return m_queue;
}
/**
* Sets the Producers's Queue object.
* <P>
* See the JMS Specification to learn more about JMS objects.
* <P>
* @param queue javax.jms.Queue
**/
public final void setQueue(Queue queue) {
m_queue = queue;
}
/**
* Returns the Producers's QueueConnection object.
* <P>
* See the JMS Specification to learn more about JMS objects.
* <P>
* @return javax.jms.QueueConnection
**/
public final QueueConnection getQueueConnection() {
return m_queueConnection;
}
/**
* Sets the Producers's QueueConnection object.
* <P>
* See the JMS Specification to learn more about JMS objects.
* <P>
* @param queueConnection javax.jms.QueueConnection
**/
public final void setQueueConnection(QueueConnection queueConnection) {
m_queueConnection = queueConnection;
}
/**
* Returns the Producers's QueueSession object.
* <P>
* See the JMS Specification to learn more about JMS objects.
* <P>
* @return javax.jms.QueueSession
**/
public final QueueSession getQueueSession() {
return m_queueSession;
}
/**
* Sets the Producers's QueueSession object.
* <P>
* See the JMS Specification to learn more about JMS objects.
* <P>
* @param session javax.jms.QueueSession
**/
public final void setQueueSession(QueueSession session) {
m_queueSession = session;
}
/**
* Returns the Producers's QueueSender object.
* <P>
* See the JMS Specification to learn more about JMS objects.
* <P>
* @return javax.jms.QueueSender
**/
public final QueueSender getQueueSender() {
return m_queueSender;
}
/**
* Sets the Producers's QueueSender object.
* <P>
* See the JMS Specification to learn more about JMS objects.
* <P>
* @param queueSender javax.jms.QueueSender
**/
public final void setQueueSender(QueueSender queueSender) {
m_queueSender = queueSender;
}
/**
* Returns the Producers's QueueRequestor object.
* <P>
* See the JMS Specification to learn more about JMS objects.
* <P>
* @return org.openeai.jms.QueueRequestor
* @see org.openeai.jms.producer.QueueRequestor
**/
public final org.openeai.jms.producer.QueueRequestor getQueueRequestor() {
return m_queueRequestor;
}
/**
* Sets the Producers's QueueRequestor object.
* <P>
* See the JMS Specification to learn more about JMS objects.
* <P>
* @param queueRequestor org.openeai.jms.producer.QueueRequestor
* @see org.openeai.jms.producer.QueueRequestor
**/
public final void setQueueRequestor(org.openeai.jms.producer.QueueRequestor queueRequestor) {
m_queueRequestor = queueRequestor;
}
// End Getter/Setters
/**
* This method stops the Producer's "Monitor Thread" so it won't attempt
* to restart the producer.
* <P>
* When the producer is started it starts a Thread that monitors the Producer's
* connection to the broker. If that connection is broken for some reason, that
* "Monitor Thread" will attempt to restart the producer. This continues indefinitely
* until the producer is able to re-connect to the broker.
* <P>
* This method allows an application to in effect stop that monitor thread so they can
* shut the producer down without it restarting itself.
**/
public void stopMonitor() {
m_monitorRunning = false;
}
/**
* This method starts the Producer's "Monitor Thread". This is a thread that runs
* for the life of the producer and checks the status of the producer's connection
* to the broker every thirty seconds. If that connection is broken
* for some reason, the Monitor Thread will attempt to restart the producer,
* re-connecting it to the broker. It will continue to do this until either the
* producer is able to re-connect or the producer is shutdown.
**/
public void startMonitor() {
if (m_monitorRunning == false) {
MonitorProducer monitorProducer = new MonitorProducer(30000);
new Thread(monitorProducer).start();
m_monitorRunning = true;
}
}
public final void stop() {
stopProducer();
}
/**
* Attempts to cleanly shutdown the Producer. This includes closing all JMS
* resources (QueueRequestor, QueueSession and QueueConnection). If errors
* occur, it will log those errors as warnings. However, regardless of the
* outcome of the "clean" shutdown attempt, the producer will be stopped. This
* method is called anytime the producer detects connection problems to the broker
* or when specifically called from an application or gateway using this Producer.
* <P>
* @see MonitorProducer
**/
public final void stopProducer() {
boolean exceptionOccurred = false;
setProducerStatus(STOPPING);
stopMonitor();
try {
if (m_queueRequestor != null) {
m_queueRequestor.close();
}
}
catch (Exception jmse) {
exceptionOccurred = true;
logger.warn("Error closing QueueRequestot: " + jmse.getMessage());
}
try {
if (m_queueSession != null) {
m_queueSession.close();
}
}
catch (Exception jmse) {
exceptionOccurred = true;
logger.warn("Error closing QueueSession: " + jmse.getMessage());
}
try {
if (m_queueConnection != null) {
m_queueConnection.close();
}
}
catch (Exception jmse) {
exceptionOccurred = true;
logger.warn("Error closing QueueConnection: " + jmse.getMessage());
}
if (exceptionOccurred) {
logger.info("Everything was stopped but there were exceptions.");
}
else {
logger.info("Everything was stopped successfully!");
}
setProducerStatus(STOPPED);
}
public final boolean start() throws JMSException {
return startProducer();
}
/**
* Starts the producer making it ready to produce messages to the Queue that
* it connects to. This follows the typical JMS pattern of starting a message producer.
* This includes:
* <ul>
* <li>Retrieving the JMS Administered objects (QueueConnectionFactory and Queue)
* from a directory server or other JNDI source
* <li>Creating a QueueConnection with the QueueConnectionFactory
* <li>Creating a QueueSession with the QueueConnection
* <li>Creating a QueueRequestor with the QueueSession, Queue and TemporaryQueuePoolSize
* specified in the deployment document
* </ul>
* <P>
* @return boolean indicating whether or not the start was successful.
* @throws JMSException
* @see PubSubProducer#startPublisher
* @see org.openeai.jms.producer.QueueRequestor
**/
public boolean startProducer() throws JMSException {
setProducerStatus(STOPPED);
logger.info("I'm the " + getProducerName() + " JMS Point 2 Point Producer");
if (getProducerId(null) == null) {
try {
logger.debug("Getting a ProducerId object...");
setProducerId(new ProducerId(getProducerIdUrl()));
logger.debug("Producer id is " + getProducerId(null).getId());
}
catch (IOException ioe) {
logger.fatal(ioe.getMessage(), ioe);
throw new JMSException(ioe.getMessage());
}
}
if (m_qcf == null || m_queue == null) {
// Create InitialContext object
DirContext ic = null;
// Assume the m_providerUrl and m_initCtxFactory variables have already
// been set.
try {
ic = getInitialContext();
if (ic == null) {
logger.fatal("Error creating initial context");
return false;
}
logger.debug("Created initial context");
}
catch (NamingException ne) {
logger.fatal(ne.getMessage(), ne);
throw new JMSException(ne.getMessage());
}
if (getConnectionFactoryName() == null || getDestinationName() == null ||
getProviderUrl() == null || getInitialContextFactory() == null) {
logger.fatal("Nothing's been initialized, can't start.");
return false;
}
try {
// Lookup QueueConnectionFactory and Queue names
logger.debug("Looking up queue connection factory name " + getConnectionFactoryName());
m_qcf = (QueueConnectionFactory)ic.lookup(getConnectionFactoryName());
logger.debug("QueueConnectionFactory Class " + m_qcf.getClass().getName());
logger.debug("Looking up queue name " + getDestinationName());
m_queue = (Queue)ic.lookup(getDestinationName());
logger.debug("Queue Class " + m_queue.getClass().getName());
// Close InitialContext resources
ic.close();
logger.debug("Closed the InitialContext...");
}
catch (NamingException ne) {
logger.fatal(ne.getMessage(), ne);
throw new JMSException(ne.getMessage());
}
catch (ClassCastException ce) {
logger.fatal(ce.getMessage(), ce);
throw new JMSException(ce.getMessage());
}
catch (Exception e) {
logger.fatal(e.getMessage(), e);
throw new JMSException(e.getMessage());
}
}
else {
logger.info("No need to create QCF or Queue.");
}
try {
// create QueueConnection
logger.debug("Creating Queue Connection");
if (getUserName() == null || getUserName().length() < 1) {
m_queueConnection = m_qcf.createQueueConnection();
}
else {
m_queueConnection = m_qcf.createQueueConnection(getUserName(), getPassword());
}
logger.debug("Created Queue Connection");
// create Queue Session, Queue Sender and Queue Requestor
m_queueSession = m_queueConnection.createQueueSession(getTransacted(), QueueSession.AUTO_ACKNOWLEDGE);
logger.debug("Created Queue Session");
m_queueRequestor = new org.openeai.jms.producer.QueueRequestor(m_queueSession, m_queue);
m_queueRequestor.setTempQueuePool(new TempQueuePool(getTempQueuePoolSize(), m_queueSession));
logger.debug("Created Queue Requestor");
m_queueConnection.start();
setProducerStatus(STARTED);
logger.info(getProducerName() + " - Point 2 Point Producer Started successfully.");
}
catch (JMSException jmse) {
logger.fatal(jmse.getMessage(), jmse);
logger.fatal("Username: " + getUserName() + " Password: " + getPassword());
throw jmse;
}
catch (Exception e) {
logger.fatal(e.getMessage(), e);
throw new JMSException(e.getMessage());
}
// Start the monitor if it isn't already running.
startMonitor();
return true;
}
/**
* Convenience method that allows calling applications to use this producer to
* create a JMS TextMessage that is used during message production. This is used
* most commonly by the OpenEAI Message Object API (MOA) foundation.
* <P>
* @return a JMS TextMessage
**/
public final TextMessage createTextMessage() {
try {
logger.debug("[PointToPointProducer] Returning TextMessage");
return m_queueSession.createTextMessage();
}
catch (JMSException jmse) {
String errMessage = "Error creating a TextMessage in the PointToPointProducer. Exception: " + jmse.getMessage();
logger.fatal(errMessage);
}
return null;
}
public XmlEnterpriseObject create(ActionableEnterpriseObject theObject)
throws TransportException {
try {
return theObject.create(this);
}
catch (Exception e) {
String errMessage = "Error processing the create request for object " +
theObject.getClass().getName() + " Exception: " + e.getMessage();
throw new TransportException(errMessage, e);
}
}
public XmlEnterpriseObject update(ActionableEnterpriseObject theObject)
throws TransportException {
try {
return theObject.update(this);
}
catch (Exception e) {
String errMessage = "Error processing the update request for object " +
theObject.getClass().getName() + " Exception: " + e.getMessage();
throw new TransportException(errMessage, e);
}
}
public XmlEnterpriseObject delete(String deleteAction, ActionableEnterpriseObject theObject)
throws TransportException {
try {
return theObject.delete(deleteAction, this);
}
catch (Exception e) {
String errMessage = "Error processing the delete request for object " +
theObject.getClass().getName() + " Exception: " + e.getMessage();
throw new TransportException(errMessage, e);
}
}
public java.util.List query(XmlEnterpriseObject keyObject, ActionableEnterpriseObject theObject)
throws TransportException {
try {
return theObject.query(keyObject, this);
}
catch (Exception e) {
String errMessage = "Error processing the query request for object " +
theObject.getClass().getName() + " Exception: " + e.getMessage();
throw new TransportException(errMessage, e);
}
}
public java.util.List generate(XmlEnterpriseObject keyObject, ActionableEnterpriseObject theObject)
throws TransportException {
try {
return theObject.query(keyObject, this);
}
catch (Exception e) {
String errMessage = "Error processing the generate request for object " +
theObject.getClass().getName() + " Exception: " + e.getMessage();
throw new TransportException(errMessage, e);
}
}
/**
* Creates a QueueSender and produces the message passed in to the Queue the producer
* is connected to. Does not wait for any response from the consumer of that message.
* <P>
* @param aMessage javax.jms.Message the message to produce
* @throws JMSException if errors occur.
* @deprecated As of OpenEAI version 4.0
**/
public final synchronized void produceMessage(Message aMessage) throws JMSException {
try {
logger.debug("ProduceMessage, started processing.");
logger.debug("Creating Queue Sender");
QueueSender queueSender = m_queueSession.createSender(m_queue);
logger.debug("Created Queue Sender");
if (getDeliveryMode().equals(PERSISTENT_DELIVERY)) {
queueSender.send(aMessage, javax.jms.DeliveryMode.PERSISTENT, 9, 0);
}
else {
queueSender.send(aMessage, javax.jms.DeliveryMode.NON_PERSISTENT, 9, 0);
}
logger.debug("Published message through " + m_queue.getQueueName());
logger.debug("ProduceMessage, finished processing.");
}
catch (Exception e) {
logger.fatal(e.getMessage(), e);
throw new JMSException(e.getMessage());
}
}
/**
* Uses the pre-started QueueRequestor to send a request to a consumer and wait
* for a response. If a JMSException occurs producing the request
* it will attempt to restart the Producer and try to send the message again.
* This typically occurs when there have been critical network issues and the
* Producer's Monitor has not restarted it yet.
* <P>
* @param aMessage javax.jms.Message the message to send in the request
* @return javax.jms.Message the response from the consumer that processed the request
* @throws JMSException if errors occur and the producer can't successfully restart itself
* and re-send the message.
**/
public final Message produceRequest(Message aMessage) throws JMSException {
// A 'request' implies a reply so, we'll use a QueueRequestor (OpenEAI Version)
// which sets the 'JMSReplyTo' property to a TemporaryQueue that it's created
// The consumer of the request should check for a ReplyTo Queue and send the
// response to that queue. The QueueRequestor will wait for a response on
// that TemporaryQueue.
Message response = null;
try {
logger.debug("ProduceRequest, started processing...");
aMessage.setJMSDeliveryMode(javax.jms.DeliveryMode.PERSISTENT);
m_queueRequestor.setTimeoutInterval(getRequestTimeoutInterval());
logger.debug("[PointToPointProducer] Sending request");
response = m_queueRequestor.request(aMessage); // Wait for a response
logger.debug("[PointToPointProducer] Got a response");
incrementMessageSequence();
logger.debug("ProduceRequest, finished processing.");
}
catch (JMSException jmse) {
// Attempt to reconnect and try the request again
logger.warn("Error producing requests: " + jmse.getMessage() +
" attempting to restart producer and re-send the request.",
jmse);
try {
stopProducer();
startProducer();
logger.info("Producer was re-started successfully, attempting to re-send the message.");
logger.debug("Sending request");
response = m_queueRequestor.request(aMessage); // Wait for a response
incrementMessageSequence();
logger.debug("Got a response");
}
catch (Exception e) {
String errMessage = "Attempt to restart the producer failed. Exception: " + e.getMessage();
logger.fatal(errMessage);
throw new JMSException(errMessage);
}
}
catch (Exception e) {
logger.fatal("Exception occurred while attempting to produce the request. Exception: " + e.getMessage());
logger.fatal(e.getMessage(), e);
// TextMessage tMsg = (TextMessage)aMessage;
throw new JMSException(e.getMessage());
}
return response;
}
/**
* Uses the pre-started QueueRequestor to send a request to a consumer and wait
* for a response. If a JMSException occurs producing the request
* it will attempt to restart the Producer and try to send the message again.
* This typically occurs when there have been critical network issues and the
* Producer's Monitor has not restarted it yet.
* <P>
* @param theObject an ActionableEnterpriseObject that the action is being performed on
* @param doc the Document that was built from the content of the object
* @return Document the response from the consumer that processed the request
* @throws TransportException if errors occur and the producer can't successfully restart itself
* and re-send the message.
**/
public final Document produceRequest(ActionableEnterpriseObject theObject, Document doc)
throws TransportException {
// A 'request' implies a reply so, we'll use a QueueRequestor (OpenEAI Version)
// which sets the 'JMSReplyTo' property to a TemporaryQueue that it's created
// The consumer of the request should check for a ReplyTo Queue and send the
// response to that queue. The QueueRequestor will wait for a response on
// that TemporaryQueue.
Document responseDoc = null;
TextMessage outMessage = createTextMessage();
XMLOutputter xmlOut = new XMLOutputter();
String requestBody = xmlOut.outputString(doc);
logger.debug("Producing Request:\n" + requestBody);
try {
outMessage.setText(requestBody);
outMessage.setStringProperty(MessageProducer.COMMAND_NAME, theObject.getCommandName());
outMessage.setStringProperty(MessageProducer.MESSAGE_NAME, theObject.getCommandName()); // backward compatibility
outMessage.setStringProperty(MessageProducer.MESSAGE_ID, theObject.getMessageId().toString());
TextMessage responseMessage = (TextMessage)produceRequest(outMessage);
String responseText = responseMessage.getText();
logger.debug("Got response:\n" + responseText);
try {
XmlDocumentReader xmlReader = new XmlDocumentReader();
responseDoc = xmlReader.initializeDocument(new ByteArrayInputStream(responseText.getBytes()), theObject.getValidation());
}
catch (XmlDocumentReaderException e) {
logger.fatal("Error parsing Standard Response document. Contents: " + responseText);
throw new TransportException("Standard Response document is not valid! Exception: " + e.getMessage(), e);
}
}
catch (JMSException e) {
throw new TransportException(e.getMessage(), e);
}
return responseDoc;
}
/**
* This Thread will sleep for 30 seconds and then wake up
* and check the status of the producer by attempting to create/delete a TemporaryQueue.
* If the creation of the TemporaryQueue fails, it assumes there is something wrong
* with the producer's connection to the broker and it will therefore not be able to produce
* any messages. When that happens, it attempts to do a "clean" shutdown on the producer and
* then restarts the producer which will re-establish its connection to the broker
* and it will be able to produce messages again. This means, if we have to take down
* a broker for any reason (on purpose or not), we will NOT have to restart all our
* "long running" producers when the broker comes back up, rather, they will do that themselves.
* <P>
* The thread is started when the producer is started the first time and continues
* this process for the life of the producer.
* <P>
* @author Tod Jackson
*/
protected class MonitorProducer implements java.lang.Runnable {
private int m_sleepInterval = 30000; // thirty seconds
public MonitorProducer(int sleepInterval) {
m_sleepInterval = sleepInterval;
}
private void restartProducer() {
if (getProducerStatus().equalsIgnoreCase(STOPPING) == false) {
stopProducer();
try {
startProducer();
}
catch (Exception e1) {
logger.fatal("Error restarting producer. Exception: " + e1.getMessage());
}
}
else {
logger.info("Producer " + getProducerName() + " is in the process of being restarted, can't restart it in the MonitorProducer thread now.");
}
}
public void run() {
// sleep for m_sleepInterval
// wake up, try to do something with the session
// if an exception occurs, restart the consumer
boolean stayAlive = true;
while(stayAlive) {
try {
Thread.sleep(m_sleepInterval);
}
catch (Exception e) {
logger.fatal("Error sleeping...");
}
// wake up and try to access the session
if (m_monitorRunning == false) {
logger.info("Monitor has been stopped. Returning from Monitor Thread.");
return;
}
try {
if (m_queueSession != null) {
TemporaryQueue tq = m_queueSession.createTemporaryQueue();
tq.delete();
logger.debug("Session is okay.");
}
else {
logger.warn("Session is null, need to restart the " + getProducerName() + " producer.");
restartProducer();
}
}
catch(JMSException e) {
logger.warn("Session is not usable, need to restart the " + getProducerName() + " producer. Exception: " + e.getMessage());
restartProducer();
}
}
}
}
/**
* This Thread will be started when the producer receives a shutdown signal from the os.
* It is established via the Runtime.getRuntime().addShutdownHook(new ProducerShutdownHook());
* in the init() method. The purpose of this is to allow a "clean" shutdown of the producer.
* <P>
* @author Tod Jackson
*/
protected class ProducerShutdownHook extends Thread {
public void run() {
logger.info(getProducerName() + " - Producer shutdown hook, stopping producer");
m_monitorRunning = false;
stopProducer();
logger.info(getProducerName() + " - Producer shutdown hook, producer stopped, now exiting.");
}
}
}