1 package org.collectionspace.services.advancedsearch;
3 import java.util.Collections;
5 import java.util.function.Predicate;
6 import java.util.stream.Collectors;
7 import javax.ws.rs.Consumes;
8 import javax.ws.rs.GET;
9 import javax.ws.rs.Path;
10 import javax.ws.rs.Produces;
11 import javax.ws.rs.core.Context;
12 import javax.ws.rs.core.MultivaluedMap;
13 import javax.ws.rs.core.Request;
14 import javax.ws.rs.core.UriInfo;
15 import javax.xml.bind.JAXBException;
16 import javax.xml.bind.Unmarshaller;
18 import org.collectionspace.services.MediaJAXBSchema;
19 import org.collectionspace.services.advancedsearch.AdvancedsearchCommonList.AdvancedsearchListItem;
20 import org.collectionspace.services.advancedsearch.mapper.CollectionObjectMapper;
21 import org.collectionspace.services.client.IQueryManager;
22 import org.collectionspace.services.collectionobject.CollectionObjectResource;
23 import org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl;
24 import org.collectionspace.services.common.UriInfoWrapper;
25 import org.collectionspace.services.common.context.RemoteServiceContextFactory;
26 import org.collectionspace.services.common.context.ServiceContextFactory;
27 import org.collectionspace.services.common.relation.RelationResource;
28 import org.collectionspace.services.jaxb.AbstractCommonList;
29 import org.collectionspace.services.media.MediaResource;
30 import org.collectionspace.services.nuxeo.client.handler.CSDocumentModelList;
31 import org.collectionspace.services.nuxeo.client.handler.CSDocumentModelList.CSDocumentModelResponse;
32 import org.collectionspace.services.nuxeo.client.handler.UnfilteredDocumentModelHandler;
33 import org.collectionspace.services.relation.RelationsCommonList;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36 import org.w3c.dom.Element;
39 * This class defines the advanced search endpoints.
41 @Path(AdvancedSearchConstants.SERVICE_PATH)
42 @Consumes("application/xml")
43 @Produces("application/xml")
44 public class AdvancedSearch
45 extends AbstractCollectionSpaceResourceImpl<AdvancedsearchListItem, AdvancedsearchListItem> {
46 // FIXME: it's not great to hardcode either of these
47 private static final String FIELDS_RETURNED = "uri|csid|refName|blobCsid|updatedAt|objectId|objectNumber|objectName|title|computedCurrentLocation|responsibleDepartments|responsibleDepartment|contentConcepts|briefDescription";
49 private final Logger logger = LoggerFactory.getLogger(AdvancedSearch.class);
50 private final CollectionObjectResource cor = new CollectionObjectResource();
51 private final MediaResource mr = new MediaResource();
52 private final RelationResource relations = new RelationResource();
54 public AdvancedSearch() {
59 * Primary advanced search API endpoint.
61 * @param request The incoming request. Injected.
62 * @param uriInfo The URI info of the incoming request, including query parameters and other search control parameters. Injected.
63 * @return A possibly-empty AbstractCommonList of the advanced search results corresponding to the query
66 public AbstractCommonList getList(@Context Request request, @Context UriInfo uriInfo) {
67 logger.info("advancedsearch called with path: {}", uriInfo.getPath());
68 MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters(true);
69 logger.info("advancedsearch called with query params: {}", queryParams);
70 final String markRelated = queryParams.getFirst(IQueryManager.MARK_RELATED_TO_CSID_AS_SUBJECT);
72 cor.setDocumentHandlerClass(UnfilteredDocumentModelHandler.class);
73 ObjectFactory objectFactory = new ObjectFactory();
74 AdvancedsearchCommonList resultsList = objectFactory.createAdvancedsearchCommonList();
76 AbstractCommonList abstractCommonList = cor.getList(uriInfo);
77 if (!(abstractCommonList instanceof CSDocumentModelList)) {
81 Unmarshaller unmarshaller;
82 CSDocumentModelList collectionObjectList = (CSDocumentModelList) abstractCommonList;
84 unmarshaller = AdvancedSearchJAXBContext.getJaxbContext().createUnmarshaller();
85 } catch (JAXBException e) {
86 // this should result in a 500, need to verify from bigReThrow to see what exception it should be
87 throw new RuntimeException("Unable to create unmarshaller for AdvancedSearch", e);
90 final CollectionObjectMapper responseMapper = new CollectionObjectMapper(unmarshaller);
91 for (CSDocumentModelResponse response : collectionObjectList.getResponseList()) {
92 String csid = response.getCsid();
93 UriInfoWrapper wrappedUriInfo = new UriInfoWrapper(uriInfo);
94 Map<String, String> blobInfo = findBlobInfo(csid, wrappedUriInfo);
96 AdvancedsearchListItem listItem = responseMapper.asListItem(response, blobInfo);
97 if (listItem != null) {
98 if (markRelated != null) {
99 RelationsCommonList relationsList = relations.getRelationForSubject(markRelated, csid, uriInfo);
100 listItem.setRelated(!relationsList.getRelationListItem().isEmpty());
102 resultsList.getAdvancedsearchListItem().add(listItem);
106 resultsList.setItemsInPage(collectionObjectList.getItemsInPage());
107 resultsList.setPageNum(collectionObjectList.getPageNum());
108 resultsList.setPageSize(collectionObjectList.getPageSize());
109 resultsList.setTotalItems(collectionObjectList.getTotalItems());
110 resultsList.setFieldsReturned(FIELDS_RETURNED);
116 * Retrieves the blob CSIDs associated with a given object's CSID
118 * @param csid The CSID of an object whose associated blobs (thumbnails) is desired
119 * @param wrappedUriInfo The wrapped (mutable) UriInfo of the incoming query that ultimately triggered this call
120 * @return A possibly-empty list of strings of the blob CSIDs associated with CSID
122 private Map<String, String> findBlobInfo(String csid, UriInfoWrapper wrappedUriInfo) {
123 MultivaluedMap<String, String> wrappedQueryParams = wrappedUriInfo.getQueryParameters();
124 wrappedQueryParams.clear();
125 wrappedQueryParams.add(IQueryManager.SEARCH_RELATED_TO_CSID_AS_SUBJECT, csid);
126 wrappedQueryParams.add("pgSz", "1");
127 wrappedQueryParams.add("pgNum", "0");
128 wrappedQueryParams.add("sortBy", "media_common:title");
129 AbstractCommonList associatedMedia = mr.getList(wrappedUriInfo);
130 if (associatedMedia == null || associatedMedia.getListItem() == null) {
131 return Collections.emptyMap();
134 Predicate<Element> tagFilter = (element -> MediaJAXBSchema.blobCsid.equals(element.getTagName()) ||
135 MediaJAXBSchema.altText.equals(element.getTagName()));
136 Predicate<Element> tagNotEmpty = (element -> element.getTextContent() != null &&
137 !element.getTextContent().isEmpty());
139 return associatedMedia.getListItem().stream()
140 .filter(item -> item != null && item.getAny() != null)
141 .flatMap(li -> li.getAny().stream())
142 .filter(tagFilter.and(tagNotEmpty))
143 .collect(Collectors.toMap(Element::getTagName, Element::getTextContent));
147 public Class<?> getCommonPartClass() {
152 public ServiceContextFactory<AdvancedsearchListItem, AdvancedsearchListItem> getServiceContextFactory() {
153 return (ServiceContextFactory<AdvancedsearchListItem, AdvancedsearchListItem>) RemoteServiceContextFactory
158 public String getServiceName() {
159 return AdvancedSearchConstants.SERVICE_NAME;
163 protected String getVersionString() {