/* * 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.apache.ofbiz.entity; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.sql.Timestamp; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import javax.xml.parsers.ParserConfigurationException; import org.apache.ofbiz.base.concurrent.ConstantFuture; import org.apache.ofbiz.base.concurrent.ExecutionPool; import org.apache.ofbiz.base.util.Debug; import org.apache.ofbiz.base.util.GeneralRuntimeException; import org.apache.ofbiz.base.util.UtilDateTime; import org.apache.ofbiz.base.util.UtilFormatOut; import org.apache.ofbiz.base.util.UtilGenerics; import org.apache.ofbiz.base.util.UtilMisc; import org.apache.ofbiz.base.util.UtilObject; import org.apache.ofbiz.base.util.UtilValidate; import org.apache.ofbiz.base.util.UtilXml; import org.apache.ofbiz.entity.cache.Cache; import org.apache.ofbiz.entity.condition.EntityCondition; import org.apache.ofbiz.entity.config.model.Datasource; import org.apache.ofbiz.entity.config.model.DelegatorElement; import org.apache.ofbiz.entity.config.model.EntityConfig; import org.apache.ofbiz.entity.datasource.GenericHelper; import org.apache.ofbiz.entity.datasource.GenericHelperFactory; import org.apache.ofbiz.entity.datasource.GenericHelperInfo; import org.apache.ofbiz.entity.eca.EntityEcaHandler; import org.apache.ofbiz.entity.model.DynamicViewEntity; import org.apache.ofbiz.entity.model.ModelEntity; import org.apache.ofbiz.entity.model.ModelEntityChecker; import org.apache.ofbiz.entity.model.ModelField; import org.apache.ofbiz.entity.model.ModelFieldType; import org.apache.ofbiz.entity.model.ModelFieldTypeReader; import org.apache.ofbiz.entity.model.ModelGroupReader; import org.apache.ofbiz.entity.model.ModelKeyMap; import org.apache.ofbiz.entity.model.ModelReader; import org.apache.ofbiz.entity.model.ModelRelation; import org.apache.ofbiz.entity.model.ModelViewEntity; import org.apache.ofbiz.entity.serialize.SerializeException; import org.apache.ofbiz.entity.serialize.XmlSerializer; import org.apache.ofbiz.entity.transaction.TransactionUtil; import org.apache.ofbiz.entity.util.DistributedCacheClear; import org.apache.ofbiz.entity.util.EntityCrypto; import org.apache.ofbiz.entity.util.EntityFindOptions; import org.apache.ofbiz.entity.util.EntityListIterator; import org.apache.ofbiz.entity.util.EntityQuery; import org.apache.ofbiz.entity.util.EntityStoreOptions; import org.apache.ofbiz.entity.util.SequenceUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.SAXException; /** * The default implementation of the <code>Delegator</code> interface. * */ public class GenericDelegator implements Delegator { public static final String module = GenericDelegator.class.getName(); protected ModelReader modelReader = null; protected ModelGroupReader modelGroupReader = null; /** 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; protected String delegatorBaseName = null; protected String delegatorFullName = null; protected String delegatorTenantId = null; private String originalDelegatorName = null; protected DelegatorElement delegatorInfo = null; protected Cache cache = null; protected final AtomicReference<Future<DistributedCacheClear>> distributedCacheClear = new AtomicReference<Future<DistributedCacheClear>>(); protected boolean warnNoEcaHandler = false; protected final AtomicReference<Future<EntityEcaHandler<?>>> entityEcaHandler = new AtomicReference<Future<EntityEcaHandler<?>>>(); protected final AtomicReference<SequenceUtil> AtomicRefSequencer = new AtomicReference<SequenceUtil>(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<String>> userIdentifierStack = new ThreadLocal<List<String>>(); /** 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<String>> sessionIdentifierStack = new ThreadLocal<List<String>>(); private boolean testMode = false; private boolean testRollbackInProgress = false; private static final AtomicReferenceFieldUpdater<GenericDelegator, LinkedBlockingDeque<?>> testOperationsUpdater = UtilGenerics.cast(AtomicReferenceFieldUpdater.newUpdater(GenericDelegator.class, LinkedBlockingDeque.class, "testOperations")); private volatile LinkedBlockingDeque<TestOperation> testOperations = null; protected static List<String> getUserIdentifierStack() { List<String> curValList = userIdentifierStack.get(); if (curValList == null) { curValList = new LinkedList<String>(); userIdentifierStack.set(curValList); } return curValList; } public static void pushUserIdentifier(String userIdentifier) { if (userIdentifier == null) { return; } List<String> curValList = getUserIdentifierStack(); curValList.add(0, userIdentifier); } public static String popUserIdentifier() { List<String> curValList = getUserIdentifierStack(); if (curValList.size() == 0) { return null; } else { return curValList.remove(0); } } public static void clearUserIdentifierStack() { List<String> curValList = getUserIdentifierStack(); curValList.clear(); } protected static List<String> getSessionIdentifierStack() { List<String> curValList = sessionIdentifierStack.get(); if (curValList == null) { curValList = new LinkedList<String>(); sessionIdentifierStack.set(curValList); } return curValList; } public static void pushSessionIdentifier(String sessionIdentifier) { if (sessionIdentifier == null) { return; } List<String> curValList = getSessionIdentifierStack(); curValList.add(0, sessionIdentifier); } public static String popSessionIdentifier() { List<String> curValList = getSessionIdentifierStack(); if (curValList.size() == 0) { return null; } else { return curValList.remove(0); } } public static void clearSessionIdentifierStack() { List<String> curValList = getSessionIdentifierStack(); curValList.clear(); } /** Only allow creation through the factory method */ protected GenericDelegator() {} /** Only allow creation through the factory method */ protected GenericDelegator(String delegatorFullName) throws GenericEntityException { //if (Debug.infoOn()) Debug.logInfo("Creating new Delegator with name \"" + delegatorFullName + "\".", module); this.setDelegatorNames(delegatorFullName); this.delegatorInfo = EntityConfig.getInstance().getDelegator(delegatorBaseName); if (this.delegatorInfo == null) { throw new GenericEntityException("No configuration found for delegator [" + delegatorFullName + "]"); } String kekText; // before continuing, if there is a tenantId use the base delegator to see if it is valid if (UtilValidate.isNotEmpty(this.delegatorTenantId)) { Delegator baseDelegator = DelegatorFactory.getDelegator(this.delegatorBaseName); GenericValue tenant = EntityQuery.use(baseDelegator).from("Tenant").where("tenantId", this.delegatorTenantId).cache(true).queryOne(); if (tenant == null) { throw new GenericEntityException("No Tenant record found for delegator [" + this.delegatorFullName + "] with tenantId [" + this.delegatorTenantId + "]"); } else if ("Y".equals(tenant.getString("disabled"))) { throw new GenericEntityException("No Tenant record found for delegator [" + this.delegatorFullName + "] with tenantId [" + this.delegatorTenantId + "]"); } GenericValue kekValue = EntityQuery.use(baseDelegator).from("TenantKeyEncryptingKey").where("tenantId", getDelegatorTenantId()).cache(true).queryOne(); if (kekValue != null) { kekText = kekValue.getString("kekText"); } else { kekText = this.delegatorInfo.getKeyEncryptingKey(); } } else { kekText = this.delegatorInfo.getKeyEncryptingKey(); } this.modelReader = ModelReader.getModelReader(delegatorBaseName); this.modelGroupReader = ModelGroupReader.getModelGroupReader(delegatorBaseName); cache = new Cache(delegatorFullName); // do the entity model check List<String> warningList = new LinkedList<String>(); Debug.logInfo("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(delegatorBaseName); List<Future<Void>> futures = new LinkedList<Future<Void>>(); for (String groupName: groupNames) { futures.add(ExecutionPool.GLOBAL_BATCH.submit(createHelperCallable(groupName))); } ExecutionPool.getAllFutures(futures); // 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 // setup the crypto class; this also after the delegator is in the cache otherwise we get infinite recursion this.crypto = new EntityCrypto(this, kekText); } private void initializeOneGenericHelper(String groupName) { GenericHelperInfo helperInfo = this.getGroupHelperInfo(groupName); if (helperInfo == null) { if (Debug.infoOn()) { Debug.logInfo("Delegator \"" + delegatorFullName + "\" NOT initializing helper for entity group \"" + groupName + "\" because the group is not associated to this delegator.", module); } return; } String helperBaseName = helperInfo.getHelperBaseName(); if (Debug.infoOn()) { Debug.logInfo("Delegator \"" + delegatorFullName + "\" initializing helper \"" + helperBaseName + "\" for entity group \"" + groupName + "\".", module); } if (UtilValidate.isNotEmpty(helperInfo.getHelperFullName())) { // pre-load field type defs, the return value is ignored ModelFieldTypeReader.getModelFieldTypeReader(helperBaseName); // get the helper and if configured, do the datasource check GenericHelper helper = GenericHelperFactory.getHelper(helperInfo); try { Datasource datasource = EntityConfig.getDatasource(helperBaseName); if (datasource.getCheckOnStart()) { if (Debug.infoOn()) { Debug.logInfo("Doing database check as requested in entityengine.xml with addMissing=" + datasource.getAddMissingOnStart(), module); } helper.checkDataSource(this.getModelEntityMapByGroup(groupName), null, datasource.getAddMissingOnStart()); } } catch (GenericEntityException e) { Debug.logWarning(e, e.getMessage(), module); } } } protected Callable<Void> createHelperCallable(final String groupName) { return new Callable<Void>() { @Override public Void call() { initializeOneGenericHelper(groupName); return null; } }; } protected void setDelegatorNames(String delegatorFullName) { this.delegatorFullName = delegatorFullName; int hashSymbolIndex = delegatorFullName.indexOf('#'); if (hashSymbolIndex == -1) { this.delegatorBaseName = delegatorFullName; } else { this.delegatorBaseName = delegatorFullName.substring(0, hashSymbolIndex); this.delegatorTenantId = delegatorFullName.substring(hashSymbolIndex + 1); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#initEntityEcaHandler() */ @Override public synchronized void initEntityEcaHandler() { // Nothing to do if already assigned: the class loader has already been called, the class instantiated and casted to EntityEcaHandler if (this.entityEcaHandler.get() != null || this.warnNoEcaHandler) { return; } Callable<EntityEcaHandler<?>> creator = new Callable<EntityEcaHandler<?>>() { public EntityEcaHandler<?> call() { return createEntityEcaHandler(); } }; FutureTask<EntityEcaHandler<?>> futureTask = new FutureTask<EntityEcaHandler<?>>(creator); if (this.entityEcaHandler.compareAndSet(null, futureTask)) { // This needs to use BATCH, as the service engine might add it's own items into a thread pool. ExecutionPool.GLOBAL_BATCH.submit(futureTask); } } protected EntityEcaHandler<?> createEntityEcaHandler() { // If useEntityEca is false do nothing: the entityEcaHandler member field with a null value would cause its code to do nothing if (this.delegatorInfo.getEntityEcaEnabled()) { //time to do some tricks with manual class loading that resolves circular dependencies, like calling services ClassLoader loader = Thread.currentThread().getContextClassLoader(); // initialize the entity eca handler String entityEcaHandlerClassName = this.delegatorInfo.getEntityEcaHandlerClassName(); try { Class<?> eecahClass = loader.loadClass(entityEcaHandlerClassName); EntityEcaHandler<?> entityEcaHandler = UtilGenerics.cast(eecahClass.newInstance()); entityEcaHandler.setDelegator(this); return entityEcaHandler; } 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 if (!this.warnNoEcaHandler) { Debug.logInfo("Entity ECA Handler disabled for delegator [" + delegatorFullName + "]", module); this.warnNoEcaHandler = true; } return null; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getDelegatorName() */ @Override public String getDelegatorName() { return this.delegatorFullName; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getDelegatorBaseName() */ @Override public String getDelegatorBaseName() { return this.delegatorBaseName; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getDelegatorBaseName() */ @Override public String getDelegatorTenantId() { return this.delegatorTenantId; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getOriginalDelegatorName() */ @Override public String getOriginalDelegatorName() { return this.originalDelegatorName == null ? this.delegatorFullName : this.originalDelegatorName; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getModelReader() */ @Override public ModelReader getModelReader() { return this.modelReader; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getModelGroupReader() */ @Override public ModelGroupReader getModelGroupReader() { return this.modelGroupReader; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getModelEntity(java.lang.String) */ @Override 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; } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getEntityGroupName(java.lang.String) */ @Override public String getEntityGroupName(String entityName) { return getModelGroupReader().getEntityGroupName(entityName, this.delegatorBaseName); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getModelEntityMapByGroup(java.lang.String) */ @Override public Map<String, ModelEntity> getModelEntityMapByGroup(String groupName) throws GenericEntityException { Set<String> entityNameSet = getModelGroupReader().getEntityNamesByGroup(delegatorBaseName, groupName); if (this.delegatorInfo.getDefaultGroupName().equals(groupName)) { // add all entities with no group name to the Set Set<String> allEntityNames = this.getModelReader().getEntityNames(); for (String entityName: allEntityNames) { if (this.delegatorInfo.getDefaultGroupName().equals(getModelGroupReader().getEntityGroupName(entityName, this.delegatorBaseName))) { entityNameSet.add(entityName); } } } Map<String, ModelEntity> entities = new HashMap<String, ModelEntity>(); if (UtilValidate.isEmpty(entityNameSet)) { 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; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getGroupHelperName(java.lang.String) */ @Override public String getGroupHelperName(String groupName) { return this.delegatorInfo.getGroupDataSource(groupName); } @Override public GenericHelperInfo getGroupHelperInfo(String entityGroupName) { if (entityGroupName == null) { return null; } String helperBaseName = this.getGroupHelperName(entityGroupName); if (helperBaseName == null) { return null; } if (UtilValidate.isNotEmpty(this.delegatorTenantId) && "org.apache.ofbiz.tenant".equals(entityGroupName)) { Debug.logInfo("Can't access entity of entityGroup = " + entityGroupName + " using tenant delegator "+ this.getDelegatorName()+", use base delegator instead", module); return null; } GenericHelperInfo helperInfo = new GenericHelperInfo(entityGroupName, helperBaseName); if (UtilValidate.isNotEmpty(this.delegatorTenantId)) { // get the JDBC parameters from the DB for the entityGroupName and tenantId try { // NOTE: instead of caching the GenericHelpInfo object do a cached query here and create a new object each time, will avoid issues when the database data changes during run time // NOTE: always use the base delegator for this to avoid problems when this is being initialized Delegator baseDelegator = DelegatorFactory.getDelegator(this.delegatorBaseName); GenericValue tenantDataSource = EntityQuery.use(baseDelegator).from("TenantDataSource").where("tenantId", this.delegatorTenantId, "entityGroupName", entityGroupName).cache(true).queryOne(); if (tenantDataSource != null) { helperInfo.setTenantId(this.delegatorTenantId); helperInfo.setOverrideJdbcUri(tenantDataSource.getString("jdbcUri")); helperInfo.setOverrideUsername(tenantDataSource.getString("jdbcUsername")); helperInfo.setOverridePassword(tenantDataSource.getString("jdbcPassword")); } else { return null; } } catch (GenericEntityException e) { // don't complain about this too much, just log the error if there is one Debug.logInfo(e, "Error getting TenantDataSource info for tenantId=" + this.delegatorTenantId + ", entityGroupName=" + entityGroupName, module); } } return helperInfo; } protected GenericHelperInfo getEntityHelperInfo(String entityName) { return this.getGroupHelperInfo(this.getEntityGroupName(entityName)); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getEntityHelperName(java.lang.String) */ @Override public String getEntityHelperName(String entityName) { return this.getGroupHelperName(this.getEntityGroupName(entityName)); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getEntityHelperName(org.apache.ofbiz.entity.model.ModelEntity) */ @Override public String getEntityHelperName(ModelEntity entity) { if (entity == null) { return null; } return getEntityHelperName(entity.getEntityName()); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getEntityHelper(java.lang.String) */ @Override public GenericHelper getEntityHelper(String entityName) throws GenericEntityException { GenericHelperInfo helperInfo = getEntityHelperInfo(entityName); if (helperInfo != null) { return GenericHelperFactory.getHelper(helperInfo); } else { throw new GenericEntityException("There is no datasource (Helper) configured for the entity-group [" + this.getEntityGroupName(entityName) + "]; was trying to find datasource (helper) for entity [" + entityName + "]"); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getEntityHelper(org.apache.ofbiz.entity.model.ModelEntity) */ @Override public GenericHelper getEntityHelper(ModelEntity entity) throws GenericEntityException { return getEntityHelper(entity.getEntityName()); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getEntityFieldType(org.apache.ofbiz.entity.model.ModelEntity, java.lang.String) */ @Override public ModelFieldType getEntityFieldType(ModelEntity entity, String type) throws GenericEntityException { return this.getModelFieldTypeReader(entity).getModelFieldType(type); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getModelFieldTypeReader(org.apache.ofbiz.entity.model.ModelEntity) */ @Override public ModelFieldTypeReader getModelFieldTypeReader(ModelEntity entity) { String helperName = getEntityHelperName(entity); if (UtilValidate.isEmpty(helperName)) { 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; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getEntityFieldTypeNames(org.apache.ofbiz.entity.model.ModelEntity) */ @Override public Collection<String> getEntityFieldTypeNames(ModelEntity entity) throws GenericEntityException { String helperName = getEntityHelperName(entity); if (UtilValidate.isEmpty(helperName)) { 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(); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makeValue(java.lang.String) */ @Override 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; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makeValue(java.lang.String, java.lang.Object) */ @Override public GenericValue makeValue(String entityName, Object... fields) { return makeValue(entityName, UtilMisc.<String, Object>toMap(fields)); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makeValue(java.lang.String, java.util.Map) */ @Override 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); } return GenericValue.create(this, entity, fields); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makeValueSingle(java.lang.String, java.lang.Object) */ @Override 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); } return GenericValue.create(this, entity, singlePkValue); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makeValidValue(java.lang.String, java.lang.Object) */ @Override public GenericValue makeValidValue(String entityName, Object... fields) { return makeValidValue(entityName, UtilMisc.<String, Object>toMap(fields)); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makeValidValue(java.lang.String, java.util.Map) */ @Override 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.setDelegator(this); value.setAllFields(fields, true, null, null); return value; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makePK(java.lang.String) */ @Override public GenericPK makePK(String entityName) { return this.makePK(entityName, (Map<String, Object>) null); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makePK(java.lang.String, java.lang.Object) */ @Override public GenericPK makePK(String entityName, Object... fields) { return makePK(entityName, UtilMisc.<String, Object>toMap(fields)); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makePK(java.lang.String, java.util.Map) */ @Override 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); } return GenericPK.create(this, entity, fields); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makePKSingle(java.lang.String, java.lang.Object) */ @Override 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); } return GenericPK.create(this, entity, singlePkValue); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#create(org.apache.ofbiz.entity.GenericPK) */ @Override public GenericValue create(GenericPK primaryKey) throws GenericEntityException { if (primaryKey == null) { throw new GenericEntityException("Cannot create from a null primaryKey"); } return this.create(GenericValue.create(primaryKey)); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#create(java.lang.String, java.lang.Object) */ @Override public GenericValue create(String entityName, Object... fields) throws GenericEntityException { return create(entityName, UtilMisc.<String, Object>toMap(fields)); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#create(java.lang.String, java.util.Map) */ @Override 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(this, entity, fields); return this.create(genericValue); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#createSingle(java.lang.String, java.lang.Object) */ @Override 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(this, entity, singlePkValue); return this.create(genericValue); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#createSetNextSeqId(org.apache.ofbiz.entity.GenericValue) */ @Override public GenericValue createSetNextSeqId(GenericValue value) throws GenericEntityException { if (value == null) { throw new GenericEntityException("Cannot create a null value"); } 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); ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_CREATE, value, false); value.setDelegator(this); // 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 = null; try { existingValue = helper.findByPrimaryKey(value.getPrimaryKey()); } catch (GenericEntityException e1) { // ignore this error, if not found it'll probably be a GenericEntityNotFoundException // it is important to not let this get thrown because it will mask the original exception } if (existingValue == null) { throw e; } else { if (Debug.infoOn()) { 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.AtomicRefSequencer.get().forceBankRefresh(value.getEntityName(), 1); value.setNextSeqId(); value = helper.create(value); if (Debug.infoOn()) { 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); } else { // 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); TransactionUtil.commit(beganTransaction); return value; } catch (Exception e) { String errMsg = "Failure in createSetNextSeqId operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#create(org.apache.ofbiz.entity.GenericValue) */ @Override public GenericValue create(GenericValue value) throws GenericEntityException { boolean beganTransaction = false; try { if (alwaysUseTransaction) { beganTransaction = TransactionUtil.begin(); } if (value == null) { throw new GenericEntityException("Cannot create a null value"); } EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(value.getEntityName()); ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE, EntityEcaHandler.OP_CREATE, value, false); GenericHelper helper = getEntityHelper(value.getEntityName()); ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_CREATE, value, false); value.setDelegator(this); // 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); } else { // 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); TransactionUtil.commit(beganTransaction); return value; } catch (Exception e) { String errMsg = "Failure in create operation for entity [" + (value != null ? value.getEntityName() : "null") + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#createOrStore(org.apache.ofbiz.entity.GenericValue) */ @Override public GenericValue createOrStore(GenericValue value) 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); } else { this.create(value); } if (value.lockEnabled()) { this.refresh(value); } TransactionUtil.commit(beganTransaction); return value; } catch (Exception e) { String errMsg = "Failure in createOrStore operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } 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); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#removeByPrimaryKey(org.apache.ofbiz.entity.GenericPK) */ @Override public int removeByPrimaryKey(GenericPK primaryKey) 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()); 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.getModelEntity().getHasFieldWithAuditLog()) { createEntityAuditLogAll(this.findOne(primaryKey.getEntityName(), primaryKey, false), true, true); } GenericValue removedEntity = null; if (testMode) { removedEntity = this.findOne(primaryKey.getEntityName(), primaryKey, false); } int num = helper.removeByPrimaryKey(primaryKey); // doCacheClear ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR, EntityEcaHandler.OP_REMOVE, primaryKey, false); this.clearCacheLine(primaryKey); this.saveEntitySyncRemoveInfo(primaryKey); if (testMode) { if (removedEntity != null) { storeForTestRollback(new TestOperation(OperationType.DELETE, removedEntity)); } } ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_REMOVE, primaryKey, false); TransactionUtil.commit(beganTransaction); return num; } catch (Exception e) { String errMsg = "Failure in removeByPrimaryKey operation for entity [" + primaryKey.getEntityName() + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#removeValue(org.apache.ofbiz.entity.GenericValue) */ @Override public int removeValue(GenericValue value) 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()); 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.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()); // Need to call removedFromDatasource() here because the helper calls removedFromDatasource() on the PK instead of the GenericEntity. value.removedFromDatasource(); // doCacheClear ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR, EntityEcaHandler.OP_REMOVE, value, false); this.clearCacheLine(value); if (testMode) { if (removedValue != null) { storeForTestRollback(new TestOperation(OperationType.DELETE, removedValue)); } } this.saveEntitySyncRemoveInfo(value.getPrimaryKey()); ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_REMOVE, value, false); TransactionUtil.commit(beganTransaction); return num; } catch (Exception e) { String errMsg = "Failure in removeValue operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#removeByAnd(java.lang.String, java.lang.Object) */ @Override public int removeByAnd(String entityName, Object... fields) throws GenericEntityException { return removeByAnd(entityName, UtilMisc.<String, Object>toMap(fields)); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#removeByAnd(java.lang.String, java.util.Map) */ @Override public int removeByAnd(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException { EntityCondition ecl = EntityCondition.makeCondition(fields); return removeByCondition(entityName, ecl); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#removeByCondition(java.lang.String, org.apache.ofbiz.entity.condition.EntityCondition) */ @Override public int removeByCondition(String entityName, EntityCondition condition) throws GenericEntityException { boolean beganTransaction = false; try { if (alwaysUseTransaction) { beganTransaction = TransactionUtil.begin(); } 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(this, modelEntity, condition); if (rowsAffected > 0) { this.clearCacheLine(entityName); } if (testMode) { for (GenericValue entity : removedEntities) { storeForTestRollback(new TestOperation(OperationType.DELETE, entity)); } } TransactionUtil.commit(beganTransaction); return rowsAffected; } catch (Exception e) { String errMsg = "Failure in removeByCondition operation for entity [" + entityName + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#removeRelated(java.lang.String, org.apache.ofbiz.entity.GenericValue) */ @Override public int removeRelated(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 = new HashMap<String, Object>(); for (ModelKeyMap keyMap : relation.getKeyMaps()) { fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName())); } return this.removeByAnd(relation.getRelEntityName(), fields); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#refresh(org.apache.ofbiz.entity.GenericValue) */ @Override public void refresh(GenericValue value) throws GenericEntityException { // always clear cache before the operation clearCacheLine(value); GenericPK pk = value.getPrimaryKey(); GenericValue newValue = this.findOne(pk.getEntityName(), pk, false); value.refreshFromValue(newValue); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#refreshFromCache(org.apache.ofbiz.entity.GenericValue) */ @Override public void refreshFromCache(GenericValue value) throws GenericEntityException { GenericPK pk = value.getPrimaryKey(); GenericValue newValue = findOne(pk.getEntityName(), pk, true); value.refreshFromValue(newValue); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#storeByCondition(java.lang.String, java.util.Map, org.apache.ofbiz.entity.condition.EntityCondition) */ @Override public int storeByCondition(String entityName, Map<String, ? extends Object> fieldsToSet, EntityCondition condition) throws GenericEntityException { boolean beganTransaction = false; try { if (alwaysUseTransaction) { beganTransaction = TransactionUtil.begin(); } 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(this, modelEntity, fieldsToSet, condition); if (rowsAffected > 0) { this.clearCacheLine(entityName); } if (testMode) { for (GenericValue entity : updatedEntities) { storeForTestRollback(new TestOperation(OperationType.UPDATE, entity)); } } TransactionUtil.commit(beganTransaction); return rowsAffected; } catch (Exception e) { String errMsg = "Failure in storeByCondition operation for entity [" + entityName + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#store(org.apache.ofbiz.entity.GenericValue) */ @Override public int store(GenericValue value) 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()); ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_STORE, value, false); // if audit log on for any fields, save old value before the update so we still have both if (value.getModelEntity().getHasFieldWithAuditLog()) { createEntityAuditLogAll(value, true, false); } GenericValue updatedEntity = null; if (testMode) { updatedEntity = this.findOne(value.getEntityName(), value.getPrimaryKey(), false); } int retVal = helper.store(value); // doCacheClear ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR, EntityEcaHandler.OP_STORE, value, false); this.clearCacheLine(value); if (testMode) { storeForTestRollback(new TestOperation(OperationType.UPDATE, updatedEntity)); } // refresh the valueObject to get the new version if (value.lockEnabled()) { refresh(value); } ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_STORE, value, false); TransactionUtil.commit(beganTransaction); return retVal; } catch (Exception e) { String errMsg = "Failure in store operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#storeAll(java.util.List) */ @Override public int storeAll(List<GenericValue> values) throws GenericEntityException { return this.storeAll(values, new EntityStoreOptions()); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#storeAll(java.util.List, org.apache.ofbiz.entity.util.EntityStoreOptions) */ @Override public int storeAll(List<GenericValue> values, EntityStoreOptions storeOptions) throws GenericEntityException { if (values == null) { return 0; } // if no store options passed, use default if (storeOptions == null) storeOptions = new EntityStoreOptions(); int numberChanged = 0; boolean beganTransaction = false; try { beganTransaction = TransactionUtil.begin(); for (GenericValue value: values) { String entityName = value.getEntityName(); GenericPK primaryKey = value.getPrimaryKey(); GenericHelper helper = getEntityHelper(entityName); // exists? // NOTE: don't use findByPrimaryKey because we don't want to the ECA events to fire and such if (!primaryKey.isPrimaryKey()) { throw new GenericModelException("[GenericDelegator.storeAll] One of the passed primary keys is not a valid primary key: " + primaryKey); } GenericValue existing = null; try { existing = helper.findByPrimaryKey(primaryKey); } catch (GenericEntityNotFoundException e) { existing = null; } if (existing == null) { if (storeOptions.isCreateDummyFks()) { value.checkFks(true); } this.create(value); numberChanged++; } else { // don't send fields that are the same, and if no fields have changed, update nothing ModelEntity modelEntity = value.getModelEntity(); GenericValue toStore = GenericValue.create(this, modelEntity, value.getPrimaryKey()); boolean atLeastOneField = false; Iterator<ModelField> nonPksIter = modelEntity.getNopksIterator(); while (nonPksIter.hasNext()) { ModelField modelField = nonPksIter.next(); String fieldName = modelField.getName(); if (value.containsKey(fieldName)) { Object fieldValue = value.get(fieldName); Object oldValue = existing.get(fieldName); if (!UtilObject.equalsHelper(oldValue, fieldValue)) { toStore.put(fieldName, fieldValue); atLeastOneField = true; } } } if (atLeastOneField) { if (storeOptions.isCreateDummyFks()) { value.checkFks(true); } numberChanged += this.store(toStore); } } } TransactionUtil.commit(beganTransaction); return numberChanged; } catch (Exception e) { String errMsg = "Failure in storeAll operation: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#removeAll(java.lang.String) */ @Override public int removeAll(String entityName) throws GenericEntityException { return removeByAnd(entityName, (Map<String, Object>) null); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#removeAll(java.util.List) */ @Override public int removeAll(List<? extends GenericEntity> dummyPKs) throws GenericEntityException { if (dummyPKs == null) { return 0; } boolean beganTransaction = false; int numRemoved = 0; try { for (GenericEntity value: dummyPKs) { if (value.containsPrimaryKey()) { numRemoved += this.removeByPrimaryKey(value.getPrimaryKey()); } else { numRemoved += this.removeByAnd(value.getEntityName(), value.getAllFields()); } } TransactionUtil.commit(beganTransaction); return numRemoved; } catch (Exception e) { String errMsg = "Failure in removeAll operation: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } // ====================================== // ======= Find Methods ================= // ====================================== /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#findOne(java.lang.String, boolean, java.lang.Object) */ @Override public GenericValue findOne(String entityName, boolean useCache, Object... fields) throws GenericEntityException { return findOne(entityName, UtilMisc.toMap(fields), useCache); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#findOne(java.lang.String, java.util.Map, boolean) */ @Override public GenericValue findOne(String entityName, Map<String, ? extends Object> fields, boolean useCache) throws GenericEntityException { GenericPK primaryKey = this.makePK(entityName, fields); if (!primaryKey.isPrimaryKey()) { throw new GenericModelException("[GenericDelegator.findOne] Passed primary key is not a valid primary key: " + primaryKey); } EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(entityName); if (useCache) { ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CHECK, EntityEcaHandler.OP_FIND, primaryKey, false); GenericValue value = cache.get(primaryKey); if (value == GenericValue.NULL_VALUE) { return null; } 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; ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_FIND, primaryKey, false); try { value = helper.findByPrimaryKey(primaryKey); } catch (GenericEntityNotFoundException e) { } if (value != null) { value.setDelegator(this); } 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); TransactionUtil.commit(beganTransaction); return value; } catch (Exception e) { String errMsg = "Failure in findOne operation for entity [" + entityName + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#findByPrimaryKeyPartial(org.apache.ofbiz.entity.GenericPK, java.util.Set) */ @Override 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) { } if (value != null) value.setDelegator(this); ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_FIND, primaryKey, false); TransactionUtil.commit(beganTransaction); return value; } catch (Exception e) { String errMsg = "Failure in findByPrimaryKeyPartial operation for entity [" + primaryKey.getEntityName() + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /** Finds all Generic entities *@param entityName The Name of the Entity as defined in the entity XML file * @see org.apache.ofbiz.entity.Delegator#findAll(java.lang.String, boolean) */ @Override public List<GenericValue> findAll(String entityName, boolean useCache) throws GenericEntityException { return this.findList(entityName, null, null, null, null, useCache); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#findByAnd(java.lang.String, java.util.Map, java.util.List, boolean) */ @Override public List<GenericValue> findByAnd(String entityName, Map<String, ? extends Object> fields, List<String> orderBy, boolean useCache) throws GenericEntityException { return this.findList(entityName, EntityCondition.makeCondition(fields), null, orderBy, null, useCache); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#find(java.lang.String, org.apache.ofbiz.entity.condition.EntityCondition, org.apache.ofbiz.entity.condition.EntityCondition, java.util.Set, java.util.List, org.apache.ofbiz.entity.util.EntityFindOptions) */ @Override 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); } if (havingEntityCondition != null) { havingEntityCondition.checkCondition(modelEntity); } ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_FIND, dummyValue, false); GenericHelper helper = getEntityHelper(modelEntity.getEntityName()); EntityListIterator eli = helper.findListIteratorByCondition(this, modelEntity, whereEntityCondition, havingEntityCondition, fieldsToSelect, orderBy, findOptions); eli.setDelegator(this); ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_FIND, dummyValue, false); return eli; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#findList(java.lang.String, org.apache.ofbiz.entity.condition.EntityCondition, java.util.Set, java.util.List, org.apache.ofbiz.entity.util.EntityFindOptions, boolean) */ @Override 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.cache.get(entityName, entityCondition, orderBy); if (cacheList != null) { return cacheList; } } boolean beganTransaction = false; try { if (alwaysUseTransaction) { beganTransaction = TransactionUtil.begin(); } EntityListIterator eli = null; List<GenericValue> list = null; try { eli = this.find(entityName, entityCondition, null, fieldsToSelect, orderBy, findOptions); list = eli.getCompleteList(); } finally { if (eli != null) { try { eli.close(); } catch (Exception exc) {} } } if (useCache) { ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_PUT, EntityEcaHandler.OP_FIND, dummyValue, false); this.cache.put(entityName, entityCondition, orderBy, list); } TransactionUtil.commit(beganTransaction); return list; } catch (Exception e) { String errMsg = "Failure in findByCondition operation for entity [" + entityName + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#findListIteratorByCondition(org.apache.ofbiz.entity.model.DynamicViewEntity, org.apache.ofbiz.entity.condition.EntityCondition, org.apache.ofbiz.entity.condition.EntityCondition, java.util.Collection, java.util.List, org.apache.ofbiz.entity.util.EntityFindOptions) */ @Override 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(this, modelViewEntity, whereEntityCondition, havingEntityCondition, fieldsToSelect, orderBy, findOptions); eli.setDelegator(this); //TODO: add decrypt fields return eli; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#findCountByCondition(java.lang.String, org.apache.ofbiz.entity.condition.EntityCondition, org.apache.ofbiz.entity.condition.EntityCondition, org.apache.ofbiz.entity.util.EntityFindOptions) */ @Override 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); } if (havingEntityCondition != null) { havingEntityCondition.checkCondition(modelEntity); } ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_FIND, dummyValue, false); GenericHelper helper = getEntityHelper(modelEntity.getEntityName()); long count = helper.findCountByCondition(this, modelEntity, whereEntityCondition, havingEntityCondition, findOptions); ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_FIND, dummyValue, false); TransactionUtil.commit(beganTransaction); return count; } catch (Exception e) { String errMsg = "Failure in findListIteratorByCondition operation for entity [DynamicView]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getMultiRelation(org.apache.ofbiz.entity.GenericValue, java.lang.String, java.lang.String, java.util.List) */ @Override 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); List<GenericValue> result = helper.findByMultiRelation(value, modelRelationOne, modelEntityOne, modelRelationTwo, modelEntityTwo, orderBy); TransactionUtil.commit(beganTransaction); return result; } catch (Exception e) { String errMsg = "Failure in getMultiRelation operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); TransactionUtil.rollback(beganTransaction, errMsg, e); throw new GenericEntityException(e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getRelated(java.lang.String, java.util.Map, java.util.List, org.apache.ofbiz.entity.GenericValue, boolean) */ @Override public List<GenericValue> getRelated(String relationName, Map<String, ? extends Object> byAndFields, List<String> orderBy, GenericValue value, boolean useCache) 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 = new HashMap<String, Object>(); if (byAndFields != null) { fields.putAll(byAndFields); } for (ModelKeyMap keyMap : relation.getKeyMaps()) { fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName())); } return this.findByAnd(relation.getRelEntityName(), fields, orderBy, useCache); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getRelatedDummyPK(java.lang.String, java.util.Map, org.apache.ofbiz.entity.GenericValue) */ @Override 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 = new HashMap<String, Object>(); if (byAndFields != null) { fields.putAll(byAndFields); } for (ModelKeyMap keyMap : relation.getKeyMaps()) { fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName())); } return GenericPK.create(this, relatedEntity, fields); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getRelatedOne(java.lang.String, org.apache.ofbiz.entity.GenericValue, boolean) */ @Override public GenericValue getRelatedOne(String relationName, GenericValue value, boolean useCache) 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 = new HashMap<String, Object>(); for (ModelKeyMap keyMap : relation.getKeyMaps()) { fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName())); } return this.findOne(relation.getRelEntityName(), fields, useCache); } // ====================================== // ======= Cache Related Methods ======== // ====================================== /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearAllCaches() */ @Override public void clearAllCaches() { this.clearAllCaches(true); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearAllCaches(boolean) */ @Override public void clearAllCaches(boolean distribute) { cache.clear(); if (!distribute) { return; } DistributedCacheClear dcc = getDistributedCacheClear(); if (dcc != null) { dcc.clearAllCaches(); } if (this.crypto != null) { this.crypto.clearKeyCache(); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearCacheLine(java.lang.String) */ @Override public void clearCacheLine(String entityName) { cache.remove(entityName); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearCacheLine(java.lang.String, java.lang.Object) */ @Override public void clearCacheLine(String entityName, Object... fields) { clearCacheLine(entityName, UtilMisc.<String, Object>toMap(fields)); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearCacheLine(java.lang.String, java.util.Map) */ @Override public void clearCacheLine(String entityName, Map<String, ? extends Object> fields) { // if no fields passed, do the all cache quickly and return if (fields == null) { 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(this, entity, fields); this.clearCacheLineFlexible(dummyValue); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearCacheLineFlexible(org.apache.ofbiz.entity.GenericEntity) */ @Override public void clearCacheLineFlexible(GenericEntity dummyPK) { this.clearCacheLineFlexible(dummyPK, true); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearCacheLineFlexible(org.apache.ofbiz.entity.GenericEntity, boolean) */ @Override public void clearCacheLineFlexible(GenericEntity dummyPK, boolean distribute) { if (dummyPK != null) { //if never cached, then don't bother clearing if (dummyPK.getModelEntity().getNeverCache()) return; cache.remove(dummyPK); if (!distribute) { return; } DistributedCacheClear dcc = getDistributedCacheClear(); if (dcc != null) { dcc.distributedClearCacheLineFlexible(dummyPK); } } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearCacheLineByCondition(java.lang.String, org.apache.ofbiz.entity.condition.EntityCondition) */ @Override public void clearCacheLineByCondition(String entityName, EntityCondition condition) { clearCacheLineByCondition(entityName, condition, true); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearCacheLineByCondition(java.lang.String, org.apache.ofbiz.entity.condition.EntityCondition, boolean) */ @Override 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; } cache.remove(entityName, condition); if (!distribute) { return; } DistributedCacheClear dcc = getDistributedCacheClear(); if (dcc != null) { dcc.distributedClearCacheLineByCondition(entityName, condition); } } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearCacheLine(org.apache.ofbiz.entity.GenericPK) */ @Override public void clearCacheLine(GenericPK primaryKey) { this.clearCacheLine(primaryKey, true); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearCacheLine(org.apache.ofbiz.entity.GenericPK, boolean) */ @Override public void clearCacheLine(GenericPK primaryKey, boolean distribute) { if (primaryKey == null) { return; } //if never cached, then don't bother clearing if (primaryKey.getModelEntity().getNeverCache()) { return; } cache.remove(primaryKey); if (!distribute) { return; } DistributedCacheClear dcc = getDistributedCacheClear(); if (dcc != null) { dcc.distributedClearCacheLine(primaryKey); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearCacheLine(org.apache.ofbiz.entity.GenericValue) */ @Override public void clearCacheLine(GenericValue value) { this.clearCacheLine(value, true); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearCacheLine(org.apache.ofbiz.entity.GenericValue, boolean) */ @Override public void clearCacheLine(GenericValue value, boolean distribute) { // 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; } cache.remove(value); if (!distribute) { return; } DistributedCacheClear dcc = getDistributedCacheClear(); if (dcc != null) { dcc.distributedClearCacheLine(value); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearAllCacheLinesByDummyPK(java.util.Collection) */ @Override public void clearAllCacheLinesByDummyPK(Collection<GenericPK> dummyPKs) { if (dummyPKs == null) { return; } for (GenericEntity entity: dummyPKs) { this.clearCacheLineFlexible(entity); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#clearAllCacheLinesByValue(java.util.Collection) */ @Override public void clearAllCacheLinesByValue(Collection<GenericValue> values) { if (values == null) { return; } for (GenericValue value: values) { this.clearCacheLine(value); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getFromPrimaryKeyCache(org.apache.ofbiz.entity.GenericPK) */ @Override public GenericValue getFromPrimaryKeyCache(GenericPK primaryKey) { if (primaryKey == null) { return null; } GenericValue value = cache.get(primaryKey); if (value == GenericValue.NULL_VALUE) { return null; } return value; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#putInPrimaryKeyCache(org.apache.ofbiz.entity.GenericPK, org.apache.ofbiz.entity.GenericValue) */ @Override public void putInPrimaryKeyCache(GenericPK primaryKey, GenericValue value) { if (primaryKey == null) { return; } if (primaryKey.getModelEntity().getNeverCache()) { if (Debug.warningOn()) { Debug.logWarning("Tried to put a value of the " + value.getEntityName() + " entity in the BY PRIMARY KEY cache but this entity has never-cache set to true, not caching.", module); } return; } // before going into the cache, make this value immutable value.setImmutable(); cache.put(primaryKey, value); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#putAllInPrimaryKeyCache(java.util.List) */ @Override public void putAllInPrimaryKeyCache(List<GenericValue> values) { if (values == null) { return; } for (GenericValue value: values) { this.putInPrimaryKeyCache(value.getPrimaryKey(), value); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#setDistributedCacheClear(org.apache.ofbiz.entity.util.DistributedCacheClear) */ @Override public void setDistributedCacheClear(DistributedCacheClear distributedCacheClear) { this.distributedCacheClear.set(new ConstantFuture<DistributedCacheClear>(distributedCacheClear)); } // ======= XML Related Methods ======== /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#readXmlDocument(java.net.URL) */ @Override public List<GenericValue> readXmlDocument(URL url) throws SAXException, ParserConfigurationException, java.io.IOException { if (url == null) { return null; } return this.makeValues(UtilXml.readXmlDocument(url, false)); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makeValues(org.w3c.dom.Document) */ @Override public List<GenericValue> makeValues(Document document) { if (document == null) { return null; } List<GenericValue> values = new LinkedList<GenericValue>(); Element docElement = document.getDocumentElement(); if (docElement == null) { return null; } if (!"entity-engine-xml".equals(docElement.getTagName())) { Debug.logError("[GenericDelegator.makeValues] Root node was not <entity-engine-xml>", module); throw new java.lang.IllegalArgumentException("Root node was not <entity-engine-xml>"); } docElement.normalize(); Node curChild = docElement.getFirstChild(); if (curChild != null) { do { if (curChild.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element) curChild; GenericValue value = this.makeValue(element); if (value != null) { values.add(value); } } } while ((curChild = curChild.getNextSibling()) != null); } else { Debug.logWarning("[GenericDelegator.makeValues] No child nodes found in document.", module); } return values; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makePK(org.w3c.dom.Element) */ @Override public GenericPK makePK(Element element) { GenericValue value = makeValue(element); return value.getPrimaryKey(); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makeValue(org.w3c.dom.Element) */ @Override public GenericValue makeValue(Element element) { if (element == null) { return null; } String entityName = element.getTagName(); // if a dash or colon is in the tag name, grab what is after it if (entityName.indexOf('-') > 0) { entityName = entityName.substring(entityName.indexOf('-') + 1); } if (entityName.indexOf(':') > 0) { entityName = entityName.substring(entityName.indexOf(':') + 1); } GenericValue value = this.makeValue(entityName); ModelEntity modelEntity = value.getModelEntity(); Iterator<ModelField> modelFields = modelEntity.getFieldsIterator(); while (modelFields.hasNext()) { ModelField modelField = modelFields.next(); String name = modelField.getName(); String attr = element.getAttribute(name); if (UtilValidate.isNotEmpty(attr)) { // GenericEntity.makeXmlElement() sets null values to GenericEntity.NULL_FIELD.toString(), so look for // that and treat it as null if (GenericEntity.NULL_FIELD.toString().equals(attr)) { value.set(name, null); } else { value.setString(name, attr); } } else { // if no attribute try a subelement Element subElement = UtilXml.firstChildElement(element, name); if (subElement != null) { value.setString(name, UtilXml.elementValue(subElement)); } } } return value; } // ======= Misc Methods ======== 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; } //if (!"find".equals(currentOperation)) { // Debug.logWarning("evalRules for entity " + value.getEntityName() + ", currentOperation " + currentOperation + ", event " + event, module); //} entityEcaHandler.evalRules(currentOperation, eventMap, event, value, isError); } } protected EntityEcaRuleRunner<?> getEcaRuleRunner(String entityName) { if (this.testRollbackInProgress) { return createEntityEcaRuleRunner(null, null); } return createEntityEcaRuleRunner(getEntityEcaHandler(), entityName); } protected static <T> EntityEcaRuleRunner<T> createEntityEcaRuleRunner(EntityEcaHandler<T> entityEcaHandler, String entityName) { return new EntityEcaRuleRunner<T>(entityEcaHandler, entityEcaHandler != null ? entityEcaHandler.getEntityEventMap(entityName) : null); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#setEntityEcaHandler(org.apache.ofbiz.entity.eca.EntityEcaHandler) */ @Override public <T> void setEntityEcaHandler(EntityEcaHandler<T> entityEcaHandler) { this.entityEcaHandler.set(new ConstantFuture<EntityEcaHandler<?>>(entityEcaHandler)); this.warnNoEcaHandler = false; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getEntityEcaHandler() */ @Override public <T> EntityEcaHandler<T> getEntityEcaHandler() { Future<EntityEcaHandler<?>> future = this.entityEcaHandler.get(); try { return UtilGenerics.cast(future != null ? future.get() : null); } catch (ExecutionException e) { Debug.logError(e, "Could not fetch EntityEcaHandler from the asynchronous instantiation", module); } catch (InterruptedException e) { Debug.logError(e, "Could not fetch EntityEcaHandler from the asynchronous instantiation", module); } return null; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getNextSeqId(java.lang.String) */ @Override public String getNextSeqId(String seqName) { return this.getNextSeqId(seqName, 1); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getNextSeqId(java.lang.String, long) */ @Override 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.delegatorInfo.getSequencedIdPrefix())) { return this.delegatorInfo.getSequencedIdPrefix() + nextSeqLong.toString(); } else { return nextSeqLong.toString(); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getNextSeqIdLong(java.lang.String) */ @Override public Long getNextSeqIdLong(String seqName) { return this.getNextSeqIdLong(seqName, 1); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getNextSeqIdLong(java.lang.String, long) */ public Long getNextSeqIdLong(String seqName, long staggerMax) { try { SequenceUtil sequencer = this.AtomicRefSequencer.get(); if (sequencer == null) { ModelEntity seqEntity = this.getModelEntity("SequenceValueItem"); sequencer = new SequenceUtil(this.getEntityHelperInfo("SequenceValueItem"), seqEntity, "seqName", "seqId"); if (!AtomicRefSequencer.compareAndSet(null, sequencer)) { sequencer = this.AtomicRefSequencer.get(); } } ModelEntity seqModelEntity = null; try { seqModelEntity = getModelReader().getModelEntity(seqName); } catch (GenericEntityException e) { Debug.logInfo("Entity definition not found for sequence name " + seqName, module); } Long newSeqId = sequencer == null ? null : sequencer.getNextSeqId(seqName, staggerMax, seqModelEntity); return newSeqId; } catch (Exception e) { String errMsg = "Failure in getNextSeqIdLong operation for seqName [" + seqName + "]: " + e.toString() + ". Rolling back transaction."; Debug.logError(e, errMsg, module); throw new GeneralRuntimeException(errMsg, e); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#setSequencer(org.apache.ofbiz.entity.util.SequenceUtil) */ @Override public void setSequencer(SequenceUtil sequencer) { this.AtomicRefSequencer.set(sequencer); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#refreshSequencer() */ @Override public void refreshSequencer() { this.AtomicRefSequencer.set(null); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#setNextSubSeqId(org.apache.ofbiz.entity.GenericValue, java.lang.String, int, int) */ @Override public void setNextSubSeqId(GenericValue value, String seqFieldName, int numericPadding, int incrementBy) { if (value != null && UtilValidate.isEmpty(value.getString(seqFieldName))) { String sequencedIdPrefix = this.delegatorInfo.getSequencedIdPrefix(); value.remove(seqFieldName); GenericValue lookupValue = this.makeValue(value.getEntityName()); lookupValue.setPKFields(value); boolean beganTransaction = false; try { if (alwaysUseTransaction) { beganTransaction = TransactionUtil.begin(); } // get values in whatever order, we will go through all of them to find the highest value List<GenericValue> allValues = this.findByAnd(value.getEntityName(), lookupValue, null, false); //Debug.logInfo("Get existing values from entity " + value.getEntityName() + " with lookupValue: " + lookupValue + ", and the seqFieldName: " + seqFieldName + ", and the results are: " + allValues, module); Integer highestSeqVal = null; for (GenericValue curValue: allValues) { String currentSeqId = curValue.getString(seqFieldName); if (currentSeqId != null) { if (UtilValidate.isNotEmpty(sequencedIdPrefix)) { if (currentSeqId.startsWith(sequencedIdPrefix)) { currentSeqId = currentSeqId.substring(sequencedIdPrefix.length()); } else { continue; } } try { int seqVal = Integer.parseInt(currentSeqId); if (highestSeqVal == null || seqVal > highestSeqVal.intValue()) { highestSeqVal = Integer.valueOf(seqVal); } } catch (Exception e) { Debug.logWarning("Error in make-next-seq-id converting SeqId [" + currentSeqId + "] in field: " + seqFieldName + " from entity: " + value.getEntityName() + " to a number: " + e.toString(), module); } } } int seqValToUse = (highestSeqVal == null ? 1 : highestSeqVal.intValue() + incrementBy); String newSeqId = sequencedIdPrefix + UtilFormatOut.formatPaddedNumber(seqValToUse, numericPadding); value.set(seqFieldName, newSeqId); // only commit the transaction if we started one... TransactionUtil.commit(beganTransaction); } catch (Exception e) { String errMsg = "Failure in setNextSubSeqId 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); } Debug.logError(e, "Error making next seqId", module); } } } @Override public Object encryptFieldValue(String entityName, ModelField.EncryptMethod encryptMethod, Object fieldValue) throws EntityCryptoException { if (encryptMethod == null) { encryptMethod = ModelField.EncryptMethod.TRUE; } if (fieldValue != null) { if (fieldValue instanceof String && UtilValidate.isEmpty(fieldValue)) { return fieldValue; } return this.crypto.encrypt(entityName, encryptMethod, fieldValue); } return fieldValue; } @Override @Deprecated public Object decryptFieldValue(String entityName, String encValue) throws EntityCryptoException { if (UtilValidate.isNotEmpty(encValue)) { return this.crypto.decrypt(entityName, ModelField.EncryptMethod.TRUE, encValue); } return null; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#encryptFieldValue(java.lang.String, java.lang.Object) */ @Override public Object decryptFieldValue(String entityName, ModelField.EncryptMethod encryptMethod, String encValue) throws EntityCryptoException { if (UtilValidate.isNotEmpty(encValue)) { return this.crypto.decrypt(entityName, encryptMethod, encValue); } return null; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#setEntityCrypto(org.apache.ofbiz.entity.util.EntityCrypto) */ @Override public void setEntityCrypto(EntityCrypto crypto) { this.crypto = crypto; } protected void absorbList(List<GenericValue> lst) { if (lst == null) { return; } for (GenericValue value: lst) { value.setDelegator(this); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#getCache() */ @Override public Cache getCache() { return cache; } protected void createEntityAuditLogAll(GenericValue value, boolean isUpdate, boolean isRemove) throws GenericEntityException { Timestamp nowTimestamp = UtilDateTime.nowTimestamp(); for (ModelField mf: value.getModelEntity().getFieldsUnmodifiable()) { if (mf.getEnableAuditLog()) { createEntityAuditLogSingle(value, mf, isUpdate, isRemove, nowTimestamp); } } } protected void createEntityAuditLogSingle(GenericValue value, ModelField mf, boolean isUpdate, boolean isRemove, Timestamp nowTimestamp) throws GenericEntityException { if (value == null || mf == null || !mf.getEnableAuditLog() || this.testRollbackInProgress) { return; } String newValueText = null; String oldValueText = null; 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) { oldValueText = "[ERROR] Old value not found even though it was an update or remove"; } } else { // lookup old value Object oldValue = oldGv.get(mf.getName()); if (oldValue != null) { oldValueText = oldValue.toString(); if (oldValueText.length() > 250) { oldValueText = oldValueText.substring(0, 250); } } } if (!isRemove) { Object newValue = value.get(mf.getName()); if (newValue != null) { newValueText = newValue.toString(); if (newValueText.length() > 250) { newValueText = newValueText.substring(0, 250); } } } if (!(newValueText == null ? "" : newValueText).equals((oldValueText == null ? "" : oldValueText))) { // only save changed values 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); entityAuditLog.set("newValueText", newValueText); entityAuditLog.set("oldValueText", oldValueText); entityAuditLog.set("changedDate", nowTimestamp); entityAuditLog.set("changedByInfo", getCurrentUserIdentifier()); entityAuditLog.set("changedSessionInfo", getCurrentSessionIdentifier()); this.create(entityAuditLog); } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#cloneDelegator(java.lang.String) */ @Override public Delegator cloneDelegator(String delegatorFullName) { // 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). GenericDelegator newDelegator = new GenericDelegator(); newDelegator.modelReader = this.modelReader; newDelegator.modelGroupReader = this.modelGroupReader; newDelegator.setDelegatorNames(UtilValidate.isNotEmpty(delegatorFullName) ? delegatorFullName : this.delegatorFullName); // set the delegatorBaseName to be the same so that configuration settings all work the same as the current // delegator, allowing the new delegatorFullName to not match a delegator name in the entityengine.xml file newDelegator.delegatorBaseName = this.delegatorBaseName; newDelegator.delegatorInfo = this.delegatorInfo; newDelegator.cache = this.cache; newDelegator.distributedCacheClear.set(this.distributedCacheClear.get()); newDelegator.originalDelegatorName = getOriginalDelegatorName(); newDelegator.entityEcaHandler.set(this.entityEcaHandler.get()); newDelegator.crypto = this.crypto; // In case this delegator is in testMode give it a reference to // the rollback list newDelegator.testMode = this.testMode; testOperationsUpdater.set(newDelegator, this.testOperations); // not setting the sequencer so that we have unique sequences. return newDelegator; } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#cloneDelegator() */ @Override public Delegator cloneDelegator() { return this.cloneDelegator(this.delegatorFullName); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#makeTestDelegator(java.lang.String) */ @Override public Delegator makeTestDelegator(String delegatorName) { GenericDelegator testDelegator = (GenericDelegator) this.cloneDelegator(delegatorName); testDelegator.entityEcaHandler.set(null); testDelegator.initEntityEcaHandler(); testDelegator.setTestMode(true); return testDelegator; } private void setTestMode(boolean testMode) { this.testMode = testMode; if (testMode) { testOperationsUpdater.set(this, new LinkedBlockingDeque<TestOperation>()); } else { this.testOperations.clear(); } } private void storeForTestRollback(TestOperation testOperation) { if (!this.testMode || this.testRollbackInProgress) { throw new IllegalStateException("An attempt was made to store a TestOperation during rollback or outside of test mode"); } this.testOperations.add(testOperation); } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#rollback() */ @Override public void rollback() { if (!this.testMode) { Debug.logError("Rollback requested outside of testmode", module); } this.testMode = false; this.testRollbackInProgress = true; if (Debug.infoOn()) { Debug.logInfo("Rolling back " + testOperations.size() + " entity operations", module); } while (!this.testOperations.isEmpty()) { TestOperation testOperation = this.testOperations.pollLast(); if (testOperation == null) { break; } try { if (testOperation.getOperation().equals(OperationType.INSERT)) { this.removeValue(testOperation.getValue()); } else if (testOperation.getOperation().equals(OperationType.UPDATE)) { this.store(testOperation.getValue()); } else if (testOperation.getOperation().equals(OperationType.DELETE)) { this.create(testOperation.getValue()); } } catch (GenericEntityException e) { Debug.logWarning(e.toString(), module); } } this.testOperations.clear(); this.testRollbackInProgress = false; this.testMode = true; } public final 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; } } /* (non-Javadoc) * @see org.apache.ofbiz.entity.Delegator#initDistributedCacheClear() */ @Override public void initDistributedCacheClear() { // Nothing to do if already assigned: the class loader has already been called, the class instantiated and casted to DistributedCacheClear if (this.distributedCacheClear.get() != null) { return; } Callable<DistributedCacheClear> creator = new Callable<DistributedCacheClear>() { public DistributedCacheClear call() { return createDistributedCacheClear(); } }; FutureTask<DistributedCacheClear> futureTask = new FutureTask<DistributedCacheClear>(creator); if (distributedCacheClear.compareAndSet(null, futureTask)) { ExecutionPool.GLOBAL_BATCH.submit(futureTask); } } protected DistributedCacheClear createDistributedCacheClear() { // If useDistributedCacheClear is false do nothing: the distributedCacheClear member field with a null value would cause dcc code to do nothing if (useDistributedCacheClear()) { //time to do some tricks with manual class loading that resolves circular dependencies, like calling services ClassLoader loader = Thread.currentThread().getContextClassLoader(); // initialize the distributedCacheClear mechanism String distributedCacheClearClassName = this.delegatorInfo.getDistributedCacheClearClassName(); try { Class<?> dccClass = loader.loadClass(distributedCacheClearClassName); DistributedCacheClear distributedCacheClear = UtilGenerics.cast(dccClass.newInstance()); distributedCacheClear.setDelegator(this, this.delegatorInfo.getDistributedCacheClearUserLoginId()); return distributedCacheClear; } 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.logVerbose("Distributed Cache Clear System disabled for delegator [" + delegatorFullName + "]", module); } return null; } protected DistributedCacheClear getDistributedCacheClear() { Future<DistributedCacheClear> future = this.distributedCacheClear.get(); try { return future != null ? future.get() : null; } catch (ExecutionException e) { Debug.logError(e, "Could not fetch DistributedCacheClear from the asynchronous instantiation", module); } catch (InterruptedException e) { Debug.logError(e, "Could not fetch DistributedCacheClear from the asynchronous instantiation", module); } return null; } @Override public boolean useDistributedCacheClear() { return this.delegatorInfo.getDistributedCacheClearEnabled(); } @Override public String getCurrentSessionIdentifier() { List<String> curValList = getSessionIdentifierStack(); return curValList.size() > 0 ? curValList.get(0) : null; } @Override public String getCurrentUserIdentifier() { List<String> curValList = getUserIdentifierStack(); return curValList.size() > 0 ? curValList.get(0) : null; } }