Package org.openeai.config

Source Code of org.openeai.config.EnterpriseFields

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

/**********************************************************************
This file is part of the OpenEAI Application Foundation or
OpenEAI Message Object API created by Tod Jackson
(tod@openeai.org) and Steve Wheat (steve@openeai.org) at
the University of Illinois Urbana-Champaign.

Copyright (C) 2002 The OpenEAI Software Foundation

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

For specific licensing details and examples of how this software
can be used to build commercial integration software or to implement
integrations for your enterprise, visit http://www.OpenEai.org/licensing.
***********************************************************************/

package org.openeai.config;

import java.util.*;

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

import org.openeai.*;
import org.openeai.scrubbers.*;
import org.openeai.xml.*;

/**
* This class wraps the EnterpriseObjects XML documents and provides our Enterprise Message
* objects with all the information they need to serialized themselves to and from different
* formats as well as providing information relating to specific business rules associated
* to specific fields contained in the EnterpriseObjects document (formatting, translations etc.).
* <P>
* Think of this object AS the Java representation of the EnterpriseObjects XML document.
* <P>
  * @author      Tod Jackson (tod@openeai.org)
  * @author      Steve Wheat (steve@openeai.org)
  * @version     3.0  - 28 January 2003
  * @see EnterpriseFormatter
  * @see EnterpriseTranslator
  * @see Field
*/
public class EnterpriseFields extends OpenEaiObject implements org.openeai.PubliclyCloneable {

  private HashMap m_fieldsForObject =
    new HashMap(); // key is string (object name), value is hashmap
  private boolean m_ignoreMissingFields = false;
  private boolean m_ignoreValidation = false;
  private String m_translationType = "";
  private Element m_docRoot = null;
  private String m_objectFieldDelimiter = "/";
  private String m_enterpriseObjectsUri = "";
  //  private static ProducerPool m_mappingProducerPool = null;
  //  private static EnterpriseObjects m_enterpriseObjects = null;

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

  /**
   * This method returns a copy of this EnterpriseFields object.  It is not entirely
   * a "deep" copy as the name implies.  However, the items that are not returned
   * as new objects do not have an impact on the use of this method.  This method
   * is intended to give objects a new copy of this object with the exception
   * of the Enterprise Objects Document Root and the Fields for the Object.  Sharing
   * a copy of those items is allowable because they are only used in "read only" mode
   * by other components of the foundation.
   *<P>
   * @return EnterpriseFields object
   * @throws EnterpriseFieldException
   */
  private final EnterpriseFields deepCopy() throws EnterpriseFieldException {
    EnterpriseFields retFields = new EnterpriseFields();
    retFields.setIgnoreMissingFields(ignoreMissingFields());
    retFields.setIgnoreValidation(ignoreValidation());
    retFields.setEnterpriseObjectsUri(getEnterpriseObjectsUri());
    retFields.setTranslationType(getTranslationType());
    //    retFields.setDocRoot((Element)getDocRoot().clone());
    retFields.setEODocRoot(getEODocRoot());
    retFields.setFieldsForObject(getFieldsForObject());

    return retFields;
  }

  public Object clone() throws CloneNotSupportedException {
    try {
      return deepCopy();
    }
    catch (Exception e) {
      throw new CloneNotSupportedException(e.getMessage());
    }
  }

