From: Aron Roberts Date: Fri, 11 Jan 2013 23:42:31 +0000 (-0800) Subject: CSPACE-5728: Batch job to update computed current location values now also supports... X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=0057adbe3afae6e5eaa103b54d12cc0c97014ee2;p=tmp%2Fjakarta-migration.git CSPACE-5728: Batch job to update computed current location values now also supports the 'group' invocation mode. --- diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-updateobjloc-nocontext.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-updateobjloc-nocontext.xml index 91198eb93..c6253a472 100644 --- a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-updateobjloc-nocontext.xml +++ b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-updateobjloc-nocontext.xml @@ -9,7 +9,7 @@ true true - false + true true false org.collectionspace.services.batch.nuxeo.UpdateObjectLocationBatchJob diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-updateobjloc.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-updateobjloc.xml index afe6d20e3..7e47ad688 100644 --- a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-updateobjloc.xml +++ b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-updateobjloc.xml @@ -9,7 +9,7 @@ true true - false + true false false org.collectionspace.services.batch.nuxeo.UpdateObjectLocationBatchJob diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-updateobjloc-group.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-updateobjloc-group.xml new file mode 100644 index 000000000..9d060f20f --- /dev/null +++ b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-updateobjloc-group.xml @@ -0,0 +1,13 @@ + + + group + CollectionObject + + ${groupCSID} + + + + + diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-update-object-loc.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-update-object-loc.xml index e96a8b613..8bc0bce3e 100644 --- a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-update-object-loc.xml +++ b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-update-object-loc.xml @@ -281,7 +281,7 @@ - + POST @@ -421,6 +421,178 @@ + + + + POST + /cspace-services/batch + batch/batch-create-updateobjloc.xml + 201 + + + + POST + /cspace-services/collectionobjects + batch/collObj1.xml + 201 + + + + POST + /cspace-services/collectionobjects + batch/collObj1.xml + 201 + + + + POST + /cspace-services/movements + batch/movement.xml + + location-1 + 1900-01-01 + + 201 + + + + POST + /cspace-services/movements + batch/movement.xml + + location-2 + 2000-01-01 + + 201 + + + + POST + /cspace-services/movements + batch/movement.xml + + location-3 + 1800-01-01 + + 201 + + + + POST + /cspace-services/relations + batch/relation.xml + + ${createCollectionObject1.CSID} + CollectionObject + ${createMovement1.CSID} + Movement + + 201 + + + + POST + /cspace-services/relations + batch/relation.xml + + ${createMovement2.CSID} + Movement + ${createCollectionObject1.CSID} + CollectionObject + + 201 + + + + POST + /cspace-services/relations + batch/relation.xml + + ${createCollectionObject2.CSID} + CollectionObject + ${createMovement3.CSID} + Movement + + 201 + + + + POST + /cspace-services/groups + batch/group.xml + 201 + + + + POST + /cspace-services/relations + batch/relation.xml + + ${createCollectionObject1.CSID} + CollectionObject + ${createGroup.CSID} + Group + + 201 + + + + POST + /cspace-services/relations + batch/relation.xml + + ${createCollectionObject2.CSID} + CollectionObject + ${createGroup.CSID} + Group + + 201 + + + + POST + /cspace-services/batch/${createBatchRecord.CSID} + batch/batch-invoke-updateobjloc-group.xml + + ${createGroup.CSID} + + 200 + + + + + + GET + /cspace-services/collectionobjects/${createCollectionObject1.CSID} + batch/updateobjloc.xml + + + batch/res/collectionobject.res.xml + + ${createMovement2.currentLocation} + + + 200 + + + + + + GET + /cspace-services/collectionobjects/${createCollectionObject2.CSID} + batch/updateobjloc.xml + + + batch/res/collectionobject.res.xml + + ${createMovement3.currentLocation} + + + 200 + + + + - diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/group.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/group.xml new file mode 100644 index 000000000..d238fccf3 --- /dev/null +++ b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/group.xml @@ -0,0 +1,10 @@ + + + + + A group title + + + + + diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/xml-replay-master.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/xml-replay-master.xml index 46895cdeb..761e4feae 100644 --- a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/xml-replay-master.xml +++ b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/xml-replay-master.xml @@ -50,6 +50,7 @@ diff --git a/services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/UpdateObjectLocationBatchJob.java b/services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/UpdateObjectLocationBatchJob.java index f29f49838..b161d076a 100644 --- a/services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/UpdateObjectLocationBatchJob.java +++ b/services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/UpdateObjectLocationBatchJob.java @@ -56,12 +56,14 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { Namespace.getNamespace( COLLECTIONOBJECTS_COMMON_NAMESPACE_PREFIX, COLLECTIONOBJECTS_COMMON_NAMESPACE_URI); + private final boolean EXCLUDE_DELETED = true; private final String CLASSNAME = this.getClass().getSimpleName(); private final Logger logger = LoggerFactory.getLogger(this.getClass()); // Initialization tasks public UpdateObjectLocationBatchJob() { - setSupportedInvocationModes(Arrays.asList(INVOCATION_MODE_SINGLE, INVOCATION_MODE_LIST, INVOCATION_MODE_NO_CONTEXT)); + setSupportedInvocationModes(Arrays.asList(INVOCATION_MODE_SINGLE, INVOCATION_MODE_LIST, + INVOCATION_MODE_GROUP, INVOCATION_MODE_NO_CONTEXT)); } /** @@ -92,10 +94,11 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { } csids.addAll(listCsids); } else if (requestIsForInvocationModeGroup()) { - // This invocation mode is currently not yet supported. - // FIXME: Add code to getMemberCsidsFromGroup() to support this mode. String groupCsid = getInvocationContext().getGroupCSID(); - List groupMemberCsids = getMemberCsidsFromGroup(groupCsid); + if (Tools.isBlank(groupCsid)) { + throw new Exception(CSID_VALUES_NOT_PROVIDED_IN_INVOCATION_CONTEXT); + } + List groupMemberCsids = getMemberCsidsFromGroup(CollectionObjectClient.SERVICE_NAME, groupCsid); if (groupMemberCsids.isEmpty()) { throw new Exception(CSID_VALUES_NOT_PROVIDED_IN_INVOCATION_CONTEXT); } @@ -107,6 +110,9 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { } csids.addAll(noContextCsids); } + if (logger.isInfoEnabled()) { + logger.info("Identified " + csids.size() + " total CollectionObject(s) to be processed via the " + CLASSNAME + " batch job"); + } // Update the value of the computed current location field for each CollectionObject setResults(updateComputedCurrentLocations(csids)); @@ -120,7 +126,6 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { } private InvocationResults updateComputedCurrentLocations(List csids) { - ResourceMap resourcemap = getResourceMap(); ResourceBase collectionObjectResource = resourcemap.get(CollectionObjectClient.SERVICE_NAME); ResourceBase movementResource = resourcemap.get(MovementClient.SERVICE_NAME); @@ -132,9 +137,13 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { // For each CollectionObject record for (String collectionObjectCsid : csids) { + // FIXME: Optionally set competition status here to + // indicate what percentage of records have been processed. + // Skip over soft-deleted CollectionObject records // - // (No context invocations already have filtered out those records) + // (Invocations using the 'no context' mode have already + // filtered out soft-deleted records.) if (!requestIsForInvocationModeNoContext()) { if (isRecordDeleted(collectionObjectResource, collectionObjectCsid)) { if (logger.isTraceEnabled()) { @@ -145,7 +154,7 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { } // Get the Movement records related to this CollectionObject record AbstractCommonList relatedMovements = - getRelatedRecords(movementResource, collectionObjectCsid, true /* exclude deleted records */); + getRelatedRecords(movementResource, collectionObjectCsid, EXCLUDE_DELETED); // Skip over CollectionObject records that have no related Movement records if (relatedMovements.getListItem().isEmpty()) { continue; @@ -154,7 +163,7 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { // based on data in its related Movement records computedCurrentLocation = computeCurrentLocation(relatedMovements); // Skip over CollectionObject records where no current location - // value can be computed from related Movement records + // value can be computed // // FIXME: Clarify: it ever necessary to 'unset' a computed // current location value, by setting it to a null or empty value, @@ -183,9 +192,9 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { } private String computeCurrentLocation(AbstractCommonList relatedMovements) { + Set alreadyProcessedMovementCsids = new HashSet(); String computedCurrentLocation; String movementCsid; - Set alreadyProcessedMovementCsids = new HashSet(); computedCurrentLocation = ""; String currentLocation; String locationDate; @@ -195,9 +204,9 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { if (Tools.isBlank(movementCsid)) { continue; } - // Avoid processing any related Movement record more than once, - // regardless of the directionality of its relation(s) to this - // CollectionObject record. + // Skip over any duplicates in the list, such as records that might + // appear as the subject of one relation record and the object of + // its reciprocal relation record if (alreadyProcessedMovementCsids.contains(movementCsid)) { continue; } else { @@ -219,10 +228,11 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { // Movement records processed so far, set the computed current location // to its current location value. // - // Assumes that all values for this element/field will be consistent ISO 8601 - // date/time representations, each of which can be ordered via string comparison. + // The following comparison assumes that all values for this element/field + // will be consistent ISO 8601 date/time representations, each of which can + // be ordered via string comparison. // - // If this is *not* the case, we can instead parse and convert these values + // If this is *not* the case, we should instead parse and convert these values // to date/time objects. if (locationDate.compareTo(mostRecentLocationDate) > 0) { mostRecentLocationDate = locationDate; @@ -253,6 +263,7 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { } } // Perform the update only if the computed current location value will change + // as a result of the update previousComputedCurrentLocation = getFieldElementValue(collectionObjectPayload, COLLECTIONOBJECTS_COMMON_SCHEMA_NAME, COLLECTIONOBJECTS_COMMON_NAMESPACE, COMPUTED_CURRENT_LOCATION_ELEMENT_NAME); @@ -260,18 +271,21 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { && computedCurrentLocation.equals(previousComputedCurrentLocation)) { return numUpdated; } + // Perform the update only if there is a non-blank object number available. + // // In the default CollectionObject validation handler, the object number // is a required field and its (non-blank) value must be present in update // payloads to successfully perform an update. - // - // FIXME: Consider making this check for an object number dependent on the - // value of a parameter passed in during batch job invocation. objectNumber = getFieldElementValue(collectionObjectPayload, COLLECTIONOBJECTS_COMMON_SCHEMA_NAME, COLLECTIONOBJECTS_COMMON_NAMESPACE, OBJECT_NUMBER_ELEMENT_NAME); if (logger.isTraceEnabled()) { logger.trace("Object number: " + objectNumber); } + // FIXME: Consider making the requirement that a non-blank object number + // be present dependent on the value of a parameter passed in during + // batch job invocation, as some implementations may have turned off that + // validation requirement. if (Tools.isBlank(objectNumber)) { return numUpdated; } @@ -375,72 +389,114 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable { return isDeleted; } - private AbstractCommonList getRelatedRecords(ResourceBase resource, String csid, boolean excludeDeletedRecords) - throws URISyntaxException, DocumentException { + private UriInfo addFilterToExcludeSoftDeletedRecords(UriInfo uriInfo) throws URISyntaxException { + if (uriInfo == null) { + uriInfo = createUriInfo(); + } + uriInfo.getQueryParameters().add(WorkflowClient.WORKFLOW_QUERY_NONDELETED, Boolean.FALSE.toString()); + return uriInfo; + } - // Get records related to a record, specified by its CSID, - // where the record is the object of the relation + private AbstractCommonList getRecordsRelatedToCsid(ResourceBase resource, String csid, + String relationshipDirection, boolean excludeDeletedRecords) throws URISyntaxException { UriInfo uriInfo = createUriInfo(); - // FIXME: Get this from constant(s), where appropriate - uriInfo.getQueryParameters().add("rtObj", csid); + uriInfo.getQueryParameters().add(relationshipDirection, csid); if (excludeDeletedRecords) { - uriInfo.getQueryParameters().add(WorkflowClient.WORKFLOW_QUERY_NONDELETED, "false"); + uriInfo = addFilterToExcludeSoftDeletedRecords(uriInfo); } - + // The 'resource' type used here identifies the record type of the + // related records to be retrieved AbstractCommonList relatedRecords = resource.getList(uriInfo); if (logger.isTraceEnabled()) { logger.trace("Identified " + relatedRecords.getTotalItems() - + " record(s) related to the object record with CSID " + csid); + + " record(s) related to the object record via direction " + relationshipDirection + " with CSID " + csid); } + return relatedRecords; + } - // Get records related to a record, specified by its CSID, - // where the record is the subject of the relation - // FIXME: Get query string(s) from constant(s), where appropriate - uriInfo = createUriInfo(); - uriInfo.getQueryParameters().add("rtSbj", csid); - if (excludeDeletedRecords) { - uriInfo.getQueryParameters().add(WorkflowClient.WORKFLOW_QUERY_NONDELETED, "false"); - } - AbstractCommonList reverseRelatedRecords = resource.getList(uriInfo); - if (logger.isTraceEnabled()) { - logger.trace("Identified " + reverseRelatedRecords.getTotalItems() - + " record(s) related to the subject record with CSID " + csid); - } + /** + * Returns the records of a specified type that are related to a specified + * record, where that record is the object of the relation. + * + * @param resource a resource. The type of this resource determines the type + * of related records that are returned. + * @param csid a CSID identifying a record + * @param excludeDeletedRecords true if 'soft-deleted' records should be + * excluded from results; false if those records should be included + * @return a list of records of a specified type, related to a specified + * record + * @throws URISyntaxException + */ + private AbstractCommonList getRecordsRelatedToObjectCsid(ResourceBase resource, String csid, boolean excludeDeletedRecords) throws URISyntaxException { + return getRecordsRelatedToCsid(resource, csid, "rtObj", excludeDeletedRecords); + } - // If the second list contains any related records, - // merge it into the first list - if (reverseRelatedRecords.getListItem().size() > 0) { - relatedRecords.getListItem().addAll(reverseRelatedRecords.getListItem()); - } + /** + * Returns the records of a specified type that are related to a specified + * record, where that record is the subject of the relation. + * + * @param resource a resource. The type of this resource determines the type + * of related records that are returned. + * @param csid a CSID identifying a record + * @param excludeDeletedRecords true if 'soft-deleted' records should be + * excluded from results; false if those records should be included + * @return a list of records of a specified type, related to a specified + * record + * @throws URISyntaxException + */ + private AbstractCommonList getRecordsRelatedToSubjectCsid(ResourceBase resource, String csid, boolean excludeDeletedRecords) throws URISyntaxException { + return getRecordsRelatedToCsid(resource, csid, "rtSbj", excludeDeletedRecords); + } + private AbstractCommonList getRelatedRecords(ResourceBase resource, String csid, boolean excludeDeletedRecords) + throws URISyntaxException, DocumentException { + AbstractCommonList relatedRecords = new AbstractCommonList(); + AbstractCommonList recordsRelatedToObjectCSID = getRecordsRelatedToObjectCsid(resource, csid, excludeDeletedRecords); + AbstractCommonList recordsRelatedToSubjectCSID = getRecordsRelatedToSubjectCsid(resource, csid, excludeDeletedRecords); + // If either list contains any related records, merge in its items + if (recordsRelatedToObjectCSID.getListItem().size() > 0) { + relatedRecords.getListItem().addAll(recordsRelatedToObjectCSID.getListItem()); + } + if (recordsRelatedToSubjectCSID.getListItem().size() > 0) { + relatedRecords.getListItem().addAll(recordsRelatedToSubjectCSID.getListItem()); + } if (logger.isTraceEnabled()) { logger.trace("Identified a total of " + relatedRecords.getListItem().size() + " record(s) related to the record with CSID " + csid); } - return relatedRecords; } - // Stub method, as this invocation mode is not currently supported - private List getMemberCsidsFromGroup(String groupCsid) throws URISyntaxException { - List memberCsids = Collections.emptyList(); + private List getCsidsList(AbstractCommonList list) { + List csids = new ArrayList(); + for (AbstractCommonList.ListItem listitem : list.getListItem()) { + csids.add(AbstractCommonListUtils.ListItemGetCSID(listitem)); + } + return csids; + } + + private List getMemberCsidsFromGroup(String serviceName, String groupCsid) throws URISyntaxException, DocumentException { + ResourceMap resourcemap = getResourceMap(); + ResourceBase resource = resourcemap.get(serviceName); + return getMemberCsidsFromGroup(resource, groupCsid); + } + + private List getMemberCsidsFromGroup(ResourceBase resource, String groupCsid) throws URISyntaxException, DocumentException { + // The 'resource' type used here identifies the record type of the + // related records to be retrieved + AbstractCommonList relatedRecords = + getRelatedRecords(resource, groupCsid, EXCLUDE_DELETED); + List memberCsids = getCsidsList(relatedRecords); return memberCsids; } private List getNoContextCsids() throws URISyntaxException { - List noContextCsids = new ArrayList(); ResourceMap resourcemap = getResourceMap(); ResourceBase collectionObjectResource = resourcemap.get(CollectionObjectClient.SERVICE_NAME); UriInfo uriInfo = createUriInfo(); - uriInfo.getQueryParameters().add(WorkflowClient.WORKFLOW_QUERY_NONDELETED, "false"); + uriInfo = addFilterToExcludeSoftDeletedRecords(uriInfo); AbstractCommonList collectionObjects = collectionObjectResource.getList(uriInfo); - for (AbstractCommonList.ListItem collectionObjectRecord : collectionObjects.getListItem()) { - noContextCsids.add(AbstractCommonListUtils.ListItemGetCSID(collectionObjectRecord)); - } - if (logger.isInfoEnabled()) { - logger.info("Identified " + noContextCsids.size() - + " total active CollectionObjects to process in the 'no context' invocation mode."); - } + List noContextCsids = getCsidsList(collectionObjects); return noContextCsids; } }