Package org.openeai.layouts

Source Code of org.openeai.layouts.XmlLayout

/*******************************************************************************
$Source: /cvs/repositories/openii3/project/java/source/org/openeai/layouts/XmlLayout.java,v $
$Revision: 1.19 $
*******************************************************************************/

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

import java.util.*;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Attribute;
import org.jdom.output.XMLOutputter;
import gnu.regexp.*;

import java.lang.reflect.Method;

import org.openeai.moa.*;
import org.openeai.config.EnterpriseFields;
import org.openeai.config.EnterpriseFieldException;

/**
* This is the default Layout manager that all Enterprise Messaging Objects use to
* build themselves from and serialize themselves to XML.  It uses information found
* in the EnterpriseObjects documents to determine the layout corresponding to a particular
* object.
* <P>
  * @author      Tod Jackson (tod@openeai.org)
  * @author      Steve Wheat (steve@openeai.org)
  * @version     3.0  - 28 January 2003
*/
public class XmlLayout extends EnterpriseLayoutManagerImpl
implements EnterpriseLayoutManager {

  private Element m_layout = null;
  private boolean m_validate = false;

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

  public void init(String layoutManagerName, Document layoutDoc)
  throws EnterpriseLayoutException {

    // Default behavior is all that's needed for XmlLayout
    super.init(layoutManagerName, layoutDoc);
  }

/**
* This is the buildOutputFromObject method that all Layout Managers must implement.
* This particular layout manager returns an Element when this method is called.
* It is up to the caller of this method to cast the object to an Element.  This Element
* is an XML Element that contains all the data currently residing in the object.
* The fields that data is retrieved from to build the element are defined in
* EnterpriseObjects document associated to the object being serialized.
* <P>
* All XmlEnterpriseObjects have a method that determines the layout manager being
* used and then calls this method on the currently used layout manager (this class for
* example).  The method in XmlEnterpriseObject is also called buildOutputFromObject.
* <P>
* @param xeo XmlEnterpriseObject the object that's being used to build the element.
* @return Object the XML element that corresponds to the data in the object.
* @throws EnterpriseLayoutException if any errors occur getting the field values from the object.
*/
  public Object buildOutputFromObject(XmlEnterpriseObject xeo)
  throws EnterpriseLayoutException {

    logger.debug("XmlLayout - Build Output From Object - Started Processing.");

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

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

    logger.debug("[xmllayout buildOutputFromObject] ObjectName is " + objectName);

    Element eOutput = new Element(objectName);
    Element eLayout = getLayout(getLayoutRoot(), objectName);
    String layoutName = eLayout.getAttribute("name").getValue();
    logger.debug("eLayout is " + layoutName);

    java.util.List lFields = eLayout.getChildren("Field");
    logger.debug("There are " + lFields.size() + " Fields in the " + layoutName + " Layout.");

    XMLOutputter xmlOut = new XMLOutputter();
    for (int i=0; i<lFields.size(); i++) {
      Element eField = (Element)lFields.get(i);
      buildElement(xeo, eOutput, eField, true);
      logger.debug("eOutput is now " + xmlOut.outputString(eOutput));
    }

    logger.debug("XmlLayout - Build Output From Object - Ended Processing.");

    return eOutput;
  }

/**
* This is the buildOutputFromObject method that all Layout Managers must implement.
* This particular layout manager returns an Element with application specifice values when this method is called.
* It is up to the caller of this method to cast the object to an Element.  This Element
* is an XML Element that contains all the data currently residing in the object.
* The fields that data is retrieved from to build the element are defined in
* the EnterpriseObjects document associated to the object being serialized.
* <P>
* This method takes the contents currently stored in the object and builds an XML Element
* from that content which contains application specific values.  These "translations" are
* performed based on information found in EnterpriseObjects.xml.
* <P>
* All XmlEnterpriseObjects have a method that determines the layout manager being
* used and then calls this method on the currently used layout manager (this class for
* example).  The method in XmlEnterpriseObject is also called buildOutputFromObject.
* <P>
* @param anXmlEnterpriseObject XmlEnterpriseObject the object that's being used to build the element.
* @param appName String target application that Enterprise Values should be converted to.
* @return Object the XML element that corresponds to the data in the object.
* @throws EnterpriseLayoutException if any errors occur getting the field values from the object.
*/
  public Object buildOutputFromObject(XmlEnterpriseObject anXmlEnterpriseObject, String appName)
  throws EnterpriseLayoutException {

    logger.debug("XmlLayout - Build Object From Input with AppName - Started Processing.");
    setTargetAppName(appName);
    Object obj = buildOutputFromObject(anXmlEnterpriseObject);
    logger.debug("XmlLayout - Build Object From Input with AppName - Ended Processing.");

    return obj;
  }

/**
* This is the buildObjectFromInput method that all Layout Managers must implement.
* This particular layout manager builds the object passed in from an Element.
* This Element is an XML Element that contains all the data the caller wishes to
* populate the object with.  This data can be application specific data and
* rules found in the EnterpriseOjbects document associated to the object being populated are then applied
* to the data in the XML Element and when it's all complete, the object contains
* Enterprise Values.
* <P>
* All XmlEnterpriseObjects have a method that determines the "input" layout manager being
* used and then calls this method on the currently used layout manager (this class for
* example).  The method in XmlEnterpriseObject is also called buildObjectFromInput.
* <P>
* @param input Object the input data that is used to populate the object (an XML Element in this case).
* @param xeo XmlEnterpriseObject the object that's being populated from the Element passed in.
* @throws EnterpriseLayoutException if an errors occur setting the Object fields with data
* contained in the XML element.
*/
  public void buildObjectFromInput(Object input, XmlEnterpriseObject xeo)
  throws EnterpriseLayoutException {

    logger.debug("XmlLayout - Build Object From Input - Started Processing.");

    Element eInput = (Element)input;   // Element from an XML document passed in.
    String className = xeo.getClass().getName();
    String objectName = className.substring(className.lastIndexOf('.') + 1)// Our based element in the XML passed in
    logger.debug("ObjectName is " + objectName);

    Element eLayout = getLayout(getLayoutRoot(), objectName);
    String layoutName = eLayout.getAttribute("name").getValue();
    logger.debug("eLayout is " + layoutName);

    java.util.List lFields = eLayout.getChildren("Field");
    logger.debug("There are " + lFields.size() + " Fields in the " + layoutName + " Layout.");

    for (int i=0; i<lFields.size(); i++) {
      Element eField = (Element)lFields.get(i);
      buildObject(xeo, eInput, eField, true);
    }

    logger.debug("XmlLayout - Build Object From Input - Ended Processing.");
  }

  private void buildElement(XmlEnterpriseObject xeo, Element eOutput,
                            Element eField, boolean parentIsRequired)
  throws EnterpriseLayoutException {

    String className = xeo.getClass().getName();
    String objectName = className.substring(className.lastIndexOf('.') + 1)// Our based element in the XML passed in
    String elementName = eOutput.getName();
    logger.debug("[buildElement] Name of Object passed in is " + objectName);

    String fieldName = eField.getAttribute("name").getValue();
    logger.debug("[buildElement] Field Name is " + fieldName);
    String fieldType = eField.getAttribute("type").getValue();
    logger.debug("Field Type is " + fieldType);
    String fieldValue = "";

    // Required has to be pulled from the Format element which should exist for
    // all fields, even Fields of type "Object".
    boolean isRequired = isRequired(eField);

    if (fieldType.equals("Element")) {
      if (isRepeating(xeo, fieldName)) {
        int numObjects = getLength(xeo, fieldName);

        for (int i=0; i<numObjects; i++) {
          Integer iParm = new Integer(i);
          Object obj = null;
          if (getTargetAppName() == null) {
            obj = getValueFromObject(xeo, fieldName, new Object[] {iParm}, new Class[] {Integer.TYPE});
          }
          else {
            obj = getValueFromObject(xeo, getTargetAppName(), fieldName, new Object[] {iParm}, new Class[] {Integer.TYPE});
          }
          if (obj instanceof String) {
            fieldValue = (String)obj;

            Element eChildOutput = new Element(fieldName);
            // Have to do this to validate the data since the object we're dealing
            // with may not have had an EnterpriseFields object when it was populated.
            try {
              String tempValue = removeXmlEscapes(fieldValue);
              // 4/4/2002 fix
              // in this case, we really do want to set the value in the vector at the index
              // so we don't keep adding items to it
              setVariableValue(xeo, fieldName, tempValue , String.class, i);
            }
            catch (Exception e) {
               throw new EnterpriseLayoutException("Error setting " + objectName + "/" + fieldName +
                "  to the value " + fieldValue + "  Exception: " + e.getMessage(), e);
            }

            // Now, we have to get the value from the object again since it may have been
            // modified when the setter methods are called above.  Otherwise, we'll be
            // creating the XML using the "non enterprise" value.
            if (getTargetAppName() == null) {
              fieldValue = (String)getValueFromObject(xeo, fieldName, new Object[] {iParm}, new Class[] {Integer.TYPE});
            }
            else {
              fieldValue = (String)getValueFromObject(xeo, getTargetAppName(), fieldName, new Object[] {iParm}, new Class[] {Integer.TYPE});
            }

            eChildOutput.setText(fieldValue);
            eOutput.addContent(eChildOutput);
          }
          else {
            // should never get here.
          }
        }
        if (numObjects == 0) {
          // Have to check the parent field (if one exists) for situations
          // where the Parent field isn't required but children of that Parent
          // are.  Example is DeceasedDate in BasicPerson.  DeceasedDate is optional
          // but Month,Day,Year are required if DeceasedDate is present...
          if (isRequired && parentIsRequired && xeo.getEnterpriseFields().ignoreValidation() == false) {
            throw new EnterpriseLayoutException("The " + fieldType + " " +
              elementName + "/" + fieldName + " is required but it has no value.  NumObjects: " + numObjects);
          }
          else {
            logger.debug(fieldName + " on " + elementName + " is required but " + elementName + " isn't so we can ignore this missing field.");
          }
        }
      }
      else {
        Object obj = null;
        if (getTargetAppName() == null) {
          obj = getValueFromObject(xeo, fieldName);
        }
        else {
          obj = getValueFromObject(xeo, getTargetAppName(), fieldName);
        }
        if (obj instanceof String) {
          fieldValue = (String)obj;
        }
        else {
        }
        if (fieldValue == null || fieldValue.trim().length() == 0) {
          // Have to check the parent field (if one exists) for situations
          // where the Parent field isn't required but children of that Parent
          // are.  Example is DeceasedDate in BasicPerson.  DeceasedDate is optional
          // but Month,Day,Year are required if DeceasedDate is present...
          if (isRequired && parentIsRequired && xeo.getEnterpriseFields().ignoreValidation() == false) {
            throw new EnterpriseLayoutException("The " + fieldType + " " +
              elementName + "/" + fieldName + " is required but it has no value.");
          }
          else {
            logger.debug(fieldName + " on " + elementName + " is required but " + elementName + " isn't so we can ignore this missing field.");
            // Don't even add the Element since it's not required and there is no
            // data in the object's field.
            return;
          }
        }

        // Have to do this to validate the data since the object we're dealing
        // with may not have had an EnterpriseFields object when it was populated.
        try {
          String tempValue = removeXmlEscapes(fieldValue);
          setVariableValue(xeo, fieldName, tempValue , String.class);
         }
        catch (Exception e) {
           throw new EnterpriseLayoutException("Error setting " + objectName + "/" + fieldName +
            "  to the value " + fieldValue + "  Exception: " + e.getMessage(), e);
         }

        // Now, we have to get the value from the object again since it may have been
        // modified when the setter methods are called above.  Otherwise, we'll be
        // creating the XML using the "non enterprise" value.
        if (getTargetAppName() == null) {
          fieldValue = (String)getValueFromObject(xeo, fieldName);
        }
        else {
          fieldValue = (String)getValueFromObject(xeo, getTargetAppName(), fieldName);
        }

        logger.debug("[buildElement] Adding Element (" + fieldName + ") with a value of " +
                     fieldValue + " to Element " + elementName + " passed in.");
        eOutput.addContent(new Element(fieldName).setText(fieldValue));
      }
    }
    else if (fieldType.equals("Attribute")) {
      StringBuffer sBuf = new StringBuffer();
      sBuf.append(fieldName.substring(0,1).toLowerCase());
      sBuf.append(fieldName.substring(1));
      String attrName = new String(sBuf);

      Object obj = null;
      if (getTargetAppName() == null) {
        obj = getValueFromObject(xeo, fieldName);
      }
      else {
        obj = getValueFromObject(xeo, getTargetAppName(), fieldName);
      }
      if (obj instanceof String) {
        fieldValue = (String)obj;
      }
      else {
      }
      if (fieldValue == null || fieldValue.trim().length() == 0) {
        // Have to check the parent field (if one exists) for situations
        // where the Parent field isn't required but children of that Parent
        // are.  Example is DeceasedDate in BasicPerson.  DeceasedDate is optional
        // but Month,Day,Year are required if DeceasedDate is present...

        // 8/6/01 - this won't work for things like Address@type, type is required but Address isn't
        // need to figure out a better way to do this.....
        if (isRequired && parentIsRequired && xeo.getEnterpriseFields().ignoreValidation() == false) {
          throw new EnterpriseLayoutException("The " + fieldType + " " +
            elementName + "/" + fieldName + " is required but it has no value.");
        }
        else {
          logger.debug(fieldName + " on " + elementName + " is required but " + elementName + " isn't so we can ignore this missing field.");
          // Don't even add the Attribute since it's not required and there is no
          // data in the object's field.
          return;
        }
      }

      // Have to do this to validate the data since the object we're dealing
      // with may not have had an EnterpriseFields object when it was populated.
      try {
        String tempValue = removeXmlEscapes(fieldValue);
         setVariableValue(xeo, fieldName, tempValue , String.class);
      }
      catch (Exception e) {
         throw new EnterpriseLayoutException("Error setting " + objectName + "/" + fieldName +
          "  to the value " + fieldValue + "  Exception: " + e.getMessage(), e);
      }

      // Now, we have to get the value from the object again since it may have been
      // modified when the setter methods are called above.  Otherwise, we'll be
      // creating the XML using the "non enterprise" value.
      if (getTargetAppName() == null) {
        fieldValue = (String)getValueFromObject(xeo, fieldName);
      }
      else {
        fieldValue = (String)getValueFromObject(xeo, getTargetAppName(), fieldName);
      }

      logger.debug("[buildElement] Adding Attribute (" + attrName + ") with a value of " +
                   fieldValue + " to Element " + elementName + " passed in.");
      eOutput.setAttribute(attrName, fieldValue);
    }
    else if (fieldType.equals("Object")) {
      // If we can't find the ObjectDefinition as a child,
      // look for it at the root of the document.  If it's
      // not there, then we have an error situation.
      Element eObjDef = eField.getChild("ObjectDefinition");
      if (eObjDef == null) {
        eObjDef = getLayout(getLayoutRoot(), fieldName);
        if (eObjDef == null) {
          throw new EnterpriseLayoutException("Can't find an ObjectDefinition in the Layout Document for " +
            objectName + "/" + fieldName);
        }
      }
      java.util.List lFields = eObjDef.getChildren("Field");
      String layoutName = eObjDef.getAttribute("name").getValue();
      logger.debug("There are " + lFields.size() + " Fields in the " + layoutName + " Layout.");

      if (isRepeating(xeo, fieldName)) {
        int numObjects = getLength(xeo, fieldName);

        java.util.List sortedIndexes = getSortedIndexes(xeo, numObjects, fieldName);
        logger.debug("XmlLayout: sortedIndexes.size: " + sortedIndexes.size());
        for (int i=0; i<sortedIndexes.size(); i++) {
          String nextIndex = (String)sortedIndexes.get(i);
          logger.debug("Sorted Index [" + i + "] is " + nextIndex);
          Integer iParm = new Integer(nextIndex);

          // the rest is the same????
          Object obj = null;
          obj = getValueFromObject(xeo, fieldName, new Object[] {iParm}, new Class[] {Integer.TYPE});
          if (obj instanceof XmlEnterpriseObject) {
            XmlEnterpriseObject aNewXeo = (XmlEnterpriseObject)obj;
            try {
              aNewXeo.setEnterpriseFields((EnterpriseFields)xeo.getEnterpriseFields().clone());
            }
            catch (Exception e) {
              throw new EnterpriseLayoutException("Exception cloning EnterpriseFields object for object " + objectName + "." +
                "  Exception: " + e.getMessage(), e);
            }
            String newXeoClassName = aNewXeo.getClass().getName();
            String newXeoObjectName = newXeoClassName.substring(newXeoClassName.lastIndexOf('.') + 1);
            Element eChildOutput = new Element(fieldName);
            for (int j=0; j<lFields.size(); j++) {
              Element eChildField = (Element)lFields.get(j);
              buildElement(aNewXeo, eChildOutput, eChildField, isRequired);
            }
            logger.debug("[buildElement] Adding [" + i + "] Element " + fieldName + " to the " + elementName + " passed in.");
            eOutput.addContent(eChildOutput);
          }
          else {
            // should never get here.
          }
        }
      }
      else {
        Object obj = null;
        obj = getValueFromObject(xeo, fieldName);       
        if (obj instanceof XmlEnterpriseObject) {
          XmlEnterpriseObject aNewXeo = (XmlEnterpriseObject)obj;
          try {
            aNewXeo.setEnterpriseFields((EnterpriseFields)xeo.getEnterpriseFields().clone());
          }
          catch (Exception e) {
            throw new EnterpriseLayoutException("Exception cloning EnterpriseFields object for object " + objectName + "." +
              "  Exception: " + e.getMessage(), e);
          }

          try {
            if (aNewXeo.isEmpty()) {
              logger.debug("No need to try and add the " + fieldName + " to the element passed in.");
              if (isRequired == false || parentIsRequired == false) {
                return;
              }
            }
            else {
              logger.debug("Object " + fieldName + " isn't empty so we have to try and add it.");
            }
          }
          catch (XmlEnterpriseObjectException e) {
            throw new EnterpriseLayoutException("Error checking if object " + objectName + "/" +
              fieldName + " is empty.  Exception: " + e.getMessage(), e);
          }
          String newXeoClassName = aNewXeo.getClass().getName();
          String newXeoObjectName = newXeoClassName.substring(newXeoClassName.lastIndexOf('.') + 1);

          Element eChildOutput = new Element(fieldName);
          for (int i=0; i<lFields.size(); i++) {
            Element eChildField = (Element)lFields.get(i);
            buildElement(aNewXeo, eChildOutput, eChildField, isRequired);
          }
          logger.debug("[buildElement] Adding Element " + fieldName + " to the " + elementName + " passed in.");
          eOutput.addContent(eChildOutput);
        }
        else {
          logger.debug("[buildElement] the field " + fieldName + " is not an XmlEnterpriseObject...");
        }
      }
    }
  }

  /**
   * This method ensures that repeatable fields of type 'Object' are always seriallized
   * in the same order sorted by combined key value for that object.  This way, the equals
   * method in XmlEnterpriseObject should evaluate to true instead of false which is
   * what will happen if the objects aren't serialized in a consistent order.
   *<P>
   * @param xeo XmlEnterpriseObject the parent xeo that we'll be retrieving child objects from
   * @param numObjects int the number of child objects (by this name) that exist in the parent object
   * @param childFieldName String the child objects name (field name)
   *<P>
   * @return java.util.List a list of indexes that correspond to the order inwhich the child
   * objects should be retrieved from the parent object to ensure they're being retrieved consistently
   * by combined key value.
   *<P>
   * @throws EnterpriseLayoutManagerException if an error occurs while sorting the child objects
   * and building the return List.
  **/
  private java.util.List getSortedIndexes(XmlEnterpriseObject xeo, int numObjects, String childFieldName) throws EnterpriseLayoutException {
    String[] sortedKeyValues = new String[numObjects];

    // add all the combined key values to a sortable array of strings.
    for (int i=0; i<numObjects; i++) {
      Integer iParm = new Integer(i);
      Object obj = null;
      obj = getValueFromObject(xeo, childFieldName, new Object[] {iParm}, new Class[] {Integer.TYPE});
      if (obj instanceof XmlEnterpriseObject) {
        XmlEnterpriseObject aNewXeo = (XmlEnterpriseObject)obj;
        String combinedKeyValue = null;
        try {
          combinedKeyValue = aNewXeo.getCombinedKeyValue();
          if (combinedKeyValue != null && combinedKeyValue.length() > 0) {
            logger.debug("getSortedIndexes: adding combined key of '" + combinedKeyValue + " - " + i + "' to sortedKeyValues Array.");
            sortedKeyValues[i] = combinedKeyValue + " - " + i;  // incase there are multiple instances of the same combined key value
          }
          else {
            sortedKeyValues[i] = Integer.toString(i);
          }
        }
        catch (Exception e) {
          throw new EnterpriseLayoutException(e.getMessage(), e);
        }
      }
    }

    // sort the array of keyvalues.
    Arrays.sort(sortedKeyValues);
    logger.debug("getSortedIndexes: sortedKeyValues size: " + sortedKeyValues.length);

    // now build a list of indexes that correspond to the sorted combinedKeyValues
    ArrayList sortedIndexes = new ArrayList();
    for (int i=0; i<sortedKeyValues.length; i++) {
      String sortedKeyValue = sortedKeyValues[i];
      boolean foundMatch = false;
      keyTest: for (int j=0; j<numObjects; j++) {
        Integer iParm = new Integer(j);
        Object obj = null;
        obj = getValueFromObject(xeo, childFieldName, new Object[] {iParm}, new Class[] {Integer.TYPE});
        if (obj instanceof XmlEnterpriseObject) {
          XmlEnterpriseObject aNewXeo = (XmlEnterpriseObject)obj;
          String combinedKeyValue = null;
          try {
            combinedKeyValue = aNewXeo.getCombinedKeyValue();
            if (combinedKeyValue != null && combinedKeyValue.length() > 0) {
              combinedKeyValue = combinedKeyValue + " - " + j;  // incase there are multiple instances of the same combined key value
              logger.debug("getSortedIndexes: comparing combinedKeyValue " + combinedKeyValue + " to " + sortedKeyValue);
            }
            else {
              combinedKeyValue = Integer.toString(j);
            }
            if (combinedKeyValue.equalsIgnoreCase(sortedKeyValue)) {
              logger.debug("getSortedIndexes: found a match!");
              sortedIndexes.add(Integer.toString(j));
              foundMatch = true;
              break keyTest;
            }
          }
          catch (Exception e) {
            throw new EnterpriseLayoutException(e.getMessage(), e);
          }
        }
      }
      if (foundMatch == false) {
        logger.fatal("getSortedIndexes: could not find a match for " + sortedKeyValue);
        throw new EnterpriseLayoutException("Could not find sort the repeatable " +
          childFieldName + " objects on the " + xeo.getClass().getName() + " object.");
      }
    }
    return sortedIndexes;
  }

  private void buildObject(XmlEnterpriseObject xeo, Element eInput,
                           Element eField, boolean parentIsRequired)
  throws EnterpriseLayoutException {

    String className = xeo.getClass().getName();
    String objectName = className.substring(className.lastIndexOf('.') + 1)// Our based element in the XML passed in
    logger.debug("Name of Object passed in is " + objectName);

    String fieldName = eField.getAttribute("name").getValue();
    logger.debug("Field Name is " + fieldName);
    String fieldType = eField.getAttribute("type").getValue();
    logger.debug("Field Type is " + fieldType);
    String fieldValue = "";

    boolean isRequired = isRequired(eField);

    if (fieldType.equals("Element")) {
      java.util.List lValues = eInput.getChildren(fieldName);
      if (lValues.size() == 0) {
        // This means there were no elements with the name matching the
        // variable "fieldName".  If this is a required field, then this
        // is an error.  Otherwise, it's okay and we can skip the field.
        if (isRequired && xeo.getEnterpriseFields().ignoreValidation() == false) {
          throw new EnterpriseLayoutException(fieldName +
            " is a required field but could not be found in the " +
            objectName + " Element passed in.");
        }
      }

      for (int j=0; j<lValues.size(); j++) {
        Element eValue = (Element)lValues.get(j);
        fieldValue = eValue.getText();
        logger.debug("Setting " + fieldName + " to " + fieldValue + " on the " + objectName + " object passed in.");

        try {
          fieldValue = removeXmlEscapes(fieldValue);
          setVariableValue(xeo, fieldName, fieldValue, String.class);
        }
        catch (Exception e) {
          throw new EnterpriseLayoutException("Error setting " + objectName + "/" + fieldName +
            "  Exception: " + e.getMessage(), e);
        }
      }
    }
    else if (fieldType.equals("Attribute")) {
      StringBuffer sBuf = new StringBuffer();
      sBuf.append(fieldName.substring(0,1).toLowerCase());
      sBuf.append(fieldName.substring(1));
      String attrName = new String(sBuf);
      Attribute anAttr = eInput.getAttribute(attrName);
      if (anAttr == null) {
        if (isRequired && xeo.getEnterpriseFields().ignoreValidation() == false) {
          throw new EnterpriseLayoutException(fieldName +
             " is a required field but could not be found in the " +
            objectName + " Element passed in.");
        }
      }
      else {
        fieldValue = anAttr.getValue();
        if (fieldValue == null || fieldValue.trim().length() == 0) {
          if (isRequired && xeo.getEnterpriseFields().ignoreValidation() == false) {
            throw new EnterpriseLayoutException(fieldName +
                                                " is a required field but could not be found in the " +
                                                objectName + " Element passed in.");
          }
        }
        logger.debug("Setting " + fieldName + " to " + fieldValue + " on the " + objectName + " object passed in.");
        try {
          fieldValue = removeXmlEscapes(fieldValue);
          setVariableValue(xeo, fieldName, fieldValue, String.class);
        }
        catch (Exception e) {
          throw new EnterpriseLayoutException("Error setting " + objectName + "/" +
            fieldName + "  Exception:" + e.getMessage(), e);
        }
      }
    }
    else if (fieldType.equals("Object")) {
      Element eObjDef = eField.getChild("ObjectDefinition");
      if (eObjDef == null) {
        logger.debug("Getting ObjectDefinition for " + fieldName + " from root...");
        eObjDef = getLayout(getLayoutRoot(), fieldName);
        if (eObjDef == null) {
          throw new EnterpriseLayoutException("Can't find an ObjectDefinition in the Layout Document for " +
            objectName + "/" + fieldName);
        }
      }
      String objClassName = eObjDef.getChild("ClassName").getText();
      String objObjectName = objClassName.substring(objClassName.lastIndexOf('.') + 1);
      String layoutName = eObjDef.getAttribute("name").getValue();

      /*
      if (fieldName.equals("EffectiveDate")) {
        logger.debug("Date class name is: " + objClassName);
      }
      */

      java.util.List lObjs = eInput.getChildren(fieldName);
      logger.debug("[xmllayout] There are " + lObjs.size() + " " + fieldName + " elements in the " + objectName + " Element passed in.");
      if (lObjs.size() == 0) {
        if (isRequired && xeo.getEnterpriseFields().ignoreValidation() == false) {
          throw new EnterpriseLayoutException(fieldName +
                                              " is a required field but could not be found in the " +
                                              objectName + " Element passed in.");
        }
      }
      else {
        XmlEnterpriseObject aNewXeo = null;
        Element eObjInput = null;
        for (int j=0; j<lObjs.size(); j++) {
          eObjInput = (Element)lObjs.get(j);
          if (elementIsEmpty(eObjInput) && isRequired == false) {
            // If the element is empty and the object is not required,
            // then there's no reason to instantiate and attempt to build
            // the object.
            logger.debug("No need to instantiate the " + fieldName + " object!");
            return;
          }
          Class classType = null;
          if (isDate(objClassName)) {
            String oName = objClassName + "(" + layoutName + ")";
            logger.debug("instantiating a " + oName);
            aNewXeo = (XmlEnterpriseObject)instantiate(oName);

            try {
              aNewXeo.setEnterpriseFields((EnterpriseFields)xeo.getEnterpriseFields().clone());
            }
            catch (Exception e) {
              throw new EnterpriseLayoutException("Exception cloning EnterpriseFields object for object " + objectName + "." +
                "  Exception: " + e.getMessage(), e);
            }

            classType = aNewXeo.getClass();
            objectName = objectName + "(" + layoutName + ")";
          }
          else {
            logger.debug("instantiating a " + objClassName);
            aNewXeo = (XmlEnterpriseObject)instantiate(objClassName);

            try {
              aNewXeo.setEnterpriseFields((EnterpriseFields)xeo.getEnterpriseFields().clone());
            }
            catch (Exception e) {
              throw new EnterpriseLayoutException("Exception cloning EnterpriseFields object for object " + objectName + "." +
                "  Exception: " + e.getMessage(), e);
            }

            classType = aNewXeo.getClass();
          }

          java.util.List lFields = eObjDef.getChildren("Field");
          logger.debug("There are " + lFields.size() + " Fields in the " + layoutName + " Layout.");
          for (int i=0; i<lFields.size(); i++) {
            Element eObjField = (Element)lFields.get(i);
            buildObject(aNewXeo, eObjInput, eObjField, isRequired);
          }

          logger.debug("Setting the " + fieldName + " object on the " + xeo.getClass().getName());

          try {
            /*
            logger.info("xeo is " + xeo.getClass().getName());
            logger.info("child is " + aNewXeo.getClass().getName());
            logger.info("fieldName is " + fieldName);
            */
            setVariableValue(xeo, fieldName, aNewXeo, classType);
          }
          catch (EnterpriseFieldException e) {
            throw new EnterpriseLayoutException("Error setting " + objectName + "/" + fieldName + "  Exception:" + e.getMessage(), e);
          }
        }
      }
    }
    else {
      throw new EnterpriseLayoutException("Invalid field type " +
        fieldType + " for field named " + objectName + "/" + fieldName);
    }
  }

  private boolean elementIsEmpty(Element e) {
    boolean retVal = true;

    java.util.List attrs = e.getAttributes();
    for (int i=0; i<attrs.size(); i++) {
      Attribute a = (Attribute)attrs.get(i);
      if (a.getValue().length() > 0) {
        logger.debug(e.getName() + " has attributes with values, must instantiate.");
        return false;
      }
    }

    java.util.List children = e.getChildren();
    for (int i=0; i<children.size(); i++) {
      Element eChild = (Element)children.get(i);
      if (eChild.getContentSize()>0) {
        retVal = elementIsEmpty(eChild);
        if (retVal) {
          logger.debug(e.getName() + " has a child with values, must instantiate.");
          return false;
        }
      }
      else {
        if (eChild.getText().length() > 0) {
          logger.debug("Child element " + eChild.getName() + " of " + e.getName() +
            " has a data in it, must instantiate.");
          return false;
        }
      }
    }

    logger.debug(e.getName() + " doesn't have any data in it");
    return retVal;
  }

  private String removeXmlEscapes(String value) throws REException {
    /*
      Look at the value and replace any Entity References
      with the appropriate values.  The special characters are:
        &amp; (replaced with &)
        &gt; (replaced with >)
        &lt; (replaced with <)
        &quot; (replaced with ")
        &apos; (replaced with ')
      This is necessary because the parser might potential croak
      if any of our data contains these characters.
    */
    String escapedValue = "";

    if (value != null || value.length() > 0) {
      RE gnuRegExp = new RE("\\&amp;");
      escapedValue = gnuRegExp.substituteAll(value,"&");

      RE gnuRegExp2 = new RE("\\&lt;");
      escapedValue = gnuRegExp2.substituteAll(escapedValue,"<");

      RE gnuRegExp3 = new RE("\\&gt;");
      escapedValue = gnuRegExp3.substituteAll(escapedValue,">");

      RE gnuRegExp4 = new RE("\\&quot;");
      escapedValue = gnuRegExp4.substituteAll(escapedValue,"\"");

      RE gnuRegExp5 = new RE("\\&apos;");
      escapedValue = gnuRegExp5.substituteAll(escapedValue,"'");
    }

    return escapedValue;
  }
}
TOP

Related Classes of org.openeai.layouts.XmlLayout

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.