  /**
   * This method reads through the supplied EnterpriseObjects XML Document and builds
   * itself according to the contents found within that document.  Each "ObjectDefinition" Element
   * found within the EnterpriseObjects document is added to this EnterpriseFields object.  This includes
   * building the EnterpriseFormatter associated to each field that is a child
   * of the each object built as well as any EnterpriseTranslator associated to that
   * field.
   *<P>
   * It recursively includes object definitions found in any included EnterpriseObject document
   * references.
   * <P>
   * This method is called by AppConfig when a Message object is being configured.
   *<P>
   * @param doc Document the JDOM Document that was associated to the object being
   * configured in the application deployment document.
   * @throws EnterpriseFieldException if errors occur building the EnterpriseFields object.
   */
  public final void init(Document doc) throws EnterpriseFieldException {

    logger.debug("Initializing EnterpriseFields...");

    // recursively parse and build all 'included' enterprise object document references.
    Element eIncludeList = doc.getRootElement().getChild("IncludeList");
    if (eIncludeList != null) {
      XmlDocumentReader xmlReader = new XmlDocumentReader();
      java.util.List eDocUriList = eIncludeList.getChildren();
      for (int i = 0; i < eDocUriList.size(); i++) {
        Element eDocUri = (Element)eDocUriList.get(i);
        String docUri = eDocUri.getText();
        try {
          Document enterpriseObjectsDoc =
            xmlReader.initializeDocument(docUri, false);
          init(enterpriseObjectsDoc);
        }
        catch (XmlDocumentReaderException e) {
          logger.fatal(e.getMessage(), e);
          String msg =
            "Exception occurred parsing the enteerprise objects document " +
            docUri + ".  Exception: " + e.getMessage();
          logger.fatal(msg);
          throw new EnterpriseFieldException(msg, e);
        }
      }
    }

    setEODocRoot(doc.getRootElement());

    // Build the enterprise fields object from information found in the EnterpriseObjects document.
    // The primary purpose of this is to get the ObjectDefinition's definition because it's used
    // below to query the EnterpriseFieldService.  If nothing is returned from that query, or,
    // if no query is performed we'll just use what we've already got in the document.
    logger.debug("Building initial EnterpriseFields from EnterpriseObjects.xml...");
    //    java.util.List lObjectDefs = getDocRoot().getChildren("ObjectDefinition");
    java.util.List lObjectDefs =
      doc.getRootElement().getChildren("ObjectDefinition");
    for (int i = 0; i < lObjectDefs.size(); i++) {
      Element eObjectDef = (Element)lObjectDefs.get(i);
      try {
        addFieldsForObject(eObjectDef);
      }
      catch (Exception e) {
        String errMessage =
          "Exception intializing initial version of EnterpriseFields.  Exception: " +
          e.getMessage();
        logger.fatal(errMessage, e);
        throw new EnterpriseFieldException(errMessage, e);
      }
    }
  }

  /*
  private void setExternalMappingProducerPool(ProducerPool pool) {
    m_mappingProducerPool = pool;
  }
  private ProducerPool getExternalMappingProducerPool() {
    return m_mappingProducerPool;
  }
  */

  /**
   * Re-initializes this EnterpriseFields object by re-reading the EnterpriseObjects.xml document
   * from the URI specified in the configuration document.  This can be called by application
   * developers if the object they're working with has "dynamic" field rules and translations
   * that might change.  These changes will be reflected in EnterpriseObjects.xml and when
   * this method is called, they will be applied to this EntepriseFields object.
   *<P>
   * This is the same basic processing that occurs when the MessageObject is initially configured at
   * application startup time.
   *
   * @throws EnterpriseFieldException if any errors occur initializing.
   */
  public final void reinitialize() throws EnterpriseFieldException {
    if (getEnterpriseObjectsUri() != null &&
        getEnterpriseObjectsUri().length() > 0) {
      XmlDocumentReader xmlReader = new XmlDocumentReader();
      try {
        Document enterpriseObjectsDoc =
          xmlReader.initializeDocument(getEnterpriseObjectsUri(), false);
        init(enterpriseObjectsDoc);
      }
      catch (Exception e) {
        String errMessage =
          "[EnterpriseFields] Exception reinitializing from " +
          getEnterpriseObjectsUri() + ".  Exception: " + e.getMessage();
        logger.fatal(errMessage);
        throw new EnterpriseFieldException(errMessage, e);
      }
    }
  }

  /**
   * Sets the EnterpriseObjects document uri associated to this EnterpriseFields object.
   * This document contains the rules that will be use to build the EnterpriseFields object.
   *
   * @param uri String URI to the EnterpriseObjects document.  Can be file system or web uri.
   */
  public final void setEnterpriseObjectsUri(String uri) {
    m_enterpriseObjectsUri = uri;
  }

  /**
   * Returns the EnterpriseObjects document uri associated to this EnterpriseFields object.
   * This document contains the rules that will be use to build the EnterpriseFields object.
   *
   * @return String URI to the EnterpriseObjects document.  Can be file system or web uri.
   */
  public final String getEnterpriseObjectsUri() {
    return m_enterpriseObjectsUri;
  }

  private void setEODocRoot(Element root) {
    m_docRoot = root;
  }

  public Element getEODocRoot() {
    return m_docRoot;
  }

