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