svn commit: r802567 [2/5] - in /ofbiz/trunk: applications/order/src/org/ofbiz/order/shoppingcart/ applications/product/src/org/ofbiz/shipment/packing/ applications/product/src/org/ofbiz/shipment/verify/ applications/product/src/org/ofbiz/shipment/weigh...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r802567 [2/5] - in /ofbiz/trunk: applications/order/src/org/ofbiz/order/shoppingcart/ applications/product/src/org/ofbiz/shipment/packing/ applications/product/src/org/ofbiz/shipment/verify/ applications/product/src/org/ofbiz/shipment/weigh...

adrianc
Added: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/DelegatorImpl.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/DelegatorImpl.java?rev=802567&view=auto
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/DelegatorImpl.java (added)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/DelegatorImpl.java Sun Aug  9 18:04:26 2009
@@ -0,0 +1,2726 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.ofbiz.entity;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import javolution.util.FastList;
+import javolution.util.FastMap;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.GeneralRuntimeException;
+import org.ofbiz.base.util.UtilDateTime;
+import org.ofbiz.base.util.UtilFormatOut;
+import org.ofbiz.base.util.UtilMisc;
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.base.util.UtilXml;
+import org.ofbiz.base.util.cache.CacheLine;
+import org.ofbiz.base.util.cache.UtilCache;
+import org.ofbiz.entity.cache.Cache;
+import org.ofbiz.entity.condition.EntityCondition;
+import org.ofbiz.entity.condition.EntityConditionList;
+import org.ofbiz.entity.condition.EntityExpr;
+import org.ofbiz.entity.condition.EntityOperator;
+import org.ofbiz.entity.config.DatasourceInfo;
+import org.ofbiz.entity.config.DelegatorInfo;
+import org.ofbiz.entity.config.EntityConfigUtil;
+import org.ofbiz.entity.datasource.GenericHelper;
+import org.ofbiz.entity.datasource.GenericHelperFactory;
+import org.ofbiz.entity.eca.EntityEcaHandler;
+import org.ofbiz.entity.model.DynamicViewEntity;
+import org.ofbiz.entity.model.ModelEntity;
+import org.ofbiz.entity.model.ModelEntityChecker;
+import org.ofbiz.entity.model.ModelField;
+import org.ofbiz.entity.model.ModelFieldType;
+import org.ofbiz.entity.model.ModelFieldTypeReader;
+import org.ofbiz.entity.model.ModelGroupReader;
+import org.ofbiz.entity.model.ModelKeyMap;
+import org.ofbiz.entity.model.ModelReader;
+import org.ofbiz.entity.model.ModelRelation;
+import org.ofbiz.entity.model.ModelViewEntity;
+import org.ofbiz.entity.serialize.SerializeException;
+import org.ofbiz.entity.serialize.XmlSerializer;
+import org.ofbiz.entity.transaction.GenericTransactionException;
+import org.ofbiz.entity.transaction.TransactionUtil;
+import org.ofbiz.entity.util.DistributedCacheClear;
+import org.ofbiz.entity.util.EntityCrypto;
+import org.ofbiz.entity.util.EntityFindOptions;
+import org.ofbiz.entity.util.EntityListIterator;
+import org.ofbiz.entity.util.SequenceUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+/**
+ * Implementation of the <code>GenericDelegator</code> interface. The class
+ * contains a reference to a shared instance of <code>DelegatorData</code> -
+ * making it possible to have per-thread instances of this class while
+ * sharing common delegator data.
+ */
+public class DelegatorImpl implements Cloneable, GenericDelegator {
+
+    protected static class EntityEcaRuleRunner<T> {
+        protected EntityEcaHandler<T> entityEcaHandler;
+        protected Map<String, List<T>> eventMap;
+
+        protected EntityEcaRuleRunner(EntityEcaHandler<T> entityEcaHandler, Map<String, List<T>> eventMap) {
+            this.entityEcaHandler = entityEcaHandler;
+            this.eventMap = eventMap;
+        }
+
+        protected void evalRules(String event, String currentOperation, GenericEntity value, boolean isError) throws GenericEntityException {
+            if (entityEcaHandler == null) {
+                return;
+            }
+            entityEcaHandler.evalRules(currentOperation, eventMap, event, value, isError);
+        }
+    }
+
+    private enum OperationType {
+        DELETE, INSERT, UPDATE
+    }
+
+    public class TestOperation {
+        private final OperationType operation;
+        private final GenericValue value;
+
+        public TestOperation(OperationType operation, GenericValue value) {
+            this.operation = operation;
+            this.value = value;
+        }
+
+        public OperationType getOperation() {
+            return operation;
+        }
+
+        public GenericValue getValue() {
+            return value;
+        }
+    }
+
+    /**
+     * This flag is only here for lower level technical testing, it shouldn't be
+     * user configurable (or at least I don't think so yet); when true all
+     * operations without a transaction will be wrapped in one; seems to be
+     * necessary for some (all?) XA aware connection pools, and should improve
+     * overall stability and consistency
+     */
+    public static final boolean alwaysUseTransaction = true;
+
+    public static final String module = DelegatorImpl.class.getName();
+
+    protected static <T> EntityEcaRuleRunner<T> createEntityEcaRuleRunner(EntityEcaHandler<T> entityEcaHandler, String entityName) {
+        return new EntityEcaRuleRunner<T>(entityEcaHandler, entityEcaHandler != null ? entityEcaHandler.getEntityEventMap(entityName) : null);
+    }
+
+    protected final DelegatorData delegatorData;
+
+    protected Locale locale = Locale.getDefault();
+
+    private boolean testMode = false;
+
+    private List<TestOperation> testOperations = null;
+
+    private boolean testRollbackInProgress = false;
+
+    protected String sessionIdentifier = "";
+
+    protected String userIdentifier = "";
+
+    protected DelegatorImpl(DelegatorData delegatorData) {
+        this.delegatorData = delegatorData;
+        if (!delegatorData.initialized) {
+            synchronized (delegatorData) {
+                if (delegatorData.initialized) {
+                    return;
+                }
+                // do the entity model check
+                List<String> warningList = FastList.newInstance();
+                Debug.logImportant("Doing entity definition check...", module);
+                try {
+                    ModelEntityChecker.checkEntities(this, warningList);
+                } catch (GenericEntityException e) {
+                    Debug.logError(e, "Error while checking entities: ", module);
+                }
+                if (warningList.size() > 0) {
+                    Debug.logWarning("=-=-=-=-= Found " + warningList.size() + " warnings when checking the entity definitions:", module);
+                    for (String warning : warningList) {
+                        Debug.logWarning(warning, module);
+                    }
+                }
+
+                // initialize helpers by group
+                Set<String> groupNames = getModelGroupReader().getGroupNames(this.delegatorData.delegatorName);
+                Iterator<String> groups = UtilMisc.toIterator(groupNames);
+                while (groups != null && groups.hasNext()) {
+                    String groupName = groups.next();
+                    String helperName = this.getGroupHelperName(groupName);
+
+                    if (Debug.infoOn())
+                        Debug.logInfo("Delegator \"" + this.delegatorData.delegatorName + "\" initializing helper \"" + helperName + "\" for entity group \"" + groupName + "\".", module);
+                    TreeSet<String> helpersDone = new TreeSet<String>();
+                    if (helperName != null && helperName.length() > 0) {
+                        // make sure each helper is only loaded once
+                        if (helpersDone.contains(helperName)) {
+                            if (Debug.infoOn())
+                                Debug.logInfo("Helper \"" + helperName + "\" already initialized, not re-initializing.", module);
+                            continue;
+                        }
+                        helpersDone.add(helperName);
+                        // pre-load field type defs, the return value is ignored
+                        ModelFieldTypeReader.getModelFieldTypeReader(helperName);
+                        // get the helper and if configured, do the datasource check
+                        GenericHelper helper = GenericHelperFactory.getHelper(helperName);
+
+                        DatasourceInfo datasourceInfo = EntityConfigUtil.getDatasourceInfo(helperName);
+                        if (datasourceInfo.checkOnStart) {
+                            if (Debug.infoOn())
+                                Debug.logInfo("Doing database check as requested in entityengine.xml with addMissing=" + datasourceInfo.addMissingOnStart, module);
+                            try {
+                                helper.checkDataSource(this.getModelEntityMapByGroup(groupName), null, datasourceInfo.addMissingOnStart);
+                            } catch (GenericEntityException e) {
+                                Debug.logWarning(e, e.getMessage(), module);
+                            }
+                        }
+                    }
+                }
+                // Let other instances know the shared data is ready to use
+                this.delegatorData.initialized = true;
+                // setup the crypto class
+                this.delegatorData.crypto = new EntityCrypto(this);
+
+                // time to do some tricks with manual class loading that resolves
+                // circular dependencies, like calling services...
+                ClassLoader loader = Thread.currentThread().getContextClassLoader();
+
+                // if useDistributedCacheClear is false do nothing since the
+                // distributedCacheClear member field with a null value will cause the
+                // dcc code to do nothing
+                if (this.delegatorData.delegatorInfo.useDistributedCacheClear) {
+                    // initialize the distributedCacheClear mechanism
+                    String distributedCacheClearClassName = this.delegatorData.delegatorInfo.distributedCacheClearClassName;
+
+                    try {
+                        Class<?> dccClass = loader.loadClass(distributedCacheClearClassName);
+                        this.delegatorData.distributedCacheClear = (DistributedCacheClear) dccClass.newInstance();
+                        this.delegatorData.distributedCacheClear.setDelegator(this, this.delegatorData.delegatorInfo.distributedCacheClearUserLoginId);
+                    } catch (ClassNotFoundException e) {
+                        Debug.logWarning(e, "DistributedCacheClear class with name " + distributedCacheClearClassName + " was not found, distributed cache clearing will be disabled", module);
+                    } catch (InstantiationException e) {
+                        Debug.logWarning(e, "DistributedCacheClear class with name " + distributedCacheClearClassName + " could not be instantiated, distributed cache clearing will be disabled", module);
+                    } catch (IllegalAccessException e) {
+                        Debug.logWarning(e, "DistributedCacheClear class with name " + distributedCacheClearClassName + " could not be accessed (illegal), distributed cache clearing will be disabled", module);
+                    } catch (ClassCastException e) {
+                        Debug.logWarning(e, "DistributedCacheClear class with name " + distributedCacheClearClassName + " does not implement the DistributedCacheClear interface, distributed cache clearing will be disabled", module);
+                    }
+                } else {
+                    Debug.logInfo("Distributed Cache Clear System disabled for delegator [" + this.delegatorData.delegatorName + "]", module);
+                }
+
+                // setup the Entity ECA Handler
+                initEntityEcaHandler();
+            }
+        }
+    }
+
+    protected void absorbList(List<GenericValue> lst) {
+        if (lst == null)
+            return;
+        for (GenericValue value : lst) {
+            value.setDelegator(this);
+        }
+    }
+
+    public void clearAllCacheLinesByDummyPK(Collection<GenericPK> dummyPKs) {
+        if (dummyPKs == null)
+            return;
+        for (GenericEntity entity : dummyPKs) {
+            this.clearCacheLineFlexible(entity);
+        }
+    }
+
+    public void clearAllCacheLinesByValue(Collection<GenericValue> values) {
+        if (values == null)
+            return;
+        for (GenericValue value : values) {
+            this.clearCacheLine(value);
+        }
+    }
+
+    public void clearAllCaches() {
+        this.clearAllCaches(true);
+    }
+
+    public void clearAllCaches(boolean distribute) {
+        this.delegatorData.cache.clear();
+        if (distribute && this.delegatorData.distributedCacheClear != null) {
+            this.delegatorData.distributedCacheClear.clearAllCaches();
+        }
+    }
+
+    public void clearCacheLine(GenericPK primaryKey) {
+        this.clearCacheLine(primaryKey, true);
+    }
+
+    public void clearCacheLine(GenericPK primaryKey, boolean distribute) {
+        if (primaryKey == null)
+            return;
+
+        // if never cached, then don't bother clearing
+        if (primaryKey.getModelEntity().getNeverCache())
+            return;
+
+        this.delegatorData.cache.remove(primaryKey);
+
+        if (distribute && this.delegatorData.distributedCacheClear != null) {
+            this.delegatorData.distributedCacheClear.distributedClearCacheLine(primaryKey);
+        }
+    }
+
+    public void clearCacheLine(GenericValue value) {
+        this.clearCacheLine(value, true);
+    }
+
+    public void clearCacheLine(GenericValue value, boolean distribute) {
+        // TODO: make this a bit more intelligent by passing in the operation
+        // being done (create, update, remove) so we can not do unnecessary
+        // cache clears...
+        // for instance:
+        // on create don't clear by primary cache (and won't clear original
+        // values because there won't be any)
+        // on remove don't clear by and for new values, but do for original
+        // values
+
+        // Debug.logInfo("running clearCacheLine for value: " + value + ",
+        // distribute: " + distribute, module);
+        if (value == null)
+            return;
+
+        // if never cached, then don't bother clearing
+        if (value.getModelEntity().getNeverCache())
+            return;
+
+        this.delegatorData.cache.remove(value);
+
+        if (distribute && this.delegatorData.distributedCacheClear != null) {
+            this.delegatorData.distributedCacheClear.distributedClearCacheLine(value);
+        }
+    }
+
+    public void clearCacheLine(String entityName) {
+        this.delegatorData.cache.remove(entityName);
+    }
+
+    public void clearCacheLine(String entityName, Map<String, ? extends Object> fields) {
+        // if no fields passed, do the all cache quickly and return
+        if (fields == null) {
+            this.delegatorData.cache.remove(entityName);
+            return;
+        }
+
+        ModelEntity entity = this.getModelEntity(entityName);
+        if (entity == null) {
+            throw new IllegalArgumentException("[GenericDelegator.clearCacheLine] could not find entity for entityName: " + entityName);
+        }
+        // if never cached, then don't bother clearing
+        if (entity.getNeverCache())
+            return;
+
+        GenericValue dummyValue = GenericValue.create(entity, fields);
+        dummyValue.setDelegator(this);
+        this.clearCacheLineFlexible(dummyValue);
+    }
+
+    public void clearCacheLine(String entityName, Object... fields) {
+        clearCacheLine(entityName, UtilMisc.<String, Object> toMap(fields));
+    }
+
+    public void clearCacheLineByCondition(String entityName, EntityCondition condition) {
+        clearCacheLineByCondition(entityName, condition, true);
+    }
+
+    public void clearCacheLineByCondition(String entityName, EntityCondition condition, boolean distribute) {
+        if (entityName != null) {
+            // if never cached, then don't bother clearing
+            if (getModelEntity(entityName).getNeverCache())
+                return;
+
+            this.delegatorData.cache.remove(entityName, condition);
+
+            if (distribute && this.delegatorData.distributedCacheClear != null) {
+                this.delegatorData.distributedCacheClear.distributedClearCacheLineByCondition(entityName, condition);
+            }
+        }
+    }
+
+    public void clearCacheLineFlexible(GenericEntity dummyPK) {
+        this.clearCacheLineFlexible(dummyPK, true);
+    }
+
+    public void clearCacheLineFlexible(GenericEntity dummyPK, boolean distribute) {
+        if (dummyPK != null) {
+            // if never cached, then don't bother clearing
+            if (dummyPK.getModelEntity().getNeverCache())
+                return;
+
+            this.delegatorData.cache.remove(dummyPK);
+
+            if (distribute && this.delegatorData.distributedCacheClear != null) {
+                this.delegatorData.distributedCacheClear.distributedClearCacheLineFlexible(dummyPK);
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected void clearCacheValues(UtilCache cache, String entityName, EntityCondition condition) {
+        Iterator iterator = cache.cacheLineTable.values().iterator();
+        while (iterator.hasNext()) {
+            CacheLine line = (CacheLine) iterator.next();
+            GenericValue value = (GenericValue) line.getValue();
+            if (value != null && value.getEntityName().equals(entityName) && condition.entityMatches(value)) {
+                iterator.remove();
+            }
+        }
+    }
+
+    @Override
+    protected Object clone() {
+        return this.cloneDelegator(this.delegatorData.delegatorName);
+    }
+
+    public GenericDelegator cloneDelegator() {
+        return this.cloneDelegator(this.delegatorData.delegatorName);
+    }
+
+    public GenericDelegator cloneDelegator(String delegatorName) {
+        // creates an exact clone of the delegator; except for the sequencer
+        // note that this will not be cached and should be used only when
+        // needed to change something for single instance (use).
+        DelegatorImpl newDelegator = new DelegatorImpl((DelegatorData) this.delegatorData.clone());
+        newDelegator.delegatorData.delegatorName = delegatorName;
+        // In case this delegator is in testMode give it a reference to
+        // the rollback list
+        newDelegator.testOperations = this.testOperations;
+        // not setting the sequencer so that we have unique sequences.
+        newDelegator.delegatorData.sequencer = null;
+        return newDelegator;
+    }
+
+    public GenericValue create(GenericPK primaryKey) throws GenericEntityException {
+        return this.create(primaryKey, true);
+    }
+
+    public GenericValue create(GenericPK primaryKey, boolean doCacheClear) throws GenericEntityException {
+        if (primaryKey == null) {
+            throw new GenericEntityException("Cannot create from a null primaryKey");
+        }
+
+        return this.create(GenericValue.create(primaryKey), doCacheClear);
+    }
+
+    public GenericValue create(GenericValue value) throws GenericEntityException {
+        return this.create(value, true);
+    }
+
+    public GenericValue create(GenericValue value, boolean doCacheClear) throws GenericEntityException {
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(value.getEntityName());
+            ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE, EntityEcaHandler.OP_CREATE, value, false);
+
+            if (value == null) {
+                throw new GenericEntityException("Cannot create a null value");
+            }
+            GenericHelper helper = getEntityHelper(value.getEntityName());
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_CREATE, value, false);
+
+            value.setDelegator(this);
+            this.encryptFields(value);
+
+            // if audit log on for any fields, save new value with no old value
+            // because it's a create
+            if (value != null && value.getModelEntity().getHasFieldWithAuditLog()) {
+                createEntityAuditLogAll(value, false, false);
+            }
+
+            value = helper.create(value);
+
+            if (testMode) {
+                storeForTestRollback(new TestOperation(OperationType.INSERT, value));
+            }
+            if (value != null) {
+                value.setDelegator(this);
+                if (value.lockEnabled()) {
+                    refresh(value, doCacheClear);
+                } else {
+                    if (doCacheClear) {
+                        ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR, EntityEcaHandler.OP_CREATE, value, false);
+                        this.clearCacheLine(value);
+                    }
+                }
+            }
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_CREATE, value, false);
+
+            return value;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in create operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction.";
+            Debug.logError(e, errMsg, module);
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
+            }
+            // after rolling back, rethrow the exception
+            throw e;
+        } finally {
+            // only commit the transaction if we started one... this will throw
+            // an exception if it fails
+            TransactionUtil.commit(beganTransaction);
+        }
+    }
+
+    public GenericValue create(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException {
+        if (entityName == null || fields == null) {
+            return null;
+        }
+        ModelEntity entity = this.getModelReader().getModelEntity(entityName);
+        GenericValue genericValue = GenericValue.create(entity, fields);
+
+        return this.create(genericValue, true);
+    }
+
+    public GenericValue create(String entityName, Object... fields) throws GenericEntityException {
+        return create(entityName, UtilMisc.<String, Object> toMap(fields));
+    }
+
+    protected void createEntityAuditLogAll(GenericValue value, boolean isUpdate, boolean isRemove) throws GenericEntityException {
+        for (ModelField mf : value.getModelEntity().getFieldsUnmodifiable()) {
+            if (mf.getEnableAuditLog()) {
+                createEntityAuditLogSingle(value, mf, isUpdate, isRemove);
+            }
+        }
+    }
+
+    protected void createEntityAuditLogSingle(GenericValue value, ModelField mf, boolean isUpdate, boolean isRemove) throws GenericEntityException {
+        if (value == null || mf == null || !mf.getEnableAuditLog() || this.testRollbackInProgress) {
+            return;
+        }
+
+        GenericValue entityAuditLog = this.makeValue("EntityAuditLog");
+        entityAuditLog.set("auditHistorySeqId", this.getNextSeqId("EntityAuditLog"));
+        entityAuditLog.set("changedEntityName", value.getEntityName());
+        entityAuditLog.set("changedFieldName", mf.getName());
+
+        String pkCombinedValueText = value.getPkShortValueString();
+        if (pkCombinedValueText.length() > 250) {
+            // uh-oh, the string is too long!
+            pkCombinedValueText = pkCombinedValueText.substring(0, 250);
+        }
+        entityAuditLog.set("pkCombinedValueText", pkCombinedValueText);
+
+        GenericValue oldGv = null;
+        if (isUpdate) {
+            // it's an update, get it from the database
+            oldGv = this.findOne(value.getEntityName(), value.getPrimaryKey(), false);
+        } else if (isRemove) {
+            oldGv = value;
+        }
+        if (oldGv == null) {
+            if (isUpdate || isRemove) {
+                entityAuditLog.set("oldValueText", "[ERROR] Old value not found even though it was an update or remove");
+            }
+        } else {
+            // lookup old value
+            String oldValueText = null;
+            Object oldValue = oldGv.get(mf.getName());
+            if (oldValue != null) {
+                oldValueText = oldValue.toString();
+                if (oldValueText.length() > 250) {
+                    oldValueText = oldValueText.substring(0, 250);
+                }
+            }
+            entityAuditLog.set("oldValueText", oldValueText);
+        }
+
+        if (!isRemove) {
+            String newValueText = null;
+            Object newValue = value.get(mf.getName());
+            if (newValue != null) {
+                newValueText = newValue.toString();
+                if (newValueText.length() > 250) {
+                    newValueText = newValueText.substring(0, 250);
+                }
+            }
+            entityAuditLog.set("newValueText", newValueText);
+        }
+
+        entityAuditLog.set("changedDate", UtilDateTime.nowTimestamp());
+        entityAuditLog.set("changedByInfo", this.userIdentifier);
+        entityAuditLog.set("changedSessionInfo", this.sessionIdentifier);
+
+        this.create(entityAuditLog);
+    }
+
+    public GenericValue createOrStore(GenericValue value) throws GenericEntityException {
+        return createOrStore(value, true);
+    }
+
+    public GenericValue createOrStore(GenericValue value, boolean doCacheClear) throws GenericEntityException {
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            GenericValue checkValue = this.findOne(value.getEntityName(), value.getPrimaryKey(), false);
+            if (checkValue != null) {
+                this.store(value, doCacheClear);
+            } else {
+                this.create(value, doCacheClear);
+            }
+            if (value.lockEnabled()) {
+                this.refresh(value);
+            }
+
+            return value;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in createOrStore operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction.";
+            Debug.logError(e, errMsg, module);
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
+            }
+            // after rolling back, rethrow the exception
+            throw e;
+        } finally {
+            // only commit the transaction if we started one... this will throw
+            // an exception if it fails
+            TransactionUtil.commit(beganTransaction);
+        }
+    }
+
+    public GenericValue createSetNextSeqId(GenericValue value) throws GenericEntityException {
+        boolean doCacheClear = true;
+
+        GenericHelper helper = getEntityHelper(value.getEntityName());
+        // just make sure it is this delegator...
+        value.setDelegator(this);
+        // this will throw an IllegalArgumentException if the entity for the
+        // value does not have one pk field, or if it already has a value set
+        // for the one pk field
+        value.setNextSeqId();
+
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(value.getEntityName());
+            ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE, EntityEcaHandler.OP_CREATE, value, false);
+
+            if (value == null) {
+                throw new GenericEntityException("Cannot create a null value");
+            }
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_CREATE, value, false);
+
+            value.setDelegator(this);
+            this.encryptFields(value);
+
+            // if audit log on for any fields, save new value with no old value
+            // because it's a create
+            if (value != null && value.getModelEntity().getHasFieldWithAuditLog()) {
+                createEntityAuditLogAll(value, false, false);
+            }
+
+            try {
+                value = helper.create(value);
+
+                if (testMode) {
+                    storeForTestRollback(new TestOperation(OperationType.INSERT, value));
+                }
+            } catch (GenericEntityException e) {
+                // see if this was caused by an existing record before resetting
+                // the sequencer and trying again
+                // NOTE: use the helper directly so ECA rules, etc won't be run
+                GenericValue existingValue = helper.findByPrimaryKey(value.getPrimaryKey());
+                if (existingValue == null) {
+                    throw e;
+                } else {
+                    Debug.logInfo("Error creating entity record with a sequenced value [" + value.getPrimaryKey() + "], trying again about to refresh bank for entity [" + value.getEntityName() + "]", module);
+
+                    // found an existing value... was probably a duplicate key,
+                    // so clean things up and try again
+                    this.delegatorData.sequencer.forceBankRefresh(value.getEntityName(), 1);
+
+                    value.setNextSeqId();
+                    value = helper.create(value);
+                    Debug.logInfo("Successfully created new entity record on retry with a sequenced value [" + value.getPrimaryKey() + "], after getting refreshed bank for entity [" + value.getEntityName() + "]", module);
+
+                    if (testMode) {
+                        storeForTestRollback(new TestOperation(OperationType.INSERT, value));
+                    }
+                }
+            }
+
+            if (value != null) {
+                value.setDelegator(this);
+                if (value.lockEnabled()) {
+                    refresh(value, doCacheClear);
+                } else {
+                    if (doCacheClear) {
+                        ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR, EntityEcaHandler.OP_CREATE, value, false);
+                        this.clearCacheLine(value);
+                    }
+                }
+            }
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_CREATE, value, false);
+
+            return value;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in create operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction.";
+            Debug.logError(e, errMsg, module);
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
+            }
+            // after rolling back, rethrow the exception
+            throw e;
+        } finally {
+            // only commit the transaction if we started one... this will throw
+            // an exception if it fails
+            TransactionUtil.commit(beganTransaction);
+        }
+    }
+
+    public GenericValue createSingle(String entityName, Object singlePkValue) throws GenericEntityException {
+        if (entityName == null || singlePkValue == null) {
+            return null;
+        }
+        ModelEntity entity = this.getModelReader().getModelEntity(entityName);
+        GenericValue genericValue = GenericValue.create(entity, singlePkValue);
+
+        return this.create(genericValue, true);
+    }
+
+    public void decryptFields(GenericEntity entity) throws GenericEntityException {
+        ModelEntity model = entity.getModelEntity();
+        String entityName = model.getEntityName();
+
+        Iterator<ModelField> i = model.getFieldsIterator();
+        while (i.hasNext()) {
+            ModelField field = i.next();
+            if (field.getEncrypt()) {
+                String keyName = entityName;
+                if (model instanceof ModelViewEntity) {
+                    ModelViewEntity modelView = (ModelViewEntity) model;
+                    keyName = modelView.getAliasedEntity(modelView.getAlias(field.getName()).getEntityAlias(), this.delegatorData.modelReader).getEntityName();
+                }
+
+                String encHex = (String) entity.get(field.getName());
+                if (UtilValidate.isNotEmpty(encHex)) {
+                    try {
+                        entity.dangerousSetNoCheckButFast(field, this.delegatorData.crypto.decrypt(keyName, encHex));
+                    } catch (EntityCryptoException e) {
+                        // not fatal -- allow returning of the encrypted value
+                        Debug.logWarning(e, "Problem decrypting field [" + entityName + " / " + field.getName() + "]", module);
+                    }
+                }
+            }
+        }
+    }
+
+    public void decryptFields(List<? extends GenericEntity> entities) throws GenericEntityException {
+        if (entities != null) {
+            for (GenericEntity entity : entities) {
+                this.decryptFields(entity);
+            }
+        }
+    }
+
+    public void encryptFields(GenericEntity entity) throws GenericEntityException {
+        ModelEntity model = entity.getModelEntity();
+        String entityName = model.getEntityName();
+
+        Iterator<ModelField> i = model.getFieldsIterator();
+        while (i.hasNext()) {
+            ModelField field = i.next();
+            if (field.getEncrypt()) {
+                Object obj = entity.get(field.getName());
+                if (obj != null) {
+                    if (obj instanceof String && UtilValidate.isEmpty((String) obj)) {
+                        continue;
+                    }
+                    entity.dangerousSetNoCheckButFast(field, this.encryptFieldValue(entityName, obj));
+                }
+            }
+        }
+    }
+
+    public void encryptFields(List<? extends GenericEntity> entities) throws GenericEntityException {
+        if (entities != null) {
+            for (GenericEntity entity : entities) {
+                this.encryptFields(entity);
+            }
+        }
+    }
+
+    public Object encryptFieldValue(String entityName, Object fieldValue) throws EntityCryptoException {
+        if (fieldValue != null) {
+            if (fieldValue instanceof String && UtilValidate.isEmpty((String) fieldValue)) {
+                return fieldValue;
+            }
+            return this.delegatorData.crypto.encrypt(entityName, fieldValue);
+        }
+        return fieldValue;
+    }
+
+    public EntityListIterator find(String entityName, EntityCondition whereEntityCondition, EntityCondition havingEntityCondition, Set<String> fieldsToSelect, List<String> orderBy, EntityFindOptions findOptions) throws GenericEntityException {
+
+        // if there is no transaction throw an exception, we don't want to
+        // create a transaction here since closing it would mess up the ELI
+        if (!TransactionUtil.isTransactionInPlace()) {
+            // throw new GenericEntityException("ERROR: Cannot do a find that
+            // returns an EntityListIterator with no transaction in place. Wrap
+            // this call in a transaction.");
+
+            // throwing an exception is a little harsh for now, just display a
+            // really big error message since we want to get all of these
+            // fixed...
+            Exception newE = new Exception("Stack Trace");
+            Debug.logError(newE, "ERROR: Cannot do a find that returns an EntityListIterator with no transaction in place. Wrap this call in a transaction.", module);
+        }
+
+        ModelEntity modelEntity = getModelReader().getModelEntity(entityName);
+        GenericValue dummyValue = GenericValue.create(modelEntity);
+        EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(modelEntity.getEntityName());
+        ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE, EntityEcaHandler.OP_FIND, dummyValue, false);
+
+        if (whereEntityCondition != null) {
+            whereEntityCondition.checkCondition(modelEntity);
+            whereEntityCondition.encryptConditionFields(modelEntity, this);
+        }
+        if (havingEntityCondition != null) {
+            havingEntityCondition.checkCondition(modelEntity);
+            havingEntityCondition.encryptConditionFields(modelEntity, this);
+        }
+
+        ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_FIND, dummyValue, false);
+        GenericHelper helper = getEntityHelper(modelEntity.getEntityName());
+        EntityListIterator eli = helper.findListIteratorByCondition(modelEntity, whereEntityCondition, havingEntityCondition, fieldsToSelect, orderBy, findOptions);
+        eli.setDelegator(this);
+
+        ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_FIND, dummyValue, false);
+        return eli;
+    }
+
+    public List<GenericValue> findAll(String entityName) throws GenericEntityException {
+        return this.findList(entityName, null, null, null, null, false);
+    }
+
+    public List<GenericValue> findAll(String entityName, List<String> orderBy) throws GenericEntityException {
+        return this.findList(entityName, null, null, orderBy, null, false);
+    }
+
+    public List<GenericValue> findAll(String entityName, String... orderBy) throws GenericEntityException {
+        return findList(entityName, null, null, Arrays.asList(orderBy), null, false);
+    }
+
+    public List<GenericValue> findAllByPrimaryKeys(Collection<GenericPK> primaryKeys) throws GenericEntityException {
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            // TODO: add eca eval calls
+            // TODO: maybe this should use the internal findBy methods
+            if (primaryKeys == null)
+                return null;
+            List<GenericValue> results = FastList.newInstance();
+
+            // from the delegator level this is complicated because different
+            // GenericPK
+            // objects in the list may correspond to different helpers
+            Map<String, List<GenericPK>> pksPerHelper = FastMap.newInstance();
+            for (GenericPK curPK : primaryKeys) {
+                String helperName = this.getEntityHelperName(curPK.getEntityName());
+                List<GenericPK> pks = pksPerHelper.get(helperName);
+
+                if (pks == null) {
+                    pks = FastList.newInstance();
+                    pksPerHelper.put(helperName, pks);
+                }
+                pks.add(curPK);
+            }
+
+            for (Map.Entry<String, List<GenericPK>> curEntry : pksPerHelper.entrySet()) {
+                String helperName = curEntry.getKey();
+                GenericHelper helper = GenericHelperFactory.getHelper(helperName);
+                List<GenericValue> values = helper.findAllByPrimaryKeys(curEntry.getValue());
+
+                results.addAll(values);
+            }
+
+            this.decryptFields(results);
+            return results;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in findAllByPrimaryKeys operation, rolling back transaction";
+            Debug.logError(e, errMsg, module);
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
+            }
+            // after rolling back, rethrow the exception
+            throw e;
+        } finally {
+            // only commit the transaction if we started one... this will throw
+            // an exception if it fails
+            TransactionUtil.commit(beganTransaction);
+        }
+    }
+
+    public List<GenericValue> findAllByPrimaryKeysCache(Collection<GenericPK> primaryKeys) throws GenericEntityException {
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            // TODO: add eca eval calls
+            // TODO: maybe this should use the internal findBy methods
+            if (primaryKeys == null)
+                return null;
+            List<GenericValue> results = FastList.newInstance();
+
+            // from the delegator level this is complicated because different
+            // GenericPK
+            // objects in the list may correspond to different helpers
+            Map<String, List<GenericPK>> pksPerHelper = FastMap.newInstance();
+            for (GenericPK curPK : primaryKeys) {
+                GenericValue value = this.getFromPrimaryKeyCache(curPK);
+
+                if (value != null) {
+                    // it is in the cache, so just put the cached value in the
+                    // results
+                    results.add(value);
+                } else {
+                    // is not in the cache, so put in a list for a call to the
+                    // helper
+                    String helperName = this.getEntityHelperName(curPK.getEntityName());
+                    List<GenericPK> pks = pksPerHelper.get(helperName);
+
+                    if (pks == null) {
+                        pks = FastList.newInstance();
+                        pksPerHelper.put(helperName, pks);
+                    }
+                    pks.add(curPK);
+                }
+            }
+
+            for (Map.Entry<String, List<GenericPK>> curEntry : pksPerHelper.entrySet()) {
+                String helperName = curEntry.getKey();
+                GenericHelper helper = GenericHelperFactory.getHelper(helperName);
+                List<GenericValue> values = helper.findAllByPrimaryKeys(curEntry.getValue());
+
+                this.putAllInPrimaryKeyCache(values);
+                results.addAll(values);
+            }
+
+            this.decryptFields(results);
+            return results;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in findAllByPrimaryKeysCache operation, rolling back transaction";
+            Debug.logError(e, errMsg, module);
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
+            }
+            // after rolling back, rethrow the exception
+            throw e;
+        } finally {
+            // only commit the transaction if we started one... this will throw
+            // an exception if it fails
+            TransactionUtil.commit(beganTransaction);
+        }
+    }
+
+    public List<GenericValue> findAllCache(String entityName) throws GenericEntityException {
+        return this.findList(entityName, null, null, null, null, true);
+    }
+
+    public List<GenericValue> findAllCache(String entityName, List<String> orderBy) throws GenericEntityException {
+        return this.findList(entityName, null, null, orderBy, null, true);
+    }
+
+    public List<GenericValue> findAllCache(String entityName, String... orderBy) throws GenericEntityException {
+        return findList(entityName, null, null, Arrays.asList(orderBy), null, true);
+    }
+
+    public <T extends EntityCondition> List<GenericValue> findByAnd(String entityName, List<T> expressions) throws GenericEntityException {
+        EntityConditionList<T> ecl = EntityCondition.makeCondition(expressions, EntityOperator.AND);
+        return this.findList(entityName, ecl, null, null, null, false);
+    }
+
+    public <T extends EntityCondition> List<GenericValue> findByAnd(String entityName, List<T> expressions, List<String> orderBy) throws GenericEntityException {
+        EntityConditionList<T> ecl = EntityCondition.makeCondition(expressions, EntityOperator.AND);
+        return this.findList(entityName, ecl, null, orderBy, null, false);
+    }
+
+    public List<GenericValue> findByAnd(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException {
+        EntityCondition ecl = EntityCondition.makeCondition(fields);
+        return this.findList(entityName, ecl, null, null, null, false);
+    }
+
+    public List<GenericValue> findByAnd(String entityName, Map<String, ? extends Object> fields, List<String> orderBy) throws GenericEntityException {
+        EntityCondition ecl = EntityCondition.makeCondition(fields);
+        return this.findList(entityName, ecl, null, orderBy, null, false);
+    }
+
+    public List<GenericValue> findByAnd(String entityName, Object... fields) throws GenericEntityException {
+        return findByAnd(entityName, UtilMisc.<String, Object> toMap(fields));
+    }
+
+    public <T extends EntityCondition> List<GenericValue> findByAnd(String entityName, T... expressions) throws GenericEntityException {
+        EntityConditionList<T> ecl = EntityCondition.makeCondition(EntityOperator.AND, expressions);
+        return this.findList(entityName, ecl, null, null, null, false);
+    }
+
+    public List<GenericValue> findByAndCache(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException {
+        return this.findList(entityName, EntityCondition.makeCondition(fields), null, null, null, true);
+    }
+
+    public List<GenericValue> findByAndCache(String entityName, Map<String, ? extends Object> fields, List<String> orderBy) throws GenericEntityException {
+        return this.findList(entityName, EntityCondition.makeCondition(fields), null, orderBy, null, true);
+    }
+
+    public List<GenericValue> findByAndCache(String entityName, Object... fields) throws GenericEntityException {
+        return this.findByAndCache(entityName, UtilMisc.<String, Object> toMap(fields));
+    }
+
+    public List<GenericValue> findByCondition(String entityName, EntityCondition entityCondition, Collection<String> fieldsToSelect, List<String> orderBy) throws GenericEntityException {
+        return this.findList(entityName, entityCondition, UtilMisc.toSet(fieldsToSelect), orderBy, null, false);
+    }
+
+    public List<GenericValue> findByCondition(String entityName, EntityCondition whereEntityCondition, EntityCondition havingEntityCondition, Collection<String> fieldsToSelect, List<String> orderBy, EntityFindOptions findOptions) throws GenericEntityException {
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            EntityListIterator eli = this.find(entityName, whereEntityCondition, havingEntityCondition, UtilMisc.toSet(fieldsToSelect), orderBy, findOptions);
+            eli.setDelegator(this);
+            List<GenericValue> list = eli.getCompleteList();
+            eli.close();
+
+            return list;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in findByCondition operation for entity [" + entityName + "]: " + e.toString() + ". Rolling back transaction.";
+            Debug.logError(e, errMsg, module);
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
+            }
+            // after rolling back, rethrow the exception
+            throw e;
+        } finally {
+            // only commit the transaction if we started one... this will throw
+            // an exception if it fails
+            TransactionUtil.commit(beganTransaction);
+        }
+    }
+
+    public List<GenericValue> findByConditionCache(String entityName, EntityCondition entityCondition, Collection<String> fieldsToSelect, List<String> orderBy) throws GenericEntityException {
+        return this.findList(entityName, entityCondition, UtilMisc.collectionToSet(fieldsToSelect), orderBy, null, true);
+    }
+
+    public List<GenericValue> findByLike(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException {
+        List<EntityExpr> likeExpressions = FastList.newInstance();
+        if (fields != null) {
+            for (Map.Entry<String, ? extends Object> fieldEntry : fields.entrySet()) {
+                likeExpressions.add(EntityCondition.makeCondition(fieldEntry.getKey(), EntityOperator.LIKE, fieldEntry.getValue()));
+            }
+        }
+        EntityConditionList<EntityExpr> ecl = EntityCondition.makeCondition(likeExpressions, EntityOperator.AND);
+        return this.findList(entityName, ecl, null, null, null, false);
+    }
+
+    public List<GenericValue> findByLike(String entityName, Map<String, ? extends Object> fields, List<String> orderBy) throws GenericEntityException {
+        List<EntityExpr> likeExpressions = FastList.newInstance();
+        if (fields != null) {
+            for (Map.Entry<String, ? extends Object> fieldEntry : fields.entrySet()) {
+                likeExpressions.add(EntityCondition.makeCondition(fieldEntry.getKey(), EntityOperator.LIKE, fieldEntry.getValue()));
+            }
+        }
+        EntityConditionList<EntityExpr> ecl = EntityCondition.makeCondition(likeExpressions, EntityOperator.AND);
+        return this.findList(entityName, ecl, null, orderBy, null, false);
+    }
+
+    public List<GenericValue> findByLike(String entityName, Object... fields) throws GenericEntityException {
+        Map<String, ? extends Object> fieldMap = UtilMisc.<String, Object> toMap(fields);
+        List<EntityExpr> likeExpressions = FastList.newInstance();
+        if (fieldMap != null) {
+            for (Map.Entry<String, ? extends Object> fieldEntry : fieldMap.entrySet()) {
+                likeExpressions.add(EntityCondition.makeCondition(fieldEntry.getKey(), EntityOperator.LIKE, fieldEntry.getValue()));
+            }
+        }
+        EntityConditionList<EntityExpr> ecl = EntityCondition.makeCondition(likeExpressions, EntityOperator.AND);
+        return this.findList(entityName, ecl, null, null, null, false);
+    }
+
+    public <T extends EntityCondition> List<GenericValue> findByOr(String entityName, List<T> expressions) throws GenericEntityException {
+        EntityConditionList<T> ecl = EntityCondition.makeCondition(expressions, EntityOperator.OR);
+        return this.findList(entityName, ecl, null, null, null, false);
+    }
+
+    public <T extends EntityCondition> List<GenericValue> findByOr(String entityName, List<T> expressions, List<String> orderBy) throws GenericEntityException {
+        EntityConditionList<T> ecl = EntityCondition.makeCondition(expressions, EntityOperator.OR);
+        return this.findList(entityName, ecl, null, orderBy, null, false);
+    }
+
+    public List<GenericValue> findByOr(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException {
+        EntityCondition ecl = EntityCondition.makeCondition(fields, EntityOperator.OR);
+        return this.findList(entityName, ecl, null, null, null, false);
+    }
+
+    public List<GenericValue> findByOr(String entityName, Map<String, ? extends Object> fields, List<String> orderBy) throws GenericEntityException {
+        EntityCondition ecl = EntityCondition.makeCondition(fields, EntityOperator.OR);
+        return this.findList(entityName, ecl, null, orderBy, null, false);
+    }
+
+    public List<GenericValue> findByOr(String entityName, Object... fields) throws GenericEntityException {
+        EntityCondition ecl = EntityCondition.makeCondition(EntityOperator.OR, fields);
+        return this.findList(entityName, ecl, null, null, null, false);
+    }
+
+    public <T extends EntityCondition> List<GenericValue> findByOr(String entityName, T... expressions) throws GenericEntityException {
+        return this.findList(entityName, EntityCondition.makeCondition(EntityOperator.AND, expressions), null, null, null, false);
+    }
+
+    public GenericValue findByPrimaryKey(GenericPK primaryKey) throws GenericEntityException {
+        return findOne(primaryKey.getEntityName(), primaryKey, false);
+    }
+
+    public GenericValue findByPrimaryKey(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException {
+        return findOne(entityName, fields, false);
+    }
+
+    public GenericValue findByPrimaryKey(String entityName, Object... fields) throws GenericEntityException {
+        return findByPrimaryKey(entityName, UtilMisc.<String, Object> toMap(fields));
+    }
+
+    public GenericValue findByPrimaryKeyCache(GenericPK primaryKey) throws GenericEntityException {
+        return findOne(primaryKey.getEntityName(), primaryKey, true);
+    }
+
+    public GenericValue findByPrimaryKeyCache(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException {
+        return findOne(entityName, fields, true);
+    }
+
+    public GenericValue findByPrimaryKeyCache(String entityName, Object... fields) throws GenericEntityException {
+        return findByPrimaryKeyCache(entityName, UtilMisc.<String, Object> toMap(fields));
+    }
+
+    public GenericValue findByPrimaryKeyCacheSingle(String entityName, Object singlePkValue) throws GenericEntityException {
+        return findOne(entityName, makePKSingle(entityName, singlePkValue), true);
+    }
+
+    public GenericValue findByPrimaryKeyPartial(GenericPK primaryKey, Set<String> keys) throws GenericEntityException {
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(primaryKey.getEntityName());
+            ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE, EntityEcaHandler.OP_FIND, primaryKey, false);
+
+            GenericHelper helper = getEntityHelper(primaryKey.getEntityName());
+            GenericValue value = null;
+
+            if (!primaryKey.isPrimaryKey()) {
+                throw new GenericModelException("[GenericDelegator.findByPrimaryKey] Passed primary key is not a valid primary key: " + primaryKey);
+            }
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_FIND, primaryKey, false);
+            try {
+                value = helper.findByPrimaryKeyPartial(primaryKey, keys);
+            } catch (GenericEntityNotFoundException e) {
+                value = null;
+            }
+            if (value != null)
+                value.setDelegator(this);
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_FIND, primaryKey, false);
+            return value;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in findByPrimaryKeyPartial operation for entity [" + primaryKey.getEntityName() + "]: " + e.toString() + ". Rolling back transaction.";
+            Debug.logError(e, errMsg, module);
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
+            }
+            // after rolling back, rethrow the exception
+            throw e;
+        } finally {
+            // only commit the transaction if we started one... this will throw
+            // an exception if it fails
+            TransactionUtil.commit(beganTransaction);
+        }
+    }
+
+    public GenericValue findByPrimaryKeyPartial(GenericPK primaryKey, String... keys) throws GenericEntityException {
+        return findByPrimaryKeyPartial(primaryKey, UtilMisc.makeSetWritable(Arrays.asList(keys)));
+    }
+
+    public GenericValue findByPrimaryKeySingle(String entityName, Object singlePkValue) throws GenericEntityException {
+        return findOne(entityName, makePKSingle(entityName, singlePkValue), false);
+    }
+
+    public long findCountByAnd(String entityName) throws GenericEntityException {
+        return findCountByCondition(entityName, null, null, null);
+    }
+
+    public long findCountByAnd(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException {
+        return findCountByCondition(entityName, EntityCondition.makeCondition(fields, EntityOperator.AND), null, null);
+    }
+
+    public long findCountByAnd(String entityName, Object... fields) throws GenericEntityException {
+        return findCountByCondition(entityName, EntityCondition.makeCondition(UtilMisc.<String, Object> toMap(fields), EntityOperator.AND), null, null);
+    }
+
+    public long findCountByCondition(String entityName, EntityCondition whereEntityCondition, EntityCondition havingEntityCondition) throws GenericEntityException {
+        return findCountByCondition(entityName, whereEntityCondition, havingEntityCondition, null);
+    }
+
+    public long findCountByCondition(String entityName, EntityCondition whereEntityCondition, EntityCondition havingEntityCondition, EntityFindOptions findOptions) throws GenericEntityException {
+
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            ModelEntity modelEntity = getModelReader().getModelEntity(entityName);
+            GenericValue dummyValue = GenericValue.create(modelEntity);
+            EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(modelEntity.getEntityName());
+            ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE, EntityEcaHandler.OP_FIND, dummyValue, false);
+
+            if (whereEntityCondition != null) {
+                whereEntityCondition.checkCondition(modelEntity);
+                whereEntityCondition.encryptConditionFields(modelEntity, this);
+            }
+            if (havingEntityCondition != null) {
+                havingEntityCondition.checkCondition(modelEntity);
+                havingEntityCondition.encryptConditionFields(modelEntity, this);
+            }
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_FIND, dummyValue, false);
+            GenericHelper helper = getEntityHelper(modelEntity.getEntityName());
+            long count = helper.findCountByCondition(modelEntity, whereEntityCondition, havingEntityCondition, findOptions);
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_FIND, dummyValue, false);
+            return count;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in findListIteratorByCondition operation for entity [DynamicView]: " + e.toString() + ". Rolling back transaction.";
+            Debug.logError(e, errMsg, module);
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
+            }
+            // after rolling back, rethrow the exception
+            throw e;
+        } finally {
+            // only commit the transaction if we started one... this will throw
+            // an exception if it fails
+            TransactionUtil.commit(beganTransaction);
+        }
+    }
+
+    public List<GenericValue> findList(String entityName, EntityCondition entityCondition, Set<String> fieldsToSelect, List<String> orderBy, EntityFindOptions findOptions, boolean useCache) throws GenericEntityException {
+
+        EntityEcaRuleRunner<?> ecaRunner = null;
+        GenericValue dummyValue = null;
+        if (useCache) {
+            ecaRunner = this.getEcaRuleRunner(entityName);
+            ModelEntity modelEntity = getModelReader().getModelEntity(entityName);
+            dummyValue = GenericValue.create(modelEntity);
+            ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CHECK, EntityEcaHandler.OP_FIND, dummyValue, false);
+
+            List<GenericValue> cacheList = this.delegatorData.cache.get(entityName, entityCondition, orderBy);
+            if (cacheList != null) {
+                return cacheList;
+            }
+        }
+
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            EntityListIterator eli = this.find(entityName, entityCondition, null, fieldsToSelect, orderBy, findOptions);
+            eli.setDelegator(this);
+            List<GenericValue> list = eli.getCompleteList();
+            eli.close();
+
+            if (useCache) {
+                ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_PUT, EntityEcaHandler.OP_FIND, dummyValue, false);
+                this.delegatorData.cache.put(entityName, entityCondition, orderBy, list);
+            }
+            return list;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in findByCondition operation for entity [" + entityName + "]: " + e.toString() + ". Rolling back transaction.";
+            Debug.logError(e, errMsg, module);
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
+            }
+            // after rolling back, rethrow the exception
+            throw e;
+        } finally {
+            // only commit the transaction if we started one... this will throw
+            // an exception if it fails
+            TransactionUtil.commit(beganTransaction);
+        }
+    }
+
+    public EntityListIterator findListIteratorByCondition(DynamicViewEntity dynamicViewEntity, EntityCondition whereEntityCondition, EntityCondition havingEntityCondition, Collection<String> fieldsToSelect, List<String> orderBy, EntityFindOptions findOptions) throws GenericEntityException {
+
+        // if there is no transaction throw an exception, we don't want to
+        // create a transaction here since closing it would mess up the ELI
+        if (!TransactionUtil.isTransactionInPlace()) {
+            // throw new GenericEntityException("ERROR: Cannot do a find that
+            // returns an EntityListIterator with no transaction in place. Wrap
+            // this call in a transaction.");
+
+            // throwing an exception is a little harsh for now, just display a
+            // really big error message since we want to get all of these
+            // fixed...
+            Exception newE = new Exception("Stack Trace");
+            Debug.logError(newE, "ERROR: Cannot do a find that returns an EntityListIterator with no transaction in place. Wrap this call in a transaction.", module);
+        }
+
+        ModelViewEntity modelViewEntity = dynamicViewEntity.makeModelViewEntity(this);
+        if (whereEntityCondition != null)
+            whereEntityCondition.checkCondition(modelViewEntity);
+        if (havingEntityCondition != null)
+            havingEntityCondition.checkCondition(modelViewEntity);
+
+        GenericHelper helper = getEntityHelper(dynamicViewEntity.getOneRealEntityName());
+        EntityListIterator eli = helper.findListIteratorByCondition(modelViewEntity, whereEntityCondition, havingEntityCondition, fieldsToSelect, orderBy, findOptions);
+        eli.setDelegator(this);
+        // TODO: add decrypt fields
+        return eli;
+    }
+
+    public EntityListIterator findListIteratorByCondition(String entityName, EntityCondition entityCondition, Collection<String> fieldsToSelect, List<String> orderBy) throws GenericEntityException {
+        return this.find(entityName, entityCondition, null, UtilMisc.collectionToSet(fieldsToSelect), orderBy, null);
+    }
+
+    public EntityListIterator findListIteratorByCondition(String entityName, EntityCondition whereEntityCondition, EntityCondition havingEntityCondition, Collection<String> fieldsToSelect, List<String> orderBy, EntityFindOptions findOptions) throws GenericEntityException {
+
+        return this.find(entityName, whereEntityCondition, havingEntityCondition, UtilMisc.collectionToSet(fieldsToSelect), orderBy, findOptions);
+    }
+
+    public GenericValue findOne(String entityName, boolean useCache, Object... fields) throws GenericEntityException {
+        return findOne(entityName, UtilMisc.toMap(fields), useCache);
+    }
+
+    public GenericValue findOne(String entityName, Map<String, ? extends Object> fields, boolean useCache) throws GenericEntityException {
+        GenericPK primaryKey = this.makePK(entityName, fields);
+        EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(entityName);
+        if (useCache) {
+            ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CHECK, EntityEcaHandler.OP_FIND, primaryKey, false);
+
+            GenericValue value = this.getFromPrimaryKeyCache(primaryKey);
+            if (value != null) {
+                return value;
+            }
+        }
+
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE, EntityEcaHandler.OP_FIND, primaryKey, false);
+
+            GenericHelper helper = getEntityHelper(entityName);
+            GenericValue value = null;
+
+            if (!primaryKey.isPrimaryKey()) {
+                throw new GenericModelException("[GenericDelegator.findOne] Passed primary key is not a valid primary key: " + primaryKey);
+            }
+            ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_FIND, primaryKey, false);
+            try {
+                value = helper.findByPrimaryKey(primaryKey);
+            } catch (GenericEntityNotFoundException e) {
+                value = null;
+            }
+            if (value != null) {
+                value.setDelegator(this);
+                this.decryptFields(value);
+            }
+
+            if (useCache) {
+                if (value != null) {
+                    ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_PUT, EntityEcaHandler.OP_FIND, value, false);
+                    this.putInPrimaryKeyCache(primaryKey, value);
+                } else {
+                    this.putInPrimaryKeyCache(primaryKey, GenericValue.NULL_VALUE);
+                }
+            }
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_FIND, (value == null ? primaryKey : value), false);
+            return value;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in findOne operation for entity [" + entityName + "]: " + e.toString() + ". Rolling back transaction.";
+            Debug.logError(e, errMsg, module);
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
+            }
+            // after rolling back, rethrow the exception
+            throw e;
+        } finally {
+            // only commit the transaction if we started one... this will throw
+            // an exception if it fails
+            TransactionUtil.commit(beganTransaction);
+        }
+    }
+
+    public Cache getCache() {
+        return this.delegatorData.cache;
+    }
+
+    public GenericDelegator getDelegator(String delegatorName) {
+        return DelegatorFactory.getGenericDelegator(delegatorName);
+    }
+
+    protected DelegatorInfo getDelegatorInfo() {
+        return this.delegatorData.delegatorInfo;
+    }
+
+    public String getDelegatorName() {
+        return this.delegatorData.delegatorName;
+    }
+
+    protected EntityEcaRuleRunner<?> getEcaRuleRunner(String entityName) {
+        if (this.testRollbackInProgress)
+            return createEntityEcaRuleRunner(null, null);
+        return createEntityEcaRuleRunner(this.delegatorData.entityEcaHandler, entityName);
+    }
+
+    @SuppressWarnings("unchecked")
+    public EntityEcaHandler getEntityEcaHandler() {
+        return this.delegatorData.entityEcaHandler;
+    }
+
+    public ModelFieldType getEntityFieldType(ModelEntity entity, String type) throws GenericEntityException {
+        return this.getModelFieldTypeReader(entity).getModelFieldType(type);
+    }
+
+    public Collection<String> getEntityFieldTypeNames(ModelEntity entity) throws GenericEntityException {
+        String helperName = getEntityHelperName(entity);
+
+        if (helperName == null || helperName.length() <= 0)
+            return null;
+        ModelFieldTypeReader modelFieldTypeReader = ModelFieldTypeReader.getModelFieldTypeReader(helperName);
+
+        if (modelFieldTypeReader == null) {
+            throw new GenericEntityException("ModelFieldTypeReader not found for entity " + entity.getEntityName() + " with helper name " + helperName);
+        }
+        return modelFieldTypeReader.getFieldTypeNames();
+    }
+
+    public String getEntityGroupName(String entityName) {
+        return getModelGroupReader().getEntityGroupName(entityName, getOriginalDelegatorName());
+    }
+
+    public GenericHelper getEntityHelper(ModelEntity entity) throws GenericEntityException {
+        return getEntityHelper(entity.getEntityName());
+    }
+
+    public GenericHelper getEntityHelper(String entityName) throws GenericEntityException {
+        String helperName = getEntityHelperName(entityName);
+
+        if (helperName != null && helperName.length() > 0) {
+            return GenericHelperFactory.getHelper(helperName);
+        } else {
+            throw new GenericEntityException("There is no datasource (Helper) configured for the entity-group [" + this.getEntityGroupName(entityName) + "]; was trying to find datesource (helper) for entity [" + entityName + "]");
+        }
+    }
+
+    public String getEntityHelperName(ModelEntity entity) {
+        if (entity == null)
+            return null;
+        return getEntityHelperName(entity.getEntityName());
+    }
+
+    public String getEntityHelperName(String entityName) {
+        return this.getGroupHelperName(this.getEntityGroupName(entityName));
+    }
+
+    public GenericValue getFromPrimaryKeyCache(GenericPK primaryKey) {
+        if (primaryKey == null)
+            return null;
+        GenericValue value = (GenericValue) this.delegatorData.cache.get(primaryKey);
+        if (value == GenericValue.NULL_VALUE) {
+            return null;
+        }
+        return value;
+    }
+
+    public String getGroupHelperName(String groupName) {
+        return this.getDelegatorInfo().groupMap.get(groupName);
+    }
+
+    public Locale getLocale() {
+        return this.locale;
+    }
+
+    public ModelEntity getModelEntity(String entityName) {
+        try {
+            return getModelReader().getModelEntity(entityName);
+        } catch (GenericEntityException e) {
+            Debug.logError(e, "Error getting entity definition from model", module);
+            return null;
+        }
+    }
+
+    public Map<String, ModelEntity> getModelEntityMapByGroup(String groupName) throws GenericEntityException {
+        Set<String> entityNameSet = getModelGroupReader().getEntityNamesByGroup(groupName);
+
+        if (this.getDelegatorInfo().defaultGroupName.equals(groupName)) {
+            // add all entities with no group name to the Set
+            Set<String> allEntityNames = this.getModelReader().getEntityNames();
+            for (String entityName : allEntityNames) {
+                if (this.getDelegatorInfo().defaultGroupName.equals(getModelGroupReader().getEntityGroupName(entityName, getDelegatorName()))) {
+                    entityNameSet.add(entityName);
+                }
+            }
+        }
+
+        Map<String, ModelEntity> entities = FastMap.newInstance();
+        if (entityNameSet == null || entityNameSet.size() == 0) {
+            return entities;
+        }
+
+        int errorCount = 0;
+        for (String entityName : entityNameSet) {
+            try {
+                ModelEntity entity = getModelReader().getModelEntity(entityName);
+                if (entity != null) {
+                    entities.put(entity.getEntityName(), entity);
+                } else {
+                    throw new IllegalStateException("Could not find entity with name " + entityName);
+                }
+            } catch (GenericEntityException ex) {
+                errorCount++;
+                Debug.logError("Entity [" + entityName + "] named in Entity Group with name " + groupName + " are not defined in any Entity Definition file", module);
+            }
+        }
+
+        if (errorCount > 0) {
+            Debug.logError(errorCount + " entities were named in ModelGroup but not defined in any EntityModel", module);
+        }
+
+        return entities;
+    }
+
+    public ModelFieldTypeReader getModelFieldTypeReader(ModelEntity entity) {
+        String helperName = getEntityHelperName(entity);
+        if (helperName == null || helperName.length() <= 0) {
+            return null;
+        }
+        ModelFieldTypeReader modelFieldTypeReader = ModelFieldTypeReader.getModelFieldTypeReader(helperName);
+        if (modelFieldTypeReader == null) {
+            throw new IllegalArgumentException("ModelFieldTypeReader not found for entity " + entity.getEntityName() + " with helper name " + helperName);
+        }
+        return modelFieldTypeReader;
+    }
+
+    public ModelGroupReader getModelGroupReader() {
+        return this.delegatorData.modelGroupReader;
+    }
+
+    public ModelReader getModelReader() {
+        return this.delegatorData.modelReader;
+    }
+
+    public List<GenericValue> getMultiRelation(GenericValue value, String relationNameOne, String relationNameTwo) throws GenericEntityException {
+        return getMultiRelation(value, relationNameOne, relationNameTwo, null);
+    }
+
+    public List<GenericValue> getMultiRelation(GenericValue value, String relationNameOne, String relationNameTwo, List<String> orderBy) throws GenericEntityException {
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+            // TODO: add eca eval calls
+            // traverse the relationships
+            ModelEntity modelEntity = value.getModelEntity();
+            ModelRelation modelRelationOne = modelEntity.getRelation(relationNameOne);
+            ModelEntity modelEntityOne = getModelEntity(modelRelationOne.getRelEntityName());
+            ModelRelation modelRelationTwo = modelEntityOne.getRelation(relationNameTwo);
+            ModelEntity modelEntityTwo = getModelEntity(modelRelationTwo.getRelEntityName());
+
+            GenericHelper helper = getEntityHelper(modelEntity);
+
+            return helper.findByMultiRelation(value, modelRelationOne, modelEntityOne, modelRelationTwo, modelEntityTwo, orderBy);
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in getMultiRelation operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction.";
+            Debug.logError(e, errMsg, module);
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
+            }
+            // after rolling back, rethrow the exception
+            throw e;
+        } finally {
+            // only commit the transaction if we started one...
+            // this will throw an exception if it fails
+            TransactionUtil.commit(beganTransaction);
+        }
+    }
+
+    public String getNextSeqId(String seqName) {
+        return this.getNextSeqId(seqName, 1);
+    }
+
+    public String getNextSeqId(String seqName, long staggerMax) {
+        Long nextSeqLong = this.getNextSeqIdLong(seqName, staggerMax);
+
+        if (nextSeqLong == null) {
+            // NOTE: the getNextSeqIdLong method SHOULD throw a runtime
+            // exception when no sequence value is found, which means we
+            // should never see it get here
+            throw new IllegalArgumentException("Could not get next sequenced ID for sequence name: " + seqName);
+        }
+
+        if (UtilValidate.isNotEmpty(this.getDelegatorInfo().sequencedIdPrefix)) {
+            return this.getDelegatorInfo().sequencedIdPrefix + nextSeqLong.toString();
+        } else {
+            return nextSeqLong.toString();
+        }
+    }
+
+    public Long getNextSeqIdLong(String seqName) {
+        return this.getNextSeqIdLong(seqName, 1);
+    }
+
+    public Long getNextSeqIdLong(String seqName, long staggerMax) {
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            if (this.delegatorData.sequencer == null) {
+                synchronized (this.delegatorData) {
+                    if (this.delegatorData.sequencer == null) {
+                        String helperName = this.getEntityHelperName("SequenceValueItem");
+                        ModelEntity seqEntity = this.getModelEntity("SequenceValueItem");
+                        this.delegatorData.sequencer = new SequenceUtil(helperName, seqEntity, "seqName", "seqId");
+                    }
+                }
+            }
+
+            // might be null, but will usually match the entity name
+            ModelEntity seqModelEntity = this.getModelEntity(seqName);
+
+            Long newSeqId = this.delegatorData.sequencer == null ? null : this.delegatorData.sequencer.getNextSeqId(seqName, staggerMax, seqModelEntity);
+
+            return newSeqId;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in getNextSeqIdLong operation for seqName [" + seqName + "]: " + e.toString() + ". Rolling back transaction.";
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
+            }
+            // rather than logging the problem and returning null, thus hiding the
+            // problem, throw an exception
+            throw new GeneralRuntimeException(errMsg, e);
+        } finally {
+            try {
+                // only commit the transaction if we started one...
+                TransactionUtil.commit(beganTransaction);
+            } catch (GenericTransactionException e1) {
+                Debug.logError(e1, "[GenericDelegator] Could not commit transaction: " + e1.toString(), module);
+            }
+        }
+    }
+
+    public String getOriginalDelegatorName() {
+        return this.delegatorData.originalDelegatorName == null ? this.delegatorData.delegatorName : this.delegatorData.originalDelegatorName;
+    }
+
+    @Deprecated
+    public List<GenericValue> getRelated(String relationName, GenericValue value) throws GenericEntityException {
+        return getRelated(relationName, null, null, value);
+    }
+
+    public List<GenericValue> getRelated(String relationName, Map<String, ? extends Object> byAndFields, List<String> orderBy, GenericValue value) throws GenericEntityException {
+        ModelEntity modelEntity = value.getModelEntity();
+        ModelRelation relation = modelEntity.getRelation(relationName);
+
+        if (relation == null) {
+            throw new GenericModelException("Could not find relation for relationName: " + relationName + " for value " + value);
+        }
+
+        // put the byAndFields (if not null) into the hash map first,
+        // they will be overridden by value's fields if over-specified
+        // this is important for security and cleanliness
+        Map<String, Object> fields = FastMap.newInstance();
+        if (byAndFields != null)
+            fields.putAll(byAndFields);
+        for (int i = 0; i < relation.getKeyMapsSize(); i++) {
+            ModelKeyMap keyMap = relation.getKeyMap(i);
+            fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName()));
+        }
+
+        return this.findByAnd(relation.getRelEntityName(), fields, orderBy);
+    }
+
+    public List<GenericValue> getRelatedByAnd(String relationName, Map<String, ? extends Object> byAndFields, GenericValue value) throws GenericEntityException {
+        return this.getRelated(relationName, byAndFields, null, value);
+    }
+
+    public List<GenericValue> getRelatedCache(String relationName, GenericValue value) throws GenericEntityException {
+        ModelEntity modelEntity = value.getModelEntity();
+        ModelRelation relation = modelEntity.getRelation(relationName);
+
+        if (relation == null) {
+            throw new GenericModelException("Could not find relation for relationName: " + relationName + " for value " + value);
+        }
+
+        Map<String, Object> fields = FastMap.newInstance();
+        for (int i = 0; i < relation.getKeyMapsSize(); i++) {
+            ModelKeyMap keyMap = relation.getKeyMap(i);
+            fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName()));
+        }
+
+        return this.findByAndCache(relation.getRelEntityName(), fields, null);
+    }
+
+    public GenericPK getRelatedDummyPK(String relationName, Map<String, ? extends Object> byAndFields, GenericValue value) throws GenericEntityException {
+        ModelEntity modelEntity = value.getModelEntity();
+        ModelRelation relation = modelEntity.getRelation(relationName);
+
+        if (relation == null) {
+            throw new GenericModelException("Could not find relation for relationName: " + relationName + " for value " + value);
+        }
+        ModelEntity relatedEntity = getModelReader().getModelEntity(relation.getRelEntityName());
+
+        // put the byAndFields (if not null) into the hash map first,
+        // they will be overridden by value's fields if
+        // over-specified this is important for security and
+        // cleanliness
+        Map<String, Object> fields = FastMap.newInstance();
+        if (byAndFields != null)
+            fields.putAll(byAndFields);
+        for (int i = 0; i < relation.getKeyMapsSize(); i++) {
+            ModelKeyMap keyMap = relation.getKeyMap(i);
+            fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName()));
+        }
+
+        GenericPK dummyPK = GenericPK.create(relatedEntity, fields);
+        dummyPK.setDelegator(this);
+        return dummyPK;
+    }
+
+    public GenericValue getRelatedOne(String relationName, GenericValue value) throws GenericEntityException {
+        ModelRelation relation = value.getModelEntity().getRelation(relationName);
+
+        if (relation == null) {
+            throw new GenericModelException("Could not find relation for relationName: " + relationName + " for value " + value);
+        }
+        if (!"one".equals(relation.getType()) && !"one-nofk".equals(relation.getType())) {
+            throw new GenericModelException("Relation is not a 'one' or a 'one-nofk' relation: " + relationName + " of entity " + value.getEntityName());
+        }
+
+        Map<String, Object> fields = FastMap.newInstance();
+        for (int i = 0; i < relation.getKeyMapsSize(); i++) {
+            ModelKeyMap keyMap = relation.getKeyMap(i);
+            fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName()));
+        }
+
+        return this.findByPrimaryKey(relation.getRelEntityName(), fields);
+    }
+
+    public GenericValue getRelatedOneCache(String relationName, GenericValue value) throws GenericEntityException {
+        ModelEntity modelEntity = value.getModelEntity();
+        ModelRelation relation = modelEntity.getRelation(relationName);
+
+        if (relation == null) {
+            throw new GenericModelException("Could not find relation for relationName: " + relationName + " for value " + value);
+        }
+        if (!"one".equals(relation.getType()) && !"one-nofk".equals(relation.getType())) {
+            throw new GenericModelException("Relation is not a 'one' or a 'one-nofk' relation: " + relationName + " of entity " + value.getEntityName());
+        }
+
+        Map<String, Object> fields = FastMap.newInstance();
+        for (int i = 0; i < relation.getKeyMapsSize(); i++) {
+            ModelKeyMap keyMap = relation.getKeyMap(i);
+            fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName()));
+        }
+
+        return this.findByPrimaryKeyCache(relation.getRelEntityName(), fields);
+    }
+
+    public List<GenericValue> getRelatedOrderBy(String relationName, List<String> orderBy, GenericValue value) throws GenericEntityException {
+        return this.getRelated(relationName, null, orderBy, value);
+    }
+
+    protected void initEntityEcaHandler() {
+        if (this.delegatorData.delegatorInfo.useEntityEca) {
+            ClassLoader loader = Thread.currentThread().getContextClassLoader();
+            // initialize the entity eca handler
+            String entityEcaHandlerClassName = this.delegatorData.delegatorInfo.entityEcaHandlerClassName;
+            try {
+                Class<?> eecahClass = loader.loadClass(entityEcaHandlerClassName);
+                this.delegatorData.entityEcaHandler = (EntityEcaHandler<?>) eecahClass.newInstance();
+                this.delegatorData.entityEcaHandler.setDelegator(this);
+            } catch (ClassNotFoundException e) {
+                Debug.logWarning(e, "EntityEcaHandler class with name " + entityEcaHandlerClassName + " was not found, Entity ECA Rules will be disabled", module);
+            } catch (InstantiationException e) {
+                Debug.logWarning(e, "EntityEcaHandler class with name " + entityEcaHandlerClassName + " could not be instantiated, Entity ECA Rules will be disabled", module);
+            } catch (IllegalAccessException e) {
+                Debug.logWarning(e, "EntityEcaHandler class with name " + entityEcaHandlerClassName + " could not be accessed (illegal), Entity ECA Rules will be disabled", module);
+            } catch (ClassCastException e) {
+                Debug.logWarning(e, "EntityEcaHandler class with name " + entityEcaHandlerClassName + " does not implement the EntityEcaHandler interface, Entity ECA Rules will be disabled", module);
+            }
+        } else {
+            Debug.logInfo("Entity ECA Handler disabled for delegator [" + this.delegatorData.delegatorName + "]", module);
+        }
+    }
+
+    public GenericPK makePK(Element element) {

[... 864 lines stripped ...]