  private void addFieldsForObject(Element eObjectDef) throws EnterpriseFieldException {
    Attribute aName = eObjectDef.getAttribute("name");
    String objectDefName = null;
    if (aName != null) {
      objectDefName = aName.getValue();
    }
    else {
      logger.debug("No 'name' attribute associated to element " +
                   eObjectDef.getName());
      return;
    }
    if (m_fieldsForObject.containsKey(objectDefName)) {
      //    if (ObjectDefinitions.OBJECTS.containsKey(objectDefName)) {
      logger.debug("Field " + objectDefName +
                   " already exists.  No need to add it.");
      return;
    }
    logger.debug("Building EnterpriseFields for " + objectDefName);
    java.util.List lFields = eObjectDef.getChildren("Field");
    HashMap hm_fields = new HashMap();
    for (int i = 0; i < lFields.size(); i++) {
      Element eField = (Element)lFields.get(i);
      String fieldType = eField.getAttribute("type").getValue();
      String fieldName = eField.getAttribute("name").getValue();
      Attribute aIsKey = eField.getAttribute("isKey");
      boolean isKey = false;
      if (aIsKey != null) {
        isKey = new Boolean(aIsKey.getValue()).booleanValue();
      }
      Element eFormatter = eField.getChild("Format");
      if (eFormatter != null) {
        EnterpriseFormatter aFormatter =
          buildFormatter(objectDefName, fieldName, eFormatter);
        Field aField = new Field();
        aField.setParentObjectName(objectDefName);
        aField.setFieldName(fieldName);
        aField.setIsKey(isKey);
        aField.setFormatter(aFormatter);
        hm_fields.put(aField.getFieldName(), aField);

        // Note, when these fields are pulled from the EnterpriseFields object
        // we'll have to look for fields that match a given name and have a
        // parent object name equal to the object using the EnterpriseFields
        // object (used in getEnterpriseValue, getApplicationValue etc.
        // We'll also need to remove the goofy "@" from the field name
        // in calls to these methods.
      }
      else {
        throw new EnterpriseFieldException("The field " + fieldName +
                                           " in the object " +
                                           objectDefName +
                                           " does not have a" +
                                           " Format associated with it.  This is required for all simple fields.");
      }
      if (fieldType.equals("Object") == false) {
        // the field is an 'Element' or an 'Attribute'
        // If it's not an object, it must have a Format associated with it.
//        Element eFormatter = eField.getChild("Format");
//        if (eFormatter != null) {
//          EnterpriseFormatter aFormatter =
//            buildFormatter(objectDefName, fieldName, eFormatter);
//          Field aField = new Field();
//          aField.setParentObjectName(objectDefName);
//          aField.setFieldName(fieldName);
//          aField.setIsKey(isKey);
//          aField.setFormatter(aFormatter);
//          hm_fields.put(aField.getFieldName(), aField);
//
//          // Note, when these fields are pulled from the EnterpriseFields object
//          // we'll have to look for fields that match a given name and have a
//          // parent object name equal to the object using the EnterpriseFields
//          // object (used in getEnterpriseValue, getApplicationValue etc.
//          // We'll also need to remove the goofy "@" from the field name
//          // in calls to these methods.
//        }
//        else {
//          throw new EnterpriseFieldException("The field " + fieldName +
//                                             " in the object " +
//                                             objectDefName +
//                                             " does not have a" +
//                                             " Format associated with it.  This is required for all simple fields.");
//        }
      }
      else {
        // if the field is a 'key' field, we need to indicate that in the
        // parent object's fields hashmap.  By doing this, we're allowing
        // complex objects to be part of a key in another object.  Hopefully!
//        if (isKey) {
//          Field aField = new Field();
//          aField.setParentObjectName(objectDefName);
//          aField.setFieldName(fieldName);
//          aField.setIsKey(isKey);
//          hm_fields.put(aField.getFieldName(), aField);
//        }

        // We need to call this method again passing the ObjectDefinition associated
        // with this field that is a complex "Object".
        // The field is an 'Object' (complex element)
        Element eChildObjectDef = eField.getChild("ObjectDefinition");
        if (eChildObjectDef == null &&
            m_fieldsForObject.containsKey(fieldName) == false) {
          //        if (eChildObjectDef == null && ObjectDefinitions.OBJECTS.containsKey(fieldName) == false) {
          XmlElementLocator xmlLoc = new XmlElementLocator();
          //          eChildObjectDef = xmlLoc.getElementByAttributeNameValue(getDocRoot(),"name",fieldName);
          Element eRoot = eObjectDef.getDocument().getRootElement();
          eChildObjectDef =
              xmlLoc.getElementByAttributeNameValue(eObjectDef.getDocument().getRootElement(),
                                                    "name", fieldName);
          if (eChildObjectDef == null) {
            throw new EnterpriseFieldException("The field " + fieldName +
                                               " in the object " +
                                               objectDefName +
                                               " does not have an" +
                                               " ObjectDefinition associated with it.  " +
                                               "This is required for all complex fields (fields that are objects).");
          }
          else {
            addFieldsForObject(eChildObjectDef);
          }
        }
      }
    }
    addFieldsForObject(objectDefName, hm_fields);
  }

