/** * Copyright (c) Codice Foundation * * 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. * * 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.wfs.v1_0_0.catalog.source; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.namespace.QName; import org.apache.commons.lang.StringUtils; import org.apache.cxf.common.util.CollectionUtils; import org.codice.ddf.spatial.ogc.wfs.catalog.common.FeatureAttributeDescriptor; import org.codice.ddf.spatial.ogc.wfs.catalog.common.FeatureMetacardType; import org.codice.ddf.spatial.ogc.wfs.catalog.common.WfsConstants; import org.codice.ddf.spatial.ogc.wfs.v1_0_0.catalog.common.Wfs10Constants; import org.codice.ddf.spatial.ogc.wfs.v1_0_0.catalog.common.Wfs10Constants.SPATIAL_OPERATORS; import org.codice.ddf.spatial.ogc.wfs.v1_0_0.catalog.common.Wfs10JTStoGML200Converter; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.MultiLineString; import com.vividsolutions.jts.geom.MultiPoint; import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; 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.filter.FilterDelegate; import ogc.schema.opengis.filter.v_1_0_0.BBOXType; import ogc.schema.opengis.filter.v_1_0_0.BinaryComparisonOpType; import ogc.schema.opengis.filter.v_1_0_0.BinaryLogicOpType; import ogc.schema.opengis.filter.v_1_0_0.BinarySpatialOpType; import ogc.schema.opengis.filter.v_1_0_0.ComparisonOpsType; import ogc.schema.opengis.filter.v_1_0_0.DistanceBufferType; import ogc.schema.opengis.filter.v_1_0_0.DistanceType; import ogc.schema.opengis.filter.v_1_0_0.FeatureIdType; import ogc.schema.opengis.filter.v_1_0_0.FilterType; import ogc.schema.opengis.filter.v_1_0_0.LiteralType; import ogc.schema.opengis.filter.v_1_0_0.LowerBoundaryType; import ogc.schema.opengis.filter.v_1_0_0.ObjectFactory; import ogc.schema.opengis.filter.v_1_0_0.PropertyIsBetweenType; import ogc.schema.opengis.filter.v_1_0_0.PropertyIsLikeType; import ogc.schema.opengis.filter.v_1_0_0.PropertyNameType; import ogc.schema.opengis.filter.v_1_0_0.SpatialOpsType; import ogc.schema.opengis.filter.v_1_0_0.UnaryLogicOpType; import ogc.schema.opengis.filter.v_1_0_0.UpperBoundaryType; import ogc.schema.opengis.gml.v_2_1_2.AbstractGeometryType; import ogc.schema.opengis.gml.v_2_1_2.BoxType; import ogc.schema.opengis.gml.v_2_1_2.CoordinatesType; import ogc.schema.opengis.gml.v_2_1_2.GeometryCollectionType; import ogc.schema.opengis.gml.v_2_1_2.LineStringType; import ogc.schema.opengis.gml.v_2_1_2.LinearRingMemberType; import ogc.schema.opengis.gml.v_2_1_2.LinearRingType; import ogc.schema.opengis.gml.v_2_1_2.MultiLineStringType; import ogc.schema.opengis.gml.v_2_1_2.MultiPointType; import ogc.schema.opengis.gml.v_2_1_2.MultiPolygonType; import ogc.schema.opengis.gml.v_2_1_2.PointType; import ogc.schema.opengis.gml.v_2_1_2.PolygonType; /** * The purpose of this class is to convert DDF OGC Filters into WFS compatible OGC Filters. This * class will return an "Invalid"(null) filter if a translation could not be made. It will return an * "Empty" filter, meaning no filters are set, only if it is a Content Type filter. */ public class WfsFilterDelegate extends FilterDelegate<FilterType> { private static final Logger LOGGER = LoggerFactory.getLogger(WfsFilterDelegate.class); private static final String MISSING_PARAMETERS_MSG = "Required parameters are missing"; private static final String PROPERTY_NOT_QUERYABLE = "'%s' is not a queryable property."; private FeatureMetacardType featureMetacardType; private ObjectFactory filterObjectFactory = new ObjectFactory(); private ogc.schema.opengis.gml.v_2_1_2.ObjectFactory gmlObjectFactory = new ogc.schema.opengis.gml.v_2_1_2.ObjectFactory(); private List<String> supportedGeo; private List<QName> geometryOperands; private String srsName; private boolean isEpsg4326 = false; public WfsFilterDelegate(FeatureMetacardType featureMetacardType, List<String> supportedGeo, String srsName) { if (featureMetacardType == null) { throw new IllegalArgumentException("FeatureMetacardType can not be null"); } this.featureMetacardType = featureMetacardType; this.supportedGeo = supportedGeo; this.srsName = srsName; if (WfsConstants.EPSG_4326.equalsIgnoreCase(srsName)) { isEpsg4326 = true; } else { LOGGER.debug( "Unable to convert geometry to {}. All geospatial queries for this featureType will be invalidated!", srsName); } setSupportedGeometryOperands(Wfs10Constants.wktOperandsAsList()); } public void setSupportedGeometryOperands(List<QName> geometryOperands) { this.geometryOperands = geometryOperands; } private boolean isGeometryOperandSupported(QName geoOperand) { return geometryOperands.contains(geoOperand); } public void setSupportedGeoFilters(List<String> supportedGeos) { LOGGER.debug("Updating supportedGeos to: {}", Arrays.toString(supportedGeos.toArray())); this.supportedGeo = supportedGeos; } @Override public FilterType and(List<FilterType> filtersToBeAnded) { return buildAndOrFilter(filtersToBeAnded, filterObjectFactory.createAnd(new BinaryLogicOpType())); } @Override public FilterType or(List<FilterType> filtersToBeOred) { // Remove invalid filters so they aren't OR'd. filtersToBeOred.removeAll(Collections.singleton(null)); return buildAndOrFilter(filtersToBeOred, filterObjectFactory.createOr(new BinaryLogicOpType())); } @Override public FilterType not(FilterType filterToBeNoted) { FilterType returnFilter = new FilterType(); if (filterToBeNoted == null) { return returnFilter; } UnaryLogicOpType notType = new UnaryLogicOpType(); if (filterToBeNoted.isSetComparisonOps()) { notType.setComparisonOps(filterToBeNoted.getComparisonOps()); } else if (filterToBeNoted.isSetLogicOps()) { notType.setLogicOps(filterToBeNoted.getLogicOps()); } else if (filterToBeNoted.isSetSpatialOps()) { notType.setSpatialOps(filterToBeNoted.getSpatialOps()); } else { return returnFilter; } returnFilter.setLogicOps(filterObjectFactory.createNot(notType)); return returnFilter; } private Set<String> getFeatureIds(List<FilterType> filters) { Set<String> ids = new HashSet<String>(); // This filter delegate requires that if one filter is a featureId // filter, they // must all be. if (!CollectionUtils.isEmpty(filters)) { boolean isFeatureIdFilter = filters.get(0) != null && filters.get(0).isSetFeatureId(); for (FilterType filterType : filters) { if ((filterType != null && filterType.isSetFeatureId()) != isFeatureIdFilter) { throw new UnsupportedOperationException( "Query with mix of feature ID and non-feature ID queries not supported"); } if (isFeatureIdFilter) { for (FeatureIdType idType : filterType.getFeatureId()) { ids.add(idType.getFid()); } } } } return ids; } private FilterType buildFeatureIdFilter(Set<String> ids) { FilterType filterType = new FilterType(); for (String id : ids) { filterType.getFeatureId().add(createFeatureIdFilter(id)); } return filterType; } private FilterType buildAndOrFilter(List<FilterType> filters, JAXBElement<BinaryLogicOpType> andOrFilter) { if (filters.isEmpty()) { return null; } removeEmptyFilters(filters); // Check if these filters contain featureID(s) Set<String> featureIds = getFeatureIds(filters); if (!CollectionUtils.isEmpty(featureIds)) { return buildFeatureIdFilter(featureIds); } // If we have 1 filter don't wrap it with AND/OR if (filters.size() == 1) { return filters.get(0); } for (FilterType filterType : filters) { // Determine which filterType is set if (filterType.isSetComparisonOps()) { andOrFilter.getValue().getComparisonOpsOrSpatialOpsOrLogicOps() .add(filterType.getComparisonOps()); } else if (filterType.isSetLogicOps()) { andOrFilter.getValue().getComparisonOpsOrSpatialOpsOrLogicOps() .add(filterType.getLogicOps()); } else if (filterType.isSetSpatialOps()) { andOrFilter.getValue().getComparisonOpsOrSpatialOpsOrLogicOps() .add(filterType.getSpatialOps()); } } FilterType returnFilter = new FilterType(); returnFilter.setLogicOps(andOrFilter); return returnFilter; } private void removeEmptyFilters(List<FilterType> filters) { // Loop through the filters and remove any empty filters List<FilterType> filtersToBeRemoved = new ArrayList<FilterType>(filters.size()); Boolean foundInvalidFilter = false; for (FilterType filterType : filters) { if (filterType == null) { foundInvalidFilter = true; } else if (!isFilterSet(filterType)) { filtersToBeRemoved.add(filterType); } } // If we found an invalid filter we want to return an invalid filter. if (foundInvalidFilter) { filters.clear(); filters.add(null); } else { filters.removeAll(filtersToBeRemoved); filters.removeAll(Collections.singleton(null)); if (filters.isEmpty()) { filters.add(new FilterType()); } } } private Boolean isFilterSet(FilterType filter) { return (filter.isSetComparisonOps() || filter.isSetLogicOps() || filter.isSetSpatialOps() || filter.isSetFeatureId()); } @Override public FilterType propertyIsEqualTo(String propertyName, String literal, boolean isCaseSensitive) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsEqualTo); } @Override public FilterType propertyIsEqualTo(String propertyName, Date date) { return buildPropertyIsFilterType(propertyName, convertDateToIso8601Format(date), PROPERTY_IS_OPS.PropertyIsEqualTo); } @Override public FilterType propertyIsEqualTo(String propertyName, int literal) { return buildPropertyIsFilterType(propertyName, Integer.valueOf(literal), PROPERTY_IS_OPS.PropertyIsEqualTo); } @Override public FilterType propertyIsEqualTo(String propertyName, short literal) { return buildPropertyIsFilterType(propertyName, Short.valueOf(literal), PROPERTY_IS_OPS.PropertyIsEqualTo); } @Override public FilterType propertyIsEqualTo(String propertyName, long literal) { return buildPropertyIsFilterType(propertyName, Long.valueOf(literal), PROPERTY_IS_OPS.PropertyIsEqualTo); } @Override public FilterType propertyIsEqualTo(String propertyName, float literal) { return buildPropertyIsFilterType(propertyName, Float.valueOf(literal), PROPERTY_IS_OPS.PropertyIsEqualTo); } @Override public FilterType propertyIsEqualTo(String propertyName, double literal) { return buildPropertyIsFilterType(propertyName, Double.valueOf(literal), PROPERTY_IS_OPS.PropertyIsEqualTo); } @Override public FilterType propertyIsEqualTo(String propertyName, boolean literal) { return buildPropertyIsFilterType(propertyName, Boolean.valueOf(literal), PROPERTY_IS_OPS.PropertyIsEqualTo); } @Override public FilterType propertyIsLike(String propertyName, String literal, boolean isCaseSensitive) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLike); } @Override public FilterType propertyIsNotEqualTo(String propertyName, String literal, boolean isCaseSensitive) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsNotEqualTo); } @Override public FilterType propertyIsNotEqualTo(String propertyName, Date literal) { return buildPropertyIsFilterType(propertyName, convertDateToIso8601Format(literal), PROPERTY_IS_OPS.PropertyIsNotEqualTo); } @Override public FilterType propertyIsNotEqualTo(String propertyName, int literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsNotEqualTo); } @Override public FilterType propertyIsNotEqualTo(String propertyName, short literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsNotEqualTo); } @Override public FilterType propertyIsNotEqualTo(String propertyName, long literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsNotEqualTo); } @Override public FilterType propertyIsNotEqualTo(String propertyName, float literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsNotEqualTo); } @Override public FilterType propertyIsNotEqualTo(String propertyName, double literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsNotEqualTo); } @Override public FilterType propertyIsNotEqualTo(String propertyName, boolean literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsNotEqualTo); } @Override public FilterType propertyIsGreaterThan(String propertyName, String literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsGreaterThan); } @Override public FilterType propertyIsGreaterThan(String propertyName, Date literal) { return buildPropertyIsFilterType(propertyName, convertDateToIso8601Format(literal), PROPERTY_IS_OPS.PropertyIsGreaterThan); } @Override public FilterType propertyIsGreaterThan(String propertyName, int literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsGreaterThan); } @Override public FilterType propertyIsGreaterThan(String propertyName, short literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsGreaterThan); } @Override public FilterType propertyIsGreaterThan(String propertyName, long literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsGreaterThan); } @Override public FilterType propertyIsGreaterThan(String propertyName, float literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsGreaterThan); } @Override public FilterType propertyIsGreaterThan(String propertyName, double literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsGreaterThan); } @Override public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, String literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsGreaterThanOrEqualTo); } @Override public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, Date literal) { return buildPropertyIsFilterType(propertyName, convertDateToIso8601Format(literal), PROPERTY_IS_OPS.PropertyIsGreaterThanOrEqualTo); } @Override public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, int literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsGreaterThanOrEqualTo); } @Override public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, short literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsGreaterThanOrEqualTo); } @Override public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, long literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsGreaterThanOrEqualTo); } @Override public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, float literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsGreaterThanOrEqualTo); } @Override public FilterType propertyIsGreaterThanOrEqualTo(String propertyName, double literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsGreaterThanOrEqualTo); } @Override public FilterType propertyIsLessThan(String propertyName, String literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLessThan); } @Override public FilterType propertyIsLessThan(String propertyName, Date literal) { return buildPropertyIsFilterType(propertyName, convertDateToIso8601Format(literal), PROPERTY_IS_OPS.PropertyIsLessThan); } @Override public FilterType propertyIsLessThan(String propertyName, int literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLessThan); } @Override public FilterType propertyIsLessThan(String propertyName, short literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLessThan); } @Override public FilterType propertyIsLessThan(String propertyName, long literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLessThan); } @Override public FilterType propertyIsLessThan(String propertyName, float literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLessThan); } @Override public FilterType propertyIsLessThan(String propertyName, double literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLessThan); } @Override public FilterType propertyIsLessThanOrEqualTo(String propertyName, String literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLessThanOrEqualTo); } @Override public FilterType propertyIsLessThanOrEqualTo(String propertyName, Date literal) { return buildPropertyIsFilterType(propertyName, convertDateToIso8601Format(literal), PROPERTY_IS_OPS.PropertyIsLessThanOrEqualTo); } @Override public FilterType propertyIsLessThanOrEqualTo(String propertyName, int literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLessThanOrEqualTo); } @Override public FilterType propertyIsLessThanOrEqualTo(String propertyName, short literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLessThanOrEqualTo); } @Override public FilterType propertyIsLessThanOrEqualTo(String propertyName, long literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLessThanOrEqualTo); } @Override public FilterType propertyIsLessThanOrEqualTo(String propertyName, float literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLessThanOrEqualTo); } @Override public FilterType propertyIsLessThanOrEqualTo(String propertyName, double literal) { return buildPropertyIsFilterType(propertyName, literal, PROPERTY_IS_OPS.PropertyIsLessThanOrEqualTo); } @Override public FilterType propertyIsBetween(String propertyName, String lowerBoundary, String upperBoundary) { return buildPropertyIsBetweenFilterType(propertyName, lowerBoundary, upperBoundary); } @Override public FilterType propertyIsBetween(String propertyName, Date lowerBoundary, Date upperBoundary) { return buildPropertyIsBetweenFilterType(propertyName, convertDateToIso8601Format(lowerBoundary), convertDateToIso8601Format(upperBoundary)); } @Override public FilterType propertyIsBetween(String propertyName, int lowerBoundary, int upperBoundary) { return buildPropertyIsBetweenFilterType(propertyName, lowerBoundary, upperBoundary); } @Override public FilterType propertyIsBetween(String propertyName, short lowerBoundary, short upperBoundary) { return buildPropertyIsBetweenFilterType(propertyName, lowerBoundary, upperBoundary); } @Override public FilterType propertyIsBetween(String propertyName, long lowerBoundary, long upperBoundary) { return buildPropertyIsBetweenFilterType(propertyName, lowerBoundary, upperBoundary); } @Override public FilterType propertyIsBetween(String propertyName, float lowerBoundary, float upperBoundary) { return buildPropertyIsBetweenFilterType(propertyName, lowerBoundary, upperBoundary); } @Override public FilterType propertyIsBetween(String propertyName, double lowerBoundary, double upperBoundary) { return buildPropertyIsBetweenFilterType(propertyName, lowerBoundary, upperBoundary); } private FilterType buildPropertyIsBetweenFilterType(String propertyName, Object lowerBoundary, Object upperBoundary) { if (!isValidInputParameters(propertyName, lowerBoundary, upperBoundary)) { throw new IllegalArgumentException(MISSING_PARAMETERS_MSG); } FilterType filter = new FilterType(); if (featureMetacardType.getProperties().contains(propertyName)) { FeatureAttributeDescriptor featureAttributeDescriptor = (FeatureAttributeDescriptor) featureMetacardType .getAttributeDescriptor(propertyName); if (featureAttributeDescriptor.isIndexed()) { filter.setComparisonOps( createPropertyIsBetween(featureAttributeDescriptor.getPropertyName(), lowerBoundary, upperBoundary)); } else { throw new IllegalArgumentException( String.format(PROPERTY_NOT_QUERYABLE, propertyName)); } } else { return null; } return filter; } private FilterType buildPropertyIsFilterType(String propertyName, Object literal, PROPERTY_IS_OPS propertyIsType) { if (!isValidInputParameters(propertyName, literal)) { throw new IllegalArgumentException(MISSING_PARAMETERS_MSG); } FilterType returnFilter = new FilterType(); // If this is a Content Type filter verify its for this Filter delegate. if (Metacard.CONTENT_TYPE.equals(propertyName)) { if (featureMetacardType.getName().equals(literal)) { return returnFilter; } return null; } // Special Case - If we get an ANY_TEXT we want to convert that to a // series of OR's if ((Metacard.ANY_TEXT.equalsIgnoreCase(propertyName))) { if (CollectionUtils.isEmpty(featureMetacardType.getTextualProperties())) { LOGGER.debug("Feature Type does not have Textual Properties to query."); return null; } if (featureMetacardType.getTextualProperties().size() == 1) { FeatureAttributeDescriptor attrDescriptor = (FeatureAttributeDescriptor) featureMetacardType .getAttributeDescriptor(featureMetacardType.getTextualProperties().get(0)); if (attrDescriptor.isIndexed()) { returnFilter.setComparisonOps( createPropertyIsFilter(attrDescriptor.getPropertyName(), literal, propertyIsType)); } else { LOGGER.debug( "All textual properties have been blacklisted. Removing from query."); return null; } } else { List<FilterType> binaryCompOpsToBeOred = new ArrayList<FilterType>(); for (String property : featureMetacardType.getTextualProperties()) { // only build filters for queryable properties FeatureAttributeDescriptor attrDesc = (FeatureAttributeDescriptor) featureMetacardType .getAttributeDescriptor(property); if (attrDesc.isIndexed()) { FilterType filter = new FilterType(); filter.setComparisonOps( createPropertyIsFilter(attrDesc.getPropertyName(), literal, propertyIsType)); binaryCompOpsToBeOred.add(filter); } else { LOGGER.debug(String.format(PROPERTY_NOT_QUERYABLE, property)); } } if (!binaryCompOpsToBeOred.isEmpty()) { returnFilter = or(binaryCompOpsToBeOred); } else { LOGGER.debug( "All textual properties have been blacklisted. Removing from query."); return null; } } // filter is for a specific property; check to see if it is valid } else if (featureMetacardType.getProperties().contains(propertyName)) { FeatureAttributeDescriptor attrDesc = (FeatureAttributeDescriptor) featureMetacardType .getAttributeDescriptor(propertyName); if (attrDesc.isIndexed()) { returnFilter.setComparisonOps( createPropertyIsFilter(attrDesc.getPropertyName(), literal, propertyIsType)); } else { // blacklisted property encountered throw new IllegalArgumentException( String.format(PROPERTY_NOT_QUERYABLE, propertyName)); } } else if (Metacard.ID.equals(propertyName)) { LOGGER.debug("feature id query for : {}", literal); String[] idTokens = literal.toString().split("\\."); if (idTokens.length > 1) { if (idTokens[0].equals(featureMetacardType.getName())) { LOGGER.debug("feature type matches metacard type; creating featureID filter"); returnFilter.getFeatureId().add(createFeatureIdFilter(literal.toString())); } else { LOGGER.debug("feature type does not match metacard type; invalidating filter"); return null; } } else { returnFilter.getFeatureId().add(createFeatureIdFilter(literal.toString())); } } else { return null; } return returnFilter; } private JAXBElement<? extends ComparisonOpsType> createPropertyIsFilter(String property, Object literal, PROPERTY_IS_OPS operation) { switch (operation) { case PropertyIsEqualTo: JAXBElement<BinaryComparisonOpType> propIsEqualTo = filterObjectFactory .createPropertyIsEqualTo(new BinaryComparisonOpType()); propIsEqualTo.getValue().getExpression().add(createPropertyNameType(property)); propIsEqualTo.getValue().getExpression().add(createLiteralType(literal)); return propIsEqualTo; case PropertyIsNotEqualTo: JAXBElement<BinaryComparisonOpType> propIsNotEqualTo = filterObjectFactory .createPropertyIsNotEqualTo(new BinaryComparisonOpType()); propIsNotEqualTo.getValue().getExpression().add(createPropertyNameType(property)); propIsNotEqualTo.getValue().getExpression().add(createLiteralType(literal)); return propIsNotEqualTo; case PropertyIsGreaterThan: JAXBElement<BinaryComparisonOpType> propIsGreaterThan = filterObjectFactory .createPropertyIsGreaterThan(new BinaryComparisonOpType()); propIsGreaterThan.getValue().getExpression().add(createPropertyNameType(property)); propIsGreaterThan.getValue().getExpression().add(createLiteralType(literal)); return propIsGreaterThan; case PropertyIsGreaterThanOrEqualTo: JAXBElement<BinaryComparisonOpType> propIsGreaterThanOrEqualTo = filterObjectFactory .createPropertyIsGreaterThanOrEqualTo(new BinaryComparisonOpType()); propIsGreaterThanOrEqualTo.getValue().getExpression() .add(createPropertyNameType(property)); propIsGreaterThanOrEqualTo.getValue().getExpression().add(createLiteralType(literal)); return propIsGreaterThanOrEqualTo; case PropertyIsLessThan: JAXBElement<BinaryComparisonOpType> propIsLessThan = filterObjectFactory .createPropertyIsLessThan(new BinaryComparisonOpType()); propIsLessThan.getValue().getExpression().add(createPropertyNameType(property)); propIsLessThan.getValue().getExpression().add(createLiteralType(literal)); return propIsLessThan; case PropertyIsLessThanOrEqualTo: JAXBElement<BinaryComparisonOpType> propIsLessThanOrEqualTo = filterObjectFactory .createPropertyIsLessThanOrEqualTo(new BinaryComparisonOpType()); propIsLessThanOrEqualTo.getValue().getExpression() .add(createPropertyNameType(property)); propIsLessThanOrEqualTo.getValue().getExpression().add(createLiteralType(literal)); return propIsLessThanOrEqualTo; case PropertyIsLike: JAXBElement<PropertyIsLikeType> propIsLike = filterObjectFactory .createPropertyIsLike(new PropertyIsLikeType()); propIsLike.getValue().setPropertyName(createPropertyNameType(property).getValue()); propIsLike.getValue().setEscape(WfsConstants.ESCAPE); propIsLike.getValue().setSingleChar(SINGLE_CHAR); propIsLike.getValue().setWildCard(WfsConstants.WILD_CARD); propIsLike.getValue().setLiteral(createLiteralType(literal).getValue()); return propIsLike; default: throw new UnsupportedOperationException("Unsupported Property Comparison Type"); } } private JAXBElement<PropertyIsBetweenType> createPropertyIsBetween(String property, Object lowerBoundary, Object upperBoundary) { PropertyIsBetweenType propertyIsBetween = new PropertyIsBetweenType(); propertyIsBetween.setLowerBoundary(createLowerBoundary(lowerBoundary)); propertyIsBetween.setUpperBoundary(createUpperBoundary(upperBoundary)); propertyIsBetween.setExpression(createPropertyNameType(property)); return filterObjectFactory.createPropertyIsBetween(propertyIsBetween); } private FeatureIdType createFeatureIdFilter(final String id) { FeatureIdType featureIdType = new FeatureIdType(); featureIdType.setFid(id); return featureIdType; } private boolean isValidInputParameters(String propertyName, Object literal) { if (literal == null || StringUtils.isEmpty(propertyName) || StringUtils .isEmpty(literal.toString())) { return false; } return true; } private boolean isValidInputParameters(String propertyName, String literal, double distance) { boolean isValid = isValidInputParameters(propertyName, literal); if (Double.valueOf(distance) < 0) { isValid = false; } return isValid; } private boolean isValidInputParameters(String propertyName, Object lowerBoundary, Object upperBoundary) { if (lowerBoundary == null || upperBoundary == null) { return false; } if (StringUtils.isEmpty(propertyName) || StringUtils.isEmpty(lowerBoundary.toString()) || StringUtils.isEmpty(upperBoundary.toString())) { return false; } return true; } private DateTime convertDateToIso8601Format(Date inputDate) { return new DateTime(inputDate); } // spatial operators @Override public FilterType beyond(String propertyName, String wkt, double distance) { if (!isEpsg4326) { return null; } if (!isValidInputParameters(propertyName, wkt, distance)) { throw new IllegalArgumentException(MISSING_PARAMETERS_MSG); } if (supportedGeo.contains(SPATIAL_OPERATORS.Beyond.getValue())) { return buildGeospatialFilterType(SPATIAL_OPERATORS.Beyond.toString(), propertyName, wkt, distance); } else if (supportedGeo.contains(SPATIAL_OPERATORS.DWithin.getValue())) { return not(dwithin(propertyName, wkt, distance)); } else { LOGGER.debug("WFS Source does not support Beyond filters"); return null; } } @Override public FilterType contains(String propertyName, String wkt) { if (!isEpsg4326) { return null; } if (!isValidInputParameters(propertyName, wkt)) { throw new IllegalArgumentException(MISSING_PARAMETERS_MSG); } if (supportedGeo.contains(SPATIAL_OPERATORS.Contains.getValue())) { return buildGeospatialFilterType(SPATIAL_OPERATORS.Contains.toString(), propertyName, wkt, null); } else if (supportedGeo.contains(SPATIAL_OPERATORS.Within.getValue())) { return not(within(propertyName, wkt)); } else { LOGGER.debug("WFS Source does not support Contains filters"); return null; } } @Override public FilterType crosses(String propertyName, String wkt) { if (!isEpsg4326) { return null; } if (!isValidInputParameters(propertyName, wkt)) { throw new IllegalArgumentException(MISSING_PARAMETERS_MSG); } if (supportedGeo.contains(SPATIAL_OPERATORS.Crosses.getValue())) { return buildGeospatialFilterType(SPATIAL_OPERATORS.Crosses.toString(), propertyName, wkt, null); } else { LOGGER.debug("WFS Source does not support Crosses filters"); return null; } } @Override public FilterType disjoint(String propertyName, String wkt) { if (!isEpsg4326) { return null; } if (!isValidInputParameters(propertyName, wkt)) { throw new IllegalArgumentException(MISSING_PARAMETERS_MSG); } if (supportedGeo.contains(SPATIAL_OPERATORS.Disjoint.getValue())) { return buildGeospatialFilterType(SPATIAL_OPERATORS.Disjoint.toString(), propertyName, wkt, null); } else if (supportedGeo.contains(SPATIAL_OPERATORS.BBOX.getValue())) { return not(bbox(propertyName, wkt)); } else if (supportedGeo.contains(SPATIAL_OPERATORS.Intersect.getValue())) { return not(intersects(propertyName, wkt)); } else { LOGGER.debug("WFS Source does not support Disjoint or BBOX filters"); return null; } } @Override public FilterType dwithin(String propertyName, String wkt, double distance) { if (!isEpsg4326) { return null; } if (!isValidInputParameters(propertyName, wkt, distance)) { throw new IllegalArgumentException(MISSING_PARAMETERS_MSG); } if (supportedGeo.contains(SPATIAL_OPERATORS.DWithin.getValue())) { return this .buildGeospatialFilterType(SPATIAL_OPERATORS.DWithin.toString(), propertyName, wkt, distance); } else if (supportedGeo.contains(SPATIAL_OPERATORS.Beyond.getValue())) { return not(beyond(propertyName, wkt, distance)); } else if (supportedGeo.contains(SPATIAL_OPERATORS.Intersect.getValue())) { String bufferedWkt = bufferGeometry(wkt, distance); return intersects(propertyName, bufferedWkt); } else { LOGGER.debug( "WFS Source does not support the DWithin filter or any of its fallback filters (Not Beyond or Intersects)."); return null; } } @Override public FilterType intersects(String propertyName, String wkt) { if (!isEpsg4326) { return null; } if (!isValidInputParameters(propertyName, wkt)) { throw new IllegalArgumentException(MISSING_PARAMETERS_MSG); } if (supportedGeo.contains(SPATIAL_OPERATORS.Intersect.getValue())) { return buildGeospatialFilterType(SPATIAL_OPERATORS.Intersect.toString(), propertyName, wkt, null); } else if (supportedGeo.contains(SPATIAL_OPERATORS.BBOX.getValue())) { return bbox(propertyName, wkt); } else if (supportedGeo.contains(SPATIAL_OPERATORS.Disjoint.getValue())) { return not(disjoint(propertyName, wkt)); } else { LOGGER.debug("WFS Source does not support Intersect or BBOX"); return null; } } @Override public FilterType overlaps(String propertyName, String wkt) { if (!isEpsg4326) { return null; } if (!isValidInputParameters(propertyName, wkt)) { throw new IllegalArgumentException(MISSING_PARAMETERS_MSG); } if (supportedGeo.contains(SPATIAL_OPERATORS.Overlaps.getValue())) { return buildGeospatialFilterType(SPATIAL_OPERATORS.Overlaps.toString(), propertyName, wkt, null); } else { LOGGER.debug("WFS Source does not support Overlaps filters"); return null; } } @Override public FilterType touches(String propertyName, String wkt) { if (!isEpsg4326) { return null; } if (!isValidInputParameters(propertyName, wkt)) { throw new IllegalArgumentException(MISSING_PARAMETERS_MSG); } if (supportedGeo.contains(SPATIAL_OPERATORS.Touches.getValue())) { return buildGeospatialFilterType(SPATIAL_OPERATORS.Touches.toString(), propertyName, wkt, null); } else { LOGGER.debug("WFS Source does not support Beyond filters"); return null; } } @Override public FilterType within(String propertyName, String wkt) { if (!isEpsg4326) { return null; } if (!isValidInputParameters(propertyName, wkt)) { throw new IllegalArgumentException(MISSING_PARAMETERS_MSG); } if (supportedGeo.contains(SPATIAL_OPERATORS.Within.getValue())) { return buildGeospatialFilterType(SPATIAL_OPERATORS.Within.toString(), propertyName, wkt, null); } else if (supportedGeo.contains(SPATIAL_OPERATORS.Contains.getValue())) { return not(within(propertyName, wkt)); } else { LOGGER.debug("WFS Source does not support Within filters"); return null; } } private FilterType bbox(String propertyName, String wkt) { if (!isEpsg4326) { return null; } if (!isValidInputParameters(propertyName, wkt)) { throw new IllegalArgumentException(MISSING_PARAMETERS_MSG); } if (supportedGeo.contains(SPATIAL_OPERATORS.BBOX.getValue())) { return buildGeospatialFilterType(SPATIAL_OPERATORS.BBOX.toString(), propertyName, wkt, null); } else { LOGGER.debug("WFS Source does not support BBOX filters"); return null; } } private FilterType buildGeospatialFilterType(String spatialOpType, String propertyName, String wkt, Double distance) { FilterType returnFilter = new FilterType(); if (Metacard.ANY_GEO.equals(propertyName)) { if (CollectionUtils.isEmpty(featureMetacardType.getGmlProperties())) { LOGGER.debug("Feature Type does not have GEO properties to query"); return null; } if (featureMetacardType.getGmlProperties().size() == 1) { FeatureAttributeDescriptor attrDesc = (FeatureAttributeDescriptor) featureMetacardType .getAttributeDescriptor(featureMetacardType.getGmlProperties().get(0)); if (attrDesc != null && attrDesc.isIndexed()) { returnFilter.setSpatialOps( createSpatialOpType(spatialOpType, attrDesc.getPropertyName(), wkt, distance)); } else { LOGGER.debug("All GEO properties have been blacklisted. Removing from query"); return null; } } else { List<FilterType> filtersToBeOred = new ArrayList<FilterType>(); for (String property : featureMetacardType.getGmlProperties()) { FeatureAttributeDescriptor attrDesc = (FeatureAttributeDescriptor) featureMetacardType .getAttributeDescriptor(property); if (attrDesc != null && attrDesc.isIndexed()) { FilterType filter = new FilterType(); filter.setSpatialOps( createSpatialOpType(spatialOpType, attrDesc.getPropertyName(), wkt, distance)); filtersToBeOred.add(filter); } else { LOGGER.debug(String.format(PROPERTY_NOT_QUERYABLE, property)); } } if (!filtersToBeOred.isEmpty()) { returnFilter = or(filtersToBeOred); } else { LOGGER.debug("All GEO properties have been blacklisted. Removing from query."); returnFilter = null; } } } else if (featureMetacardType.getGmlProperties().contains(propertyName)) { FeatureAttributeDescriptor attrDesc = (FeatureAttributeDescriptor) featureMetacardType .getAttributeDescriptor(propertyName); if (attrDesc != null && attrDesc.isIndexed()) { FilterType filter = new FilterType(); filter.setSpatialOps( createSpatialOpType(spatialOpType, attrDesc.getPropertyName(), wkt, distance)); return filter; } else { // blacklisted property encountered throw new IllegalArgumentException( String.format(PROPERTY_NOT_QUERYABLE, propertyName)); } } else { return null; } return returnFilter; } private JAXBElement<? extends SpatialOpsType> createSpatialOpType(String operation, String propertyName, String wkt, Double distance) { switch (SPATIAL_OPERATORS.valueOf(operation)) { case BBOX: return buildBBoxType(propertyName, wkt); case Beyond: return buildDistanceBufferType( filterObjectFactory.createBeyond(new DistanceBufferType()), propertyName, wkt, distance); case Contains: return buildBinarySpatialOpType( filterObjectFactory.createContains(new BinarySpatialOpType()), propertyName, wkt); case Crosses: return buildBinarySpatialOpType( filterObjectFactory.createCrosses(new BinarySpatialOpType()), propertyName, wkt); case Disjoint: return buildBinarySpatialOpType( filterObjectFactory.createDisjoint(new BinarySpatialOpType()), propertyName, wkt); case DWithin: return buildDistanceBufferType( filterObjectFactory.createDWithin(new DistanceBufferType()), propertyName, wkt, distance); case Intersect: return buildBinarySpatialOpType( filterObjectFactory.createIntersects(new BinarySpatialOpType()), propertyName, wkt); case Overlaps: return buildBinarySpatialOpType( filterObjectFactory.createOverlaps(new BinarySpatialOpType()), propertyName, wkt); case Touches: return buildBinarySpatialOpType( filterObjectFactory.createTouches(new BinarySpatialOpType()), propertyName, wkt); case Within: return buildBinarySpatialOpType( filterObjectFactory.createWithin(new BinarySpatialOpType()), propertyName, wkt); default: throw new UnsupportedOperationException( "Unsupported geospatial filter type " + SPATIAL_OPERATORS.valueOf(operation) + " specified"); } } private JAXBElement<BinarySpatialOpType> buildBinarySpatialOpType( JAXBElement<BinarySpatialOpType> bsot, String propertyName, String wkt) { bsot.getValue().setPropertyName(createPropertyNameType(propertyName).getValue()); bsot.getValue().setGeometry(createGeometryOperand(wkt)); return bsot; } private JAXBElement<DistanceBufferType> buildDistanceBufferType( JAXBElement<DistanceBufferType> dbt, String propertyName, String wkt, double distance) { DistanceType distanceType = new DistanceType(); distanceType.setContent(Double.toString(distance)); // the filter adapter normalizes all distances to meters distanceType.setUnits(WfsConstants.METERS); dbt.getValue().setDistance(distanceType); dbt.getValue().setGeometry(createPoint(wkt)); dbt.getValue().setPropertyName(createPropertyNameType(propertyName).getValue()); return dbt; } private JAXBElement<BBOXType> buildBBoxType(String propertyName, String wkt) { BBOXType bboxType = new BBOXType(); JAXBElement<BoxType> box = createBoxType(wkt); bboxType.setBox(box.getValue()); bboxType.setPropertyName(createPropertyNameType(propertyName).getValue()); return filterObjectFactory.createBBOX(bboxType); } private JAXBElement<BoxType> createBoxType(String wkt) { BoxType box = new BoxType(); box.setSrsName(srsName); box.setCoordinates(createCoordinatesTypeFromWkt(wkt).getValue()); return gmlObjectFactory.createBox(box); } private JAXBElement<PolygonType> createPolygon(String wkt) { PolygonType polygon = new PolygonType(); LinearRingType linearRing = new LinearRingType(); Coordinate[] coordinates = getCoordinatesFromWkt(wkt); if (coordinates != null && coordinates.length > 0) { StringBuffer coordString = new StringBuffer(); for (Coordinate coordinate : coordinates) { coordString.append(coordinate.x).append(",").append(coordinate.y).append(" "); } CoordinatesType coordinatesType = new CoordinatesType(); coordinatesType.setValue(coordString.toString()); coordinatesType.setDecimal("."); coordinatesType.setCs(","); coordinatesType.setTs(" "); linearRing.setCoordinates(coordinatesType); LinearRingMemberType member = new LinearRingMemberType(); member.setGeometry(gmlObjectFactory.createLinearRing(linearRing)); polygon.setOuterBoundaryIs(member); polygon.setSrsName(srsName); return gmlObjectFactory.createPolygon(polygon); } else { throw new IllegalArgumentException( "Unable to parse Polygon coordinates from WKT String"); } } private JAXBElement<PointType> createPoint(String wkt) { Coordinate[] coordinates = getCoordinatesFromWkt(wkt); if (coordinates != null && coordinates.length > 0) { StringBuilder coordString = new StringBuilder(); coordString.append(coordinates[0].x).append(",").append(coordinates[0].y); CoordinatesType coordinatesType = new CoordinatesType(); coordinatesType.setValue(coordString.toString()); PointType point = new PointType(); point.setSrsName(srsName); point.setCoordinates(coordinatesType); return gmlObjectFactory.createPoint(point); } else { throw new IllegalArgumentException("Unable to parse Point coordinates from WKT String"); } } private String buildCoordinateString(Envelope envelope) { StringBuilder sb = new StringBuilder(); sb.append(envelope.getMinX()).append(",").append(envelope.getMinY()).append(" ") .append(envelope.getMaxX()).append(",").append(envelope.getMaxY()); return sb.toString(); } private JAXBElement<CoordinatesType> createCoordinatesTypeFromWkt(String wkt) { Envelope envelope = createEnvelopeFromWkt(wkt); String coords = buildCoordinateString(envelope); CoordinatesType coordinatesType = new CoordinatesType(); coordinatesType.setValue(coords); return gmlObjectFactory.createCoordinates(coordinatesType); } private JAXBElement<LiteralType> createLiteralType(Object literalValue) { JAXBElement<LiteralType> literalType = filterObjectFactory.createLiteral(new LiteralType()); literalType.getValue().getContent().add(literalValue.toString()); return literalType; } private JAXBElement<PropertyNameType> createPropertyNameType(String propertyNameValue) { JAXBElement<PropertyNameType> propertyNameType = filterObjectFactory .createPropertyName(new PropertyNameType()); propertyNameType.getValue().setContent(propertyNameValue); return propertyNameType; } private LowerBoundaryType createLowerBoundary(Object lowerBoundary) { LowerBoundaryType lowerBoundaryType = new LowerBoundaryType(); lowerBoundaryType.setExpression(createLiteralType(lowerBoundary)); return lowerBoundaryType; } private UpperBoundaryType createUpperBoundary(Object upperBoundary) { UpperBoundaryType upperBoundaryType = new UpperBoundaryType(); upperBoundaryType.setExpression(createLiteralType(upperBoundary)); return upperBoundaryType; } private Envelope createEnvelopeFromWkt(String wkt) { Envelope envelope = null; try { Geometry geo = getGeometryFromWkt(wkt); envelope = geo.getEnvelopeInternal(); } catch (ParseException e) { throw new IllegalArgumentException("Unable to parse WKT String", e); } return envelope; } private Coordinate[] getCoordinatesFromWkt(String wkt) { Coordinate[] coordinates = null; try { Geometry geo = getGeometryFromWkt(wkt); coordinates = geo.getCoordinates(); } catch (ParseException e) { throw new IllegalArgumentException("Unable to parse WKT String", e); } return coordinates; } private Geometry getGeometryFromWkt(String wkt) throws ParseException { return new WKTReader().read(wkt); } private String bufferGeometry(String wkt, double distance) { LOGGER.debug("Buffering WKT {} by distance {} meter(s).", wkt, distance); String bufferedWkt = null; try { Geometry geometry = getGeometryFromWkt(wkt); double bufferInDegrees = metersToDegrees(distance); LOGGER.debug("Buffering {} by {} degree(s).", geometry.getClass().getSimpleName(), bufferInDegrees); Geometry bufferedGeometry = geometry.buffer(bufferInDegrees); bufferedWkt = new WKTWriter().write(bufferedGeometry); LOGGER.debug("Buffered WKT: {}.", bufferedWkt); } catch (ParseException e) { throw new IllegalArgumentException("Unable to parse WKT String", e); } 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 / WfsConstants.EARTH_MEAN_RADIUS_METERS) * WfsConstants.RADIANS_TO_DEGREES; LOGGER.debug("{} meter(s) is approximately {} degree(s) of latitude.", distance, degrees); return degrees; } private JAXBElement<LineStringType> createLineString(Geometry geometry) { JAXBElement<LineStringType> jaxbElement = null; try { String gml = Wfs10JTStoGML200Converter.convertGeometryToGML(geometry); LineStringType lineStringType = (LineStringType) Wfs10JTStoGML200Converter .convertGMLToGeometryType(gml, Wfs10Constants.LINESTRING); jaxbElement = (JAXBElement<LineStringType>) Wfs10JTStoGML200Converter .convertGeometryTypeToJAXB(lineStringType); } catch (JAXBException jbe) { LOGGER.error("Unable to create LineString with geometry: [{}]", geometry); } return jaxbElement; } private JAXBElement<MultiPointType> createMultiPoint(Geometry geometry) { JAXBElement<MultiPointType> jaxbElement = null; try { String gml = Wfs10JTStoGML200Converter.convertGeometryToGML(geometry); MultiPointType multiPointType = (MultiPointType) Wfs10JTStoGML200Converter .convertGMLToGeometryType(gml, Wfs10Constants.POINT); jaxbElement = (JAXBElement<MultiPointType>) Wfs10JTStoGML200Converter .convertGeometryTypeToJAXB(multiPointType); } catch (JAXBException jbe) { LOGGER.error("Unable to create MultiPointType with geometry: [{}]", geometry); } return jaxbElement; } private JAXBElement<MultiLineStringType> createMultiLineString(Geometry geometry) { JAXBElement<MultiLineStringType> jaxbElement = null; try { String gml = Wfs10JTStoGML200Converter.convertGeometryToGML(geometry); MultiLineStringType multiLineStringType = (MultiLineStringType) Wfs10JTStoGML200Converter .convertGMLToGeometryType(gml, Wfs10Constants.MULTI_LINESTRING); jaxbElement = (JAXBElement<MultiLineStringType>) Wfs10JTStoGML200Converter .convertGeometryTypeToJAXB(multiLineStringType); } catch (JAXBException jbe) { LOGGER.error("Unable to create MultiLineStringType with geometry: [{}]", geometry); } return jaxbElement; } private JAXBElement<MultiPolygonType> createMultiPolygon(Geometry geometry) { JAXBElement<MultiPolygonType> jaxbElement = null; try { String gml = Wfs10JTStoGML200Converter.convertGeometryToGML(geometry); MultiLineStringType multiLineStringType = (MultiLineStringType) Wfs10JTStoGML200Converter .convertGMLToGeometryType(gml, Wfs10Constants.MULTI_LINESTRING); jaxbElement = (JAXBElement<MultiPolygonType>) Wfs10JTStoGML200Converter .convertGeometryTypeToJAXB(multiLineStringType); } catch (JAXBException jbe) { LOGGER.error("Unable to create MultiPolygonType with geometry: [{}]", geometry); } return jaxbElement; } private JAXBElement<GeometryCollectionType> createGeometryCollection(Geometry geometry) { JAXBElement<GeometryCollectionType> jaxbElement = null; try { String gml = Wfs10JTStoGML200Converter.convertGeometryToGML(geometry); GeometryCollectionType geometryCollectionType = (GeometryCollectionType) Wfs10JTStoGML200Converter .convertGMLToGeometryType(gml, Wfs10Constants.GEOMETRY_COLLECTION); jaxbElement = (JAXBElement<GeometryCollectionType>) Wfs10JTStoGML200Converter .convertGeometryTypeToJAXB(geometryCollectionType); } catch (JAXBException jbe) { LOGGER.error("Unable to create MultiPolygonType with geometry: [{}]", geometry); } return jaxbElement; } private JAXBElement<? extends AbstractGeometryType> createGeometryOperand(String wkt) { String convertedWkt = wkt; Geometry wktGeometry = null; try { wktGeometry = getGeometryFromWkt(convertedWkt); } catch (ParseException e) { throw new IllegalArgumentException( "Unable to parse WKT Geometry [" + convertedWkt + "]", e); } if (wktGeometry instanceof Polygon) { if (isGeometryOperandSupported(Wfs10Constants.POLYGON)) { return createPolygon(convertedWkt); } else { throw new IllegalArgumentException("The Polygon operand is not supported."); } } else if (wktGeometry instanceof Point) { if (isGeometryOperandSupported(Wfs10Constants.POINT)) { return createPoint(convertedWkt); } else { throw new IllegalArgumentException("The Point operand is not supported."); } } else if (wktGeometry instanceof LineString) { if (isGeometryOperandSupported(Wfs10Constants.LINESTRING)) { return createLineString(wktGeometry); } else { throw new IllegalArgumentException("The LineString operand is not supported."); } } else if (wktGeometry instanceof MultiPoint) { if (isGeometryOperandSupported(Wfs10Constants.MULTI_POINT)) { return createMultiPoint(wktGeometry); } else { throw new IllegalArgumentException("The MultiPoint operand is not supported."); } } else if (wktGeometry instanceof MultiLineString) { if (isGeometryOperandSupported(Wfs10Constants.MULTI_LINESTRING)) { return createMultiLineString(wktGeometry); } else { throw new IllegalArgumentException("The MultiLineString operand is not supported."); } } else if (wktGeometry instanceof MultiPolygon) { if (isGeometryOperandSupported(Wfs10Constants.MULTI_POLYGON)) { return createMultiPolygon(wktGeometry); } else { throw new IllegalArgumentException("The MultiPolygon operand is not supported."); } } else if (wktGeometry instanceof GeometryCollection) { if (isGeometryOperandSupported(Wfs10Constants.GEOMETRY_COLLECTION)) { return createGeometryCollection(wktGeometry); } else { throw new IllegalArgumentException( "The GeometryCollection operand is not supported."); } } throw new IllegalArgumentException("Unable to create Geometry from WKT String"); } private static enum PROPERTY_IS_OPS { PropertyIsEqualTo, PropertyIsLike, PropertyIsNotEqualTo, PropertyIsGreaterThan, PropertyIsGreaterThanOrEqualTo, PropertyIsLessThan, PropertyIsLessThanOrEqualTo; } }