Author: jleroux
Date: Wed Nov 25 08:15:42 2015
New Revision: 1716319
URL: http://svn.apache.org/viewvc?rev=1716319&view=rev
Log:
A patch from Anne Jessel for "Entity ECAs not triggered correctly when using
Delegator.storeAll() method" https://issues.apache.org/jira/browse/OFBIZ-3847
As reported by Martin Kreidenweis
The conditions don't work when updating (not creating) entities using the
Delegator.storeAll() method. E.g. the following condition does not work:
<eca entity="Product" operation="create-store" event="return">
<condition field-name="autoCreateKeywords" operator="not-equals"
value="N"/>
<action service="indexProductKeywords" mode="sync"
value-attr="productInstance"/>
</eca>
The indexProductKeywords service is called anyway when the product is updated
and the autoCreateKeywords was "N" and stays "N". It works correctly for newly
created products.
The problem is in the method GenericDelegator.storeAll(), where unchanged field
values are not passed down to the store() method. The store method calls the
ECA engine, which does not receive the unchanged values at all and thus cannot
evaluate the EECA conditions correctly.
Scott's comment:We could consider having EntityEcaCondition.eval() perform a db
lookup if any of the fields it needs to evaluate are missing. If they are
missing it could fully populate the entity with the missing fields so that a
lookup is only required at most once per delegator operation. If no ECA
conditions require any missing fields then the lookup wouldn't be performed, so
the performance penalty would only be incurred when necessary.
Anne: I've created a patch modeled after Scott's suggestion. I'd appreciate
someone reviewing it. It does work for me, however I am concerned that it might
fail when the value of a field that is part of the EECA condition is being
changed from non-null to null using GenericDelegator.storeAll, because of the
way storeAll works. There may be a simple solution I've missed.
jleroux: After reviewing and waiting for Anne's feedback, I commit because
even if in some cases it would not work it's at least better than current
situation
Modified:
ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaCondition.java
ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaRule.java
Modified:
ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaCondition.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaCondition.java?rev=1716319&r1=1716318&r2=1716319&view=diff
==============================================================================
---
ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaCondition.java
(original)
+++
ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaCondition.java
Wed Nov 25 08:15:42 2015
@@ -18,11 +18,13 @@
*******************************************************************************/
package org.ofbiz.entityext.eca;
+import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.ObjectType;
+import org.ofbiz.base.util.UtilValidate;
import org.ofbiz.entity.GenericEntity;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.service.DispatchContext;
@@ -116,4 +118,16 @@ public final class EntityEcaCondition im
buf.append("[").append(format).append("]");
return buf.toString();
}
+
+ protected List<String> getFieldNames() {
+ List<String> fieldNameList = new ArrayList<String>();
+ if( UtilValidate.isNotEmpty(lhsValueName) ) {
+ fieldNameList.add(lhsValueName);
+ }
+ if( !constant && UtilValidate.isNotEmpty(rhsValueName)) {
+ fieldNameList.add(rhsValueName);
+ }
+ return fieldNameList;
+ }
+
}
Modified:
ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaRule.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaRule.java?rev=1716319&r1=1716318&r2=1716319&view=diff
==============================================================================
---
ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaRule.java
(original)
+++
ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaRule.java
Wed Nov 25 08:15:42 2015
@@ -27,8 +27,10 @@ import java.util.Set;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.UtilXml;
+import org.ofbiz.entity.Delegator;
import org.ofbiz.entity.GenericEntity;
import org.ofbiz.entity.GenericEntityException;
+import org.ofbiz.entity.GenericValue;
import org.ofbiz.service.DispatchContext;
import org.w3c.dom.Element;
@@ -47,6 +49,7 @@ public final class EntityEcaRule impleme
private final List<EntityEcaCondition> conditions;
private final List<Object> actionsAndSets;
private boolean enabled = true;
+ private final List<String> conditionFieldNames = new ArrayList<String>();
public EntityEcaRule(Element eca) {
this.entityName = eca.getAttribute("entity");
@@ -57,9 +60,13 @@ public final class EntityEcaRule impleme
ArrayList<Object> actionsAndSets = new ArrayList<Object>();
for (Element element: UtilXml.childElementList(eca)) {
if ("condition".equals(element.getNodeName())) {
- conditions.add(new EntityEcaCondition(element, true));
+ EntityEcaCondition ecaCond = new EntityEcaCondition(element,
true);
+ conditions.add(ecaCond);
+ conditionFieldNames.addAll(ecaCond.getFieldNames());
} else if ("condition-field".equals(element.getNodeName())) {
- conditions.add(new EntityEcaCondition(element, false));
+ EntityEcaCondition ecaCond = new EntityEcaCondition(element,
false);
+ conditions.add(ecaCond);
+ conditionFieldNames.addAll(ecaCond.getFieldNames());
} else if ("action".equals(element.getNodeName())) {
actionsAndSets.add(new EntityEcaAction(element));
} else if ("set".equals(element.getNodeName())) {
@@ -116,6 +123,22 @@ public final class EntityEcaRule impleme
if (!"any".equals(this.operationName) &&
this.operationName.indexOf(currentOperation) == -1) {
return;
}
+ // Are fields tested in a condition missing? If so, we need to load
them
+ List<String> fieldsToLoad = new ArrayList<String>();
+ for( String conditionFieldName : conditionFieldNames) {
+ if( value.get(conditionFieldName) == null) {
+ fieldsToLoad.add(conditionFieldName);
+ }
+ }
+
+ if( !fieldsToLoad.isEmpty()) {
+ Delegator delegator = dctx.getDelegator();
+ GenericValue oldValue = delegator.findOne(entityName,
value.getPrimaryKey(), false);
+ for( String fieldName : fieldsToLoad) {
+ value.put(fieldName, oldValue.get(fieldName));
+ }
+ }
+
Map<String, Object> context = new HashMap<String, Object>();
context.putAll(value);