  private EnterpriseFormatter buildFormatter(String objectName,
                                             String fieldName,
                                             Element eFormatter) throws EnterpriseFieldException {

    // Build formatter object
    logger.debug("Building Formatter for " + objectName + "/" + fieldName);
    EnterpriseFormatter aFormatter = new EnterpriseFormatter();
    if (eFormatter != null) {
      Attribute aDatatype = eFormatter.getAttribute("datatype");
      if (aDatatype != null) {
        aFormatter.setDatatype(aDatatype.getValue());
      }
      aFormatter.setRequired(new Boolean(eFormatter.getAttribute("required").getValue()).booleanValue());

      // Build the translator
      Element eTranslator = eFormatter.getChild("Translation");
      if (eTranslator != null) {
        logger.debug("Found a Translator for " + objectName + "/" + fieldName);
        EnterpriseTranslator aTranslator =
          buildTranslator(objectName, fieldName, eTranslator);
        if (aTranslator != null) {
          aFormatter.setTranslator(aTranslator);
        }
      }

      // Get the mask information
      Element eMask = eFormatter.getChild("Mask");
      if (eMask != null) {
        aFormatter.setMask(eMask.getText());
      }

      // Build srubber object(s)
      java.util.List lScrubbers = eFormatter.getChildren("Scrubber");
      logger.debug("Field " + fieldName + " has " + lScrubbers.size() +
                   " Scrubber(s)");
      for (int i = 0; i < lScrubbers.size(); i++) {
        Element eScrubber = (Element)lScrubbers.get(i);
        if (eScrubber != null) {
          String scrubberClass = eScrubber.getChild("ClassName").getText();
          String sequence = eScrubber.getAttribute("sequence").getValue();
          try {
            // Need to do this mulitple times based on sequence
            logger.debug("Instantiating scrubber: " + scrubberClass +
                         " for field " + fieldName);
            java.lang.Class obj = java.lang.Class.forName(scrubberClass);
            EnterpriseScrubber aScrubber =
              (EnterpriseScrubber)obj.newInstance();
            aScrubber.setSequence(Integer.parseInt(sequence));
            if (aScrubber.getSequence() <= aFormatter.getScrubbers().size()) {
              aFormatter.insertScrubber(aScrubber.getSequence() - 1,
                                        aScrubber);
            }
            else {
              aFormatter.addScrubber(aScrubber);
            }
          }
          catch (Exception e) {
            String errMessage =
              "Error instantiating Scrubber " + scrubberClass +
              "  Exception: " + e.getMessage();
            throw new EnterpriseFieldException(errMessage, e);
          }
        }
      }

      Element eLength = eFormatter.getChild("Length");
      if (eLength != null) {
        aFormatter.setLengthType(eLength.getAttribute("type").getValue());
        try {
          aFormatter.setLength(Integer.parseInt(eLength.getAttribute("value").getValue()));
          //        aFormatter.setLength(Integer.parseInt(eLength.getText()));
        }
        catch (Exception e) {
          logger.warn("Invalid length " +
                      eLength.getAttribute("value").getValue() +
                      " specified for field " + objectName + "/" + fieldName);
        }
      }
    }
    return aFormatter;
  }

  private EnterpriseTranslator buildTranslator(String objectName,
                                               String fieldName,
                                               Element eTrans) throws EnterpriseFieldException {

    boolean errorOccurred = false;
    String errorMessage = "";
    EnterpriseTranslator aTrans = new EnterpriseTranslator();
    logger.debug("Building Translation object for field: " + objectName + "/" +
                 fieldName);
    java.util.List maps = eTrans.getChildren("Mapping");
    ArrayList vMapsForField = new ArrayList();
    for (int m = 0; m < maps.size(); m++) {
      Element eMap = (Element)maps.get(m);
      java.util.List lvValues = eMap.getChildren("EnterpriseValue");
      for (int o = 0; o < lvValues.size(); o++) {
        EnterpriseMapping aMap = new EnterpriseMapping();
        aMap.setFieldName(fieldName);
        Element eEnterpriseValue = (Element)lvValues.get(o);
        aMap.setEnterpriseValue(eEnterpriseValue.getText());
        java.util.List values = eMap.getChildren("ApplicationValue");
        HashMap appValues = addValuesToMapping(fieldName, values);
        logger.debug("Added " + appValues.size() + " appValues for " +
                     objectName + m_objectFieldDelimiter + fieldName +
                     " to Mapping.");
        if (appValues.size() > 0) {
          aMap.setApplicationValues(appValues);
          //          logger.debug(objectName + " EnterpriseValue for mapping [" + o + "] is: " + aMap.getEnterpriseValue());
        }
        vMapsForField.add(aMap);
      }
    }

    try {
      aTrans.addMapping(objectName + m_objectFieldDelimiter + fieldName,
                        vMapsForField);
      logger.debug("Added " + vMapsForField.size() + " mappings for " +
                   objectName + m_objectFieldDelimiter + fieldName);
    }
    catch (EnterpriseTranslationException e) {
      errorOccurred = true;
      errorMessage = e.getMessage();
      logger.warn("An Error occurred building the map for " + fieldName +
                  ": " + errorMessage);
    }

    // don't want to do this or we'll be really screwed.
    /*
    if (errorOccurred) {
      throw new EnterpriseFieldException(errorMessage);
    }
    */

    if (aTrans.getMappings().size() > 0) {
      return aTrans;
    }
    else {
      return null;
    }
  }

