Package org.openeai.jms.consumer.commands

Source Code of org.openeai.jms.consumer.commands.ConsumerCommand

/*******************************************************************************
$Source: /cvs/repositories/openii3/project/java/source/org/openeai/jms/consumer/commands/ConsumerCommand.java,v $
$Revision: 1.12 $
*******************************************************************************/

/**********************************************************************
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.consumer.commands;

import org.openeai.*;
import org.openeai.xml.*;
import org.openeai.config.*;

import org.openeai.moa.*;
import org.openeai.moa.jmsobjects.*;
import org.openeai.moa.objects.resources.*;
import org.openeai.moa.objects.testsuite.*;

import java.util.*;
import java.io.*;
import javax.jms.*;
import org.apache.log4j.*;

import org.jdom.output.XMLOutputter;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Attribute;

/**
* The "default" anscestor of all Commands that are executed by either PubSubConsumer or PointToPointConsumer.
*<P>
* Organizations can add an additional layer between this class and the command implementations they develop
* or they can even eliminate the use of this class altogether.  This class provides many useful convenience
* methods that are commonly needed by all command implementations.  Additional common routines will be added
* to this layer as time goes by...
* <P>
* @author      Tod Jackson (tod@openeai.org)
* @author      Steve Wheat (steve@openeai.org)
* @version     3.0  - 28 January 2003
*<P>
* @see RequestCommandImpl
* @see RequestCommand
* @see SyncCommandImpl
* @see SyncCommand
*/
public class ConsumerCommand extends OpenEaiObject {

  public static Category logger;
  private HashMap m_msgComponents = new HashMap();
  private Vector m_appConfigs = new Vector();
  private AppConfig m_appConfig = new AppConfig();
  private boolean m_inboundXmlValidation = false;
  private boolean m_outboundXmlValidation = false;
  private boolean m_writeToFile = false;
  private String m_messageDumpDir = "";

  protected final static String MESSAGE_ACTION = "messageAction";
  protected final static String MESSAGE_CATEGORY = "messageCategory";
  protected final static String MESSAGE_OBJECT = "messageObject";
  protected final static String MESSAGE_RELEASE = "messageRelease";
  protected final static String MESSAGE_TYPE = "messageType";

  protected final static String CREATE_ACTION = "create";
  protected final static String DELETE_ACTION = "delete";
  protected final static String QUERY_ACTION = "query";
  protected final static String UPDATE_ACTION = "update";

  protected final static String DATA_AREA = "DataArea";
  protected final static String NEW_DATA = "NewData";
  protected final static String DELETE_DATA = "DeleteData";
  protected final static String BASELINE_DATA = "BaselineData";
 
  protected final static String TEST_ID = "TestId";
  protected final static String SENDER = "Sender";
 

  public ConsumerCommand() {
  }

/**
  * Default constructor behavior that will apply to all command implementations.
  * Sets the AppConfig object
  * Sets Xml Validation (inbound and outbound)
  * Determines if this command should write incomming messages to a file and
  * establishes the location to which those files should be written.
  * @param cConfig CommandConfig the CommandConfig Java object that wraps the CommandConfig
  * Element from the deployment document.
  * @throws InstantiationException if errors occur during initialization.
  */
  public ConsumerCommand(CommandConfig cConfig) throws InstantiationException {
    setAppName(cConfig.getAppName());
    setAppConfig(cConfig.getAppConfig());
    setInboundXmlValidation(cConfig.getInboundXmlValidation());
    setOutboundXmlValidation(cConfig.getOutboundXmlValidation());
    setWriteToFile(cConfig.writeToFile());
    setMessageDumpDirectory(cConfig.getMessageDumpDirectory());

    try {
      LoggerConfig lConfig = new LoggerConfig();
      lConfig = (LoggerConfig)getAppConfig().getObjectByType(lConfig.getClass().getName());
      logger = Category.getInstance(getClass().getName().substring(0, getClass().getName().lastIndexOf('.')));
      PropertyConfigurator.configure(lConfig.getProperties());
    }
    catch (Exception e) {
      logger = org.openeai.OpenEaiObject.logger;
    }
  }


