svn commit: r812692 [2/3] - 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: r812692 [2/3] - 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
Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java?rev=812692&r1=812691&r2=812692&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java Tue Sep  8 20:56:14 2009
@@ -18,25 +18,58 @@
  */
 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.Locale;
+import java.util.ListIterator;
 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;
@@ -44,127 +77,618 @@
 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;
 
 /**
- * Delegator Interface
+ * Generic Data Source Delegator Class
+ *
  */
-public interface GenericDelegator {
+public class GenericDelegator implements DelegatorInterface {
 
-    public void clearAllCacheLinesByDummyPK(Collection<GenericPK> dummyPKs);
+    public static final String module = GenericDelegator.class.getName();
 
-    public void clearAllCacheLinesByValue(Collection<GenericValue> values);
+    protected ModelReader modelReader = null;
+    protected ModelGroupReader modelGroupReader = null;
 
-    /** This method is a shortcut to completely clear all entity engine caches.
-     * For performance reasons this should not be called very often.
+    /** 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;
+
+    /** the delegatorCache will now be a HashMap, allowing reload of definitions,
+     * but the delegator will always be the same object for the given name */
+    protected static Map<String, GenericDelegator> delegatorCache = FastMap.newInstance();
+    protected String delegatorName = null;
+    protected DelegatorInfo delegatorInfo = null;
+
+    protected Cache cache = null;
+
+    /** keeps a list of field key sets used in the by and cache, a Set (of Sets of fieldNames) for each entityName */
+    protected Map andCacheFieldSets = FastMap.newInstance();
+
+    protected DistributedCacheClear distributedCacheClear = null;
+    protected EntityEcaHandler<?> entityEcaHandler = null;
+    protected SequenceUtil sequencer = null;
+    protected EntityCrypto crypto = null;
+
+    /** A ThreadLocal variable to allow other methods to specify a user identifier (usually the userLoginId, though technically the Entity Engine doesn't know anything about the UserLogin entity) */
+    protected static ThreadLocal<List<Object>> userIdentifierStack = new ThreadLocal<List<Object>>();
+    /** A ThreadLocal variable to allow other methods to specify a session identifier (usually the visitId, though technically the Entity Engine doesn't know anything about the Visit entity) */
+    protected static ThreadLocal<List<Object>> sessionIdentifierStack = new ThreadLocal<List<Object>>();
+
+    private boolean testMode = false;
+    private boolean testRollbackInProgress = false;
+    private List<TestOperation> testOperations = null;
+    private enum OperationType {INSERT, UPDATE, DELETE};
+    
+    private String originalDelegatorName = null;
+
+
+    public static GenericDelegator getGenericDelegator(String delegatorName) {
+        if (delegatorName == null) {
+            delegatorName = "default";
+            Debug.logWarning(new Exception("Location where getting delegator with null name"), "Got a getGenericDelegator call with a null delegatorName, assuming default for the name.", module);
+        }
+        GenericDelegator delegator = delegatorCache.get(delegatorName);
+
+        if (delegator == null) {
+            synchronized (GenericDelegator.class) {
+                // must check if null again as one of the blocked threads can still enter
+                delegator = delegatorCache.get(delegatorName);
+                if (delegator == null) {
+                    if (Debug.infoOn()) Debug.logInfo("Creating new delegator [" + delegatorName + "] (" + Thread.currentThread().getName() + ")", module);
+                    //Debug.logInfo(new Exception(), "Showing stack where new delegator is being created...", module);
+                    try {
+                        delegator = new GenericDelegator(delegatorName);
+                    } catch (GenericEntityException e) {
+                        Debug.logError(e, "Error creating delegator", module);
+                    }
+                    if (delegator != null) {
+                        delegatorCache.put(delegatorName, delegator);
+                    } else {
+                        Debug.logError("Could not create delegator with name " + delegatorName + ", constructor failed (got null value) not sure why/how.", module);
+                    }
+                }
+            }
+        }
+        return delegator;
+    }
+
+    protected static List<Object> getUserIdentifierStack() {
+        List<Object> curValList = userIdentifierStack.get();
+        if (curValList == null) {
+            curValList = FastList.newInstance();
+            userIdentifierStack.set(curValList);
+        }
+        return curValList;
+    }
+
+    public static String getCurrentUserIdentifier() {
+        List<Object> curValList = getUserIdentifierStack();
+        Object curVal = curValList.size() > 0 ? curValList.get(0) : null;
+        if (curVal == null) {
+            return null;
+        } else {
+            return curVal.toString();
+        }
+    }
+
+    public static void pushUserIdentifier(String userIdentifier) {
+        if (userIdentifier == null) {
+            return;
+        }
+        List<Object> curValList = getUserIdentifierStack();
+        curValList.add(0, userIdentifier);
+    }
+
+    public static String popUserIdentifier() {
+        List<Object> curValList = getUserIdentifierStack();
+        if (curValList.size() == 0) {
+            return null;
+        } else {
+            return (String) curValList.remove(0);
+        }
+    }
+
+    public static void clearUserIdentifierStack() {
+        List<Object> curValList = getUserIdentifierStack();
+        curValList.clear();
+    }
+
+    protected static List<Object> getSessionIdentifierStack() {
+        List<Object> curValList = sessionIdentifierStack.get();
+        if (curValList == null) {
+            curValList = FastList.newInstance();
+            sessionIdentifierStack.set(curValList);
+        }
+        return curValList;
+    }
+
+    public static String getCurrentSessionIdentifier() {
+        List<Object> curValList = getSessionIdentifierStack();
+        Object curVal = curValList.size() > 0 ? curValList.get(0) : null;
+        if (curVal == null) {
+            return null;
+        } else {
+            return curVal.toString();
+        }
+    }
+
+    public static void pushSessionIdentifier(String sessionIdentifier) {
+        if (sessionIdentifier == null) {
+            return;
+        }
+        List<Object> curValList = getSessionIdentifierStack();
+        curValList.add(0, sessionIdentifier);
+    }
+
+    public static String popSessionIdentifier() {
+        List<Object> curValList = getSessionIdentifierStack();
+        if (curValList.size() == 0) {
+            return null;
+        } else {
+            return (String) curValList.remove(0);
+        }
+    }
+
+    public static void clearSessionIdentifierStack() {
+        List<Object> curValList = getSessionIdentifierStack();
+        curValList.clear();
+    }
+
+    /** Only allow creation through the factory method */
+    protected GenericDelegator() {}
+
+    /** Only allow creation through the factory method */
+    protected GenericDelegator(String delegatorName) throws GenericEntityException {
+        //if (Debug.infoOn()) Debug.logInfo("Creating new Delegator with name \"" + delegatorName + "\".", module);
+
+        this.delegatorName = delegatorName;
+        this.modelReader = ModelReader.getModelReader(delegatorName);
+        this.modelGroupReader = ModelGroupReader.getModelGroupReader(delegatorName);
+
+        cache = new Cache(delegatorName);
+
+        // do the entity model check
+        List<String> warningList = FastList.newInstance();
+        Debug.logImportant("Doing entity definition check...", module);
+        ModelEntityChecker.checkEntities(this, warningList);
+        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(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 \"" + 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);
+                    }
+                }
+            }
+        }
+
+        // NOTE: doing some things before the ECAs and such to make sure it is in place just in case it is used in a service engine startup thing or something
+        // put the delegator in the master Map by its name
+        GenericDelegator.delegatorCache.put(delegatorName, this);
+
+        // setup the crypto class
+        this.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 (getDelegatorInfo().useDistributedCacheClear) {
+            // initialize the distributedCacheClear mechanism
+            String distributedCacheClearClassName = getDelegatorInfo().distributedCacheClearClassName;
+
+            try {
+                Class dccClass = loader.loadClass(distributedCacheClearClassName);
+                this.distributedCacheClear = (DistributedCacheClear) dccClass.newInstance();
+                this.distributedCacheClear.setDelegator(this, getDelegatorInfo().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 [" + delegatorName + "]", module);
+        }
+
+        // setup the Entity ECA Handler
+        initEntityEcaHandler();
+    }
+
+    public void initEntityEcaHandler() {
+        if (getDelegatorInfo().useEntityEca) {
+            ClassLoader loader = Thread.currentThread().getContextClassLoader();
+            // initialize the entity eca handler
+            String entityEcaHandlerClassName = getDelegatorInfo().entityEcaHandlerClassName;
+
+            try {
+                Class eecahClass = loader.loadClass(entityEcaHandlerClassName);
+                this.entityEcaHandler = (EntityEcaHandler) eecahClass.newInstance();
+                this.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 [" + delegatorName + "]", module);
+        }
+    }
+
+    public String getDelegatorName() {
+        return this.delegatorName;
+    }
+    
+    /** Gets the name of the server configuration that corresponds to this delegator
+     * @return server configuration name
      */
-    public void clearAllCaches();
+    public String getOriginalDelegatorName() {
+        return this.originalDelegatorName == null ? this.delegatorName : this.originalDelegatorName;
+    }
+
+    protected DelegatorInfo getDelegatorInfo() {
+        if (this.delegatorInfo == null) {
+            this.delegatorInfo = EntityConfigUtil.getDelegatorInfo(this.delegatorName);
+        }
+        return this.delegatorInfo;
+    }
 
-    public void clearAllCaches(boolean distribute);
+    /** Gets the instance of ModelReader that corresponds to this delegator
+     *@return ModelReader that corresponds to this delegator
+     */
+    public ModelReader getModelReader() {
+        return this.modelReader;
+    }
 
-    /** Remove a CACHED Generic Entity from the cache by its primary key, does NOT
-     * check to see if the passed GenericPK is a complete primary key.
-     * Also tries to clear the corresponding all cache entry.
-     *@param primaryKey The primary key to clear by.
+    /** Gets the instance of ModelGroupReader that corresponds to this delegator
+     *@return ModelGroupReader that corresponds to this delegator
      */
-    public void clearCacheLine(GenericPK primaryKey);
+    public ModelGroupReader getModelGroupReader() {
+        return this.modelGroupReader;
+    }
 
-    public void clearCacheLine(GenericPK primaryKey, boolean distribute);
+    /** Gets the instance of ModelEntity that corresponds to this delegator and the specified entityName
+     *@param entityName The name of the entity to get
+     *@return ModelEntity that corresponds to this delegator and the specified entityName
+     */
+    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;
+        }
+    }
 
