/** * Copyright (C) 2016 Pink Summit, LLC (info@pinksummit.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.di2e.ecdr.broker.endpoint.rest; import java.util.Collection; import java.util.List; import java.util.Set; import javax.ws.rs.GET; import javax.ws.rs.HEAD; import javax.ws.rs.HeaderParam; import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import org.apache.commons.lang.StringUtils; import org.apache.cxf.jaxrs.ext.MessageContext; import org.opengis.filter.sort.SortBy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ddf.catalog.CatalogFramework; import ddf.catalog.federation.FederationException; import ddf.catalog.operation.QueryRequest; import ddf.catalog.operation.QueryResponse; import ddf.catalog.operation.impl.QueryRequestImpl; import ddf.catalog.source.SourceUnavailableException; import ddf.catalog.source.UnsupportedQueryException; import net.di2e.ecdr.api.auditor.SearchAuditor; import net.di2e.ecdr.api.cache.QueryRequestCache; import net.di2e.ecdr.api.federation.NormalizingFederationStrategy; import net.di2e.ecdr.api.query.QueryConfiguration; import net.di2e.ecdr.api.query.QueryLanguage; import net.di2e.ecdr.api.transform.TransformIdMapper; import net.di2e.ecdr.commons.constants.SearchConstants; import net.di2e.ecdr.commons.endpoint.rest.AbstractRestSearchEndpoint; import net.di2e.ecdr.commons.query.CDRQueryImpl; /** * JAX-RS Web Service which implements the CDR REST Brokered Search Specification which is based on the CDR Search Spec * which is in turn based on Open Search * * The key difference between CDR Brokered Search and CDR Search is that Brokered Search can route the search to * multiple sources (FederatedSource). * */ @Path( "/" ) public class CDRRestBrokerServiceImpl extends AbstractRestSearchEndpoint { private static final Logger LOGGER = LoggerFactory.getLogger( CDRRestBrokerServiceImpl.class ); private static final String RELATIVE_URL = "/services/cdr/broker/rest"; private static final String SERVICE_TYPE = "CDR REST Brokered Search Service"; private NormalizingFederationStrategy sortedFedStrategy = null; /** * Constructor for JAX RS CDR Search Service. Values should ideally be passed into the constructor using a * dependency injection framework like blueprint * * @param framework * Catalog Framework which will be used for search * @param builder * FilterBuilder implementation * @param parser * The instance of the QueryParser to use which will determine how to parse the parameters from the query * String. Query parsers are tied to different versions of a query profile */ public CDRRestBrokerServiceImpl( CatalogFramework framework, List<QueryLanguage> queryLangs, TransformIdMapper mapper, List<SearchAuditor> auditorList, QueryConfiguration queryConfig, QueryRequestCache queryCache, NormalizingFederationStrategy sortedFedStrategy, List<Object> geoCoderList ) { super( framework, queryLangs, mapper, auditorList, queryConfig, queryCache, geoCoderList ); this.sortedFedStrategy = sortedFedStrategy; } @HEAD public Response ping( @Context UriInfo uriInfo, @HeaderParam( "Accept-Encoding" ) String encoding, @HeaderParam( "Authorization" ) String auth ) { Response response = executePing( uriInfo, encoding, auth ); LOGGER.debug( "Ping (HTTP HEAD) was called to check if the CDR Broker Endpoint is available, result is [{}]", response.getStatus() ); return response; } /** * Search method that gets called when issuing an HTTP GET to the corresponding URL. HTTP GET URL query parameters * contain the query criteria values * * @param uriInfo * Query parameters obtained by e * @param encoding * @param auth * @return */ @GET public Response search( @Context MessageContext context, @HeaderParam( "Accept-Encoding" ) String encoding, @HeaderParam( "Authorization" ) String auth ) { UriInfo uriInfo = context.getUriInfo(); LOGGER.debug( "Query received on CDR Broker Endpoint: {}", uriInfo.getRequestUri() ); return executeSearch( context.getHttpServletRequest(), uriInfo, encoding, auth ); } @Override public String getServiceType() { return SERVICE_TYPE; } @Override public String getServiceRelativeUrl() { return RELATIVE_URL; } @Override public String getServiceDescription() { return "Provides a RESTful search service using the CDR Brokered Search specification."; } @Override public String getParameterTemplate( String queryLanguageName ) { return super.getParameterTemplate( queryLanguageName ) + "&" + SearchConstants.SOURCE_PARAMETER + "={cdrb:routeTo?}"; } @Override public QueryResponse executeQuery( String localSourceId, MultivaluedMap<String, String> queryParameters, CDRQueryImpl query ) throws SourceUnavailableException, UnsupportedQueryException, FederationException { Collection<String> siteNames = query.getSiteNames(); QueryRequest queryRequest = new QueryRequestImpl( query, siteNames.isEmpty(), siteNames, getQueryProperties( queryParameters, localSourceId ) ); SortBy originalSortBy = query.getSortBy(); QueryResponse queryResponse = originalSortBy == null ? getCatalogFramework().query( queryRequest ) : getCatalogFramework().query( queryRequest ); return queryResponse; } @Override protected String replaceTemplateValues( String osdTemplate ) { // @formatter:off String additionalParams = "cdrb:routeTo - a comma separated lists of siteNames (sources) that the query should be federated to " + System.lineSeparator() + " default: [sent to all sites]" + System.lineSeparator() + " allowedValues: " + getAllSites() + System.lineSeparator() + " localSourceId: " + getCatalogFramework().getId() + System.lineSeparator() + " example: site1,site2"; // @formatter:on osdTemplate = StringUtils.replace( osdTemplate, "${additionalBasicParameters}", additionalParams, 1 ); return super.replaceTemplateValues( osdTemplate ); } private String getAllSites() { StringBuilder builder = new StringBuilder(); Set<String> ids = getCatalogFramework().getSourceIds(); for ( String id : ids ) { builder.append( "'" + id + "' " ); } return builder.toString().trim(); } }