  private HashMap addValuesToMapping(String fieldName, java.util.List values) {
    //     logger.debug("There are " + values.size() + " application values for " + fieldName);
    HashMap hm = new HashMap();
    boolean foundApp = false;
    for (int n = 0; n < values.size(); n++) {
      Element aValue = (Element)values.get(n);
      String appValue = (String)aValue.getChild("Value").getText().trim();
      String appName = aValue.getAttribute("applicationName").getValue();
      boolean preferred =
        new Boolean(aValue.getAttribute("preferred").getValue()).booleanValue();
      if (getTranslationType().equalsIgnoreCase("all")) {
        if (preferred) {
          hm.put(appName, appValue);
          foundApp = true;
        }
      }
      else {
        //        logger.debug("EnterpriseFields, getAppName() is: " + getAppName());
        //        logger.debug("EnterpriseFields, appName is: " + appName);
        if (appName.equalsIgnoreCase(getAppName()) ||
            appName.equalsIgnoreCase("Default")) {
          //          logger.debug("EnterpriseFields, adding " + fieldName + "/" + appValue + " to translations for application: " + appName);
          hm.put(appValue, appName);
          //          if (appName.equals(getAppName())) {
          foundApp = true;
          //          }
        }
      }
    }
    if (foundApp) {
      return hm;
    }
    else {
      return new HashMap();
    }
  }

  /**
   * Sets the translation type that should be used when converting from application specific to enterprise value as specified
   * in the application's deployment document and that is associated to the message object being configured.
   * <P>
   * Currently, two types are supported:
   * <ul>
   * <li>application - build the EnterpriseTranslator object only for a given application.  This means, the translator
   * will not have any knowledge of translations associated to any application except for the application being configured.
   * This is typically the most commonly used translation type.  The only time when this value should not be used is when the
   * application needs to know about translations associated to other applications.  This is the case with some infrastructural
   * applications like Routers and Proxies.
   * <li>all - build the EnterpriseTranslator object with translation information for all applications.  This is typically only
   * used for enterprise wide infrastructural type applications/gateways like Routers and Proxies.
   * </ul>
   * <P>
   * @param translationType String the translation type associated to the EnterpriseTranslator that will be used to translate from application
   * specific values to enterprise values.  Valid types are:  "application" and "all".
   */
  public final void setTranslationType(String translationType) {
    m_translationType = translationType;
  }

  /**
   * Returns the translation type that should be used when converting from application specific to enterprise value as specified
   * in the application's deployment document and that is associated to the message object being configured.
   * <P>
   * Currently, two types are supported:
   * <ul>
   * <li>application - build the EnterpriseTranslator object only for a given application.  This means, the translator
   * will not have any knowledge of translations associated to any application except for the application being configured.
   * This is typically the most commonly used translation type.  The only time when this value should not be used is when the
   * application needs to know about translations associated to other applications.  This is the case with some infrastructural
   * applications like Routers and Proxies.
   * <li>all - build the EnterpriseTranslator object with translation information for all applications.  This is typically only
   * used for enterprise wide infrastructural type applications/gateways like Routers and Proxies.
   * </ul>
   * <P>
   * @return String the translation type associated to the EnterpriseTranslator that will be used to translate from application
   * specific values to enterprise values.  Valid types are:  "application" and "all".
   */
  public final String getTranslationType() {
    return m_translationType;
  }