  /* ControlArea Convenience methods */

  private String getControlAreaAttributeValue( Document inDoc, String attrName ) {
    Element eControlArea = getControlArea(inDoc.getRootElement());
    if (eControlArea != null) {
      Attribute a = eControlArea.getAttribute( attrName );
      if (a != null) {
        return a.getValue();
      }
    }
    return null;
  }

  /**
  * Returns the value of the 'messageCategory' Attribute from the ControlArea
  * in the Document passed in.  Returns null if the attribute does not exist.
  *<P>
  * @return String the messageCategory value from the ControlArea or null if none exists
  * @param inDoc Document the Document object that was created from the JMS Message
  * passed to the exeucte method of the command being executed.
  **/
  protected String getMessageCategory( Document inDoc ) {
    return getControlAreaAttributeValue( inDoc, MESSAGE_CATEGORY );
  }

  /**
  * Returns the value of the 'messageObject' Attribute from the ControlArea
  * in the Document passed in.  Returns null if the attribute does not exist.
  *<P>
  * @return String the messageObject value from the ControlArea or null if none exists
  * @param inDoc Document the Document object that was created from the JMS Message
  * passed to the exeucte method of the command being executed.
  **/
  protected String getMessageObject( Document inDoc ) {
    return getControlAreaAttributeValue( inDoc, MESSAGE_OBJECT );
  }

  /**
  * Returns the value of the 'messageAction' Attribute from the ControlArea
  * in the Document passed in.  Returns null if the attribute does not exist.
  *<P>
  * @return String the messageAction value from the ControlArea or null if none exists
  * @param inDoc Document the Document object that was created from the JMS Message
  * passed to the exeucte method of the command being executed.
  **/
  protected String getMessageAction( Document inDoc ) {
    return getControlAreaAttributeValue( inDoc, MESSAGE_ACTION );
  }

  /**
  * Returns the value of the 'messageType' Attribute from the ControlArea
  * in the Document passed in.  Returns null if the attribute does not exist.
  *<P>
  * @return String the messageType value from the ControlArea or null if none exists
  * @param inDoc Document the Document object that was created from the JMS Message
  * passed to the exeucte method of the command being executed.
  **/
  protected String getMessageType( Document inDoc ) {
    return getControlAreaAttributeValue( inDoc, MESSAGE_TYPE );
  }

  /**
  * Returns the value of the 'messageRelease' Attribute from the ControlArea
  * in the Document passed in.  Returns null if the attribute does not exist.
  *<P>
  * @return String the messageRelease value from the ControlArea or null if none exists
  * @param inDoc Document the Document object that was created from the JMS Message
  * passed to the exeucte method of the command being executed.
  **/
  protected String getMessageRelease( Document inDoc ) {
    return getControlAreaAttributeValue( inDoc, MESSAGE_RELEASE );
  }

  /* End ControlArea Convenience methods */

