blob: ba77efd582fb0883037eab1337e71d5f4763e3e0 [file] [log] [blame]
/*
* 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 static org.ofbiz.api.authorization.BasicPermissions.*;
import org.ofbiz.api.authorization.AccessController;
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;
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) {
initDelegatorData();
}
}
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 {
ThreadContext.pushExecutionArtifact(value);
AccessController accessController = ThreadContext.getAccessController();
boolean beganTransaction = false;
try {
accessController.checkPermission(Create);
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 {
ThreadContext.popExecutionArtifact();
// 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 {
ThreadContext.pushExecutionArtifact(value);
AccessController accessController = ThreadContext.getAccessController();
boolean beganTransaction = false;
try {
GenericValue checkValue = this.findOne(value.getEntityName(), value.getPrimaryKey(), false);
if (checkValue != null) {
accessController.checkPermission(Update);
} else {
accessController.checkPermission(Create);
}
if (alwaysUseTransaction) {
beganTransaction = TransactionUtil.begin();
}
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 {
ThreadContext.popExecutionArtifact();
// 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);
ThreadContext.pushExecutionArtifact(modelEntity);
AccessController accessController = ThreadContext.getAccessController();
ListIterator<GenericValue> li = accessController.applyFilters((ListIterator<GenericValue>) eli);
ThreadContext.popExecutionArtifact();
return (EntityListIterator) li;
}
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);
AccessController accessController = ThreadContext.getAccessController();
results = accessController.applyFilters(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);
AccessController accessController = ThreadContext.getAccessController();
results = accessController.applyFilters(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);
ThreadContext.pushExecutionArtifact("GenericDelegator.findByCondition", entityName);
AccessController accessController = ThreadContext.getAccessController();
eli = (EntityListIterator) accessController.applyFilters((ListIterator<GenericValue>) eli);
ThreadContext.popExecutionArtifact();
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) {
ThreadContext.pushExecutionArtifact("GenericDelegator.findList", entityName);
AccessController accessController = ThreadContext.getAccessController();
cacheList = accessController.applyFilters(cacheList);
ThreadContext.popExecutionArtifact();
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);
}
ThreadContext.pushExecutionArtifact("GenericDelegator.findList", entityName);
AccessController accessController = ThreadContext.getAccessController();
list = accessController.applyFilters(list);
ThreadContext.popExecutionArtifact();
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
ThreadContext.pushExecutionArtifact("GenericDelegator.findListIteratorByCondition", modelViewEntity.getEntityName());
AccessController accessController = ThreadContext.getAccessController();
eli = (EntityListIterator) accessController.applyFilters((ListIterator<GenericValue>) eli);
ThreadContext.popExecutionArtifact();
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 ThreadContext.getLocale();
}
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 initDelegatorData() {
synchronized (this.delegatorData) {
if (this.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
ThreadContext.runUnprotected();
try {
this.delegatorData.crypto = new EntityCrypto(this);
} finally {
ThreadContext.endRunUnprotected();
}
// 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 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) {
GenericValue value = makeValue(element);
return value.getPrimaryKey();
}
public GenericPK makePK(String entityName) {
return this.makePK(entityName, (Map<String, Object>) null);
}
public GenericPK makePK(String entityName, Map<String, ? extends Object> fields) {
ModelEntity entity = this.getModelEntity(entityName);
if (entity == null) {
throw new IllegalArgumentException("[GenericDelegator.makePK] could not find entity for entityName: " + entityName);
}
GenericPK pk = GenericPK.create(entity, fields);
pk.setDelegator(this);
return pk;
}
public GenericPK makePK(String entityName, Object... fields) {
return makePK(entityName, UtilMisc.<String, Object> toMap(fields));
}
public GenericPK makePKSingle(String entityName, Object singlePkValue) {
ModelEntity entity = this.getModelEntity(entityName);
if (entity == null) {
throw new IllegalArgumentException("[GenericDelegator.makePKSingle] could not find entity for entityName: " + entityName);
}
GenericPK pk = GenericPK.create(entity, singlePkValue);
pk.setDelegator(this);
return pk;
}
public GenericDelegator makeTestDelegator(String delegatorName) {
DelegatorImpl testDelegator = (DelegatorImpl) this.cloneDelegator(delegatorName);
testDelegator.setTestMode(true);
return testDelegator;
}
public GenericValue makeValidValue(String entityName, Map<String, ? extends Object> fields) {
ModelEntity entity = this.getModelEntity(entityName);
if (entity == null) {
throw new IllegalArgumentException("[GenericDelegator.makeValidValue] could not find entity for entityName: " + entityName);
}
GenericValue value = GenericValue.create(entity);
value.setPKFields(fields, true);
value.setNonPKFields(fields, true);
value.setDelegator(this);
return value;
}
public GenericValue makeValidValue(String entityName, Object... fields) {
return makeValidValue(entityName, UtilMisc.<String, Object> toMap(fields));
}
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 (attr != null && attr.length() > 0) {
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;
}
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;
}
public GenericValue makeValue(String entityName, Map<String, ? extends Object> fields) {
ModelEntity entity = this.getModelEntity(entityName);
if (entity == null) {
throw new IllegalArgumentException("[GenericDelegator.makeValue] could not find entity for entityName: " + entityName);
}
GenericValue value = GenericValue.create(entity, fields);
value.setDelegator(this);
return value;
}
public GenericValue makeValue(String entityName, Object... fields) {
return makeValue(entityName, UtilMisc.<String, Object> toMap(fields));
}
public List<GenericValue> makeValues(Document document) {
if (document == null)
return null;
List<GenericValue> values = FastList.newInstance();
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;
}
public GenericValue makeValueSingle(String entityName, Object singlePkValue) {
ModelEntity entity = this.getModelEntity(entityName);
if (entity == null) {
throw new IllegalArgumentException("[GenericDelegator.makeValue] could not find entity for entityName: " + entityName);
}
GenericValue value = GenericValue.create(entity, singlePkValue);
value.setDelegator(this);
return value;
}
public void putAllInPrimaryKeyCache(List<GenericValue> values) {
if (values == null)
return;
for (GenericValue value : values) {
this.putInPrimaryKeyCache(value.getPrimaryKey(), value);
}
}
public void putInPrimaryKeyCache(GenericPK primaryKey, GenericValue value) {
if (primaryKey == null)
return;
if (primaryKey.getModelEntity().getNeverCache()) {
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();
this.delegatorData.cache.put(primaryKey, value);
}
// ======= XML Related Methods ========
public List<GenericValue> readXmlDocument(URL url) throws SAXException, ParserConfigurationException, java.io.IOException {
if (url == null)
return null;
return this.makeValues(UtilXml.readXmlDocument(url, false));
}
public void refresh(GenericValue value) throws GenericEntityException {
this.refresh(value, true);
}
public void refresh(GenericValue value, boolean doCacheClear) throws GenericEntityException {
if (doCacheClear) {
// always clear cache before the operation
clearCacheLine(value);
}
GenericPK pk = value.getPrimaryKey();
GenericValue newValue = this.findOne(pk.getEntityName(), pk, false);
value.refreshFromValue(newValue);
}
public void refreshFromCache(GenericValue value) throws GenericEntityException {
GenericPK pk = value.getPrimaryKey();
GenericValue newValue = findOne(pk.getEntityName(), pk, true);
value.refreshFromValue(newValue);
}
public void refreshSequencer() {
this.delegatorData.sequencer = null;
}
public int removeAll(List<? extends GenericEntity> dummyPKs) throws GenericEntityException {
return this.removeAll(dummyPKs, true);
}
public int removeAll(List<? extends GenericEntity> dummyPKs, boolean doCacheClear) 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(), doCacheClear);
} else {
numRemoved += this.removeByAnd(value.getEntityName(), value.getAllFields(), doCacheClear);
}
}
return numRemoved;
} catch (GenericEntityException e) {
String errMsg = "Failure in removeAll operation: " + 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 int removeAll(String entityName) throws GenericEntityException {
return removeByAnd(entityName, (Map<String, Object>) null);
}
public int removeByAnd(String entityName, boolean doCacheClear, Object... fields) throws GenericEntityException {
return removeByAnd(entityName, UtilMisc.<String, Object> toMap(fields), doCacheClear);
}
public int removeByAnd(String entityName, Map<String, ? extends Object> fields) throws GenericEntityException {
return this.removeByAnd(entityName, fields, true);
}
public int removeByAnd(String entityName, Map<String, ? extends Object> fields, boolean doCacheClear) throws GenericEntityException {
EntityCondition ecl = EntityCondition.makeCondition(fields);
return removeByCondition(entityName, ecl, doCacheClear);
}
public int removeByAnd(String entityName, Object... fields) throws GenericEntityException {
return removeByAnd(entityName, UtilMisc.<String, Object> toMap(fields));
}
public int removeByCondition(String entityName, EntityCondition condition) throws GenericEntityException {
return this.removeByCondition(entityName, condition, true);
}
public int removeByCondition(String entityName, EntityCondition condition, boolean doCacheClear) throws GenericEntityException {
ThreadContext.pushExecutionArtifact("GenericDelegator.removeByCondition", entityName);
AccessController accessController = ThreadContext.getAccessController();
boolean beganTransaction = false;
try {
accessController.checkPermission(Delete);
if (alwaysUseTransaction) {
beganTransaction = TransactionUtil.begin();
}
if (doCacheClear) {
// always clear cache before the operation
this.clearCacheLineByCondition(entityName, condition);
}
ModelEntity modelEntity = getModelReader().getModelEntity(entityName);
GenericHelper helper = getEntityHelper(entityName);
List<GenericValue> removedEntities = null;
if (testMode) {
removedEntities = this.findList(entityName, condition, null, null, null, false);
}
int rowsAffected = helper.removeByCondition(modelEntity, condition);
if (testMode) {
for (GenericValue entity : removedEntities) {
storeForTestRollback(new TestOperation(OperationType.DELETE, entity));
}
}
return rowsAffected;
} catch (GenericEntityException e) {
String errMsg = "Failure in removeByCondition operation for entity [" + entityName + "]: " + e.toString() + ". Rolling back transaction.";
Debug.logError(e, errMsg, module);
try {
// only rollback the transaction if we started one...
TransactionUtil.rollback(beganTransaction, errMsg, e);
} catch (GenericEntityException e2) {
Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
}
// after rolling back, rethrow the exception
throw e;
} finally {
ThreadContext.popExecutionArtifact();
// only commit the transaction if we started one... this will throw
// an exception if it fails
TransactionUtil.commit(beganTransaction);
}
}
public int removeByPrimaryKey(GenericPK primaryKey) throws GenericEntityException {
int retVal = this.removeByPrimaryKey(primaryKey, true);
return retVal;
}
public int removeByPrimaryKey(GenericPK primaryKey, boolean doCacheClear) throws GenericEntityException {
ThreadContext.pushExecutionArtifact(primaryKey);
AccessController accessController = ThreadContext.getAccessController();
boolean beganTransaction = false;
try {
accessController.checkPermission(Delete);
if (alwaysUseTransaction) {
beganTransaction = TransactionUtil.begin();
}
EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(primaryKey.getEntityName());
ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE, EntityEcaHandler.OP_REMOVE, primaryKey, false);
GenericHelper helper = getEntityHelper(primaryKey.getEntityName());
if (doCacheClear) {
// always clear cache before the operation
ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR, EntityEcaHandler.OP_REMOVE, primaryKey, false);
this.clearCacheLine(primaryKey);
}
ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_REMOVE, primaryKey, false);
// if audit log on for any fields, save old value before
// removing so it's still there
if (primaryKey != null && primaryKey.getModelEntity().getHasFieldWithAuditLog()) {
createEntityAuditLogAll(this.findOne(primaryKey.getEntityName(), primaryKey, false), true, true);
}
GenericValue removedEntity = null;
if (testMode) {
removedEntity = this.findOne(primaryKey.entityName, primaryKey, false);
}
int num = helper.removeByPrimaryKey(primaryKey);
this.saveEntitySyncRemoveInfo(primaryKey);
if (testMode) {
storeForTestRollback(new TestOperation(OperationType.DELETE, removedEntity));
}
ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_REMOVE, primaryKey, false);
return num;
} catch (GenericEntityException e) {
String errMsg = "Failure in removeByPrimaryKey operation for entity [" + primaryKey.getEntityName() + "]: " + e.toString() + ". Rolling back transaction.";
Debug.logError(e, errMsg, module);
try {
// only rollback the transaction if we started one...
TransactionUtil.rollback(beganTransaction, errMsg, e);
} catch (GenericEntityException e2) {
Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
}
// after rolling back, rethrow the exception
throw e;
} finally {
ThreadContext.popExecutionArtifact();
// only commit the transaction if we started one... this will throw an
// exception if it fails
TransactionUtil.commit(beganTransaction);
}
}
public int removeRelated(String relationName, GenericValue value) throws GenericEntityException {
return this.removeRelated(relationName, value, true);
}
public int removeRelated(String relationName, GenericValue value, boolean doCacheClear) throws GenericEntityException {
ModelEntity modelEntity = value.getModelEntity();
ModelRelation relation = modelEntity.getRelation(relationName);
if (relation == null) {
throw new GenericModelException("Could not find relation for relationName: " + relationName + " for value " + value);
}
Map<String, Object> fields = FastMap.newInstance();
for (int i = 0; i < relation.getKeyMapsSize(); i++) {
ModelKeyMap keyMap = relation.getKeyMap(i);
fields.put(keyMap.getRelFieldName(), value.get(keyMap.getFieldName()));
}
return this.removeByAnd(relation.getRelEntityName(), fields, doCacheClear);
}
public int removeValue(GenericValue value) throws GenericEntityException {
return this.removeValue(value, true);
}
public int removeValue(GenericValue value, boolean doCacheClear) throws GenericEntityException {
ThreadContext.pushExecutionArtifact(value);
AccessController accessController = ThreadContext.getAccessController();
// 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 {
accessController.checkPermission(Delete);
if (alwaysUseTransaction) {
beganTransaction = TransactionUtil.begin();
}
EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(value.getEntityName());
ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE, EntityEcaHandler.OP_REMOVE, value, false);
GenericHelper helper = getEntityHelper(value.getEntityName());
if (doCacheClear) {
ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR, EntityEcaHandler.OP_REMOVE, value, false);
this.clearCacheLine(value);
}
ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_REMOVE, value, false);
// if audit log on for any fields, save old value before actual
// remove
if (value != null && value.getModelEntity().getHasFieldWithAuditLog()) {
createEntityAuditLogAll(value, true, true);
}
GenericValue removedValue = null;
if (testMode) {
removedValue = this.findOne(value.getEntityName(), value.getPrimaryKey(), false);
}
int num = helper.removeByPrimaryKey(value.getPrimaryKey());
if (testMode) {
storeForTestRollback(new TestOperation(OperationType.DELETE, removedValue));
}
this.saveEntitySyncRemoveInfo(value.getPrimaryKey());
ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_REMOVE, value, false);
return num;
} catch (GenericEntityException e) {
String errMsg = "Failure in removeValue operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction.";
Debug.logError(e, errMsg, module);
try {
// only rollback the transaction if we started one...
TransactionUtil.rollback(beganTransaction, errMsg, e);
} catch (GenericEntityException e2) {
Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
}
// after rolling back, rethrow the exception
throw e;
} finally {
ThreadContext.popExecutionArtifact();
// only commit the transaction if we started one... this will throw
// an exception if it fails
TransactionUtil.commit(beganTransaction);
}
}
public void rollback() {
if (!this.testMode) {
Debug.logError("Rollback requested outside of testmode", module);
}
this.testMode = false;
this.testRollbackInProgress = true;
synchronized (testOperations) {
Debug.logInfo("Rolling back " + testOperations.size() + " entity operations", module);
ListIterator<TestOperation> iterator = this.testOperations.listIterator(this.testOperations.size());
while (iterator.hasPrevious()) {
TestOperation testOperation = iterator.previous();
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;
}
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);
}
}
public void setDistributedCacheClear(DistributedCacheClear distributedCacheClear) {
this.delegatorData.distributedCacheClear = distributedCacheClear;
}
public void setEntityCrypto(EntityCrypto crypto) {
this.delegatorData.crypto = crypto;
}
@SuppressWarnings("unchecked")
public void setEntityEcaHandler(EntityEcaHandler entityEcaHandler) {
this.delegatorData.entityEcaHandler = entityEcaHandler;
}
public void setNextSubSeqId(GenericValue value, String seqFieldName, int numericPadding, int incrementBy) {
if (value != null && UtilValidate.isEmpty(value.getString(seqFieldName))) {
String sequencedIdPrefix = this.getDelegatorInfo().sequencedIdPrefix;
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);
// 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);
}
}
}
public void setLocale(Locale locale) {
ThreadContext.setLocale(locale);
}
public void setSessionIdentifier(String identifier) {
this.sessionIdentifier = identifier;
}
public void setUserIdentifier(String identifier) {
this.userIdentifier = identifier;
}
public void setSequencer(SequenceUtil sequencer) {
this.delegatorData.sequencer = sequencer;
}
private void setTestMode(boolean testMode) {
this.testMode = testMode;
if (testMode) {
this.testOperations = FastList.newInstance();
} else {
this.testOperations.clear();
}
}
public int store(GenericValue value) throws GenericEntityException {
return this.store(value, true);
}
public int store(GenericValue value, boolean doCacheClear) throws GenericEntityException {
ThreadContext.pushExecutionArtifact(value);
AccessController accessController = ThreadContext.getAccessController();
boolean beganTransaction = false;
try {
accessController.checkPermission(Update);
if (alwaysUseTransaction) {
beganTransaction = TransactionUtil.begin();
}
EntityEcaRuleRunner<?> ecaRunner = this.getEcaRuleRunner(value.getEntityName());
ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE, EntityEcaHandler.OP_STORE, value, false);
GenericHelper helper = getEntityHelper(value.getEntityName());
if (doCacheClear) {
// always clear cache before the operation
ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR, EntityEcaHandler.OP_STORE, value, false);
this.clearCacheLine(value);
}
ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_STORE, value, false);
this.encryptFields(value);
// if audit log on for any fields, save old value before the update
// so we still have both
if (value != null && value.getModelEntity().getHasFieldWithAuditLog()) {
createEntityAuditLogAll(value, true, false);
}
GenericValue updatedEntity = null;
if (testMode) {
updatedEntity = this.findOne(value.entityName, value.getPrimaryKey(), false);
}
int retVal = helper.store(value);
if (testMode) {
storeForTestRollback(new TestOperation(OperationType.UPDATE, updatedEntity));
}
// refresh the valueObject to get the new version
if (value.lockEnabled()) {
refresh(value, doCacheClear);
}
ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_STORE, value, false);
return retVal;
} catch (GenericEntityException e) {
String errMsg = "Failure in store operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction.";
Debug.logError(e, errMsg, module);
try {
// only rollback the transaction if we started one...
TransactionUtil.rollback(beganTransaction, errMsg, e);
} catch (GenericEntityException e2) {
Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
}
// after rolling back, rethrow the exception
throw e;
} finally {
ThreadContext.popExecutionArtifact();
// only commit the transaction if we started one... this will throw
// an exception if it fails
TransactionUtil.commit(beganTransaction);
}
}
public int storeAll(List<GenericValue> values) throws GenericEntityException {
return this.storeAll(values, true);
}
public int storeAll(List<GenericValue> values, boolean doCacheClear) throws GenericEntityException {
return this.storeAll(values, doCacheClear, false);
}
public int storeAll(List<GenericValue> values, boolean doCacheClear, boolean createDummyFks) throws GenericEntityException {
if (values == null) {
return 0;
}
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);
this.decryptFields(existing);
} catch (GenericEntityNotFoundException e) {
existing = null;
}
if (existing == null) {
if (createDummyFks) {
value.checkFks(true);
}
this.create(value, doCacheClear);
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(modelEntity, (Map<String, ? extends Object>) value.getPrimaryKey());
toStore.setDelegator(this);
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 ((fieldValue == null && oldValue != null) || (fieldValue != null && !fieldValue.equals(oldValue))) {
toStore.put(fieldName, fieldValue);
atLeastOneField = true;
}
}
}
if (atLeastOneField) {
if (createDummyFks) {
value.checkFks(true);
}
numberChanged += this.store(toStore, doCacheClear);
}
}
}
return numberChanged;
} catch (GenericEntityException e) {
String errMsg = "Failure in storeAll operation: " + 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 int storeByCondition(String entityName, Map<String, ? extends Object> fieldsToSet, EntityCondition condition) throws GenericEntityException {
return storeByCondition(entityName, fieldsToSet, condition, true);
}
public int storeByCondition(String entityName, Map<String, ? extends Object> fieldsToSet, EntityCondition condition, boolean doCacheClear) throws GenericEntityException {
ThreadContext.pushExecutionArtifact("GenericDelegator.storeByCondition", entityName);
AccessController accessController = ThreadContext.getAccessController();
boolean beganTransaction = false;
try {
accessController.checkPermission(Update);
if (alwaysUseTransaction) {
beganTransaction = TransactionUtil.begin();
}
if (doCacheClear) {
// always clear cache before the operation
this.clearCacheLineByCondition(entityName, condition);
}
ModelEntity modelEntity = getModelReader().getModelEntity(entityName);
GenericHelper helper = getEntityHelper(entityName);
List<GenericValue> updatedEntities = null;
if (testMode) {
updatedEntities = this.findList(entityName, condition, null, null, null, false);
}
int rowsAffected = helper.storeByCondition(modelEntity, fieldsToSet, condition);
if (testMode) {
for (GenericValue entity : updatedEntities) {
storeForTestRollback(new TestOperation(OperationType.UPDATE, entity));
}
}
return rowsAffected;
} catch (GenericEntityException e) {
String errMsg = "Failure in storeByCondition operation for entity [" + entityName + "]: " + e.toString() + ". Rolling back transaction.";
Debug.logError(e, errMsg, module);
try {
// only rollback the transaction if we started one...
TransactionUtil.rollback(beganTransaction, errMsg, e);
} catch (GenericEntityException e2) {
Debug.logError(e2, "[GenericDelegator] Could not rollback transaction: " + e2.toString(), module);
}
// after rolling back, rethrow the exception
throw e;
} finally {
ThreadContext.popExecutionArtifact();
// only commit the transaction if we started one... this will throw
// an exception if it fails
TransactionUtil.commit(beganTransaction);
}
}
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);
}
}