/**
* 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 org.codice.ddf.spatial.ogc.csw.catalog.common.source;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.namespace.QName;
import org.apache.commons.lang.StringUtils;
import org.codice.ddf.spatial.ogc.csw.catalog.common.CswConstants;
import org.codice.ddf.spatial.ogc.csw.catalog.common.CswConstants.BinarySpatialOperand;
import org.codice.ddf.spatial.ogc.csw.catalog.common.CswSourceConfiguration;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import com.vividsolutions.jts.io.WKTWriter;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.types.Core;
import net.opengis.filter.v_1_1_0.ComparisonOperatorType;
import net.opengis.filter.v_1_1_0.ComparisonOperatorsType;
import net.opengis.filter.v_1_1_0.FilterCapabilities;
import net.opengis.filter.v_1_1_0.FilterType;
import net.opengis.filter.v_1_1_0.GeometryOperandsType;
import net.opengis.filter.v_1_1_0.ScalarCapabilitiesType;
import net.opengis.filter.v_1_1_0.SpatialCapabilitiesType;
import net.opengis.filter.v_1_1_0.SpatialOperatorNameType;
import net.opengis.filter.v_1_1_0.SpatialOperatorType;
import net.opengis.filter.v_1_1_0.SpatialOperatorsType;
import net.opengis.ows.v_1_0_0.DomainType;
import net.opengis.ows.v_1_0_0.Operation;
/**
* CswFilterDelegate is an implementation of a {@link ddf.catalog.filter.FilterDelegate}. It extends
* {@link CswAbstractFilterDelegate} and converts a {@link org.opengis.filter.Filter} into a {@link net.opengis.filter.v_1_1_0.FilterType}.
* <p>
* Generic type that the FilterDelegate will return as a final result
*/
public class CswFilterDelegate extends CswAbstractFilterDelegate<FilterType> {
private static final Logger LOGGER = LoggerFactory.getLogger(CswFilterDelegate.class);
// 1000 Nautical Miles in meters
private static final double NEAREST_NEIGHBOR_DISTANCE_LIMIT = 1852000;
// according to the spec, this will include at a minimum: equal, not equal,
// less, greater, greater or equal, less or equal, and like
private Set<ComparisonOperatorType> comparisonOps;
// according to the spec, this will include at a minimum: bbox
private Map<SpatialOperatorNameType, SpatialOperatorType> spatialOps;
private List<QName> globalGeometryOperands;
// according to the spec, logicalOps (and/or/not) are always supported
private boolean logicalOps;
private CswSourceConfiguration cswSourceConfiguration;
private CswFilterFactory cswFilterFactory;
/**
* Instantiates a CswFilterDelegate instance
*
* @param getRecordsOp An {@link net.opengis.ows.v_1_0_0.Operation} for the getRecords feature of the Csw service
* @param filterCapabilities The {@link net.opengis.filter.v_1_1_0.FilterCapabilities} understood by the Csw service
* @param outputFormatValues An {@link net.opengis.ows.v_1_0_0.DomainType} containing a list of valid Output Formats supported
* @param resultTypesValues An {@link net.opengis.ows.v_1_0_0.DomainType} containing a list of Result Types supported
*/
public CswFilterDelegate(Operation getRecordsOp, FilterCapabilities filterCapabilities,
DomainType outputFormatValues, DomainType resultTypesValues,
CswSourceConfiguration cswSourceConfiguration) {
super(getRecordsOp, outputFormatValues, resultTypesValues);
this.cswSourceConfiguration = cswSourceConfiguration;
this.cswFilterFactory = new CswFilterFactory(cswSourceConfiguration.getCswAxisOrder(),
cswSourceConfiguration.isSetUsePosList());
updateAllowedOperations(filterCapabilities);
}
@Override
public FilterType and(List<FilterType> filters) {
areLogicalOperationsSupported();
return cswFilterFactory.buildAndFilter(filters);
}
@Override
public FilterType or(List<FilterType> filters) {
areLogicalOperationsSupported();
if (filters.contains(null)) {
throw new UnsupportedOperationException("Invalid filters found in list of filters!");
}
return cswFilterFactory.buildOrFilter(filters);
}
@Override
public FilterType not(FilterType filter) {
areLogicalOperationsSupported();
return cswFilterFactory.buildNotFilter(filter);
}
@Override
public FilterType propertyIsEqualTo(String propertyName, String literal,
boolean isCaseSensitive) {
isComparisonOperationSupported(ComparisonOperatorType.EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsEqualToFilter(propertyName,
literal,
isCaseSensitive);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsEqualTo(String propertyName, Date literal) {
isComparisonOperationSupported(ComparisonOperatorType.EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsEqualToFilter(propertyName,
convertDateToIso8601Format(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsEqualTo(String propertyName, int literal) {
isComparisonOperationSupported(ComparisonOperatorType.EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsEqualToFilter(propertyName,
Integer.valueOf(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsEqualTo(String propertyName, short literal) {
isComparisonOperationSupported(ComparisonOperatorType.EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsEqualToFilter(propertyName,
Short.valueOf(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsEqualTo(String propertyName, long literal) {
isComparisonOperationSupported(ComparisonOperatorType.EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsEqualToFilter(propertyName,
Long.valueOf(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsEqualTo(String propertyName, float literal) {
isComparisonOperationSupported(ComparisonOperatorType.EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsEqualToFilter(propertyName,
new Float(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsEqualTo(String propertyName, double literal) {
isComparisonOperationSupported(ComparisonOperatorType.EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsEqualToFilter(propertyName,
new Double(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsEqualTo(String propertyName, boolean literal) {
isComparisonOperationSupported(ComparisonOperatorType.EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsEqualToFilter(propertyName,
Boolean.valueOf(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsNotEqualTo(String propertyName, String literal,
boolean isCaseSensitive) {
isComparisonOperationSupported(ComparisonOperatorType.NOT_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsNotEqualToFilter(propertyName,
literal,
isCaseSensitive);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsNotEqualTo(String propertyName, Date literal) {
isComparisonOperationSupported(ComparisonOperatorType.NOT_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsNotEqualToFilter(propertyName,
this.convertDateToIso8601Format(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsNotEqualTo(String propertyName, int literal) {
isComparisonOperationSupported(ComparisonOperatorType.NOT_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsNotEqualToFilter(propertyName,
Integer.valueOf(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsNotEqualTo(String propertyName, short literal) {
isComparisonOperationSupported(ComparisonOperatorType.NOT_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsNotEqualToFilter(propertyName,
Short.valueOf(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsNotEqualTo(String propertyName, long literal) {
isComparisonOperationSupported(ComparisonOperatorType.NOT_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsNotEqualToFilter(propertyName,
Long.valueOf(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsNotEqualTo(String propertyName, float literal) {
isComparisonOperationSupported(ComparisonOperatorType.NOT_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsNotEqualToFilter(propertyName,
new Float(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsNotEqualTo(String propertyName, double literal) {
isComparisonOperationSupported(ComparisonOperatorType.NOT_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsNotEqualToFilter(propertyName,
new Double(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsNotEqualTo(String propertyName, boolean literal) {
isComparisonOperationSupported(ComparisonOperatorType.NOT_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsNotEqualToFilter(propertyName,
Boolean.valueOf(literal),
true);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThan(String propertyName, String literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanFilter(propertyName, literal);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThan(String propertyName, Date literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanFilter(propertyName,
convertDateToIso8601Format(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThan(String propertyName, int literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanFilter(propertyName, Integer.valueOf(
literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThan(String propertyName, short literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanFilter(propertyName, Short.valueOf(
literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThan(String propertyName, long literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanFilter(propertyName, Long.valueOf(
literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThan(String propertyName, float literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanFilter(propertyName,
new Float(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThan(String propertyName, double literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanFilter(propertyName, new Double(
literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, String literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanOrEqualToFilter(propertyName,
literal);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, Date literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanOrEqualToFilter(propertyName,
convertDateToIso8601Format(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, int literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanOrEqualToFilter(propertyName,
Integer.valueOf(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, short literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanOrEqualToFilter(propertyName,
Short.valueOf(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, long literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanOrEqualToFilter(propertyName,
Long.valueOf(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, float literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanOrEqualToFilter(propertyName,
new Float(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, double literal) {
isComparisonOperationSupported(ComparisonOperatorType.GREATER_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsGreaterThanOrEqualToFilter(propertyName,
new Double(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThan(String propertyName, String literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanFilter(propertyName, literal);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThan(String propertyName, Date literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanFilter(propertyName,
convertDateToIso8601Format(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThan(String propertyName, int literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanFilter(propertyName, Integer.valueOf(
literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThan(String propertyName, short literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanFilter(propertyName, Short.valueOf(
literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThan(String propertyName, long literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanFilter(propertyName,
Long.valueOf(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThan(String propertyName, float literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanFilter(propertyName, new Float(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThan(String propertyName, double literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanFilter(propertyName,
new Double(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThanOrEqualTo(String propertyName, String literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanOrEqualToFilter(propertyName, literal);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThanOrEqualTo(String propertyName, Date literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanOrEqualToFilter(propertyName,
convertDateToIso8601Format(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThanOrEqualTo(String propertyName, int literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanOrEqualToFilter(propertyName,
Integer.valueOf(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThanOrEqualTo(String propertyName, short literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanOrEqualToFilter(propertyName,
Short.valueOf(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThanOrEqualTo(String propertyName, long literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanOrEqualToFilter(propertyName,
Long.valueOf(literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThanOrEqualTo(String propertyName, float literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanOrEqualToFilter(propertyName, new Float(
literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLessThanOrEqualTo(String propertyName, double literal) {
isComparisonOperationSupported(ComparisonOperatorType.LESS_THAN_EQUAL_TO);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLessThanOrEqualToFilter(propertyName, new Double(
literal));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsBetween(String propertyName, String lowerBoundary,
String upperBoundary) {
isComparisonOperationSupported(ComparisonOperatorType.BETWEEN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsBetweenFilter(propertyName,
lowerBoundary,
upperBoundary);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsBetween(String propertyName, Date lowerBoundary,
Date upperBoundary) {
isComparisonOperationSupported(ComparisonOperatorType.BETWEEN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsBetweenFilter(propertyName,
convertDateToIso8601Format(lowerBoundary),
convertDateToIso8601Format(upperBoundary));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsBetween(String propertyName, int lowerBoundary, int upperBoundary) {
isComparisonOperationSupported(ComparisonOperatorType.BETWEEN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsBetweenFilter(propertyName, Integer.valueOf(
lowerBoundary), Integer.valueOf(upperBoundary));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsBetween(String propertyName, short lowerBoundary,
short upperBoundary) {
isComparisonOperationSupported(ComparisonOperatorType.BETWEEN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsBetweenFilter(propertyName, Short.valueOf(
lowerBoundary), Short.valueOf(upperBoundary));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsBetween(String propertyName, long lowerBoundary,
long upperBoundary) {
isComparisonOperationSupported(ComparisonOperatorType.BETWEEN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsBetweenFilter(propertyName, Long.valueOf(
lowerBoundary), Long.valueOf(upperBoundary));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsBetween(String propertyName, float lowerBoundary,
float upperBoundary) {
isComparisonOperationSupported(ComparisonOperatorType.BETWEEN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsBetweenFilter(propertyName, new Float(
lowerBoundary), new Float(upperBoundary));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsBetween(String propertyName, double lowerBoundary,
double upperBoundary) {
isComparisonOperationSupported(ComparisonOperatorType.BETWEEN);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsBetweenFilter(propertyName, new Double(
lowerBoundary), new Double(upperBoundary));
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsNull(String propertyName) {
isComparisonOperationSupported(ComparisonOperatorType.NULL_CHECK);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsNullFilter(propertyName);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsLike(String propertyName, String pattern, boolean isCaseSensitive) {
isComparisonOperationSupported(ComparisonOperatorType.LIKE);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsLikeFilter(propertyName,
pattern,
isCaseSensitive);
} else {
return new FilterType();
}
}
@Override
public FilterType propertyIsFuzzy(String propertyName, String pattern) {
isComparisonOperationSupported(ComparisonOperatorType.FUZZY);
propertyName = mapPropertyName(propertyName);
if (isPropertyQueryable(propertyName)) {
return cswFilterFactory.buildPropertyIsFuzzyFilter(propertyName, pattern);
} else {
return new FilterType();
}
}
@Override
public FilterType xpathIsFuzzy(String xpath, String literal) {
return propertyIsFuzzy(xpath, literal);
}
@Override
public FilterType xpathIsLike(String xpath, String pattern, boolean isCaseSensitive) {
return propertyIsLike(xpath, pattern, isCaseSensitive);
}
@Override
public FilterType xpathExists(String xpath) {
return not(propertyIsNull(xpath));
}
@Override
public FilterType beyond(String propertyName, String wkt, double distance) {
LOGGER.debug("Attempting to build {} filter for property {} and WKT {} in LON/LAT order.",
new Object[] {SpatialOperatorNameType.BEYOND.name(), propertyName, wkt, distance});
if (isAnyGeo(propertyName)) {
propertyName = mapPropertyName(propertyName);
}
if (isSpatialOperationSupported(SpatialOperatorNameType.BEYOND)) {
BinarySpatialOperand beyondBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.BEYOND,
wkt);
if (beyondBinarySpatialOperand == BinarySpatialOperand.GEOMETRY) {
return cswFilterFactory.buildBeyondGeospatialFilter(propertyName, wkt, distance);
}
}
// If beyond is not supported, fallback to not(dwithin())
if (isSpatialOperationSupported(SpatialOperatorNameType.D_WITHIN)) {
BinarySpatialOperand dwithinBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.D_WITHIN,
wkt);
if (dwithinBinarySpatialOperand == BinarySpatialOperand.GEOMETRY) {
return not(dwithin(propertyName, wkt, distance));
}
}
String message = "CSW source does not support " + SpatialOperatorNameType.BEYOND.name()
+ " filter or any of its fallback spatial filters. This may be due to spatial operators not being supported "
+ "or geometry operands not being supported. See the Get Capabilities Response to determine the cause.";
throw new UnsupportedOperationException(message);
}
@Override
public FilterType contains(String propertyName, String wkt) {
LOGGER.debug("Attempting to build {} filter for property {} and WKT {} in LON/LAT order.",
new Object[] {SpatialOperatorNameType.CONTAINS.name(), propertyName, wkt});
if (isAnyGeo(propertyName)) {
propertyName = mapPropertyName(propertyName);
}
if (isSpatialOperationSupported(SpatialOperatorNameType.CONTAINS)) {
BinarySpatialOperand containsBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.CONTAINS,
wkt);
if (containsBinarySpatialOperand != BinarySpatialOperand.NONE) {
return cswFilterFactory.buildContainsGeospatialFilter(propertyName,
wkt,
containsBinarySpatialOperand);
}
}
if (isSpatialOperationSupported(SpatialOperatorNameType.WITHIN)) {
BinarySpatialOperand withinBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.WITHIN,
wkt);
if (withinBinarySpatialOperand != BinarySpatialOperand.NONE) {
return not(within(propertyName, wkt));
}
}
String message = "CSW source does not support " + SpatialOperatorNameType.CONTAINS.name()
+ " filter or any of its fallback spatial filters. This may be due to spatial operators not being supported "
+ "or geometry operands not being supported. See the Get Capabilities Response to determine the cause.";
throw new UnsupportedOperationException(message);
}
@Override
public FilterType disjoint(String propertyName, String wkt) {
LOGGER.debug(
"Attempting to build {} filter for property {} and WKT {} in LON/LAT order in LON/LAT order.",
new Object[] {SpatialOperatorNameType.DISJOINT.name(), propertyName, wkt});
if (isAnyGeo(propertyName)) {
propertyName = mapPropertyName(propertyName);
}
if (isSpatialOperationSupported(SpatialOperatorNameType.DISJOINT)) {
BinarySpatialOperand disjointBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.DISJOINT,
wkt);
if (disjointBinarySpatialOperand != BinarySpatialOperand.NONE) {
return cswFilterFactory.buildDisjointGeospatialFilter(propertyName,
wkt,
disjointBinarySpatialOperand);
}
}
if (isSpatialOperationSupported(SpatialOperatorNameType.BBOX)) {
BinarySpatialOperand bboxBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.BBOX,
wkt);
// BBOX only supports Envelope
if (bboxBinarySpatialOperand == BinarySpatialOperand.ENVELOPE) {
return not(cswFilterFactory.buildBBoxGeospatialFilter(propertyName, wkt));
}
}
if (isSpatialOperationSupported(SpatialOperatorNameType.INTERSECTS)) {
BinarySpatialOperand intersectsBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.INTERSECTS,
wkt);
if (intersectsBinarySpatialOperand != BinarySpatialOperand.NONE) {
return not(intersects(propertyName, wkt));
}
}
String message = "CSW source does not support " + SpatialOperatorNameType.DISJOINT.name()
+ " filter or any of its fallback spatial filters. This may be due to spatial operators not being supported "
+ "or geometry operands not being supported. See the Get Capabilities Response to determine the cause.";
throw new UnsupportedOperationException(message);
}
@Override
public FilterType crosses(String propertyName, String wkt) {
LOGGER.debug("Attempting to build {} filter for property {} and WKT {} in LON/LAT order.",
new Object[] {SpatialOperatorNameType.CROSSES.name(), propertyName, wkt});
if (isAnyGeo(propertyName)) {
propertyName = mapPropertyName(propertyName);
}
if (isSpatialOperationSupported(SpatialOperatorNameType.CROSSES)) {
BinarySpatialOperand binarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.CROSSES,
wkt);
if (binarySpatialOperand != BinarySpatialOperand.NONE) {
return cswFilterFactory.buildCrossesGeospatialFilter(propertyName,
wkt,
binarySpatialOperand);
}
}
String message = "CSW source does not support " + SpatialOperatorNameType.CROSSES.name()
+ " filter or any of its fallback spatial filters. This may be due to spatial operators not being supported "
+ "or geometry operands not being supported. See the Get Capabilities Response to determine the cause.";
throw new UnsupportedOperationException(message);
}
@Override
public FilterType dwithin(String propertyName, String wkt, double distance) {
LOGGER.debug("Attempting to build {} filter for property {} and WKT {} in LON/LAT order.",
new Object[] {SpatialOperatorNameType.D_WITHIN.name(), propertyName, wkt,
distance});
if (isAnyGeo(propertyName)) {
propertyName = mapPropertyName(propertyName);
}
if (isSpatialOperationSupported(SpatialOperatorNameType.D_WITHIN)) {
BinarySpatialOperand dwithinBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.D_WITHIN,
wkt);
if (dwithinBinarySpatialOperand == BinarySpatialOperand.GEOMETRY) {
return cswFilterFactory.buildDWithinGeospatialFilter(propertyName, wkt, distance);
}
}
LOGGER.debug("Unable to construct {} spatial filter. Attempting to fall back to NOT {}.",
SpatialOperatorNameType.D_WITHIN.name(),
SpatialOperatorNameType.BEYOND.name());
if (isSpatialOperationSupported(SpatialOperatorNameType.BEYOND)) {
BinarySpatialOperand beyondBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.BEYOND,
wkt);
if (beyondBinarySpatialOperand == BinarySpatialOperand.GEOMETRY) {
return not(beyond(propertyName, wkt, distance));
}
}
LOGGER.debug("Unable to construct NOT {} spatial filter. Attempting to fall back to {}.",
SpatialOperatorNameType.BEYOND.name(),
SpatialOperatorNameType.INTERSECTS.name());
if (isSpatialOperationSupported(SpatialOperatorNameType.INTERSECTS)) {
String bufferedWkt = bufferGeometry(wkt, distance);
BinarySpatialOperand intersectsBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.INTERSECTS,
bufferedWkt);
if (intersectsBinarySpatialOperand != BinarySpatialOperand.NONE) {
return intersects(propertyName, bufferedWkt);
}
}
String message = "CSW source does not support " + SpatialOperatorNameType.D_WITHIN.name()
+ " filter or any of its fallback spatial filters. This may be due to spatial operators not being supported "
+ "or geometry operands not being supported. See the Get Capabilities Response to determine the cause.";
throw new UnsupportedOperationException(message);
}
@Override
public FilterType nearestNeighbor(String propertyName, String wkt) {
// Convert Nearest Neighbor to DWithin
return dwithin(propertyName, wkt, NEAREST_NEIGHBOR_DISTANCE_LIMIT);
}
@Override
public FilterType intersects(String propertyName, String wkt) {
LOGGER.debug("Attempting to build {} filter for property {} and WKT {} in LON/LAT order.",
new Object[] {SpatialOperatorNameType.INTERSECTS.name(), propertyName, wkt});
if (isAnyGeo(propertyName)) {
propertyName = mapPropertyName(propertyName);
}
if (isSpatialOperationSupported(SpatialOperatorNameType.INTERSECTS)) {
LOGGER.debug("Building INTERSECTS filter");
BinarySpatialOperand intersectsBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.INTERSECTS,
wkt);
LOGGER.debug("BinarySpatialOperand: {}", intersectsBinarySpatialOperand);
if (intersectsBinarySpatialOperand != BinarySpatialOperand.NONE) {
return cswFilterFactory.buildIntersectsGeospatialFilter(propertyName,
wkt,
intersectsBinarySpatialOperand);
}
}
if (isSpatialOperationSupported(SpatialOperatorNameType.BBOX)) {
BinarySpatialOperand bboxBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.BBOX,
wkt);
// BBOX only supports Envelope
if (bboxBinarySpatialOperand == BinarySpatialOperand.ENVELOPE) {
LOGGER.debug("Falling back to {} filter.", SpatialOperatorNameType.BBOX.name());
return cswFilterFactory.buildBBoxGeospatialFilter(propertyName, wkt);
}
}
if (isSpatialOperationSupported(SpatialOperatorNameType.DISJOINT)) {
BinarySpatialOperand disjointBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.DISJOINT,
wkt);
if (disjointBinarySpatialOperand != BinarySpatialOperand.NONE) {
LOGGER.debug("Falling back to {} filter.", SpatialOperatorNameType.DISJOINT.name());
return not(disjoint(propertyName, wkt));
}
}
String message =
"CSW source does not support " + SpatialOperatorNameType.INTERSECTS.name() + " for "
+ getGeometryOperandFromWkt(wkt)
+ " filter or any of its fallback spatial filters. This may be due to spatial operators not being supported "
+ "or geometry operands not being supported. See the Get Capabilities Response to determine the cause.";
throw new UnsupportedOperationException(message);
}
@Override
public FilterType overlaps(String propertyName, String wkt) {
LOGGER.debug("Attempting to build {} filter for property {} and WKT {} in LON/LAT order.",
new Object[] {SpatialOperatorNameType.OVERLAPS.name(), propertyName, wkt});
if (isAnyGeo(propertyName)) {
propertyName = mapPropertyName(propertyName);
}
if (isSpatialOperationSupported(SpatialOperatorNameType.OVERLAPS)) {
BinarySpatialOperand overlapsBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.OVERLAPS,
wkt);
if (overlapsBinarySpatialOperand != BinarySpatialOperand.NONE) {
return cswFilterFactory.buildOverlapsGeospatialFilter(propertyName,
wkt,
overlapsBinarySpatialOperand);
}
}
String message = "CSW source does not support " + SpatialOperatorNameType.OVERLAPS.name()
+ " filter.";
throw new UnsupportedOperationException(message);
}
@Override
public FilterType touches(String propertyName, String wkt) {
LOGGER.debug("Attempting to build {} filter for property {} and WKT {} in LON/LAT order.",
new Object[] {SpatialOperatorNameType.TOUCHES.name(), propertyName, wkt});
if (isAnyGeo(propertyName)) {
propertyName = mapPropertyName(propertyName);
}
if (isSpatialOperationSupported(SpatialOperatorNameType.TOUCHES)) {
BinarySpatialOperand touchesBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.TOUCHES,
wkt);
if (touchesBinarySpatialOperand != BinarySpatialOperand.NONE) {
return cswFilterFactory.buildTouchesGeospatialFilter(propertyName,
wkt,
touchesBinarySpatialOperand);
}
}
String message = "CSW source does not support " + SpatialOperatorNameType.TOUCHES.name()
+ " filter.";
throw new UnsupportedOperationException(message);
}
@Override
public FilterType within(String propertyName, String wkt) {
LOGGER.debug("Attempting to build {} filter for property {} and WKT {} in LON/LAT order.",
new Object[] {SpatialOperatorNameType.WITHIN.name(), propertyName, wkt});
if (isAnyGeo(propertyName)) {
propertyName = mapPropertyName(propertyName);
}
if (isSpatialOperationSupported(SpatialOperatorNameType.WITHIN)) {
BinarySpatialOperand withinBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.WITHIN,
wkt);
if (withinBinarySpatialOperand != BinarySpatialOperand.NONE) {
return cswFilterFactory.buildWithinGeospatialFilter(propertyName,
wkt,
withinBinarySpatialOperand);
}
}
if (isSpatialOperationSupported(SpatialOperatorNameType.CONTAINS)) {
LOGGER.debug("Falling back to {} filter.", SpatialOperatorNameType.CONTAINS.name());
BinarySpatialOperand containsBinarySpatialOperand = useGeometryOrEnvelope(
SpatialOperatorNameType.CONTAINS,
wkt);
if (containsBinarySpatialOperand != BinarySpatialOperand.NONE) {
return contains(propertyName, wkt);
}
}
String message =
"CSW source does not support " + SpatialOperatorNameType.WITHIN.name() + " filter.";
throw new UnsupportedOperationException(message);
}
@Override
public FilterType during(String propertyName, Date startDate, Date endDate) {
return cswFilterFactory.buildPropertyIsBetweenFilter(mapPropertyName(propertyName),
convertDateToIso8601Format(startDate),
convertDateToIso8601Format(endDate));
}
@Override
public FilterType relative(String propertyName, long duration) {
Date currentDate = new Date();
return during(propertyName, new Date(currentDate.getTime() - duration), currentDate);
}
@Override
public FilterType before(String propertyName, Date date) {
return cswFilterFactory.buildPropertyIsLessThanFilter(mapPropertyName(propertyName),
convertDateToIso8601Format(date));
}
@Override
public FilterType after(String propertyName, Date date) {
return cswFilterFactory.buildPropertyIsGreaterThanFilter(mapPropertyName(propertyName),
convertDateToIso8601Format(date));
}
private DateTime convertDateToIso8601Format(Date inputDate) {
return new DateTime(inputDate);
}
protected String mapPropertyName(String propertyName) {
if (isAnyText(propertyName) || isMetadata(propertyName)) {
propertyName = CswConstants.ANY_TEXT;
} else if (isAnyGeo(propertyName)) {
propertyName = CswConstants.BBOX_PROP;
}
propertyName = StringUtils.defaultIfBlank(cswSourceConfiguration.getMetacardMapping(
propertyName), propertyName);
return propertyName;
}
private boolean isAnyText(String propertyName) {
return Metacard.ANY_TEXT.equalsIgnoreCase(propertyName);
}
private boolean isAnyGeo(String propertyName) {
return Metacard.ANY_GEO.equalsIgnoreCase(propertyName);
}
protected boolean isContentTypeVersion(String propertyName) {
return Metacard.CONTENT_TYPE_VERSION.equalsIgnoreCase(propertyName);
}
protected boolean isMetadata(String propertyName) {
return Core.METADATA.equalsIgnoreCase(propertyName);
}
private boolean isSpatialOperationSupported(SpatialOperatorNameType operation) {
return spatialOps.containsKey(operation);
}
private Geometry getGeometryFromWkt(String wkt) {
try {
return new WKTReader().read(wkt);
} catch (ParseException e) {
throw new IllegalArgumentException("Unable to parse WKT: " + wkt, e);
}
}
private BinarySpatialOperand useGeometryOrEnvelope(SpatialOperatorNameType spatialOperatorName,
String wkt) {
BinarySpatialOperand binarySpatialOperand = null;
boolean isEnvelopeSupported = false;
boolean isGeometrySupported = false;
String wktGeometryOperand = getGeometryOperandFromWkt(wkt);
LOGGER.debug(
"Attempting to determine if geometry operand [{}] is supported for spatial operator [{}].",
wktGeometryOperand,
spatialOperatorName.toString());
/**
* Check if the geometry operand is supported for the specific spatial operation. For
* example, check if the geometry operand POINT is supported for the spatial operator
* INTERSECTS.
*/
for (QName geometryOperand : getGeometryOperands(spatialOperatorName)) {
String localPart = geometryOperand.getLocalPart();
LOGGER.debug("Geometry operand from Get Capabilities Response: {}", localPart);
if (wktGeometryOperand.equalsIgnoreCase(localPart)) {
isGeometrySupported = true;
} else if (BinarySpatialOperand.ENVELOPE.toString()
.equalsIgnoreCase(localPart)) {
isEnvelopeSupported = true;
}
}
/**
* Check if the geometry operand is supported for the specific spatial operation by checking
* the global geometry operands (geometry operands that apply to all spatial operators).
*/
if (globalGeometryOperands != null) {
for (QName geometryOperand : globalGeometryOperands) {
String localPart = geometryOperand.getLocalPart();
LOGGER.debug(
"Geometry operand from Get Capabilities Response (Global to all Spatial Operators): {}",
localPart);
if (wktGeometryOperand.equalsIgnoreCase(localPart)) {
isGeometrySupported = true;
} else if (BinarySpatialOperand.ENVELOPE.toString()
.equalsIgnoreCase(localPart)) {
isEnvelopeSupported = true;
}
}
}
LOGGER.debug("Is geometry [{}] supported? {}", wktGeometryOperand, isGeometrySupported);
LOGGER.debug("Is envelope supported? {}", isEnvelopeSupported);
/**
* In most cases, if the Geometry is supported use it; otherwise, use an Envelope. Geometry
* is not valid for BBOX, only use Envelope. Envelope is not valid for Beyond and D_Within,
* only use Geometry.
*/
if (isGeometrySupported && spatialOperatorName != SpatialOperatorNameType.BBOX) {
binarySpatialOperand = BinarySpatialOperand.GEOMETRY;
} else if (isEnvelopeSupported && spatialOperatorName != SpatialOperatorNameType.BEYOND
&& spatialOperatorName != SpatialOperatorNameType.D_WITHIN) {
binarySpatialOperand = BinarySpatialOperand.ENVELOPE;
} else {
binarySpatialOperand = BinarySpatialOperand.NONE;
}
LOGGER.debug("Use geometry or envelope? {}", binarySpatialOperand.toString());
return binarySpatialOperand;
}
private String getGeometryOperandFromWkt(String wkt) {
return wkt.split("\\(")[0].trim();
}
private List<QName> getGeometryOperands(SpatialOperatorNameType spatialOperatorName) {
SpatialOperatorType spatialOperatorType = spatialOps.get(spatialOperatorName);
List<QName> geometryOperands = new ArrayList<>();
if (spatialOperatorType != null) {
GeometryOperandsType geometryOperandsType = spatialOperatorType.getGeometryOperands();
if (geometryOperandsType != null) {
geometryOperands = geometryOperandsType.getGeometryOperand();
}
}
return geometryOperands;
}
private String bufferGeometry(String wkt, double distance) {
LOGGER.debug("Buffering WKT {} by distance {} meter(s).", wkt, distance);
Geometry geometry = getGeometryFromWkt(wkt);
double bufferInDegrees = metersToDegrees(distance);
LOGGER.debug("Buffering {} by {} degree(s).",
geometry.getClass()
.getSimpleName(),
bufferInDegrees);
Geometry bufferedGeometry = geometry.buffer(bufferInDegrees);
String bufferedWkt = new WKTWriter().write(bufferedGeometry);
LOGGER.debug("Buffered WKT: {}.", bufferedWkt);
return bufferedWkt;
}
/**
* This method approximates the degrees in latitude for the given distance (in meters) using the
* formula for the meridian distance on Earth.
* <p>
* degrees = distance in meters/radius of Earth in meters * 180.0/pi
* <p>
* The approximate degrees in latitude can be used to compute a buffer around a given geometry
* (see bufferGeometry()).
*/
private double metersToDegrees(double distance) {
double degrees = (distance / CswConstants.EARTH_MEAN_RADIUS_METERS)
* CswConstants.RADIANS_TO_DEGREES;
LOGGER.debug("{} meter(s) is approximately {} degree(s) of latitude.", distance, degrees);
return degrees;
}
private void isComparisonOperationSupported(ComparisonOperatorType operation) {
if (!comparisonOps.contains(operation)) {
throw new UnsupportedOperationException(
"Unsupported Property Comparison Type of [" + operation.value() + "].");
}
}
private void areLogicalOperationsSupported() {
if (!logicalOps) {
throw new UnsupportedOperationException("Logical Operations are not supported.");
}
}
/**
* Reads the {@link net.opengis.filter.v_1_1_0.FilterCapabilities} in order to determine what types of queries the server
* can handle.
*
* @param filterCapabilities The {@link net.opengis.filter.v_1_1_0.FilterCapabilities} understood by the Csw service
*/
private final void updateAllowedOperations(FilterCapabilities filterCapabilities) {
comparisonOps = Collections.newSetFromMap(new ConcurrentHashMap<>(new EnumMap<>(
ComparisonOperatorType.class)));
spatialOps = new ConcurrentHashMap<>(new EnumMap<>(SpatialOperatorNameType.class));
logicalOps = true;
if (null == filterCapabilities) {
LOGGER.info("CSW Service doesn't support any filters");
return;
}
ScalarCapabilitiesType scalarCapabilities = filterCapabilities.getScalarCapabilities();
if (null != scalarCapabilities) {
ComparisonOperatorsType comparisonOperators =
scalarCapabilities.getComparisonOperators();
if (null != comparisonOperators) { // filter out nulls
for (ComparisonOperatorType comp : comparisonOperators.getComparisonOperator()) {
if (null != comp) {
comparisonOps.add(comp);
}
}
}
logicalOps = (null != scalarCapabilities.getLogicalOperators());
}
SpatialCapabilitiesType spatialCapabilities = filterCapabilities.getSpatialCapabilities();
if (null != spatialCapabilities && null != spatialCapabilities.getSpatialOperators()) {
setSpatialOps(spatialCapabilities.getSpatialOperators());
}
GeometryOperandsType geometryOperandsType = null;
if (spatialCapabilities != null) {
geometryOperandsType = spatialCapabilities.getGeometryOperands();
}
if (geometryOperandsType != null) {
globalGeometryOperands = geometryOperandsType.getGeometryOperand();
LOGGER.debug("globalGeometryOperands: {}", globalGeometryOperands);
}
}
public GeometryOperandsType getGeoOpsForSpatialOp(SpatialOperatorNameType name) {
SpatialOperatorType sot = spatialOps.get(name);
if (sot != null) {
return sot.getGeometryOperands();
}
return null;
}
public void setSpatialOps(SpatialOperatorsType spatialOperators) {
spatialOps = new ConcurrentHashMap<>(new EnumMap<>(SpatialOperatorNameType.class));
for (SpatialOperatorType spatialOp : spatialOperators.getSpatialOperator()) {
LOGGER.debug("Adding key [spatialOp Name: {}]", spatialOp.getName());
spatialOps.put(spatialOp.getName(), spatialOp);
LOGGER.debug("spatialOps Map: {}", spatialOps.toString());
}
}
}