]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
2bf7797346c778e2c7f28e41e0cf70274213f74c
[tmp/jakarta-migration.git] /
1 package org.collectionspace.services.nuxeo.elasticsearch;
2
3 import java.io.IOException;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.Calendar;
7 import java.util.Collections;
8 import java.util.GregorianCalendar;
9 import java.util.HashSet;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Set;
14
15 import javax.ws.rs.core.HttpHeaders;
16
17 import org.apache.commons.lang3.StringUtils;
18 import org.codehaus.jackson.JsonGenerator;
19 import org.codehaus.jackson.JsonNode;
20 import org.codehaus.jackson.map.ObjectMapper;
21 import org.codehaus.jackson.node.IntNode;
22 import org.codehaus.jackson.node.ObjectNode;
23 import org.codehaus.jackson.node.TextNode;
24 import org.collectionspace.services.common.api.RefNameUtils;
25 import org.nuxeo.ecm.automation.jaxrs.io.documents.JsonESDocumentWriter;
26 import org.nuxeo.ecm.core.api.CoreSession;
27 import org.nuxeo.ecm.core.api.DocumentModel;
28 import org.nuxeo.ecm.core.api.DocumentModelList;
29
30 public class DefaultESDocumentWriter extends JsonESDocumentWriter {
31         private static ObjectMapper objectMapper = new ObjectMapper();
32
33         @Override
34         public void writeDoc(JsonGenerator jg, DocumentModel doc, String[] schemas,
35                         Map<String, String> contextParameters, HttpHeaders headers)
36                         throws IOException {
37
38                 ObjectNode denormValues = getDenormValues(doc);
39
40                 jg.writeStartObject();
41
42                 writeSystemProperties(jg, doc);
43                 writeSchemas(jg, doc, schemas);
44                 writeContextParameters(jg, doc, contextParameters);
45                 writeDenormValues(jg, doc, denormValues);
46
47                 jg.writeEndObject();
48                 jg.flush();
49         }
50
51         public ObjectNode getDenormValues(DocumentModel doc) {
52                 ObjectNode denormValues = objectMapper.createObjectNode();
53                 String docType = doc.getType();
54
55                 if (docType.startsWith("CollectionObject")) {
56                         CoreSession session = doc.getCoreSession();
57                         String csid = doc.getName();
58                         String tenantId = (String) doc.getProperty("collectionspace_core", "tenantId");
59
60                         denormMediaRecords(session, csid, tenantId, denormValues);
61                         denormAcquisitionRecords(session, csid, tenantId, denormValues);
62                         denormExhibitionRecords(session, csid, tenantId, denormValues);
63
64                         // Compute the title of the record for the public browser, and store it so that it can
65                         // be used for sorting ES query results.
66
67                         String title = computeTitle(doc);
68
69                         if (title != null) {
70                                 denormValues.put("title", title);
71                         }
72
73                         // Create a list of production years from the production date structured dates.
74
75                         List<Map<String, Object>> prodDateGroupList = (List<Map<String, Object>>) doc.getProperty("collectionobjects_common", "objectProductionDateGroupList");
76
77                         denormValues.putArray("prodYears").addAll(structDatesToYearNodes(prodDateGroupList));
78                 }
79
80                 return denormValues;
81         }
82
83         public void writeDenormValues(JsonGenerator jg, DocumentModel doc, ObjectNode denormValues) throws IOException {
84                 if (denormValues != null && denormValues.size() > 0) {
85                         if (jg.getCodec() == null) {
86                                 jg.setCodec(objectMapper);
87                         }
88
89                         Iterator<Map.Entry<String, JsonNode>> entries = denormValues.getFields();
90
91                         while (entries.hasNext()) {
92                                 Map.Entry<String, JsonNode> entry = entries.next();
93
94                                 jg.writeFieldName("collectionspace_denorm:" + entry.getKey());
95                                 jg.writeTree(entry.getValue());
96                         }
97                 }
98         }
99
100         private void denormMediaRecords(CoreSession session, String csid, String tenantId, ObjectNode denormValues) {
101                 // Store the csid and alt text of media records that are related to this object.
102
103                 String relatedRecordQuery = String.format("SELECT * FROM Relation WHERE relations_common:subjectCsid = '%s' AND relations_common:objectDocumentType = 'Media' AND ecm:currentLifeCycleState = 'project' AND collectionspace_core:tenantId = '%s'", csid, tenantId);
104                 DocumentModelList relationDocs = session.query(relatedRecordQuery);
105                 List<JsonNode> mediaCsids = new ArrayList<JsonNode>();
106                 List<JsonNode> mediaAltTexts = new ArrayList<JsonNode>();
107
108                 if (relationDocs.size() > 0) {
109                         Iterator<DocumentModel> iterator = relationDocs.iterator();
110
111                         while (iterator.hasNext()) {
112                                 DocumentModel relationDoc = iterator.next();
113                                 String mediaCsid = (String) relationDoc.getProperty("relations_common", "objectCsid");
114                                 DocumentModel mediaDoc = getRecordByCsid(session, tenantId, "Media", mediaCsid);
115
116                                 if (isMediaPublished(mediaDoc)) {
117                                         mediaCsids.add(new TextNode(mediaCsid));
118
119                                         String altText = (String) mediaDoc.getProperty("media_common", "altText");
120
121                                         if (altText == null) {
122                                                 altText = "";
123                                         }
124
125                                         mediaAltTexts.add(new TextNode(altText));
126                                 }
127                         }
128                 }
129
130                 denormValues.putArray("mediaCsid").addAll(mediaCsids);
131                 denormValues.putArray("mediaAltText").addAll(mediaAltTexts);
132                 denormValues.put("hasMedia", mediaCsids.size() > 0);
133         }
134
135         private void denormAcquisitionRecords(CoreSession session, String csid, String tenantId, ObjectNode denormValues) {
136                 // Store the credit lines of acquisition records that are related to this object.
137
138                 String relatedRecordQuery = String.format("SELECT * FROM Relation WHERE relations_common:subjectCsid = '%s' AND relations_common:objectDocumentType = 'Acquisition' AND ecm:currentLifeCycleState = 'project' AND collectionspace_core:tenantId = '%s'", csid, tenantId);
139                 DocumentModelList relationDocs = session.query(relatedRecordQuery);
140                 List<JsonNode> creditLines = new ArrayList<JsonNode>();
141
142                 if (relationDocs.size() > 0) {
143                         Iterator<DocumentModel> iterator = relationDocs.iterator();
144
145                         while (iterator.hasNext()) {
146                                 DocumentModel relationDoc = iterator.next();
147                                 String acquisitionCsid = (String) relationDoc.getProperty("relations_common", "objectCsid");
148                                 String creditLine = getCreditLine(session, tenantId, acquisitionCsid);
149
150                                 if (creditLine != null && creditLine.length() > 0) {
151                                         creditLines.add(new TextNode(creditLine));
152                                 }
153                         }
154                 }
155
156                 denormValues.putArray("creditLine").addAll(creditLines);
157 }
158
159 private void denormExhibitionRecords(CoreSession session, String csid, String tenantId, ObjectNode denormValues) {
160         // Store the title, general note, and curatorial note of exhibition records that are published, and related to this object.
161
162         String relatedRecordQuery = String.format("SELECT * FROM Relation WHERE relations_common:subjectCsid = '%s' AND relations_common:objectDocumentType = 'Exhibition' AND ecm:currentLifeCycleState = 'project' AND collectionspace_core:tenantId = '%s'", csid, tenantId);
163         DocumentModelList relationDocs = session.query(relatedRecordQuery);
164         List<JsonNode> exhibitions = new ArrayList<JsonNode>();
165
166         if (relationDocs.size() > 0) {
167                 Iterator<DocumentModel> iterator = relationDocs.iterator();
168
169                 while (iterator.hasNext()) {
170                         DocumentModel relationDoc = iterator.next();
171                         String exhibitionCsid = (String) relationDoc.getProperty("relations_common", "objectCsid");
172                         DocumentModel exhibitionDoc = getRecordByCsid(session, tenantId, "Exhibition", exhibitionCsid);
173
174                         if (exhibitionDoc != null && isExhibitionPublished(exhibitionDoc)) {
175                                 ObjectNode exhibitionNode = objectMapper.createObjectNode();
176
177                                 String title = (String) exhibitionDoc.getProperty("exhibitions_common", "title");
178                                 String generalNote = (String) exhibitionDoc.getProperty("exhibitions_common", "generalNote");
179                                 String curatorialNote = (String) exhibitionDoc.getProperty("exhibitions_common", "curatorialNote");
180
181                                 exhibitionNode.put("title", title);
182                                 exhibitionNode.put("generalNote", generalNote);
183                                 exhibitionNode.put("curatorialNote", curatorialNote);
184
185                                 exhibitions.add(exhibitionNode);
186                         }
187                 }
188         }
189
190         denormValues.putArray("exhibition").addAll(exhibitions);
191 }
192
193         /**
194          * Compute a title for the public browser. This needs to be indexed in ES so that it can
195          * be used for sorting. (Even if it's just extracting the primary value.)
196          */
197         private String computeTitle(DocumentModel doc) {
198                 List<Map<String, Object>> titleGroups = (List<Map<String, Object>>) doc.getProperty("collectionobjects_common", "titleGroupList");
199                 String primaryTitle = null;
200
201                 if (titleGroups.size() > 0) {
202                         Map<String, Object> primaryTitleGroup = titleGroups.get(0);
203                         primaryTitle = (String) primaryTitleGroup.get("title");
204                 }
205
206                 if (StringUtils.isNotEmpty(primaryTitle)) {
207                         return primaryTitle;
208                 }
209
210                 List<Map<String, Object>> objectNameGroups = (List<Map<String, Object>>) doc.getProperty("collectionobjects_common", "objectNameList");
211                 String primaryObjectName = null;
212
213                 if (objectNameGroups.size() > 0) {
214                         Map<String, Object> primaryObjectNameGroup = objectNameGroups.get(0);
215                         primaryObjectName = (String) primaryObjectNameGroup.get("objectName");
216                 }
217
218                 return primaryObjectName;
219         }
220
221         private boolean isPublished(DocumentModel doc, String publishedFieldPart, String publishedFieldName) {
222                 boolean isPublished = false;
223
224                 if (doc != null) {
225                         List<String> publishToValues = (List<String>) doc.getProperty(publishedFieldPart, publishedFieldName);
226
227                         if (publishToValues != null) {
228                                 for (int i=0; i<publishToValues.size(); i++) {
229                                         String value = publishToValues.get(i);
230                                         String shortId = RefNameUtils.getItemShortId(value);
231
232                                         if (shortId.equals("all") || shortId.equals("cspacepub")) {
233                                                 isPublished = true;
234                                                 break;
235                                         }
236                                 }
237                         }
238                 }
239
240                 return isPublished;
241
242         }
243
244         private boolean isMediaPublished(DocumentModel mediaDoc) {
245                 return isPublished(mediaDoc, "media_common", "publishToList");
246         }
247
248         private boolean isExhibitionPublished(DocumentModel exhibitionDoc) {
249                 return isPublished(exhibitionDoc, "exhibitions_common", "publishToList");
250         }
251
252         private String getCreditLine(CoreSession session, String tenantId, String acquisitionCsid) {
253                 String creditLine = null;
254                 DocumentModel acquisitionDoc = getRecordByCsid(session, tenantId, "Acquisition", acquisitionCsid);
255
256                 if (acquisitionDoc != null) {
257                         creditLine = (String) acquisitionDoc.getProperty("acquisitions_common", "creditLine");
258                 }
259
260                 return creditLine;
261         }
262
263         protected DocumentModel getRecordByCsid(CoreSession session, String tenantId, String recordType, String csid) {
264                 String getRecordQuery = String.format("SELECT * FROM %s WHERE ecm:name = '%s' AND ecm:currentLifeCycleState = 'project' AND collectionspace_core:tenantId = '%s'", recordType, csid, tenantId);
265
266                 DocumentModelList docs = session.query(getRecordQuery);
267
268                 if (docs != null && docs.size() > 0) {
269                         return docs.get(0);
270                 }
271
272                 return null;
273         }
274
275         protected List<JsonNode> structDateToYearNodes(Map<String, Object> structDate) {
276                 return structDatesToYearNodes(Arrays.asList(structDate));
277         }
278
279         protected List<JsonNode> structDatesToYearNodes(List<Map<String, Object>> structDates) {
280                 Set<Integer> years = new HashSet<Integer>();
281
282                 for (Map<String, Object> structDate : structDates) {
283                         if (structDate != null) {
284                                 GregorianCalendar earliestCalendar = (GregorianCalendar) structDate.get("dateEarliestScalarValue");
285                                 GregorianCalendar latestCalendar = (GregorianCalendar) structDate.get("dateLatestScalarValue");
286
287                                 if (earliestCalendar != null && latestCalendar != null) {
288                                         // Grr @ latest scalar value historically being exclusive.
289                                         // Subtract one day to make it inclusive.
290                                         latestCalendar.add(Calendar.DATE, -1);
291
292                                         Integer earliestYear = earliestCalendar.get(Calendar.YEAR);
293                                         Integer latestYear = latestCalendar.get(Calendar.YEAR);;
294
295                                         for (int year = earliestYear; year <= latestYear; year++) {
296                                                 years.add(year);
297                                         }
298                                 }
299                         }
300                 }
301
302                 List<Integer> yearList = new ArrayList<Integer>(years);
303                 Collections.sort(yearList);
304
305                 List<JsonNode> yearNodes = new ArrayList<JsonNode>();
306
307                 for (Integer year : yearList) {
308                         yearNodes.add(new IntNode(year));
309                 }
310
311                 return yearNodes;
312         }
313 }