Package org.openeai.config

Source Code of org.openeai.config.AppConfig

/*******************************************************************************
$Source: /cvs/repositories/openii3/project/java/source/org/openeai/config/AppConfig.java,v $
$Revision: 1.35 $
*******************************************************************************/

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

import java.lang.reflect.*;

import java.util.*;

import javax.naming.*;
import javax.naming.directory.*;

import com.sun.jndi.ldap.*;

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

import org.openeai.*;
import org.openeai.threadpool.*;
import org.openeai.xml.*;
import org.openeai.jms.producer.*;
import org.openeai.jms.consumer.*;
import org.openeai.dbpool.EnterpriseConnectionPool;
import org.openeai.moa.*;

/**
* The AppConfig class acts as a container for all pre-configured object that an
* application may use.  It reads an application's config XML document, instantiates
* the objects contained in that document and configures them according to the
* information found in the document.  Then, those objects are available to the application
* via the getObject, getObjectByType or getObjectsLike methods.
* <P>
* The config document can be stored in several different places which include: file system,
* web server or directory server.  Typically, an application instantiates app config
* using a properties file that contains all the properties AppConfig needs to find
* the configuration document and configure the application listed in the properties file.
*<P>
* Currently, an AppConfig is associated to these distinct types of applications:
* <ul>
* <li>A runnable class like MessageConsumerClient or GenericAppRunner
* <li>A Servlet
* <li>A ScheduledCommand implementation
* <li>A Command implementation
* </ul>
*
* <P>
* <B>Configuration Parameters:</B>
* <P>
* These are the configuration parameters that may exist in an application's
* property file.
* <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>instanceName</TD>
* <TD>no, unless a gateway is being started</TD>
* <TD>For gateways, this property is used by PubSubConsumers to establish
* their durable subscriptions.  This should be reflective of where the
* gateway is physically running (machine name etc.)</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>providerUrl</TD>
* <TD>yes</TD>
* <TD>Indicates where the config doc is located.
* If the protocol specified is "ldaps" AppConfig will use SSL to connect to the
* directory server.  It does this by using JSSE.  Other protocols that can be
* specified include http:, https: and file:.  A local file system path can
* also be specified like "/usr/configs/ConfigDoc.xml" or "c:/user/configs/ConfigDoc.xml".</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>initialContextFactory</TD>
* <TD>no, unless the providerUrl is ldap/ldaps</TD>
* <TD>The initialContextFactory property indicates how AppConfig is to connect
* to the store (only applies to directory server connection)</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>securityPrincipal</TD>
* <TD>no, unless the providerUrl is ldap/ldaps</TD>
* <TD>The securityPrincipal and securityCredentials are directory server credentials
* used to connect to the providerUrl in the directory server.  This is only related
* to configuration documents stored in a directory server.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>securityCredentials</TD>
* <TD>no, unless the providerUrl is ldap/ldaps</TD>
* <TD>The securityPrincipal and securityCredentials are directory server credentials
* used to connect to the providerUrl in the directory server.  This is only related
* to configuration documents stored in a directory server.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>configDocName</TD>
* <TD>no, unless the providerUrl is ldap/ldaps</TD>
* <TD>name of the object as it's stored in the directory server.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>messageComponentName</TD>
* <TD>yes</TD>
* <TD>the application/gateway etc. being configured specifically, as it's named in the config doc.</TD>
* </TR>
* </TABLE>
* <P>
* Example properties file:
*
* <ul>
* <li>instanceName=SomeGateway-1
* <li>providerUrl=ldaps://ldap.some.company.com:636/ou=Development,ou=Configurations,ou=Messaging,dc=uillinois,dc=edu
* <li>initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory
* <li>securityPrincipal=uid=Gateway1,ou=Users,ou=Messaging,dc=uillinois,dc=edu
* <li>securityCredentials=secretpw
* <li>configDocName=configxmlname=SampleGateway
* <li>messageComponentName=SampleGateway
* </ul>
*
* <P>
*    Directory Server Example:
* <ul>
* <li>providerUrl=ldaps://ldap.some.company.com:636/ou=Development,ou=Configurations,ou=Messaging,dc=uillinois,dc=edu
* <li>providerUrl=ldap://ldap.some.company.com:389/ou=Development,ou=Configurations,ou=Messaging,dc=uillinois,dc=edu
*</ul>
* <P>
*    Web Server Example:
* <ul>
* <li>providerUrl=http://www.aits.uillinois.edu/config/xml/SomeApp.xml
* <li>providerUrl=https://www.aits.uillinois.edu/config/xml/SomeApp.xml
* </ul>
* <P>
*    File system Example:
* <ul>
* <li>providerUrl=/usr/config/xml/SomeApp.xml
* <li>providerUrl=c:/usr/config/xml/SomeApp.xml
* <li>providerUrl=file://localhost/usr/config/xml/SomeApp.xml
* </ul>
*<P>
* @author      Tod Jackson (tod@openeai.org)
* @author      Steve Wheat (steve@openeai.org)
* @version     3.0  - 28 January 2003
*/
public class AppConfig extends EnterpriseConfigurationObjectImpl implements EnterpriseConfigurationObject {

  private Hashtable m_objects = new Hashtable(5, 0.75f);
  private String m_docUri = "";
  private ThreadPool m_threadPool = null;
  private String m_exceptionMessage = "";
  private String m_exceptionStackTrace = "";
  private String m_instanceName = "";
  private boolean m_exceptionOccurred = false;
  private boolean m_isInitialized = false;
  private String m_providerUrl = "";
  private boolean m_useThreads = true;
  /*
  private EnterpriseFields m_fields = null;
  private EnterpriseLayoutManager m_inputXmlLayoutManager = null;
  private EnterpriseLayoutManager m_outputXmlLayoutManager = null;
  */

  // this is the main appConfig to hold shared resources among
  // commands and is set only once to be the top-level AppConfig
  private static AppConfig m_mainAppConfig = null;
  //  private AppConfig m_mainAppConfig = null;

  /**
   * Constructor
   */
  public AppConfig() {
    setMainAppConfig(this);
    setType("AppConfig");
    //    initializeThreadPool("10","0","1", false);
  }