-    /** Remove a CACHED GenericValue from as many caches as it can. Automatically
-     * tries to remove entries from the all cache, the by primary key cache, and
-     * the by and cache. This is the ONLY method that tries to clear automatically
-     * from the by and cache.
-     *@param value The GenericValue to clear by.
+    /** Gets the helper name that corresponds to this delegator and the specified entityName
+     *@param entityName The name of the entity to get the helper for
+     *@return String with the helper name that corresponds to this delegator and the specified entityName
      */
-    public void clearCacheLine(GenericValue value);
+    public String getEntityGroupName(String entityName) {
+        return getModelGroupReader().getEntityGroupName(entityName, getOriginalDelegatorName());
+    }
 
-    public void clearCacheLine(GenericValue value, boolean distribute);
+    /** Gets a Map of entity name & entity model pairs that are in the named group
+     *@param groupName The name of the group
+     *@return Map of entityName String keys and ModelEntity instance values
+     */
+    public Map<String, ModelEntity> getModelEntityMapByGroup(String groupName) throws GenericEntityException {
+        Set<String> entityNameSet = getModelGroupReader().getEntityNamesByGroup(groupName);
 
-    /** Remove all CACHED Generic Entity (List) from the cache
-     *@param entityName The Name of the Entity as defined in the entity XML file
+        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;
+    }
+
+    /** Gets the helper name that corresponds to this delegator and the specified entityName
+     *@param groupName The name of the group to get the helper name for
+     *@return String with the helper name that corresponds to this delegator and the specified entityName
      */
-    public void clearCacheLine(String entityName);
+    public String getGroupHelperName(String groupName) {
+        return this.getDelegatorInfo().groupMap.get(groupName);
+    }
 
-    /** Remove a CACHED Generic Entity (List) from the cache, either a PK, ByAnd, or All
-     *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param fields The fields of the named entity to query by with their corresponding values
+    /** Gets the helper name that corresponds to this delegator and the specified entityName
+     *@param entityName The name of the entity to get the helper name for
+     *@return String with the helper name that corresponds to this delegator and the specified entityName
      */
-    public void clearCacheLine(String entityName, Map<String, ? extends Object> fields);
+    public String getEntityHelperName(String entityName) {
+        return this.getGroupHelperName(this.getEntityGroupName(entityName));
+    }
 
-    /** Remove a CACHED Generic Entity (List) from the cache, either a PK, ByAnd, or All
-     *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param fields The fields of the named entity to query by with their corresponding values
+    /** Gets the helper name that corresponds to this delegator and the specified entity
+     *@param entity The entity to get the helper for
+     *@return String with the helper name that corresponds to this delegator and the specified entity
      */
-    public void clearCacheLine(String entityName, Object... fields);
+    public String getEntityHelperName(ModelEntity entity) {
+        if (entity == null)
+            return null;
+        return getEntityHelperName(entity.getEntityName());
+    }
 
-    public void clearCacheLineByCondition(String entityName, EntityCondition condition);
+    /** Gets the an instance of helper that corresponds to this delegator and the specified entityName
+     *@param entityName The name of the entity to get the helper for
+     *@return GenericHelper that corresponds to this delegator and the specified entityName
+     */
+    public GenericHelper getEntityHelper(String entityName) throws GenericEntityException {
+        String helperName = getEntityHelperName(entityName);
 
-    public void clearCacheLineByCondition(String entityName, EntityCondition condition, boolean distribute);
+        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 + "]");
+        }
+    }
 
