|
Author: adrianc
Date: Sun Apr 28 20:10:02 2013 New Revision: 1476826 URL: http://svn.apache.org/r1476826 Log: A small overhaul for the ModelEntity class. The class is not thread-safe. Worse, there were four ModelField-related collections that were not updated consistently - causing invalid data. Two of the collections (field list and field map) were redundant, so I eliminated one. This is a step toward thread-safety, but the class still isn't thread-safe. It would be best if this class was immutable, but that will require a lot of re-engineering. Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntity.java ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelReader.java ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java 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=1476826&r1=1476825&r2=1476826&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 Sun Apr 28 20:10:02 2013 @@ -20,6 +20,7 @@ package org.ofbiz.entity.model; import java.io.PrintWriter; import java.io.Serializable; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -32,6 +33,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; +import java.util.concurrent.CopyOnWriteArrayList; import org.ofbiz.base.util.Debug; import org.ofbiz.base.util.GeneralException; @@ -68,7 +70,7 @@ public class ModelEntity extends ModelIn public static final String CREATE_STAMP_TX_FIELD = "createdTxStamp"; /** The ModelReader that created this Entity */ - protected ModelReader modelReader = null; + private final ModelReader modelReader; /** The entity-name of the Entity */ protected String entityName = ""; @@ -85,22 +87,23 @@ public class ModelEntity extends ModelIn /** The sequence-bank-size of the Entity */ protected Integer sequenceBankSize = null; - /** A List of the Field objects for the Entity */ - protected List<ModelField> fields = new LinkedList<ModelField>(); + /** Synchronization object used to control access to the ModelField collection objects. + * A single lock is used for all ModelField collections so collection updates are atomic. */ + private final Object fieldsLock = new Object(); - protected Map<String, ModelField> fieldsMap = null; + private final Map<String, ModelField> fieldsMap = new HashMap<String, ModelField>(); /** A List of the Field objects for the Entity, one for each Primary Key */ - protected List<ModelField> pks = new LinkedList<ModelField>(); + private final ArrayList<ModelField> pks = new ArrayList<ModelField>(); /** A List of the Field objects for the Entity, one for each NON Primary Key */ - protected List<ModelField> nopks = new LinkedList<ModelField>(); + private final ArrayList<ModelField> nopks = new ArrayList<ModelField>(); /** relations defining relationships between this entity and other entities */ - protected List<ModelRelation> relations = new LinkedList<ModelRelation>(); + protected CopyOnWriteArrayList<ModelRelation> relations = new CopyOnWriteArrayList<ModelRelation>(); /** indexes on fields/columns in this entity */ - protected List<ModelIndex> indexes = new LinkedList<ModelIndex>(); + private CopyOnWriteArrayList<ModelIndex> indexes = new CopyOnWriteArrayList<ModelIndex>(); /** The reference of the dependentOn entity model */ protected ModelEntity specializationOfModelEntity = null; @@ -109,7 +112,7 @@ public class ModelEntity extends ModelIn protected Map<String, ModelEntity> specializedEntities = new HashMap<String, ModelEntity>(); /** map of ModelViewEntities that references this model */ - protected Set<String> viewEntities = new HashSet<String>(); + private final Set<String> viewEntities = new HashSet<String>(); /** An indicator to specify if this entity requires locking for updates */ protected boolean doLock = false; @@ -127,14 +130,14 @@ public class ModelEntity extends ModelIn protected boolean autoClearCache = true; - protected Boolean hasFieldWithAuditLog = null; - /** The location of this entity's definition */ protected String location = ""; // ===== CONSTRUCTORS ===== /** Default Constructor */ - public ModelEntity() {} + public ModelEntity() { + this.modelReader = null; + } protected ModelEntity(ModelReader reader) { this.modelReader = reader; @@ -154,32 +157,30 @@ public class ModelEntity extends ModelIn /** XML Constructor */ public ModelEntity(ModelReader reader, Element entityElement, UtilTimer utilTimer, ModelInfo def) { this(reader, entityElement, def); - if (utilTimer != null) utilTimer.timerString(" createModelEntity: before general/basic info"); this.populateBasicInfo(entityElement); - + if (utilTimer != null) utilTimer.timerString(" createModelEntity: before prim-keys"); + List<String> pkFieldNames = new ArrayList<String>(); + for (Element pkElement: UtilXml.childElementList(entityElement, "prim-key")) { + pkFieldNames.add(pkElement.getAttribute("field").intern()); + } if (utilTimer != null) utilTimer.timerString(" createModelEntity: before fields"); for (Element fieldElement: UtilXml.childElementList(entityElement, "field")) { ModelField field = reader.createModelField(fieldElement); if (field != null) { - field.setModelEntity(this); - this.fields.add(field); + internalAddField(field, pkFieldNames); } } - // if applicable automatically add the STAMP_FIELD and STAMP_TX_FIELD fields - if ((this.doLock || !this.noAutoStamp) && !this.isField(STAMP_FIELD)) { + if ((this.doLock || !this.noAutoStamp) && !fieldsMap.containsKey(STAMP_FIELD)) { ModelField newField = reader.createModelField(STAMP_FIELD, "date-time", null, false); newField.setIsAutoCreatedInternal(true); - newField.setModelEntity(this); - this.fields.add(newField); + internalAddField(newField, pkFieldNames); } - if (!this.noAutoStamp && !this.isField(STAMP_TX_FIELD)) { + if (!this.noAutoStamp && !fieldsMap.containsKey(STAMP_TX_FIELD)) { ModelField newField = reader.createModelField(STAMP_TX_FIELD, "date-time", null, false); newField.setIsAutoCreatedInternal(true); - newField.setModelEntity(this); - this.fields.add(newField); - + 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); @@ -187,20 +188,16 @@ public class ModelEntity extends ModelIn txIndex.setModelEntity(this); indexes.add(txIndex); } - // if applicable automatically add the CREATE_STAMP_FIELD and CREATE_STAMP_TX_FIELD fields - if ((this.doLock || !this.noAutoStamp) && !this.isField(CREATE_STAMP_FIELD)) { + if ((this.doLock || !this.noAutoStamp) && !fieldsMap.containsKey(CREATE_STAMP_FIELD)) { ModelField newField = reader.createModelField(CREATE_STAMP_FIELD, "date-time", null, false); newField.setIsAutoCreatedInternal(true); - newField.setModelEntity(this); - this.fields.add(newField); + internalAddField(newField, pkFieldNames); } - if (!this.noAutoStamp && !this.isField(CREATE_STAMP_TX_FIELD)) { + if (!this.noAutoStamp && !fieldsMap.containsKey(CREATE_STAMP_TX_FIELD)) { ModelField newField = reader.createModelField(CREATE_STAMP_TX_FIELD, "date-time", null, false); newField.setIsAutoCreatedInternal(true); - newField.setModelEntity(this); - this.fields.add(newField); - + 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); @@ -208,26 +205,17 @@ public class ModelEntity extends ModelIn txIndex.setModelEntity(this); indexes.add(txIndex); } - - if (utilTimer != null) utilTimer.timerString(" createModelEntity: before prim-keys"); - for (Element pkElement: UtilXml.childElementList(entityElement, "prim-key")) { - ModelField field = reader.findModelField(this, pkElement.getAttribute("field").intern()); - if (field != null) { - this.pks.add(field); - field.isPk = true; - field.isNotNull = true; + // Must be done last to preserve pk field sequence + for (String pkFieldName : pkFieldNames) { + ModelField pkField = fieldsMap.get(pkFieldName); + if (pkField == null) { + Debug.logWarning("Error in entity definition - primary key is invalid for entity " + this.getEntityName(), module); } else { - Debug.logError("[ModelReader.createModelEntity] ERROR: Could not find field \"" + - pkElement.getAttribute("field") + "\" specified in a prim-key", module); + pks.add(pkField); } } - - // now that we have the pks and the fields, make the nopks List - this.nopks = new LinkedList<ModelField>(); - for (ModelField field: this.fields) { - if (!field.isPk) this.nopks.add(field); - } - + pks.trimToSize(); + nopks.trimToSize(); if (utilTimer != null) utilTimer.timerString(" createModelEntity: before relations"); this.populateRelated(reader, entityElement); this.populateIndexes(entityElement); @@ -236,6 +224,7 @@ public class ModelEntity extends ModelIn /** DB Names Constructor */ public ModelEntity(String tableName, Map<String, DatabaseUtil.ColumnCheckInfo> colMap, ModelFieldTypeReader modelFieldTypeReader, boolean isCaseSensitive) { // if there is a dot in the name, remove it and everything before it, should be the schema name + this.modelReader = null; this.tableName = tableName; int dotIndex = this.tableName.indexOf("."); if (dotIndex >= 0) { @@ -245,9 +234,8 @@ public class ModelEntity extends ModelIn for (Map.Entry<String, DatabaseUtil.ColumnCheckInfo> columnEntry: colMap.entrySet()) { DatabaseUtil.ColumnCheckInfo ccInfo = columnEntry.getValue(); ModelField newField = new ModelField(ccInfo, modelFieldTypeReader); - this.fields.add(newField); + addField(newField); } - this.updatePkLists(); } protected void populateBasicInfo(Element entityElement) { @@ -271,24 +259,38 @@ 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 { + this.nopks.add(newField); + } + newField.setModelEntity(this); + this.fieldsMap.put(newField.getName(), newField); + } protected void populateRelated(ModelReader reader, Element entityElement) { + List<ModelRelation> tempList = new ArrayList<ModelRelation>(this.relations); for (Element relationElement: UtilXml.childElementList(entityElement, "relation")) { ModelRelation relation = reader.createRelation(this, relationElement); if (relation != null) { relation.setModelEntity(this); - this.relations.add(relation); + tempList.add(relation); } } + this.relations = new CopyOnWriteArrayList<ModelRelation>(tempList); } 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); - this.indexes.add(index); + tempList.add(index); } + this.indexes = new CopyOnWriteArrayList<ModelIndex>(tempList); } public boolean containsAllPkFieldNames(Set<String> fieldNames) { @@ -353,9 +355,12 @@ public class ModelEntity extends ModelIn } else { // add to the entity as a new field field.setModelEntity(this); - this.fields.add(field); - // this will always be true for now as extend-entity fielsd are always nonpks - if (!field.isPk) this.nopks.add(field); + 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); + } } } } @@ -463,17 +468,12 @@ public class ModelEntity extends ModelIn } public boolean getHasFieldWithAuditLog() { - if (this.hasFieldWithAuditLog == null) { - this.hasFieldWithAuditLog = false; - for (ModelField mf: this.fields) { - if (mf.getEnableAuditLog()) { - this.hasFieldWithAuditLog = true; - } + for (ModelField mf : getFieldsUnmodifiable()) { + if (mf.getEnableAuditLog()) { + return true; } - return this.hasFieldWithAuditLog; - } else { - return this.hasFieldWithAuditLog; } + return false; } /* Get the location of this entity's definition */ @@ -508,24 +508,11 @@ public class ModelEntity extends ModelIn return this.sequenceBankSize; } - public void updatePkLists() { - pks = new LinkedList<ModelField>(); - nopks = new LinkedList<ModelField>(); - - for (ModelField field: fields) { - if (field.isPk) - pks.add(field); - else - nopks.add(field); - } - } - public boolean isField(String fieldName) { if (fieldName == null) return false; - for (ModelField field: fields) { - if (field.name.equals(fieldName)) return true; + synchronized (fieldsLock) { + return fieldsMap.containsKey(fieldName); } - return false; } public boolean areFields(Collection<String> fieldNames) { @@ -537,23 +524,34 @@ public class ModelEntity extends ModelIn } public int getPksSize() { - return this.pks.size(); + synchronized (fieldsLock) { + return this.pks.size(); + } } public ModelField getOnlyPk() { - if (this.pks.size() == 1) { - return this.pks.get(0); - } else { - throw new IllegalArgumentException("Error in getOnlyPk, the [" + this.getEntityName() + "] entity has more than one pk!"); + synchronized (fieldsLock) { + if (this.pks.size() == 1) { + return this.pks.get(0); + } else { + throw new IllegalArgumentException("Error in getOnlyPk, the [" + this.getEntityName() + "] entity has more than one pk!"); + } } } public Iterator<ModelField> getPksIterator() { - return this.pks.iterator(); + return getPkFields().iterator(); + } + + @SuppressWarnings("unchecked") + public List<ModelField> getPkFields() { + synchronized (fieldsLock) { + return (List) this.pks.clone(); + } } public List<ModelField> getPkFieldsUnmodifiable() { - return Collections.unmodifiableList(this.pks); + return Collections.unmodifiableList(getPkFields()); } public String getFirstPkFieldName() { @@ -566,29 +564,41 @@ public class ModelEntity extends ModelIn } public int getNopksSize() { - return this.nopks.size(); + synchronized (fieldsLock) { + return this.nopks.size(); + } } public Iterator<ModelField> getNopksIterator() { - return this.nopks.iterator(); + return getNopksCopy().iterator(); } public List<ModelField> getNopksCopy() { - List<ModelField> newList = new LinkedList<ModelField>(); - newList.addAll(this.nopks); - return newList; + synchronized (fieldsLock) { + return new ArrayList<ModelField>(this.nopks); + } } public int getFieldsSize() { - return this.fields.size(); + synchronized (fieldsLock) { + return this.fieldsMap.size(); + } } public Iterator<ModelField> getFieldsIterator() { - return this.fields.iterator(); + synchronized (fieldsLock) { + List<ModelField> newList = new ArrayList<ModelField>(fieldsMap.size()); + newList.addAll(this.fieldsMap.values()); + return newList.iterator(); + } } public List<ModelField> getFieldsUnmodifiable() { - return Collections.unmodifiableList(this.fields); + synchronized (fieldsLock) { + List<ModelField> newList = new ArrayList<ModelField>(fieldsMap.size()); + newList.addAll(this.fieldsMap.values()); + return Collections.unmodifiableList(newList); + } } /** The col-name of the Field, the alias of the field if this is on a view-entity */ @@ -600,95 +610,59 @@ public class ModelEntity extends ModelIn public ModelField getField(String fieldName) { if (fieldName == null) return null; - if (fieldsMap == null) { - createFieldsMap(); + synchronized (fieldsLock) { + return fieldsMap.get(fieldName); } - ModelField modelField = fieldsMap.get(fieldName); - if (modelField == null) { - // sometimes weird things happen and this getField method is called before the fields are all populated, so before moving on just re-create the fieldsMap again real quick... - // the purpose of the fieldsMap is for speed, but if failures are a little slower, no biggie - createFieldsMap(); - modelField = fieldsMap.get(fieldName); - } - return modelField; - } - - protected synchronized void createFieldsMap() { - Map<String, ModelField> tempMap = new HashMap<String, ModelField>(); - for (int i = 0; i < fields.size(); i++) { - ModelField field = fields.get(i); - tempMap.put(field.name, field); - } - fieldsMap = tempMap; } public void addField(ModelField field) { - if (field == null) return; + if (field == null) + return; field.setModelEntity(this); - this.fields.add(field); - - if (field.isPk) { - pks.add(field); - } else { - nopks.add(field); - } - } - - public ModelField removeField(int index) { - ModelField field = null; - - field = fields.remove(index); - if (field == null) return null; - - if (field.isPk) { - pks.remove(field); - } else { - nopks.remove(field); + synchronized (fieldsLock) { + fieldsMap.put(field.getName(), field); + if (field.isPk) { + pks.add(field); + } else { + nopks.add(field); + } } - return field; } public ModelField removeField(String fieldName) { - if (fieldName == null) return null; - ModelField field = null; - - // FIXME: when the field is removed, i is still incremented - // while not correct, this doesn't cause any problems - for (int i = 0; i < fields.size(); i++) { - field = fields.get(i); - if (field.name.equals(fieldName)) { - fields.remove(i); + if (fieldName == null) + return null; + synchronized (fieldsLock) { + ModelField field = fieldsMap.remove(fieldName); + if (field != null) { if (field.isPk) { pks.remove(field); } else { nopks.remove(field); } } - field = null; + return field; } - return field; } public List<String> getAllFieldNames() { - return getFieldNamesFromFieldVector(fields); + synchronized (fieldsLock) { + List<String> newList = new ArrayList<String>(fieldsMap.size()); + newList.addAll(this.fieldsMap.keySet()); + return newList; + } } public List<String> getPkFieldNames() { - return getFieldNamesFromFieldVector(pks); + return getFieldNamesFromFieldVector(getPkFields()); } public List<String> getNoPkFieldNames() { - return getFieldNamesFromFieldVector(nopks); - } - - public List<String> getFieldNamesFromFieldVector(ModelField... modelFields) { - return getFieldNamesFromFieldVector(Arrays.asList(modelFields)); + return getFieldNamesFromFieldVector(getNopksCopy()); } - public List<String> getFieldNamesFromFieldVector(List<ModelField> modelFields) { - List<String> nameList = new LinkedList<String>(); - - if (modelFields == null || modelFields.size() <= 0) return nameList; + private List<String> getFieldNamesFromFieldVector(List<ModelField> modelFields) { + List<String> nameList = new ArrayList<String>(modelFields.size()); for (ModelField field: modelFields) { nameList.add(field.name); } @@ -804,15 +778,21 @@ public class ModelEntity extends ModelIn } public int getViewEntitiesSize() { - return this.viewEntities.size(); + synchronized (viewEntities) { + return this.viewEntities.size(); + } } public Iterator<String> getViewConvertorsIterator() { - return this.viewEntities.iterator(); + synchronized (viewEntities) { + return new HashSet<String>(this.viewEntities).iterator(); + } } public void addViewEntity(ModelViewEntity view) { - this.viewEntities.add(view.getEntityName()); + synchronized (viewEntities) { + this.viewEntities.add(view.getEntityName()); + } } public List<? extends Map<String, Object>> convertToViewValues(String viewEntityName, GenericEntity entity) { @@ -822,7 +802,9 @@ public class ModelEntity extends ModelIn } public boolean removeViewEntity(String viewEntityName) { - return this.viewEntities.remove(viewEntityName); + synchronized (viewEntities) { + return this.viewEntities.remove(viewEntityName); + } } public boolean removeViewEntity(ModelViewEntity viewEntity) { @@ -883,15 +865,15 @@ public class ModelEntity extends ModelIn } public String fieldNameString(String separator, String afterLast) { - return nameString(fields, separator, afterLast); + return nameString(getFieldsUnmodifiable(), separator, afterLast); } public String fieldTypeNameString() { - return typeNameString(fields); + return typeNameString(getFieldsUnmodifiable()); } public String primKeyClassNameString() { - return typeNameString(pks); + return typeNameString(getPkFields()); } public String pkNameString() { @@ -899,11 +881,11 @@ public class ModelEntity extends ModelIn } public String pkNameString(String separator, String afterLast) { - return nameString(pks, separator, afterLast); + return nameString(getPkFields(), separator, afterLast); } public String nonPkNullList() { - return fieldsStringList(fields, "null", ", ", false, true); + return fieldsStringList(getFieldsUnmodifiable(), "null", ", ", false, true); } @Deprecated @@ -1577,7 +1559,7 @@ public class ModelEntity extends ModelIn // for classProperties add field names AND relationship names to get a nice, complete chart List<String> classPropertiesList = new LinkedList<String>(); topLevelMap.put("classProperties", classPropertiesList); - for (ModelField field: this.fields) { + for (ModelField field: this.fieldsMap.values()) { if (field.getIsAutoCreatedInternal()) continue; if (field.getIsPk()) { classPropertiesList.add(field.getName() + "*"); @@ -1595,7 +1577,7 @@ public class ModelEntity extends ModelIn // attributes List<Map<String, Object>> attributesList = new LinkedList<Map<String, Object>>(); topLevelMap.put("attributes", attributesList); - for (ModelField field: this.fields) { + for (ModelField field: this.fieldsMap.values()) { if (field.getIsAutoCreatedInternal()) continue; ModelFieldType fieldType = modelFieldTypeReader.getModelFieldType(field.getType()); @@ -1632,7 +1614,7 @@ public class ModelEntity extends ModelIn // primaryKeyAttributes List<String> primaryKeyAttributesList = new LinkedList<String>(); topLevelMap.put("primaryKeyAttributes", primaryKeyAttributesList); - for (ModelField pkField: this.pks) { + for (ModelField pkField : getPkFields()) { primaryKeyAttributesList.add(pkField.getName()); } 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=1476826&r1=1476825&r2=1476826&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 Sun Apr 28 20:10:02 2013 @@ -607,7 +607,7 @@ TEMP_VIEW_LOOP: } public ModelField findModelField(ModelEntity entity, String fieldName) { - for (ModelField field: entity.fields) { + for (ModelField field: entity.getFieldsUnmodifiable()) { if (field.name.compareTo(fieldName) == 0) { return field; } Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java?rev=1476826&r1=1476825&r2=1476826&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java (original) +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java Sun Apr 28 20:10:02 2013 @@ -489,12 +489,7 @@ public class ModelViewEntity extends Mod } } - this.fields.add(field); - if (field.isPk) { - this.pks.add(field); - } else { - this.nopks.add(field); - } + addField(field); if ("count".equals(alias.function) || "count-distinct".equals(alias.function)) { // if we have a "count" function we have to change the type Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java?rev=1476826&r1=1476825&r2=1476826&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java (original) +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java Sun Apr 28 20:10:02 2013 @@ -46,6 +46,8 @@ import org.ofbiz.entity.condition.Entity import org.ofbiz.entity.condition.EntityOperator; import org.ofbiz.entity.config.DatasourceInfo; import org.ofbiz.entity.config.EntityConfigUtil; +import org.ofbiz.entity.model.ModelEntity; +import org.ofbiz.entity.model.ModelField; import org.ofbiz.entity.testtools.EntityTestCase; import org.ofbiz.entity.transaction.GenericTransactionException; import org.ofbiz.entity.transaction.TransactionUtil; @@ -61,6 +63,8 @@ public class EntityTestSuite extends Ent * with Derby. Going up to 100,000 causes problems all around because Java List seems to be capped at about 65,000 values. * * NOTE: setting this lower so that the general tests don't take so long to run; to really push it can increase this number. + * NOTE: Let's try to distinguish between functional testing and stress testing. Any value greater than 1 will be sufficient + * for functional testing. Values like 10,000 or 100,000 are more appropriate for stress testing. */ public static final long TEST_COUNT = 1000; @@ -70,6 +74,20 @@ public class EntityTestSuite extends Ent final static private int _level1max = 3; // number of TestingNode entities to create + public void testModels() throws Exception { + ModelEntity modelEntity = delegator.getModelEntity("TestingType"); + assertNotNull("TestingType entity model not null", modelEntity); + ModelField modelField = modelEntity.getField("description"); + assertNotNull("TestingType.description field model not null", modelField); + modelField = new ModelField("newDesc", modelField.getType(), "NEW_DESC", false); + modelEntity.addField(modelField); + modelField = modelEntity.getField("newDesc"); + assertNotNull("TestingType.newDesc field model not null", modelField); + modelEntity.removeField("newDesc"); + modelField = modelEntity.getField("newDesc"); + assertNull("TestingType.newDesc field model is null", modelField); + } + /* * Tests storing values with the delegator's .create, .makeValue, and .storeAll methods */ |
| Free forum by Nabble | Edit this page |
