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/04/28 22:10:03 UTC
svn commit: r1476826 - in
/ofbiz/trunk/framework/entity/src/org/ofbiz/entity: model/ModelEntity.java
model/ModelReader.java model/ModelViewEntity.java test/EntityTestSuite.java
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
*/