-    /** Remove a CACHED Generic Entity from the cache by its primary key.
-     * Checks to see if the passed GenericPK is a complete primary key, if
-     * it is then the cache line will be removed from the primaryKeyCache; if it
-     * is NOT a complete primary key it will remove the cache line from the andCache.
-     * If the fields map is empty, then the allCache for the entity will be cleared.
-     *@param dummyPK The dummy primary key to clear by.
+    /** Gets the an instance of helper that corresponds to this delegator and the specified entity
+     *@param entity The entity to get the helper for
+     *@return GenericHelper that corresponds to this delegator and the specified entity
+     */
+    public GenericHelper getEntityHelper(ModelEntity entity) throws GenericEntityException {
+        return getEntityHelper(entity.getEntityName());
+    }
+
+    /** Gets a field type instance by name from the helper that corresponds to the specified entity
+     *@param entity The entity
+     *@param type The name of the type
+     *@return ModelFieldType instance for the named type from the helper that corresponds to the specified entity
+     */
+    public ModelFieldType getEntityFieldType(ModelEntity entity, String type) throws GenericEntityException {
+        return this.getModelFieldTypeReader(entity).getModelFieldType(type);
+    }
+    
+    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;
+    }
+
+    /** Gets field type names from the helper that corresponds to the specified entity
+     *@param entity The entity
+     *@return Collection of field type names from the helper that corresponds to the specified entity
      */
-    public void clearCacheLineFlexible(GenericEntity dummyPK);
+    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();
+    }
+
+    /** Creates a Entity in the form of a GenericValue without persisting it */
+    public GenericValue makeValue(String entityName) {
+        ModelEntity entity = this.getModelEntity(entityName);
+        if (entity == null) {
+            throw new IllegalArgumentException("[GenericDelegator.makeValue] could not find entity for entityName: " + entityName);
+        }
+        GenericValue value = GenericValue.create(entity);
+        value.setDelegator(this);
+        return value;
+    }
+
+    /** Creates a Entity in the form of a GenericValue without persisting it */
+    public GenericValue makeValue(String entityName, Object... fields) {
+        return makeValue(entityName, UtilMisc.<String, Object>toMap(fields));
+    }
+
+    /** Creates a Entity in the form of a GenericValue without persisting it */
+    public GenericValue makeValue(String entityName, Map<String, ? extends Object> fields) {
+        ModelEntity entity = this.getModelEntity(entityName);
+        if (entity == null) {
+            throw new IllegalArgumentException("[GenericDelegator.makeValue] could not find entity for entityName: " + entityName);
+        }
+        GenericValue value = GenericValue.create(entity, fields);
+        value.setDelegator(this);
+        return value;
+    }
 
-    public void clearCacheLineFlexible(GenericEntity dummyPK, boolean distribute);
+    /** Creates a Entity in the form of a GenericValue without persisting it */
+    public GenericValue makeValueSingle(String entityName, Object singlePkValue) {
+        ModelEntity entity = this.getModelEntity(entityName);
+        if (entity == null) {
+            throw new IllegalArgumentException("[GenericDelegator.makeValue] could not find entity for entityName: " + entityName);
+        }
+        GenericValue value = GenericValue.create(entity, singlePkValue);
+        value.setDelegator(this);
+        return value;
+    }
+
+    /** Creates a Entity in the form of a GenericValue without persisting it; only valid fields will be pulled from the fields Map */
+    public GenericValue makeValidValue(String entityName, Object... fields) {
+        return makeValidValue(entityName, UtilMisc.<String, Object>toMap(fields));
+    }
+
+    /** Creates a Entity in the form of a GenericValue without persisting it; only valid fields will be pulled from the fields Map */
+    public GenericValue makeValidValue(String entityName, Map<String, ? extends Object> fields) {
+        ModelEntity entity = this.getModelEntity(entityName);
+        if (entity == null) {
+            throw new IllegalArgumentException("[GenericDelegator.makeValidValue] could not find entity for entityName: " + entityName);
+        }
+        GenericValue value = GenericValue.create(entity);
+        value.setPKFields(fields, true);
+        value.setNonPKFields(fields, true);
+        value.setDelegator(this);
+        return value;
+    }
+
+    /** Creates a Primary Key in the form of a GenericPK without persisting it */
+    public GenericPK makePK(String entityName) {
+        return this.makePK(entityName, (Map<String, Object>) null);
+    }
+
+    /** Creates a Primary Key in the form of a GenericPK without persisting it */
+    public GenericPK makePK(String entityName, Object... fields) {
+        return makePK(entityName, UtilMisc.<String, Object>toMap(fields));
+    }
 
-    public GenericDelegator cloneDelegator();
+    /** Creates a Primary Key in the form of a GenericPK without persisting it */
+    public GenericPK makePK(String entityName, Map<String, ? extends Object> fields) {
+        ModelEntity entity = this.getModelEntity(entityName);
+        if (entity == null) {
+            throw new IllegalArgumentException("[GenericDelegator.makePK] could not find entity for entityName: " + entityName);
+        }
+        GenericPK pk = GenericPK.create(entity, fields);
+
+        pk.setDelegator(this);
+        return pk;
+    }
 
-    public GenericDelegator cloneDelegator(String delegatorName);
+    /** Creates a Primary Key in the form of a GenericPK without persisting it */
+    public GenericPK makePKSingle(String entityName, Object singlePkValue) {
+        ModelEntity entity = this.getModelEntity(entityName);
+        if (entity == null) {
+            throw new IllegalArgumentException("[GenericDelegator.makePKSingle] could not find entity for entityName: " + entityName);
+        }
+        GenericPK pk = GenericPK.create(entity, singlePkValue);
+
+        pk.setDelegator(this);
+        return pk;
+    }
 
     /** Creates a Entity in the form of a GenericValue and write it to the datasource
      *@param primaryKey The GenericPK to create a value in the datasource from
      *@return GenericValue instance containing the new instance
      */
