/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.csw; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import net.opengis.cat.csw20.ElementSetType; import net.opengis.cat.csw20.GetRecordByIdType; import org.eclipse.emf.common.util.EList; import org.geoserver.csw.records.RecordDescriptor; import org.geoserver.csw.records.SpatialFilterChecker; import org.geoserver.csw.response.CSWRecordsResult; import org.geoserver.csw.store.CatalogStore; import org.geoserver.feature.CompositeFeatureCollection; import org.geoserver.platform.ServiceException; import org.geotools.csw.CSW; import org.geotools.data.Query; import org.geotools.data.Transaction; import org.geotools.factory.CommonFactoryFinder; import org.geotools.feature.FeatureCollection; import org.opengis.feature.type.Name; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.identity.FeatureId; /** * Runs the GetRecordById request * * @author Niels Charlier */ public class GetRecordById { static final FilterFactory2 FF = CommonFactoryFinder.getFilterFactory2(); CSWInfo csw; CatalogStore store; private List<RecordDescriptor> recordDescriptors; public GetRecordById(CSWInfo csw, CatalogStore store, List<RecordDescriptor> recordDescriptors) { this.csw = csw; this.store = store; this.recordDescriptors = recordDescriptors; } public CSWRecordsResult run(GetRecordByIdType request) { // mark the time the request started Date timestamp = new Date(); try { // build the queries RecordDescriptor rd = getRecordDescriptor(request); List<Query> queries = toGtQueries(rd, request.getId(), request); // compute the number of records matched (in validate mode this is also a quick way // to check the request) int numberOfRecordsMatched = 0; int[] counts = new int[queries.size()]; for (int i = 0; i < queries.size(); i++) { counts[i] = store.getRecordsCount(queries.get(i), Transaction.AUTO_COMMIT); numberOfRecordsMatched += counts[i]; } FeatureCollection records = null; // time to run the queries if we are not in hits mode List<FeatureCollection> results = new ArrayList<FeatureCollection>(); for (int i = 0; i < queries.size(); i++) { FeatureCollection collection = store.getRecords(queries.get(i), Transaction.AUTO_COMMIT, request.getOutputSchema()); if(collection != null && collection.size() > 0) { results.add(collection); } } if (results.size() == 1) { records = results.get(0); } else if (results.size() > 1) { records = new CompositeFeatureCollection(results); } ElementSetType elementSet = getElementSetName(request); CSWRecordsResult result = new CSWRecordsResult(elementSet, request.getOutputSchema(), numberOfRecordsMatched, numberOfRecordsMatched, 0, timestamp, records); return result; } catch(IOException e) { throw new ServiceException("Request failed due to: " + e.getMessage(), e); } } private ElementSetType getElementSetName(GetRecordByIdType request) { ElementSetType elementSet = request.getElementSetName() != null ? request .getElementSetName().getValue() : null; if (elementSet == null) { // the default is "summary" elementSet = ElementSetType.SUMMARY; } return elementSet; } private List<Query> toGtQueries(RecordDescriptor rd, EList<URI> ids, GetRecordByIdType request) throws IOException { // prepare to build the queries Set<FeatureId> fids = new HashSet<FeatureId>(); for (URI id: ids) { fids.add (FF.featureId(id.toString())); } Filter filter = FF.id(fids); // build one query Name typeName = rd.getFeatureDescriptor().getName(); Query q = new Query(typeName.getLocalPart()); q.setFilter(filter); // perform some necessary query adjustments Query adapted = rd.adaptQuery(q); // the specification demands that we throw an error if a spatial operator // is used against a non spatial property if (q.getFilter() != null) { rd.verifySpatialFilters(q.getFilter()); } //smuggle base url adapted.getHints().put(GetRecords.KEY_BASEURL, request.getBaseUrl()); List<Query> result = new ArrayList<Query>(); result.add(adapted); return result; } /** * Search for the record descriptor maching the request, throws a service exception in case none * is found * * @param request * */ private RecordDescriptor getRecordDescriptor(GetRecordByIdType request) { String outputSchema = request.getOutputSchema(); if (outputSchema == null) { outputSchema = CSW.NAMESPACE; request.setOutputFormat(CSW.NAMESPACE); } for (RecordDescriptor rd : recordDescriptors) { if (outputSchema.equals(rd.getOutputSchema())) { return rd; } } throw new ServiceException("Cannot encode records in output schema " + outputSchema, ServiceException.INVALID_PARAMETER_VALUE, "outputSchema"); } }