/*******************************************************************************
$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;
}
}