  /**
   * This constructor might be used if an application knows URI of the document that is
   * to be used to configure the application.  Note, this can only be a web address or a file URI.
   * This is generally not needed but is provided as a potential convenience method.
   *
   * @throws EnterpriseConfigurationObjectException if any errors occur while initializing the component.
   */
  public AppConfig(String docUri,
                   String appName) throws EnterpriseConfigurationObjectException {
    setMainAppConfig(this);
    if (isInitialized()) {
      logger.info("[AppConfig] can't initialize AppConfig for " + appName +
                  " because it's already been initialized.");
      return;
    }
    setType("AppConfig");
    setName(appName);
    setDocUri(docUri);
    initializeFromFile(getDocUri(), appName);
    setIsInitialized(true);
  }

  /**
   * This is the most commonly used constructor.  Most applications, gateways, servlets etc.
   * will simply read a properties file on the file system which contains information regarding
   * where to find the configuration document and what component to configure.  See Class description for more
   * details on the Properties file used.
   *
   * @throws EnterpriseConfigurationObjectException if any errors occur while initializing the component.
   */
  public AppConfig(Properties props) throws EnterpriseConfigurationObjectException {

    setMainAppConfig(this);
    setProperties(props);

    String appName = props.getProperty("messageComponentName");
    if (appName == null) {
      throw new EnterpriseConfigurationObjectException("Null 'messageComponentName' not allowed.");
    }
    setName(appName);
    setAppName(appName);

    if (isInitialized()) {
      logger.info("[AppConfig] can't initialize AppConfig for " + getName() +
                  " because it's already been initialized.");
      return;
    }

    String instanceName = props.getProperty("instanceName", "");
    setInstanceName(instanceName);

    String providerUrl = props.getProperty("providerUrl");
    if (providerUrl == null) {
      throw new EnterpriseConfigurationObjectException("Null 'providerUrl' not allowed.");
    }

    if (providerUrl.toLowerCase().indexOf("ldap") == 0) {
      // initialize from a directory server
      initializeFromDirectoryServer(props);
    }
    else {
      // attempt to load config document from web server or file system
      initializeFromFile(providerUrl, appName);
    }
    setIsInitialized(true);
  }

  /**
   * This constructor might be used if an application has already parsed the deployment document and found
   * the configuration Element associated to the application.  This is generally not needed but is provided
   * as a potential convenience method.
   *
   * @throws EnterpriseConfigurationObjectException if any errors occur while initializing the component.
   */
  public AppConfig(Element configElement) throws EnterpriseConfigurationObjectException {
    setMainAppConfig(this);
    setType("AppConfig");
    setName(configElement.getAttribute("id").getValue());
    logger.info("[AppConfig] initializing application " + getName());
    if (isInitialized()) {
      logger.info("[AppConfig] can't initialize AppConfig for " + getName() +
                  " because it's already been initialized.");
      return;
    }
    //    initializeThreadPool("10","0","1", false);
    init(configElement.getChild("Configuration"));
    setIsInitialized(true);
  }

  /**
   * Sets the providerUrl instance variable associated with this Application.  This
   * is the location in the directory server, file system or web server where the
   * deployment document resides.  i.e. - this is where the AppConfig object should
   * "look" for the deployment document.
   *
   * @param url String the providerUrl.
   */
  public final void setProviderUrl(String url) {
    m_providerUrl = url;
  }

  /**
   * Returns the providerUrl instance variable associated with this Application.  This
   * is the location in the directory server, file system or web server where the
   * deployment document resides.  i.e. - this is where the AppConfig object should
   * "look" for the deployment document.
   *
   * @return String the providerUrl.
   */
  public final String getProviderUrl() {
    return m_providerUrl;
  }

  /**
   * Sets the EnterpriseFields object associated with this Application.
   *
   */
  /*
  public void setEnterpriseFields(EnterpriseFields fields) {
    m_fields = fields;
  }
  */

  /**
   * Returns the EnterpriseFields object associated with this Application.
   *
   * @return  org.openeai.config.EnterpriseFields the
   * EnterpriseFields object associated with this Application.
   *
   */
  /*
  public EnterpriseFields getEnterpriseFields() {
    return m_fields;
  }
  */

  /*
  public void setInputXmlLayoutManager(EnterpriseLayoutManager elm) {
    m_inputXmlLayoutManager = elm;
  }
  public EnterpriseLayoutManager getInputXmlLayoutManager() {
    return m_inputXmlLayoutManager;
  }
  public void setOutputXmlLayoutManager(EnterpriseLayoutManager elm) {
    m_outputXmlLayoutManager = elm;
  }
  public EnterpriseLayoutManager getOutputXmlLayoutManager() {
    return m_outputXmlLayoutManager;
  }
  */

  /**
   * Returns the main appConfig (in other words, the top-level AppConfig).
   * This allows access to shared resources, such as database pools, from
   * individual commands instantiated through the main or top-level AppConfig.
   */
  public AppConfig getMainAppConfig() {
    // wait for the main AppConfig to be fully initialized
    if (m_mainAppConfig != null) {
      logger.debug("Waiting for all initialization threads to complete before returning main AppConfig");
      while (!m_mainAppConfig.isInitialized()) {
        try {
          Thread.sleep(1000);
        }
        catch (Exception e) {
        }
      }
      logger.debug("done - Waiting for all initialization threads to complete before returning main AppConfig");
    }
    return m_mainAppConfig;
  }

  /**
   * Sets the main appConfig to be the top-level AppConfig.
   */
  private synchronized void setMainAppConfig(AppConfig appConfig) {
    if (m_mainAppConfig == null)
      m_mainAppConfig = appConfig;
  }

  /**
   * Sets the AppConfig initialization indicator.  When setting the indicator to true, we
   * will wait until all initialization threads are complete before setting this to true.
   * This is neccessary for any commands that required shared resources, that is resources
   * such as database pools that may be defined only in the main or top-level AppConfig.
   */
  private void setIsInitialized(boolean init) {
    if (init) {
      // wait for thread pool to complete its work...
      if (m_threadPool != null && m_useThreads == true) {
        logger.debug("Waiting for all initialization threads to complete before setting AppConfig to initialized status");
        while (m_threadPool.getJobsInProgress() > 0) {
          try {
            Thread.sleep(1000);
          }
          catch (Exception e) {
          }
        }
      }
    }
    m_isInitialized = init;
    logger.debug("AppConfig set to " +
                 (m_isInitialized ? "initialized" : "uninitialized") +
                 " status");
  }

  /**
   * Returns an indication that specifies if this AppConfig object has been initialized yet.
   *
   * @return boolean
   */
  public final boolean isInitialized() {
    return m_isInitialized;
  }

  private String getInstanceName() {
    return m_instanceName;
  }

  private void setInstanceName(String instanceName) {
    m_instanceName = instanceName;
  }

