package org.gbif.occurrence.ws.resources; import org.gbif.api.model.common.search.SearchResponse; import org.gbif.api.model.occurrence.DownloadFormat; import org.gbif.api.model.occurrence.DownloadRequest; import org.gbif.api.model.occurrence.Occurrence; import org.gbif.api.model.occurrence.predicate.Predicate; import org.gbif.api.model.occurrence.search.OccurrenceSearchParameter; import org.gbif.api.model.occurrence.search.OccurrenceSearchRequest; import org.gbif.api.service.occurrence.DownloadRequestService; import org.gbif.api.service.occurrence.OccurrenceSearchService; import org.gbif.occurrence.download.service.PredicateFactory; import org.gbif.ws.util.ExtraMediaTypes; import java.security.Principal; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.Sets; import com.google.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.gbif.api.model.common.paging.PagingConstants.PARAM_LIMIT; import static org.gbif.api.model.common.search.SearchConstants.QUERY_PARAM; import static org.gbif.ws.paths.OccurrencePaths.CATALOG_NUMBER_PATH; import static org.gbif.ws.paths.OccurrencePaths.COLLECTION_CODE_PATH; import static org.gbif.ws.paths.OccurrencePaths.INSTITUTION_CODE_PATH; import static org.gbif.ws.paths.OccurrencePaths.OCC_SEARCH_PATH; import static org.gbif.ws.paths.OccurrencePaths.RECORDED_BY_PATH; import static org.gbif.ws.paths.OccurrencePaths.RECORD_NUMBER_PATH; import static org.gbif.ws.paths.OccurrencePaths.OCCURRENCE_ID_PATH; import static org.gbif.ws.paths.OccurrencePaths.ORGANISM_ID_PATH; import static org.gbif.ws.paths.OccurrencePaths.WATER_BODY_PATH; import static org.gbif.ws.paths.OccurrencePaths.STATE_PROVINCE_PATH; import static org.gbif.ws.paths.OccurrencePaths.LOCALITY_PATH; import static org.gbif.occurrence.download.service.DownloadSecurityUtil.assertUserAuthenticated; /** * Occurrence resource. */ @Path(OCC_SEARCH_PATH) @Produces({MediaType.APPLICATION_JSON, ExtraMediaTypes.APPLICATION_JAVASCRIPT}) public class OccurrenceSearchResource { private static final Logger LOG = LoggerFactory.getLogger(OccurrenceSearchResource.class); private static final Splitter EMAIL_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings(); private final OccurrenceSearchService searchService; private final DownloadRequestService downloadRequestService; @Inject public OccurrenceSearchResource(OccurrenceSearchService searchService, DownloadRequestService downloadRequestService) { this.searchService = searchService; this.downloadRequestService = downloadRequestService; } @GET public SearchResponse<Occurrence,OccurrenceSearchParameter> search(@Context OccurrenceSearchRequest request) { LOG.debug("Executing query, parameters {}, limit {}, offset {}", request.getParameters(), request.getLimit(), request.getOffset()); return searchService.search(request); } @GET @Path("download") public String download(@Context HttpServletRequest httpRequest, @QueryParam("notification_address") String emails, @QueryParam("format") String format, @Context SecurityContext securityContext) { String creator = assertUserAuthenticated(securityContext).getName(); checkNotNullParameter("notification_address", emails); checkNotNullParameter("format", format); checkNotNullParameter("creator", creator); Predicate predicate = PredicateFactory.build(httpRequest.getParameterMap()); LOG.info("Predicate build for passing to download [{}]", predicate); DownloadRequest download = new DownloadRequest(predicate, creator, Sets.newHashSet(EMAIL_SPLITTER.split(emails)), true, DownloadFormat.valueOf(format.toUpperCase())); LOG.debug("Creating download with DownloadRequest [{}] from service [{}]", download, downloadRequestService); try { String downloadKey = downloadRequestService.create(download); LOG.debug("Got key [{}] for new download", downloadKey); return downloadKey; } catch(Exception ex) { LOG.error("Error processing search-to-download request", ex); throw new WebApplicationException(Response.serverError().build()); } } /** * Validates that a parameter is not null or empty. */ private static void checkNotNullParameter(String paramName, String paramValue) { if (Strings.isNullOrEmpty(paramValue)) { throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) .entity("Parameter " + paramName + " can't be null").build()); } } @GET @Path(CATALOG_NUMBER_PATH) public List<String> suggestCatalogNumber(@QueryParam(QUERY_PARAM) String prefix, @QueryParam(PARAM_LIMIT) int limit) { LOG.debug("Executing catalog number suggest/search, query {}, limit {}", prefix, limit); return searchService.suggestCatalogNumbers(prefix, limit); } @GET @Path(COLLECTION_CODE_PATH) public List<String> suggestCollectionCodes(@QueryParam(QUERY_PARAM) String prefix, @QueryParam(PARAM_LIMIT) int limit) { LOG.debug("Executing collection codes suggest/search, query {}, limit {}", prefix, limit); return searchService.suggestCollectionCodes(prefix, limit); } @GET @Path(RECORDED_BY_PATH) public List<String> suggestRecordedBy(@QueryParam(QUERY_PARAM) String prefix, @QueryParam(PARAM_LIMIT) int limit) { LOG.debug("Executing recorded_by suggest/search, query {}, limit {}", prefix, limit); return searchService.suggestRecordedBy(prefix, limit); } @GET @Path(RECORD_NUMBER_PATH) public List<String> suggestRecordNumbers(@QueryParam(QUERY_PARAM) String prefix, @QueryParam(PARAM_LIMIT) int limit) { LOG.debug("Executing record number suggest/search, query {}, limit {}", prefix, limit); return searchService.suggestRecordNumbers(prefix, limit); } @GET @Path(INSTITUTION_CODE_PATH) public List<String> suggestInstitutionCodes(@QueryParam(QUERY_PARAM) String prefix, @QueryParam(PARAM_LIMIT) int limit) { LOG.debug("Executing institution codes suggest/search, query {}, limit {}", prefix, limit); return searchService.suggestInstitutionCodes(prefix, limit); } @GET @Path(OCCURRENCE_ID_PATH) public List<String> suggestOccurrenceIds(@QueryParam(QUERY_PARAM) String prefix, @QueryParam(PARAM_LIMIT) int limit) { LOG.debug("Executing occurrenceId suggest/search, query {}, limit {}", prefix, limit); return searchService.suggestOccurrenceIds(prefix, limit); } @GET @Path(ORGANISM_ID_PATH) public List<String> suggestOrganismIds(@QueryParam(QUERY_PARAM) String prefix, @QueryParam(PARAM_LIMIT) int limit) { LOG.debug("Executing organismId suggest/search, query {}, limit {}", prefix, limit); return searchService.suggestOrganismIds(prefix, limit); } @GET @Path(LOCALITY_PATH) public List<String> suggestLocality(@QueryParam(QUERY_PARAM) String prefix, @QueryParam(PARAM_LIMIT) int limit) { LOG.debug("Executing locality suggest/search, query {}, limit {}", prefix, limit); return searchService.suggestLocalities(prefix, limit); } @GET @Path(STATE_PROVINCE_PATH) public List<String> suggestStateProvince(@QueryParam(QUERY_PARAM) String prefix, @QueryParam(PARAM_LIMIT) int limit) { LOG.debug("Executing stateProvince suggest/search, query {}, limit {}", prefix, limit); return searchService.suggestStateProvinces(prefix, limit); } @GET @Path(WATER_BODY_PATH) public List<String> suggestWaterBody(@QueryParam(QUERY_PARAM) String prefix, @QueryParam(PARAM_LIMIT) int limit) { LOG.debug("Executing waterBody suggest/search, query {}, limit {}", prefix, limit); return searchService.suggestWaterBodies(prefix, limit); } }