1 package org.collectionspace.services.listener;
3 import org.apache.commons.logging.Log;
4 import org.apache.commons.logging.LogFactory;
5 import org.collectionspace.services.client.workflow.WorkflowClient;
6 import org.collectionspace.services.common.api.Tools;
7 import org.collectionspace.services.movement.nuxeo.MovementConstants;
8 import org.nuxeo.ecm.core.api.ClientException;
9 import org.nuxeo.ecm.core.api.DocumentModel;
10 import org.nuxeo.ecm.core.event.Event;
11 import org.nuxeo.ecm.core.event.EventContext;
12 import org.nuxeo.ecm.core.event.EventListener;
13 import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
15 public class UpdateObjectLocationOnMove implements EventListener {
17 // FIXME: We might experiment here with using log4j instead of Apache Commons Logging;
18 // am using the latter to follow Ray's pattern for now
19 final Log logger = LogFactory.getLog(UpdateObjectLocationOnMove.class);
22 public void handleEvent(Event event) throws ClientException {
24 logger.trace("In handleEvent in UpdateObjectLocationOnMove ...");
26 EventContext eventContext = event.getContext();
27 if (eventContext == null) {
30 DocumentEventContext docEventContext = (DocumentEventContext) eventContext;
31 DocumentModel docModel = docEventContext.getSourceDocument();
32 if (isMovementDocument(docModel) && isActiveDocument(docModel)) {
33 logger.debug("A create or update event for an active Movement document was received by UpdateObjectLocationOnMove ...");
37 // Use a JDBC call to test whether a SQL function exists to
38 // supply the last identified location of a CollectionObject.
39 // If it does not, bail.
41 // At the moment, that function is named lastIdentifiedLocation(),
42 // resides in the resources of the collectionobject.services module,
43 // and will be created in the database via the Ant 'create_nuxeo_db'
46 // For now, assume this function will exist in the 'nuxeo' database;
47 // future work to create per-tenant repositories will likely require that
48 // our JDBC statements connect to the appropriate tenant-specific database.
50 // Get this Movement record's CSID via the document model.
52 // Find every CollectionObject record related to this Movement record:
54 // Via an NXQL query, get a list of (non-deleted) relation records where:
55 // * This movement record's CSID is the subject CSID of the relation.
56 // * The object document type is a CollectionObject doctype.
58 // Iterate through that list of Relation records and build a list of
59 // CollectionObject CSIDs, by extracting the object CSIDs of those records.
61 // For each such CollectionObject:
63 // Verify that the CollectionObject record is active (use isActiveDocument(), below).
65 // Via a JDBC call, invoke the SQL function to supply the last
66 // identified location of that CollectionObject, giving it the CSID
67 // of the CollectionObject record as an argument.
69 // Check that the SQL function's returned value, which is expected
70 // to be a reference (refName) to a storage location authority term,
73 // * Capable of being successfully parsed by an authority item parser,
74 // returning a non-null parse result.
76 // Compare that returned value to the value in the
77 // lastIdentifiedLocation field of that CollectionObject
79 // If the two values differ, update the CollectionObject record,
80 // setting the value of the lastIdentifiedLocation field of that
81 // CollectionObject record to the value returned from the SQL function.
87 * Identifies whether a document is a Movement document
89 * @param docModel a document model
90 * @return true if the document is a Movement document; false if it is not.
92 private boolean isMovementDocument(DocumentModel docModel) {
93 return documentMatchesType(docModel, MovementConstants.NUXEO_DOCTYPE);
96 // FIXME: Generic methods like the following might be split off
97 // into an event utilities class. - ADR 2012-12-05
99 // FIXME: Identify whether the equivalent of this utility method is
100 // already implemented and substitute a call to the latter if so.
103 * Identifies whether a document matches a supplied document type.
105 * @param docModel a document model.
106 * @param docType a document type string.
107 * @return true if the document matches the supplied document type; false if it does not.
109 private boolean documentMatchesType(DocumentModel docModel, String docType) {
110 if (docModel == null || Tools.isBlank(docType)) {
113 if (docModel.getType().startsWith(docType)) {
121 * Identifies whether a document is an active document; that is, if it is
122 * not a versioned record; not a proxy (symbolic link to an actual record);
123 * and not in the 'deleted' workflow state.
125 * (A note relating the latter: Nuxeo appears to send 'documentModified'
126 * events even on workflow transitions, such when records are 'soft deleted'
127 * by being transitioned to the 'deleted' workflow state.)
130 * @return true if the document is an active document; false if it is not.
132 private boolean isActiveDocument(DocumentModel docModel) {
133 if (docModel == null) {
136 boolean isActiveDocument = false;
138 if (!docModel.isVersion()
139 && !docModel.isProxy()
140 && !docModel.getCurrentLifeCycleState().equals(WorkflowClient.WORKFLOWSTATE_DELETED)) {
141 isActiveDocument = true;
143 } catch (ClientException ce) {
144 logger.warn("Error while identifying whether document is an active document: ", ce);
146 return isActiveDocument;