You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by nm...@apache.org on 2016/03/19 09:04:16 UTC
svn commit: r1735737 - in /ofbiz/trunk/framework/service:
servicedef/services_test_se.xml
src/org/ofbiz/service/engine/EntityAutoEngine.java
src/org/ofbiz/service/test/ServiceEntityAutoTests.java
Author: nmalin
Date: Sat Mar 19 08:04:16 2016
New Revision: 1735737
URL: http://svn.apache.org/viewvc?rev=1735737&view=rev
Log:
Related to the thread http://ofbiz.135035.n4.nabble.com/entity-auto-and-cancel-operation-td4676929.html on the dev mailing list and the issue OFBIZ-6892, this commit manage the action expire on entity-auto engine.
When you call expire on a entity :
* if a date field is present on service attribute, OFBiz try to expire it with the given value or with now date
* else try to expire thruDate field
* else try to expire *ThruDate or thru*Date field
With the new action I refactoring the code to separate each action on dedicate function.
the unit test associate to expire action was updated.
Modified:
ofbiz/trunk/framework/service/servicedef/services_test_se.xml
ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/EntityAutoEngine.java
ofbiz/trunk/framework/service/src/org/ofbiz/service/test/ServiceEntityAutoTests.java
Modified: ofbiz/trunk/framework/service/servicedef/services_test_se.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/servicedef/services_test_se.xml?rev=1735737&r1=1735736&r2=1735737&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/servicedef/services_test_se.xml (original)
+++ ofbiz/trunk/framework/service/servicedef/services_test_se.xml Sat Mar 19 08:04:16 2016
@@ -91,6 +91,15 @@ under the License.
engine="entity-auto" default-entity-name="Testing" invoke="delete">
<auto-attributes include="pk" mode="IN" optional="false"/>
</service>
+ <service name="testEntityAutoExpireTestingNodeMember" auth="false"
+ engine="entity-auto" default-entity-name="TestingNodeMember" invoke="expire">
+ <auto-attributes include="pk" mode="IN" optional="false"/>
+ </service>
+ <service name="testEntityAutoExpireTestFieldType" auth="false"
+ engine="entity-auto" default-entity-name="TestFieldType" invoke="expire">
+ <auto-attributes include="pk" mode="IN" optional="false"/>
+ <attribute name="dateTimeField" mode="IN" type="Timestamp" optional="true"/>
+ </service>
<!-- lock wait timeout retry testing services - a scenario that we can't do automatically with the single service because the parent owns the tx we have to have end before it will succeed -->
<service name="testServiceLockWaitTimeoutRetryCantRecover" engine="java" auth="false" transaction-timeout="2"
Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/EntityAutoEngine.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/EntityAutoEngine.java?rev=1735737&r1=1735736&r2=1735737&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/EntityAutoEngine.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/EntityAutoEngine.java Sat Mar 19 08:04:16 2016
@@ -21,6 +21,7 @@ package org.ofbiz.service.engine;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -48,6 +49,7 @@ public final class EntityAutoEngine exte
public static final String module = EntityAutoEngine.class.getName();
public static final String resource = "ServiceErrorUiLabels";
+ private static final List<String> availableInvokeActionNames = UtilMisc.toList("create", "update", "delete", "expire");
public EntityAutoEngine(ServiceDispatcher dispatcher) {
super(dispatcher);
@@ -69,12 +71,10 @@ public final class EntityAutoEngine exte
// static java service methods should be: public Map<String, Object> methodName(DispatchContext dctx, Map<String, Object> context)
DispatchContext dctx = dispatcher.getLocalContext(localName);
Locale locale = (Locale) parameters.get("locale");
- Map<String, Object> localContext = new HashMap<String, Object>();
- localContext.put("parameters", parameters);
Map<String, Object> result = ServiceUtil.returnSuccess();
// check the package and method names
- if (modelService.invoke == null || (!"create".equals(modelService.invoke) && !"update".equals(modelService.invoke) && !"delete".equals(modelService.invoke))) {
+ if (modelService.invoke == null || !availableInvokeActionNames.contains(modelService.invoke)) {
throw new GenericServiceException("In Service [" + modelService.name + "] the invoke value must be create, update, or delete for entity-auto engine");
}
@@ -108,280 +108,401 @@ public final class EntityAutoEngine exte
}
}
- if ("create".equals(modelService.invoke)) {
- GenericValue newEntity = dctx.getDelegator().makeValue(modelEntity.getEntityName());
+ switch (modelService.invoke) {
+ case "create":
+ result = invokeCreate(dctx, parameters, modelService, modelEntity, allPksInOnly, pkFieldNameOutOnly);
+ break;
+ case "update":
+ result = invokeUpdate(dctx, parameters, modelService, modelEntity, allPksInOnly);
+ break;
+ case "delete":
+ result = invokeDelete(dctx, parameters, modelService, modelEntity, allPksInOnly);
+ break;
+ case "expire":
+ result = invokeExpire(dctx, parameters, modelService, modelEntity, allPksInOnly);
+ if (ServiceUtil.isSuccess(result)) {
+ result = invokeUpdate(dctx, parameters, modelService, modelEntity, allPksInOnly);
+ }
+ break;
+ default:
+ break;
+ }
+ GenericValue crudValue = (GenericValue) result.get("crudValue");
+ if (crudValue != null) {
+ result.remove("crudValue");
+ result.putAll(modelService.makeValid(crudValue, "OUT"));
+ }
+ } catch (GeneralException e) {
+ Debug.logError(e, "Error doing entity-auto operation for entity [" + modelEntity.getEntityName() + "] in service [" + modelService.name + "]: " + e.toString(), module);
+ return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ServiceEntityAutoOperation", UtilMisc.toMap("entityName", modelEntity.getEntityName(), "serviceName", modelService.name,"errorString", e.toString()), locale));
+ }
- boolean isSinglePk = modelEntity.getPksSize() == 1;
- boolean isDoublePk = modelEntity.getPksSize() == 2;
- Iterator<ModelField> pksIter = modelEntity.getPksIterator();
-
- ModelField singlePkModeField = isSinglePk ? pksIter.next() : null;
- ModelParam singlePkModelParam = isSinglePk ? modelService.getParam(singlePkModeField.getName()) : null;
- boolean isSinglePkIn = isSinglePk ? singlePkModelParam.isIn() : false;
- boolean isSinglePkOut = isSinglePk ? singlePkModelParam.isOut() : false;
-
- ModelParam doublePkPrimaryInParam = null;
- ModelParam doublePkSecondaryOutParam = null;
- ModelField doublePkSecondaryOutField = null;
- if (isDoublePk) {
- ModelField firstPkField = pksIter.next();
- ModelParam firstPkParam = modelService.getParam(firstPkField.getName());
- ModelField secondPkField = pksIter.next();
- ModelParam secondPkParam = modelService.getParam(secondPkField.getName());
- if (firstPkParam.isIn() && secondPkParam.isOut()) {
- doublePkPrimaryInParam = firstPkParam;
- doublePkSecondaryOutParam = secondPkParam;
- doublePkSecondaryOutField = secondPkField;
- } else if (firstPkParam.isOut() && secondPkParam.isIn()) {
- doublePkPrimaryInParam = secondPkParam;
- doublePkSecondaryOutParam = firstPkParam;
- doublePkSecondaryOutField = firstPkField;
- } else {
- // we don't have an IN and an OUT... so do nothing and leave them null
- }
- }
+ return result;
+ }
- if (isSinglePk && isSinglePkOut && !isSinglePkIn) {
- /*
- **** primary sequenced primary key ****
- *
- <auto-attributes include="pk" mode="OUT" optional="false"/>
- *
- <make-value entity-name="Example" value-name="newEntity"/>
- <sequenced-id-to-env sequence-name="Example" env-name="newEntity.exampleId"/> <!-- get the next sequenced ID -->
- <field-to-result field-name="newEntity.exampleId" result-name="exampleId"/>
- <set-nonpk-fields map-name="parameters" value-name="newEntity"/>
- <create-value value-name="newEntity"/>
- *
- */
-
- String sequencedId = dctx.getDelegator().getNextSeqId(modelEntity.getEntityName());
- newEntity.set(singlePkModeField.getName(), sequencedId);
- } else if (isSinglePk && isSinglePkOut && isSinglePkIn) {
- /*
- **** primary sequenced key with optional override passed in ****
- *
- <auto-attributes include="pk" mode="INOUT" optional="true"/>
- *
- <make-value value-name="newEntity" entity-name="Product"/>
- <set-nonpk-fields map-name="parameters" value-name="newEntity"/>
- <set from-field="parameters.productId" field="newEntity.productId"/>
- <if-empty field="newEntity.productId">
- <sequenced-id-to-env sequence-name="Product" env-name="newEntity.productId"/>
- <else>
- <check-id field-name="productId" map-name="newEntity"/>
- <check-errors/>
- </else>
- </if-empty>
- <field-to-result field-name="productId" map-name="newEntity" result-name="productId"/>
- <create-value value-name="newEntity"/>
- *
- */
-
- Object pkValue = parameters.get(singlePkModelParam.name);
- if (UtilValidate.isEmpty(pkValue)) {
- pkValue = dctx.getDelegator().getNextSeqId(modelEntity.getEntityName());
- } else {
- // pkValue passed in, check and if there are problems return an error
+ private static Map<String, Object> invokeCreate(DispatchContext dctx, Map<String, Object> parameters, ModelService modelService, ModelEntity modelEntity, boolean allPksInOnly, List<String> pkFieldNameOutOnly)
+ throws GeneralException {
+ Locale locale = (Locale) parameters.get("locale");
+ Map<String, Object> result = ServiceUtil.returnSuccess();
- if (pkValue instanceof String) {
- StringBuffer errorDetails = new StringBuffer();
- if (!UtilValidate.isValidDatabaseId((String) pkValue, errorDetails)) {
- return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ServiceParameterValueNotValid", UtilMisc.toMap("parameterName", singlePkModelParam.name,"errorDetails", errorDetails), locale));
- }
- }
- }
- newEntity.set(singlePkModeField.getName(), pkValue);
- } else if (isDoublePk && doublePkPrimaryInParam != null && doublePkSecondaryOutParam != null) {
- /*
- **** secondary sequenced primary key ****
- *
- <auto-attributes include="pk" mode="IN" optional="false"/>
- <override name="exampleItemSeqId" mode="OUT"/> <!-- make this OUT rather than IN, we will automatically generate the next sub-sequence ID -->
- *
- <make-value entity-name="ExampleItem" value-name="newEntity"/>
- <set-pk-fields map-name="parameters" value-name="newEntity"/>
- <make-next-seq-id value-name="newEntity" seq-field-name="exampleItemSeqId"/> <!-- this finds the next sub-sequence ID -->
- <field-to-result field-name="newEntity.exampleItemSeqId" result-name="exampleItemSeqId"/>
- <set-nonpk-fields map-name="parameters" value-name="newEntity"/>
- <create-value value-name="newEntity"/>
- */
-
- newEntity.setPKFields(parameters, true);
- dctx.getDelegator().setNextSubSeqId(newEntity, doublePkSecondaryOutField.getName(), 5, 1);
- } else if (allPksInOnly) {
- /*
- **** plain specified primary key ****
- *
- <auto-attributes include="pk" mode="IN" optional="false"/>
- *
- <make-value entity-name="Example" value-name="newEntity"/>
- <set-pk-fields map-name="parameters" value-name="newEntity"/>
- <set-nonpk-fields map-name="parameters" value-name="newEntity"/>
- <create-value value-name="newEntity"/>
- *
- */
- newEntity.setPKFields(parameters, true);
- //with all pks present on parameters, check if the entity is not already exists.
- GenericValue lookedUpValue = PrimaryKeyFinder.runFind(modelEntity, parameters, dctx.getDelegator(), false, true, null, null);
- if (lookedUpValue != null) {
- return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ServiceValueFound", UtilMisc.toMap("pkFields", newEntity.getPkShortValueString()), locale));
- }
- } else {
- /* We haven't all Pk and their are 3 or more, now check if isn't a associate entity with own sequence
- <set-pk-fields map="parameters" value-field="newEntity"/>
- <sequenced-id sequence-name="ExempleItemAssoc" field="newEntity.exempleItemAssocId"/>
- <create-value value-field="newEntity"/>
- */
- if (pkFieldNameOutOnly != null && pkFieldNameOutOnly.size() == 1) {
- newEntity.setPKFields(parameters, true);
- String pkFieldName = pkFieldNameOutOnly.getFirst();
- //if it's a fromDate, don't update it now, it's will be done next step
- if (! "fromDate".equals(pkFieldName)) {
- String pkValue = dctx.getDelegator().getNextSeqId(modelEntity.getEntityName());
- newEntity.set(pkFieldName, pkValue);
- }
- } else {
- throw new GenericServiceException("In Service [" + modelService.name + "] which uses the entity-auto engine with the create invoke option: " +
- "could not find a valid combination of primary key settings to do a known create operation; options include: " +
- "1. a single OUT pk for primary auto-sequencing, " +
- "2. a single INOUT pk for primary auto-sequencing with optional override, " +
- "3. a 2-part pk with one part IN (existing primary pk) and one part OUT (the secondary pk to sub-sequence), " +
- "4. a N-part pk with N-1 part IN and one party OUT only (missing pk is a sub-sequence mainly for entity assoc), " +
- "5. all pk fields are IN for a manually specified primary key");
- }
- }
+ GenericValue newEntity = dctx.getDelegator().makeValue(modelEntity.getEntityName());
+
+ boolean isSinglePk = modelEntity.getPksSize() == 1;
+ boolean isDoublePk = modelEntity.getPksSize() == 2;
+ Iterator<ModelField> pksIter = modelEntity.getPksIterator();
+
+ ModelField singlePkModeField = isSinglePk ? pksIter.next() : null;
+ ModelParam singlePkModelParam = isSinglePk ? modelService.getParam(singlePkModeField.getName()) : null;
+ boolean isSinglePkIn = isSinglePk ? singlePkModelParam.isIn() : false;
+ boolean isSinglePkOut = isSinglePk ? singlePkModelParam.isOut() : false;
+
+ ModelParam doublePkPrimaryInParam = null;
+ ModelParam doublePkSecondaryOutParam = null;
+ ModelField doublePkSecondaryOutField = null;
+ if (isDoublePk) {
+ ModelField firstPkField = pksIter.next();
+ ModelParam firstPkParam = modelService.getParam(firstPkField.getName());
+ ModelField secondPkField = pksIter.next();
+ ModelParam secondPkParam = modelService.getParam(secondPkField.getName());
+ if (firstPkParam.isIn() && secondPkParam.isOut()) {
+ doublePkPrimaryInParam = firstPkParam;
+ doublePkSecondaryOutParam = secondPkParam;
+ doublePkSecondaryOutField = secondPkField;
+ } else if (firstPkParam.isOut() && secondPkParam.isIn()) {
+ doublePkPrimaryInParam = secondPkParam;
+ doublePkSecondaryOutParam = firstPkParam;
+ doublePkSecondaryOutField = firstPkField;
+ } else {
+ // we don't have an IN and an OUT... so do nothing and leave them null
+ }
+ }
+
+ if (isSinglePk && isSinglePkOut && !isSinglePkIn) {
+ /*
+ **** primary sequenced primary key ****
+ *
+ <auto-attributes include="pk" mode="OUT" optional="false"/>
+ *
+ <make-value entity-name="Example" value-name="newEntity"/>
+ <sequenced-id-to-env sequence-name="Example" env-name="newEntity.exampleId"/> <!-- get the next sequenced ID -->
+ <field-to-result field-name="newEntity.exampleId" result-name="exampleId"/>
+ <set-nonpk-fields map-name="parameters" value-name="newEntity"/>
+ <create-value value-name="newEntity"/>
+ *
+ */
+
+ String sequencedId = dctx.getDelegator().getNextSeqId(modelEntity.getEntityName());
+ newEntity.set(singlePkModeField.getName(), sequencedId);
+ } else if (isSinglePk && isSinglePkOut && isSinglePkIn) {
+ /*
+ **** primary sequenced key with optional override passed in ****
+ *
+ <auto-attributes include="pk" mode="INOUT" optional="true"/>
+ *
+ <make-value value-name="newEntity" entity-name="Product"/>
+ <set-nonpk-fields map-name="parameters" value-name="newEntity"/>
+ <set from-field="parameters.productId" field="newEntity.productId"/>
+ <if-empty field="newEntity.productId">
+ <sequenced-id-to-env sequence-name="Product" env-name="newEntity.productId"/>
+ <else>
+ <check-id field-name="productId" map-name="newEntity"/>
+ <check-errors/>
+ </else>
+ </if-empty>
+ <field-to-result field-name="productId" map-name="newEntity" result-name="productId"/>
+ <create-value value-name="newEntity"/>
+ *
+ */
- // handle the case where there is a fromDate in the pk of the entity, and it is optional or undefined in the service def, populate automatically
- ModelField fromDateField = modelEntity.getField("fromDate");
- if (fromDateField != null && fromDateField.getIsPk()) {
- ModelParam fromDateParam = modelService.getParam("fromDate");
- if (fromDateParam == null || parameters.get("fromDate") == null) {
- newEntity.set("fromDate", UtilDateTime.nowTimestamp());
+ Object pkValue = parameters.get(singlePkModelParam.name);
+ if (UtilValidate.isEmpty(pkValue)) {
+ pkValue = dctx.getDelegator().getNextSeqId(modelEntity.getEntityName());
+ } else {
+ // pkValue passed in, check and if there are problems return an error
+
+ if (pkValue instanceof String) {
+ StringBuffer errorDetails = new StringBuffer();
+ if (!UtilValidate.isValidDatabaseId((String) pkValue, errorDetails)) {
+ return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ServiceParameterValueNotValid", UtilMisc.toMap("parameterName", singlePkModelParam.name,"errorDetails", errorDetails), locale));
}
}
+ }
+ newEntity.set(singlePkModeField.getName(), pkValue);
+ } else if (isDoublePk && doublePkPrimaryInParam != null && doublePkSecondaryOutParam != null) {
+ /*
+ **** secondary sequenced primary key ****
+ *
+ <auto-attributes include="pk" mode="IN" optional="false"/>
+ <override name="exampleItemSeqId" mode="OUT"/> <!-- make this OUT rather than IN, we will automatically generate the next sub-sequence ID -->
+ *
+ <make-value entity-name="ExampleItem" value-name="newEntity"/>
+ <set-pk-fields map-name="parameters" value-name="newEntity"/>
+ <make-next-seq-id value-name="newEntity" seq-field-name="exampleItemSeqId"/> <!-- this finds the next sub-sequence ID -->
+ <field-to-result field-name="newEntity.exampleItemSeqId" result-name="exampleItemSeqId"/>
+ <set-nonpk-fields map-name="parameters" value-name="newEntity"/>
+ <create-value value-name="newEntity"/>
+ */
- newEntity.setNonPKFields(parameters, true);
- if (modelEntity.getField("createdDate") != null) {
- newEntity.set("createdDate", UtilDateTime.nowTimestamp());
- if (modelEntity.getField("createdByUserLogin") != null) {
- GenericValue userLogin = (GenericValue) parameters.get("userLogin");
- if (userLogin != null) {
- newEntity.set("createdByUserLogin", userLogin.get("userLoginId"));
- if (modelEntity.getField("lastModifiedByUserLogin") != null) {
- newEntity.set("lastModifiedByUserLogin", userLogin.get("userLoginId"));
- }
- }
- }
- if (modelEntity.getField("lastModifiedDate") != null) {
- newEntity.set("lastModifiedDate", UtilDateTime.nowTimestamp());
+ newEntity.setPKFields(parameters, true);
+ dctx.getDelegator().setNextSubSeqId(newEntity, doublePkSecondaryOutField.getName(), 5, 1);
+ } else if (allPksInOnly) {
+ /*
+ **** plain specified primary key ****
+ *
+ <auto-attributes include="pk" mode="IN" optional="false"/>
+ *
+ <make-value entity-name="Example" value-name="newEntity"/>
+ <set-pk-fields map-name="parameters" value-name="newEntity"/>
+ <set-nonpk-fields map-name="parameters" value-name="newEntity"/>
+ <create-value value-name="newEntity"/>
+ *
+ */
+ newEntity.setPKFields(parameters, true);
+ //with all pks present on parameters, check if the entity is not already exists.
+ GenericValue lookedUpValue = PrimaryKeyFinder.runFind(modelEntity, parameters, dctx.getDelegator(), false, true, null, null);
+ if (lookedUpValue != null) {
+ return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ServiceValueFound", UtilMisc.toMap("pkFields", newEntity.getPkShortValueString()), locale));
+ }
+ } else {
+ /* We haven't all Pk and their are 3 or more, now check if isn't a associate entity with own sequence
+ <set-pk-fields map="parameters" value-field="newEntity"/>
+ <sequenced-id sequence-name="ExempleItemAssoc" field="newEntity.exempleItemAssocId"/>
+ <create-value value-field="newEntity"/>
+ */
+ if (pkFieldNameOutOnly != null && pkFieldNameOutOnly.size() == 1) {
+ newEntity.setPKFields(parameters, true);
+ String pkFieldName = pkFieldNameOutOnly.get(0);
+ //if it's a fromDate, don't update it now, it's will be done next step
+ if (! "fromDate".equals(pkFieldName)) {
+ String pkValue = dctx.getDelegator().getNextSeqId(modelEntity.getEntityName());
+ newEntity.set(pkFieldName, pkValue);
+ }
+ } else {
+ throw new GenericServiceException("In Service [" + modelService.name + "] which uses the entity-auto engine with the create invoke option: " +
+ "could not find a valid combination of primary key settings to do a known create operation; options include: " +
+ "1. a single OUT pk for primary auto-sequencing, " +
+ "2. a single INOUT pk for primary auto-sequencing with optional override, " +
+ "3. a 2-part pk with one part IN (existing primary pk) and one part OUT (the secondary pk to sub-sequence), " +
+ "4. a N-part pk with N-1 part IN and one party OUT only (missing pk is a sub-sequence mainly for entity assoc), " +
+ "5. all pk fields are IN for a manually specified primary key");
+ }
+ }
+
+ // handle the case where there is a fromDate in the pk of the entity, and it is optional or undefined in the service def, populate automatically
+ ModelField fromDateField = modelEntity.getField("fromDate");
+ if (fromDateField != null && fromDateField.getIsPk()) {
+ ModelParam fromDateParam = modelService.getParam("fromDate");
+ if (fromDateParam == null || parameters.get("fromDate") == null) {
+ newEntity.set("fromDate", UtilDateTime.nowTimestamp());
+ }
+ }
+
+ newEntity.setNonPKFields(parameters, true);
+ if (modelEntity.getField("createdDate") != null) {
+ newEntity.set("createdDate", UtilDateTime.nowTimestamp());
+ if (modelEntity.getField("createdByUserLogin") != null) {
+ GenericValue userLogin = (GenericValue) parameters.get("userLogin");
+ if (userLogin != null) {
+ newEntity.set("createdByUserLogin", userLogin.get("userLoginId"));
+ if (modelEntity.getField("lastModifiedByUserLogin") != null) {
+ newEntity.set("lastModifiedByUserLogin", userLogin.get("userLoginId"));
+ } else if (modelEntity.getField("changedByUserLogin") != null) {
+ newEntity.set("changedByUserLogin", userLogin.get("userLoginId"));
}
}
- newEntity.create();
- result.putAll(modelService.makeValid(newEntity, "OUT"));
- } else if ("update".equals(modelService.invoke)) {
- /*
- <auto-attributes include="pk" mode="IN" optional="false"/>
- *
- <entity-one entity-name="ExampleItem" value-name="lookedUpValue"/>
- <set-nonpk-fields value-name="lookedUpValue" map-name="parameters"/>
- <store-value value-name="lookedUpValue"/>
- */
-
- // check to make sure that all primary key fields are defined as IN attributes
- if (!allPksInOnly) {
- throw new GenericServiceException("In Service [" + modelService.name + "] which uses the entity-auto engine with the update invoke option not all pk fields have the mode IN");
- }
+ }
+ if (modelEntity.getField("lastModifiedDate") != null) {
+ newEntity.set("lastModifiedDate", UtilDateTime.nowTimestamp());
+ } else if (modelEntity.getField("changedDate") != null) {
+ newEntity.set("changedDate", UtilDateTime.nowTimestamp());
+ }
+ }
+ newEntity.create();
+ result.put("crudValue", newEntity);
+ return result;
+ }
- GenericValue lookedUpValue = PrimaryKeyFinder.runFind(modelEntity, parameters, dctx.getDelegator(), false, true, null, null);
- if (lookedUpValue == null) {
- return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ServiceValueNotFound", locale));
- }
+ private static Map<String, Object> invokeUpdate(DispatchContext dctx, Map<String, Object> parameters, ModelService modelService, ModelEntity modelEntity, boolean allPksInOnly)
+ throws GeneralException {
+ Locale locale = (Locale) parameters.get("locale");
+ Map<String, Object> localContext = new HashMap<String, Object>();
+ localContext.put("parameters", parameters);
+ Map<String, Object> result = ServiceUtil.returnSuccess();
+ /*
+ <auto-attributes include="pk" mode="IN" optional="false"/>
+ *
+ <entity-one entity-name="ExampleItem" value-name="lookedUpValue"/>
+ <set-nonpk-fields value-name="lookedUpValue" map-name="parameters"/>
+ <store-value value-name="lookedUpValue"/>
+ */
+
+ // check to make sure that all primary key fields are defined as IN attributes
+ if (!allPksInOnly) {
+ throw new GenericServiceException("In Service [" + modelService.name + "] which uses the entity-auto engine with the update invoke option not all pk fields have the mode IN");
+ }
- localContext.put("lookedUpValue", lookedUpValue);
+ GenericValue lookedUpValue = PrimaryKeyFinder.runFind(modelEntity, parameters, dctx.getDelegator(), false, true, null, null);
+ if (lookedUpValue == null) {
+ return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ServiceValueNotFound", locale));
+ }
- // populate the oldStatusId out if there is a service parameter for it, and before we do the set non-pk fields
- /*
- <auto-attributes include="pk" mode="IN" optional="false"/>
- <attribute name="oldStatusId" type="String" mode="OUT" optional="false"/>
- *
- <field-to-result field-name="lookedUpValue.statusId" result-name="oldStatusId"/>
- */
- ModelParam statusIdParam = modelService.getParam("statusId");
- ModelField statusIdField = modelEntity.getField("statusId");
- ModelParam oldStatusIdParam = modelService.getParam("oldStatusId");
- if (statusIdParam != null && statusIdParam.isIn() && oldStatusIdParam != null && oldStatusIdParam.isOut() && statusIdField != null) {
- result.put("oldStatusId", lookedUpValue.get("statusId"));
- }
+ // localContext.put("lookedUpValue", lookedUpValue);
- // do the StatusValidChange check
- /*
- <if-compare-field field="lookedUpValue.statusId" operator="not-equals" to-field="parameters.statusId">
- <!-- if the record exists there should be a statusId, but just in case make it so it won't blow up -->
- <if-not-empty field="lookedUpValue.statusId">
- <!-- if statusId change is not in the StatusValidChange list, complain... -->
- <entity-one entity-name="StatusValidChange" value-name="statusValidChange" auto-field-map="false">
- <field-map field-name="statusId" env-name="lookedUpValue.statusId"/>
- <field-map field-name="statusIdTo" env-name="parameters.statusId"/>
- </entity-one>
- <if-empty field="statusValidChange">
- <!-- no valid change record found? return an error... -->
- <add-error><fail-property resource="CommonUiLabels" property="CommonErrorNoStatusValidChange"/></add-error>
- <check-errors/>
- </if-empty>
- </if-not-empty>
- </if-compare-field>
- */
- String parameterStatusId = (String) parameters.get("statusId");
- if (statusIdParam != null && statusIdParam.isIn() && UtilValidate.isNotEmpty(parameterStatusId) && statusIdField != null) {
- String lookedUpStatusId = (String) lookedUpValue.get("statusId");
- if (UtilValidate.isNotEmpty(lookedUpStatusId) && !parameterStatusId.equals(lookedUpStatusId)) {
- // there was an old status, and in this call we are trying to change it, so do the StatusValidChange check
- GenericValue statusValidChange = dctx.getDelegator().findOne("StatusValidChange", true, "statusId", lookedUpStatusId, "statusIdTo", parameterStatusId);
- if (statusValidChange == null) {
- // uh-oh, no valid change...
- return ServiceUtil.returnError(UtilProperties.getMessage("CommonUiLabels", "CommonErrorNoStatusValidChange", localContext, locale));
- }
- }
+ // populate the oldStatusId out if there is a service parameter for it, and before we do the set non-pk fields
+ /*
+ <auto-attributes include="pk" mode="IN" optional="false"/>
+ <attribute name="oldStatusId" type="String" mode="OUT" optional="false"/>
+ *
+ <field-to-result field-name="lookedUpValue.statusId" result-name="oldStatusId"/>
+ */
+ ModelParam statusIdParam = modelService.getParam("statusId");
+ ModelField statusIdField = modelEntity.getField("statusId");
+ ModelParam oldStatusIdParam = modelService.getParam("oldStatusId");
+ if (statusIdParam != null && statusIdParam.isIn() && oldStatusIdParam != null && oldStatusIdParam.isOut() && statusIdField != null) {
+ result.put("oldStatusId", lookedUpValue.get("statusId"));
+ }
+
+ // do the StatusValidChange check
+ /*
+ <if-compare-field field="lookedUpValue.statusId" operator="not-equals" to-field="parameters.statusId">
+ <!-- if the record exists there should be a statusId, but just in case make it so it won't blow up -->
+ <if-not-empty field="lookedUpValue.statusId">
+ <!-- if statusId change is not in the StatusValidChange list, complain... -->
+ <entity-one entity-name="StatusValidChange" value-name="statusValidChange" auto-field-map="false">
+ <field-map field-name="statusId" env-name="lookedUpValue.statusId"/>
+ <field-map field-name="statusIdTo" env-name="parameters.statusId"/>
+ </entity-one>
+ <if-empty field="statusValidChange">
+ <!-- no valid change record found? return an error... -->
+ <add-error><fail-property resource="CommonUiLabels" property="CommonErrorNoStatusValidChange"/></add-error>
+ <check-errors/>
+ </if-empty>
+ </if-not-empty>
+ </if-compare-field>
+ */
+ String parameterStatusId = (String) parameters.get("statusId");
+ if (statusIdParam != null && statusIdParam.isIn() && UtilValidate.isNotEmpty(parameterStatusId) && statusIdField != null) {
+ String lookedUpStatusId = (String) lookedUpValue.get("statusId");
+ if (UtilValidate.isNotEmpty(lookedUpStatusId) && !parameterStatusId.equals(lookedUpStatusId)) {
+ // there was an old status, and in this call we are trying to change it, so do the StatusValidChange check
+ GenericValue statusValidChange = dctx.getDelegator().findOne("StatusValidChange", true, "statusId", lookedUpStatusId, "statusIdTo", parameterStatusId);
+ if (statusValidChange == null) {
+ // uh-oh, no valid change...
+ return ServiceUtil.returnError(UtilProperties.getMessage("CommonUiLabels", "CommonErrorNoStatusValidChange", localContext, locale));
}
- // NOTE: nothing here to maintain the status history, that should be done with a custom service called by SECA rule
+ }
+ }
+ // NOTE: nothing here to maintain the status history, that should be done with a custom service called by SECA rule
- lookedUpValue.setNonPKFields(parameters, true);
- if (modelEntity.getField("lastModifiedDate") != null) {
- lookedUpValue.set("lastModifiedDate", UtilDateTime.nowTimestamp());
+ lookedUpValue.setNonPKFields(parameters, true);
+ if (modelEntity.getField("lastModifiedDate") != null
+ || modelEntity.getField("changedDate") != null) {
+ if (modelEntity.getField("lastModifiedDate") != null) {
+ lookedUpValue.set("lastModifiedDate", UtilDateTime.nowTimestamp());
+ } else {
+ lookedUpValue.set("changedDate", UtilDateTime.nowTimestamp());
+ }
+ if (modelEntity.getField("lastModifiedByUserLogin") != null
+ || modelEntity.getField("changedByUserLogin") != null) {
+ GenericValue userLogin = (GenericValue) parameters.get("userLogin");
+ if (userLogin != null) {
if (modelEntity.getField("lastModifiedByUserLogin") != null) {
- GenericValue userLogin = (GenericValue) parameters.get("userLogin");
- if (userLogin != null) {
- lookedUpValue.set("lastModifiedByUserLogin", userLogin.get("userLoginId"));
- }
+ lookedUpValue.set("lastModifiedByUserLogin", userLogin.get("userLoginId"));
+ } else {
+ lookedUpValue.set("changedByUserLogin", userLogin.get("userLoginId"));
}
}
- lookedUpValue.store();
- } else if ("delete".equals(modelService.invoke)) {
- /*
- <auto-attributes include="pk" mode="IN" optional="false"/>
- *
- <entity-one entity-name="ExampleItem" value-name="lookedUpValue"/>
- <remove-value value-name="lookedUpValue"/>
- */
-
- // check to make sure that all primary key fields are defined as IN attributes
- if (!allPksInOnly) {
- throw new GenericServiceException("In Service [" + modelService.name + "] which uses the entity-auto engine with the delete invoke option not all pk fields have the mode IN");
- }
+ }
+ }
+ lookedUpValue.store();
+ result.put("crudValue", lookedUpValue);
+ return result;
+ }
- GenericValue lookedUpValue = PrimaryKeyFinder.runFind(modelEntity, parameters, dctx.getDelegator(), false, true, null, null);
- if (lookedUpValue != null) {
- lookedUpValue.remove();
- } else {
- return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ServiceValueNotFoundForRemove", locale));
- }
+ private static Map<String, Object> invokeDelete(DispatchContext dctx, Map<String, Object> parameters, ModelService modelService, ModelEntity modelEntity, boolean allPksInOnly)
+ throws GeneralException {
+ Locale locale = (Locale) parameters.get("locale");
+ /*
+ <auto-attributes include="pk" mode="IN" optional="false"/>
+ *
+ <entity-one entity-name="ExampleItem" value-name="lookedUpValue"/>
+ <remove-value value-name="lookedUpValue"/>
+ */
+
+ // check to make sure that all primary key fields are defined as IN attributes
+ if (!allPksInOnly) {
+ throw new GenericServiceException("In Service [" + modelService.name + "] which uses the entity-auto engine with the delete invoke option not all pk fields have the mode IN");
+ }
+
+ GenericValue lookedUpValue = PrimaryKeyFinder.runFind(modelEntity, parameters, dctx.getDelegator(), false, true, null, null);
+ if (lookedUpValue == null) {
+ return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ServiceValueNotFoundForRemove", locale));
+ }
+ lookedUpValue.remove();
+ return ServiceUtil.returnSuccess();
+ }
+
+ /**
+ * Analyse the entity, service and parameter to resolve the field to update with what value
+ * @param dctx
+ * @param parameters
+ * @param modelService
+ * @param modelEntity
+ * @param lookedUpValue
+ * @param allPksInOnly
+ * @return
+ * @throws GeneralException
+ */
+ private static Map<String, Object> invokeExpire(DispatchContext dctx, Map<String, Object> parameters, ModelService modelService, ModelEntity modelEntity, boolean allPksInOnly)
+ throws GeneralException {
+ Locale locale = (Locale) parameters.get("locale");
+ LinkedList<String> fieldThruDates = new LinkedList<String>();
+ boolean thruDatePresent = false;
+ String fieldDateNameIn = null;
+
+ // check to make sure that all primary key fields are defined as IN attributes
+ if (!allPksInOnly) {
+ throw new GenericServiceException("In Service [" + modelService.name + "] which uses the entity-auto engine with the update invoke option not all pk fields have the mode IN");
+ }
+ GenericValue lookedUpValue = PrimaryKeyFinder.runFind(modelEntity, parameters, dctx.getDelegator(), false, true, null, null);
+ if (lookedUpValue == null) {
+ return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ServiceValueNotFound", locale));
+ }
+
+ //check if a non pk date field is present on parameters
+ for (String fieldDateName : modelEntity.getNoPkFieldNames()) {
+ if ("thruDate".equals(fieldDateName)) {
+ thruDatePresent = true;
+ } else if (fieldDateName.endsWith("ThruDate")) {
+ fieldThruDates.add(fieldDateName);
+ } else if (fieldDateName.startsWith("thru") && fieldDateName.endsWith("Date")) {
+ fieldThruDates.add(fieldDateName);
+ } else if (fieldDateNameIn == null && modelService.getParam(fieldDateName) != null
+ && modelEntity.getField(fieldDateName).getType().contains("date")) {
+ fieldDateNameIn = fieldDateName;
}
- } catch (GeneralException e) {
- Debug.logError(e, "Error doing entity-auto operation for entity [" + modelEntity.getEntityName() + "] in service [" + modelService.name + "]: " + e.toString(), module);
- return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ServiceEntityAutoOperation", UtilMisc.toMap("entityName", modelEntity.getEntityName(), "serviceName", modelService.name,"errorString", e.toString()), locale));
}
- return result;
+ if (Debug.infoOn())
+ Debug.logInfo(" FIELD FOUND : " + fieldDateNameIn + " ## # " + fieldThruDates + " ### " + thruDatePresent, module);
+
+ if (Debug.infoOn())
+ Debug.logInfo(" parameters IN : " + parameters, module);
+ // Resolve the field without value to expire and check if the value is present on parameters or use now
+ if (fieldDateNameIn != null) {
+ if (parameters.get(fieldDateNameIn) == null) parameters.put(fieldDateNameIn, UtilDateTime.nowTimestamp());
+ } else if (thruDatePresent && UtilValidate.isEmpty(lookedUpValue.getTimestamp("thruDate"))) {
+ if (UtilValidate.isEmpty(parameters.get("thruDate"))) parameters.put("thruDate", UtilDateTime.nowTimestamp());
+ } else {
+ for (String fieldDateName: fieldThruDates) {
+ if (UtilValidate.isEmpty(lookedUpValue.getTimestamp(fieldDateName))) {
+ if (UtilValidate.isEmpty(parameters.get(fieldDateName))) parameters.put(fieldDateName, UtilDateTime.nowTimestamp());
+ break;
+ }
+ }
+ }
+ if (Debug.infoOn())
+ Debug.logInfo(" parameters OUT : " + parameters, module);
+ return ServiceUtil.returnSuccess();
}
}
Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/test/ServiceEntityAutoTests.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/test/ServiceEntityAutoTests.java?rev=1735737&r1=1735736&r2=1735737&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/test/ServiceEntityAutoTests.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/test/ServiceEntityAutoTests.java Sat Mar 19 08:04:16 2016
@@ -18,6 +18,7 @@
*******************************************************************************/
package org.ofbiz.service.test;
+import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -153,4 +154,43 @@ public class ServiceEntityAutoTests exte
assertTrue(ServiceUtil.isError(results));
assertEquals(UtilProperties.getMessage("ServiceErrorUiLabels", "ServiceValueNotFoundForRemove", Locale.ENGLISH), ServiceUtil.getErrorMessage(results));
}
+
+ public void testEntityAutoExpireEntity() throws Exception {
+ Timestamp now = UtilDateTime.nowTimestamp();
+ delegator.create("Testing", "testingId", "TESTING_6");
+ delegator.create("TestingNode", "testingNodeId", "TESTNODE_6");
+ Map<String, Object> testingNodeMemberPkMap = UtilMisc.toMap("testingId", "TESTING_6", "testingNodeId", "TESTNODE_6", "fromDate", now);
+ delegator.create("TestingNodeMember", testingNodeMemberPkMap);
+
+ //test expire the thruDate
+ Map<String, Object> results = dispatcher.runSync("testEntityAutoExpireTestingNodeMember", testingNodeMemberPkMap);
+ assertTrue(ServiceUtil.isSuccess(results));
+ GenericValue testingNodeMember = EntityQuery.use(delegator).from("TestingNodeMember").where(testingNodeMemberPkMap).queryOne();
+ Timestamp expireDate = testingNodeMember.getTimestamp("thruDate");
+ assertNotNull("Expire thruDate set ", expireDate);
+
+ //test expire to ensure the thruDate isn't update but extendThruDate is
+ results = dispatcher.runSync("testEntityAutoExpireTestingNodeMember", testingNodeMemberPkMap);
+ assertTrue(ServiceUtil.isSuccess(results));
+ testingNodeMember = EntityQuery.use(delegator).from("TestingNodeMember").where(testingNodeMemberPkMap).queryOne();
+ assertTrue(expireDate.compareTo(testingNodeMember.getTimestamp("thruDate")) == 0);
+ assertNotNull("Expire extendThruDate set ", testingNodeMember.getTimestamp("extendThruDate"));
+
+ //test expire a specific field
+ delegator.create("TestFieldType", "testFieldTypeId", "TESTING_6");
+ Map<String, Object> testingExpireMap = UtilMisc.toMap("testFieldTypeId", "TESTING_6");
+ results = dispatcher.runSync("testEntityAutoExpireTestFieldType", testingExpireMap);
+ assertTrue(ServiceUtil.isSuccess(results));
+ GenericValue testFieldType = EntityQuery.use(delegator).from("TestFieldType").where("testFieldTypeId", "TESTING_6").queryOne();
+ assertNotNull("Expire dateTimeField set", testFieldType.getTimestamp("dateTimeField"));
+
+ //test expire a specific field with in value
+ delegator.create("TestFieldType", "testFieldTypeId", "TESTING_6bis");
+ testingExpireMap = UtilMisc.toMap("testFieldTypeId", "TESTING_6bis", "dateTimeField", now);
+ results = dispatcher.runSync("testEntityAutoExpireTestFieldType", testingExpireMap);
+ assertTrue(ServiceUtil.isSuccess(results));
+ testFieldType = EntityQuery.use(delegator).from("TestFieldType").where("testFieldTypeId", "TESTING_6bis").queryOne();
+ assertTrue(now.compareTo(testFieldType.getTimestamp("dateTimeField")) == 0);
+ }
+
}