-    public GenericValue create(GenericPK primaryKey) throws GenericEntityException;
+    public GenericValue create(GenericPK primaryKey) throws GenericEntityException {
+        return this.create(primaryKey, true);
+    }
 
     /** Creates a Entity in the form of a GenericValue and write it to the datasource
      *@param primaryKey The GenericPK to create a value in the datasource from
      *@param doCacheClear boolean that specifies whether to clear related cache entries for this primaryKey to be created
      *@return GenericValue instance containing the new instance
      */
-    public GenericValue create(GenericPK primaryKey, boolean doCacheClear) throws GenericEntityException;
+    public GenericValue create(GenericPK primaryKey, boolean doCacheClear) throws GenericEntityException {
+        if (primaryKey == null) {
+            throw new GenericEntityException("Cannot create from a null primaryKey");
+        }
 
-    /** Creates a Entity in the form of a GenericValue and write it to the datasource
-     *@param value The GenericValue to create a value in the datasource from
-     *@return GenericValue instance containing the new instance
-     */
-    public GenericValue create(GenericValue value) throws GenericEntityException;
+        return this.create(GenericValue.create(primaryKey), doCacheClear);
+    }
 
-    /** Creates a Entity in the form of a GenericValue and write it to the datasource
-     *@param value The GenericValue to create a value in the datasource from
-     *@param doCacheClear boolean that specifies whether or not to automatically clear cache entries related to this operation
+    /** Creates a Entity in the form of a GenericValue and write it to the database
      *@return GenericValue instance containing the new instance
      */
-    public GenericValue create(GenericValue value, boolean doCacheClear) throws GenericEntityException;
+    public GenericValue create(String entityName, Object... fields) throws GenericEntityException {
+        return create(entityName, UtilMisc.<String, Object>toMap(fields));
+    }
 
     /** Creates a Entity in the form of a GenericValue and write it to the database
      *@return GenericValue instance containing the new instance
      */
-    public GenericValue create(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException;
+    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);
+    }
 
     /** Creates a Entity in the form of a GenericValue and write it to the database
      *@return GenericValue instance containing the new instance
      */
-    public GenericValue create(String entityName, Object... fields) throws GenericEntityException;
+    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);
 
-    /** Creates or stores an Entity
-     *@param value The GenericValue instance containing the new or existing instance
-     *@return GenericValue instance containing the new or updated instance
-     */
-    public GenericValue createOrStore(GenericValue value) throws GenericEntityException;
+        return this.create(genericValue, true);
+    }
 
-    /** Creates or stores an Entity
-     *@param value The GenericValue instance containing the new or existing instance
-     *@param doCacheClear boolean that specifies whether or not to automatically clear cache entries related to this operation
-     *@return GenericValue instance containing the new or updated instance
+    /** Creates a Entity in the form of a GenericValue and write it to the datasource
+     *@param value The GenericValue to create a value in the datasource from
+     *@return GenericValue instance containing the new instance
      */
-    public GenericValue createOrStore(GenericValue value, boolean doCacheClear) throws GenericEntityException;
+    public GenericValue create(GenericValue value) throws GenericEntityException {
+        return this.create(value, true);
+    }
 
     /** Sets the sequenced ID (for entity with one primary key field ONLY), and then does a create in the database
      * as normal. The reason to do it this way is that it will retry and fix the sequence if somehow the sequencer
@@ -172,320 +696,958 @@
      *@param value The GenericValue to create a value in the datasource from
      *@return GenericValue instance containing the new instance
      */
-    public GenericValue createSetNextSeqId(GenericValue value) throws GenericEntityException;
+    public GenericValue createSetNextSeqId(GenericValue value) throws GenericEntityException {
+        boolean doCacheClear = true;
 
-    /** Creates a Entity in the form of a GenericValue and write it to the database
+        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.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);
+        }
+    }
+
+    /** Creates a Entity in the form of a GenericValue and write it to the datasource
+     *@param value The GenericValue to create a value in the datasource from
+     *@param doCacheClear boolean that specifies whether or not to automatically clear cache entries related to this operation
      *@return GenericValue instance containing the new instance
      */
-    public GenericValue createSingle(String entityName, Object singlePkValue) throws GenericEntityException;
-
-    public void decryptFields(GenericEntity entity) throws GenericEntityException;
-
-    public void decryptFields(List<? extends GenericEntity> entities) throws GenericEntityException;
-
-    public void encryptFields(GenericEntity entity) throws GenericEntityException;
-
-    public void encryptFields(List<? extends GenericEntity> entities) throws GenericEntityException;
+    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 Object encryptFieldValue(String entityName, Object fieldValue) throws EntityCryptoException;
+    /** Creates or stores an Entity
+     *@param value The GenericValue instance containing the new or existing instance
+     *@param doCacheClear boolean that specifies whether or not to automatically clear cache entries related to this operation
+     *@return GenericValue instance containing the new or updated instance
+     */
+    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);
+        }
+    }
 
-    /** Finds GenericValues by the conditions specified in the EntityCondition object, the the EntityCondition javadoc for more details.
-     * NOTE 20080502: 3 references
-     *@param entityName The name of the Entity as defined in the entity XML file
-     *@param whereEntityCondition The EntityCondition object that specifies how to constrain this query before any groupings are done (if this is a view entity with group-by aliases)
-     *@param havingEntityCondition The EntityCondition object that specifies how to constrain this query after any groupings are done (if this is a view entity with group-by aliases)
-     *@param fieldsToSelect The fields of the named entity to get from the database; if empty or null all fields will be retreived
-     *@param orderBy The fields of the named entity to order the query by; optionally add a " ASC" for ascending or " DESC" for descending
-     *@param findOptions An instance of EntityFindOptions that specifies advanced query options. See the EntityFindOptions JavaDoc for more details.
-     *@return EntityListIterator representing the result of the query: NOTE THAT THIS MUST BE CLOSED (preferably in a finally block) WHEN YOU ARE
-     *      DONE WITH IT, AND DON'T LEAVE IT OPEN TOO LONG BEACUSE IT WILL MAINTAIN A DATABASE CONNECTION.
+    /** Creates or stores an Entity
+     *@param value The GenericValue instance containing the new or existing instance
+     *@return GenericValue instance containing the new or updated instance
      */