  /**
   * Returns the config document URI that is used to locate the XML config document for
   * this application.
   *
   * @return String
   */
  public final String getDocUri() {
    return m_docUri;
  }

  /**
   * Sets the config document URI that is used to locate the XML config document for
   * this application.
   *
   * @param docUri String
   */
  public final void setDocUri(String docUri) {
    m_docUri = docUri;
  }

  /**
   * Re-initializes this AppConfig object.  This method stops any running component
   * that it's managing, re-reads the deployment document and re-initializes/re-starts
   * all objects for this application that's listed in the deployment document.
   *
   * @throws EnterpriseConfigurationObjectException
   */
  public final void reInitialize() throws EnterpriseConfigurationObjectException {
    // Stop any running producers and/or consumers.
    setIsInitialized(false);
    Enumeration keys = getObjects().keys();
    while (keys.hasMoreElements()) {
      Object obj = getObjects().get(keys.nextElement());
      if (obj instanceof PointToPointProducer) {
        PointToPointProducer p2p = (PointToPointProducer)obj;
        p2p.stopProducer();
      }
      if (obj instanceof PointToPointConsumer) {
        PointToPointConsumer p2p = (PointToPointConsumer)obj;
        p2p.stopConsumer();
      }
      if (obj instanceof PubSubProducer) {
        PubSubProducer pubSub = (PubSubProducer)obj;
        pubSub.stopPublisher();
      }
      if (obj instanceof PubSubConsumer) {
        PubSubConsumer pubSub = (PubSubConsumer)obj;
        pubSub.stopConsumer();
      }
    }

    // Reset the objects hashtable to a blank Hashtable.
    setObjects(new Hashtable(5, 0.75f));

    // Rebuild the AppConfig object based on information used when it was initialized
    // the first time.
    if (getDocUri().length() > 0) {
      // Initialize from file...
    }
    else if (getProperties() != null && getProperties().size() > 0) {
      // Initialized from properties (directory server)
      initializeFromDirectoryServer(getProperties());
    }
    else {
      // error
    }
  }

  /**
   * Loads the configuration document from a URI (file or webserver etc.).
   *
   * @param docUri String file URI to the document (http:, file: etc.)
   * @param appName String appName the name of the messaging component in the configuration document that the AppConfig object should be lookning for.
   * @throws EnterpriseConfigurationObjectException
   */
  public void initializeFromFile(String docUri,
                                 String appName) throws EnterpriseConfigurationObjectException {
    setType("AppConfig");
    setDocUri(docUri);
    try {
      XmlDocumentReader xmlReader = new XmlDocumentReader();
      setConfigDoc(xmlReader.initializeDocument(getDocUri(), getValidation()));
    }
    catch (XmlDocumentReaderException e) {
      String msg =
        "Error initializing document " + getDocUri() + " for Component named " +
        appName + "  Exception: " + e.getMessage();
      logger.fatal(msg);
      throw new EnterpriseConfigurationObjectException(msg, e);
    }
    setName(appName);
    if (this.getAppName() == null || this.getAppName().length() == 0) {
      setAppName(appName);
    }
    init();
    setIsInitialized(true);
  }

  /**
   * Loads the configuration document from a Directory Server via LDAP (ldap or ldaps)
   *
   * @param props Java Properties object containing the appropriate properties needed to configure this AppConfig object.
   *<P>
   * See class description for list of properties.
   *<P>
   * @throws EnterpriseConfigurationObjectException
   */
  private void initializeFromDirectoryServer(Properties props) throws EnterpriseConfigurationObjectException {
    setType("AppConfig");
    setProperties(props);

    String appName = props.getProperty("messageComponentName");
    if (appName == null) {
      throw new EnterpriseConfigurationObjectException("Null 'messageComponentName' not allowed.");
    }

    String providerUrl = props.getProperty("providerUrl");
    if (providerUrl == null) {
      throw new EnterpriseConfigurationObjectException("Null 'providerUrl' not allowed.");
    }

    String initialCtxFactory = props.getProperty("initialContextFactory");
    if (initialCtxFactory == null) {
      throw new EnterpriseConfigurationObjectException("Null 'initialContextFactory' not allowed.");
    }

    String principal = props.getProperty("securityPrincipal");
    if (principal == null) {
      throw new EnterpriseConfigurationObjectException("Null 'securityPrincipal' not allowed.");
    }

    String credentials = props.getProperty("securityCredentials");
    if (credentials == null) {
      throw new EnterpriseConfigurationObjectException("Null 'securityCredentials' not allowed.");
    }

    String configDocName = props.getProperty("configDocName");
    if (configDocName == null) {
      throw new EnterpriseConfigurationObjectException("Null 'configDocName' not allowed.");
    }

    DirContext ic = null;
    Hashtable env = new Hashtable(5, 0.75f);

    boolean useSsl = false;
    if (providerUrl.indexOf("ldaps:") != -1) {
      useSsl = true;
      // Replace the ldaps with ldap
      String newProviderUrl =
        "ldap:" + providerUrl.substring(providerUrl.indexOf(":") + 1);
      providerUrl = newProviderUrl;
      logger.debug("ProviderUrl was changed to " + providerUrl);
    }

    logger.debug("Getting initial context");
    env.put(Context.INITIAL_CONTEXT_FACTORY, initialCtxFactory);
    logger.debug("Set initCtxFactory to " + initialCtxFactory);
    env.put(Context.PROVIDER_URL, providerUrl);
    logger.debug("Set providerUrl to " + providerUrl);

    if (useSsl) {
      // Bind via ssl
      logger.debug("Setting SECURITY_PROTOCOL to ssl");
      env.put(Context.SECURITY_PROTOCOL, "ssl");
    }

    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    env.put(Context.SECURITY_PRINCIPAL, principal);
    logger.debug("Set principal to " + principal);
    env.put(Context.SECURITY_CREDENTIALS, credentials);
    logger.debug("Set credentials to " + credentials);

    String configDocContents = null;
    try {
      logger.info("Creating a new InitialContext object (ie - connecting to the DirectoryServer to retrieve configuration document)...");
      Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
      ic = new InitialDirContext(env);
      logger.info("Created the InitialContext object...");

      SearchControls constraints = new SearchControls();
      constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
      NamingEnumeration results = null;
      results = ic.search(providerUrl, configDocName, constraints);
      if (results == null || !results.hasMoreElements()) {
        throw new EnterpriseConfigurationObjectException("No matching records found for " +
                                                         configDocName);
      }
      else {
        logger.debug("Found " + configDocName);
        while (results.hasMoreElements()) {
          SearchResult sr = (SearchResult)results.next();
          javax.naming.directory.Attributes attrs = sr.getAttributes();
          javax.naming.directory.Attribute battr =
            attrs.get("configxmldocument");
          configDocContents = (String)battr.get();
        }
      }
      ic.close();
    }
    catch (NamingException ne) {
      String errMessage =
        "NamingException Creating InitialContext.  Exception: " +
        ne.getMessage();
      logger.fatal(errMessage, ne);
      throw new EnterpriseConfigurationObjectException(errMessage, ne);
    }
    catch (Exception e) {
      String errMessage =
        "UnknownException Creating InitialContext.  Exception: " +
        e.getMessage();
      logger.fatal(errMessage, e);
      throw new EnterpriseConfigurationObjectException(errMessage, e);
    }

    try {
      XmlDocumentReader xmlReader = new XmlDocumentReader();
      boolean v = getValidation();
      Document cDoc =
        xmlReader.initializeDocument(new StringReader(configDocContents), v);
      setConfigDoc(cDoc);
    }
    catch (XmlDocumentReaderException e) {
      String errMessage =
        "Error initializing configuration document from directory server.  " +
        "Exception: " + e.getMessage();
      logger.fatal(errMessage);
      throw new EnterpriseConfigurationObjectException(errMessage, e);
    }
    setName(appName);
    init();
    setIsInitialized(true);
  }