  /**
   * Sets the flag indicating whether or not this EnterpriseFields object will be allowed to work if some of the object
   * definitions specified in an objects definition are missing from the EnterpriseObjects document.  This is used
   * when a application value is being converted to an enterprise value.  If this is true, missing object definition information
   * will be allowed.  This should ONLY ever be false in a Development environment.  Even then, it's arguable whether it should EVER
   * be set to true.
   *<P>
   * It was originally intended to allow development work to continue while the EnterpriseObjects document is finished up.
   *<P>
   * @param ignore boolean true means allow missing fields, false means throw an error if any missing fields exist.
   */
  public final void setIgnoreMissingFields(boolean ignore) {
    m_ignoreMissingFields = ignore;
  }

  /**
   * Returns the flag indicating whether or not missing field definitions will be allowed or not.
   *<P>
   * @return boolean true means missing fields will be allowe, false means they won't and an error will occur if they do.
   */
  public final boolean ignoreMissingFields() {
    return m_ignoreMissingFields;
  }

  /**
   * Sets a flag indicating whether or not "object" validation should be used when converting an application
   * value to an enterprise value.  If this value is set to true in the MessageObject's Configuration, any value
   * passed to a setter method on that object will be allowed.  No formatting rules, translations or scrubbing will occur
   * on that data.  While typically, one would never set this to 'true' there are cases where this needs to be set
   * to allow data into an object during testing and when making a copy of an object (@see org.openeai.moa.XmlEnterpriseObject#deepCopy())
   *
   * @param ignore boolean true means validation will be ignored and any value passed to a setter method will be allowed, false
   * means all data passed to the setter methods will be ran through the object's EnterpriseFormatter to apply rules to and validate
   * the data being passed.
   */
  public final void setIgnoreValidation(boolean ignore) {
    m_ignoreValidation = ignore;
  }

  /**
   * Returns the flag indicating whether or not "object" validation is turned on or not.  This method is called
   * when application data is ran through the EnterpriseFields object to potentially convert the data from application
   * value to Enterprise value.
   *<P>
   * @return boolean true means validation will be ignored and any value passed to a setter method will be allowed, false
   * means all data passed to the setter methods will be ran through the object's EnterpriseFormatter to apply rules to and validate
   * the data being passed.
   */
  public final boolean ignoreValidation() {
    return m_ignoreValidation;
  }

  /**
   * This method adds an ObjectDefinition (all fields and their rules for an object) to a
   * HashMap that is keyed by object name.  For example, if the object being built
   * is the BasicPerson object, there would be a BasicPerson entry added with a key
   * of "BasicPerson" and a value consisting of another HashMap that is all the child
   * Fields of that BasicPerson.  This is all specified in the EnterpriseObjects document
   * associated to the BasicPerson MessageObject in the configuration document for the application
   * that the BasicPerson object is a part of.  Additionally, there would be entries added
   * for all other objects listed in that EnterpriseObjects document.
   *<P>
   * @param objectName String the name of the object definition being added.
   * @param fields HashMap a list of all Fields that are children of the object being added.
   * @see Field
   */
  public final void addFieldsForObject(String objectName, HashMap fields) {
    m_fieldsForObject.put(objectName, fields);
    //    ObjectDefinitions.OBJECTS.put(objectName, fields);
  }

  /**
   * Returns the HashMap of all fields this EnterpriseFields object knows about.
   *
   * @return HashMap the list of all fields associated to this EnterpriseFields object.
   */
  public final HashMap getFieldsForObject() {
    return m_fieldsForObject;
  }

  /**
   * Sets the HashMap of all fields this EnterpriseFields object knows about.
   *
   * @return HashMap the list of all fields associated to this EnterpriseFields object.
   */
  public final void setFieldsForObject(HashMap fields) {
    m_fieldsForObject = fields;
  }

  /**
   * Returns the HashMap of all fields this EnterpriseFields object knows about that corresponds
   * to a specific object name.  For example, if someone needs to get a list of all Field
   * objects associated to the BasicPerson object, they'd call this method passing
   * "BasicPerson" as the parm.  This will return all child Field objects of BasicPerson.
   *
   * @return HashMap the list of all fields associated to this EnterpriseFields object.
   * @see Field
   */
  public final HashMap getFieldsForObject(String objectName) {
    if (m_fieldsForObject.containsKey(objectName)) {
      return (HashMap)m_fieldsForObject.get(objectName);
    }
    /*
    if (ObjectDefinitions.OBJECTS.containsKey(objectName)) {
      return(HashMap)ObjectDefinitions.OBJECTS.get(objectName);
    }
    */
    return new HashMap();
  }