-    public EntityListIterator find(String entityName, EntityCondition whereEntityCondition, EntityCondition havingEntityCondition, Set<String> fieldsToSelect, List<String> orderBy, EntityFindOptions findOptions) throws GenericEntityException;
+    public GenericValue createOrStore(GenericValue value) throws GenericEntityException {
+        return createOrStore(value, true);
+    }
+
+    protected void saveEntitySyncRemoveInfo(GenericEntity dummyPK) throws GenericEntityException {
+        // don't store remove info on entities where it is disabled
+        if (dummyPK.getModelEntity().getNoAutoStamp() || this.testRollbackInProgress) {
+            return;
+        }
+
+        // don't store remove info on things removed on an entity sync
+        if (dummyPK.getIsFromEntitySync()) {
+            return;
+        }
+
+        String serializedPK = null;
+        try {
+            serializedPK = XmlSerializer.serialize(dummyPK);
+        } catch (SerializeException e) {
+            Debug.logError(e, "Could not serialize primary key to save EntitySyncRemove", module);
+        } catch (FileNotFoundException e) {
+            Debug.logError(e, "Could not serialize primary key to save EntitySyncRemove", module);
+        } catch (IOException e) {
+            Debug.logError(e, "Could not serialize primary key to save EntitySyncRemove", module);
+        }
+
+        if (serializedPK != null) {
+            GenericValue entitySyncRemove = this.makeValue("EntitySyncRemove");
+            entitySyncRemove.set("primaryKeyRemoved", serializedPK);
+            this.createSetNextSeqId(entitySyncRemove);
+        }
+    }
 
