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);
result.put(singlePkModelParam.name, 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
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);
result.put(singlePkModelParam.name, 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);
result.put(doublePkSecondaryOutParam.name, newEntity.get(doublePkSecondaryOutField.getName()));
} 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);
} 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 secdonary pk to sub-sequence, " +
"4. 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 || (fromDateParam.isOptional() && parameters.get("fromDate") == null)) {
newEntity.set("fromDate", UtilDateTime.nowTimestamp());
}
}
newEntity.setNonPKFields(parameters, true);
newEntity.create();
} 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");
}
GenericValue lookedUpValue = PrimaryKeyFinder.runFind(modelEntity, parameters, dctx.getDelegator(), false, true, null, null);
if (lookedUpValue == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ServiceValueNotFound", locale));
}
localContext.put("lookedUpValue", lookedUpValue);
// 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"));
}