  public Hashtable getObjects() {
    return m_objects;
  }

  private void setObjects(Hashtable objects) {
    m_objects = objects;
  }

  /**
   * Returns the <b>first</b> object stored in this AppConfig that is a class of object
   * matching the the class name passed in.
   * <P>
   * If the object has been configured with the 'refresh' attribute set to 'true'
   * the object will be refreshed based on the current contents of the config document
   * before it's returned.  Currently, this only works for PropertyConfig objects so
   * properties associated to an application like a Servlet, ScheduledApp or Gateway
   * can be refreshed dynamically without restarting the app.  This will only work
   * if the application actually retrieves the Properties object from AppConfig
   * when the business logic is executed as opposed to retrieving those properties
   * when the command or servlet is first instantiated.
   * <P>
   * Note, XmlEnterpriseObjects stored in an AppConfig will be cloned and the clone
   * will be returned.  For all other types of objects stored in an AppConfig, a
   * reference to that object will be returned.
   *
   * @param className String the class name of the object being retrieved.
   * @return Object
   * @throws EnterpriseConfigurationObjectException if no objects of type passed in exist.
   * @see #getObject
   */
  public final synchronized Object getObjectByType(String className) throws EnterpriseConfigurationObjectException {
    Enumeration keys = getObjects().keys();
    Object o2 = null;

    Class compareClass = null;

    try {
      compareClass = Class.forName(className);
    }
    catch (ClassNotFoundException exp) {
      throw new EnterpriseConfigurationObjectException(exp);
    }

    while (keys.hasMoreElements()) {
      String name = (String)keys.nextElement();
      Object o = getObjects().get(name);
      logger.debug("Comparing " + className + " to " + o.getClass().getName());
      if (compareClass.isInstance(o)) {

        // If it's an XmlEnterpriseObject, we'll do a "deepCopy" on that object
        if (o instanceof XmlEnterpriseObject) {
          XmlEnterpriseObject x = (XmlEnterpriseObject)o;
          try {
            XmlEnterpriseObject x2 = (XmlEnterpriseObject)x.clone();
            return x2;
          }
          catch (Exception e) {
            String errMessage =
              "Error performing clone on " + className + "  Exception: " +
              e.getMessage();
            logger.fatal(errMessage);
            throw new EnterpriseConfigurationObjectException(errMessage, e);
          }
        }

        // check 'refresh' attribute associated to all EnterpriseConfiguration objects.  If refresh is true,
        // refresh the object before returning it.
        if (o instanceof EnterpriseConfigurationObject) {
          EnterpriseConfigurationObject eco = (EnterpriseConfigurationObject)o;
          if (eco.refresh()) {
            logger.debug("Need to refresh the " + name + " object....");
            refreshObject(name);
            logger.debug("Done refreshing the " + name + " object.");
            return getObjects().get(name.toLowerCase());
          }
        }

        // Otherwise, we'll just return a reference to the object.
        return o;
      }
    }
    if (o2 == null) {
      String errMessage =
        "AppConfig: Object of type " + className + " could not be found in this " +
        getName() + " AppConfig.";
      logger.debug(errMessage);
      throw new EnterpriseConfigurationObjectException(errMessage);
    }
    return o2;
  }

  /**
   * Returns a List of objects currently stored in this AppConfig object with names that contain
   * the pattern passed in.
   *
   * @param pattern String the "pattern" name of the object(s) being retrieved.
   * @return List of objects who's names contain the pattern passed in (empty list if none exist).
   * @throws EnterpriseConfigurationObjectException if no objects exist with names containing the pattern passed in.
   * @see #getObject
   */
  public final synchronized java.util.List getObjectsLike(String pattern) throws EnterpriseConfigurationObjectException {
    // Returns a list of objects that are stored in this AppConfig that have a name
    // which contains the "pattern" passed in.  For each object with that pattern
    // in it's name, add it to the "returnVector" then return the vector at the end.
    java.util.List returnList = Collections.synchronizedList(new ArrayList());
    Set keySet = getObjects().keySet();
    Iterator it = keySet.iterator();
    while (it.hasNext()) {
      String keyName = (String)it.next();
      if (keyName.indexOf(pattern.toLowerCase().trim()) != -1) {
        returnList.add(getObject(keyName));
      }
    }
    return returnList;
  }

  /**
   * Convenience method that returns a Properties object associated to a PropertyConfig
   * object.  This allows developers to retrieve named properties from an AppConfig
   * without having to go through the extra step of retrieving a PropertyConfig object
   * and then calling the 'getProperties' method on that object.  It can still be done
   * that way but this method just provides a mechanism for doing with fewer lines of
   * code.
   *
   * @param name String the name of the PropertyConfig object being retrieved as it's named in the Deployment document.
   * @return Properties object associated to the PropertyConfig object who's name matches the name passed in.
   * @throws EnterpriseConfigurationException if no object exists with a name passed in or if the
   * object named 'name' is not a PropertyConfig object.
   * @see #getObject
   */
  public final synchronized Properties getProperties(String name) throws EnterpriseConfigurationObjectException {

    Object o = getObject(name);

    // If it's a PropertyConfig object, get the Properties object associated
    // to it and return it.
    if (o instanceof PropertyConfig) {
      PropertyConfig p = (PropertyConfig)o;
      return p.getProperties();
    }
    else {
      String errMessage =
        "AppConfig:  the object named '" + name + "' is not " +
        "an instance of the PropertyConfig class.";
      throw new EnterpriseConfigurationObjectException(errMessage);
    }
  }

