1 package org.collectionspace.services.advancedsearch;
3 import java.util.ArrayList;
4 import java.util.Collections;
6 import java.util.stream.Collectors;
8 import javax.ws.rs.Consumes;
9 import javax.ws.rs.GET;
10 import javax.ws.rs.Path;
11 import javax.ws.rs.Produces;
12 import javax.ws.rs.core.Context;
13 import javax.ws.rs.core.MultivaluedMap;
14 import javax.ws.rs.core.Request;
15 import javax.ws.rs.core.UriInfo;
16 import javax.xml.bind.JAXBException;
17 import javax.xml.bind.Unmarshaller;
19 import org.collectionspace.collectionspace_core.CollectionSpaceCore;
20 import org.collectionspace.services.MediaJAXBSchema;
21 import org.collectionspace.services.advancedsearch.AdvancedsearchCommonList.AdvancedsearchListItem;
22 import org.collectionspace.services.advancedsearch.model.BriefDescriptionListModel;
23 import org.collectionspace.services.advancedsearch.model.ContentConceptListModel;
24 import org.collectionspace.services.advancedsearch.model.ObjectNameListModel;
25 import org.collectionspace.services.advancedsearch.model.ResponsibleDepartmentsListModel;
26 import org.collectionspace.services.advancedsearch.model.TitleGroupListModel;
27 import org.collectionspace.services.client.CollectionObjectClient;
28 import org.collectionspace.services.client.CollectionSpaceClient;
29 import org.collectionspace.services.client.IQueryManager;
30 import org.collectionspace.services.client.PayloadOutputPart;
31 import org.collectionspace.services.client.PoxPayloadOut;
32 import org.collectionspace.services.collectionobject.CollectionObjectResource;
33 import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
34 import org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl;
35 import org.collectionspace.services.common.UriInfoWrapper;
36 import org.collectionspace.services.common.context.RemoteServiceContextFactory;
37 import org.collectionspace.services.common.context.ServiceContextFactory;
38 import org.collectionspace.services.common.relation.RelationResource;
39 import org.collectionspace.services.jaxb.AbstractCommonList;
40 import org.collectionspace.services.media.MediaResource;
41 import org.collectionspace.services.nuxeo.client.handler.CSDocumentModelList;
42 import org.collectionspace.services.nuxeo.client.handler.CSDocumentModelList.CSDocumentModelResponse;
43 import org.collectionspace.services.nuxeo.client.handler.UnfilteredDocumentModelHandler;
44 import org.collectionspace.services.relation.RelationsCommonList;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.w3c.dom.Document;
48 import org.w3c.dom.Element;
51 * This class defines the advanced search endpoints.
53 @Path(AdvancedSearchConstants.SERVICE_PATH)
54 @Consumes("application/xml")
55 @Produces("application/xml")
56 public class AdvancedSearch
57 extends AbstractCollectionSpaceResourceImpl<AdvancedsearchListItem, AdvancedsearchListItem> {
58 private static final String FIELDS_RETURNED = "uri|csid|refName|blobCsid|updatedAt|objectId|objectNumber|objectName|title|computedCurrentLocation|responsibleDepartments|responsibleDepartment|contentConcepts|briefDescription";
59 // FIXME: it's not great to hardcode this here
60 private static final String COMMON_PART_NAME = CollectionObjectClient.SERVICE_NAME
61 + CollectionSpaceClient.PART_LABEL_SEPARATOR
62 + CollectionSpaceClient.PART_COMMON_LABEL;
64 private final Logger logger = LoggerFactory.getLogger(AdvancedSearch.class);
65 private final CollectionObjectResource cor = new CollectionObjectResource();
66 private final MediaResource mr = new MediaResource();
67 private final RelationResource relations = new RelationResource();
69 public AdvancedSearch() {
74 * Primary advanced search API endpoint.
76 * @param request The incoming request. Injected.
77 * @param uriInfo The URI info of the incoming request, including query parameters and other search control parameters. Injected.
78 * @return A possibly-empty AbstractCommonList of the advanced search results corresponding to the query
81 public AbstractCommonList getList(@Context Request request, @Context UriInfo uriInfo) {
82 logger.info("advancedsearch called with path: {}", uriInfo.getPath());
83 MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters(true);
84 logger.info("advancedsearch called with query params: {}", queryParams);
85 final String markRelated = queryParams.getFirst(IQueryManager.MARK_RELATED_TO_CSID_AS_SUBJECT);
87 cor.setDocumentHandlerClass(UnfilteredDocumentModelHandler.class);
88 ObjectFactory objectFactory = new ObjectFactory();
90 AdvancedsearchCommonList resultsList = objectFactory.createAdvancedsearchCommonList();
91 // FIXME: this shouldn't be necessary?
92 resultsList.advancedsearchListItem = new ArrayList<>();
94 AbstractCommonList abstractCommonList = cor.getList(uriInfo);
95 if (!(abstractCommonList instanceof CSDocumentModelList)) {
99 Unmarshaller unmarshaller;
100 CSDocumentModelList collectionObjectList = (CSDocumentModelList) abstractCommonList;
102 unmarshaller = AdvancedSearchJAXBContext.getJaxbContext().createUnmarshaller();
103 } catch (JAXBException e) {
104 // this should result in a 500, need to verify from bigReThrow to see what exception it should be
105 throw new RuntimeException("Unable to create unmarshaller for AdvancedSearch", e);
108 for (CSDocumentModelResponse response : collectionObjectList.getResponseList()) {
109 PoxPayloadOut outputPayload = response.getPayload();
110 PayloadOutputPart corePart = outputPayload.getPart(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA);
111 PayloadOutputPart commonPart = outputPayload.getPart(COMMON_PART_NAME);
112 CollectionSpaceCore core;
113 CollectionobjectsCommon collectionObject;
116 core = (CollectionSpaceCore) unmarshaller.unmarshal((Document) corePart.getBody());
117 collectionObject = (CollectionobjectsCommon) unmarshaller.unmarshal((Document) commonPart.getBody());
118 } catch (JAXBException e) {
119 throw new RuntimeException(e);
122 String csid = response.getCsid();
123 UriInfoWrapper wrappedUriInfo = new UriInfoWrapper(uriInfo);
124 List<String> blobCsids = findBlobCsids(csid, wrappedUriInfo);
126 AdvancedsearchListItem listItem = objectFactory.createAdvancedsearchCommonListAdvancedsearchListItem();
128 listItem.setCsid(csid);
129 listItem.setRefName(core.getRefName());
130 listItem.setUri(core.getUri());
131 listItem.setUpdatedAt(core.getUpdatedAt());
133 logger.warn("advancedsearch: could not find collectionspace_core associated with csid {}", csid);
136 if (collectionObject != null) {
137 listItem.setObjectNumber(collectionObject.getObjectNumber());
138 listItem.setBriefDescription(BriefDescriptionListModel
139 .briefDescriptionListToDisplayString(collectionObject.getBriefDescriptions()));
140 listItem.setComputedCurrentLocation(collectionObject.getComputedCurrentLocation());
141 listItem.setObjectName(
142 ObjectNameListModel.objectNameListToDisplayString(collectionObject.getObjectNameList()));
144 TitleGroupListModel.titleGroupListToDisplayString(collectionObject.getTitleGroupList()));
145 ResponsibleDepartmentsList rdl = ResponsibleDepartmentsListModel
146 .responsibleDepartmentListToResponsibleDepartmentsList(
147 collectionObject.getResponsibleDepartments());
148 listItem.setResponsibleDepartments(rdl);
149 listItem.setResponsibleDepartment(
150 ResponsibleDepartmentsListModel.responsibleDepartmentsListDisplayString(rdl));
152 listItem.setContentConcepts(
153 ContentConceptListModel.contentConceptListDisplayString(collectionObject.getContentConcepts()));
155 // from media resource
156 if (blobCsids.size() > 0) {
157 listItem.setBlobCsid(blobCsids.get(0));
159 // add the populated item to the results
160 resultsList.getAdvancedsearchListItem().add(listItem);
162 logger.warn("advancedsearch: could not find CollectionobjectsCommon associated with csid {}", csid);
165 if (markRelated != null) {
166 RelationsCommonList relationsList = relations.getRelationForSubject(markRelated, csid, uriInfo);
167 listItem.setRelated(!relationsList.getRelationListItem().isEmpty());
171 // NOTE: I think this is necessary for the front end to know what to do with
172 // what's returned (?)
173 AbstractCommonList abstractList = (AbstractCommonList) resultsList;
174 abstractList.setItemsInPage(collectionObjectList.getItemsInPage());
175 abstractList.setPageNum(collectionObjectList.getPageNum());
176 abstractList.setPageSize(collectionObjectList.getPageSize());
177 abstractList.setTotalItems(collectionObjectList.getTotalItems());
178 // FIXME: is there a way to generate this rather than hardcode it?
179 abstractList.setFieldsReturned(FIELDS_RETURNED);
185 * Retrieves the blob CSIDs associated with a given object's CSID
187 * @param csid The CSID of an object whose associated blobs (thumbnails) is desired
188 * @param wrappedUriInfo The wrapped (mutable) UriInfo of the incoming query that ultimately triggered this call
189 * @return A possibly-empty list of strings of the blob CSIDs associated with CSID
191 private List<String> findBlobCsids(String csid, UriInfoWrapper wrappedUriInfo) {
192 MultivaluedMap<String, String> wrappedQueryParams = wrappedUriInfo.getQueryParameters();
193 wrappedQueryParams.clear();
194 wrappedQueryParams.add(IQueryManager.SEARCH_RELATED_TO_CSID_AS_SUBJECT, csid);
195 wrappedQueryParams.add("pgSz", "1");
196 wrappedQueryParams.add("pgNum", "0");
197 wrappedQueryParams.add("sortBy", "media_common:title");
198 AbstractCommonList associatedMedia = mr.getList(wrappedUriInfo);
199 if (associatedMedia == null || associatedMedia.getListItem() == null) {
200 return Collections.emptyList();
203 return associatedMedia.getListItem().stream()
204 .filter(item -> item != null && item.getAny() != null)
205 .flatMap(li -> li.getAny().stream())
206 .filter(element -> MediaJAXBSchema.blobCsid.equals(element.getTagName()))
207 .map(Element::getTextContent)
208 .filter(blobCsid -> blobCsid != null && !blobCsid.isEmpty())
209 .collect(Collectors.toList());
213 public Class<?> getCommonPartClass() {
218 public ServiceContextFactory<AdvancedsearchListItem, AdvancedsearchListItem> getServiceContextFactory() {
219 return (ServiceContextFactory<AdvancedsearchListItem, AdvancedsearchListItem>) RemoteServiceContextFactory
224 public String getServiceName() {
225 return AdvancedSearchConstants.SERVICE_NAME;
229 protected String getVersionString() {