  /**
  *  Gets the message body from the JMS message passed in and creates an XML document
  *  from that data.  Also, this method writes the message to a file (as an xml document)
  *  if writeToFile is true, this is established in the Command's constructor.
  *  @param messageNumber int
  * @param aMessage JMS Message
  */
  protected Document initializeInput(int messageNumber, Message aMessage) throws JMSException {
    // Handle Text Message
    TextMessage textMsg = null;
    try {
      textMsg = (TextMessage)aMessage;
    }
    catch (ClassCastException e) {
      logger.fatal(e.getMessage(), e);
      throw new JMSException(e.getMessage());
    }

    // Build an XML Document out of the contents of the message passed in...
    Document inDoc = null;
    try {
      XmlDocumentReader xmlReader = new XmlDocumentReader();
      inDoc = xmlReader.initializeDocument(new ByteArrayInputStream(textMsg.getText().getBytes()), getInboundXmlValidation());
    }
    catch (XmlDocumentReaderException e) {
      logger.fatal("Error creating document from message passed in");
      logger.fatal("Message sent in is: \n" + getMessageBody(inDoc));
      logger.fatal(e.getMessage(), e);
      throw new JMSException(e.getMessage());
    }

    logger.debug("Processing message " + getMessageBody(inDoc));

    if (writeToFile()) {
      // Write the XML Document to a file, using the MessageId as the name
      try {
        writeMessageToFile(inDoc);
      }
      catch (IOException e) {
        logger.fatal("Exception occurred writing message to file.  Exception: " + e.getMessage());
      }
    }

    return inDoc;
  }

/**
  *  Sets the messageDumpDirectory variable that will be the target of the writeMessageToFile call if
  *  the command needs to write the incoming message to a file.
  *  It is called in the from the Command constructor.
  *  @param dumpDir String
  */
  protected void setMessageDumpDirectory(String dumpDir) {
    m_messageDumpDir = dumpDir;
  }
/**
  *  Returns the messageDumpDirectory variable that will be the target of the writeMessageToFile call if
  *  the command needs to write the incoming message to a file.
  *  It is called by the Command if it needs to write the message to file.
  *  @return - String
  */
  protected String getMessageDumpDirectory() {
    return m_messageDumpDir;
  }

/**
  *  Sets the writeToFile variable that will be used by the commands to determine if they should write the message
  *  to a file.
  *  It is called in the from the Command constructor.
  *  @param writeToFile boolean
  */
  protected void setWriteToFile(boolean writeToFile) {
    m_writeToFile = writeToFile;
  }
/**
  *  Returns the writeToFile variable that will be used by the commands to determine if they should write the message
  *  to a file.
  *  It is called by commands to determine if they should write the incoming message to a file.
  *  @return - boolean
  */
  protected boolean writeToFile() {
    return m_writeToFile;
  }

/**
  *  Returns the messageBody that was built during the initializeInput method call.
  *  this will be a 'String' object built from the message body of the JMS message passed in.
  *  @return  String
  */
  public final String getMessageBody(Document inDoc) {
    XMLOutputter xmlOut = new XMLOutputter();
    return xmlOut.outputString(inDoc);
  }

/**
  *  Set AppConfig associated to this command.  It is called in the
  *  constructor of Command.
  *  @param aConfig AppConfig
  */
  protected void setAppConfig(AppConfig aConfig) {
    m_appConfig = aConfig;
  }
/**
  *  Get AppConfig associated to this command.  It is called by commands to get access
  *  to command specific OpenEAI objects like message objects, db connection pools, producers
  *  threadpools, properties etc..
  *  @return  AppConfig
  */
  public final AppConfig getAppConfig() {
    return m_appConfig;
  }

/**
  *  Set inbound xml validation.  This is used to determine whether or not to
  *  validate the xml document as when it's first consumed.  It is called in the
  *  constructor of Command.
  *  @param validate
  */
  protected void setInboundXmlValidation(boolean validate) {
    m_inboundXmlValidation = validate;
  }
/**
  *  Get inbound xml validation.  This is used to determine whether or not to
  *  validate the xml document as when it's first consumed.
  * @return  boolean
  */
  protected boolean getInboundXmlValidation() {
    return m_inboundXmlValidation;
  }

/**
  *  Set outbound xml validation.  This is used to determine whether or not to
  *  validate the xml document before it's returned or routed.  It is called in the
  *  constructor of Command.
  *  @param validate
  */
  protected void setOutboundXmlValidation(boolean validate) {
    m_outboundXmlValidation = validate;
  }
/**
  *  Get outbound xml validation.  This is used to determine whether or not to
  *  validate the xml document before it's returned or routed.  It is called by
  *  commands...
  * @return  boolean
  */
  protected boolean getOutboundXmlValidation() {
    return m_outboundXmlValidation;
  }