-    /** Finds all Generic entities
-     * NOTE 20080502: 14 references; all changed to findList
-     *@param entityName The Name of the Entity as defined in the entity XML file
-     *@return    List containing all Generic entities
-     *@deprecated Use findList() instead
+    /** Remove a Generic Entity corresponding to the primaryKey
+     *@param primaryKey  The primary key of the entity to remove.
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public List<GenericValue> findAll(String entityName) throws GenericEntityException;
+    public int removeByPrimaryKey(GenericPK primaryKey) throws GenericEntityException {
+        int retVal = this.removeByPrimaryKey(primaryKey, true);
+        return retVal;
+    }
 
-    /** Finds all Generic entities
-     * NOTE 20080502: 10 references; all changed to findList
-     *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param orderBy The fields of the named entity to order the query by; optionally add a " ASC" for ascending or " DESC" for descending
-     *@return    List containing all Generic entities
-     *@deprecated Use findList() instead
+    /** Remove a Generic Entity corresponding to the primaryKey
+     *@param primaryKey  The primary key of the entity to remove.
+     *@param doCacheClear boolean that specifies whether to clear cache entries for this primaryKey to be removed
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public List<GenericValue> findAll(String entityName, List<String> orderBy) throws GenericEntityException;
+    public int removeByPrimaryKey(GenericPK primaryKey, boolean doCacheClear) throws GenericEntityException {
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(primaryKey.getEntityName());
+            ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE, EntityEcaHandler.OP_REMOVE, primaryKey, false);
+
+            GenericHelper helper = getEntityHelper(primaryKey.getEntityName());
+
+            if (doCacheClear) {
+                // always clear cache before the operation
+                ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR, EntityEcaHandler.OP_REMOVE, primaryKey, false);
+                this.clearCacheLine(primaryKey);
+            }
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_REMOVE, primaryKey, false);
+
+            // if audit log on for any fields, save old value before removing so it's still there
+            if (primaryKey != null && primaryKey.getModelEntity().getHasFieldWithAuditLog()) {
+                createEntityAuditLogAll(this.findOne(primaryKey.getEntityName(), primaryKey, false), true, true);
+            }
+
+            GenericValue removedEntity = null;
+            if (testMode) {
+                removedEntity = this.findOne(primaryKey.entityName, primaryKey, false);
+            }
+            int num = helper.removeByPrimaryKey(primaryKey);
+            this.saveEntitySyncRemoveInfo(primaryKey);
+
+            if (testMode) {
+                storeForTestRollback(new TestOperation(OperationType.DELETE, removedEntity));
+            }
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_REMOVE, primaryKey, false);
+
+            return num;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in removeByPrimaryKey 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);
+        }
+    }
 
-    /** Finds all Generic entities
-     * NOTE 20080502: 0 references
-     *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param orderBy The fields of the named entity to order the query by; optionally add a " ASC" for ascending or " DESC" for descending
-     *@return    List containing all Generic entities
-     *@deprecated Use findList() instead
+    /** Remove a Generic Value from the database
+     *@param value The GenericValue object of the entity to remove.
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public List<GenericValue> findAll(String entityName, String... orderBy) throws GenericEntityException;
+    public int removeValue(GenericValue value) throws GenericEntityException {
+        return this.removeValue(value, true);
+    }
 
-    /** Find a number of Generic Value objects by their Primary Keys, all at once
-     * NOTE 20080502: 0 references
-     *@param primaryKeys A Collection of primary keys to find by.
-     *@return List of GenericValue objects corresponding to the passed primaryKey objects
-     *@deprecated
+    /** Remove a Generic Value from the database
+     *@param value The GenericValue object of the entity to remove.
+     *@param doCacheClear boolean that specifies whether to clear cache entries for this value to be removed
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public List<GenericValue> findAllByPrimaryKeys(Collection<GenericPK> primaryKeys) throws GenericEntityException;
+    public int removeValue(GenericValue value, boolean doCacheClear) throws GenericEntityException {
+        // NOTE: this does not call the GenericDelegator.removeByPrimaryKey method because it has more information to pass to the ECA rule hander
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(value.getEntityName());
+            ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE, EntityEcaHandler.OP_REMOVE, value, false);
+
+            GenericHelper helper = getEntityHelper(value.getEntityName());
+
+            if (doCacheClear) {
+                ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR, EntityEcaHandler.OP_REMOVE, value, false);
+                this.clearCacheLine(value);
+            }
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_REMOVE, value, false);
+
+            // if audit log on for any fields, save old value before actual remove
+            if (value != null && value.getModelEntity().getHasFieldWithAuditLog()) {
+                createEntityAuditLogAll(value, true, true);
+            }
+
+            GenericValue removedValue = null;
+            if (testMode) {
+                removedValue = this.findOne(value.getEntityName(), value.getPrimaryKey(), false);
+            }
+
+            int num = helper.removeByPrimaryKey(value.getPrimaryKey());
+
+            if (testMode) {
+                storeForTestRollback(new TestOperation(OperationType.DELETE, removedValue));
+            }
+
+            this.saveEntitySyncRemoveInfo(value.getPrimaryKey());
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_REMOVE, value, false);
+
+            return num;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in removeValue 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);
+        }
+    }
 
-    /** Find a number of Generic Value objects by their Primary Keys, all at once;
-     *  this first looks in the local cache for each PK and if there then it puts it
-     *  in the return list rather than putting it in the batch to send to
-     *  a given helper.
-     * NOTE 20080502: 0 references
-     *@param primaryKeys A Collection of primary keys to find by.
-     *@return List of GenericValue objects corresponding to the passed primaryKey objects
-     *@deprecated
+    /** Removes/deletes Generic Entity records found by all of the specified fields (ie: combined using AND)
+     *@param entityName The Name of the Entity as defined in the entity XML file
+     *@param fields The fields of the named entity to query by with their corresponding values
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public List<GenericValue> findAllByPrimaryKeysCache(Collection<GenericPK> primaryKeys) throws GenericEntityException;
+    public int removeByAnd(String entityName, Object... fields) throws GenericEntityException {
+        return removeByAnd(entityName, UtilMisc.<String, Object>toMap(fields));
+    }
 
-    /** Finds all Generic entities, looking first in the cache
-     * NOTE 20080502: 4 references; all changed to findList
+    /** Removes/deletes Generic Entity records found by all of the specified fields (ie: combined using AND)
      *@param entityName The Name of the Entity as defined in the entity XML file
-     *@return    List containing all Generic entities
-     *@deprecated Use findList() instead
+     *@param fields The fields of the named entity to query by with their corresponding values
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public List<GenericValue> findAllCache(String entityName) throws GenericEntityException;
+    public int removeByAnd(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException {
+        return this.removeByAnd(entityName, fields, true);
+    }
 
-    /** Finds all Generic entities, looking first in the cache; uses orderBy for lookup, but only keys results on the entityName and fields
-     * NOTE 20080502: 2 references; all changed to findList
+    /** Removes/deletes Generic Entity records found by all of the specified fields (ie: combined using AND)
      *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param orderBy The fields of the named entity to order the query by; optionally add a " ASC" for ascending or " DESC" for descending
-     *@return    List containing all Generic entities
-     *@deprecated Use findList() instead
+     *@param doCacheClear boolean that specifies whether to clear cache entries for this value to be removed
+     *@param fields The fields of the named entity to query by with their corresponding values
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public List<GenericValue> findAllCache(String entityName, List<String> orderBy) throws GenericEntityException;
+    public int removeByAnd(String entityName, boolean doCacheClear, Object... fields) throws GenericEntityException {
+        return removeByAnd(entityName, UtilMisc.<String, Object>toMap(fields), doCacheClear);
+    }
 
-    /** Finds all Generic entities, looking first in the cache; uses orderBy for lookup, but only keys results on the entityName and fields
-     * NOTE 20080502: 0 references
+    /** Removes/deletes Generic Entity records found by all of the specified fields (ie: combined using AND)
      *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param orderBy The fields of the named entity to order the query by; optionally add a " ASC" for ascending or " DESC" for descending
-     *@return    List containing all Generic entities
-     *@deprecated Use findList() instead
+     *@param fields The fields of the named entity to query by with their corresponding values
+     *@param doCacheClear boolean that specifies whether to clear cache entries for this value to be removed
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public List<GenericValue> findAllCache(String entityName, String... orderBy) throws GenericEntityException;
+    public int removeByAnd(String entityName, Map<String, ? extends Object> fields, boolean doCacheClear) throws GenericEntityException {
+        EntityCondition ecl = EntityCondition.makeCondition(fields);
+        return removeByCondition(entityName, ecl, doCacheClear);
+    }
 
-    /** Finds Generic Entity records by all of the specified expressions (ie: combined using AND)
-     * NOTE 20080502: 11 references; all changed to findList
+    /** Removes/deletes Generic Entity records found by the condition
      *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param expressions The expressions to use for the lookup, each consisting of at least a field name, an EntityOperator, and a value to compare to
-     *@return List of GenericValue instances that match the query
-     *@deprecated Use findList() instead
+     *@param condition The condition used to restrict the removing
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public <T extends EntityCondition> List<GenericValue> findByAnd(String entityName, List<T> expressions) throws GenericEntityException;
+    public int removeByCondition(String entityName, EntityCondition condition) throws GenericEntityException {
+        return this.removeByCondition(entityName, condition, true);
+    }
 
-    /** Finds Generic Entity records by all of the specified expressions (ie: combined using AND)
-     * NOTE 20080502: 24 references; all changed to findList
+    /** Removes/deletes Generic Entity records found by the condition
      *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param expressions The expressions to use for the lookup, each consisting of at least a field name, an EntityOperator, and a value to compare to
-     *@param orderBy The fields of the named entity to order the query by; optionally add a " ASC" for ascending or " DESC" for descending
-     *@return List of GenericValue instances that match the query
-     *@deprecated Use findList() instead
+     *@param condition The condition used to restrict the removing
+     *@param doCacheClear boolean that specifies whether to clear cache entries for this value to be removed
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public <T extends EntityCondition> List<GenericValue> findByAnd(String entityName, List<T> expressions, List<String> orderBy) throws GenericEntityException;
+    public int removeByCondition(String entityName, EntityCondition condition, boolean doCacheClear) throws GenericEntityException {
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            if (doCacheClear) {
+                // always clear cache before the operation
+                this.clearCacheLineByCondition(entityName, condition);
+            }
+            ModelEntity modelEntity = getModelReader().getModelEntity(entityName);
+            GenericHelper helper = getEntityHelper(entityName);
+
+            List<GenericValue> removedEntities = null;
+            if (testMode) {
+                removedEntities = this.findList(entityName, condition, null, null, null, false);
+            }
+
+            int rowsAffected = helper.removeByCondition(modelEntity, condition);
+
+            if (testMode) {
+                for (GenericValue entity : removedEntities) {
+                    storeForTestRollback(new TestOperation(OperationType.DELETE, entity));
+                }
+            }
+
+            return rowsAffected;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in removeByCondition 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);
+        }
+    }
 
-    /** Finds Generic Entity records by all of the specified fields (ie: combined using AND)
-     * NOTE 20080502: 264 references
-     * @param entityName The Name of the Entity as defined in the entity XML file
-     * @param fields The fields of the named entity to query by with their corresponding values
-     * @return List of GenericValue instances that match the query
+    /** Remove the named Related Entity for the GenericValue from the persistent store
+     *@param relationName String containing the relation name which is the
+     *      combination of relation.title and relation.rel-entity-name as
+     *      specified in the entity XML definition file
+     *@param value GenericValue instance containing the entity
+     *@return int representing number of rows effected by this operation
      */
