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