You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ad...@apache.org on 2013/05/01 10:16:56 UTC

svn commit: r1477929 [1/2] - in /ofbiz/trunk/framework: entity/src/org/ofbiz/entity/ entity/src/org/ofbiz/entity/datasource/ entity/src/org/ofbiz/entity/jdbc/ entity/src/org/ofbiz/entity/model/ entity/src/org/ofbiz/entity/test/ webtools/src/org/ofbiz/w...

Author: adrianc
Date: Wed May  1 08:16:56 2013
New Revision: 1477929

URL: http://svn.apache.org/r1477929
Log:
Moving toward immutable entity model classes. Also some code cleanups, simplified API, and JavaDocs.

Modified:
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/DatabaseUtil.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/DynamicViewEntity.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelChild.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntity.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntityChecker.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelField.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelIndex.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelKeyMap.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelReader.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelRelation.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java
    ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/GenericWebEvent.java
    ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/WebToolsServices.java

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java?rev=1477929&r1=1477928&r2=1477929&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java Wed May  1 08:16:56 2013
@@ -1215,8 +1215,7 @@ public class GenericDelegator implements
         }
 
         Map<String, Object> fields = new HashMap<String, Object>();
-        for (int i = 0; i < relation.getKeyMapsSize(); i++) {
-            ModelKeyMap keyMap = relation.getKeyMap(i);
+        for (ModelKeyMap keyMap : relation.getKeyMaps()) {
             fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName()));
         }
 
@@ -1960,8 +1959,7 @@ public class GenericDelegator implements
         if (byAndFields != null) {
             fields.putAll(byAndFields);
         }
-        for (int i = 0; i < relation.getKeyMapsSize(); i++) {
-            ModelKeyMap keyMap = relation.getKeyMap(i);
+        for (ModelKeyMap keyMap : relation.getKeyMaps()) {
             fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName()));
         }
 
@@ -1986,8 +1984,7 @@ public class GenericDelegator implements
         if (byAndFields != null) {
             fields.putAll(byAndFields);
         }
-        for (int i = 0; i < relation.getKeyMapsSize(); i++) {
-            ModelKeyMap keyMap = relation.getKeyMap(i);
+        for (ModelKeyMap keyMap : relation.getKeyMaps()) {
             fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName()));
         }
 
@@ -2035,8 +2032,7 @@ public class GenericDelegator implements
         }
 
         Map<String, Object> fields = new HashMap<String, Object>();
