/*******************************************************************************
$Source: /cvs/repositories/openii3/project/java/source/org/openeai/config/CommandConfig.java,v $
$Revision: 1.16 $
*******************************************************************************/
/**********************************************************************
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.config;
import java.util.HashMap;
import org.jdom.Element;
import org.jdom.Attribute;
import org.openeai.xml.*;
/**
* A CommandConfig is a wrapper class that takes information stored in an
* OpenEAI Deployment document (Command Element) and stores it in a Java object.
* Then the configuration object is passed to the constructor of command implementations
* (both ScheduledCommands and ConsumerCommands) and they are able to configure
* themselves with the information found in the config object.
* <P>
* <B>Configuration Parameters:</B>
* <P>
* These are the configuration parameters specified by the Command
* Element in the Deployment document. NOTE: Like all other OpenEAI configuration
* objects, there is a "container" level associated to Command objects.
* Many Elements and attributes are required at that level and may be optionally
* overridden at this level. This is to avoid having to enter redundant information
* in the Deployment document if all (or most) Command objects being configured should use
* the same configuration information. Therefore, many of the Command configuration
* parameters are optional at this level but required at the "container" level. Where
* this is the case, it will be indicated by an "*".
* <P>
* <TABLE BORDER=2 CELLPADDING=5 CELLSPACING=2>
* <TR>
* <TH>Name</TH>
* <TH>Required</TH>
* <TH>Description</TH>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>CommandName</TD>
* <TD>yes</TD>
* <TD>Name of the Command. The consumer will look at the COMMAND_NAME JMS Property
* associated to each message it consumes and execute the command with that name.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>CommandClass</TD>
* <TD>yes</TD>
* <TD>Fully qualified class name of the Command implementation for the consumer
* to instantiate. The consumer will then execute this instance each time it
* consumes a message that has a COMMAND_NAME JMS Property with this CommandName.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>Configuration</TD>
* <TD>no</TD>
* <TD>The configuration Element that specifies what components this Command will
* have at its disposal. This is the Command's AppConfig object.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>MessagingComponents</TD>
* <TD>no</TD>
* <TD>Other messaging components that this command might need to interact with.
* Typically, this is only needed for infrastructure type gateways, like Routers
* and Proxies that will forward messages to other components in an enterprise.
* This will end up being an AppConfig object for each one of those components
* so this Command may have Producers, Properties, MessageObjects etc.
* set up according to that components needs. It is mostly just a convienient
* way to accomplish this goal re-using existing foundation to configure and
* organize those objects.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>type</TD>
* <TD>yes</TD>
* <TD>The type of command being initialized (Request, Sync or Scheduled)</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>isDefault (true | false)</TD>
* <TD>no (defaults to false)</TD>
* <TD>Signifies that the command being initialized is the "default" command
* to be executed if the message consumed by the consumer does not have the
* COMMAND_NAME JMS Property set on it.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>isAbsolute (true | false)</TD>
* <TD>no (defaults to false)</TD>
* <TD>If true, indicates that the command being initialized is the <B>ONLY</B> command
* that will ever be executed by the consumer no matter what the
* COMMAND_NAME JMS Property set to. It is only appropriate to set this to true
* if the Consumer only executes one command.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>inboundXmlValidation (true | false)</TD>
* <TD>no*</TD>
* <TD>Indicates whether or not this Command should perform XML validation
* on the messages passed to it. This is automatically checked and performed when
* the command uses the initializeInput method to build the Document out of the
* JMS Message passed to it by the Consumer.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>outboundXmlValidation (true | false)</TD>
* <TD>no*</TD>
* <TD>Indicates whether or not this Command should perform XML validation
* on the messages it returns or forwards after it's finished performing the
* business logic associated to the command. This is NOT currently automatically
* performed by any foundation code. It is up to the Command itself to check
* this flag and validate the document itself. This may eventually be put in the
* buildReplyDocument method as a convenience.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>writeToFile (true | false)</TD>
* <TD>no*</TD>
* <TD>Indicates whether or not this Command should serialize the contents
* of the Message passed to it when it builds the XML Document from the message.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>messageDumpDirectory</TD>
* <TD>no</TD>
* <TD>Indicates the directory where the message should be serialized to
* (if writeToFile is true). If no directory is specified, it will default
* to the current directory of the running application (the gateway).</TD>
* </TR>
* </TABLE>
* @author Tod Jackson (tod@openeai.org)
* @author Steve Wheat (steve@openeai.org)
* @version 3.0 - 28 January 2003
*/
public class CommandConfig
extends EnterpriseConfigurationObjectImpl
implements EnterpriseConfigurationObject {
private String m_type = "";
private String m_name = "";
private String m_className = "";
private HashMap m_msgComponents = new HashMap();
private boolean m_default = false;
private boolean m_absolute = false;
//private HashMap m_configs = new HashMap();
private AppConfig m_appConfig = null;
private boolean m_inboundXmlValidation = false;
private boolean m_outboundXmlValidation = false;
private boolean m_writeToFile = false;
private String m_messageDumpDir = "";
private Element m_defaultParms = null;
/**
* This is the constructor used by ConsumerConfig to instantiate the config object.
* Then, ConsumerConfig calls this object's init(Element) method passing the configuration
* element it retrieved from the XML configuration document which this object uses
* to configure itself. After this object has initialized itself,
* it will be used to instantiate and initialize the framework object
* (MessageObject, Producers, Consumers, ThreadPools etc.)
* with the properties it's been initialized with.
*/
public CommandConfig() {
setType("CommandConfig");
}
public CommandConfig(String configDocUrl, String commandName) throws EnterpriseConfigurationObjectException {
setType("CommandConfig");
XmlDocumentReader xmlReader = new XmlDocumentReader();
try {
setConfigDoc(xmlReader.initializeDocument(configDocUrl, getValidation()));
}
catch (XmlDocumentReaderException e) {
String msg = "Error Initializing config document at " + configDocUrl +
" Exception: " + e.getMessage();
logger.fatal(msg);
throw new EnterpriseConfigurationObjectException(msg, e);
}
setName(commandName);
init();
}
public CommandConfig(Element configElement) throws EnterpriseConfigurationObjectException {
setType("CommandConfig");
init(configElement);
}
/**
* Sets the default paramaters associated to this command as specified in the "Commands" Configuration
* Element (the container) in the application's config document.
*<P>
* These default parameters are built from the "container" level configuration component in the config
* document (Commands). This is to allow "default" configuration information to be specified for all Commands
* that exist within this container. If needed a particular Command can override these default parameters. Otherwise
* the default parameters are used. This way, duplicate configuration information does not have to be specified
* for each Command.
*
* @param eDefaultParms Element
*/
public void setDefaultParms(Element eDefaultParms) {
m_defaultParms = eDefaultParms;
}
/**
* Returns the default paramaters associated to this command as specified in the "Commands" Configuration
* Element (the container) in the application's config document.
*<P>
* These default parameters are built from the "container" level configuration component in the config
* document (Commands). This is to allow "default" configuration information to be specified for all Commands
* that exist within this container. If needed a particular Command can override these default parameters. Otherwise
* the default parameters are used. This way, duplicate configuration information does not have to be specified
* for each Command.
*
* @return Element
*/
public Element getDefaultParms() {
return m_defaultParms;
}
/**
* Sets the message dump directory that this command should use to persist incomming messages if
* the "writeToFile" flag is true. This information is obtained from the configuration document
* for this command.
*
* @param dumpDir String
*/
public void setMessageDumpDirectory(String dumpDir) {
m_messageDumpDir = dumpDir;
}
/**
* Returns the message dump directory that this command should use to persist incomming messages if
* the "writeToFile" flag is true.
*
* @return String
*/
public String getMessageDumpDirectory() {
return m_messageDumpDir;
}
/**
* Sets the boolean indicator which will be used to determine whether or not this command should validate the Xml Document
* it creates from the JMS message that it receives. This is specified in the Configuration document
* for the command.
*
* @param validate boolean
*/
public void setInboundXmlValidation(boolean validate) {
m_inboundXmlValidation = validate;
}
/**
* Returns a boolean value that indicates whether or not this command should validate the Xml Document
* it creates from the JMS message that it receives. This is specified in the Configuration document
* for the command.
*
* @return boolean
*/
public boolean getInboundXmlValidation() {
return m_inboundXmlValidation;
}
/**
* Sets a boolean value that indicates if this command should write the incomming messages
* it recieves to the file system. This is specified in the Configuration document
* for the command via the "writeToFile" attribute.
*
* @return boolean
*/
public void setWriteToFile(boolean writeToFile) {
m_writeToFile = writeToFile;
}
/**
* Returns a boolean value that indicates if this command should write the incomming messages
* it recieves to the file system. This is specified in the Configuration document
* for the command via the "writeToFile" attribute.
*
* @return boolean
*/
public boolean writeToFile() {
return m_writeToFile;
}
/**
* Sets an indicator that specifies if this command should validate any Xml Documents
* it publishes or returns to a client. It would publish the message if it's a SyncCommand
* and it would return the message if it's a RequestCommand. This is specified in the Configuration document
* for the command.
*
* @param validate boolean
*/
public void setOutboundXmlValidation(boolean validate) {
m_outboundXmlValidation = validate;
}
/**
* Returns a boolean value that indicates whether or not this command should validate any Xml Documents
* it publishes or returns to a client. It would publish the message if it's an SyncCommand
* and it would return the message if it's an RequestCommand. This is specified in the Configuration document
* for the command.
*
* @return boolean
*/
public boolean getOutboundXmlValidation() {
return m_outboundXmlValidation;
}
/**
* Adds a configuration Element to a HashMap for another Message Component that this command may need to
* know about. Some gateways need to forward Sync or Request messages to other gateways. Typically, these
* are infrastructure type gateways like routers and request proxies. This structure allows those types
* of gateways to store up the configuration for the end points that they need to message with. Then, those
* gateways can treat these 'message component' elements as AppConfig objects for the end points. They can
* know the 'application' configuration for that end-point (like message objects, producers etc.) and use
* that configuration to determine when to message with that end-point and what foundation objects to use
* to do so.
*<P>
*
* @param name String the name of the Messaging Component (end-point)
* @param eComponent Element the configuration Element associated to that end-point. This information can be used
* to build an AppConfig object associated to that end-point.
*/
public void addMsgComponent(String name, Element eComponent) {
m_msgComponents.put(name, eComponent);
}
/**
* Returns a configuration Element associated to a particular end-point by name. This is the "Configuration"
* Element listed in the deployment document for the command being configured.
*
* @param name String the name of the messaging component (end-point)
* @return Element the configuration Element that was stored for that end-point.
*/
public Element getMsgComponent(String name) {
return(Element)m_msgComponents.get(name);
}
/**
* Returns the entire HashMap of configuration Elements for all messaging components that this command
* might need to know about.
*
* @return HashMap the list of Messaging Components that was built based on informatino found in this command's
* configuration document.
*/
public HashMap getMsgComponents() {
return m_msgComponents;
}
/**
* Returns the AppConfig object associated to this command as specified in the Command's Configuration
* Element in the config document.
*
* @return AppConfig
*/
public AppConfig getAppConfig() {
return m_appConfig;
}
/**
* Sets the AppConfig object associated to this command as specified in the Command's Configuration
* Element in the config document.
*
* @param appConfig AppConfig
*/
public void setAppConfig(AppConfig appConfig) {
m_appConfig = appConfig;
}
/**
* Returns a boolean value that indicates if this command is the "default" command the consumer
* instantiating this command should execute if no "COMMAND_NAME" is specified in the JMS Message
* it consumes. This is specified in the Configuration document
* for the command via the "isDefault" attribute.
*
* @return boolean
*/
public boolean isDefault() {
return m_default;
}
/**
* Sets the boolean value that indicates if this command is the "default" command the consumer
* instantiating this command should execute if no "COMMAND_NAME" is specified in the JMS Message
* it consumes. This is specified in the Configuration document
* for the command via the "isDefault" attribute.
*
* @return boolean
*/
public void setDefault(boolean def) {
m_default = def;
}
/**
* Returns a boolean value that indicates if this command is the "absolute" command the consumer
* instantiating this command should execute no matter what "COMMAND_NAME" is specified in the JMS Message
* it consumes. This is specified in the Configuration document
* for the command via the "isAbsolute" attribute.
*
* @return boolean
*/
public boolean isAbsolute() {
return m_absolute;
}
/**
* Sets the boolean value that indicates if this command is the "absolute" command the consumer
* instantiating this command should execute no matter what "COMMAND_NAME" is specified in the JMS Message
* it consumes. This is specified in the Configuration document
* for the command via the "isAbsolute" attribute.
*
* @return boolean
*/
public void setAbsolute(boolean def) {
m_absolute = def;
}
/**
* Sets the type associated to this command. This is specified in the Configuration document
* for the command. Currently, valid values include "syncMessage", "requestMessage" and "scheduled".
*
* @return String
*/
public void setType(String type) {
m_type = type;
}
/**
* Returns type associated to this command. This is specified in the Configuration document
* for the command. Currently, valid values include "syncMessage", "requestMessage" and "scheduled".
*
* @return String
*/
public String getType() {
return m_type;
}
/**
* Sets the name of this command as specified in the configuration document.
*
* @param name String
*/
public void setName(String name) {
m_name = name;
}
/**
* Returns the name of this command as specified in the configuration document.
*
* @return String
*/
public String getName() {
return m_name;
}
/**
* Sets the ClassName associated to this command as specified in the Command's Configuration
* Element in the config document.
*
* @param className String
*/
public void setClassName(String className) {
m_className = className;
}
/**
* Returns the ClassName associated to this command as specified in the Command's Configuration
* Element in the config document.
*
* @return String
*/
public String getClassName() {
return m_className;
}
/**
* Implements the init(Element) method that all EnterpriseConfiguration objects must implement.
* This init method takes the Configuration element passed in and pulls out configuration information
* specific to the Command being initialized. Then it sets various instance variables and properties on itself which will
* be used by the Command when the Consumer or Schedule instantiates it passing this configuration object. The Command
* will then use the configuration java object to initialize itself.
*
* @param eCommand Element the configuration element that AppConfig has pulled from the configuration document
* relevant to the Command being configured. Or, the element that was found in the init() method.
* @throws EnterpriseConfigurationObjectException if errors occur processing the configuration Element.
*/
public void init(Element eCommand) throws EnterpriseConfigurationObjectException {
setName(eCommand.getChild("CommandName").getText());
setClassName(eCommand.getChild("CommandClass").getText());
setType(eCommand.getAttribute("type").getValue());
Attribute aDefault = eCommand.getAttribute("isDefault");
if (aDefault != null) {
setDefault(new Boolean(aDefault.getValue()).booleanValue());
}
else {
setDefault(false);
}
Attribute aAbsolute = eCommand.getAttribute("isAbsolute");
if (aAbsolute != null) {
setAbsolute(new Boolean(aAbsolute.getValue()).booleanValue());
}
else {
setAbsolute(false);
}
Attribute aInboundValidation = eCommand.getAttribute("inboundXmlValidation");
if (aInboundValidation != null) {
setInboundXmlValidation(new Boolean(aInboundValidation.getValue()).booleanValue());
}
else {
// Use default values...
aInboundValidation = getDefaultParms().getAttribute("inboundXmlValidation");
if (aInboundValidation != null) {
setInboundXmlValidation(new Boolean(aInboundValidation.getValue()).booleanValue());
}
else {
setInboundXmlValidation(false);
}
}
Attribute aOutboundValidation = eCommand.getAttribute("outboundXmlValidation");
if (aOutboundValidation != null) {
setOutboundXmlValidation(new Boolean(aOutboundValidation.getValue()).booleanValue());
}
else {
// Use default values...
aOutboundValidation = getDefaultParms().getAttribute("outboundXmlValidation");
if (aOutboundValidation != null) {
setOutboundXmlValidation(new Boolean(aOutboundValidation.getValue()).booleanValue());
}
else {
setOutboundXmlValidation(false);
}
}
Attribute aWriteToFile = eCommand.getAttribute("writeToFile");
if (aWriteToFile != null) {
setWriteToFile(new Boolean(aWriteToFile.getValue()).booleanValue());
}
else {
// Use default values...
aWriteToFile = getDefaultParms().getAttribute("writeToFile");
if (aWriteToFile != null) {
setWriteToFile(new Boolean(aWriteToFile.getValue()).booleanValue());
}
else {
setWriteToFile(false);
}
}
Attribute aMsgDumpDir = eCommand.getAttribute("messageDumpDirectory");
if (aMsgDumpDir != null) {
setMessageDumpDirectory(aMsgDumpDir.getValue());
}
else {
// Use default values...
aMsgDumpDir = getDefaultParms().getAttribute("messageDumpDirectory");
if (aMsgDumpDir != null) {
setMessageDumpDirectory(aMsgDumpDir.getValue());
}
}
logger.debug("Element returned: ");
logger.debug(" - " + eCommand.getName());
logger.debug(" - " + getName());
Element eConfiguration = eCommand.getChild("Configuration");
if (eConfiguration != null) {
AppConfig aConfig = new AppConfig();
aConfig.setName(getName());
aConfig.setAppName(getAppName());
aConfig.init(eConfiguration);
setAppConfig(aConfig);
}
Element eMsgComponents = eCommand.getChild("MessagingComponents");
if (eMsgComponents != null) {
java.util.List lMsgComponents = eMsgComponents.getChildren();
for (int i=0; i<lMsgComponents.size(); i++) {
Element eMsgComponent = (Element)lMsgComponents.get(i); // Applications, MessageGateways etc.
java.util.List lComponents = eMsgComponent.getChildren();
logger.debug(eMsgComponent.getName() + " has " + lComponents.size() + " children.");
for (int j=0; j<lComponents.size(); j++) {
Element eComponent = (Element)lComponents.get(j); // Application, MessageGateway etc.
String id = eComponent.getAttribute("id").getValue();
logger.info("Adding MessageComponent named " + id);
addMsgComponent(id, eComponent);
}
}
}
java.util.List lProps = eCommand.getChildren("Property");
for (int i=0; i<lProps.size(); i++) {
Element eProp = (Element)lProps.get(i);
String key = eProp.getChild("PropertyName").getText();
String value = eProp.getChild("PropertyValue").getText();
addProperty(key, value);
}
}
/**
* Implements the init() method that all EnterpriseConfiguration objects must implement.
* This init method retreives the root element of the confuration document and
* then finds the specific configuration element associated to the Command being configured
* then it calls the init(Element) method which actually initializes the CommandConfig
* with the information found in the configuration element.
*
*/
private void init() throws EnterpriseConfigurationObjectException {
Element rootElement = getConfigDoc().getRootElement();
logger.debug("RootElement is: " + rootElement.getName());
// Find the element specified by producerName in the document
Element configElement = getConfigElementByAttributeValue(getName(), "name");
init(configElement);
}
}