/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package ddf.catalog.pubsub; import java.io.IOException; import java.io.Serializable; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import javax.security.auth.Subject; import javax.xml.datatype.XMLGregorianCalendar; import org.geotools.filter.AttributeExpressionImpl; import org.geotools.filter.FilterFactoryImpl; import org.geotools.styling.UomOgcMapping; import org.geotools.temporal.object.DefaultInstant; import org.geotools.temporal.object.DefaultPeriod; import org.geotools.temporal.object.DefaultPosition; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory; import org.opengis.filter.FilterVisitor; import org.opengis.filter.PropertyIsLike; import org.opengis.filter.expression.Expression; import org.opengis.filter.sort.SortBy; import org.opengis.filter.sort.SortOrder; import org.opengis.temporal.Instant; import org.opengis.temporal.Period; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ddf.catalog.data.ContentType; import ddf.catalog.data.Metacard; import ddf.catalog.impl.filter.SpatialFilter; import ddf.catalog.operation.Query; import ddf.catalog.operation.QueryRequest; import ddf.catalog.operation.ResourceResponse; import ddf.catalog.operation.SourceResponse; import ddf.catalog.pubsub.internal.SubscriptionFilterVisitor; import ddf.catalog.resource.ResourceNotFoundException; import ddf.catalog.resource.ResourceNotSupportedException; import ddf.catalog.source.FederatedSource; import ddf.catalog.source.SourceMonitor; import ddf.catalog.source.UnsupportedQueryException; import ddf.measure.Distance; import ddf.measure.Distance.LinearUnit; public class MockQuery implements FederatedSource, Query { public static final FilterFactory FILTER_FACTORY = new FilterFactoryImpl(); private static final Logger LOGGER = LoggerFactory.getLogger(MockQuery.class); // PLACEHOLDER for security private Subject user; private Integer startIndex; private Integer count; private long maxTimeout; private boolean isEnterprise; private Set<String> siteIds; private SortBy sortBy; private Filter filter; private List<Filter> filters; public MockQuery() { this(null, 0, 10, "RELEVANCE", SortOrder.DESCENDING, 30000); } public MockQuery(Subject user, int startIndex, int count, String sortField, SortOrder sortOrder, long maxTimeout) { this.user = user; this.startIndex = startIndex; this.count = count; if (sortField != null && sortOrder != null) { this.sortBy = FILTER_FACTORY.sort(sortField.toUpperCase(), sortOrder); // RELEVANCE or // TEMPORAL } this.maxTimeout = maxTimeout; this.filters = new ArrayList<Filter>(); } public void addContextualFilter(String searchPhrase, String textPathSections) { addContextualFilter(searchPhrase, textPathSections, false); } public void addContextualFilter(String searchPhrase, String textPathSections, boolean caseSensitive) { Filter filter = null; if (searchPhrase != null) { if (textPathSections != null) { List<Filter> xpathFilters = new ArrayList<Filter>(); String[] selectors = textPathSections.split(","); for (int i = 0; i < selectors.length; i++) { Expression xpathRef = new AttributeExpressionImpl(selectors[i]); filter = FILTER_FACTORY.like(xpathRef, searchPhrase); xpathFilters.add(filter); } filter = FILTER_FACTORY.or(xpathFilters); } else { filter = FILTER_FACTORY.like(FILTER_FACTORY.property(Metacard.ANY_TEXT), searchPhrase, SubscriptionFilterVisitor.LUCENE_WILDCARD_CHAR, SubscriptionFilterVisitor.LUCENE_SINGLE_CHAR, SubscriptionFilterVisitor.LUCENE_ESCAPE_CHAR, caseSensitive); } if (filter != null) { filters.add(filter); } } } public void addTemporalFilter(XMLGregorianCalendar start, XMLGregorianCalendar end, String timeType) { Filter filter = null; String timeProperty = Metacard.MODIFIED; if (timeType != null && timeType.toLowerCase() .equals(Metacard.EFFECTIVE)) { timeProperty = Metacard.EFFECTIVE; } if (start != null && end != null) { int compareTo = start.toGregorianCalendar() .compareTo(end.toGregorianCalendar()); if (compareTo > 0) { throw new IllegalArgumentException( "start date [" + start + "] should not be later than" + " end date [" + end + "]"); } else if (compareTo == 0) { filter = FILTER_FACTORY.equals(FILTER_FACTORY.property(timeProperty), FILTER_FACTORY.literal(start.toGregorianCalendar() .getTime())); } else { // t1.start < timeType instance < t1.end DefaultPosition defaultPosition = new DefaultPosition(start.toGregorianCalendar() .getTime()); Instant startInstant = new DefaultInstant(defaultPosition); Instant endInstant = new DefaultInstant(new DefaultPosition(end.toGregorianCalendar() .getTime())); Period period = new DefaultPeriod(startInstant, endInstant); filter = FILTER_FACTORY.during(FILTER_FACTORY.property(timeProperty), FILTER_FACTORY.literal(period)); } filters.add(filter); } } public void addEntryFilter(String id) { Filter filter = null; if (id != null) { LOGGER.debug("Creating entry by ID filter"); filter = FILTER_FACTORY.equals(FILTER_FACTORY.property(Metacard.ID), FILTER_FACTORY.literal(id)); filters.add(filter); } else { LOGGER.debug("id was NULL - EntryFilter not created"); } } public void addSpatialFilter(String geometryWkt, Double inputRadius, String linearUnit, String spatialType) { Filter filter = null; try { if (geometryWkt == null || geometryWkt.isEmpty()) { return; } SpatialFilter spatialFilter = new SpatialFilter(geometryWkt); if (spatialType.equals("CONTAINS")) { filter = FILTER_FACTORY.within(Metacard.ANY_GEO, spatialFilter.getGeometry()); } else if (spatialType.equals("OVERLAPS")) { filter = FILTER_FACTORY.intersects(Metacard.ANY_GEO, spatialFilter.getGeometry()); } else if (spatialType.equals("NEAREST_NEIGHBOR")) { filter = FILTER_FACTORY.beyond(Metacard.ANY_GEO, spatialFilter.getGeometry(), 0.0, UomOgcMapping.METRE.name()); } else if (spatialType.equals("POINT_RADIUS")) { Double normalizedRadius = convertRadius(linearUnit, inputRadius); filter = FILTER_FACTORY.dwithin(Metacard.ANY_GEO, spatialFilter.getGeometry(), normalizedRadius, UomOgcMapping.METRE.name()); } else { return; } } catch (IllegalArgumentException e) { LOGGER.debug("Invalid spatial query type specified. Will not apply spatial filter."); return; } if (filter != null) { filters.add(filter); } } private Double convertRadius(String linearUnit, Double inputRadius) { if (linearUnit.equals("FOOT_U_S")) { return new Distance(inputRadius, LinearUnit.FOOT_U_S).getAs(LinearUnit.METER); } else if (linearUnit.equals("KILOMETER")) { return new Distance(inputRadius, LinearUnit.KILOMETER).getAs(LinearUnit.METER); } else if (linearUnit.equals("MILE")) { return new Distance(inputRadius, LinearUnit.MILE).getAs(LinearUnit.METER); } else if (linearUnit.equals("NAUTICAL_MILE")) { return new Distance(inputRadius, LinearUnit.NAUTICAL_MILE).getAs(LinearUnit.METER); } else if (linearUnit.equals("YARD")) { return new Distance(inputRadius, LinearUnit.YARD).getAs(LinearUnit.METER); } else if (linearUnit.equals("METER")) { } return inputRadius; } public void addTypeFilter(List<MockTypeVersionsExtension> extensionList) { List<Filter> runningFilterList = new ArrayList<Filter>(); for (MockTypeVersionsExtension e : extensionList) { String type = e.getExtensionTypeName(); List<String> versions = e.getVersions(); Filter oneTypeFilter = null; Expression expressionType = FILTER_FACTORY.property(Metacard.CONTENT_TYPE); Expression expressionVersion = FILTER_FACTORY.property(Metacard.CONTENT_TYPE_VERSION); // Create a list of type-version pairs // Logically 'AND' the type and versions together if (versions != null && !versions.isEmpty()) { List<Filter> andedTypeVersionPairs = new ArrayList<Filter>(); for (String v : versions) { if (v != null) { PropertyIsLike typeFilter = FILTER_FACTORY.like(expressionType, type, "*", "?", "\\", false); PropertyIsLike versionFilter = FILTER_FACTORY.like(expressionVersion, v, "*", "?", "\\", false); andedTypeVersionPairs.add(FILTER_FACTORY.and(typeFilter, versionFilter)); } } // Check if we had any pairs and logically 'OR' them together. if (!andedTypeVersionPairs.isEmpty()) { oneTypeFilter = FILTER_FACTORY.or(andedTypeVersionPairs); } else { // if we don't have any pairs, means we don't have versions, handle single type oneTypeFilter = FILTER_FACTORY.like(expressionType, type, "*", "?", "\\", false); } } else { // we do not have versions, handle single type case oneTypeFilter = FILTER_FACTORY.like(expressionType, type, "*", "?", "\\", false); } runningFilterList.add(oneTypeFilter); } if (!runningFilterList.isEmpty()) { Filter filter = FILTER_FACTORY.or(runningFilterList); filters.add(filter); } } @Override public Object accept(FilterVisitor visitor, Object obj) { LOGGER.debug("accept"); return filter.accept(visitor, obj); } @Override public boolean evaluate(Object object) { return filter.evaluate(object); } @Override public boolean requestsTotalResultsCount() { // always send back total count for NCES return true; } @Override public long getTimeoutMillis() { return maxTimeout; } public void setSiteIds(Set<String> siteIds) { this.siteIds = siteIds; } public void setIsEnterprise(boolean isEnterprise) { this.isEnterprise = isEnterprise; } @Override public SortBy getSortBy() { return sortBy; } public Filter getFilter() { // If multiple filters, then AND them all together if (filters.size() > 1) { return FILTER_FACTORY.and(filters); // If only one filter, then just return it // (AND'ing it would create an erroneous </ogc:and> closing tag) } else if (filters.size() == 1) { return (Filter) filters.get(0); // Otherwise, no filters } else { return null; } } @Override public boolean isAvailable() { return false; } @Override public boolean isAvailable(SourceMonitor callback) { return isAvailable(); } @Override public SourceResponse query(QueryRequest request) throws UnsupportedQueryException { return null; } @Override public Set<ContentType> getContentTypes() { return null; } @Override public String getId() { return null; } @Override public String getVersion() { return null; } @Override public String getTitle() { return null; } @Override public String getDescription() { return null; } @Override public String getOrganization() { return null; } @Override public ResourceResponse retrieveResource(URI uri, Map<String, Serializable> arguments) throws IOException, ResourceNotFoundException, ResourceNotSupportedException { return null; } public Set<String> getSupportedSchemes() { return null; } @Override public int getStartIndex() { return startIndex; } @Override public int getPageSize() { return count; } @Override public Set<String> getOptions(Metacard metacard) { return null; } }