  /**
   * Returns the object stored in this AppConfig object with the name passed in.
   * The name of the objects are specified in the XML Configuration documents and
   * are the names by which AppConfig stores objects as it configures itself.
   * <P>
   * If the object has been configured with the 'refresh' attribute set to 'true'
   * the object will be refreshed based on the current contents of the config document
   * before it's returned.  Currently, this only works for PropertyConfig objects so
   * properties associated to an application like a Servlet, ScheduledApp or Gateway
   * can be refreshed dynamically without restarting the app.  This will only work
   * if the application actually retrieves the Properties object from AppConfig
   * when the business logic is executed as opposed to retrieving those properties
   * when the command or servlet is first instantiated.
   * <P>
   * Note, XmlEnterpriseObjects stored in an AppConfig will be cloned and the clone
   * will be returned.  For all other types of objects stored in an AppConfig, a
   * reference to that object will be returned.
   *
   * @param name String the name of the object being retrieved.
   * @return Object who's name matches the name passed in.
   * @throws EnterpriseConfigurationException if no object exists with a name passed in.
   * @see #getObjectByType
   * @see #getObjectsLike
   */
  public final synchronized Object getObject(String name) throws EnterpriseConfigurationObjectException {

    logger.debug("Attempting to retrieve " + name + " from AppConfig");
    Object o = getObjects().get(name.toLowerCase());

    if (o == null) {
      throw new EnterpriseConfigurationObjectException("Object named " + name +
                                                       " could not be found in this AppConfig object.");
    }

    logger.debug("Retrieved " + name + " from AppConfig");

    try {
      // If it's an XmlEnterpriseObject, we'll do a "deepCopy" on that object
      if (o instanceof XmlEnterpriseObject) {
        logger.debug("Performing a clone on " + name);
        XmlEnterpriseObject x = (XmlEnterpriseObject)o;
        try {
          XmlEnterpriseObject x2 = (XmlEnterpriseObject)x.clone();
          logger.debug("done cloning...");
          return x2;
        }
        catch (Exception e) {
          String errMessage =
            "Error performing clone on " + x.getClass().getName() +
            "  Exception: " + e.getMessage();
          logger.fatal(errMessage);
          throw new EnterpriseConfigurationObjectException(errMessage, e);
        }
      }

      // check 'refresh' attribute associated to all EnterpriseConfiguration objects.  If refresh is true,
      // refresh the object before returning it.
      if (o instanceof EnterpriseConfigurationObject) {
        EnterpriseConfigurationObject eco = (EnterpriseConfigurationObject)o;
        if (eco.refresh()) {
          //          if (isInitialized()) {
          logger.debug("Need to refresh the " + name + " object....");
          refreshObject(name);
          logger.debug("Done refreshing the " + name + " object.");
          return getObjects().get(name.toLowerCase());
          //          }
          //          else {
          //            logger.info("Not refreshing the " + name + " object because this AppConfig is still initializing.");
          //            return o;
          //          }
        }
      }

      // just return a reference to the object.
      return o;
    }
    catch (Exception e) {
      logger.fatal("AppConfig: Exception occurred.  Exception: " +
                   e.getMessage());
      throw new EnterpriseConfigurationObjectException("AppConfig: Exception occurred.  Exception: " +
                                                       e.getMessage(), e);
    }
  }

  private void refreshObject(String name) throws EnterpriseConfigurationObjectException {
    String providerUrl = getProperties().getProperty("providerUrl");
    Properties props = null;
    if (providerUrl == null) {
      // we must be in a command
      providerUrl =
          getMainAppConfig().getProperties().getProperty("providerUrl");
      props = getMainAppConfig().getProperties();
    }
    else {
      props = getProperties();
    }

    if (providerUrl == null) {
      // the appconfig was initialized via one of the 'initializeFrom..." methods.
      providerUrl = getDocUri();
      setProviderUrl(providerUrl);
    }

    if (providerUrl.toLowerCase().indexOf("ldap") == 0) {
      //      refreshObjectFromDirectoryServer(name, props);
    }
    else {
      // attempt to load config document from web server or file system
      refreshObjectFromFile(name);
    }
  }

  private void refreshObjectFromFile(String objectName) throws EnterpriseConfigurationObjectException {
    Document configDoc = null;
    String docUri = getDocUri();
    try {
      XmlDocumentReader xmlReader = new XmlDocumentReader();
      if (docUri == null || docUri.length() == 0) {
        // we must be in a command
        docUri = getMainAppConfig().getDocUri();
      }
      configDoc = xmlReader.initializeDocument(docUri, false);
      setConfigDoc(configDoc);
    }
    catch (XmlDocumentReaderException e) {
      String msg =
        "Error initializing document " + getDocUri() + " for Component named " +
        objectName + "  Exception: " + e.getMessage();
      logger.fatal(msg, e);
      throw new EnterpriseConfigurationObjectException(msg, e);
    }
    try {
      String appName = this.getAppName();
      logger.debug("looking for application named: " + appName);
      Element mainConfigElement =
        getElementByAttributeValue(getConfigDoc().getRootElement(), appName);
      XmlElementLocator locator = new XmlElementLocator();
      Element configElement =
        locator.getElementByAttributeNameValueRecursive(mainConfigElement,
                                                        "name", objectName);
      String className =
        getObjects().get(objectName.toLowerCase()).getClass().getName();
      setObjects(addObject(getObjects(), objectName, className, null,
                           configElement));
    }
    catch (Exception e) {
      logger.fatal(e.getMessage(), e);
      throw new EnterpriseConfigurationObjectException(e.getMessage(), e);
    }
  }

