From e76d7312c3347e6e7712f430949704f2273ac22a Mon Sep 17 00:00:00 2001 From: Aron Roberts Date: Wed, 12 Dec 2012 13:49:19 -0800 Subject: [PATCH] CSPACE-5727: Basic Movement record changes are working again, after adding handling of relation record events. Relation addition is also working to update computed current locations, but relation deletion (via the UI) is not. --- .../listener/UpdateObjectLocationOnMove.java | 180 +++++++++++------- 1 file changed, 111 insertions(+), 69 deletions(-) diff --git a/3rdparty/nuxeo/nuxeo-platform-listener/updateobjectlocationonmove/src/main/java/org/collectionspace/services/listener/UpdateObjectLocationOnMove.java b/3rdparty/nuxeo/nuxeo-platform-listener/updateobjectlocationonmove/src/main/java/org/collectionspace/services/listener/UpdateObjectLocationOnMove.java index 0565838bc..6b8ca9a78 100644 --- a/3rdparty/nuxeo/nuxeo-platform-listener/updateobjectlocationonmove/src/main/java/org/collectionspace/services/listener/UpdateObjectLocationOnMove.java +++ b/3rdparty/nuxeo/nuxeo-platform-listener/updateobjectlocationonmove/src/main/java/org/collectionspace/services/listener/UpdateObjectLocationOnMove.java @@ -3,8 +3,10 @@ package org.collectionspace.services.listener; import java.util.ArrayList; import java.util.GregorianCalendar; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.collectionspace.services.client.workflow.WorkflowClient; @@ -65,81 +67,66 @@ public class UpdateObjectLocationOnMove implements EventListener { DocumentEventContext docEventContext = (DocumentEventContext) eventContext; DocumentModel docModel = docEventContext.getSourceDocument(); - // If this event does not involve one of the relevant doctypes - // designated as being handled by this event handler, return - // without further handling the event. - boolean involvesRelevantDocType = false; - relevantDocTypesList.add(MovementConstants.NUXEO_DOCTYPE); - relevantDocTypesList.add(RELATION_DOCTYPE); - for (String docType : relevantDocTypesList) { - if (documentMatchesType(docModel, docType)) { - involvesRelevantDocType = true; - break; - } - } - if (!involvesRelevantDocType) { - return; - } - - if (logger.isTraceEnabled()) { - logger.trace("An event involving a document of the relevant type(s) was received by UpdateObjectLocationOnMove ..."); - } - - // Note: currently, all Document lifecycle transitions on - // the relevant doctype(s) are handled by this event handler, - // not just transitions between 'soft deleted' and active states. - // - // We are assuming that we'll want to re-compute current locations - // for related CollectionObjects on any such transitions, as the - // semantics of such transitions are opaque to this event handler, - // since arbitrary workflows can be bound to those doctype(s). - // - // If we need to filter out some of those lifecycle transitions, - // such as excluding transitions to the 'locked' workflow state; or, - // alternately, if we want to restrict this event handler's - // scope to handle only transitions into the 'soft deleted' state, - // we can add additional checks for doing so at this point. - // If this document event involves a Relation record, does this pertain to // a relationship between a Movement record and a CollectionObject record? // // If not, we're not interested in processing this document event // in this event handler, as it will have no bearing on updating a // computed current location for a CollectionObject. + // - // If so, get the Movement CSID from the relation record. // (The rest of the code flow below is then identical to that which // is followed when this document event involves a Movement record.) String movementCsid = ""; - boolean eventPertainsToRelevantRelationship = false; if (documentMatchesType(docModel, RELATION_DOCTYPE)) { - String subjectDocType = (String) docModel.getProperty(RELATIONS_COMMON_SCHEMA, SUBJECT_DOCTYPE_PROPERTY); - String objectDocType = (String) docModel.getProperty(RELATIONS_COMMON_SCHEMA, OBJECT_DOCTYPE_PROPERTY); - if (subjectDocType.startsWith(MOVEMENT_DOCTYPE) && objectDocType.startsWith(COLLECTIONOBJECT_DOCTYPE)) { - eventPertainsToRelevantRelationship = true; - movementCsid = (String) docModel.getProperty(RELATIONS_COMMON_SCHEMA, SUBJECT_CSID_PROPERTY); - } else if (subjectDocType.startsWith(COLLECTIONOBJECT_DOCTYPE) && objectDocType.startsWith(MOVEMENT_DOCTYPE)) { - eventPertainsToRelevantRelationship = true; - movementCsid = (String) docModel.getProperty(RELATIONS_COMMON_SCHEMA, OBJECT_CSID_PROPERTY); + if (logger.isTraceEnabled()) { + logger.trace("An event involving a Relation document was received by UpdateObjectLocationOnMove ..."); } - if (!eventPertainsToRelevantRelationship) { + // Get a Movement CSID from the Relation record. (If we can't + // get it, then we don't have a pertinent relation record.) + movementCsid = getCsidForDesiredDocType(docModel, MOVEMENT_DOCTYPE, COLLECTIONOBJECT_DOCTYPE); + if (Tools.isBlank(movementCsid)) { + logger.warn("Could not obtain CSID for Movement record from document event."); + logger.warn(NO_FURTHER_PROCESSING_MESSAGE); return; } - } - - // If we haven't obtained the Movement CSID from a Relation record, - // then we can infer this is a Movement record (the only other type - // of document handled by this event handler), and obtain the CSID - // directly from that record. - if (Tools.isBlank(movementCsid)) { + } else if (documentMatchesType(docModel, MOVEMENT_DOCTYPE)) { + if (logger.isTraceEnabled()) { + logger.trace("An event involving a Movement document was received by UpdateObjectLocationOnMove ..."); + } + // Otherwise, get a Movement CSID directly from the Movement record. movementCsid = NuxeoUtils.getCsid(docModel); - } - if (Tools.isBlank(movementCsid)) { - logger.warn("Could not obtain CSID for Movement record from document event."); - logger.warn(NO_FURTHER_PROCESSING_MESSAGE); + if (Tools.isBlank(movementCsid)) { + logger.warn("Could not obtain CSID for Movement record from document event."); + logger.warn(NO_FURTHER_PROCESSING_MESSAGE); + return; + } + } else { + if (logger.isTraceEnabled()) { + logger.trace("This event did not involve a document relevant to UpdateObjectLocationOnMove ..."); + } return; } + // Note: currently, all Document lifecycle transitions on + // the relevant doctype(s) are handled by this event handler, + // not just transitions between 'soft deleted' and active states. + // + // We are assuming that we'll want to re-compute current locations + // for related CollectionObjects on all such transitions, as the + // semantics of such transitions are opaque to this event handler, + // because arbitrary workflows can be bound to those doctype(s). + // + // If we need to filter out some of those lifecycle transitions, + // such as excluding transitions to the 'locked' workflow state; or, + // alternately, if we want to restrict this event handler's + // scope to handle only transitions into the 'soft deleted' state, + // we can add additional checks for doing so at this point in the code. + + if (logger.isTraceEnabled()) { + logger.trace("Movement CSID=" + movementCsid); + } + // Find CollectionObject records that are related to this Movement record: // // Via an NXQL query, get a list of active relation records where: @@ -162,8 +149,8 @@ public class UpdateObjectLocationOnMove implements EventListener { + ")" + ACTIVE_DOCUMENT_WHERE_CLAUSE_FRAGMENT, RELATION_DOCTYPE, RELATIONS_COMMON_SCHEMA, movementCsid, COLLECTIONOBJECT_DOCTYPE); - DocumentModelList relatedDocModels = coreSession.query(query); - if (relatedDocModels == null || relatedDocModels.isEmpty()) { + DocumentModelList relationDocModels = coreSession.query(query); + if (relationDocModels == null || relationDocModels.isEmpty()) { // Encountering a Movement record that is not related to any // CollectionObject is potentially a normal occurrence, so no // error messages are logged here when we stop handling this event. @@ -171,16 +158,16 @@ public class UpdateObjectLocationOnMove implements EventListener { } // Iterate through the list of Relation records found and build - // a list of CollectionObject CSIDs, by extracting the object CSIDs + // a list of CollectionObject CSIDs, by extracting the relevant CSIDs // from those Relation records. // FIXME: The following code might be refactored into a generic 'get // values of a single property from a list of document models' method, // if this doesn't already exist. String csid = ""; - List collectionObjectCsids = new ArrayList(); - for (DocumentModel relatedDocModel : relatedDocModels) { - csid = (String) relatedDocModel.getProperty(RELATIONS_COMMON_SCHEMA, OBJECT_CSID_PROPERTY); + Set collectionObjectCsids = new HashSet(); // Prevents/removes duplicates on add + for (DocumentModel relationDocModel : relationDocModels) { + csid = getCsidForDesiredDocType(relationDocModel, COLLECTIONOBJECT_DOCTYPE, MOVEMENT_DOCTYPE); if (Tools.notBlank(csid)) { collectionObjectCsids.add(csid); } @@ -201,7 +188,13 @@ public class UpdateObjectLocationOnMove implements EventListener { Map docModelsToUpdate = new HashMap(); for (String collectionObjectCsid : collectionObjectCsids) { + if (logger.isTraceEnabled()) { + logger.trace("CollectionObject CSID=" + collectionObjectCsids); + } collectionObjectDocModel = getDocModelFromCsid(coreSession, collectionObjectCsid); + if (collectionObjectDocModel == null) { + continue; + } // Verify that the CollectionObject record is active. if (!isActiveDocument(collectionObjectDocModel)) { continue; @@ -222,6 +215,7 @@ public class UpdateObjectLocationOnMove implements EventListener { if ((Tools.isBlank(computedCurrentLocationRefName) || (RefNameUtils.parseAuthorityTermInfo(computedCurrentLocationRefName) == null))) { logger.warn("Could not parse computed current location refName '" + computedCurrentLocationRefName + "'"); + continue; } else { if (logger.isTraceEnabled()) { logger.trace("refName passes basic validation tests."); @@ -230,15 +224,16 @@ public class UpdateObjectLocationOnMove implements EventListener { // If the value returned from the function passes validation, // compare it to the value in the computedCurrentLocation // field of that CollectionObject. - // - // If the CollectionObject does not already have a - // computedCurrentLocation value, or if the two values differ ... String existingComputedCurrentLocationRefName = (String) collectionObjectDocModel.getProperty(COLLECTIONOBJECTS_COMMON_SCHEMA, COMPUTED_CURRENT_LOCATION_PROPERTY); + if (logger.isTraceEnabled()) { + logger.trace("Existing computedCurrentLocation refName=" + existingComputedCurrentLocationRefName); + } + // If the CollectionObject lacks a computed current location value, + // or if the new computed value differs from its existing value ... if (Tools.isBlank(existingComputedCurrentLocationRefName) - || !computedCurrentLocationRefName.equals(existingComputedCurrentLocationRefName)) { + || (!computedCurrentLocationRefName.equals(existingComputedCurrentLocationRefName))) { if (logger.isTraceEnabled()) { - logger.trace("Existing computedCurrentLocation refName=" + existingComputedCurrentLocationRefName); logger.trace("computedCurrentLocation refName requires updating."); } // ... set aside this CollectionObject's docModel and its new @@ -248,7 +243,7 @@ public class UpdateObjectLocationOnMove implements EventListener { if (logger.isTraceEnabled()) { logger.trace("computedCurrentLocation refName does NOT require updating."); } - } + } } } @@ -346,8 +341,10 @@ public class UpdateObjectLocationOnMove implements EventListener { } if (collectionObjectDocModels == null || collectionObjectDocModels.isEmpty()) { logger.warn("Could not get document models for CollectionObject(s)."); + return null; } else if (collectionObjectDocModels.size() != 1) { logger.debug("Found more than 1 document with CSID=" + collectionObjectCsid); + return null; } return collectionObjectDocModels.get(0); } @@ -395,10 +392,17 @@ public class UpdateObjectLocationOnMove implements EventListener { + ")" + ACTIVE_DOCUMENT_WHERE_CLAUSE_FRAGMENT, RELATION_DOCTYPE, RELATIONS_COMMON_SCHEMA, collectionObjectCsid, MOVEMENT_DOCTYPE); + if (logger.isTraceEnabled()) { + logger.trace("query=" + query); + } DocumentModelList relatedDocModels = session.query(query); if (relatedDocModels == null || relatedDocModels.isEmpty()) { + logger.warn("Unexpectedly found no Movement records related to this CollectionObject record."); return computedCurrentLocation; } else { + if (logger.isTraceEnabled()) { + logger.trace("Found " + relatedDocModels.size() + " Movement record(s) related to this CollectionObject record."); + } } // Iterate through related movement records, to get the CollectionObject's // computed current location from the related Movement record with the @@ -417,10 +421,19 @@ public class UpdateObjectLocationOnMove implements EventListener { csid = (String) relatedDocModel.getProperty(RELATIONS_COMMON_SCHEMA, OBJECT_CSID_PROPERTY); } movementDocModel = getDocModelFromCsid(session, csid); + if (movementDocModel == null) { + continue; + } + if (logger.isTraceEnabled()) { + logger.trace("Movement CSID=" + NuxeoUtils.getCsid(movementDocModel)); + } // Verify that the Movement record is active. This will also exclude // versioned Movement records from the computation of the current // location, for tenants that are versioning such records. if (!isActiveDocument(movementDocModel)) { + if (logger.isTraceEnabled()) { + logger.trace("Skipping this inactive Movement record ..."); + } continue; } GregorianCalendar locationDate = @@ -438,4 +451,33 @@ public class UpdateObjectLocationOnMove implements EventListener { } return computedCurrentLocation; } + + /** + * Returns the CSID for a desired document type from a Relation record, + * where the relationship involves two specified, different document types. + * + * @param relationDocModel a document model for a Relation record. + * @param desiredDocType a desired document type. + * @param relatedDocType a related document type. + * @throws ClientException + * @return the CSID from the desired document type in the relation. Returns + * an empty string if the Relation record does not involve both the desired + * and related document types, or if the desired document type is at both + * ends of the relation. + */ + private String getCsidForDesiredDocType(DocumentModel relationDocModel, + String desiredDocType, String relatedDocType) throws ClientException { + String csid = ""; + String subjectDocType = (String) relationDocModel.getProperty(RELATIONS_COMMON_SCHEMA, SUBJECT_DOCTYPE_PROPERTY); + String objectDocType = (String) relationDocModel.getProperty(RELATIONS_COMMON_SCHEMA, OBJECT_DOCTYPE_PROPERTY); + if (subjectDocType.startsWith(desiredDocType) && objectDocType.startsWith(desiredDocType)) { + return csid; + } + if (subjectDocType.startsWith(desiredDocType) && objectDocType.startsWith(relatedDocType)) { + csid = (String) relationDocModel.getProperty(RELATIONS_COMMON_SCHEMA, SUBJECT_CSID_PROPERTY); + } else if (subjectDocType.startsWith(relatedDocType) && objectDocType.startsWith(desiredDocType)) { + csid = (String) relationDocModel.getProperty(RELATIONS_COMMON_SCHEMA, OBJECT_CSID_PROPERTY); + } + return csid; + } } \ No newline at end of file -- 2.47.3