Package org.openeai.moa

Source Code of org.openeai.moa.XmlEnterpriseObjectImpl

/*******************************************************************************
$Source: /cvs/repositories/openii3/project/java/source/org/openeai/moa/XmlEnterpriseObjectImpl.java,v $
$Revision: 1.39 $
*******************************************************************************/

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

import java.io.ByteArrayInputStream;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Properties;

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

import org.openeai.xml.*;
import org.openeai.config.*;
import org.openeai.layouts.*;
import org.openeai.moa.objects.testsuite.TestId;

/**
* This is the ancestor class of our "xml aware" objects inclued in the
* Message Object API (MOA).  This includes both "message/jms aware" objects like
* BasicPerson and child objects that are "xml aware" but not "message/jms aware"
* like the Address object which is a child object of BasicPerson.
* <P>
  * @author      Tod Jackson (tod@openeai.org)
  * @author      Steve Wheat (steve@openeai.org)
  * @version     3.0  - 28 January 2003
*/
public class XmlEnterpriseObjectImpl
extends EnterpriseObjectBase implements XmlEnterpriseObject, org.openeai.PubliclyCloneable {

  private EnterpriseLayoutManager m_saveInputLManager = null;
  private EnterpriseLayoutManager m_saveOutputLManager = null;
  private boolean m_validate = false;
  private boolean m_deferInitialization = false;
 
  private Document m_provideDoc=null;
  private Document m_responseDoc=null;
  private Document m_createDoc=null;
  private Document m_updateDoc=null;
  private Document m_deleteDoc=null;
  private Document m_queryDoc=null;
  private Document m_generateDoc=null;
  private Document m_createSyncDoc=null;
  private Document m_deleteSyncDoc=null;
  private Document m_updateSyncDoc=null;
  private Document m_generateSyncDoc=null;

  private String m_provideDocUri=null;
  private String m_responseDocUri=null;
  private String m_createDocUri=null;
  private String m_updateDocUri=null;
  private String m_deleteDocUri=null;
  private String m_queryDocUri=null;
  private String m_generateDocUri=null;
  private String m_createSyncDocUri=null;
  private String m_deleteSyncDocUri=null;
  private String m_updateSyncDocUri=null;
  private String m_generateSyncDocUri=null;

  // Move the following to EnterpriseObject...
//  private MessageSeries m_messageSeries = null;
//  private Predecessor m_predecessor = null;

  private EnterpriseFields m_fields = null;
  public static EnterpriseFields ENTERPRISE_FIELDS = null;

  private HashMap m_inputLayoutManagers = new HashMap();
  private HashMap m_outputLayoutManagers = new HashMap();
    private final static String LIST = "java.util.List";

  public static EnterpriseLayoutManager XML_LAYOUT_MANAGER = null;
  private EnterpriseLayoutManager m_inputLayoutManager = null;
  private EnterpriseLayoutManager m_outputLayoutManager = null;

  private TestId m_testId = null;

  private XmlEnterpriseObject m_baseline = null;

  /**
  *
  **/
  private void setDeferInitialization(boolean defer) {
    m_deferInitialization = defer;
  }
  /**
  *
  **/
  public final boolean deferInitialization() {
    return m_deferInitialization;
  }
 
  /**
   * Sets the baseline object associated to this object.  The baseline object
   * is populated by all objects when that object performs a Query action
   * via the JmsEnterpriseObject.query method.  Then,
   * when updates are performed on the object and an Update-Request/Sync is made on behalf
   * of the object (via the JmsEnterpriseObject.update/updateSync method, it uses the baseline
   * object to populate the DataArea/BaselineData element in the update document.
   * The baseline object remains untouched during the processing on the main object.
   *<P>
   * @param baseline XmlEnterpriseObject the baseline object (e.g. - BasicPerson) that is an
   * image of the object at the time the Query action was performed.
   */
  public final void setBaseline(XmlEnterpriseObject baseline) {
    m_baseline = baseline;
  }
  /**
   * Returns the baseline object associated to this object.  The baseline object
   * is populated by all objects when that object performs a Query action
   * via the JmsEnterpriseObject.query method.  Then,
   * when updates are performed on the object and an Update-Request/Sync is made on behalf
   * of the object (via the JmsEnterpriseObject.update/updateSync method, it uses the baseline
   * object to populate the DataArea/BaselineData element in the update document.
   * The baseline object remains untouched during the processing on the main object.
   *<P>
   * @return XmlEnterpriseObject the baseline object (e.g. - BasicPerson) that is an
   * image of the object at the time of the Query.
   */
  public final XmlEnterpriseObject getBaseline() {
    return m_baseline;
  }

  /**
  * Sets the test id associated to this object.  This is used during testing to correlate
  * a message sent by a particular object to a message consumed by a gateway.  This is
  * related to the OpenEAI Test Suite foundation.
  *<P>
  * @param tId TestId the test id object associated to this object.
  */
  public void setTestId(TestId tId) {
    m_testId = tId;
  }
  /**
  * Returns the test id associated to this object.  This is used during testing to correlate
  * a message sent by a particular object to a message consumed by a gateway.  This is
  * related to the OpenEAI Test Suite foundation.
  *<P>
  * @return  TestId the test id object associated to this object.
  */
  public TestId getTestId() {
    return m_testId;
  }

  /**
   * Constructor
   */
  public XmlEnterpriseObjectImpl() {
  }

  // Move the following to EnterpriseObject...

  /*
  public void setMessageSeries(MessageSeries series) {
    m_messageSeries = series;
  }
  public MessageSeries getMessageSeries() {
    return m_messageSeries;
  }
  public void initializeMessageSeries(String uuidUri) throws XmlEnterpriseObjectException {
    try {
      GenericUuid guuid = new GenericUuid(uuidUri);
      String uuid = guuid.getId();
      MessageSeries mSeries = new MessageSeries();
      mSeries.setMessageSeriesId(uuid);
      mSeries.setMessageSeriesSequence("1");
      setMessageSeries(mSeries);
    }
    catch (Exception e) {
      String errMessage = "Error initializing MessageSeries.  Exception: " + e.getMessage();
      logger.fatal(errMessage);
      throw new XmlEnterpriseObjectException(errMessage, e);
    }
  }

  public void setPredecessor(Predecessor predecessor) {
    m_predecessor = predecessor;
  }
  public Predecessor getPredecessor() {
    return m_predecessor;
  }
  */

  /**
   * Object initialization.  This method initializes the current object with information
   * contained in the MessageObjectConfig passed in.  All XmlEnterpriseObjectImpls
   * inherit this functionality and the init method is called when the AppConfig object
   * is being built for a particular application.  This method will never be called
   * directly from an application.  The call is "behind the scenes".  The values stored in the config
   * object passed in are retreived from the Application Deployment and EnterpriseObjects
   * documents.  This includes configuration information for things like:  Primed Documents,
   * Xml Validation, Enterprise field rules (translation, formats, scrubbing etc.) and
   * Layout management.  See the documentation for the Application Deployment and
   * EnterpriseObjects Xml documents for more information on these items.  More information
   * can also be found in the JavaDoc for the org.openeai.config package.
   *<P>
   * @param mConfig   MessageObjectConfig object loaded with all configuration information
   * relative to this object built from the configuration document.
   *<P>
   * @throws EnterpriseObjectException if errors occur initializing the current MessageObject.
   * @see org.openeai.config.MessageObjectConfig
   * @see org.openeai.config.EnterpriseFields
   */
  public void init(MessageObjectConfig mConfig) throws EnterpriseObjectException {
    Properties props = mConfig.getProperties();
    XmlDocumentReader xmlReader = new XmlDocumentReader();

    setDeferInitialization(new Boolean(props.getProperty("deferInitialization","false")).booleanValue());

    try {
      setCreateDocUri(props.getProperty("create-PrimedXmlDocument",null));
      setCreateSyncDocUri(props.getProperty("createSync-PrimedXmlDocument",null));
      setDeleteDocUri(props.getProperty("delete-PrimedXmlDocument",null));
      setDeleteSyncDocUri(props.getProperty("deleteSync-PrimedXmlDocument",null));
      setGenerateDocUri(props.getProperty("generate-PrimedXmlDocument",null));
      setGenerateSyncDocUri(props.getProperty("generate-PrimedXmlDocument",null));
      setUpdateDocUri(props.getProperty("update-PrimedXmlDocument",null));
      setUpdateSyncDocUri(props.getProperty("updateSync-PrimedXmlDocument",null));
      setQueryDocUri(props.getProperty("query-PrimedXmlDocument",null));
      setProvideDocUri(props.getProperty("provide-PrimedXmlDocument",null));
      setResponseDocUri(props.getProperty("response-PrimedXmlDocument",null));

      // if initialization is deferred, we'll wait until the user makes their
      // first request of a particular document to initialize it.
      if (deferInitialization() == false) {
        setCreateDoc(xmlReader.initializeDocument(getCreateDocUri(), getValidation()));
        setCreateSyncDoc(xmlReader.initializeDocument(getCreateSyncDocUri(), getValidation()));
        setDeleteDoc(xmlReader.initializeDocument(getDeleteDocUri(), getValidation()));
        setDeleteSyncDoc(xmlReader.initializeDocument(getDeleteSyncDocUri(), getValidation()));
        setGenerateDoc(xmlReader.initializeDocument(getGenerateDocUri(), getValidation()));
        setGenerateSyncDoc(xmlReader.initializeDocument(getGenerateSyncDocUri(), getValidation()));
        setUpdateDoc(xmlReader.initializeDocument(getUpdateDocUri(), getValidation()));
        setUpdateSyncDoc(xmlReader.initializeDocument(getUpdateSyncDocUri(), getValidation()));
        setQueryDoc(xmlReader.initializeDocument(getQueryDocUri(), getValidation()));
        setProvideDoc(xmlReader.initializeDocument(getProvideDocUri(), getValidation()));
        setResponseDoc(xmlReader.initializeDocument(getResponseDocUri(), getValidation()));
      }
    }
    catch (XmlDocumentReaderException e) {
      logger.fatal(e.getMessage(), e);
      throw new EnterpriseObjectException(e.getMessage(), e);
    }

    try {
      setValidation(new Boolean(props.getProperty("xmlDocumentValidation","false")).booleanValue());
      setEnterpriseFields((EnterpriseFields)mConfig.getEnterpriseFields().clone());

      // Set a Static Enterprise fields object here as well for use by objects that
      // aren't configured via a config doc?
      // note, the following inclusion of JmsEnterpriseObject is only for backward compatibility
      if ((this instanceof org.openeai.moa.jmsobjects.JmsEnterpriseObject) ||
         (this instanceof org.openeai.moa.ActionableEnterpriseObject)) {
        if (XmlEnterpriseObjectImpl.ENTERPRISE_FIELDS == null) {
            logger.debug("Setting static EnterpriseFields object to be that of " + getClass().getName());
          XmlEnterpriseObjectImpl.ENTERPRISE_FIELDS = (EnterpriseFields)mConfig.getEnterpriseFields().clone();
        }
      }

      setInputLayoutManagers(mConfig.getInputLayoutManagers());
      setInputLayoutManager(mConfig.getInputLayoutManager());      // The default one (first in list).
      setOutputLayoutManagers(mConfig.getOutputLayoutManagers());
      setOutputLayoutManager(mConfig.getOutputLayoutManager());      // The default one (first in list).

      // Set a static Xml Layout manager (input and output) for objects that aren't configured
      // via a config doc.     
      // note, the following inclusion of JmsEnterpriseObject is only for backward compatibility
      if ((this instanceof org.openeai.moa.jmsobjects.JmsEnterpriseObject) ||
         (this instanceof org.openeai.moa.ActionableEnterpriseObject)) {
        if (XmlEnterpriseObjectImpl.XML_LAYOUT_MANAGER == null) {
            logger.debug("Setting static XmlLayoutManager object to be that of " + getClass().getName());
          XmlEnterpriseObjectImpl.XML_LAYOUT_MANAGER = getInputLayoutManager("xml");
        }
      }
    }
    catch (Exception e) {
      throw new EnterpriseObjectException(e.getMessage(), e);
    }
  }

  /**
  * This method sets the EnterpriseFields and XML layout manager information on the child object
  * passed in to be that of the current object.  This is a convenience method that can
  * be used by Parent objects when returning a child object from a "getter" method.  Since
  * the child objects will not be initialized with this information at start up, this
  * eliminates the need to application developers to do this programmatically since
  * it can be done automatically in the getter methods.
  *<P>
  * Example:  The BasicPerson object has a child object in it called Name.  The
  * name object is another XmlEnterpriseObjectImpl.  When the getName() method is
  * called on BasicPerson, this method is called to "give" the Name object being returned
  * the EnterpriseFields and XmlLayout manager associated to the BasicPerson.  Since
  * the BasicPerson's EnterpriseObjects XML document will also have to include the Name
  * object's definition, the Name object returned by the BasicPerson.getName() method will
  * have what it needs to function properly and no action will be required by the developers.
  *<P>
  * @param childXeo XmlEnterpriseObjectImpl the child object being initialized.
  */
  public final void initializeChild(XmlEnterpriseObject childXeo) {
    // set the enterprsiefields and xmllayout manager on the object
    // we're returning to that of this parent object.  This way,
    // the object returned will be all set up for buildObjectFromInput etc.
    if (childXeo.getEnterpriseFields() != null) {
      try {
  //      childXeo.setEnterpriseFields((EnterpriseFields)getEnterpriseFields().clone());
        childXeo.setEnterpriseFields(getEnterpriseFields());
      }
      catch (Exception e) {
        childXeo.setEnterpriseFields(getEnterpriseFields());
      }
    }

    // this way only initialized the child with the current XML Layout Manager.
    // this may not be enough in some cases (where there are is more than one layout
    // manager in use).
    /* 
    XmlLayout inXmlLayout = (XmlLayout)getInputLayoutManager("xml");
    XmlLayout outXmlLayout = (XmlLayout)getOutputLayoutManager("xml");
    childXeo.getInputLayoutManagers().put("xml",inXmlLayout);
    childXeo.setInputLayoutManager(inXmlLayout);
    childXeo.getOutputLayoutManagers().put("xml",outXmlLayout);
    childXeo.setOutputLayoutManager(outXmlLayout);
    */

    // this is the way it should be, so we'll be sure to pass along
    // ALL layout managers and not just the XML one.
    childXeo.setInputLayoutManager(getInputLayoutManager());
    childXeo.setInputLayoutManagers(getInputLayoutManagers());
    childXeo.setOutputLayoutManager(getOutputLayoutManager());
    childXeo.setOutputLayoutManagers(getOutputLayoutManagers());
  }
 
  /**
   * Recursively checks the contents of the object and true if it contains any data.  Otherwise,
   * it returns false.  For example, if the BasicPerson/Name/FirstName variable
   * has data in it, this method will return true.  If no instance variables, or child
   * objects have data in them, it returns false.
   *<P>
   * @return boolean an indicator specifying whether or not the object is empty.
   *<P>
   * @throws XmlEnterpriseObjectException if any errors occur when determining
   * if the object empty.
   */
  public boolean isEmpty() throws XmlEnterpriseObjectException {

    boolean isDate = isDate();
    Method[] methods = getClass().getDeclaredMethods();
    java.util.ArrayList m = new java.util.ArrayList();
    for (int i=0; i<methods.length; i++) {
      m.add(methods[i]);
    }
    if (isDate) {
      Class superClass = getClass().getSuperclass();
      String superClassName = superClass.getName();
      String superObjectName = superClassName.substring(superClassName.lastIndexOf('.') + 1);
      if (superObjectName.equals("Date") || superObjectName.equals("Datetime")) {
        // it extends the OpenEAI Date/Datetime object.
        Method[] superClassMethods = superClass.getDeclaredMethods();
        for (int i=0; i<superClassMethods.length; i++) {
          m.add(superClassMethods[i]);
        }
      }
    }

    for (int i=0; i<m.size(); i++) {
      Method getter = (Method)m.get(i);
      String methodName = getter.getName();

      // Ignore the getType method on Date objects only.
      if (methodName.equals("getType") && isDate) {
        continue;
      }

      // Ignore getter methods that take parms.
      if (getter.getParameterTypes().length > 0) {
        continue;
      }

      if (methodName.indexOf("get") == 0) {
        // If we find a getter method, we need to call it.  If it's a String
        // we need to check to see if it's length is greater than zero, if
        // if is, return true.
        // If it's an XmlEnterpriseObjectImpl, we need to return the isEmpty
        // method on it.
        // If it's a List, we need to check its length and if it's greater
        // than zero return true;
        String fieldName = methodName.substring(methodName.indexOf("get")+3);
        logger.debug("[isEmpty] Calling getter method for " + fieldName);

        try {
          Object obj = getter.invoke(this, new Object[] {});
          if (obj instanceof String) {
            String retVal = (String)obj;
            if (retVal != null) {
              if (retVal.length() > 0) {
                logger.debug("[isEmpty-String] Found data in " + fieldName);
                return false;
              }
            }
          }
          else if (obj instanceof XmlEnterpriseObject) {
            XmlEnterpriseObject xeo = (XmlEnterpriseObject)obj;
            boolean xeoIsEmpty = xeo.isEmpty();
            if (xeoIsEmpty == false) {
              logger.debug("[isEmpty-XmlEnterpriseObjectImpl] Found data in " + fieldName);
              return false;
            }
          }
          else if (obj instanceof java.util.List) {
            java.util.List v = (java.util.List)obj;
            if (v.size() > 0) {
              logger.debug("[isEmpty-List] Found data in " + fieldName);
              return false;
            }
          }
        }
        catch (InvocationTargetException e) {
          String errMessage = "Couldn't invoke method: get" + fieldName + " on object " +
                       getClass().getName() + "  Exception: " + e.getMessage();
          throw new XmlEnterpriseObjectException(errMessage, e);
        }
        catch (IllegalAccessException e1) {
          String errMessage = "Couldn't access method: get" + fieldName + " on object " +
                       getClass().getName() + "  Exception: " + e1.getMessage();
          throw new XmlEnterpriseObjectException(errMessage, e1);
        }
      }
    }
    return true;
  }

  /**
   * Checks to see if this object is a "Date/Datetime" object.  This is because Dates and Datetimes
   * contain special constructors that indicate the type of Date/Datetime being built and
   * several other foundation components need to determine if an object being dealt with
   * is one of those Date/Datetime objects.
   *
   * @return  boolean
   *
   */
  public final boolean isDate() {
    String className = getClass().getName();
    String objectName = className.substring(className.lastIndexOf('.') + 1);
    if (objectName.equals("Date") || objectName.equals("Datetime")) {
      return true;
    }
    return false;
  }
  private boolean isDate(String className) {
    String objectName = className.substring(className.lastIndexOf('.') + 1);
    if (objectName.equals("Date") || objectName.equals("Datetime")) {
      return true;
    }
    return false;
  }

  public Object clone() throws CloneNotSupportedException {
    try {
      return deepCopy();
    }
    catch (Exception e) {
      throw new CloneNotSupportedException(e.getMessage());
    }
  }
  /**
   * Performs a recursive field for field copy of the current Object and returns the result.
   * Any object found that supports the "clone" method is cloned.  Since all simple fields within
   * an XmlEnterpriseObjectImpl are ultimately Strings, the resulting object is in fact a new object
   * because the copy is recursive.
   *
   * @return  XmlEnterpriseObject a "deep" copy of the object.
   *
   */
  private XmlEnterpriseObject deepCopy() throws EnterpriseObjectException {
    // Create a new XmlEnterpriseObjectImpl,
    // Go through all getter methods of the current object, and call the setter
    // methods on the new object...

    // Save this value because we're going to have to potentially set initial values to null or blank
    // on fields that aren't allowed to be null or blank when the message is produced.  Therefore,
    // we'll set this value to false while we do the copy and then set it back to whatever the value
    // was initially when we're done.

    String className = this.getClass().getName();
    EnterpriseFields xeoFields = null;
     boolean existingIgnoreValidation = getEnterpriseFields().ignoreValidation();
    XmlEnterpriseObject newXeo = null;
    try {
      xeoFields = (EnterpriseFields)getEnterpriseFields().clone();
      if (xeoFields == null) {
        throw new EnterpriseObjectException("No EnterpriseFields object found in this " + className + ".  Cannot continue!");
      }
      java.lang.Class obj = java.lang.Class.forName(className);
      newXeo = (XmlEnterpriseObject)obj.newInstance();
      newXeo.setEnterpriseFields((EnterpriseFields)getEnterpriseFields().clone());
      newXeo.getEnterpriseFields().setIgnoreValidation(true);
      logger.debug("[deepCopy] Instantiated a " + newXeo.getClass().getName());
    }
    catch (Exception e) {
      throw new EnterpriseObjectException("Error instantiating a " + className + "  Exception: " + e.getMessage(), e);
    }

    Method[] methods = newXeo.getClass().getMethods();
    for (int i=0; i<methods.length; i++) {
      Method setter = methods[i];
      String methodName = setter.getName();
      Class[] parmTypes = setter.getParameterTypes();

      if (parmTypes.length == 1) {
        if (methodName.indexOf("set") == 0) {
          // If we find a setter method, we need to call the corresponding getter
          // method on the new XmlEnterpriseObject we created passing the value
          // returned from the getter method from the current object.
          String fieldName = methodName.substring(methodName.indexOf("set")+3);
          Method getter = null;
          logger.debug("[deepCopy] Calling setter method for " + fieldName);

          try {
            getter = newXeo.getClass().getMethod("get" + fieldName, new Class[] {});
            Class c = getter.getReturnType();
            // Have to create a new List if the return type is List, cloning isn't enough
            // So, we'll create a new list to be used in the call to the setter method
            // We'll populate that list with values from the getter method (one at a time).
            // If the objects stored in the list are of type XmlEnterpriseObjectImpl
            // we'll call the deepCopy method on each one of those objects before adding
            // them to the new list.
            if (c == java.util.List.class) {
              java.util.List getterList = (java.util.List)getter.invoke(this, new Object[] {});
              if (getterList != null) {
                java.util.List setterList = java.util.Collections.synchronizedList(new java.util.ArrayList());
                for (int j=0; j<getterList.size(); j++) {
                  Object vObj = getterList.get(j);
                  if (vObj instanceof XmlEnterpriseObject) {
                    XmlEnterpriseObject vXeo = (XmlEnterpriseObject)vObj;
                    setterList.add((XmlEnterpriseObject)vXeo.clone());
                  }
                  else {
                    // The only other type of objects that should exist in our lists (for now anyway)
                    // besides XmlEnterpriseObjectImpls are Strings, therefore, we'll just cast it
                    // here to a String to create another "copy" of the string contained in the list
                    // we're copying.

                    // New - 4/4/2002 to determine "growing" problem
                    String vStringObj = (String)vObj;
                    setterList.add(vStringObj);
                    // End New - 4/4/2002
                  }
                }
                setter.invoke(newXeo, new Object[] {setterList});
              }
            }
            else {
              // Either do a clone or just call the getter method.
              Method cloneMethod = null;
              try {
                cloneMethod = c.getMethod("clone", new Class[] {});
                newXeo.getEnterpriseFields().setIgnoreValidation(true);
                if (isDate(c.getName())) {
                  org.openeai.PubliclyCloneable gObj = (org.openeai.PubliclyCloneable)getter.invoke(this, new Object[] {});
                  if (gObj != null) {
                    Object cObj = gObj.clone();
                    setter.invoke(newXeo, new Object[] {cObj});
                  }
                }
                else {
                   setter.invoke(newXeo, new Object[] {cloneMethod.invoke(getter.invoke(this, new Object[] {}), new Object[] {})});
                }
                logger.debug("Called the clone method for " + c.getName() + " on field: " + fieldName);
              }
              catch (Exception e) {
                logger.debug("No clone method found for " + c.getName());
              }
              if (cloneMethod == null) {
                if (getter.invoke(this, new Object[] {}) != null) {
                  newXeo.getEnterpriseFields().setIgnoreValidation(true);
                  setter.invoke(newXeo, new Object[] {getter.invoke(this, new Object[] {})});
                }
                else {
                  logger.debug("get" + fieldName + " method returned a null.");
                }
              }
            }
          }
          catch (NoSuchMethodException exc) {
            logger.debug("Couldn't find method: get" + fieldName + " on object " +
                         className + " ignoring..."  );
          }
          catch (InvocationTargetException e) {
            throw new EnterpriseObjectException("Error invoking method: get" + fieldName +
              " on object " + className + "  Exception: " + e.getMessage(), e);
          }
          catch (IllegalAccessException e1) {
            throw new EnterpriseObjectException("Error invoking method: get" + fieldName +
              " on object " + className + "  Exception: " + e1.getMessage(), e1);
          }
          catch (Exception e2) {
            throw new EnterpriseObjectException("Error cloning object " +
              className + "  Exception: " + e2.getMessage(), e2);
          }
        }
      }
    }
    // before we return the deep copy, re-set the enterprise fields object back
    // to its original setting so translation/validation will be turned back on or off...
    newXeo.getEnterpriseFields().setIgnoreValidation(existingIgnoreValidation);
    return newXeo;
  }

  // Move the following to EnterpriseObject...

  /**
   * Sets the EnterpriseFields object associated with this object.
   * For information on the EnterpriseFields object, refer to the JavaDoc
   * for the org.openeai.config package.  This is called
   * when the object is initialized.  The EnterpriseFields object is built
   * based on information found in the EnterpriseObjects document.
   *<P>
   * This information is specified in the MessageObjectConfig XML Element in the deployment
   * documents and is passed to this object during initialization by the MessageObjectConfig
   * Java object.
   *<P>
   * @param fields EnterpriseFields the EnterpriseFields object that will be used by this
   * object to validate/format data passed to setter methods on this object.
   * @see org.openeai.config.EnterpriseFields
   */
  public final void setEnterpriseFields(EnterpriseFields fields) {
    m_fields = fields;
  }
  /**
   * Returns the EnterpriseFields object associated with this object.
   * For information on the EnterpriseFields object, refer to the JavaDoc
   * for the org.openeai.config package.
   *<P>
   * @return EnterpriseFields the EnterpriseFields object that will be used by this
   * object to validate/format data passed to setter methods on this object.
   * @see org.openeai.config.EnterpriseFields
   *
   */
  public final EnterpriseFields getEnterpriseFields() {
    /*
    return m_fields;
    */
    if (m_fields != null) {
      logger.debug("Using NORMAL enterprise fields object for " + getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1));
      if (m_fields.getEODocRoot() == null) {
        // the EnterpriseFields object hasn't been initialized,
        // it was deferred when the object was initialized.
        // we need to:
        // - parse the EO document
        // - initialize the m_fields object
        logger.debug("EnterpriseFields object is not initialized for the " +
          getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1) +
          " object.  Initializing it for it's first use.");
        try {
          XmlDocumentReader xmlReader = new XmlDocumentReader();               
          m_fields.init(xmlReader.initializeDocument(m_fields.getEnterpriseObjectsUri(),getValidation()));
        }
        catch (Exception e) {
          logger.fatal(e.getMessage(), e);
        }
        return m_fields;
      }
      else {
        return m_fields;
      }
    }