  /**
   * This is the "workhorse" initialization method for an AppConfig object.  This method
   * is called once the "Configuration" element for an application, gateway etc. has been
   * retrieved from their config document.  The configuration element passed in is used
   * to determine which objects to instantiate and initialize with the information found
   * in the Configuration element.
   *<P>
   * This method loops through all the child elements within the Configuration element
   * passed in and instantiates configuration Java objects with those individual config elements.
   * Then, it passes those Java objects to the appropriate Java object's constructor.  These
   * Java objects that are instantiated with the configuration objects, are then available to
   * applications via the getObject, getObjectsLike and getObjectByType methods.
   *<P>
   * For example, an XML aware ProducerConfig object is instantiated/initialized with the ProducerConfig XML element.
   * This object is then used to construct either a PointToPointProducer or a PubSubProducer foundation component
   * depending on the information contained in the ProducerConfig object/element.
   * Finally, the Producer that's instantiated is stored within the AppConfig object and can be retrieved
   * during application execution by the application developer.  This way, the Producer is instantiated, configured
   * and potentially started (ready for producing messages) all based on information contained in the
   * configuration document.  All the application developer has to do
   * is enter the appropriate configuration information into the config document and start his application.  When
   * the application is started, an AppConfig object is built and the appropriate Producers are added to it
   * for use by the application being developed.
   *
   * @param eConfig Element the Configuration Element for the application, gateway, servlet etc. being configured.
   * @throws EnterpriseConfigurationObjectException if any errors occur while initializing the component.
   */
  public void init(Element eConfig) throws EnterpriseConfigurationObjectException {
    // Now that we've found an application, we need to get the Configuration
    // Element out.
    java.util.List configChildren = eConfig.getChildren();
    logger.debug(getName() + " has " + configChildren.size() +
                 " Configuration children.");
    // Now we'll get a list of all config lists (MessageObjectConfigs, ProducerConfigs, etc.).
    for (int i = 0; i < configChildren.size(); i++) {
      Element eConfig2 = (Element)configChildren.get(i);
      java.util.List configList = eConfig2.getChildren();
      java.util.List defaultAttrs = eConfig2.getAttributes();
      // Now, we need to go through all the Configuration elements and instantiate
      // the appropriate Java Config object for that Config element.  This will be based on
      // the configClassName attribute in the config elements.
      // MessageObjectConfigs/MessageObjectConfig, ProducerConfigs/ProducerConfig, etc.)
      // This is what we'll perform utilizing the thread pool.
      try {
        if (m_useThreads) {
          if (m_threadPool == null) {
            initializeThreadPool("10", "0", "1", false);
          }
          m_threadPool.addJob(new InitConfigsThread(eConfig2.getName(),
                                                    defaultAttrs, configList));
        }
        else {
          new InitConfigsThread(eConfig2.getName(), defaultAttrs,
                                configList).run();
        }
      }
      catch (ThreadPoolException e) {
      }
    }
    if (m_useThreads) {
      logger.debug("Waiting for Threads to complete.");
      while (m_threadPool.getJobsInProgress() > 0) {
        try {
          Thread.sleep(500);
        }
        catch (Exception e) {
        }
      }
      logger.debug("Threads are done.");
    }
    if (m_exceptionOccurred) {
      logger.fatal("Exception Occurrred while configuring application " +
                   getName());
      logger.fatal("Exception Message: " + m_exceptionMessage);
      logger.fatal("Exception Stack: " + m_exceptionStackTrace);
      throw new EnterpriseConfigurationObjectException(m_exceptionMessage);
    }
    logger.debug("Added " + getObjects().size() +
                 " objects to object Hashtable");
    logger.info("Initialization complete for Application named: " + getName());
  }

  /**
   * Starts the initialization process for this AppConfig object.
   * - retrieves the root element from the config doc
   * - finds the messaging component element we're configuring (application, gateway etc.)
   * - retreives the "Configuration" element from that messaging component.
   * - calls the init(Element) method which performs the instantiation and initialization
   *   of all components listed in the Configuration element.
   *<P>
   * This is called when the AppConfig object is instantiated with a Properties object
   * and initializes itself from a file or from a directory server.
   *
   * @throws EnterpriseConfigurationObjectException if any errors occur while initializing the component.
   */
  private void init() throws EnterpriseConfigurationObjectException {
    /*
    - Go through all MessagingComponents and find this application.
    - Once the app is found, loop through the Configuration element
      and instantiate a ConfigObject for each configuration object listed.
    - Then, take the config object and instantiate the appropriate configurable
      object starting the ones that need to be started (Producers, Consumers) and
      initializing the ones that need initialized (Logger).
    - After they've been successfully initialized, started etc. add the names
      of the objects to the m_configObjectNames Vector and add the configurable object
      to the m_objects Vector.
    */
    Element rootElement = getConfigDoc().getRootElement();
    Element appElement = getElementByAttributeValue(rootElement, getName());
    Element eConfig = null;
    if (appElement != null) {
      logger.debug("Found app " + getName() + " in " + appElement.getName());
      eConfig = appElement.getChild("Configuration");
      if (eConfig == null) {
        String errMsg =
          "Could not find Configuration information for application '" +
          getName() +
          "' check that the 'messageComponentName' property matches " +
          "what's in the Deployment document.";
        logger.fatal(errMsg);
        throw new EnterpriseConfigurationObjectException(errMsg);
      }

      // determine if we should initialize this AppConfig object using threads or not.
      // default is 'true' (we should use threads).
      Attribute aInitializeUsingThreads =
        eConfig.getAttribute("initializeUsingThreads");
      if (aInitializeUsingThreads != null) {
        String initUsingThreads = aInitializeUsingThreads.getValue();
        logger.debug("initUsingThreads String value: '" + initUsingThreads +
                     "'");
        if (initUsingThreads.equalsIgnoreCase("true") == false &&
            initUsingThreads.equalsIgnoreCase("false") == false) {
          initUsingThreads = "true";
        }
        m_useThreads =
            new Boolean(initUsingThreads.toLowerCase()).booleanValue();
      }
      else {
        logger.debug("initializeUsingThreads Attribute couldn not be found.");
      }
      logger.debug("m_useThreads is '" + m_useThreads + "'");
      if (m_useThreads) {
        initializeThreadPool("10", "0", "1", false);
      }
    }
    else {
      // Need to throw an exception here!
      String errMsg =
        "Could not find Configuration information for application '" +
        getName() +
        "' check that the 'messageComponentName' property matches " +
        "what's in the Deployment document.";
      logger.fatal(errMsg);
      throw new EnterpriseConfigurationObjectException(errMsg);
    }
    init(eConfig);
  }

