Package org.openeai.jms.producer

Source Code of org.openeai.jms.producer.PointToPointProducer$ProducerShutdownHook

/*******************************************************************************
$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.");
    }
  }
}
TOP

Related Classes of org.openeai.jms.producer.PointToPointProducer$ProducerShutdownHook

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.