//    return m_fields;
    else {
      // return static enterprise fields object?

      // EVENTUALLY, this needs to go away.
     
      logger.debug("Using STATIC enterprise fields object for " + getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1));
      try {
        if (ENTERPRISE_FIELDS.getEODocRoot() == null) {
          // the static EnterpriseFields object hasn't been initialized,
          // it was deferred when the object was initialized.
          // we need to:
          // - parse the EO document
          // - initialize the m_fields object
          logger.debug("STATIC EnterpriseFields object is not initialized for the " +
            getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1) +
            " object.  Initializing it for it's first use.");
          try {
            XmlDocumentReader xmlReader = new XmlDocumentReader();               
            ENTERPRISE_FIELDS.init(xmlReader.initializeDocument(ENTERPRISE_FIELDS.getEnterpriseObjectsUri(),getValidation()));
          }
          catch (Exception e) {
            logger.fatal(e.getMessage(), e);
          }
        }
        m_fields = (EnterpriseFields)ENTERPRISE_FIELDS.clone();
      }
      catch (Exception e) {
        logger.warn("Error cloning static enterprise fields object.  Returning reference to static EnterpriseFields object.  Exception: " + e.getMessage());
        m_fields = ENTERPRISE_FIELDS;
      }
      return m_fields;
    }
  }
  /**
  * Uses the EnterpriseFields object associated to this object to convert the application
  * value passed in to the enterprise value.
  *<P>
  * @return String the enterprise value that corresponds to the rules for the field
  * @param fieldName String the name of the field for which the conversion is being performed
  * @param appValue String the value being converted.
  * @see org.openeai.config.EnterpriseFields
  */
  protected String getEnterpriseValue(String fieldName, String appValue)
  throws EnterpriseFieldException {

    String className = getClass().getName();
    String objectName = "";
    if (isDate()) {
      try {
        Method getter = getClass().getMethod("getType", new Class[] {});
        objectName = (String)getter.invoke(this, new Object[] {});
      }
      catch (Exception e) {
        String errMessage = "Couldn't invoke method: getType() on object " +
               getClass().getName() + "  Exception: " + e.getMessage();
        throw new EnterpriseFieldException(errMessage, e);
      }
    }
    else {
      objectName = className.substring(className.lastIndexOf('.') + 1);
    }
    EnterpriseFields fields = getEnterpriseFields();
    if (fields == null || fields.getFieldsForObject(objectName).size() == 0) {
      // this means this object doesn't have an EnterpriseFields object
      // associated with it yet.  This is okay because the only time it really
      // matters is when an EnterpriseMessage is built.  At that time,
      // this object will have one associated with it because it will get
      // set by the "message action" methods in JmsEnterpriseObject and
      // in any build...Message methods...
      logger.debug("No fields found for object: " + objectName);
      return appValue;
    }
    String retValue = "";
    retValue = fields.getEnterpriseValue(objectName, fieldName, appValue);
    logger.debug("[XmlEnterpriseObjectImpl] Enterprise value for " +
                 objectName + "/" + fieldName + " is " + retValue);
    return retValue;
  }

  /**
  * Uses the EnterpriseFields object associated to this object to convert the enterprise
  * value passed in to the application specific value based on rules found in the EnterpriseObjects XML
  * document associated to the object for the application name passed in.
  *<P>
  * @return String the applicaiton specific value that corresponds to the rules for the field
  * @param appName String the name of the applicatoin for which the conversion is being performed
  * @param fieldName String the name of the field for which the conversion is being performed
  * @param enterpriseValue String the value being converted.
  * @see org.openeai.config.EnterpriseFields
  */
  protected String getApplicationValue(String appName, String fieldName, String enterpriseValue)
  throws EnterpriseFieldException {

    if (enterpriseValue == null) { enterpriseValue = ""; }
    String className = getClass().getName();
    String objectName = "";
    if (isDate()) {
      try {
        Method getter = getClass().getMethod("getType", new Class[] {});
        objectName = (String)getter.invoke(this, new Object[] {});
      }
      catch (Exception e) {
        String errMessage = "Couldn't invoke method: getType() on object " +
               getClass().getName() + "  Exception: " + e.getMessage();
        throw new EnterpriseFieldException(errMessage, e);
      }
    }
    else {
      objectName = className.substring(className.lastIndexOf('.') + 1);
    }
    EnterpriseFields fields = getEnterpriseFields();
    if (fields == null || fields.getFieldsForObject(objectName).size() == 0) {
      // this means this object doesn't have an EnterpriseFields object
      // associated with it yet.  This is okay because the only time it really
      // matters is when an EnterpriseMessage is built.  At that time,
      // this object will have one associated with it because it will get
      // set by the "message action" methods in JmsEnterpriseObject and
      // in any build...Message methods...
      logger.debug("No fields found for object: " + objectName);
      return enterpriseValue;
    }
    String retValue = "";
    retValue = fields.getApplicationValue(objectName, appName, fieldName, enterpriseValue);
    logger.debug("[XmlEnterpriseObjectImpl] Application value for " +
                 objectName + "/" + fieldName + " is " + retValue + " for application " + appName);
    return retValue;
  }

  // Move the following to EnterpriseObject...
  // EnterpriseLayoutManager methods
  private void initializeLayoutManager(EnterpriseLayoutManager elm) {
    try {
      XmlDocumentReader xmlReader = new XmlDocumentReader();               
      elm.init(elm.getLayoutManagerName(),
        xmlReader.initializeDocument(elm.getEnterpriseObjectsUri(),getValidation()));
    }
    catch (Exception e) {
      logger.fatal(e.getMessage(), e);
    }
  }
  /**
   * Returns a HashMap containing all Input Layout managers associated to
   * this object.  These are all the input layout managers that may be used by
   * this object.  Since objects may support several different layout managers
   * that are used to build themselves, this is necessary.
   *<P>
   * @return HashMap the list of Input Layout managers that may be used by this
   * object.
   */
  public final HashMap getInputLayoutManagers() {
    return m_inputLayoutManagers;
  }
  public final void setInputLayoutManagers(HashMap iManagers) {
    m_inputLayoutManagers = iManagers;
  }
  public final void addInputLayoutManager(String type, EnterpriseLayoutManager iLayout) {
    m_inputLayoutManagers.put(type, iLayout);
  }
  public final void setInputLayoutManager(EnterpriseLayoutManager elm) {
    m_inputLayoutManager = elm;
  }
  /**
   * Returns this object's currently assigned Input Layout manager.  If no
   * current input layout manager exists, it returns the XmlLayout manager that all
   * objects must have.
   *<P>
   * @return EnterpriseLayoutManager the currently assigned input layout manager.
   * if no input layout manager has been assigned, it returns the XmlLayout manager.
   */
  public final EnterpriseLayoutManager getInputLayoutManager() {
    if (m_inputLayoutManager == null) {
      // check to make sure the static XML Layout manager has been initialized
      // if not, initialize it.
      if (XML_LAYOUT_MANAGER.getLayoutRoot() == null) {     
        logger.debug("STATIC XML_LAYOUT_MANAGER object is not initialized for the " +
          getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1) +
          " object.  Initializing it for it's first use (input).");
        initializeLayoutManager(XML_LAYOUT_MANAGER);
      }
      return XML_LAYOUT_MANAGER;
    }
    // check to make sure the Layout manager has been initialized
    // if not, initialize it.
    if (m_inputLayoutManager.getLayoutRoot() == null) {     
      logger.debug("Input LayoutManager object is not initialized for the " +
        getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1) +
        " object.  Initializing it for it's first use.");
      initializeLayoutManager(m_inputLayoutManager);
    }
   
    return m_inputLayoutManager;
  }
  /**
   * Returns an Input Layout manager for this object of a specified type.  (e.g. - "xml", "extract").
   * If no layout manager of the specified type exists, it returns null.
   *<P>
   * @param type String the type of input layout manager ("xml", "extract" etc.).
   *<P>
   * @return EnterpriseLayoutManager the input layout manager that is the type
   * specified as a parm.
   */
  public final EnterpriseLayoutManager getInputLayoutManager(String type) {
    if (m_inputLayoutManagers.containsKey(type)) {
      // check to make sure the Layout manager has been initialized
      // if not, initialize it before returning.
      EnterpriseLayoutManager elm = (EnterpriseLayoutManager)m_inputLayoutManagers.get(type);
      if (elm.getLayoutRoot() == null) {     
        logger.debug("Input LayoutManager object of type '" + type + "' is not initialized for the " +
          getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1) +
          " object.  Initializing it for it's first use.");
        initializeLayoutManager(elm);
      }
      return elm;
    }
    if (type.equalsIgnoreCase("xml")) {
      logger.debug("No Input XmlLayout manager found for object, " + getClass().getName() + " using static XmlLayout manager.");
      if (XML_LAYOUT_MANAGER != null) {
        // check to make sure the Layout manager has been initialized
        // if not, initialize it before returning.
        if (XML_LAYOUT_MANAGER.getLayoutRoot() == null) {     
          logger.debug("STATIC Input LayoutManager object of type '" + type + "' is not initialized for the " +
            getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1) +
            " object.  Initializing it for it's first use.");
          initializeLayoutManager(XML_LAYOUT_MANAGER);
        }
        return XML_LAYOUT_MANAGER;
      }
    }
    logger.fatal("Couldn't find an Input Layout Manager of type " + type + " for " + getClass().getName());
    return null;
  }

  /**
   * Returns a HashMap containing all Output Layout managers associated to
   * this object.  These are all the output layout managers that may be used by
   * this object.  Since objects may support several different layout managers
   * that are used to serialize themselves, this is necessary.
   *<P>
   * @return HashMap the list of Output Layout managers that may be used by this
   * object.
   */
  public final HashMap getOutputLayoutManagers() {
    return m_outputLayoutManagers;
  }
  public final void setOutputLayoutManagers(HashMap oManagers) {
    m_outputLayoutManagers = oManagers;
  }
  public final void addOutputLayoutManager(String type, EnterpriseLayoutManager oLayout) {
    m_outputLayoutManagers.put(type, oLayout);
  }
  public final void setOutputLayoutManager(EnterpriseLayoutManager elm) {
    m_outputLayoutManager = elm;
  }
  /**
   * Returns this object's currently assigned Output Layout manager.  If no
   * current output layout manager exists, it returns the XmlLayout manager that all
   * objects must have.
   *<P>
   * @return EnterpriseLayoutManager the currently assigned output layout manager.
   * if no output layout manager has been assigned, it returns the XmlLayout manager.
   */
  public final EnterpriseLayoutManager getOutputLayoutManager() {
    if (m_outputLayoutManager == null) {
      // check to make sure the Layout manager has been initialized
      // if not, initialize it before returning.
      if (XML_LAYOUT_MANAGER.getLayoutRoot() == null) {     
        logger.debug("STATIC OutputLayoutManager object is not initialized for the " +
          getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1) +
          " object.  Initializing it for it's first use.");
        initializeLayoutManager(XML_LAYOUT_MANAGER);
      }
      return XML_LAYOUT_MANAGER;
    }
    // check to make sure the Layout manager has been initialized
    // if not, initialize it before returning.
    if (m_outputLayoutManager.getLayoutRoot() == null) {     
      logger.debug("Output LayoutManager object is not initialized for the " +
        getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1) +
        " object.  Initializing it for it's first use.");
      initializeLayoutManager(m_outputLayoutManager);
    }
    return m_outputLayoutManager;
  }
  /**
   * Returns an Output Layout manager for this object of a specified type.  (e.g. - "xml", "extract").
   * If no layout manager of the specified type exists, it returns null.
   *<P>
   * @param type String the type of output layout manager ("xml", "extract" etc.).
   *<P>
   * @return EnterpriseLayoutManager the output layout manager that is the type
   * specified as a parm.
   */
  public final EnterpriseLayoutManager getOutputLayoutManager(String type) {
    if (m_outputLayoutManagers.containsKey(type)) {
      // check to make sure the Layout manager has been initialized
      // if not, initialize it before returning.
      EnterpriseLayoutManager elm = (EnterpriseLayoutManager)m_outputLayoutManagers.get(type);
      if (elm.getLayoutRoot() == null) {     
        logger.debug("Output LayoutManager object of type '" + type + "' is not initialized for the " +
          getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1) +
          " object.  Initializing it for it's first use.");
        initializeLayoutManager(elm);
      }
      return elm;
    }
    if (type.equalsIgnoreCase("xml")) {
      logger.debug("No Output XmlLayout manager found for object, " + getClass().getName() + " using static XmlLayout manager.");
      if (XML_LAYOUT_MANAGER != null) {
        // check to make sure the Layout manager has been initialized
        // if not, initialize it before returning.
        if (XML_LAYOUT_MANAGER.getLayoutRoot() == null) {     
          logger.debug("STATIC Output LayoutManager object of type '" + type + "' is not initialized for the " +
            getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1) +
            " object.  Initializing it for it's first use.");
          initializeLayoutManager(XML_LAYOUT_MANAGER);
        }
        return XML_LAYOUT_MANAGER;
      }
    }
    logger.fatal("Couldn't find an Output Layout Manager of type " + type + " for " + getClass().getName());
    return null;
  }

  /**
   * Using the currently assigned input layout manager, this method
   * takes the input passed in and builds the object from that input.
   * For example, if the data passed in is a BasicPerson XML Element, and
   * the current inputLayoutManager is the XmlLayout manager, it will ask
   * the layout manager to build the BasicPerson object from that element.
   * The layout manager will then take the data in the element and put it into
   * the appropriate instance variables (via object getter/setter methods).  While
   * it's doing that, the input data will be validated based on business rules
   * found in the EnterpriseFields object (built from EnterpriseObjects.xml)
   * <P>
   * Additionally, if the data passed in is "application specific" data (like codes)
   * this data will be converted to Enterprise Values based on Translation information
   * also obtained from the EnterpriseObjects.xml document.
   *<P>
   * This method (along with buildOutputFromObject and the Layout Manager infrastructure)
   * allows us to generalize the building our message objects so we don't have to
   * put all of that logic in the objects themselves.  We just implement new Layout Managers
   * and associate those layouts to the objects.  All objects have an Xml Layout Manager
   * associated to them that is derived from the EnterpriseObjects.xml document.
   *<P>
   * @param input Object the data that will be used to build the object.
   * e.g. - Element, String etc.
   *<P>
   * @throws EnterpriseLayoutException.  If an error occurs building the object
   * from the data passed in.
   */
  public final void buildObjectFromInput(Object input) throws EnterpriseLayoutException {
    if (getInputLayoutManager() == null) {
      throw new EnterpriseLayoutException("INPUT LAYOUT MANAGER IS NULL for object " + getClass().getName());
    }
    getInputLayoutManager().buildObjectFromInput(input, this);
  }

  /**
   * Using the currently assigned output layout manager, this method
   * uses the current contents of the object and builds an output object as
   * implemented by the layout manager.
   * For example, if the object is a BasicPerson, and
   * the current outputLayoutManager is the XmlLayout manager, it will ask
   * the layout manager to build the BasicPerson XML Element from BasicPerson object.
   * The layout manager will then retrieve the data from the BasicPerson object
   * via object getter methods and build an Element from the data.  While
   * it's doing that, the object will be validated based on business rules
   * found in the EnterpriseFields object (built from EnterpriseObjects.xml)
   *<P>
   * This method (along with buildInputFromObject and the Layout Manager infrastructure)
   * allows us to generalize the serialization our message objects so we don't have to
   * put all of that logic in the objects themselves.  We just implement new Layout Managers
   * and associate those layouts to the objects.  All objects have an Xml Layout Manager
   * associated to them that is derived from the EnterpriseObjects.xml document.
   *<P>
   * @return  Object the data that will be built from the object.  The calling applicatons
   * will cast this object to the appropriate thing. e.g. - Element, String etc.
   *<P>
   * @throws EnterpriseLayoutException.  If an error occurs building the output
   * from the object.
   */
  public final Object buildOutputFromObject() throws EnterpriseLayoutException {
    if (getOutputLayoutManager() == null) {
      throw new EnterpriseLayoutException("OUTPUT LAYOUT MANAGER IS NULL for object " + getClass().getName());
    }
    return getOutputLayoutManager().buildOutputFromObject(this);
  }
  /**
   * Using the currently assigned output layout manager, this method
   * uses the current contents of the object and builds an output object as
   * implemented by the layout manager for the specified application name.
   * For example, if the object is a BasicPerson, and
   * the current outputLayoutManager is the ExtractLayout manager, it will ask
   * the layout manager to build an extract line with application specific values
   * using the contents of the BasicPerson object.  This allows us to "reverse translate"
   * our enterprise values to application specific values (like codes etc.)
   * The information related to these translations can be found in the EnterpriseObjects.xml document.
   *<P>
   * This method (along with buildInputFromObject and the Layout Manager infrastructure)
   * allows us to generalize the serialization our message objects so we don't have to
   * put all of that logic in the objects themselves.  We just implement new Layout Managers
   * and associate those layouts to the objects.  All objects have an Xml Layout Manager
   * associated to them that is derived from the EnterpriseObjects.xml document.
   *<P>
   * @return  Object the data that will be built from the object.  The calling applicatons
   * will cast this object to the appropriate thing. e.g. - Element, String etc.
   *<P>
   * @throws EnterpriseLayoutException.  If an error occurs building the output
   * from the object.
   */
  public final Object buildOutputFromObject(String appName) throws EnterpriseLayoutException {
    if (getOutputLayoutManager() == null) {
      throw new EnterpriseLayoutException("OUTPUT LAYOUT MANAGER IS NULL for object " + getClass().getName());
    }
    return getOutputLayoutManager().buildOutputFromObject(this, appName);
  }

  /**
   * This method allows application developers to build an object from
   * a XML String representation of an object that was previously converted
   * to an XML String via the toXmlString() method.  This method basically
   * uses the "xml" inputLayoutManager to build the object from an Element that
   * gets created out of the String passed in.  This is so developers don't have to
   * convert the String to an element themselves (as a convenience).  They just
   * have to pass the String and this method takes care of converting it to an Element
   * and asking the layout manager to build the object from that element.
   *<P>
   * @param theString String the XML String that will be used to build the object.
   *<P>
   * @throws XmlEnterpriseObjectException.  If an error occurs building the object
   * from the data passed in.
   */
  public final void buildObjectFromXmlString(String theString) throws XmlEnterpriseObjectException {
    if (theString == null || theString.length() == 0) {
      logger.warn("Can't build the object from the blank or null string passed in.");
      return;
    }
    try {
      XmlDocumentReader xmlReader = new XmlDocumentReader();
      Document objectDoc = xmlReader.initializeDocument(new ByteArrayInputStream(theString.getBytes()), false);
      Element eObject = objectDoc.getRootElement();
      EnterpriseLayoutManager saveInputLManager = null;
      saveInputLManager = getInputLayoutManager();
      EnterpriseLayoutManager xmlInputLayoutManager = getInputLayoutManager("xml");
      if (xmlInputLayoutManager == null) {
        throw new XmlEnterpriseObjectException("Could not find an XML Input Layout Manager for object " + getClass().getName());
      }
      setInputLayoutManager(xmlInputLayoutManager);
      buildObjectFromInput(eObject);
      setInputLayoutManager(saveInputLManager);
    }
    catch (Exception e) {
      String errMessage = "Unknown exception occurred building object " +
                   getClass().getName() + " from an XML String.  String is: \n" + theString + "\n\n" +
                   "Exception: " + e.getMessage();
      throw new XmlEnterpriseObjectException(errMessage, e);
    }
  }

  // document methods
  public final Document getCreateDoc() {
    if (m_createDoc != null) {
      return(Document)m_createDoc.clone();
    }
    else {
      if (getCreateDocUri() != null) {
        try {
          XmlDocumentReader xmlReader = new XmlDocumentReader();
          logger.debug("Primed 'Create' document initialization was deferred.  Initializing for first use.");
          setCreateDoc(xmlReader.initializeDocument(getCreateDocUri(), getValidation()));
          return(Document)m_createDoc.clone();
        }
        catch (Exception e) {
          logger.fatal(e.getMessage(), e);
        }
      }
      return null;
    }
  }

  /**
  * Returns the primed create XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Create-Request primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @return String the Create-Request primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final String getCreateDocUri() {
    return m_createDocUri;
  }
  /**
  * Sets the primed create XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Create-Request primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @param uri String the Create-Request primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final void setCreateDocUri(String uri) {
    m_createDocUri = uri;
  }

  public Document getProvideDoc() {
    if (m_provideDoc != null) {
      return(Document)m_provideDoc.clone();
    }
    else {
      if (getProvideDocUri() != null) {
        try {
          XmlDocumentReader xmlReader = new XmlDocumentReader();
          logger.debug("Primed 'Provide' document initialization was deferred.  Initializing for first use.");
          setProvideDoc(xmlReader.initializeDocument(getProvideDocUri(), getValidation()));
          return(Document)m_provideDoc.clone();
        }
        catch (Exception e) {
          logger.fatal(e.getMessage(), e);
        }
      }
      return null;
    }
  }
  /**
  * Returns the primed Provide-Reply XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Provide-Reply primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @return String the Provide-Reply primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final String getProvideDocUri() {
    return m_provideDocUri;
  }
  /**
  * Sets the primed Provide-Reply XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Provide-Reply primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @param uri String the Provide-Reply primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final void setProvideDocUri(String uri) {
    m_provideDocUri = uri;
  }

  public Document getResponseDoc() {
    if (m_responseDoc != null) {
      return(Document)m_responseDoc.clone();
    }
    else {
      if (getResponseDocUri() != null) {
        try {
          XmlDocumentReader xmlReader = new XmlDocumentReader();
          logger.debug("Primed 'Response' document initialization was deferred.  Initializing for first use.");
          setResponseDoc(xmlReader.initializeDocument(getResponseDocUri(), getValidation()));
          return(Document)m_responseDoc.clone();
        }
        catch (Exception e) {
          logger.fatal(e.getMessage(), e);
        }
      }
      return null;
    }
  }
  /**
  * Returns the primed Response-Reply XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Response-Reply primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @return String the Response-Reply primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final String getResponseDocUri() {
    return m_responseDocUri;
  }
  /**
  * Sets the primed Response-Reply XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Response-Reply primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @param uri String the Response-Reply primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final void setResponseDocUri(String uri) {
    m_responseDocUri = uri;
  }

  public final Document getDeleteDoc() {
    if (m_deleteDoc != null) {
      return(Document)m_deleteDoc.clone();
    }
    else {
      if (getDeleteDocUri() != null) {
        try {
          XmlDocumentReader xmlReader = new XmlDocumentReader();
          logger.debug("Primed 'Delete' document initialization was deferred.  Initializing for first use.");
          setDeleteDoc(xmlReader.initializeDocument(getDeleteDocUri(), getValidation()));
          return(Document)m_deleteDoc.clone();
        }
        catch (Exception e) {
          logger.fatal(e.getMessage(), e);
        }
      }
      return null;
    }
  }
  /**
  * Returns the primed Delete-Request XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Delete-Request primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @return String the Response-Reply primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final String getDeleteDocUri() {
    return m_deleteDocUri;
  }
  /**
  * Sets the primed Delete-Request XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Delete-Request primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @param uri String the Response-Reply primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final void setDeleteDocUri(String uri) {
    m_deleteDocUri = uri;
  }

  public final  Document getUpdateDoc() {
    if (m_updateDoc != null) {
      return(Document)m_updateDoc.clone();
    }
    else {
      if (getUpdateDocUri() != null) {
        try {
          XmlDocumentReader xmlReader = new XmlDocumentReader();
          logger.debug("Primed 'Update' document initialization was deferred.  Initializing for first use.");
          setUpdateDoc(xmlReader.initializeDocument(getUpdateDocUri(), getValidation()));
          return(Document)m_updateDoc.clone();
        }
        catch (Exception e) {
          logger.fatal(e.getMessage(), e);
        }
      }
      return null;
    }
  }
  /**
  * Returns the primed Update-Request XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Update-Request primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @return String the Response-Reply primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final String getUpdateDocUri() {
    return m_updateDocUri;
  }
  /**
  * Sets the primed Update-Request XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Update-Request primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @param uri String the Response-Reply primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final void setUpdateDocUri(String uri) {
    m_updateDocUri = uri;
  }

  public final  Document getGenerateDoc() {
    if (m_generateDoc != null) {
      return(Document)m_generateDoc.clone();
    }
    else {
      if (getGenerateDocUri() != null) {
        try {
          XmlDocumentReader xmlReader = new XmlDocumentReader();
          logger.debug("Primed 'Generate' document initialization was deferred.  Initializing for first use.");
          setGenerateDoc(xmlReader.initializeDocument(getGenerateDocUri(), getValidation()));
          return(Document)m_generateDoc.clone();
        }
        catch (Exception e) {
          logger.fatal(e.getMessage(), e);
        }
      }
      return null;
    }
  }
  /**
  * Returns the primed Generate-Request XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Generate-Request primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @return String the Generate-Reply primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final  String getGenerateDocUri() {
    return m_generateDocUri;
  }
  /**
  * Sets the primed Generate-Request XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Generate-Request primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @param uri String the Generate-Reply primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final  void setGenerateDocUri(String uri) {
    m_generateDocUri = uri;
  }

  public final Document getCreateSyncDoc() {
    if (m_createSyncDoc != null) {
      return(Document)m_createSyncDoc.clone();
    }
    else {
      if (getCreateSyncDocUri() != null) {
        try {
          XmlDocumentReader xmlReader = new XmlDocumentReader();
          logger.debug("Primed 'CreateSync' document initialization was deferred.  Initializing for first use.");
          setCreateSyncDoc(xmlReader.initializeDocument(getCreateSyncDocUri(), getValidation()));
          return(Document)m_createSyncDoc.clone();
        }
        catch (Exception e) {
          logger.fatal(e.getMessage(), e);
        }
      }
      return null;
    }
  }
  /**
  * Returns the primed Create-Sync XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Create-Sync primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @return String the Create-Sync primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final String getCreateSyncDocUri() {
    return m_createSyncDocUri;
  }
  /**
  * Sets the primed Create-Sync XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Create-Sync primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @param uri String the Create-Sync primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final void setCreateSyncDocUri(String uri) {
    m_createSyncDocUri = uri;
  }

  public final Document getDeleteSyncDoc() {
    if (m_deleteSyncDoc != null) {
      return(Document)m_deleteSyncDoc.clone();
    }
    else {
      if (getDeleteSyncDocUri() != null) {
        try {
          XmlDocumentReader xmlReader = new XmlDocumentReader();
          logger.debug("Primed 'DeleteSync' document initialization was deferred.  Initializing for first use.");
          setDeleteSyncDoc(xmlReader.initializeDocument(getDeleteSyncDocUri(), getValidation()));
          return(Document)m_deleteSyncDoc.clone();
        }
        catch (Exception e) {
          logger.fatal(e.getMessage(), e);
        }
      }
      return null;
    }
  }
  /**
  * Returns the primed Delete-Sync XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Delete-Sync primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @return String the Delete-Sync primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final String getDeleteSyncDocUri() {
    return m_deleteSyncDocUri;
  }
  /**
  * Sets the primed Delete-Sync XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Delete-Sync primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @return String the Delete-Sync primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final void setDeleteSyncDocUri(String uri) {
    m_deleteSyncDocUri = uri;
  }

  public final Document getUpdateSyncDoc() {
    if (m_updateSyncDoc != null) {
      return(Document)m_updateSyncDoc.clone();
    }
    else {
      if (getUpdateSyncDocUri() != null) {
        try {
          XmlDocumentReader xmlReader = new XmlDocumentReader();
          logger.debug("Primed 'UpdateSync' document initialization was deferred.  Initializing for first use.");
          setUpdateSyncDoc(xmlReader.initializeDocument(getUpdateSyncDocUri(), getValidation()));
          return(Document)m_updateSyncDoc.clone();
        }
        catch (Exception e) {
          logger.fatal(e.getMessage(), e);
        }
      }
      return null;
    }
  }
  /**
  * Returns the primed Update-Sync XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Update-Sync primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @return String the Update-Sync primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final String getUpdateSyncDocUri() {
    return m_updateSyncDocUri;
  }
  /**
  * Sets the primed Update-Sync XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Update-Sync primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @param uri String the Update-Sync primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final void setUpdateSyncDocUri(String uri) {
    m_updateSyncDocUri = uri;
  }

  public final Document getGenerateSyncDoc() {
    if (m_generateSyncDoc != null) {
      return(Document)m_generateSyncDoc.clone();
    }
    else {
      if (getGenerateSyncDocUri() != null) {
        try {
          XmlDocumentReader xmlReader = new XmlDocumentReader();
          logger.debug("Primed 'GenerateSync' document initialization was deferred.  Initializing for first use.");
          setGenerateSyncDoc(xmlReader.initializeDocument(getGenerateSyncDocUri(), getValidation()));
          return(Document)m_generateSyncDoc.clone();
        }
        catch (Exception e) {
          logger.fatal(e.getMessage(), e);
        }
      }
      return null;
    }
  }
  /**
  * Returns the primed Generate-Sync XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Generate-Sync primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @return String the Generate-Sync primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final String getGenerateSyncDocUri() {
    return m_generateSyncDocUri;
  }
  /**
  * Sets the primed Generate-Sync XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Generate-Sync primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @param uri String the Generate-Sync primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final void setGenerateSyncDocUri(String uri) {
    m_generateSyncDocUri = uri;
  }

  public final Document getQueryDoc() {
    if (m_queryDoc != null) {
      return(Document)m_queryDoc.clone();
    }
    else {
      if (getQueryDocUri() != null) {
        try {
          XmlDocumentReader xmlReader = new XmlDocumentReader();
          setQueryDoc(xmlReader.initializeDocument(getQueryDocUri(), getValidation()));
          return(Document)m_queryDoc.clone();
        }
        catch (Exception e) {
          logger.fatal(e.getMessage(), e);
        }
      }
      return null;
    }
  }
  /**
  * Returns the primed Query-Request XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Query-Request primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @return String the Query-Request primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final String getQueryDocUri() {
    return m_queryDocUri;
  }
  /**
  * Sets the primed Query-Request XML document URI.  This URI corresponds to the
  * PrimedXmlDocument elements listed in the MessageObjectConfig portion of the deployment
  * descriptor.  The method is called when the object is initialized by AppConfig to
  * create the Query-Request primed document using the URI specified in the deployment
  * descriptor.
  * <P>
  * @param uri String the Query-Request primed document URI as listed in the MessageObjectConfig
  * Element associate to this object.
  **/
  public final void setQueryDocUri(String uri) {
    m_queryDocUri = uri;
  }
 
  protected String getRootElementName(Element e) {
    while (e.isRootElement() == false) {
      logger.debug("Element name: " + e.getName());
      e = (Element) e.getParent();
      logger.debug("Element name: " + e.getName());
    }
    return e.getName();
  }

  /**
   * 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.
   * Clients should never need to call this method directly.
   *
   * @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;
  }

  /**
  * Sets a boolean flag indicating whether or not XML validation will be used when messages
  * are produced/published by this object.  If XML validation is turned on, the resulting
  * XML document that gets generated from the contents of this object will be validated
  * from an XML perspective prior to producing/publishing any messages.
  *<P>
  * This information is specified in the MessageObjectConfig XML Element in the deployment
  * documents and is passed to this object during initialization by the MessageObjectConfig
  * Java object.
  *<P>
  * @param validate boolean true=XML validation will be on, false=XML validation will be off.
  */
  public final void setValidation(boolean validate) {
    m_validate = validate;
  }
  /**
  * Returns a boolean flag indicating whether or not XML validation will be used when messages
  * are produced/published by this object.  If XML validation is turned on, the resulting
  * XML document that gets generated from the contents of this object will be validated
  * from an XML perspective prior to producing/publishing any messages.
  *<P>
  * This information is specified in the MessageObjectConfig XML Element in the deployment
  * documents and is passed to this object during initialization by the MessageObjectConfig
  * Java object.
  *<P>
  * @return boolean true=XML validation will be on, false=XML validation will be off.
  */
  public final boolean getValidation() {
    return m_validate;
  }

  public final void setCreateDoc(Document doc) {
    m_createDoc = doc;
  }

  public final void setDeleteDoc(Document doc) {
    m_deleteDoc = doc;
  }

  /**
   * Sets the "primed" update document associated with this object.  This is called
   * during object initialization and is set based on information in the MessagingEnterprise
   * document.  Clients should never need to call this method directly.
  *<P>
  * This information is specified in the MessageObjectConfig XML Element in the deployment
  * documents and is passed to this object during initialization by the MessageObjectConfig
  * Java object.
  *<P>
   * @param doc  org.jdom.Document the "primed" update Document
   *
   */
  public final void setUpdateDoc(Document doc) {
    m_updateDoc = doc;
  }

  /**
   * Sets the "primed" generate document associated with this object.  This is called
   * during object initialization and is set based on information in the MessagingEnterprise
   * document.  Clients should never need to call this method directly.
  *<P>
  * This information is specified in the MessageObjectConfig XML Element in the deployment
  * documents and is passed to this object during initialization by the MessageObjectConfig
  * Java object.
  *<P>
   * @param doc  org.jdom.Document the "primed" generate Document
   *
   */
  public final void setGenerateDoc(Document doc) {
    m_generateDoc = doc;
  }

  public final void setCreateSyncDoc(Document doc) {
    m_createSyncDoc = doc;
  }

  public final void setDeleteSyncDoc(Document doc) {
    m_deleteSyncDoc = doc;
  }

  public final void setUpdateSyncDoc(Document doc) {
    m_updateSyncDoc = doc;
  }

  public void setResponseDoc(Document doc) {
    m_responseDoc = doc;
  }

  public void setProvideDoc(Document doc) {
    m_provideDoc = doc;
  }
 
  public final void setGenerateSyncDoc(Document doc) {
    m_generateSyncDoc = doc;
  }

  public final void setQueryDoc(Document doc) {
    m_queryDoc = doc;
  }

  public final void dumpData() {
    try {
      EnterpriseLayoutManager elm = getOutputLayoutManager("xml");
      if (elm != null) {
        Object obj = elm.buildOutputFromObject(this);
        if (obj instanceof Element) {
          XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
          logger.info(fmt.outputString((Element)obj));
        }
      }
    }
    catch (Exception exc) {
      logger.fatal("dumpData: Exception caught: " + exc.getMessage());
      //exc.printStackTrace();
    }
  }

  /**
   * A convenience method that can be used to compare two Xml aware objects (XmlEnterpriseObjectImpl).
   * This method converts the current object and the object passed in to an XML String
   * via the toXmlString() method.  Then it does a String comparison on those two strings.
   * Note, this method IS case sensitive.
   *<P>
   * @return  boolean
   *<P>
   * @throws XmlEnterpriseObjectException.  If an error occurs serializing the
   * object to a String.  This is usually due to invalid data (formats etc.) determined
   * from the object's current rules as specified in EnterpriseFields.
   */
  public final boolean equals(XmlEnterpriseObject xeo) throws XmlEnterpriseObjectException {
    if (isEmpty() && xeo.isEmpty() == false) {
      return false;
    }
    else if (isEmpty() == false && xeo.isEmpty()) {
      return false;
    }
    else if (isEmpty() && xeo.isEmpty()) {
      return true;
    }
   
    if (this.toXmlString().equals(xeo.toXmlString())) {
      return true;
    }
    else {
      return false;
    }
  }

  /**
  * Returns a comma separated String containing all the data currently stored in this object.
  *<P>
  * Format for returned data:
  * <P>
  * FieldName1=some value, FieldName2=field2 data etc.
  * <P>
  * @return String
  */
  public String toString() {
    StringBuffer sBuf = new StringBuffer();
    String className = this.getClass().getName();

    Method[] methods = getClass().getDeclaredMethods();
    for (int i=0; i<methods.length; i++) {
      Method getter = methods[i];
      String methodName = getter.getName();
      Class c = getter.getReturnType();
      Class[] parms = getter.getParameterTypes();

      if (methodName.indexOf("get") == 0 && parms.length == 0) {
        String fieldName = methodName.substring(methodName.indexOf("get")+3);
        try {
          if (c == String.class) {
            // just call the getter method.
            String sObj = (String)getter.invoke(this, new Object[] {});
            if (sObj != null) {
              sBuf.append(fieldName + "=" + sObj + ", ");
            }
          }
          else {
            Object xObj = getter.invoke(this, new Object[] {});
            if (xObj != null) {
              sBuf.append(fieldName + "=" + xObj.toString() + ", ");
            }
          }
        }
        catch (InvocationTargetException e) {
          logger.fatal("Error invoking method: get" + fieldName +
            " on object " + className + "  Exception: " + e.getMessage());
          logger.fatal(e.getMessage(), e);
        }
        catch (IllegalAccessException e1) {
          logger.fatal("Error invoking method: get" + fieldName +
            " on object " + className + "  Exception: " + e1.getMessage());
          logger.fatal(e1.getMessage(), e1);
        }
      }
    }
    // need to check the length of sBuf here before attempting to trim it.
    if (sBuf.length() > 2) {
      sBuf.delete(sBuf.length() - 2, sBuf.length());
    }
    return sBuf.toString();
  }

  /**
   * A convenience method that can be used simply by application developers
   * to retreive the contents of the object as an XML String.  Basically,
   * this is a fully valid XML Element just represented as a String.  This
   * data can then be used to persist the entire object, and/or build an
   * Element from that String which can be used to build the object from an
   * input (an XML Element).
   *<P>
   * @return  String the XML representation of the object as a String.
   *<P>
   * @throws XmlEnterpriseObjectException.  If an error occurs serializing the
   * object to a String.  This is usually due to invalid data (formats etc.) determined
   * from the object's current rules as specified in EnterpriseFields.
   */
  public final String toXmlString() throws XmlEnterpriseObjectException {
    /*
    if (isEmpty()) {
      return null;
    }
    */
    try {
      EnterpriseLayoutManager saveOutElm = getOutputLayoutManager();
      EnterpriseLayoutManager outElm = getOutputLayoutManager("xml");
      EnterpriseLayoutManager inElm = getInputLayoutManager("xml");
      if (outElm == null) {
        throw new XmlEnterpriseObjectException("Couldn't find an XML " +
                                               "Output Layout Manager for " + getClass().getName());
      }
      if (inElm == null) {
        throw new XmlEnterpriseObjectException("Couldn't find an XML " +
                                               "Input Layout Manager for " + getClass().getName());
      }
      setOutputLayoutManager(outElm);
      Element eOutput = (Element)buildOutputFromObject();
      setOutputLayoutManager(saveOutElm);

      XmlEnterpriseObject xeo = null;
      String className = this.getClass().getName();
      java.lang.Class obj = java.lang.Class.forName(className);

      if (isDate()) {
        try {
          Method getter = getClass().getMethod("getType", new Class[] {});
          String dateType = (String)getter.invoke(this, new Object[] {});
          Class[] parms = {String.class};
          Constructor c = obj.getConstructor(parms);
          Object[] o = {dateType};
          xeo = (XmlEnterpriseObject)c.newInstance(o);
        }
        catch (Exception e) {
          String errMessage = "Couldn't invoke method: getType() on object " +
                 getClass().getName() + "  Exception: " + e.getMessage();
          throw new EnterpriseFieldException(errMessage, e);
        }
      }
      else {
        // default
        xeo = (XmlEnterpriseObject)obj.newInstance();
      }

      xeo.setEnterpriseFields((EnterpriseFields)getEnterpriseFields().clone());
      xeo.setOutputLayoutManager(outElm);
      xeo.setInputLayoutManager(inElm);

      logger.debug("re-building object from input...");
      xeo.buildObjectFromInput(eOutput);
      XMLOutputter xmlOut = new XMLOutputter();
      String objAsXmlString = xmlOut.outputString((Element)xeo.buildOutputFromObject());
      logger.debug("[toXmlString] " + className + " as an XML String: \n" + objAsXmlString);

      // To test to make sure it doesn't have any goofy characters in it...
      // If it does, an exception will be thrown here.
      XmlDocumentReader xmlReader = new XmlDocumentReader();
      Document objectDoc = xmlReader.initializeDocument(new ByteArrayInputStream(objAsXmlString.getBytes()), false);

      return objAsXmlString;
    }
    catch (Exception exc) {
      logger.fatal(exc.getMessage(), exc);
      String errMessage = "Error in toXmlString: " + exc.getMessage() + " on object " +
                   getClass().getName() + "  Exception: " + exc.getMessage();
      throw new XmlEnterpriseObjectException(errMessage, exc);
    }
  }
 
  /**
   * goes through all the key fields on the xeo passed in and creates a string containing all the
   * values from those key fields.  This string is used by other methods to determine if there are
   * matching new/baseline xeos with the same key information.  That allows us to determine
   * if a transaction should be an insert, update, delete or ignored.
   * <P>
   * @return String the combined key value
   * <P>
   * @throws XmlEnterpriseObjectException
  **/
  public final String getCombinedKeyValue()
  throws XmlEnterpriseObjectException {
    // goes through all the key fields on the xeo passed in and creates a string containing all the
    // values from those key fields.  This string is used by other methods to determine if there are
    // matching new/baseline xeos with the same key information.  That allows us to determine
    // if a transaction should be an insert, update, delete or ignored.

    String className = getClass().getName();
    String objectName = className.substring(className.lastIndexOf('.') + 1)// Our based element in the XML passed in

    if (isDate()) {
      try {
        Method getter = getClass().getMethod("getType", new Class[] {});
        objectName = (String)getter.invoke(this, new Object[] {});
      }
      catch (Exception e) {
        String errMessage = "Couldn't invoke method: getType() on object " +
               getClass().getName() + "  Exception: " + e.getMessage();
        throw new XmlEnterpriseObjectException(errMessage, e);
      }
    }

    java.util.List keys = getEnterpriseFields().getKeyNamesForField( objectName );

    StringBuffer combinedKeyValue = new StringBuffer();
    for (int i=0; i<keys.size(); i++) {
      String keyName = (String)keys.get(i);
      Object obj = getValueFromObject(keyName);
      String keyValue = "";
      if (obj instanceof XmlEnterpriseObject) {
        XmlEnterpriseObject x = (XmlEnterpriseObject)obj;
        String xClassName = x.getClass().getName();
        String xObjectName = xClassName.substring(xClassName.lastIndexOf('.') + 1);
        java.util.List xKeys = x.getEnterpriseFields().getKeyNamesForField( xObjectName );
        if (xKeys != null && xKeys.size() > 0) {
          keyValue = x.getCombinedKeyValue();
        }
        else {
          keyValue = x.toString();
        }
      }
      else if (isRepeating(keyName)) {
        // it's a list, we need to go through each object and get the combined
        // key value from each item in the list.
//        int numObjects = getLength(keyName);
//        StringBuffer repeatingKeyValue = new StringBuffer();
//        for (int j=0; j<numObjects; j++) {
//           Integer iParm = new Integer(j);
//           Object repeatingObj = null;
//           repeatingObj = getValueFromObject(keyName, new Object[] {iParm}, new Class[] {Integer.TYPE});
//           if (repeatingObj instanceof XmlEnterpriseObject) {
//             XmlEnterpriseObject x = (XmlEnterpriseObject)repeatingObj;
//             String xClassName = x.getClass().getName();
//             String xObjectName = xClassName.substring(xClassName.lastIndexOf('.') + 1);
//             java.util.List xKeys = x.getEnterpriseFields().getKeyNamesForField( xObjectName );
//             if (xKeys != null && xKeys.size() > 0) {
//               repeatingKeyValue.append(x.getCombinedKeyValue());
//             }
//             else {
//               repeatingKeyValue.append(x.toString());
//             }            
//           }
//           else {
//             repeatingKeyValue.append((String)repeatingObj);
//           }
//        }
//        keyValue = repeatingKeyValue.toString();

        // actually, if it's a repeating field and it's required, it CAN'T be part of the key
        // so, we'll just ignore it....
      }
      else {
        keyValue = (String)obj;
      }
      if (keyValue != null && keyValue.length() > 0) {
        combinedKeyValue.append(keyValue);
      }
    }
    return combinedKeyValue.toString();
  }
 
  /**
   * Convenience method that tells the layout manager implementation how many instances
   * of a given repeatable field exist on the parent object.  This is useful in determining
   * how many child objects need to be serialized when building an output from an object.
   *<P>
   * If a child object is a repeating object within a parent object, the "getter"
   * method for that child object will return a java.util.List.  This method invokes
   * the getter method for the child object and returns the size of that List.  If the
   * List returned is null, zero will be returned.
   * <P>
   * For example, the Address child object in the BasicPerson object is repeating.  Therefore,
   * the BasicPerson object has a "getAddress" method that returns a java.util.List of Address
   * objects that exist in that BasicPerson.  This method invokes that method and
   * returns the size of the returned object. 
   * <P>
   * @return int the number of child objects
   * @param xeo XmlEnterpriseObject the parent object being queried
   * @param fieldName String the name of the child object being tested
   * @throws EnterpriseLayoutException if an error occurs executing the getter method for the particular
   * field on the parent object passed in.  An exception will also be thrown if the
   * object being checked is not a repeating field (the object returned by the getter method
   * is not a java.util.List.
   */
    protected int getLength(String fieldName) throws XmlEnterpriseObjectException {
        int numObjects = 0;
        String className = this.getClass().getName();
        String objectName = className.substring(className.lastIndexOf('.') + 1);    // Our based element in the XML passed in
   
    try {
            Method getter = null;
            logger.debug("Seeing if " + fieldName + " is a repeating object on " + objectName + " passed in.");
            getter = this.getClass().getMethod("get" + fieldName, new Class[] {});
      String returnType = getter.getReturnType().getName();
      logger.debug("get" + fieldName + " return type: " + returnType);

      if (returnType.equals(LIST)) {
            Object obj = getter.invoke(this, new Object[] {});
        if (obj != null) {
          java.util.List aList = (java.util.List)obj;
          numObjects = aList.size();
        }
        else {
          numObjects = 0;
        }
      }
      else {
        throw new EnterpriseLayoutException("The field '" + fieldName +
          "' is NOT a repeating child field in the '" + objectName + "' object.");
      }
    }
    catch (Exception e) {
            throw new XmlEnterpriseObjectException("Unexpected Error attempting to invoke the 'get" +
        fieldName + "' method on the '" + objectName + "' object.  Exception: " + e.getMessage(), e);
    }

        return numObjects;
    }

  /**
   * Convenience method that indicates if the field specified
   * is a repeating field this object.
   *<P>
   * If a child object is a repeating object within a parent object, the "getter"
   * method for that child object will return a java.util.List.  This method inspects the
   * return type of that getter method and checks to see if it's a java.util.List.
   * <P>
   * For example, the Address child object in the BasicPerson object is repeating.  Therefore,
   * the BasicPerson object has a "getAddress" method that returns a java.util.List of Address
   * objects that exist in that BasicPerson.  This method invokes that method and
   * checks the class type (instanceof) the returned object.  If it's a java.util.List
   * it knows the Address is a repeating child on the BasicPerson.  This will work for any
   * XmlEnterpriseObject.
   * <P>
   * @return boolean true if the field is a repeating field, false if not.
   * @param fieldName String the name of the field being tested.
   * @throws XmlEnterpriseObjectException if an error occurs executing the child object's getter method.
   */
    public boolean isRepeating(String fieldName) throws XmlEnterpriseObjectException {
        boolean isRepeating = false;
        String className = this.getClass().getName();
        String objectName = className.substring(className.lastIndexOf('.') + 1);    // Our based element in the XML passed in

    try {
            Method getter = null;
            logger.debug("Seeing if " + fieldName + " is a repeating object on " + objectName + " passed in.");
            getter = this.getClass().getMethod("get" + fieldName, new Class[] {});
      String returnType = getter.getReturnType().getName();
      logger.debug("get" + fieldName + " return type: " + returnType);

      if (returnType.equals(LIST)) {
        logger.debug(fieldName + " is a repeating object in " + objectName + " passed in.");
        isRepeating = true;
      }
      else {
        logger.debug(fieldName + " is NOT a repeating object in " + objectName + " passed in.");
      }
    }
    catch (Exception e) {
      logger.fatal(e.getMessage(), e);
            throw new XmlEnterpriseObjectException("Unexpected Error attempting to invoke the 'get" +
        fieldName + "' method on the '" + objectName + "' object.  Exception: " + e.getMessage(), e);
    }

        return isRepeating;
    }

  /**
  * Returns the current value from the field name passed in.  Convenience
  * method to allow "reflective" use of XmlEnterpriseObjects.  Allows for
  * parameters.  This is especially neccessary when retrieving an individual
  * object from a list of objects contained within the parent object.
  *<P>
  * @return Object the value from the field
  * @param fieldName String the name of the field from which to retrieve data
  * @param parms Object[] any parameters that need to be passed to the getter method being called.
  * @param parmTypes Class[] the paramater types associated to any parameters.
  * @throws XmlEnterpriseObjectException if the field name passed in does not exist
  * or if any other errors occur calling the getter method associated to the field.
  */
  public final Object getValueFromObject(String fieldName, Object[] parms, Class[] parmTypes)
  throws XmlEnterpriseObjectException {

    String className = getClass().getName();
    String objectName = className.substring(className.lastIndexOf('.') + 1)// Our based element in the XML passed in
    try {
      Method getter = null;
      logger.debug("Calling getter method for " + fieldName);
      getter = getClass().getMethod("get" + fieldName, parmTypes);
      Class c = getter.getReturnType();
      Object obj = getter.invoke(this, parms);
      return obj;
    }
    catch (Exception e) {
      String errMessage = "Error calling getter method for " +
        objectName + "/" + fieldName + " Exception: " + e.getMessage();
      throw new XmlEnterpriseObjectException(errMessage, e);
    }
  }
  /**
  * Returns the current value from the field name passed in.  Convenience
  * method to allow "reflective" use of XmlEnterpriseObjects.  Assumes
  * the getter method being called does not take any parameters.
  *<P>
  * @return Object the value from the field
  * @param fieldName String the name of the field from which to retrieve data
  * @throws XmlEnterpriseObjectException if the field name passed in does not exist
  * or if any other errors occur calling the getter method associated to the field.
  */
  public final Object getValueFromObject(String fieldName)
  throws XmlEnterpriseObjectException {

    String className = getClass().getName();
    String objectName = className.substring(className.lastIndexOf('.') + 1)// Our based element in the XML passed in
    try {
      Method getter = null;
      logger.debug("Calling getter method for " + fieldName);
      getter = getClass().getMethod("get" + fieldName, new Class[] {});
      Class c = getter.getReturnType();
      Object obj = getter.invoke(this, new Object[] {});
      return obj;
    }
    catch (Exception e) {
      String errMessage = "Error calling getter method for " +
        objectName + "/" + fieldName + ".  Exception: " + e.getMessage();
      throw new XmlEnterpriseObjectException(errMessage, e);
    }
  }

  /**
  * Sets the current value the field name passed in to the value passed in.  Convenience
  * method to allow "reflective" use of XmlEnterpriseObjects.  Assumes
  * the setter method being called takes one String parameter.
  *<P>
  * @param fieldName String the name of the field from which to retrieve data
  * @param value String the value to set on the field
  * @throws XmlEnterpriseObjectException if the field name passed in does not exist
  * or if any other errors occur calling the setter method associated to the field.
  */
  public final void setValue(String fieldName, String value)
    throws XmlEnterpriseObjectException {

    String className = getClass().getName();
    String objectName = className.substring(className.lastIndexOf('.') + 1);
    try {
      Method setter = null;
      Object[] parms = new Object[] {};
      parms[0] = value;
      Class[] parmTypes = new Class[] {};
      parmTypes[0] = value.getClass();
      logger.debug("Calling setter method for " + fieldName);
      setter = getClass().getMethod("set" + fieldName, parmTypes);
      setter.invoke(this, parms);
    }
    catch (Exception e) {
      String errMessage = "Error calling setter method for " +
        objectName + "/" + fieldName + " Exception: " + e.getMessage();
      throw new XmlEnterpriseObjectException(errMessage, e);
    }
  }
 
 
  protected void saveLayoutManagers() {
    // Since ever object performing these actions are going to be using an XML
    // Layout Manager for querying, updating, deleting ect. we need to save the
    // layout manager the object is currently using, then change the manager
    // to be the XML layout manager (which all objects should have by default)
    // After all of this is done, we'll set the layout manager back to what it
    // was when this method was called...

    // Save layout manager
    EnterpriseLayoutManager tmpInput = getInputLayoutManager("xml");
    if (tmpInput != null) {
      m_saveInputLManager = getInputLayoutManager();
      setInputLayoutManager(tmpInput);
      logger.debug("[saveLayoutManagers] Input layout manager for " + getClass().getName() + " is " + getInputLayoutManager().getClass().getName());
    }

    EnterpriseLayoutManager tmpOutput = getOutputLayoutManager("xml");
    if (tmpOutput != null) {
      m_saveOutputLManager = getOutputLayoutManager();
      setOutputLayoutManager(tmpOutput);
      logger.debug("[saveLayoutManagers] Output layout manager for " + getClass().getName() + " is " + getOutputLayoutManager().getClass().getName());
    }
  }
  protected void restoreLayoutManagers() {
    setInputLayoutManager(m_saveInputLManager);
    setOutputLayoutManager(m_saveOutputLManager);
  }
}
TOP

Related Classes of org.openeai.moa.XmlEnterpriseObjectImpl

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.