  private Hashtable addObject(Hashtable map, String oName, String cClass,
                              String oClass,
                              Element eConfig2) throws EnterpriseConfigurationObjectException {
    String configType = eConfig2.getName();
    if (oClass == null) {
      try {
        java.lang.Class obj = java.lang.Class.forName(cClass);
        EnterpriseConfigurationObject eco =
          (EnterpriseConfigurationObject)obj.newInstance();
        eco.setAppName(getName());
        eco.init(eConfig2);
        logger.debug("Adding " + oName + "-" + eco.getClass().getName() +
                     " to AppConfig for Application: " + getName());
        if (eco instanceof LoggerConfig) {
          initializeLog4j(eco.getProperties());
          map.put(oName.toLowerCase(), eco);
        }
        else {
          map.put(oName.toLowerCase(), eco);
        }
      }
      catch (Exception e) {
        String errMessage =
          "Error initializing class " + cClass + "  Exception: " +
          e.getMessage();
        logger.fatal(errMessage);
        throw new EnterpriseConfigurationObjectException(errMessage, e);
      }
    }
    else {
      try {
        logger.debug("Initializing object: " + oClass + " with config " +
                     cClass + " for Application " + getName());
        java.lang.Class obj = java.lang.Class.forName(cClass);
        java.lang.Class obj2 = java.lang.Class.forName(oClass);
        EnterpriseConfigurationObject eco =
          (EnterpriseConfigurationObject)obj.newInstance();
        eco.setAppName(getName());
        eco.init(eConfig2);

        // 'instanceName' will be used by all objects so they can tell what instance
        // of a particular application they are.  Specifically, the PubSubConsumers
        // will use this property so they can dynamically build their subscription
        // name based on 'instanceName' and 'ConsumerName' as specified in the
        // config document for the consumer.
        eco.getProperties().put("instanceName", getInstanceName());

        Class[] parms2 = { eco.getClass() };
        Constructor c2 = obj2.getConstructor(parms2);
        Object[] o2 = { eco }; // The config object
        if (configType.equalsIgnoreCase("ProducerConfig")) {
          // We may have to instantiate multiple producers and increment their names
          // accordingly.
          org.jdom.Attribute aNumberOfProducers =
            eConfig2.getAttribute("numberOfProducers");
          if (aNumberOfProducers != null) {
            String sNum = aNumberOfProducers.getValue().trim();
            if (sNum != null && sNum.length() > 0 &&
                sNum.equals("0") == false) {
              Vector vProducers = new Vector();
              int numProducers = Integer.parseInt(sNum);
              for (int i = 0; i < numProducers; i++) {
                Object o3 =
                  c2.newInstance(o2); // The object we're configuring, constructed with the config object.
                map.put(oName.toLowerCase() + i, o3);
                vProducers.add(o3);
              }
              // Add the actual producer pool object to AppConfig
              ProducerPool pool = new ProducerPool(vProducers);
              map.put(oName.toLowerCase(), pool);
            }
          }
          else {
            Object o3 =
              c2.newInstance(o2); // The object we're configuring, constructed with the config object.
            map.put(oName.toLowerCase(), o3);
          }
        }
        else {
          Object o3 =
            c2.newInstance(o2); // The object we're configuring, constructed with the config object.
          map.put(oName.toLowerCase(), o3);
        }
        // Set the EnterpriseFields object in this AppConfig to be the first one
        // we find in an XmlEnterpriseObject being configured.  This is so
        // other XmlEnterpriseObject objects will have access to this via the
        // AppConfig instead of having to get it from the XmlEnterpriseObject
        // that was configured by AppConfig.
        /*
        if (o3 instanceof XmlEnterpriseObject && getEnterpriseFields() == null) {
          XmlEnterpriseObject anXeo = (XmlEnterpriseObject)o3;
          setEnterpriseFields(anXeo.getEnterpriseFields());
          setInputXmlLayoutManager(anXeo.getInputLayoutManager("xml"));
          setOutputXmlLayoutManager(anXeo.getOutputLayoutManager("xml"));
        }
        */
      }
      catch (Exception e) {
        String errMessage =
          "Error initializing class " + oClass + " with config " + cClass +
          "  Exception: " + e.getMessage();
        logger.fatal(errMessage, e);
        throw new EnterpriseConfigurationObjectException(errMessage, e);
      }
    }
    return map;
  }

  private void initializeThreadPool(String maxThreads, String minThreads,
                                    String maxIdleTime,
                                    boolean checkBeforeProcessing) {
    logger.debug("Initializing ThreadPool...");
    Properties threadPoolProps = new Properties();
    threadPoolProps.setProperty("maxThreads", maxThreads);
    threadPoolProps.setProperty("minThreads", minThreads);
    threadPoolProps.setProperty("maxIdleTime", maxIdleTime);
    threadPoolProps.setProperty("checkBeforeProcessing",
                                new Boolean(checkBeforeProcessing).toString());
    m_threadPool = new ThreadPoolImpl(threadPoolProps);
  }

  private class InitConfigsThread implements java.lang.Runnable {
    java.util.List m_configList = null;
    java.util.List m_defaultAttrs = null;
    String m_listName = "";

    public InitConfigsThread(String configListName,
                             java.util.List defaultAttrs,
                             java.util.List configList) {
      m_configList = configList;
      m_defaultAttrs = defaultAttrs;
      m_listName = configListName;
    }

    public void run() {
      ArrayList aConfigObjects = new ArrayList();
      Element eDefaultParms = new Element("DefaultParms");

      if (m_defaultAttrs.size() == 0) {
        logger.debug("No default attributes for this config object.");
      }
      for (int i = 0; i < m_defaultAttrs.size(); i++) {
        org.jdom.Attribute anAttr = (org.jdom.Attribute)m_defaultAttrs.get(i);
        eDefaultParms.setAttribute((org.jdom.Attribute)anAttr.clone());
      }

      for (int j = 0; j < m_configList.size(); j++) {
        Element eConfigObject = (Element)m_configList.get(j);

        // If the name of eConfigObject is the same as m_configList (i.e. - ProducerConfigs/ProducerConfig
        // that will be the configuration element used for the specific object we're configuring
        // Otherwise, we'll add all the "default" configuration information for all configuration objects
        // i.e. - parms that all ProducerConfig objects withing the ProducerConfigs container will use
        // to a separate element that will be used for default values.
        // Then, we'll go through all of those and configure them with default values or
        // config specific values if they over-ride the default values.

        if (eConfigObject.getName().equals(m_listName.substring(0,
                                                                m_listName.length() -
                                                                1))) {
          aConfigObjects.add(eConfigObject);
        }
        else {
          logger.debug("Found a default config element for the '" +
                       eConfigObject.getName() +
                       "' element.  m_listName is: " + m_listName);
          eDefaultParms.addContent((Element)eConfigObject.clone());
        }
      }

      // Now, we're going to instantiate and initialize the object we're configuring (ie a ProducerConfig etc.)
      for (int i = 0; i < aConfigObjects.size(); i++) {
        Element eConfigObject = (Element)aConfigObjects.get(i);
        try {
          if (m_useThreads) {
            if (m_threadPool == null) {
              initializeThreadPool("10", "0", "1", false);
            }
            m_threadPool.addJob(new InitializeObjectThread(eDefaultParms,
                                                           eConfigObject));
          }
          else {
            new InitializeObjectThread(eDefaultParms, eConfigObject).run();
          }
        }
        catch (ThreadPoolException e) {
        }
      }
    }
  }