  protected void addAppConfig(AppConfig aConfig) {
    m_appConfigs.add(aConfig);
  }
  protected Vector getAppConfigs() {
    return m_appConfigs;
  }

/**
  *  Sets the HashMap that is a list of Messaging Components (gateways) that this command
  *  needs to know about.  This is specifically used by gateways like Routers and Proxies
  *  which need to forward sync or request messages to an end point.  This is a list
  *  of AppConfig objects that correspond to that end point and contains message object,
  *  producers etc. that are needed to route/forward a message to that end point.
  *<P>
  * @param components HashMap a HashMap containing AppConfigs for end points of intrest to this command.
  *<P>
  * @return  void
  */
  public final void setMsgComponents(HashMap components) {
    m_msgComponents = components;
  }
/**
  *  Returns the HashMap that is a list of Messaging Components (gateways) that this command
  *  needs to know about.  This is specifically used by gateways like Routers and Proxies
  *  which need to forward sync or request messages to an end point.  This is a list
  *  of AppConfig objects that correspond to that end point and contains message object,
  *  producers etc. that are needed to route/forward a message to that end point.
  *<P>
  * @return  HashMap a HashMap containing AppConfigs for end points of intrest to this command.
  */
  public final HashMap getMsgComponents() {
    return m_msgComponents;
  }

  private void writeMessageToFile(Document inDoc) throws IOException {
    Element eControlArea = getControlArea(inDoc.getRootElement());
    String msgObject = eControlArea.getAttribute("messageObject").getValue();
    writeMessageToFile(msgObject, inDoc, getMessageDumpDirectory());
  }

/**
  *  Used by decendant commands to serialize a message passed to the command to the file system.
  *  Generally, this method will only be called when the initializeInput method is called and
  *  the JMS Message is initially turned into an XML Document (org.jdom.Document).  However, some
  *  commands may also wish to serialize the document themselves, for example, a Router may wish
  *  to serialize the document after it's modified the content of the message and before it routes it.
  *<P>
  @param msgObject String the name of the message object contained in the message
  *  @param doc Document the XML document being serialize
  *  @param msgDumpDir String the path to which the file should be written.
  */
  protected void writeMessageToFile(String msgObject, Document doc, String msgDumpDir) throws IOException {
    // Write the XML Document to a file, using the MessageId as the name

    // Create the dump directory if it doesn't exist..
    File messageStore = new File(msgDumpDir);
    if (messageStore.exists() == false) {
      messageStore.mkdirs();
    }

    XMLOutputter xmlOut = new XMLOutputter();
    Element eControlArea = getControlArea(doc.getRootElement());
    Element eMessageId = eControlArea.getChild("Sender").getChild("MessageId");
    String senderAppId = eMessageId.getChild("SenderAppId").getText();
    String producerId = eMessageId.getChild("ProducerId").getText();
    String messageSeq = eMessageId.getChild("MessageSeq").getText();
    String fileName = senderAppId + "-" + producerId + "-" + messageSeq + ".xml";
    if (msgDumpDir.lastIndexOf("/") != msgDumpDir.length() - 1) {
      msgDumpDir = msgDumpDir + "/";
    }
    logger.info("Writing message to file: " + msgDumpDir + fileName);
    try {
       xmlOut.output(doc, new FileOutputStream(msgDumpDir + fileName));
    }
    catch (Exception e) {
      String msg = "Error dumping message to a file.  Exception: " + e.getMessage();
      logger.fatal(msg);
      throw new IOException(msg);
    }
  }

  /**
   * Builds a single Error object that can be added to the ArrayList of errors (or for any other reason)
   * to pass to the publishSyncError method.
   *
   * @param errType String error Type  ('application' or 'system')
   * @param errNumber String error Number
   * @param errDescription String error Description
   *
   * @return          org.openeai.moa.objects.Error the error object that gets built.
   */
  protected org.openeai.moa.objects.resources.Error buildError(String errType, String errNumber, String errDescription) {
    org.openeai.moa.objects.resources.Error anError =
      new org.openeai.moa.objects.resources.Error();
    anError.setType(errType);
    anError.setErrorNumber(errNumber);
    anError.setErrorDescription(errDescription);
    return anError;
  }

  protected String convertToString(Document doc) throws IOException {
    XMLOutputter xmlOut = new XMLOutputter();
    ByteArrayOutputStream bArray = new ByteArrayOutputStream();
    xmlOut.output(doc, bArray);
    return new String(bArray.toByteArray());
  }