-    public List<GenericValue> findByAnd(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException;
+    public int removeRelated(String relationName, GenericValue value) throws GenericEntityException {
+        return this.removeRelated(relationName, value, true);
+    }
 
-    /** Finds Generic Entity records by all of the specified fields (ie: combined using AND)
-     * NOTE 20080502: 72 references
-     * @param entityName The Name of the Entity as defined in the entity XML file
-     * @param fields The fields of the named entity to query by with their corresponding values
-     * @param orderBy The fields of the named entity to order the query by;
-     *      optionally add a " ASC" for ascending or " DESC" for descending
-     * @return List of GenericValue instances that match the query
-     */
-    public List<GenericValue> findByAnd(String entityName, Map<String, ? extends Object> fields, List<String> orderBy) throws GenericEntityException;
-
-    /** Finds Generic Entity records by all of the specified fields (ie: combined using AND)
-     * NOTE 20080502: 1 references
-     * @param entityName The Name of the Entity as defined in the entity XML file
-     * @param fields The fields of the named entity to query by with their corresponding values
-     * @return List of GenericValue instances that match the query
-     */
-    public List<GenericValue> findByAnd(String entityName, Object... fields) throws GenericEntityException;
-
-    /** Finds Generic Entity records by all of the specified expressions (ie: combined using AND)
-     * NOTE 20080502: 0 references
-     *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param expressions The expressions to use for the lookup, each consisting of at least a field name, an EntityOperator, and a value to compare to
-     *@return List of GenericValue instances that match the query
-     *@deprecated Use findList() instead
+    /** Remove the named Related Entity for the GenericValue from the persistent store
+     *@param relationName String containing the relation name which is the
+     *      combination of relation.title and relation.rel-entity-name as
+     *      specified in the entity XML definition file
+     *@param value GenericValue instance containing the entity
+     *@param doCacheClear boolean that specifies whether to clear cache entries for this value to be removed
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public <T extends EntityCondition> List<GenericValue> findByAnd(String entityName, T... expressions) throws GenericEntityException;
+    public int removeRelated(String relationName, GenericValue value, boolean doCacheClear) 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()));
+        }
 
-    /** Finds Generic Entity records by all of the specified fields (ie: combined using AND), looking first in the cache; uses orderBy for lookup, but only keys results on the entityName and fields
-     * NOTE 20080502: 91 references
-     *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param fields The fields of the named entity to query by with their corresponding values
-     *@return List of GenericValue instances that match the query
-     */
-    public List<GenericValue> findByAndCache(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException;
+        return this.removeByAnd(relation.getRelEntityName(), fields, doCacheClear);
+    }
 
-    /** Finds Generic Entity records by all of the specified fields (ie: combined using AND), looking first in the cache; uses orderBy for lookup, but only keys results on the entityName and fields
-     * NOTE 20080502: 56 references
-     *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param fields The fields of the named entity to query by with their corresponding values
-     *@param orderBy The fields of the named entity to order the query by; optionally add a " ASC" for ascending or " DESC" for descending
-     *@return List of GenericValue instances that match the query
+    /** Refresh the Entity for the GenericValue from the persistent store
+     *@param value GenericValue instance containing the entity to refresh
      */
-    public List<GenericValue> findByAndCache(String entityName, Map<String, ? extends Object> fields, List<String> orderBy) throws GenericEntityException;
+    public void refresh(GenericValue value) throws GenericEntityException {
+        this.refresh(value, true);
+    }
 
-    /** Finds Generic Entity records by all of the specified fields (ie: combined using AND), looking first in the cache; uses orderBy for lookup, but only keys results on the entityName and fields
-     * NOTE 20080502: 0 references
-     *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param fields The fields of the named entity to query by with their corresponding values
-     *@return List of GenericValue instances that match the query
-     *@deprecated Use findList() instead
+    /** Refresh the Entity for the GenericValue from the persistent store
+     *@param value GenericValue instance containing the entity to refresh
+     *@param doCacheClear boolean that specifies whether or not to automatically clear cache entries related to this operation
      */
-    @Deprecated
-    public List<GenericValue> findByAndCache(String entityName, Object... fields) throws GenericEntityException;
+    public void refresh(GenericValue value, boolean doCacheClear) throws GenericEntityException {
+        if (doCacheClear) {
+            // always clear cache before the operation
+            clearCacheLine(value);
+        }
+        GenericPK pk = value.getPrimaryKey();
+        GenericValue newValue = this.findOne(pk.getEntityName(), pk, false);
+        value.refreshFromValue(newValue);
+    }
 
-    /** Finds GenericValues by the conditions specified in the EntityCondition object, the the EntityCondition javadoc for more details.
-     * NOTE 20080502: 64 references; all changed to findList
-     *@param entityName The Name of the Entity as defined in the entity model XML file
-     *@param entityCondition The EntityCondition object that specifies how to constrain this query
-     *@param fieldsToSelect The fields of the named entity to get from the database; if empty or null all fields will be retreived
-     *@param orderBy The fields of the named entity to order the query by; optionally add a " ASC" for ascending or " DESC" for descending
-     *@return List of GenericValue objects representing the result
-     *@deprecated Use findList() instead
+    /** Refresh the Entity for the GenericValue from the cache
+     *@param value GenericValue instance containing the entity to refresh
      */
-    @Deprecated
-    public List<GenericValue> findByCondition(String entityName, EntityCondition entityCondition, Collection<String> fieldsToSelect, List<String> orderBy) throws GenericEntityException;
+    public void refreshFromCache(GenericValue value) throws GenericEntityException {
+        GenericPK pk = value.getPrimaryKey();
+        GenericValue newValue = findOne(pk.getEntityName(), pk, true);
+        value.refreshFromValue(newValue);
+    }
 
-    /** Finds GenericValues by the conditions specified in the EntityCondition object, the the EntityCondition javadoc for more details.
-     * NOTE 20080502: 6 references; all changed to findList
+   /** Store a group of values
      *@param entityName The name of the Entity as defined in the entity XML file
-     *@param whereEntityCondition The EntityCondition object that specifies how to constrain this query before any groupings are done (if this is a view entity with group-by aliases)
-     *@param havingEntityCondition The EntityCondition object that specifies how to constrain this query after any groupings are done (if this is a view entity with group-by aliases)
-     *@param fieldsToSelect The fields of the named entity to get from the database; if empty or null all fields will be retreived
-     *@param orderBy The fields of the named entity to order the query by; optionally add a " ASC" for ascending or " DESC" for descending
-     *@param findOptions An instance of EntityFindOptions that specifies advanced query options. See the EntityFindOptions JavaDoc for more details.
-     *@return List of GenericValue objects representing the result
-     *@deprecated Use findList() instead
+     *@param fieldsToSet The fields of the named entity to set in the database
+     *@param condition The condition that restricts the list of stored values
+     *@return int representing number of rows effected by this operation
+     *@throws GenericEntityException
      */
-    @Deprecated
-    public List<GenericValue> findByCondition(String entityName, EntityCondition whereEntityCondition, EntityCondition havingEntityCondition, Collection<String> fieldsToSelect, List<String> orderBy, EntityFindOptions findOptions) throws GenericEntityException;
+    public int storeByCondition(String entityName, Map<String, ? extends Object> fieldsToSet, EntityCondition condition) throws GenericEntityException {
+        return storeByCondition(entityName, fieldsToSet, condition, true);
+    }
 
-    /** Finds GenericValues by the conditions specified in the EntityCondition object, looking first in the cache, see the EntityCondition javadoc for more details.
-     * NOTE 20080502: 17 references; all changed to findList
-     *@param entityName The Name of the Entity as defined in the entity model XML file
-     *@param entityCondition The EntityCondition object that specifies how to constrain this query
-     *@param fieldsToSelect The fields of the named entity to get from the database; if empty or null all fields will be retreived
-     *@param orderBy The fields of the named entity to order the query by; optionally add a " ASC" for ascending or " DESC" for descending
-     *@return List of GenericValue objects representing the result
-     *@deprecated Use findList() instead
+    /** Store a group of values
+     *@param entityName The name of the Entity as defined in the entity XML file
+     *@param fieldsToSet The fields of the named entity to set in the database
+     *@param condition The condition that restricts the list of stored values
+     *@param doCacheClear boolean that specifies whether to clear cache entries for these values
+     *@return int representing number of rows effected by this operation
+     *@throws GenericEntityException
      */
-    @Deprecated
-    public List<GenericValue> findByConditionCache(String entityName, EntityCondition entityCondition, Collection<String> fieldsToSelect, List<String> orderBy) throws GenericEntityException;
+    public int storeByCondition(String entityName, Map<String, ? extends Object> fieldsToSet, EntityCondition condition, boolean doCacheClear) throws GenericEntityException {
+        boolean beganTransaction = false;
+        try {
+            if (alwaysUseTransaction) {
+                beganTransaction = TransactionUtil.begin();
+            }
+
+            if (doCacheClear) {
+                // always clear cache before the operation
+                this.clearCacheLineByCondition(entityName, condition);
+            }
+            ModelEntity modelEntity = getModelReader().getModelEntity(entityName);
+            GenericHelper helper = getEntityHelper(entityName);
+
+            List<GenericValue> updatedEntities = null;
+            if (testMode) {
+                updatedEntities = this.findList(entityName, condition, null, null, null, false);
+            }
+
+            int rowsAffected =  helper.storeByCondition(modelEntity, fieldsToSet, condition);
+
+            if (testMode) {
+                for (GenericValue entity : updatedEntities) {
+                    storeForTestRollback(new TestOperation(OperationType.UPDATE, entity));
+                }
+            }
+
+            return rowsAffected;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in storeByCondition 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);
+        }
+    }
 