-        for (int i = 0; i < relation.getKeyMapsSize(); i++) {
-            ModelKeyMap keyMap = relation.getKeyMap(i);
+        for (ModelKeyMap keyMap : relation.getKeyMaps()) {
             fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName()));
         }
 

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java?rev=1477929&r1=1477928&r2=1477929&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java Wed May  1 08:16:56 2013
@@ -1559,8 +1559,7 @@ public class GenericEntity implements Ma
             if ("one".equalsIgnoreCase(relation.getType())) {
                 // see if the related value exists
                 Map<String, Object> fields = new HashMap<String, Object>();
-                for (int i = 0; i < relation.getKeyMapsSize(); i++) {
-                    ModelKeyMap keyMap = relation.getKeyMap(i);
+                for (ModelKeyMap keyMap : relation.getKeyMaps()) {
                     fields.put(keyMap.getRelFieldName(), this.get(keyMap.getFieldName()));
                 }
                 EntityFieldMap ecl = EntityCondition.makeCondition(fields);
@@ -1569,10 +1568,8 @@ public class GenericEntity implements Ma
                     if (insertDummy) {
                         // create the new related value (dummy)
                         GenericValue newValue = this.getDelegator().makeValue(relation.getRelEntityName());
-                        Iterator<ModelKeyMap> keyMapIter = relation.getKeyMapsIterator();
                         boolean allFieldsSet = true;
-                        while (keyMapIter.hasNext()) {
-                            ModelKeyMap mkm = keyMapIter.next();
+                        for (ModelKeyMap mkm : relation.getKeyMaps()) {
                             if (this.get(mkm.getFieldName()) != null) {
                                 newValue.set(mkm.getRelFieldName(), this.get(mkm.getFieldName()));
                                 if (Debug.infoOn()) Debug.logInfo("Set [" + mkm.getRelFieldName() + "] to - " + this.get(mkm.getFieldName()), module);

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java?rev=1477929&r1=1477928&r2=1477929&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java Wed May  1 08:16:56 2013
@@ -936,11 +936,8 @@ public class GenericDAO {
         }
 
         // construct assoc->target relation string
-        int kmsize = modelRelationTwo.getKeyMapsSize();
         StringBuilder wheresb = new StringBuilder();
-
-        for (int i = 0; i < kmsize; i++) {
-            ModelKeyMap mkm = modelRelationTwo.getKeyMap(i);
+        for (ModelKeyMap mkm : modelRelationTwo.getKeyMaps()) {
             String lfname = mkm.getFieldName();
             String rfname = mkm.getRelFieldName();
 
@@ -952,12 +949,9 @@ public class GenericDAO {
 
         // construct the source entity qualifier
         // get the fields from relation description
-        kmsize = modelRelationOne.getKeyMapsSize();
         Map<ModelField, Object> bindMap = new HashMap<ModelField, Object>();
-
-        for (int i = 0; i < kmsize; i++) {
+        for (ModelKeyMap mkm : modelRelationOne.getKeyMaps()) {
             // get the equivalent column names in the relation
-            ModelKeyMap mkm = modelRelationOne.getKeyMap(i);
             String sfldname = mkm.getFieldName();
             String lfldname = mkm.getRelFieldName();
             ModelField amf = modelEntityOne.getField(lfldname);

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/DatabaseUtil.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/DatabaseUtil.java?rev=1477929&r1=1477928&r2=1477929&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/DatabaseUtil.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/DatabaseUtil.java Wed May  1 08:16:56 2013
@@ -2280,12 +2280,10 @@ public class DatabaseUtil {
 
     public String makeFkConstraintClause(ModelEntity entity, ModelRelation modelRelation, ModelEntity relModelEntity, int constraintNameClipLength, String fkStyle, boolean useFkInitiallyDeferred) {
         // make the two column lists
-        Iterator<ModelKeyMap> keyMapsIter = modelRelation.getKeyMapsIterator();
         StringBuilder mainCols = new StringBuilder();
         StringBuilder relCols = new StringBuilder();
 
-        while (keyMapsIter.hasNext()) {
-            ModelKeyMap keyMap = keyMapsIter.next();
+        for (ModelKeyMap keyMap : modelRelation.getKeyMaps()) {
 
             ModelField mainField = entity.getField(keyMap.getFieldName());
             if (mainField == null) {
@@ -2712,11 +2710,9 @@ public class DatabaseUtil {
     }
 
     public String makeIndexClause(ModelEntity entity, ModelIndex modelIndex) {
-        Iterator<ModelIndex.Field> fieldsIter = modelIndex.getFieldsIterator();
         StringBuilder mainCols = new StringBuilder();
 
-        while (fieldsIter.hasNext()) {
-            ModelIndex.Field field = fieldsIter.next();
+        for (ModelIndex.Field field : modelIndex.getFields()) {
             ModelIndex.Function function = field.getFunction();
             if (mainCols.length() > 0) {
                 mainCols.append(", ");
@@ -2931,11 +2927,9 @@ public class DatabaseUtil {
     }
 
     public String makeFkIndexClause(ModelEntity entity, ModelRelation modelRelation, int constraintNameClipLength) {
-        Iterator<ModelKeyMap> keyMapsIter = modelRelation.getKeyMapsIterator();
         StringBuilder mainCols = new StringBuilder();
 
-        while (keyMapsIter.hasNext()) {
-            ModelKeyMap keyMap = keyMapsIter.next();
+        for (ModelKeyMap keyMap : modelRelation.getKeyMaps()) {
             ModelField mainField = entity.getField(keyMap.getFieldName());
 
             if (mainField == null) {

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/DynamicViewEntity.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/DynamicViewEntity.java?rev=1477929&r1=1477928&r2=1477929&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/DynamicViewEntity.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/DynamicViewEntity.java Wed May  1 08:16:56 2013
@@ -288,7 +288,7 @@ public class DynamicViewEntity {
     }
 
     public void addRelation(String type, String title, String relEntityName, List<ModelKeyMap> modelKeyMaps) {
-        ModelRelation relation = new ModelRelation(type, title, relEntityName, null, modelKeyMaps);
+        ModelRelation relation = ModelRelation.create(null, null, type, title, relEntityName, null, modelKeyMaps, false);
         this.relations.add(relation);
     }
 

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelChild.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelChild.java?rev=1477929&r1=1477928&r2=1477929&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelChild.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelChild.java Wed May  1 08:16:56 2013
@@ -21,36 +21,33 @@ package org.ofbiz.entity.model;
 import java.io.Serializable;
 
 /**
- * Generic Entity - Entity model class
+ * Abstract entity model class.
  *
  */
 @SuppressWarnings("serial")
 public abstract class ModelChild implements Serializable {
 
-    protected ModelEntity parentModelEntity;
+    private final ModelEntity modelEntity;
     /** The description for documentation purposes */
-    protected String description = "";
+    private final String description;
 
-    protected ModelChild() {}
-    protected ModelChild(ModelEntity parentModelEntity) {
-        setModelEntity(parentModelEntity);
+    // TODO: Eliminate the need for this.
+    protected ModelChild() {
+        this.modelEntity = null;
+        this.description = "";
     }
 
-    protected void setModelEntity(ModelEntity parentModelEntity) {
-        this.parentModelEntity = parentModelEntity;
+    protected ModelChild(ModelEntity modelEntity, String description) {
+        this.modelEntity = modelEntity;
+        this.description = description;
     }
 
     public ModelEntity getModelEntity() {
-        return parentModelEntity;
+        return this.modelEntity;
     }
 
     /** The description for documentation purposes */
     public String getDescription() {
         return this.description;
     }
-
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
 }

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntity.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntity.java?rev=1477929&r1=1477928&r2=1477929&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntity.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntity.java Wed May  1 08:16:56 2013
@@ -44,6 +44,7 @@ import org.ofbiz.base.util.UtilPlist;
 import org.ofbiz.base.util.UtilTimer;
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.base.util.UtilXml;
+import org.ofbiz.entity.model.ModelIndex.Field;
 import org.ofbiz.entity.Delegator;
 import org.ofbiz.entity.GenericEntity;
 import org.ofbiz.entity.GenericEntityException;
@@ -55,7 +56,7 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
 /**
- * Generic Entity - Entity model class
+ * An object that models the <code>&lt;entity&gt;</code> element.
  *
  */
 @SuppressWarnings("serial")
@@ -166,43 +167,37 @@ public class ModelEntity extends ModelIn
         }
         if (utilTimer != null) utilTimer.timerString("  createModelEntity: before fields");
         for (Element fieldElement: UtilXml.childElementList(entityElement, "field")) {
-            ModelField field = reader.createModelField(fieldElement);
-            if (field != null) {
-                internalAddField(field, pkFieldNames);
-            }
+            String fieldName = UtilXml.checkEmpty(fieldElement.getAttribute("name")).intern();
+            boolean isPk = pkFieldNames.contains(fieldName);
+            ModelField field = ModelField.create(this, fieldElement, isPk);
+            internalAddField(field, pkFieldNames);
         }
         // if applicable automatically add the STAMP_FIELD and STAMP_TX_FIELD fields
         if ((this.doLock || !this.noAutoStamp) && !fieldsMap.containsKey(STAMP_FIELD)) {
-            ModelField newField = reader.createModelField(STAMP_FIELD, "date-time", null, false);
-            newField.setIsAutoCreatedInternal(true);
+            ModelField newField = ModelField.create(this, "", STAMP_FIELD, "date-time", null, null, null, false, false, false, true, false, null);
             internalAddField(newField, pkFieldNames);
         }
         if (!this.noAutoStamp && !fieldsMap.containsKey(STAMP_TX_FIELD)) {
-            ModelField newField = reader.createModelField(STAMP_TX_FIELD, "date-time", null, false);
-            newField.setIsAutoCreatedInternal(true);
+            ModelField newField = ModelField.create(this, "", STAMP_TX_FIELD, "date-time", null, null, null, false, false, false, true, false, null);
             internalAddField(newField, pkFieldNames);
             // also add an index for this field
             String indexName = ModelUtil.shortenDbName(this.tableName + "_TXSTMP", 18);
-            ModelIndex txIndex = new ModelIndex(this, indexName, false);
-            txIndex.addIndexField(ModelEntity.STAMP_TX_FIELD);
-            txIndex.setModelEntity(this);
+            Field indexField = new Field(STAMP_TX_FIELD, null);
+            ModelIndex txIndex = ModelIndex.create(this, null, indexName, UtilMisc.toList(indexField), false);
             indexes.add(txIndex);
         }
         // if applicable automatically add the CREATE_STAMP_FIELD and CREATE_STAMP_TX_FIELD fields
         if ((this.doLock || !this.noAutoStamp) && !fieldsMap.containsKey(CREATE_STAMP_FIELD)) {
-            ModelField newField = reader.createModelField(CREATE_STAMP_FIELD, "date-time", null, false);
-            newField.setIsAutoCreatedInternal(true);
+            ModelField newField = ModelField.create(this, "", CREATE_STAMP_FIELD, "date-time", null, null, null, false, false, false, true, false, null);
             internalAddField(newField, pkFieldNames);
         }
         if (!this.noAutoStamp && !fieldsMap.containsKey(CREATE_STAMP_TX_FIELD)) {
-            ModelField newField = reader.createModelField(CREATE_STAMP_TX_FIELD, "date-time", null, false);
-            newField.setIsAutoCreatedInternal(true);
+            ModelField newField = ModelField.create(this, "", CREATE_STAMP_TX_FIELD, "date-time", null, null, null, false, false, false, true, false, null);
             internalAddField(newField, pkFieldNames);
             // also add an index for this field
             String indexName = ModelUtil.shortenDbName(this.tableName + "_TXCRTS", 18);
-            ModelIndex txIndex = new ModelIndex(this, indexName, false);
-            txIndex.addIndexField(ModelEntity.CREATE_STAMP_TX_FIELD);
-            txIndex.setModelEntity(this);
+            Field indexField = new Field(CREATE_STAMP_TX_FIELD, null);
+            ModelIndex txIndex = ModelIndex.create(this, null, indexName, UtilMisc.toList(indexField), false);
             indexes.add(txIndex);
         }
         // Must be done last to preserve pk field sequence
@@ -216,6 +211,7 @@ public class ModelEntity extends ModelIn
         }
         pks.trimToSize();
         nopks.trimToSize();
+        reader.incrementFieldCount(fieldsMap.size());
         if (utilTimer != null) utilTimer.timerString("  createModelEntity: before relations");
         this.populateRelated(reader, entityElement);
         this.populateIndexes(entityElement);
@@ -231,9 +227,9 @@ public class ModelEntity extends ModelIn
             this.tableName = this.tableName.substring(dotIndex + 1);
         }
         this.entityName = ModelUtil.dbNameToClassName(this.tableName);
-        for (Map.Entry<String, DatabaseUtil.ColumnCheckInfo> columnEntry: colMap.entrySet()) {
+        for (Map.Entry<String, DatabaseUtil.ColumnCheckInfo> columnEntry : colMap.entrySet()) {
             DatabaseUtil.ColumnCheckInfo ccInfo = columnEntry.getValue();
-            ModelField newField = new ModelField(ccInfo, modelFieldTypeReader);
+            ModelField newField = ModelField.create(this, ccInfo, modelFieldTypeReader);
             addField(newField);
         }
     }
@@ -260,13 +256,9 @@ public class ModelEntity extends ModelIn
     }
 
     private void internalAddField(ModelField newField, List<String> pkFieldNames) {
-        if (pkFieldNames.contains(newField.getName())) {
-            newField.setIsPk(true);
-            // Constructor will add to pk list
-        } else {
+        if (!newField.getIsPk()) {
             this.nopks.add(newField);
         }
-        newField.setModelEntity(this);
         this.fieldsMap.put(newField.getName(), newField);
     }
 
@@ -275,7 +267,6 @@ public class ModelEntity extends ModelIn
         for (Element relationElement: UtilXml.childElementList(entityElement, "relation")) {
             ModelRelation relation = reader.createRelation(this, relationElement);
             if (relation != null) {
-                relation.setModelEntity(this);
                 tempList.add(relation);
             }
         }
@@ -286,8 +277,7 @@ public class ModelEntity extends ModelIn
     protected void populateIndexes(Element entityElement) {
         List<ModelIndex> tempList = new ArrayList<ModelIndex>(this.indexes);
         for (Element indexElement: UtilXml.childElementList(entityElement, "index")) {
-            ModelIndex index = new ModelIndex(this, indexElement);
-            index.setModelEntity(this);
+            ModelIndex index = ModelIndex.create(this, indexElement);
             tempList.add(index);
         }
         this.indexes = new CopyOnWriteArrayList<ModelIndex>(tempList);
@@ -333,34 +323,37 @@ public class ModelEntity extends ModelIn
             }
         }
         
-        for (Element fieldElement: UtilXml.childElementList(extendEntityElement, "field")) {
-            ModelField field = reader.createModelField(fieldElement);
-            if (field != null) {
-                ModelField existingField = this.getField(field.getName());
-                if (existingField != null) {
-                    // override the existing field's attributes
-                    // TODO: only overrides of type, colName and description are currently supported
-                    if (UtilValidate.isNotEmpty(field.getType())) {
-                        existingField.setType(field.getType());
-                    }
-                    if (UtilValidate.isNotEmpty(field.getColName())) {
-                        existingField.setColName(field.getColName());
-                    }
-                    if (UtilValidate.isNotEmpty(field.getDescription())) {
-                        existingField.setDescription(field.getDescription());
-                    }
-                    if (UtilValidate.isNotEmpty(field.getEnableAuditLog())) {
-                        existingField.setEnableAuditLog(field.getEnableAuditLog());
-                    }
-                } else {
-                    // add to the entity as a new field
-                    field.setModelEntity(this);
-                    synchronized (fieldsLock) {
-                        this.fieldsMap.put(field.getName(), field);
-                        // this will always be true for now as extend-entity fields are always nonpks
-                        if (!field.isPk)
-                            this.nopks.add(field);
+        for (Element fieldElement : UtilXml.childElementList(extendEntityElement, "field")) {
+            ModelField newField = ModelField.create(this, fieldElement, false);
+            ModelField existingField = this.getField(newField.getName());
+            if (existingField != null) {
+                // override the existing field's attributes
+                // TODO: only overrides of type, colName and description are currently supported
+                String type = existingField.getType();
+                if (!newField.getType().isEmpty()) {
+                    type = newField.getType();
+                }
+                String colName = existingField.getColName();
+                if (!newField.getColName().isEmpty()) {
+                    colName = newField.getColName();
+                }
+                String description = existingField.getDescription();
+                if (!newField.getDescription().isEmpty()) {
+                    description = newField.getDescription();
+                }
+                newField = ModelField.create(this, description, existingField.getName(), type, colName, existingField.getColValue(), existingField.getFieldSet(),
+                        existingField.getIsNotNull(), existingField.getIsPk(), existingField.getEncrypt(), existingField.getIsAutoCreatedInternal(),
+                        existingField.getEnableAuditLog(), existingField.getValidators());
+            }
+            // add to the entity as a new field
+            synchronized (fieldsLock) {
+                this.fieldsMap.put(newField.getName(), newField);
+                if (!newField.getIsPk()) {
+                    // this will always be true for now as extend-entity fields are always nonpks
+                    if (existingField != null) {
+                        this.nopks.remove(existingField);
                     }
+                    this.nopks.add(newField);
                 }
             }
         }
@@ -618,10 +611,9 @@ public class ModelEntity extends ModelIn
     public void addField(ModelField field) {
         if (field == null)
             return;
-        field.setModelEntity(this);
         synchronized (fieldsLock) {
             fieldsMap.put(field.getName(), field);
-            if (field.isPk) {
+            if (field.getIsPk()) {
                 pks.add(field);
             } else {
                 nopks.add(field);
@@ -635,7 +627,7 @@ public class ModelEntity extends ModelIn
         synchronized (fieldsLock) {
             ModelField field = fieldsMap.remove(fieldName);
             if (field != null) {
-                if (field.isPk) {
+                if (field.getIsPk()) {
                     pks.remove(field);
                 } else {
                     nopks.remove(field);
@@ -664,7 +656,7 @@ public class ModelEntity extends ModelIn
     private List<String> getFieldNamesFromFieldVector(List<ModelField> modelFields) {
         List<String> nameList = new ArrayList<String>(modelFields.size());
         for (ModelField field: modelFields) {
-            nameList.add(field.name);
+            nameList.add(field.getName());
         }
         return nameList;
     }
@@ -734,13 +726,12 @@ public class ModelEntity extends ModelIn
     public ModelRelation getRelation(String relationName) {
         if (relationName == null) return null;
         for (ModelRelation relation: relations) {
-            if (relationName.equals(relation.title + relation.relEntityName)) return relation;
+            if (relationName.equals(relation.getTitle() + relation.getRelEntityName())) return relation;
         }
         return null;
     }
 
     public void addRelation(ModelRelation relation) {
-        relation.setModelEntity(this);
         this.relations.add(relation);
     }
 
@@ -769,7 +760,6 @@ public class ModelEntity extends ModelIn
     }
 
     public void addIndex(ModelIndex index) {
-        index.setModelEntity(this);
         this.indexes.add(index);
     }
 
@@ -825,10 +815,10 @@ public class ModelEntity extends ModelIn
         int i = 0;
 
         for (; i < flds.size() - 1; i++) {
-            returnString.append(flds.get(i).name);
+            returnString.append(flds.get(i).getName());
             returnString.append(separator);
         }
-        returnString.append(flds.get(i).name);
+        returnString.append(flds.get(i).getName());
         returnString.append(afterLast);
         return returnString.toString();
     }
@@ -848,15 +838,15 @@ public class ModelEntity extends ModelIn
 
         for (; i < flds.size() - 1; i++) {
             ModelField curField = flds.get(i);
-            returnString.append(curField.type);
+            returnString.append(curField.getType());
             returnString.append(" ");
-            returnString.append(curField.name);
+            returnString.append(curField.getName());
             returnString.append(", ");
         }
         ModelField curField = flds.get(i);
-        returnString.append(curField.type);
+        returnString.append(curField.getType());
         returnString.append(" ");
-        returnString.append(curField.name);
+        returnString.append(curField.getName());
         return returnString.toString();
     }
 
@@ -946,7 +936,7 @@ public class ModelEntity extends ModelIn
         int i = 0;
 
         for (; i < flds.size(); i++) {
-            if (onlyNonPK && flds.get(i).isPk) continue;
+            if (onlyNonPK && flds.get(i).getIsPk()) continue;
             sb.append(eachString);
             if (appendIndex) sb.append(i + 1);
             if (i < flds.size() - 1) sb.append(separator);
@@ -995,7 +985,7 @@ public class ModelEntity extends ModelIn
         Iterator<ModelField> fldsIt = flds.iterator();
         while (fldsIt.hasNext()) {
             ModelField field = fldsIt.next();
-            sb.append(field.colName);
+            sb.append(field.getColName());
             if (fldsIt.hasNext()) {
                 sb.append(separator);
             }
@@ -1027,10 +1017,10 @@ public class ModelEntity extends ModelIn
         int i = 0;
 
         for (; i < flds.size() - 1; i++) {
-            returnString.append(ModelUtil.upperFirstChar(flds.get(i).name));
+            returnString.append(ModelUtil.upperFirstChar(flds.get(i).getName()));
             returnString.append(separator);
         }
-        returnString.append(ModelUtil.upperFirstChar(flds.get(i).name));
+        returnString.append(ModelUtil.upperFirstChar(flds.get(i).getName()));
         returnString.append(afterLast);
         return returnString.toString();
     }
@@ -1048,12 +1038,12 @@ public class ModelEntity extends ModelIn
         int i = 0;
 
         for (; i < flds.size() - 1; i++) {
-            returnString.append(flds.get(i).colName);
+            returnString.append(flds.get(i).getColName());
             returnString.append(" like {");
             returnString.append(i);
             returnString.append("} AND ");
         }
-        returnString.append(flds.get(i).colName);
+        returnString.append(flds.get(i).getColName());
         returnString.append(" like {");
         returnString.append(i);
         returnString.append("}");
@@ -1076,17 +1066,17 @@ public class ModelEntity extends ModelIn
             returnString.append("\"");
             returnString.append(tableName);
             returnString.append("_");
-            returnString.append(flds.get(i).colName);
+            returnString.append(flds.get(i).getColName());
             returnString.append("=\" + ");
-            returnString.append(flds.get(i).name);
+            returnString.append(flds.get(i).getName());
             returnString.append(" + \"&\" + ");
         }
         returnString.append("\"");
         returnString.append(tableName);
         returnString.append("_");
-        returnString.append(flds.get(i).colName);
+        returnString.append(flds.get(i).getColName());
         returnString.append("=\" + ");
-        returnString.append(flds.get(i).name);
+        returnString.append(flds.get(i).getName());
         return returnString.toString();
     }
 
@@ -1107,21 +1097,21 @@ public class ModelEntity extends ModelIn
             returnString.append("\"");
             returnString.append(tableName);
             returnString.append("_");
-            returnString.append(flds.get(i).colName);
+            returnString.append(flds.get(i).getColName());
             returnString.append("=\" + ");
             returnString.append(ModelUtil.lowerFirstChar(entityName));
             returnString.append(".get");
-            returnString.append(ModelUtil.upperFirstChar(flds.get(i).name));
+            returnString.append(ModelUtil.upperFirstChar(flds.get(i).getName()));
             returnString.append("() + \"&\" + ");
         }
         returnString.append("\"");
         returnString.append(tableName);
         returnString.append("_");
-        returnString.append(flds.get(i).colName);
+        returnString.append(flds.get(i).getColName());
         returnString.append("=\" + ");
         returnString.append(ModelUtil.lowerFirstChar(entityName));
         returnString.append(".get");
-        returnString.append(ModelUtil.upperFirstChar(flds.get(i).name));
+        returnString.append(ModelUtil.upperFirstChar(flds.get(i).getName()));
         returnString.append("()");
         return returnString.toString();
     }
@@ -1143,23 +1133,23 @@ public class ModelEntity extends ModelIn
             returnString.append("\"");
             returnString.append(tableName);
             returnString.append("_");
-            returnString.append(flds.get(i).colName);
+            returnString.append(flds.get(i).getColName());
             returnString.append("=\" + ");
             returnString.append(ModelUtil.lowerFirstChar(entityName));
             returnString.append(entityNameSuffix);
             returnString.append(".get");
-            returnString.append(ModelUtil.upperFirstChar(flds.get(i).name));
+            returnString.append(ModelUtil.upperFirstChar(flds.get(i).getName()));
             returnString.append("() + \"&\" + ");
         }
         returnString.append("\"");
         returnString.append(tableName);
         returnString.append("_");
-        returnString.append(flds.get(i).colName);
+        returnString.append(flds.get(i).getColName());
         returnString.append("=\" + ");
         returnString.append(ModelUtil.lowerFirstChar(entityName));
         returnString.append(entityNameSuffix);
         returnString.append(".get");
-        returnString.append(ModelUtil.upperFirstChar(flds.get(i).name));
+        returnString.append(ModelUtil.upperFirstChar(flds.get(i).getName()));
         returnString.append("()");
         return returnString.toString();
     }
@@ -1178,36 +1168,36 @@ public class ModelEntity extends ModelIn
         int i = 0;
 
         for (; i < flds.size() - 1; i++) {
-            ModelKeyMap keyMap = relation.findKeyMapByRelated(flds.get(i).name);
+            ModelKeyMap keyMap = relation.findKeyMapByRelated(flds.get(i).getName());
 
             if (keyMap != null) {
                 returnString.append("\"");
                 returnString.append(tableName);
                 returnString.append("_");
-                returnString.append(flds.get(i).colName);
+                returnString.append(flds.get(i).getColName());
                 returnString.append("=\" + ");
-                returnString.append(ModelUtil.lowerFirstChar(relation.mainEntity.entityName));
+                returnString.append(ModelUtil.lowerFirstChar(relation.getModelEntity().entityName));
                 returnString.append(".get");
-                returnString.append(ModelUtil.upperFirstChar(keyMap.fieldName));
+                returnString.append(ModelUtil.upperFirstChar(keyMap.getFieldName()));
                 returnString.append("() + \"&\" + ");
             } else {
-                Debug.logWarning("-- -- ENTITYGEN ERROR:httpRelationArgList: Related Key in Key Map not found for name: " + flds.get(i).name + " related entity: " + relation.relEntityName + " main entity: " + relation.mainEntity.entityName + " type: " + relation.type, module);
+                Debug.logWarning("-- -- ENTITYGEN ERROR:httpRelationArgList: Related Key in Key Map not found for name: " + flds.get(i).getName() + " related entity: " + relation.getRelEntityName() + " main entity: " + relation.getModelEntity().entityName + " type: " + relation.getType(), module);
             }
         }
-        ModelKeyMap keyMap = relation.findKeyMapByRelated(flds.get(i).name);
+        ModelKeyMap keyMap = relation.findKeyMapByRelated(flds.get(i).getName());
 
         if (keyMap != null) {
             returnString.append("\"");
             returnString.append(tableName);
             returnString.append("_");
-            returnString.append(flds.get(i).colName);
+            returnString.append(flds.get(i).getColName());
             returnString.append("=\" + ");
-            returnString.append(ModelUtil.lowerFirstChar(relation.mainEntity.entityName));
+            returnString.append(ModelUtil.lowerFirstChar(relation.getModelEntity().entityName));
             returnString.append(".get");
-            returnString.append(ModelUtil.upperFirstChar(keyMap.fieldName));
+            returnString.append(ModelUtil.upperFirstChar(keyMap.getFieldName()));
             returnString.append("()");
         } else {
-            Debug.logWarning("-- -- ENTITYGEN ERROR:httpRelationArgList: Related Key in Key Map not found for name: " + flds.get(i).name + " related entity: " + relation.relEntityName + " main entity: " + relation.mainEntity.entityName + " type: " + relation.type, module);
+            Debug.logWarning("-- -- ENTITYGEN ERROR:httpRelationArgList: Related Key in Key Map not found for name: " + flds.get(i).getName() + " related entity: " + relation.getRelEntityName() + " main entity: " + relation.getModelEntity().entityName + " type: " + relation.getType(), module);
         }
         return returnString.toString();
     }
@@ -1241,18 +1231,18 @@ public class ModelEntity extends ModelIn
 
         int i = 0;
 
-        if (relation.findKeyMapByRelated(flds.get(i).name) == null) {
-            returnString.append(flds.get(i).type);
+        if (relation.findKeyMapByRelated(flds.get(i).getName()) == null) {
+            returnString.append(flds.get(i).getType());
             returnString.append(" ");
-            returnString.append(flds.get(i).name);
+            returnString.append(flds.get(i).getName());
         }
         i++;
         for (; i < flds.size(); i++) {
-            if (relation.findKeyMapByRelated(flds.get(i).name) == null) {
+            if (relation.findKeyMapByRelated(flds.get(i).getName()) == null) {
                 if (returnString.length() > 0) returnString.append(", ");
-                returnString.append(flds.get(i).type);
+                returnString.append(flds.get(i).getType());
                 returnString.append(" ");
-                returnString.append(flds.get(i).name);
+                returnString.append(flds.get(i).getName());
             }
         }
         return returnString.toString();
@@ -1272,20 +1262,20 @@ public class ModelEntity extends ModelIn
         int i = 0;
 
         for (; i < flds.size() - 1; i++) {
-            ModelKeyMap keyMap = relation.findKeyMapByRelated(flds.get(i).name);
+            ModelKeyMap keyMap = relation.findKeyMapByRelated(flds.get(i).getName());
 
             if (keyMap != null) {
-                returnString.append(keyMap.fieldName);
+                returnString.append(keyMap.getFieldName());
                 returnString.append(", ");
             } else {
-                returnString.append(flds.get(i).name);
+                returnString.append(flds.get(i).getName());
                 returnString.append(", ");
             }
         }
-        ModelKeyMap keyMap = relation.findKeyMapByRelated(flds.get(i).name);
+        ModelKeyMap keyMap = relation.findKeyMapByRelated(flds.get(i).getName());
 
-        if (keyMap != null) returnString.append(keyMap.fieldName);
-        else returnString.append(flds.get(i).name);
+        if (keyMap != null) returnString.append(keyMap.getFieldName());
+        else returnString.append(flds.get(i).getName());
         return returnString.toString();
     }
 
@@ -1630,7 +1620,7 @@ public class ModelEntity extends ModelIn
                 if (useRelationshipNames || relationship.isAutoRelation()) {
                     relationshipMap.put("name", relationship.getCombinedName());
                 } else {
-                    relationshipMap.put("name", relationship.getKeyMapsIterator().next().getFieldName());
+                    relationshipMap.put("name", relationship.getKeyMaps().iterator().next().getFieldName());
                 }
                 relationshipMap.put("destination", relationship.getRelEntityName());
                 if ("many".equals(relationship.getType())) {
@@ -1645,7 +1635,7 @@ public class ModelEntity extends ModelIn
 
                 List<Map<String, Object>> joinsMapList = new LinkedList<Map<String, Object>>();
                 relationshipMap.put("joins", joinsMapList);
-                for (ModelKeyMap keyMap: relationship.getKeyMapsClone()) {
+                for (ModelKeyMap keyMap: relationship.getKeyMaps()) {
                     Map<String, Object> joinsMap = new HashMap<String, Object>();
                     joinsMapList.add(joinsMap);
 

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntityChecker.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntityChecker.java?rev=1477929&r1=1477928&r2=1477929&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntityChecker.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntityChecker.java Wed May  1 08:16:56 2013
@@ -215,10 +215,10 @@ public class ModelEntityChecker {
                             //if relation is of type one, make sure keyMaps
                             // match the PK of the relatedEntity
                             if ("one".equals(relation.getType()) || "one-nofk".equals(relation.getType())) {
-                                if (relatedEntity.getPksSize() != relation.getKeyMapsSize())
+                                if (relatedEntity.getPksSize() != relation.getKeyMaps().size())
                                         warningList.add("[RelatedOneKeyMapsWrongSize] The number of primary keys (" + relatedEntity.getPksSize()
                                                         + ") of related entity " + relation.getRelEntityName()
-                                                        + " does not match the number of keymaps (" + relation.getKeyMapsSize()
+                                                        + " does not match the number of keymaps (" + relation.getKeyMaps().size()
                                                         + ") for relation of type one \"" + relation.getTitle() + relation.getRelEntityName()
                                                         + "\" of entity " + entity.getEntityName() + ".");
                                 Iterator<ModelField> pksIter = relatedEntity.getPksIterator();
@@ -238,8 +238,7 @@ public class ModelEntityChecker {
                         // this entity
                         //make sure all keyMap 'relFieldName's match fields of
                         // the relatedEntity
-                        for (int rkm = 0; rkm < relation.getKeyMapsSize(); rkm++) {
-                            ModelKeyMap keyMap = relation.getKeyMap(rkm);
+                        for (ModelKeyMap keyMap : relation.getKeyMaps()) {
 
                             ModelField field = entity.getField(keyMap.getFieldName());
                             ModelField rfield = null;

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelField.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelField.java?rev=1477929&r1=1477928&r2=1477929&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelField.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelField.java Wed May  1 08:16:56 2013
@@ -19,214 +19,242 @@
 package org.ofbiz.entity.model;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
+import org.ofbiz.base.lang.ThreadSafe;
+import org.ofbiz.base.util.UtilXml;
+import org.ofbiz.entity.jdbc.DatabaseUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
-import org.ofbiz.entity.jdbc.DatabaseUtil;
-import org.ofbiz.base.util.UtilValidate;
-import org.ofbiz.base.util.UtilXml;
 
 /**
- * Generic Entity - Field model class
+ * An object that models the <code>&lt;field&gt;</code> element.
  *
  */
+@ThreadSafe
 @SuppressWarnings("serial")
-public class ModelField extends ModelChild {
+public final class ModelField extends ModelChild {
+
+    /**
+     * Returns a new <code>ModelField</code> instance, initialized with the specified values.
+     * 
+     * @param modelEntity The <code>ModelEntity</code> this field is a member of.
+     * @param name The field name.
+     * @param type The field type.
+     * @param isPk <code>true</code> if this field is part of the primary key.
+     */
+    public static ModelField create(ModelEntity modelEntity, String name, String type, boolean isPk) {
+        return create(modelEntity, null, name, type, null, null, null, false, isPk, false, false, false, null);
+    }
+
+    /**
+     * Returns a new <code>ModelField</code> instance, initialized with the specified values.
+     * 
+     * @param modelEntity The <code>ModelEntity</code> this field is a member of.
+     * @param description The field description.
+     * @param name The field name.
+     * @param type The field type.
+     * @param colName The data source column name for this field. Will be generated automatically if left empty.
+     * @param colValue
+     * @param fieldSet The field set name this field is a member of.
+     * @param isNotNull <code>true</code> if this field cannot contain a null value.
+     * @param isPk <code>true</code> if this field is part of the primary key.
+     * @param encrypt <code>true</code> if this field is encrypted.
+     * @param isAutoCreatedInternal <code>true</code> if this field was generated automatically by the entity engine.
+     * @param enableAuditLog <code>true</code> if this field is included in the entity audit log.
+     * @param validators The validators for this field.
+     */
+    @SuppressWarnings("unchecked")
+    public static ModelField create(ModelEntity modelEntity, String description, String name, String type, String colName, String colValue, String fieldSet, boolean isNotNull, boolean isPk, boolean encrypt, boolean isAutoCreatedInternal, boolean enableAuditLog, List<String> validators) {
+        // TODO: Validate parameters.
+        if (description == null) {
+            description = "";
+        }
+        if (name == null) {
+            name = "";
+        }
+        if (type == null) {
+            type = "";
+        }
+        if (colName == null || colName.isEmpty()) {
+            colName = ModelUtil.javaNameToDbName(name);
+        }
+        if (colValue == null) {
+            colValue = "";
+        }
+        if (fieldSet == null) {
+            fieldSet = "";
+        }
+        if (validators == null) {
+            validators = Collections.EMPTY_LIST;
+        } else {
+            validators = Collections.unmodifiableList(validators);
+        }
+        if (isPk) {
+            isNotNull = true;
+        }
+        return new ModelField(modelEntity, description, name, type, colName, colValue, fieldSet, isNotNull, isPk, encrypt, isAutoCreatedInternal, enableAuditLog, validators);
+    }
+
+    /**
+     * Returns a new <code>ModelField</code> instance, initialized with the specified values.
+     * 
+     * @param modelEntity The <code>ModelEntity</code> this field is a member of.
+     * @param fieldElement The <code>&lt;field&gt;</code> element containing the values for this field.
+     * @param isPk <code>true</code> if this field is part of the primary key.
+     */
+    @SuppressWarnings("unchecked")
+    public static ModelField create(ModelEntity modelEntity, Element fieldElement, boolean isPk) {
+        String description = UtilXml.childElementValue(fieldElement, "description");
+        if (description == null) {
+            description = "";
+        }
+        String name = fieldElement.getAttribute("name").intern();
+        String type = fieldElement.getAttribute("type").intern();
+        String colName = fieldElement.getAttribute("col-name").intern();
+        if (colName.isEmpty()) {
+            colName = ModelUtil.javaNameToDbName(name);
+        }
+        String colValue = "";
+        String fieldSet = fieldElement.getAttribute("field-set").intern();
+        boolean isNotNull = "true".equals(fieldElement.getAttribute("not-null"));
+        if (isPk) {
+            isNotNull = true;
+        }
+        boolean encrypt = "true".equals(fieldElement.getAttribute("encrypt"));
+        boolean enableAuditLog = "true".equals(fieldElement.getAttribute("enable-audit-log"));
+        List<String>validators = Collections.EMPTY_LIST;
+        List<? extends Element> elementList = UtilXml.childElementList(fieldElement, "validate");
+        if (!elementList.isEmpty()) {
+            validators = new ArrayList<String>(elementList.size());
+            for (Element validateElement : elementList) {
+                validators.add(validateElement.getAttribute("name").intern());
+            }
+            validators = Collections.unmodifiableList(validators);
+        }
+        return new ModelField(modelEntity, description, name, type, colName, colValue, fieldSet, isNotNull, isPk, encrypt, false, enableAuditLog, validators);
+    }
+
+    /**
+     * Returns a new <code>ModelField</code> instance, initialized with the specified values.
+     * 
+     * @param modelEntity The <code>ModelEntity</code> this field is a member of.
+     * @param ccInfo The <code>ColumnCheckInfo</code> containing the values for this field.
+     * @param modelFieldTypeReader
+     */
+    @SuppressWarnings("unchecked")
+    public static ModelField create(ModelEntity modelEntity, DatabaseUtil.ColumnCheckInfo ccInfo, ModelFieldTypeReader modelFieldTypeReader) {
+        String colName = ccInfo.columnName;
+        String name = ModelUtil.dbNameToVarName(colName);
+        String type = ModelUtil.induceFieldType(ccInfo.typeName, ccInfo.columnSize, ccInfo.decimalDigits, modelFieldTypeReader);
+        boolean isPk = ccInfo.isPk;
+        boolean isNotNull = "NO".equals(ccInfo.isNullable.toUpperCase());
+        String description = "";
+        String colValue = "";
+        String fieldSet = "";
+        boolean encrypt = false;
+        boolean enableAuditLog = false;
+        return new ModelField(modelEntity, description, name, type, colName, colValue, fieldSet, isNotNull, isPk, encrypt, false, enableAuditLog, Collections.EMPTY_LIST);
+    }
+
+    /*
+     * Developers - this is an immutable class. Once constructed, the object should not change state.
+     * Therefore, 'setter' methods are not allowed. If client code needs to modify the object's
+     * state, then it can create a new copy with the changed values.
+     */
 
     /** The name of the Field */
-    protected String name = "";
+    private final String name;
 
     /** The type of the Field */
-    protected String type = "";
+    private final String type;
 
     /** The col-name of the Field */
-    protected String colName = "";
+    private final String colName;
 
-    protected String colValue;
+    private final String colValue;
 
     /** boolean which specifies whether or not the Field is a Primary Key */
-    protected boolean isPk = false;
-    protected boolean encrypt = false;
-    protected boolean isNotNull = false;
-    protected boolean isAutoCreatedInternal = false;
-    protected boolean enableAuditLog = false;
+    private final boolean isPk;
+    private final boolean encrypt;
+    private final boolean isNotNull;
+    private final boolean isAutoCreatedInternal;
+    private final boolean enableAuditLog;
 
     /** when any field in the same set is selected in a query, all fields in that set will be selected */
-    protected String fieldSet = "";
+    private final String fieldSet;
 
     /** validators to be called when an update is done */
-    protected List<String> validators = new ArrayList<String>();
-
-    /** Default Constructor */
-    public ModelField() {}
+    private final List<String> validators;
 
-    /** Fields Constructor */
-    public ModelField(String name, String type, String colName, boolean isPk) {
-        this(name, type, colName, isPk, false, false);
-    }
-
-    public ModelField(String name, String type, String colName, boolean isPk, boolean encrypt, boolean enableAuditLog) {
+    private ModelField(ModelEntity modelEntity, String description, String name, String type, String colName, String colValue, String fieldSet, boolean isNotNull, boolean isPk, boolean encrypt, boolean isAutoCreatedInternal, boolean enableAuditLog, List<String> validators) {
+        super(modelEntity, description);
         this.name = name;
         this.type = type;
-        this.setColName(colName);
+        this.colName = colName;
+        this.colValue = colValue;
+        this.fieldSet = fieldSet;
         this.isPk = isPk;
+        this.isNotNull = isNotNull;
         this.encrypt = encrypt;
         this.enableAuditLog = enableAuditLog;
+        this.isAutoCreatedInternal = isAutoCreatedInternal;
+        this.validators = validators;
     }
 
-    /** XML Constructor */
-    public ModelField(Element fieldElement) {
-        this.type = UtilXml.checkEmpty(fieldElement.getAttribute("type")).intern();
-        this.name = UtilXml.checkEmpty(fieldElement.getAttribute("name")).intern();
-        this.setColName(UtilXml.checkEmpty(fieldElement.getAttribute("col-name")).intern());
-        this.isPk = false; // is set elsewhere
-        this.encrypt = UtilXml.checkBoolean(fieldElement.getAttribute("encrypt"), false);
-        this.description = UtilXml.childElementValue(fieldElement, "description");
-        this.enableAuditLog = UtilXml.checkBoolean(fieldElement.getAttribute("enable-audit-log"), false);
-        this.isNotNull = UtilXml.checkBoolean(fieldElement.getAttribute("not-null"), false);
-        this.fieldSet = UtilXml.checkEmpty(fieldElement.getAttribute("field-set")).intern();
-
-        NodeList validateList = fieldElement.getElementsByTagName("validate");
-
-        for (int i = 0; i < validateList.getLength(); i++) {
-            Element element = (Element) validateList.item(i);
-
-            this.validators.add(UtilXml.checkEmpty(element.getAttribute("name")).intern());
-        }
-    }
-
-    /** DB Names Constructor */
-    public ModelField(DatabaseUtil.ColumnCheckInfo ccInfo, ModelFieldTypeReader modelFieldTypeReader) {
-        this.colName = ccInfo.columnName;
-        this.name = ModelUtil.dbNameToVarName(this.colName);
-
-        // figure out the type according to the typeName, columnSize and decimalDigits
-        this.type = ModelUtil.induceFieldType(ccInfo.typeName, ccInfo.columnSize, ccInfo.decimalDigits, modelFieldTypeReader);
-
-        this.isPk = ccInfo.isPk;
-    }
-
-    /** The name of the Field */
+    /** Returns the name of this field. */
     public String getName() {
         return this.name;
     }
 
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /** The type of the Field */
+    /** Returns the type of this field. */
     public String getType() {
         return this.type;
     }
 
-    public void setType(String type) {
-        this.type = type;
-    }
-
-    /** The col-name of the Field */
+    /** Returns the data source column name of this field. */
     public String getColName() {
         return this.colName;
     }
 
-    public void setColName(String colName) {
-        this.colName = colName;
-        if (UtilValidate.isEmpty(this.colName)) {
-            this.colName = ModelUtil.javaNameToDbName(UtilXml.checkEmpty(this.name));
-        }
-    }
-
     public String getColValue() {
-        return UtilValidate.isEmpty(this.colValue) ? this.colName : this.colValue;
+        return this.colValue.isEmpty() ? this.colName : this.colValue;
     }
 
-    public void setColValue(String colValue) {
-        this.colValue = colValue;
-    }
-
-    /** boolean which specifies whether or not the Field is a Primary Key */
+    /** Returns <code>true</code> if this field is part of the primary key. */
     public boolean getIsPk() {
         return this.isPk;
     }
 
-    public void setIsPk(boolean isPk) {
-        this.isPk = isPk;
-        if (isPk) {
-            setIsNotNull(true);
-        }
-    }
-
+    /** Returns <code>true</code> if this field cannot contain null. */
     public boolean getIsNotNull() {
         return this.isNotNull;
     }
 
-    public void setIsNotNull(boolean isNotNull) {
-        this.isNotNull = isNotNull;
-    }
-
+    /** Returns <code>true</code> if this field is encrypted. */
     public boolean getEncrypt() {
         return this.encrypt;
     }
 
-    public void setEncrypt(boolean encrypt) {
-        this.encrypt = encrypt;
-    }
-
+    /** Returns <code>true</code> if this field is included in the entity audit log. */
     public boolean getEnableAuditLog() {
         return this.enableAuditLog;
     }
-    
-    public void setEnableAuditLog(boolean enableAuditLog) {
-        this.enableAuditLog = enableAuditLog;
-    }
 
+    /** Returns <code>true</code> if this field was generated automatically by the entity engine. */
     public boolean getIsAutoCreatedInternal() {
         return this.isAutoCreatedInternal;
     }
 
-    public void setIsAutoCreatedInternal(boolean isAutoCreatedInternal) {
-        this.isAutoCreatedInternal = isAutoCreatedInternal;
-    }
-
+    /** Returns the field set name this field is a member of. */
     public String getFieldSet() {
         return fieldSet;
     }
 
-    public void setFieldSet(String fieldSet) {
-        this.fieldSet = fieldSet;
-    }
-
-    /** validators to be called when an update is done */
-    public String getValidator(int index) {
-        return this.validators.get(index);
-    }
-
-    public int getValidatorsSize() {
-        return this.validators.size();
-    }
-
-    public void addValidator(String validator) {
-        this.validators.add(validator);
-    }
-
-    public String removeValidator(int index) {
-        return this.validators.remove(index);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj.getClass() != getClass()) return false;
-        ModelField other = (ModelField) obj;
-        return other.getName().equals(getName()) && other.getModelEntity() == getModelEntity();
-    }
-
-    @Override
-    public int hashCode() {
-        return getModelEntity().hashCode() ^ getName().hashCode();
+    public List<String> getValidators() {
+        return this.validators;
     }
 
     @Override
@@ -234,6 +262,7 @@ public class ModelField extends ModelChi
         return getModelEntity() + "@" + getName();
     }
 
+    // TODO: Externalize this.
     public Element toXmlElement(Document document) {
         Element root = document.createElement("field");
         root.setAttribute("name", this.getName());

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelIndex.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelIndex.java?rev=1477929&r1=1477928&r2=1477929&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelIndex.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelIndex.java Wed May  1 08:16:56 2013
@@ -19,128 +19,111 @@
 package org.ofbiz.entity.model;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
-import java.util.Iterator;
 
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
-import org.ofbiz.base.util.StringUtil;
+import org.ofbiz.base.lang.ThreadSafe;
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.base.util.UtilXml;
-import org.ofbiz.base.util.collections.IteratorWrapper;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 /**
- * Generic Entity - Relation model class
+ * An object that models the <code>&lt;index&gt;</code> element.
  *
  */
+@ThreadSafe
 @SuppressWarnings("serial")
-public class ModelIndex extends ModelChild {
+public final class ModelIndex extends ModelChild {
+
+    /**
+     * Returns a new <code>ModelIndex</code> instance, initialized with the specified values.
+     * 
+     * @param modelEntity The <code>ModelEntity</code> this index is a member of.
+     * @param description The index description.
+     * @param name The index name.
+     * @param fields The fields that are included in this index.
+     * @param unique <code>true</code> if this index returns unique values.
+     */
+    @SuppressWarnings("unchecked")
+    public static ModelIndex create(ModelEntity modelEntity, String description, String name, List<Field> fields, boolean unique) {
+        if (description == null) {
+            description = "";
+        }
+        if (name == null) {
+            name = "";
+        }
+        if (fields == null) {
+            fields = Collections.EMPTY_LIST;
+        } else {
+            fields = Collections.unmodifiableList(fields);
+        }
+        return new ModelIndex(modelEntity, description, name, fields, unique);
+    }
+
+    /**
+     * Returns a new <code>ModelIndex</code> instance, initialized with the specified values.
+     * 
+     * @param modelEntity The <code>ModelEntity</code> this index is a member of.
+     * @param indexElement The <code>&lt;index&gt;</code> element containing the values for this index.
+     */
+    @SuppressWarnings("unchecked")
+    public static ModelIndex create(ModelEntity modelEntity, Element indexElement) {
+        String name = indexElement.getAttribute("name").intern();
+        boolean unique = "true".equals(indexElement.getAttribute("unique"));
+        String description = UtilXml.childElementValue(indexElement, "description");
+        List<Field>fields = Collections.EMPTY_LIST;
+        List<? extends Element> elementList = UtilXml.childElementList(indexElement, "index-field");
+        if (!elementList.isEmpty()) {
+            fields = new ArrayList<Field>(elementList.size());
+            for (Element indexFieldElement : elementList) {
+                String fieldName = indexFieldElement.getAttribute("name").intern();
+                String function = indexFieldElement.getAttribute("function").intern();
+                fields.add(new Field(fieldName, UtilValidate.isNotEmpty(function) ? Function.valueOf(function.toUpperCase()) : null));
+            }
+            fields = Collections.unmodifiableList(fields);
+        }
+        return new ModelIndex(modelEntity, description, name, fields, unique);
+    }
+
+    /*
+     * Developers - this is an immutable class. Once constructed, the object should not change state.
+     * Therefore, 'setter' methods are not allowed. If client code needs to modify the object's
+     * state, then it can create a new copy with the changed values.
+     */
 
     /** the index name, used for the database index name */
-    protected String name;
+    private final String name;
 
     /** specifies whether or not this index should include the unique constraint */
-    protected boolean unique;
+    private final boolean unique;
 
     /** list of the field names included in this index */
-    protected List<Field> fields = new ArrayList<Field>();
+    private final List<Field> fields;
 
-    /** Default Constructor */
-    public ModelIndex() {
-        name = "";
-        unique = false;
-    }
-
-    /** Direct Create Constructor */
-    public ModelIndex(ModelEntity mainEntity, String name, boolean unique) {
-        super(mainEntity);
+    private ModelIndex(ModelEntity mainEntity, String description, String name, List<Field> fields, boolean unique) {
+        super(mainEntity, description);
         this.name = name;
+        this.fields = fields;
         this.unique = unique;
     }
 
-    /** XML Constructor */
-    public ModelIndex(ModelEntity mainEntity, Element indexElement) {
-        super(mainEntity);
-
-        this.name = UtilXml.checkEmpty(indexElement.getAttribute("name")).intern();
-        this.unique = "true".equals(UtilXml.checkEmpty(indexElement.getAttribute("unique")));
-        this.description = StringUtil.internString(UtilXml.childElementValue(indexElement, "description"));
-
-        NodeList indexFieldList = indexElement.getElementsByTagName("index-field");
-        for (int i = 0; i < indexFieldList.getLength(); i++) {
-            Element indexFieldElement = (Element) indexFieldList.item(i);
-
-            if (indexFieldElement.getParentNode() == indexElement) {
-                String fieldName = indexFieldElement.getAttribute("name").intern();
-                String function = indexFieldElement.getAttribute("function");
-                this.fields.add(new Field(fieldName, UtilValidate.isNotEmpty(function) ? Function.valueOf(function.toUpperCase()) : null));
-            }
-        }
-    }
-
-    /** the index name, used for the database index name */
+    /** Returns the index name. */
     public String getName() {
         return this.name;
     }
 
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /** specifies whether or not this index should include the unique constraint */
+    /** Returns <code>true</code> if this index returns unique values. */
     public boolean getUnique() {
         return this.unique;
     }
 
-    public void setUnique(boolean unique) {
-        this.unique = unique;
-    }
-
-    /** @deprecated use getFieldsIterator() */
-    @Deprecated
-    public Iterator<String> getIndexFieldsIterator() {
-        return new IteratorWrapper<String, Field>(this.fields.iterator()) {
-            @Override
-            protected void noteRemoval(String dest, Field src) {
-            }
-
-            @Override
-            protected String convert(Field src) {
-                return src.getFieldName();
-            }
-        };
-    }
-
-    public Iterator<Field> getFieldsIterator() {
-        return this.fields.iterator();
-    }
-
-    public int getIndexFieldsSize() {
-        return this.fields.size();
-    }
-
-    public String getIndexField(int index) {
-        return this.fields.get(index).getFieldName();
-    }
-
-    public void addIndexField(String fieldName) {
-        this.fields.add(new Field(fieldName, null));
-    }
-
-    public void addIndexField(String fieldName, String functionName) {
-        this.fields.add(new Field(fieldName, Function.valueOf(functionName)));
-    }
-
-    public void addIndexField(String fieldName, Function function) {
-        this.fields.add(new Field(fieldName, function));
-    }
-
-    public String removeIndexField(int index) {
-        return this.fields.remove(index).getFieldName();
+    /** Returns the fields included in this index. */
+    public List<Field> getFields() {
+        return this.fields;
     }
 
+    // TODO: Externalize this.
     public Element toXmlElement(Document document) {
         Element root = document.createElement("index");
         root.setAttribute("name", this.getName());

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelKeyMap.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelKeyMap.java?rev=1477929&r1=1477928&r2=1477929&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelKeyMap.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelKeyMap.java Wed May  1 08:16:56 2013
@@ -23,25 +23,30 @@ import java.util.List;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
+import org.ofbiz.base.lang.ThreadSafe;
 import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.UtilXml;
 
 
 /**
- * Generic Entity - KeyMap model class
+ * An object that models the <code>&lt;key-map&gt;</code> element.
  *
  */
+@ThreadSafe
 @SuppressWarnings("serial")
-public class ModelKeyMap implements java.io.Serializable {
+public final class ModelKeyMap implements java.io.Serializable {
+
+    /*
+     * Developers - this is an immutable class. Once constructed, the object should not change state.
+     * Therefore, 'setter' methods are not allowed. If client code needs to modify the object's
+     * state, then it can create a new copy with the changed values.
+     */
 
     /** name of the field in this entity */
-    protected String fieldName = "";
+    private final String fieldName;
 
     /** name of the field in related entity */
-    protected String relFieldName = "";
-
-    /** Default Constructor */
-    public ModelKeyMap() {}
+    private final String relFieldName;
 
     /** Data Constructor, if relFieldName is null defaults to fieldName */
     public ModelKeyMap(String fieldName, String relFieldName) {
@@ -56,24 +61,16 @@ public class ModelKeyMap implements java
         this.relFieldName = UtilXml.checkEmpty(keyMapElement.getAttribute("rel-field-name"), this.fieldName).intern();
     }
 
-    /** name of the field in this entity */
+    /** Returns the field name. */
     public String getFieldName() {
         return this.fieldName;
     }
 
-    public void setFieldName(String fieldName) {
-        this.fieldName = fieldName;
-    }
-
-    /** name of the field in related entity */
+    /** Returns the related entity field name. */
     public String getRelFieldName() {
         return this.relFieldName;
     }
 
-    public void setRelFieldName(String relFieldName) {
-        this.relFieldName = relFieldName;
-    }
-
     // ======= Some Convenience Oriented Factory Methods =======
     public static List<ModelKeyMap> makeKeyMapList(String fieldName1) {
         return UtilMisc.toList(new ModelKeyMap(fieldName1, null));
@@ -104,13 +101,13 @@ public class ModelKeyMap implements java
         return true;
     }
 
+    // TODO: Externalize this.
     public Element toXmlElement(Document document) {
         Element root = document.createElement("key-map");
         root.setAttribute("field-name", this.getFieldName());
         if (!this.getFieldName().equals(this.getRelFieldName())) {
             root.setAttribute("rel-field-name", this.getRelFieldName());
         }
-
         return root;
     }
 }

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelReader.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelReader.java?rev=1477929&r1=1477928&r2=1477929&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelReader.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelReader.java Wed May  1 08:16:56 2013
@@ -25,6 +25,7 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.ArrayList;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
@@ -341,35 +342,31 @@ TEMP_VIEW_LOOP:
                                         throw new GenericModelException("Error getting related entity [" + modelRelation.getRelEntityName() + "] definition from entity [" + curEntityName + "]", e);
                                     }
                                     if (relatedEnt != null) {
+                                        // create the new relationship even if one exists so we can show what we are looking for in the info message
                                         // don't do relationship to the same entity, unless title is "Parent", then do a "Child" automatically
-                                        String targetTitle = modelRelation.getTitle();
-                                        if (curModelEntity.getEntityName().equals(relatedEnt.getEntityName()) && "Parent".equals(targetTitle)) {
-                                            targetTitle = "Child";
+                                        String title = modelRelation.getTitle();
+                                        if (curModelEntity.getEntityName().equals(relatedEnt.getEntityName()) && "Parent".equals(title)) {
+                                            title = "Child";
                                         }
-
-                                        // create the new relationship even if one exists so we can show what we are looking for in the info message
-                                        ModelRelation newRel = new ModelRelation();
-                                        newRel.setModelEntity(relatedEnt);
-                                        newRel.setRelEntityName(curModelEntity.getEntityName());
-                                        newRel.setTitle(targetTitle);
-                                        newRel.setAutoRelation(true);
+                                        String description = "";
+                                        String type = "";
+                                        String relEntityName = curModelEntity.getEntityName();
+                                        String fkName = "";
+                                        ArrayList<ModelKeyMap> keyMaps = new ArrayList<ModelKeyMap>();
+                                        boolean isAutoRelation = true;
                                         Set<String> curEntityKeyFields = new HashSet<String>();
-                                        for (int kmn = 0; kmn < modelRelation.getKeyMapsSize(); kmn++) {
-                                            ModelKeyMap curkm = modelRelation.getKeyMap(kmn);
-                                            ModelKeyMap newkm = new ModelKeyMap();
-                                            newRel.addKeyMap(newkm);
-                                            newkm.setFieldName(curkm.getRelFieldName());
-                                            newkm.setRelFieldName(curkm.getFieldName());
+                                        for (ModelKeyMap curkm : modelRelation.getKeyMaps()) {
+                                            keyMaps.add(new ModelKeyMap(curkm.getRelFieldName(), curkm.getFieldName()));
                                             curEntityKeyFields.add(curkm.getFieldName());
                                         }
+                                        keyMaps.trimToSize();
                                         // decide whether it should be one or many by seeing if the key map represents the complete pk of the relEntity
                                         if (curModelEntity.containsAllPkFieldNames(curEntityKeyFields)) {
                                             // always use one-nofk, we don't want auto-fks getting in for these automatic ones
-                                            newRel.setType("one-nofk");
-
+                                            type = "one-nofk";
                                             // to keep it clean, remove any additional keys that aren't part of the PK
                                             List<String> curPkFieldNames = curModelEntity.getPkFieldNames();
-                                            Iterator<ModelKeyMap> nrkmIter = newRel.getKeyMapsIterator();
+                                            Iterator<ModelKeyMap> nrkmIter = keyMaps.iterator();
                                             while (nrkmIter.hasNext()) {
                                                 ModelKeyMap nrkm =nrkmIter.next();
                                                 String checkField = nrkm.getRelFieldName();
@@ -378,10 +375,11 @@ TEMP_VIEW_LOOP:
                                                 }
                                             }
                                         } else {
-                                            newRel.setType("many");
+                                            type= "many";
                                         }
+                                        ModelRelation newRel = ModelRelation.create(relatedEnt, description, type, title, relEntityName, fkName, keyMaps, isAutoRelation);
 
-                                        ModelRelation existingRelation = relatedEnt.getRelation(targetTitle + curModelEntity.getEntityName());
+                                        ModelRelation existingRelation = relatedEnt.getRelation(title + curModelEntity.getEntityName());
                                         if (existingRelation == null) {
                                             numAutoRelations++;
                                             if (curModelEntity.getEntityName().equals(relatedEnt.getEntityName())) {
@@ -392,16 +390,16 @@ TEMP_VIEW_LOOP:
                                         } else {
                                             if (newRel.equals(existingRelation)) {
                                                 // don't warn if the target title+entity = current title+entity
-                                                if (!(targetTitle + curModelEntity.getEntityName()).equals(modelRelation.getTitle() + modelRelation.getRelEntityName())) {
+                                                if (Debug.infoOn() && !(title + curModelEntity.getEntityName()).equals(modelRelation.getTitle() + modelRelation.getRelEntityName())) {
                                                     //String errorMsg = "Relation already exists to entity [] with title [" + targetTitle + "],from entity []";
                                                     String message = "Entity [" + relatedEnt.getPackageName() + ":" + relatedEnt.getEntityName() + "] already has identical relationship to entity [" +
-                                                            curModelEntity.getEntityName() + "] title [" + targetTitle + "]; would auto-create: type [" +
+                                                            curModelEntity.getEntityName() + "] title [" + title + "]; would auto-create: type [" +
                                                             newRel.getType() + "] and fields [" + newRel.keyMapString(",", "") + "]";
                                                     orderedMessages.add(message);
                                                 }
                                             } else {
                                                 String message = "Existing relationship with the same name, but different specs found from what would be auto-created for Entity [" + relatedEnt.getEntityName() + "] and relationship to entity [" +
-                                                        curModelEntity.getEntityName() + "] title [" + targetTitle + "]; would auto-create: type [" +
+                                                        curModelEntity.getEntityName() + "] title [" + title + "]; would auto-create: type [" +
                                                         newRel.getType() + "] and fields [" + newRel.keyMapString(",", "") + "]";
                                                 Debug.logVerbose(message, module);
                                             }
@@ -555,7 +553,7 @@ TEMP_VIEW_LOOP:
                 }
             }
             if (UtilValidate.isNotEmpty(entityFilterSet) && !entityFilterSet.contains(entityName)) {
-                //Debug.logInfo("Not including entity " + entityName + " becuase it is not in the entity set: " + entityFilterSet, module);
+                //Debug.logInfo("Not including entity " + entityName + " because it is not in the entity set: " + entityFilterSet, module);
                 continue;
             }
 
@@ -602,32 +600,11 @@ TEMP_VIEW_LOOP:
 
     public ModelRelation createRelation(ModelEntity entity, Element relationElement) {
         this.numRelations++;
-        ModelRelation relation = new ModelRelation(entity, relationElement);
+        ModelRelation relation = ModelRelation.create(entity, relationElement, false);
         return relation;
     }
 
-    public ModelField findModelField(ModelEntity entity, String fieldName) {
-        for (ModelField field: entity.getFieldsUnmodifiable()) {
-            if (field.name.compareTo(fieldName) == 0) {
-                return field;
-            }
-        }
-        return null;
-    }
-
-    public ModelField createModelField(String name, String type, String colName, boolean isPk) {
-        this.numFields++;
-        ModelField field = new ModelField(name, type, colName, isPk);
-        return field;
-    }
-
-    public ModelField createModelField(Element fieldElement) {
-        if (fieldElement == null) {
-            return null;
-        }
-
-        this.numFields++;
-        ModelField field = new ModelField(fieldElement);
-        return field;
+    public void incrementFieldCount(int amount) {
+        this.numFields += amount;
     }
 }