  private Field getField(String name, HashMap fields) {
    if (fields.containsKey(name)) {
      return (Field)fields.get(name);
    }
    return null;
  }

  /**
   * Returns a list of all key fields associated to an object.  A field is specified as a
   * "key" field in the EnterpriseObjects document.  This attribute is typically used
   * so layout managers can returned a consistent image of an object when that object
   * gets serialized etc. so that serialized representation of the object will always
   * match other things being equal.  Additionally, it is used often to determine in
   * the case of Updates on objects with complex repeatable fields, which one of those
   * repeatable child objects has changed.  The key fields cannot change so it is able
   * to find objects with matching key fields, and if they're different, it knows that
   * particular child object needs to be updated.
   *<P>
   * @return java.util.List the list of names of all key fields for the object name passed in.
   */
  public final java.util.List getKeyNamesForField(String objectName) {
    ArrayList retList = new ArrayList();
    HashMap hm = getFieldsForObject(objectName);
    Iterator it = hm.keySet().iterator();
    while (it.hasNext()) {
      String key = (String)it.next();
      Field aField = (Field)hm.get(key);
      if (aField.isKey()) {
        retList.add(aField.getFieldName());
      }
    }
    return retList;
  }

  /**
   * Returns the application specific value that corresponds to the enterprise value passed in.
   * If a Field has a translation associated to it, that data can be translated both from application to enterprise value
   * and vice-versa.  If not translation is associated to the field, the enterprise value is returned.
   *<P>
   * @return String the application specific value that corresponds to the enterprise value passed in.  If no
   * translator is associated to the field, the enterprise value is returned.
   * @param objectName String the name of the parent object of the field for which data is being translated
   * @param appName String the name of the target application that the enterprise value should be translated to
   * @param fieldName String the name of the field that needs to have the data translated for it.
   * @param enterpriseValue String the enterprise value that needs to be "reverse translated"
   * @throws EnterpriseFieldException if any errors occur converting the enterprise value to the application value
   * @see EnterpriseFormatter
   * @see EnterpriseTranslator
   */
  public final String getApplicationValue(String objectName, String appName,
                                          String fieldName,
                                          String enterpriseValue) throws EnterpriseFieldException {

    String objField = objectName + m_objectFieldDelimiter + fieldName;

    // NEW START 8/8
    HashMap fields = getFieldsForObject(objectName);
    Field field = getField(fieldName, fields);
    // NEW END 8/8

    String appValue = "";

    if (field != null) {
      EnterpriseFormatter aFormatter = field.getFormatter();
      if (aFormatter != null) {
        EnterpriseTranslator aTrans = aFormatter.getTranslator();
        if (aTrans != null) {
          // Translation
          try {
            appValue =
                aTrans.convertToAppValue(appName, objField, fieldName, enterpriseValue);
          }
          catch (EnterpriseTranslationException e) {
            String errMsg =
              "FIELD: " + objField + " is invalid.  Exception: " +
              e.getMessage();
            logger.fatal("EnterpriseFields:Translation Error: " + errMsg);
            throw new EnterpriseFieldException(errMsg, e);
          }
        }
        else {
          // If the Field doesn't have a translation associated with it,
          // we'll just use the Enterprise Value from the message.  This is OKAY.
          logger.debug("[EnterpriseFields.getApplicationValue] No Translator associated to field " +
                       objField);
          appValue = enterpriseValue;
        }
      }
      else {
        // If a field doesn't have a Format associated with it, this is an error!
        String errMsg =
          "Field " + objField + " doesn't have a Format associated with it.";
        logger.fatal("EnterpriseFields:Format Error: " + errMsg);
        throw new EnterpriseFieldException(errMsg);
      }
    }
    else {
      if (ignoreMissingFields() == false) {
        String errMsg =
          "Field " + objField + " doesn't exist in the Enterprise Field list.";
        logger.fatal("EnterpriseFields:MissingField Error: " + errMsg);
        throw new EnterpriseFieldException(errMsg);
      }
      else {
        appValue =
            enterpriseValue; // Ignore this error (this should only happen in testing)
      }
    }
    return appValue;
  }