-    /**
-     * NOTE 20080502: 1 references; all changed to findList
-     *@deprecated Use findList() instead
+    /** Store the Entity from the GenericValue to the persistent store
+     *@param value GenericValue instance containing the entity
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public List<GenericValue> findByLike(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException;
+    public int store(GenericValue value) throws GenericEntityException {
+        return this.store(value, true);
+    }
 
-    /**
-     * NOTE 20080502: 1 references; all changed to findList
-     *@deprecated Use findList() instead
+    /** Store the Entity from the GenericValue to the persistent store
+     *@param value GenericValue instance containing the entity
+     *@param doCacheClear boolean that specifies whether or not to automatically clear cache entries related to this operation
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public List<GenericValue> findByLike(String entityName, Map<String, ? extends Object> fields, List<String> orderBy) throws GenericEntityException;
+    public int store(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_STORE, value, false);
+            GenericHelper helper = getEntityHelper(value.getEntityName());
+
+            if (doCacheClear) {
+                // always clear cache before the operation
+                ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR, EntityEcaHandler.OP_STORE, value, false);
+                this.clearCacheLine(value);
+            }
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_STORE, value, false);
+            this.encryptFields(value);
+
+            // if audit log on for any fields, save old value before the update so we still have both
+            if (value != null && value.getModelEntity().getHasFieldWithAuditLog()) {
+                createEntityAuditLogAll(value, true, false);
+            }
+
+            GenericValue updatedEntity = null;
+
+            if (testMode) {
+                updatedEntity = this.findOne(value.entityName, value.getPrimaryKey(), false);
+            }
+
+            int retVal = helper.store(value);
+
+            if (testMode) {
+                storeForTestRollback(new TestOperation(OperationType.UPDATE, updatedEntity));
+            }
+            // refresh the valueObject to get the new version
+            if (value.lockEnabled()) {
+                refresh(value, doCacheClear);
+            }
+
+            ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_STORE, value, false);
+
+            return retVal;
+        } catch (GenericEntityException e) {
+            String errMsg = "Failure in store 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);
+        }
+    }
 
-    /**
-     * NOTE 20080502: 0 references
-     *@deprecated Use findList() instead
+    /** Store the Entities from the List GenericValue instances to the persistent store.
+     *  <br/>This is different than the normal store method in that the store method only does
+     *  an update, while the storeAll method checks to see if each entity exists, then
+     *  either does an insert or an update as appropriate.
+     *  <br/>These updates all happen in one transaction, so they will either all succeed or all fail,
+     *  if the data source supports transactions. This is just like to othersToStore feature
+     *  of the GenericEntity on a create or store.
+     *@param values List of GenericValue instances containing the entities to store
+     *@return int representing number of rows effected by this operation
      */
-    @Deprecated
-    public List<GenericValue> findByLike(String entityName, Object... fields) throws GenericEntityException;
+    public int storeAll(List<GenericValue> values) throws GenericEntityException {
+        return this.storeAll(values, true);
+    }
 
-    /** Finds Generic Entity records by all of the specified expressions (ie: combined using OR)
-     * NOTE 20080502: 2 references; all changed to findList
-     *@param entityName The Name of the Entity as defined in the entity XML file
-     *@param expressions The expressions to use for the lookup, each consisting of at least a field name, an EntityOperator, and a value to compare to
-     *@return List of GenericValue instances that match the query
-     *@deprecated Use findList() instead
+    /** Store the Entities from the List GenericValue instances to the persistent store.
+     *  <br/>This is different than the normal store method in that the store method only does
+     *  an update, while the storeAll method checks to see if each entity exists, then
+     *  either does an insert or an update as appropriate.

[... 2628 lines stripped ...]