]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
1a63c5f6ce7fa49822503dd91aa522cc83225131
[tmp/jakarta-migration.git] /
1 package org.collectionspace.services.listener.botgarden;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.HashSet;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Set;
9
10 import org.apache.commons.lang.StringUtils;
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13
14 import org.collectionspace.services.batch.BatchResource;
15 import org.collectionspace.services.batch.nuxeo.UpdateAccessCodeBatchJob;
16 import org.collectionspace.services.batch.nuxeo.UpdateAccessCodeBatchJob.UpdateAccessCodeResults;
17 import org.collectionspace.services.client.BatchClient;
18 import org.collectionspace.services.client.PoxPayloadIn;
19 import org.collectionspace.services.client.PoxPayloadOut;
20 import org.collectionspace.services.client.workflow.WorkflowClient;
21 import org.collectionspace.services.collectionobject.nuxeo.CollectionObjectBotGardenConstants;
22 import org.collectionspace.services.collectionobject.nuxeo.CollectionObjectConstants;
23 import org.collectionspace.services.common.ResourceMap;
24 import org.collectionspace.services.common.context.ServiceContext;
25 import org.collectionspace.services.common.invocable.InvocationResults;
26 import org.collectionspace.services.common.relation.nuxeo.RelationConstants;
27 import org.collectionspace.services.nuxeo.client.java.CoreSessionWrapper;
28 import org.collectionspace.services.nuxeo.listener.AbstractCSEventSyncListenerImpl;
29 import org.collectionspace.services.taxonomy.nuxeo.TaxonBotGardenConstants;
30 import org.collectionspace.services.taxonomy.nuxeo.TaxonConstants;
31 import org.collectionspace.services.taxonomy.nuxeo.TaxonomyAuthorityConstants;
32
33 import org.jboss.resteasy.spi.ResteasyProviderFactory;
34
35 import org.nuxeo.ecm.core.api.DocumentModel;
36 import org.nuxeo.ecm.core.api.event.CoreEventConstants;
37 import org.nuxeo.ecm.core.api.event.DocumentEventTypes;
38 import org.nuxeo.ecm.core.event.Event;
39 import org.nuxeo.ecm.core.event.EventContext;
40 import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
41
42 /**
43  * A listener that updates the access code on taxon records when collectionobjects
44  * or taxon records are created or modified.
45  *
46  * @see org.collectionspace.services.batch.nuxeo.UpdateAccessCodeBatchJob
47  * @author ray
48  *
49  */
50 public class UpdateAccessCodeListener extends AbstractCSEventSyncListenerImpl {
51         static final Log logger = LogFactory.getLog(UpdateAccessCodeListener.class);
52
53         public static final String PREVIOUS_DEAD_FLAG_PROPERTY_NAME = "UpdateAccessCodeListener.previousDeadFlag";
54         public static final String PREVIOUS_TAXON_NAMES_PROPERTY_NAME = "UpdateAccessCodeListener.previousTaxonNames";
55         public static final String PREVIOUS_ACCESS_CODE_PROPERTY_NAME = "UpdateAccessCodeListener.previousAccessCode";
56         public static final String DELETED_RELATION_PARENT_CSID_PROPERTY_NAME = "UpdateAccessCodeListener.deletedRelationParentCsid";
57
58         private static final String[] TAXON_PATH_ELEMENTS = CollectionObjectBotGardenConstants.TAXON_FIELD_NAME.split("/");
59         private static final String TAXONOMIC_IDENT_GROUP_LIST_FIELD_NAME = TAXON_PATH_ELEMENTS[0];
60         private static final String TAXON_FIELD_NAME = TAXON_PATH_ELEMENTS[2];
61
62         @Override
63         public boolean shouldHandleEvent(Event event) {
64                 return event.getContext() instanceof DocumentEventContext;
65         }
66         
67         @Override
68         public void handleCSEvent(Event event) {
69                 EventContext ec = event.getContext();
70
71                 DocumentEventContext context = (DocumentEventContext) ec;
72                 DocumentModel doc = context.getSourceDocument();
73                 String docType = doc.getType();
74
75                 logger.debug("docType=" + docType);
76
77                 if (docType.startsWith(CollectionObjectConstants.NUXEO_DOCTYPE) &&
78                                 !doc.isVersion() &&
79                                 !doc.isProxy() &&
80                                 !doc.getCurrentLifeCycleState().equals(WorkflowClient.WORKFLOWSTATE_DELETED)) {
81
82                         if (event.getName().equals(DocumentEventTypes.BEFORE_DOC_UPDATE)) {
83                                 // Stash the previous dead flag and taxonomic ident values, so they can be retrieved in the documentModified handler.
84
85                                 DocumentModel previousDoc = (DocumentModel) context.getProperty(CoreEventConstants.PREVIOUS_DOCUMENT_MODEL);
86
87                                 String previousDeadFlag = (String) previousDoc.getProperty(CollectionObjectBotGardenConstants.DEAD_FLAG_SCHEMA_NAME,
88                                                 CollectionObjectBotGardenConstants.DEAD_FLAG_FIELD_NAME);
89                                 context.setProperty(PREVIOUS_DEAD_FLAG_PROPERTY_NAME, previousDeadFlag);
90
91                                 List<String> previousTaxonNames = getTaxonNames(previousDoc);
92                                 context.setProperty(PREVIOUS_TAXON_NAMES_PROPERTY_NAME, previousTaxonNames.toArray(new String[previousTaxonNames.size()]));
93                         }
94                         else {
95                                 boolean deadFlagChanged = false;
96                                 Set<String> deletedTaxonNames = null;
97                                 Set<String> addedTaxonNames = null;
98
99                                 String currentDeadFlag = (String) doc.getProperty(CollectionObjectBotGardenConstants.DEAD_FLAG_SCHEMA_NAME,
100                                                 CollectionObjectBotGardenConstants.DEAD_FLAG_FIELD_NAME);
101
102                                 if (currentDeadFlag == null) {
103                                         currentDeadFlag = "";
104                                 }
105
106                                 if (event.getName().equals(DocumentEventTypes.DOCUMENT_UPDATED)) {
107                                         // As an optimization, check if the dead flag of the collectionobject has
108                                         // changed, or if the taxonomic identification has changed. If so, we need to
109                                         // update the access codes of referenced taxon records.
110
111                                         String previousDeadFlag = (String) context.getProperty(PREVIOUS_DEAD_FLAG_PROPERTY_NAME);
112
113                                         if (previousDeadFlag == null) {
114                                                 previousDeadFlag = "";
115                                         }
116
117                                         if (previousDeadFlag.equals(currentDeadFlag)) {
118                                                 logger.debug("dead flag not changed: previousDeadFlag=" + previousDeadFlag + " currentDeadFlag=" + currentDeadFlag);
119                                         }
120                                         else {
121                                                 logger.debug("dead flag changed: previousDeadFlag=" + previousDeadFlag + " currentDeadFlag=" + currentDeadFlag);
122                                                 deadFlagChanged = true;
123                                         }
124
125                                         List<String> previousTaxonNames = Arrays.asList((String[]) context.getProperty(PREVIOUS_TAXON_NAMES_PROPERTY_NAME));
126                                         List<String> currentTaxonNames = getTaxonNames(doc);
127
128                                         deletedTaxonNames = findDeletedTaxonNames(previousTaxonNames, currentTaxonNames);
129                                         logger.debug("found deleted taxon names: " + StringUtils.join(deletedTaxonNames, ", "));
130
131                                         addedTaxonNames = findAddedTaxonNames(previousTaxonNames, currentTaxonNames);
132                                         logger.debug("found added taxon names: " + StringUtils.join(addedTaxonNames, ", "));
133                                 }
134                                 else if (event.getName().equals(DocumentEventTypes.DOCUMENT_CREATED)) {
135                                         deadFlagChanged = true;
136                                 }
137
138                                 if (deadFlagChanged) {
139                                         String collectionObjectCsid = doc.getName();
140
141                                         try {
142                                                 // Pass false for the second parameter to updateReferencedAccessCodes, so that it doesn't
143                                                 // propagate changes up the taxon hierarchy. Propagation is taken care of by this
144                                                 // event handler: As taxon records are modified, this handler executes, and updates the
145                                                 // parent.
146
147                                                 InvocationResults results = createUpdater(context).updateReferencedAccessCodes(collectionObjectCsid, false);
148
149                                                 logger.debug("updateReferencedAccessCodes complete: numAffected=" + results.getNumAffected() + " userNote=" + results.getUserNote());
150                                         }
151                                         catch (Exception e) {
152                                                 logger.error(e.getMessage(), e);
153                                         }
154                                 }
155                                 else {
156                                         // If the dead flag didn't change, we still need to recalculate the access codes of
157                                         // any taxonomic idents that were added.
158
159                                         if (addedTaxonNames != null) {
160                                                 boolean isDead = currentDeadFlag.equalsIgnoreCase("true");
161                                                 boolean knownAlive = !isDead;
162
163                                                 for (String addedTaxonName : addedTaxonNames) {
164                                                         logger.debug("updating added taxon: " + addedTaxonName);
165
166                                                         try {
167                                                                 UpdateAccessCodeResults results = createUpdater(context).updateAccessCode(addedTaxonName, false, knownAlive);
168
169                                                                 logger.debug("updateAccessCode complete: numAffected=" + results.getNumAffected());
170                                                         }
171                                                         catch (Exception e) {
172                                                                 logger.error(e.getMessage(), e);
173                                                         }
174                                                 }
175                                         }
176                                 }
177
178                                 if (deletedTaxonNames != null) {
179                                         // If any taxonomic idents were removed from the collectionobject, they need to have their
180                                         // access codes recalculated.
181
182                                         for (String deletedTaxonName : deletedTaxonNames) {
183                                                 logger.debug("updating deleted taxon: " + deletedTaxonName);
184
185                                                 try {
186                                                         InvocationResults results = createUpdater(context).updateAccessCode(deletedTaxonName, false);
187
188                                                         logger.debug("updateAccessCode complete: numAffected=" + results.getNumAffected() + " userNote=" + results.getUserNote());
189                                                 }
190                                                 catch (Exception e) {
191                                                         logger.error(e.getMessage(), e);
192                                                 }
193                                         }
194                                 }
195                         }
196                 }
197                 else if (docType.startsWith(TaxonConstants.NUXEO_DOCTYPE) &&
198                                 !docType.startsWith(TaxonomyAuthorityConstants.NUXEO_DOCTYPE) &&
199                                 !doc.isVersion() &&
200                                 !doc.isProxy() &&
201                                 !doc.getCurrentLifeCycleState().equals(WorkflowClient.WORKFLOWSTATE_DELETED)) {
202
203                         if (event.getName().equals(DocumentEventTypes.BEFORE_DOC_UPDATE)) {
204                                 // Stash the previous access code value, so it can be retrieved in the documentModified handler.
205
206                                 DocumentModel previousDoc = (DocumentModel) context.getProperty(CoreEventConstants.PREVIOUS_DOCUMENT_MODEL);
207                                 String previousAccessCode = (String) previousDoc.getProperty(TaxonBotGardenConstants.ACCESS_CODE_SCHEMA_NAME, TaxonBotGardenConstants.ACCESS_CODE_FIELD_NAME);
208
209                                 context.setProperty(PREVIOUS_ACCESS_CODE_PROPERTY_NAME, previousAccessCode);
210                         }
211                         else {
212                                 boolean updateRequired = false;
213
214                                 if (event.getName().equals(DocumentEventTypes.DOCUMENT_UPDATED)) {
215                                         // As an optimization, check if the access code of the taxon has
216                                         // changed. We only need to update the access code of the parent taxon
217                                         // record if it has.
218
219                                         String previousAccessCode = (String) context.getProperty(PREVIOUS_ACCESS_CODE_PROPERTY_NAME);
220                                         String currentAccessCode = (String) doc.getProperty(TaxonBotGardenConstants.ACCESS_CODE_SCHEMA_NAME, TaxonBotGardenConstants.ACCESS_CODE_FIELD_NAME);
221
222                                         if (previousAccessCode == null) {
223                                                 previousAccessCode = "";
224                                         }
225
226                                         if (currentAccessCode == null) {
227                                                 currentAccessCode = "";
228                                         }
229
230                                         if (previousAccessCode.equals(currentAccessCode)) {
231                                                 logger.debug("update not required: previousAccessCode=" + previousAccessCode + " currentAccessCode=" + currentAccessCode);
232                                         }
233                                         else {
234                                                 logger.debug("update required: previousAccessCode=" + previousAccessCode + " currentAccessCode=" + currentAccessCode);
235                                                 updateRequired = true;
236                                         }
237                                 }
238                                 else if (event.getName().equals(DocumentEventTypes.DOCUMENT_CREATED)) {
239                                         updateRequired = true;
240                                 }
241
242                                 if (updateRequired) {
243                                         String taxonCsid = doc.getName();
244
245                                         try {
246                                                 // Pass false for the second parameter to updateReferencedAccessCodes, so that it doesn't
247                                                 // propagate changes up the taxon hierarchy. Propagation is taken care of by this
248                                                 // event handler: As taxon records are modified, this handler executes, and updates the
249                                                 // parent.
250
251                                                 InvocationResults results = createUpdater(context).updateParentAccessCode(taxonCsid, false);
252
253                                                 logger.debug("updateParentAccessCode complete: numAffected=" + results.getNumAffected() + " userNote=" + results.getUserNote());
254                                         }
255                                         catch (Exception e) {
256                                                 logger.error(e.getMessage(), e);
257                                         }
258                                 }
259                         }
260                 }
261                 else if (doc.getType().equals(RelationConstants.NUXEO_DOCTYPE) &&
262                                 !doc.isVersion() &&
263                                 !doc.isProxy()) {
264
265                         if (event.getName().equals(DocumentEventTypes.DOCUMENT_CREATED)) {
266                                 String subjectDocType = (String) doc.getProperty(RelationConstants.SUBJECT_DOCTYPE_SCHEMA_NAME, RelationConstants.SUBJECT_DOCTYPE_FIELD_NAME);
267                                 String objectDocType = (String) doc.getProperty(RelationConstants.OBJECT_DOCTYPE_SCHEMA_NAME, RelationConstants.OBJECT_DOCTYPE_FIELD_NAME);;
268                                 String relationType = (String) doc.getProperty(RelationConstants.TYPE_SCHEMA_NAME, RelationConstants.TYPE_FIELD_NAME);
269
270                                 logger.debug("subjectDocType=" + subjectDocType + " objectDocType=" + objectDocType + " relationType=" + relationType);
271
272                                 if (subjectDocType.equals(TaxonConstants.NUXEO_DOCTYPE) && objectDocType.equals(TaxonConstants.NUXEO_DOCTYPE) && relationType.equals(RelationConstants.BROADER_TYPE)) {
273                                         String parentTaxonCsid = (String) doc.getProperty(RelationConstants.OBJECT_CSID_SCHEMA_NAME, RelationConstants.OBJECT_CSID_FIELD_NAME);
274                                         String childTaxonCsid = (String) doc.getProperty(RelationConstants.SUBJECT_CSID_SCHEMA_NAME, RelationConstants.SUBJECT_CSID_FIELD_NAME);
275
276                                         logger.debug("child added, updating parent taxon: parentTaxonCsid=" + parentTaxonCsid + " childTaxonCsid=" + childTaxonCsid);
277
278                                         try {
279                                                 UpdateAccessCodeResults results = createUpdater(context).updateAccessCode(parentTaxonCsid, false, childTaxonCsid);
280
281                                                 logger.debug("updateAccessCode complete: numAffected=" + results.getNumAffected());
282                                         }
283                                         catch (Exception e) {
284                                                 logger.error(e.getMessage(), e);
285                                         }
286                                 }
287                         }
288                         else if (event.getName().equals(DocumentEventTypes.ABOUT_TO_REMOVE)) {
289                                 String subjectDocType = (String) doc.getProperty(RelationConstants.SUBJECT_DOCTYPE_SCHEMA_NAME, RelationConstants.SUBJECT_DOCTYPE_FIELD_NAME);
290                                 String objectDocType = (String) doc.getProperty(RelationConstants.OBJECT_DOCTYPE_SCHEMA_NAME, RelationConstants.OBJECT_DOCTYPE_FIELD_NAME);;
291                                 String relationType = (String) doc.getProperty(RelationConstants.TYPE_SCHEMA_NAME, RelationConstants.TYPE_FIELD_NAME);
292
293                                 logger.debug("subjectDocType=" + subjectDocType + " objectDocType=" + objectDocType + " relationType=" + relationType);
294
295                                 if (subjectDocType.equals(TaxonConstants.NUXEO_DOCTYPE) && objectDocType.equals(TaxonConstants.NUXEO_DOCTYPE) && relationType.equals(RelationConstants.BROADER_TYPE)) {
296                                         String parentTaxonCsid = (String) doc.getProperty(RelationConstants.OBJECT_CSID_SCHEMA_NAME, RelationConstants.OBJECT_CSID_FIELD_NAME);
297
298                                         // Stash the parent taxon csid, so it can be retrieved in the documentRemoved handler.
299                                         logger.debug("about to delete taxon hierarchy relation: parentTaxonCsid=" + parentTaxonCsid);
300                                         context.setProperty(DELETED_RELATION_PARENT_CSID_PROPERTY_NAME, parentTaxonCsid);
301                                 }
302                         }
303                         else if (event.getName().equals(DocumentEventTypes.DOCUMENT_REMOVED)) {
304                                 String parentTaxonCsid = (String) context.getProperty(DELETED_RELATION_PARENT_CSID_PROPERTY_NAME);
305
306                                 if (StringUtils.isNotEmpty(parentTaxonCsid)) {
307                                         logger.debug("child removed, updating parent taxon: parentTaxonCsid=" + parentTaxonCsid);
308
309                                         try {
310                                                 InvocationResults results = createUpdater(context).updateAccessCode(parentTaxonCsid, false);
311
312                                                 logger.debug("updateAccessCode complete: numAffected=" + results.getNumAffected() + " userNote=" + results.getUserNote());
313                                         }
314                                         catch (Exception e) {
315                                                 logger.error(e.getMessage(), e);
316                                         }
317                                 }
318                         }
319                 }
320         }
321
322         private List<String> getTaxonNames(DocumentModel doc) {
323                 List<Map<String, Object>> taxonomicIdentGroupList = (List<Map<String, Object>>) doc.getProperty(CollectionObjectBotGardenConstants.TAXON_SCHEMA_NAME,
324                                 TAXONOMIC_IDENT_GROUP_LIST_FIELD_NAME);
325                 List<String> taxonNames = new ArrayList<String>();
326
327                 for (Map<String, Object> taxonomicIdentGroup : taxonomicIdentGroupList) {
328                         String taxonName = (String) taxonomicIdentGroup.get(TAXON_FIELD_NAME);
329
330                         if (StringUtils.isNotEmpty(taxonName)) {
331                                 taxonNames.add(taxonName);
332                         }
333                 }
334
335                 return taxonNames;
336         }
337
338         private Set<String> findDeletedTaxonNames(List<String> previousTaxonNames, List<String> currentTaxonNames) {
339                 Set<String> currentTaxonNameSet = new HashSet<String>(currentTaxonNames);
340                 Set<String> deletedTaxonNameSet = new HashSet<String>();
341
342                 for (String previousTaxonName : previousTaxonNames) {
343                         if (!currentTaxonNameSet.contains(previousTaxonName)) {
344                                 deletedTaxonNameSet.add(previousTaxonName);
345                         }
346                 }
347
348                 return deletedTaxonNameSet;
349         }
350
351         private Set<String> findAddedTaxonNames(List<String> previousTaxonNames, List<String> currentTaxonNames) {
352                 Set<String> previousTaxonNameSet = new HashSet<String>(previousTaxonNames);
353                 Set<String> addedTaxonNameSet = new HashSet<String>();
354
355                 for (String currentTaxonName : currentTaxonNames) {
356                         if (!previousTaxonNameSet.contains(currentTaxonName)) {
357                                 addedTaxonNameSet.add(currentTaxonName);
358                         }
359                 }
360
361                 return addedTaxonNameSet;
362         }
363
364         private UpdateAccessCodeBatchJob createUpdater(DocumentEventContext context) throws Exception {
365                 ResourceMap resourceMap = ResteasyProviderFactory.getContextData(ResourceMap.class);
366                 BatchResource batchResource = (BatchResource) resourceMap.get(BatchClient.SERVICE_NAME);
367                 ServiceContext<PoxPayloadIn, PoxPayloadOut> serviceContext = batchResource.createServiceContext(batchResource.getServiceName());
368
369                 serviceContext.setCurrentRepositorySession(new CoreSessionWrapper(context.getCoreSession()));
370
371                 UpdateAccessCodeBatchJob updater = new UpdateAccessCodeBatchJob();
372                 updater.setServiceContext(serviceContext);
373                 updater.setResourceMap(resourceMap);
374
375                 return updater;
376         }
377         
378         @Override
379         public Log getLogger() {
380                 return logger;
381         }
382 }