1 package org.collectionspace.services.nuxeo.elasticsearch.materials;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Iterator;
6 import java.util.LinkedHashSet;
11 import org.apache.commons.lang3.StringUtils;
13 import org.codehaus.jackson.JsonNode;
14 import org.codehaus.jackson.map.ObjectMapper;
15 import org.codehaus.jackson.node.ObjectNode;
16 import org.codehaus.jackson.node.TextNode;
18 import org.collectionspace.services.common.api.RefNameUtils;
19 import org.collectionspace.services.nuxeo.elasticsearch.DefaultESDocumentWriter;
20 import org.nuxeo.ecm.core.api.CoreSession;
21 import org.nuxeo.ecm.core.api.DocumentModel;
22 import org.nuxeo.ecm.core.api.DocumentModelList;
24 public class MaterialsESDocumentWriter extends DefaultESDocumentWriter {
27 public ObjectNode getDenormValues(DocumentModel doc) {
28 ObjectMapper objectMapper = new ObjectMapper();
29 ObjectNode denormValues = objectMapper.createObjectNode();
31 String docType = doc.getType();
33 if (docType.startsWith("Materialitem")) {
34 CoreSession session = doc.getCoreSession();
36 // Store the csids of media records that reference this material authority item via the
39 String refName = (String) doc.getProperty("collectionspace_core", "refName");
41 if (StringUtils.isNotEmpty(refName)) {
42 String tenantId = (String) doc.getProperty("collectionspace_core", "tenantId");
44 denormMediaRecords(session, refName, tenantId, denormValues);
47 // Compute the title of the record for the public browser, and store it so that it can
48 // be used for sorting ES query results.
50 String title = computeTitle(doc);
53 denormValues.put("title", title);
56 List<Map<String, Object>> termGroups = (List<Map<String, Object>>) doc.getProperty("materials_common", "materialTermGroupList");
57 List<String> commercialNames = findTermDisplayNamesWithFlag(termGroups, "commercial");
58 List<String> commonNames = findTermDisplayNamesWithFlag(termGroups, "common");
60 // Find and store the commercial names and common names for this item. This simplifies
61 // search and display in the Material Order application.
63 if (commercialNames.size() > 0) {
64 denormValues.putArray("commercialNames").addAll(jsonNodes(commercialNames));
67 if (commonNames.size() > 0) {
68 denormValues.putArray("commonNames").addAll(jsonNodes(commonNames));
71 // Combine term creator organizations and term editor organizations into a holding
72 // institutions field.
74 Set<String> holdingInstitutions = new LinkedHashSet<String>();
76 holdingInstitutions.addAll(getTermAttributionContributors(doc));
77 holdingInstitutions.addAll(getTermAttributionEditors(doc));
79 if (holdingInstitutions.size() > 0) {
80 denormValues.putArray("holdingInstitutions").addAll(jsonNodes(holdingInstitutions));
84 // Below is sample code for denormalizing fields from the computed current location (place
85 // item) into collection object documents. This was written for the public browser
86 // prototype for public art.
89 if (docType.startsWith("CollectionObject")) {
90 CoreSession session = doc.getCoreSession();
92 String refName = (String) doc.getProperty("collectionobjects_common", "computedCurrentLocation");
94 if (StringUtils.isNotEmpty(refName)) {
95 String escapedRefName = refName.replace("'", "\\'");
96 String placeQuery = String.format("SELECT * FROM PlaceitemTenant5000 WHERE places_common:refName = '%s'", escapedRefName);
98 DocumentModelList placeDocs = session.query(placeQuery, 1);
100 if (placeDocs.size() > 0) {
101 DocumentModel placeDoc = placeDocs.get(0);
103 String placementType = (String) placeDoc.getProperty("places_publicart:placementType").getValue();
105 if (placementType != null) {
106 denormValues.put("placementType", placementType);
109 Property geoRefGroup;
112 geoRefGroup = placeDoc.getProperty("places_common:placeGeoRefGroupList/0");
113 } catch (PropertyNotFoundException e) {
117 if (geoRefGroup != null) {
118 Double decimalLatitude = (Double) geoRefGroup.getValue("decimalLatitude");
119 Double decimalLongitude = (Double) geoRefGroup.getValue("decimalLongitude");
121 if (decimalLatitude != null && decimalLongitude != null) {
122 ObjectNode geoPointNode = objectMapper.createObjectNode();
124 geoPointNode.put("lat", decimalLatitude);
125 geoPointNode.put("lon", decimalLongitude);
127 denormValues.put("geoPoint", geoPointNode);
133 String uri = (String) doc.getProperty("collectionobjects_core", "uri");
134 String csid = uri.substring(uri.lastIndexOf('/') + 1);
135 String mediaQuery = String.format("SELECT media_common:blobCsid, media_common:title FROM Relation WHERE relations_common:subjectCsid = '%s' AND relations_common:objectDocumentType = 'Media'", csid);
137 DocumentModelList mediaDocs = session.query(mediaQuery, 1);
139 if (mediaDocs.size() > 0) {
148 private void denormMediaRecords(CoreSession session, String refName, String tenantId, ObjectNode denormValues) {
149 // Store the csid and alt text of media records that are related to this object.
151 String escapedRefName = refName.replace("'", "\\'");
152 String mediaQuery = String.format("SELECT * FROM Media WHERE media_common:coverage = '%s' AND ecm:currentLifeCycleState = 'project' AND collectionspace_core:tenantId = '%s' ORDER BY media_common:identificationNumber", escapedRefName, tenantId);
153 DocumentModelList mediaDocs = session.query(mediaQuery);
154 List<JsonNode> mediaCsids = new ArrayList<JsonNode>();
155 List<JsonNode> mediaAltTexts = new ArrayList<JsonNode>();
157 if (mediaDocs.size() > 0) {
158 Iterator<DocumentModel> iterator = mediaDocs.iterator();
160 while (iterator.hasNext()) {
161 DocumentModel mediaDoc = iterator.next();
163 if (isMediaPublished(mediaDoc)) {
164 String mediaCsid = (String) mediaDoc.getName();
166 mediaCsids.add(new TextNode(mediaCsid));
168 String altText = (String) mediaDoc.getProperty("media_common", "altText");
170 if (altText == null) {
174 mediaAltTexts.add(new TextNode(altText));
179 denormValues.putArray("mediaCsid").addAll(mediaCsids);
180 denormValues.putArray("mediaAltText").addAll(mediaAltTexts);
185 * Compute a title for the public browser. This needs to be indexed in ES so that it can
186 * be used for sorting. (Even if it's just extracting the primary value.)
188 private String computeTitle(DocumentModel doc) {
189 List<Map<String, Object>> termGroups = (List<Map<String, Object>>) doc.getProperty("materials_common", "materialTermGroupList");
190 String primaryDisplayName = null;
192 if (termGroups.size() > 0) {
193 Map<String, Object> primaryTermGroup = termGroups.get(0);
194 primaryDisplayName = (String) primaryTermGroup.get("termDisplayName");
197 return primaryDisplayName;
200 private List<String> findTermDisplayNamesWithFlag(List<Map<String, Object>> termGroups, String flagShortId) {
201 List<String> termDisplayNames = new ArrayList<String>();
203 for (Map<String, Object> termGroup : termGroups) {
204 String termFlag = (String) termGroup.get("termFlag");
206 if (termFlag != null && termFlag.contains("(" + flagShortId + ")")) {
207 String candidateTermDisplayName = (String) termGroup.get("termDisplayName");
209 if (StringUtils.isNotEmpty(candidateTermDisplayName)) {
210 termDisplayNames.add(candidateTermDisplayName);
215 return termDisplayNames;
218 private Set<String> getTermAttributionContributors(DocumentModel doc) {
219 Set orgs = new LinkedHashSet<String>();
221 List<Map<String, Object>> groups = (List<Map<String, Object>>) doc.getProperty("materials_common", "materialTermAttributionContributingGroupList");
223 for (Map<String, Object> group : groups) {
224 String org = (String) group.get("materialTermAttributionContributingOrganization");
226 if (StringUtils.isNotEmpty(org)) {
234 private Set<String> getTermAttributionEditors(DocumentModel doc) {
235 Set orgs = new LinkedHashSet<String>();
237 List<Map<String, Object>> groups = (List<Map<String, Object>>) doc.getProperty("materials_common", "materialTermAttributionEditingGroupList");
239 for (Map<String, Object> group : groups) {
240 String org = (String) group.get("materialTermAttributionEditingOrganization");
242 if (StringUtils.isNotEmpty(org)) {
250 private boolean isMediaPublished(DocumentModel mediaDoc) {
251 List<String> publishToValues = (List<String>) mediaDoc.getProperty("media_materials", "publishToList");
252 boolean isPublished = false;
254 if (publishToValues != null) {
255 for (int i=0; i<publishToValues.size(); i++) {
256 String value = publishToValues.get(i);
257 String shortId = RefNameUtils.getItemShortId(value);
259 if (shortId.equals("all") || shortId.equals("materialorder")) {
269 private List<JsonNode> jsonNodes(Collection<String> values) {
270 List<JsonNode> nodes = new ArrayList<JsonNode>();
271 Iterator<String> iterator = values.iterator();
273 while (iterator.hasNext()) {
274 String value = iterator.next();
276 nodes.add(new TextNode(value));