  /**
   * Returns the "enterprise value" that corresponds to the application value passed in based
   * on formatting rules specified in the EnterpriseObjects document.  This is the method that takes
   * the application value passed in, runs it through the EnterpriseFormattter object associated to the
   * Field (specified by the field namd passed in) and returns the results of those rules being applied.
   * <P>
   * @return String the enterprise value after all formatting rules have been applied.
   * @param objectName String the name of the parent object of which the field is a child.
   * @param fieldName String the name of the field that has the EnterpriseFormatter that needs to be used to apply the rules.
   * @param appValue String the application specific value that needs to have the formatting rules applied to it.
   * @throws EnterpriseFieldException if any formatting rule is broken
   * @see EnterpriseFormatter
   * @see EnterpriseTranslator
   * @see Field
   */
  public final String getEnterpriseValue(String objectName, String fieldName,
                                         String appValue) throws EnterpriseFieldException {
    // Get the field.
    // Get the translator for the field
    // If a translation is performed, we're done, return the enterprise value
    // If not, we need to validate the format of the value passed in.

    String objField = objectName + m_objectFieldDelimiter + fieldName;

    if (ignoreValidation()) {
      return appValue;
    }

    // NEW START 8/8
    HashMap fields = getFieldsForObject(objectName);
    if (fields == null) {
      logger.fatal("Could not find any fields for " + objectName);
    }
    Field field = getField(fieldName, fields);
    // NEW END 8/8

    // If it's not a required field, we don't have to worry about
    // formatting, translating or scrubbing if it's null or empty...
    if (appValue == null || appValue.length() == 0) {
      appValue = ""; // Just to be safe.
      if (field != null) {
        if (field.isRequired() == false) {
          logger.debug(objField +
                       " is being populated with a null value so we're going to convert it to an empty string.");
        }
      }
    }

    String enterpriseValue = appValue;

    if (field != null) {
      EnterpriseFormatter aFormatter = field.getFormatter();
      if (aFormatter != null) {
        EnterpriseTranslator aTrans = aFormatter.getTranslator();
        if (aTrans != null && aTrans.getMappings().size() > 0) {
          // Translation
          try {
            enterpriseValue =
                aTrans.convertToEnterpriseValue(objField, fieldName,
                                                enterpriseValue,
                                                field.isRequired());
            if (enterpriseValue == null || enterpriseValue.length() == 0) {
              if (field != null) {
                if (field.isRequired() == false) {
                  return "";
                }
              }
            }
          }
          catch (EnterpriseTranslationException e) {
            String errMsg =
              "FIELD: " + objField + " is invalid.  Exception: " +
              e.getMessage();
            logger.fatal("EnterpriseFields:Translation Error: " + errMsg);
            throw new EnterpriseFieldException(errMsg, e);
          }
        }
        if (enterpriseValue.equals(appValue) ||
            enterpriseValue.length() == 0) { // No translation was performed
          // Scrubbing
          // Need to call each scrubber here (by sequence).
          for (int i = 0; i < aFormatter.getScrubbers().size(); i++) {
            try {
              EnterpriseScrubber aScrubber = aFormatter.getScrubber(i);
              if (aScrubber != null) {
                enterpriseValue = aScrubber.scrub(enterpriseValue);
              }
            }
            catch (EnterpriseScrubberException e) {
              String errMsg =
                "FIELD: " + objField + " is invalid.  Exception:" +
                e.getMessage();
              logger.fatal("EnterpriseFields:Scrubber Error: " + errMsg);
              throw new EnterpriseFieldException(errMsg, e);
            }
          }
          // Format
          try {
            enterpriseValue = aFormatter.format(enterpriseValue);
          }
          catch (InvalidFormatException e) {
            String errMsg =
              "FIELD: " + objField + " is invalid.  Exception: " +
              e.getMessage();
            logger.debug("EnterpriseFields:Format Error: " + errMsg);
            throw new EnterpriseFieldException(errMsg, e);
          }
          /*
          try {
            enterpriseValue = aFormatter.applyMask(enterpriseValue);
          }
          catch (EnterpriseMaskException e) {
          }
          */
        }
      }
      else {
        String errMsg =
          "Field " + objField + " doesn't have a Format associated with it!";
        logger.fatal("EnterpriseFields:Format Error: " + errMsg);
        throw new EnterpriseFieldException(errMsg);
      }
    }
    else {
      if (ignoreMissingFields() == false) {
        String errMsg =
          "Field " + objField + " doesn't exist in the Enterprise Field list.";
        logger.fatal("EnterpriseFields:MissingField Error: " + errMsg);
        throw new EnterpriseFieldException(errMsg);
      }
    }

    logger.debug("Returing enterprise value: '" + enterpriseValue + "' for " +
                 objField + " which was converted from application value: '" +
                 appValue + "'");

    return enterpriseValue;
  }
}
TOP

Related Classes of org.openeai.config.EnterpriseFields

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.