]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
c32ca0a49637b3982ae8c402725faeec56c6651b
[tmp/jakarta-migration.git] /
1 package org.collectionspace.services.listener;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6
7 import org.apache.commons.collections.ListUtils;
8 import org.apache.commons.lang3.StringUtils;
9 import org.collectionspace.services.common.api.RefNameUtils;
10 import org.collectionspace.services.nuxeo.listener.AbstractCSEventPostCommitListenerImpl;
11 import org.nuxeo.ecm.core.api.CoreSession;
12 import org.nuxeo.ecm.core.api.DocumentModel;
13 import org.nuxeo.ecm.core.api.DocumentModelList;
14 import org.nuxeo.ecm.core.api.event.DocumentEventTypes;
15 import org.nuxeo.ecm.core.event.Event;
16 import org.nuxeo.ecm.core.event.EventBundle;
17 import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
18 import org.nuxeo.elasticsearch.ElasticSearchComponent;
19 import org.nuxeo.elasticsearch.api.ElasticSearchService;
20 import org.nuxeo.runtime.api.Framework;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 /**
25  * Event listener that triggers reindexing of records in Elasticsearch when an associated record
26  * is created/updated/deleted. When a record is created or updated Nuxeo will automatically
27  * reindex it in ElasticSearch, but Nuxeo does not know about other records that may also need to
28  * be reindexed; for example, if a related record denormalizes data from the updated record at
29  * index time.
30  */
31 public class Reindex extends AbstractCSEventPostCommitListenerImpl {
32         private static final Logger logger = LoggerFactory.getLogger(Reindex.class);
33
34         // This listener runs asynchronously post-commit, so that reindexing records after a
35         // save does not hold up the save.
36
37         public static final String PREV_COVERAGE_KEY = "Reindex.PREV_COVERAGE";
38         public static final String PREV_CREDIT_LINE_KEY = "Reindex.PREV_CREDIT_LINE";
39         public static final String PREV_PUBLISH_TO_KEY = "Reindex.PREV_PUBLISH_TO";
40         public static final String PREV_RELATED_COLLECTION_OBJECT_CSID_KEY = "Reindex.PREV_RELATED_COLLECTION_OBJECT_CSID";
41         public static final String ELASTICSEARCH_ENABLED_PROP = "elasticsearch.enabled";
42
43         @Override
44         public boolean shouldHandleEventBundle(EventBundle eventBundle) {
45                 if (Framework.isBooleanPropertyTrue(ELASTICSEARCH_ENABLED_PROP) && eventBundle.size() > 0) {
46                         return true;
47                 }
48
49                 return false;
50         }
51
52         @Override
53         public boolean shouldHandleEvent(Event event) {
54                 DocumentEventContext eventContext = (DocumentEventContext) event.getContext();
55                 DocumentModel doc = eventContext.getSourceDocument();
56                 String docType = doc.getType();
57
58                 if (
59                         docType.startsWith("Media")
60                         || docType.startsWith("Relation")
61                         || docType.startsWith("Acquisition")
62                 ) {
63                         return true;
64                 }
65
66                 return false;
67         }
68
69         @Override
70         @SuppressWarnings("unchecked")
71         public void handleCSEvent(Event event) {
72                 DocumentEventContext eventContext = (DocumentEventContext) event.getContext();
73                 DocumentModel doc = eventContext.getSourceDocument();
74                 String docType = doc.getType();
75                 String eventName = event.getName();
76
77                 // TODO: Make this configurable. This is currently hardcoded to the needs of the standard
78                 // profiles.
79
80                 if (docType.startsWith("Media")) {
81                         // When a media record is created, reindex the material item that is referenced by its
82                         // coverage field.
83
84                         // When a media record is updated and the coverage changed, reindex both the old and new
85                         // referenced material items.
86
87                         // When a media record is deleted, reindex the material item that was referenced by its
88                         // coverage field.
89
90                         if (
91                                 eventName.equals(DocumentEventTypes.DOCUMENT_CREATED) ||
92                                 eventName.equals(DocumentEventTypes.DOCUMENT_UPDATED)
93                         ) {
94                                 String prevCoverage = (String) eventContext.getProperty(PREV_COVERAGE_KEY);
95                                 String coverage = (String) doc.getProperty("media_common", "coverage");
96
97                                 List<String> prevPublishTo = (List<String>) eventContext.getProperty(PREV_PUBLISH_TO_KEY);
98
99                                 // Materials profile had publishToList defined in a local extension schema before
100                                 // that field was added to the common schema.
101
102                                 List<String> publishTo = (List<String>) doc.getProperty(
103                                         doc.hasSchema("media_materials") ? "media_materials" : "media_common",
104                                         "publishToList");
105
106                                 if (
107                                         !ListUtils.isEqualList(prevPublishTo, publishTo) ||
108                                         !StringUtils.equals(prevCoverage, coverage)
109                                 ) {
110                                         if (!StringUtils.equals(prevCoverage, coverage)) {
111                                                 reindexMaterial(doc.getRepositoryName(), prevCoverage);
112                                         }
113
114                                         reindexMaterial(doc.getRepositoryName(), coverage);
115
116                                         if (!ListUtils.isEqualList(prevPublishTo, publishTo)) {
117                                                 reindexRelatedCollectionObjects(doc);
118                                         }
119                                 }
120                         }
121                         else if (eventName.equals("lifecycle_transition_event") && doc.getCurrentLifeCycleState().equals("deleted")) {
122                                 String coverage = (String) doc.getProperty("media_common", "coverage");
123
124                                 reindexMaterial(doc.getRepositoryName(), coverage);
125                         }
126                         else if (eventName.equals(DocumentEventTypes.DOCUMENT_REMOVED)) {
127                                 String prevCoverage = (String) eventContext.getProperty(PREV_COVERAGE_KEY);
128
129                                 reindexMaterial(doc.getRepositoryName(), prevCoverage);
130                                 reindexPrevRelatedCollectionObjects(eventContext);
131                         }
132                 }
133                 else if (docType.startsWith("Acquisition")) {
134                         if (eventName.equals(DocumentEventTypes.DOCUMENT_UPDATED)) {
135                                 String prevCreditLine = (String) eventContext.getProperty(PREV_CREDIT_LINE_KEY);
136                                 String creditLine = (String) doc.getProperty("acquisitions_common", "creditLine");
137
138                                 if (!StringUtils.equals(prevCreditLine, creditLine)) {
139                                         reindexRelatedCollectionObjects(doc);
140                                 }
141                         }
142                         else if (eventName.equals(DocumentEventTypes.DOCUMENT_REMOVED)) {
143                                 reindexPrevRelatedCollectionObjects(eventContext);
144                         }
145                 }
146                 else if (docType.startsWith("Relation")) {
147                         if (
148                                 eventName.equals(DocumentEventTypes.DOCUMENT_CREATED)
149                                 || (eventName.equals("lifecycle_transition_event") && doc.getCurrentLifeCycleState().equals("deleted"))
150                         ) {
151                                 String subjectDocumentType = (String) doc.getProperty("relations_common", "subjectDocumentType");
152                                 String objectDocumentType = (String) doc.getProperty("relations_common", "objectDocumentType");
153
154                                 if (
155                                         (subjectDocumentType.equals("Media") || subjectDocumentType.equals("Acquisition"))
156                                         && objectDocumentType.equals("CollectionObject")
157                                 ) {
158                                         String collectionObjectCsid = (String) doc.getProperty("relations_common", "objectCsid");
159
160                                         reindexCollectionObject(doc.getRepositoryName(), collectionObjectCsid);
161                                 }
162                         }
163                         else if (eventName.equals(DocumentEventTypes.DOCUMENT_REMOVED)) {
164                                 reindexPrevRelatedCollectionObjects(eventContext);
165                         }
166                 }
167         }
168
169         @Override
170         protected Logger getLogger() {
171                 return logger;
172         }
173
174         private void reindexMaterial(String repositoryName, String refName) {
175                 if (StringUtils.isEmpty(refName) || !refName.startsWith(RefNameUtils.URN_PREFIX)) {
176                         return;
177                 }
178
179                 String escapedRefName = refName.replace("'", "\\'");
180                 String query = String.format("SELECT ecm:uuid FROM Materialitem WHERE collectionspace_core:refName = '%s'", escapedRefName);
181
182                 ElasticSearchComponent es = (ElasticSearchComponent) Framework.getService(ElasticSearchService.class);
183                 es.runReindexingWorker(repositoryName, query);
184         }
185
186         private void reindexPrevRelatedCollectionObjects(DocumentEventContext eventContext) {
187                 List<String> prevRelatedCollectionObjectCsids = (List<String>) eventContext.getProperty(PREV_RELATED_COLLECTION_OBJECT_CSID_KEY);
188
189                 if (prevRelatedCollectionObjectCsids != null) {
190                         for (String prevRelatedCollectionObjectCsid : prevRelatedCollectionObjectCsids) {
191                                 reindexCollectionObject(eventContext.getRepositoryName(), prevRelatedCollectionObjectCsid);
192                         }
193                 }
194         }
195
196         private void reindexRelatedCollectionObjects(DocumentModel doc) {
197                 CoreSession session = doc.getCoreSession();
198                 String repositoryName = doc.getRepositoryName();
199                 String tenantId = (String) doc.getProperty("collectionspace_core", "tenantId");
200                 String csid = doc.getName();
201
202                 String relatedRecordQuery = String.format("SELECT * FROM Relation WHERE relations_common:subjectCsid = '%s' AND relations_common:objectDocumentType = 'CollectionObject' AND ecm:currentLifeCycleState = 'project' AND collectionspace_core:tenantId = '%s'", csid, tenantId);
203                 DocumentModelList relationDocs = session.query(relatedRecordQuery);
204                 List<String> collectionObjectCsids = new ArrayList<String>();
205
206                 if (relationDocs.size() > 0) {
207                         Iterator<DocumentModel> iterator = relationDocs.iterator();
208
209                         while (iterator.hasNext()) {
210                                 DocumentModel relationDoc = iterator.next();
211                                 String collectionObjectCsid = (String) relationDoc.getProperty("relations_common", "objectCsid");
212
213                                 collectionObjectCsids.add(collectionObjectCsid);
214                         }
215                 }
216
217                 for (String collectionObjectCsid : collectionObjectCsids) {
218                         reindexCollectionObject(repositoryName, collectionObjectCsid);
219                 }
220         }
221
222         private void reindexCollectionObject(String repositoryName, String csid) {
223                 if (StringUtils.isEmpty(csid)) {
224                         return;
225                 }
226
227                 String query = String.format("SELECT ecm:uuid FROM CollectionObject WHERE ecm:name = '%s'", csid);
228
229                 ElasticSearchComponent es = (ElasticSearchComponent) Framework.getService(ElasticSearchService.class);
230                 es.runReindexingWorker(repositoryName, query);
231         }
232 }