  private class InitializeObjectThread implements java.lang.Runnable {
    Element m_configElement = null;
    Element m_defaultParms = null;

    public InitializeObjectThread(Element defaultParms,
                                  Element configElement) {
      m_configElement = configElement;
      m_defaultParms = defaultParms;
    }

    public void run() {
      String configClass = null, configName = null, objectClass = null;

      // Use the ConfigClass in the lower level config object, if specified
      // Otherwise, use the default from the "container" level.
      if (m_configElement.getChild("ConfigClass") != null) {
        configClass = m_configElement.getChild("ConfigClass").getText();
      }
      else {
        configClass = m_defaultParms.getChild("ConfigClass").getText();
      }

      // All config objects must have a name.
      org.jdom.Attribute nameAttr = m_configElement.getAttribute("name");
      configName = nameAttr.getValue();
      logger.debug("Initializing object: " + configName);

      // Use the object class from the lower level config object, if specified
      // otherwise, try to use whatever's specified at the "container" level.
      // If it's not found, that's okay.
      if (m_configElement.getChild("ObjectClass") != null) {
        objectClass = m_configElement.getChild("ObjectClass").getText();
      }
      else {
        try {
          objectClass = m_defaultParms.getChild("ObjectClass").getText();
        }
        catch (NullPointerException e) {
          logger.warn(m_configElement.getName() +
                       " doesn't have an ObjectClass");
        }
      }

      // Now, we're going to build one configuration object that will be used
      // to instantiate and initialize the object we're configuring.  We'll take
      // all information from the lower level if it exists, otherwise, we'll use
      // information specified at the container level.

      // First the attributes
      java.util.List defaultAttrList = m_defaultParms.getAttributes();
      for (int i = 0; i < defaultAttrList.size(); i++) {
        org.jdom.Attribute aDefaultParm =
          (org.jdom.Attribute)defaultAttrList.get(i);
        if (m_configElement.getAttribute(aDefaultParm.getName()) == null) {
          m_configElement.setAttribute((org.jdom.Attribute)aDefaultParm.clone());
        }
      }

      // Add the name Attribute back on...
      //      m_configElement.setAttribute((org.jdom.Attribute)nameAttr.clone());

      // Now the elements
      java.util.List defaultElementList = m_defaultParms.getChildren();
      for (int i = 0; i < defaultElementList.size(); i++) {
        Element eDefaultParm = (Element)defaultElementList.get(i);
        if (m_configElement.getChild(eDefaultParm.getName()) == null) {
          m_configElement.addContent((Element)eDefaultParm.clone());
        }
      }

      // Instantiate and save the config object
      // LoggerConfig, ProducerConfig, ConsumerConfig, MessageObjectConfig
      if (configClass != null) {
        try {
          setObjects(addObject(getObjects(), configName, configClass,
                               objectClass, m_configElement));
        }
        catch (Exception e) {
          logger.fatal("Exception Occurred configuring " + configName + " " +
                       objectClass + " with " + configClass);
          m_exceptionOccurred = true;
          m_exceptionMessage = e.getMessage();
          ByteArrayOutputStream bw = new ByteArrayOutputStream();
          PrintWriter pw = new PrintWriter(bw, true);
          e.printStackTrace(pw);
          m_exceptionStackTrace = bw.toString();
          return;
        }
      }
    }
  }

  /**
   * Returns name and class information about all objects currently stored in this
   * AppConfig object.  Line feed included.  Debug use only...
   *
   * @return String
   */
  public String dumpStats() {
    StringBuffer sb = new StringBuffer();
    Enumeration keys = m_objects.keys();
    while (keys.hasMoreElements()) {
      String keyName = (String)keys.nextElement();
      Object obj = m_objects.get(keyName);
      String className = obj.getClass().getName();
      sb.append("Name: " + keyName + " / " + className + "\n");
    }
    return new String(sb);
  }

  /**
  * Recursively shuts down all objects contained within this AppConfig.  This
  * includes things like MessageProducers, MessageConsumers and Database Connection
  * pools that may have open connections to external sources like Brokers and Databases.
  **/
  public void shutdown() throws EnterpriseConfigurationObjectException {
    logger.debug("[AppConfig] removing all objects from space...");
    logger.debug("[AppConfig] stats: " + dumpStats());
    try {
      Enumeration keys = getObjects().keys();
      logger.debug("[AppConfig] got keys..." + keys);
      while (keys.hasMoreElements()) {
        String keyName = (String)keys.nextElement();
        Object obj = getObjects().get(keyName);
        if (obj instanceof org.openeai.afa.ScheduledApp) {
          org.openeai.afa.ScheduledApp sa = (org.openeai.afa.ScheduledApp)obj;
          logger.info("[AppConfig] Stopping scheduled app...");
          sa.stop();
        }
        if (obj instanceof org.openeai.jms.consumer.MessageConsumer) {
          MessageConsumer mc = (MessageConsumer)obj;
          mc.stop();
        }
        if (obj instanceof org.openeai.jms.producer.MessageProducer) {
          MessageProducer mp = (MessageProducer)obj;
          mp.stop();
        }
        if (obj instanceof org.openeai.jms.producer.ProducerPool) {
          ProducerPool p = (ProducerPool)obj;
          java.util.List producers = p.getProducers();
          for (int i = 0; i < producers.size(); i++) {
            MessageProducer mp = (MessageProducer)producers.get(i);
            mp.stop();
          }
        }
        logger.debug("[AppConfig] removing '" + keyName + "'");
        getObjects().remove(keyName);
      }
    }
    catch (Exception e) {
      throw new EnterpriseConfigurationObjectException(e.getMessage(), e);
    }
  }
}
TOP

Related Classes of org.openeai.config.AppConfig

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.