  /**
  * Takes the release number passed in which is generally pulled from a message
  * passed to a command and converts it into a release number that can be used
  * for naming conventions in configuration documents.  Since gateways have to be
  * able to support multiple versions of a message object, it is sometimes helpful
  * to adopt a naming convention to name these objects.  Then, a ConsumerCommand implementation
  * can take the release from the message and convert it into the release used to
  * name an object in order to retrieve that object from an AppConfig.
  * <P>
  * For example, the messageRelease attribute in the message consumed is "1.0", this
  * method will convert that to "v1_0" which is a common naming convention that's been
  * used by many of the OpenEAI reference implementation applications/gateways.  The
  * gateway has a message object with this release appended to its name in its
  * configuration document.  For example, "BasicPerson.v1_0".  Then, the command
  * can retrieve message objects from its AppConfig without having to hard code any
  * names etc. instead, it can rely on the contents of the message and use that information
  * to derive the necessary name.
  * <P>
  * @param release String the messageRelease pulled from the message (e.g. - 1.0, 2.0 etc.)
  * @return String the converted release (e.g. - v1_0, v2_0 etc.) that can be used
  * to pull the object from the commands AppConfig.
  **/
  public final String generateRelease(String release) {
    if (release != null) {
      return "v" + release.replace('.', '_');
    }
    else {
      return null;
    }
  }

  /**
   * This method looks at the document and returns the appropriate ControlArea.
   * Since there can be three different control areas based on the message
   * (ControlAreaRequest, ControlAreaReply and ControlAreaSync) we need to have
   * some intelligence built in when retrieving the element from the document.
   * Therefore, command implementations can just call this method and get a ControlArea
   * element based on the type of message being processed without having to make
   * assumptions regarding the type of message it's processing and without performing
   * this logic themselves.
   *
   * @param root  org.jdom.Element the root element of the document
   *
   * @return          Element the ControlArea element (may be ControlAreaRequest,
   *                  ControlAreaReply or ControlAreaSync depending on the doc)
   */
  protected Element getControlArea(Element root) {
    java.util.List cList = root.getChildren();
    Element retElem = null;
    for (int i=0; i<cList.size(); i++) {
      Element current = (Element)cList.get(i);
      if (current.getName().indexOf("ControlArea") != -1) {
        retElem = current;
      }
    }
    return retElem;
  }
 
  /**
   * Returns the test ID extracted from the supplied document.  This TestId will
   * be made part of any sync messages published as a result of a Request action
   * being performed.
   * <P>
   * This data is then used by the OpenEAI TestSuite Application to correlate
   * the Sync message published to the Request message that precipitated the
   * Sync message and verify that the appropriate Sync message is published.
   * <P>
   * @param testIdObjectName the name of the TestId object as specified in this
   * Command's AppConfig (Configuration Element).
   * @param eControlArea the Control Area element from which to extract a test ID.
   **/
  protected TestId extractTestId( String testIdObjectName, Element eControlArea ) {
    Element eTestId = eControlArea.getChild( SENDER ).getChild( TEST_ID );
    TestId testId = null;
    try {
      testId = (TestId) getAppConfig().getObject( testIdObjectName );
    }
    catch (Exception e) {
      // ignore this exception
      logger.debug(e.getMessage(), e);
    }
    if (eTestId != null && testId != null) {
      try {
          testId.buildObjectFromInput( eTestId );
          logger.debug( "extractTestId found test ID " + testId );
      }
      catch (Exception e) {
          logger.warn( "Could not build the TestId object from the TestId Element in the ControlArea.  Ignoring this." );
      }
    }
    else {
      logger.debug( "Could not find the TestId Element in the ControlArea.  Ignoring this." );
    }
    return testId;
  }

  /**
  *
  **/
  public void shutdown() throws CommandException {
    try {
      logger.info(getAppConfig().getName() + " shutting myself down.");
      getAppConfig().shutdown();
      for (int i=0; i<getAppConfigs().size(); i++) {
        AppConfig a = (AppConfig)getAppConfigs().get(i);
        logger.info(a.getName() + " shutting myself down.");
        a.shutdown();
      }
    }
    catch (Exception e) {
      throw new CommandException(e.getMessage(), e);
    }
  }
}
TOP

Related Classes of org.openeai.jms.consumer.commands.ConsumerCommand

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.