1 package org.collectionspace.services.listener;
3 import java.util.ArrayList;
4 import java.util.IllegalFormatException;
7 import org.apache.commons.logging.Log;
8 import org.apache.commons.logging.LogFactory;
9 import org.collectionspace.services.client.workflow.WorkflowClient;
10 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
11 import org.collectionspace.services.nuxeo.client.java.CoreSessionWrapper;
12 import org.collectionspace.services.nuxeo.listener.AbstractCSEventListenerImpl;
13 import org.nuxeo.ecm.core.api.DocumentModel;
14 import org.nuxeo.ecm.core.api.DocumentModelList;
15 import org.nuxeo.ecm.core.api.impl.LifeCycleFilter;
16 import org.nuxeo.ecm.core.event.Event;
17 import org.nuxeo.ecm.core.event.EventContext;
18 import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
20 public class UpdateRelationsOnDelete extends AbstractCSEventListenerImpl {
22 // FIXME: We might experiment here with using log4j instead of Apache Commons Logging;
23 // am using the latter to follow Ray's pattern for now
24 final Log logger = LogFactory.getLog(UpdateRelationsOnDelete.class);
26 // FIXME: Get these constant values from external sources rather than redeclaring here
27 final static String RELATION_DOCTYPE = "Relation";
28 final static String RELATIONS_COMMON_SUBJECT_CSID_FIELD = "relations_common:subjectCsid";
29 final static String RELATIONS_COMMON_OBJECT_CSID_FIELD = "relations_common:objectCsid";
32 public void handleEvent(Event event) {
33 logger.trace("In handleEvent in UpdateRelationsOnDelete ...");
35 EventContext eventContext = event.getContext();
37 if (isRegistered(event) && isDocumentSoftDeletedEvent(eventContext)) {
39 logger.trace("A soft deletion event was received by UpdateRelationsOnDelete ...");
41 DocumentEventContext docContext = (DocumentEventContext) eventContext;
42 DocumentModel docModel = docContext.getSourceDocument();
44 // Exclude soft deletion events involving Relation records themselves
45 // from handling by this event handler.
46 if (docModel != null && docModel.getType().startsWith(RELATION_DOCTYPE)) {
50 // Retrieve a list of relation records, where the soft deleted
51 // document provided in the context of the current event is
52 // either the subject or object of any relation
54 // Build a query string
55 String csid = docModel.getName();
60 String.format("SELECT * FROM Relation WHERE ecm:isProxy = 0 AND (%1$s='%3$s' OR %2$s='%3$s')",
61 RELATIONS_COMMON_SUBJECT_CSID_FIELD, RELATIONS_COMMON_OBJECT_CSID_FIELD, csid);
62 logger.trace("Query string=" + queryString);
63 } catch (IllegalFormatException ife) {
64 logger.warn("Construction of formatted query string failed: ", ife);
65 logger.warn("Actions in this event listener will NOT be performed, as a result of a previous Exception.");
69 // Create a filter to exclude from the list results any records
70 // that have already been soft deleted or are locked
71 List<String> workflowStatesToFilter = new ArrayList<String>();
72 workflowStatesToFilter.add(WorkflowClient.WORKFLOWSTATE_DELETED);
73 workflowStatesToFilter.add(WorkflowClient.WORKFLOWSTATE_LOCKED);
74 workflowStatesToFilter.add(WorkflowClient.WORKFLOWSTATE_LOCKED_DELETED);
75 workflowStatesToFilter.add(WorkflowClient.WORKFLOWSTATE_REPLICATED_DELETED);
77 LifeCycleFilter workflowStateFilter = new LifeCycleFilter(null, workflowStatesToFilter);
79 // Perform the filtered query
80 CoreSessionInterface session = new CoreSessionWrapper(docModel.getCoreSession());
81 DocumentModelList matchingDocuments;
83 matchingDocuments = session.query(queryString.toString(), workflowStateFilter);
84 } catch (Exception ce) {
85 logger.warn("Error attempting to retrieve relation records where "
86 + "record of type '" + docModel.getType() + "' with CSID " + csid
87 + " is the subject or object of any relation: " + ce.getMessage());
91 // Cycle through the list results, soft deleting each matching relation record
92 logger.info("Attempting to soft delete " + matchingDocuments.size() + " relation records pertaining to a soft deleted record.");
93 for (DocumentModel doc : matchingDocuments) {
94 doc.followTransition(WorkflowClient.WORKFLOWTRANSITION_DELETE);
101 // FIXME: Generic methods like the following might be split off
102 // into an event utilities class. - ADR 2012-12-05
105 * Identifies whether a supplied event concerns a document that has
106 * been transitioned to the 'deleted' workflow state.
108 * @param eventContext an event context
110 * @return true if this event concerns a document that has
111 * been transitioned to the 'deleted' workflow state.
113 private boolean isDocumentSoftDeletedEvent(EventContext eventContext) {
114 boolean isSoftDeletedEvent = false;
116 if (eventContext instanceof DocumentEventContext) {
117 if (eventContext.getProperties().containsKey(WorkflowClient.WORKFLOWTRANSITION_TO)
119 (eventContext.getProperties().get(WorkflowClient.WORKFLOWTRANSITION_TO).equals(WorkflowClient.WORKFLOWSTATE_DELETED)
121 eventContext.getProperties().get(WorkflowClient.WORKFLOWTRANSITION_TO).equals(WorkflowClient.WORKFLOWSTATE_LOCKED_DELETED))) {
122 isSoftDeletedEvent = true;
126 return isSoftDeletedEvent;