/* * Constellation - An open source and standard compliant SDI * http://www.constellation-sdi.org * * Copyright 2014 Geomatys. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.constellation.filter; import com.vividsolutions.jts.geom.Geometry; import org.apache.lucene.search.Filter; import org.apache.sis.util.logging.Logging; import org.geotoolkit.cql.CQL; import org.geotoolkit.cql.CQLException; import org.geotoolkit.csw.xml.QueryConstraint; import org.geotoolkit.factory.FactoryFinder; import org.geotoolkit.factory.Hints; import org.geotoolkit.filter.FilterFactoryImpl; import org.geotoolkit.filter.SpatialFilterType; import org.geotoolkit.geometry.jts.SRIDGenerator; import org.geotoolkit.geometry.jts.SRIDGenerator.Version; import org.geotoolkit.gml.GeometrytoJTS; import org.geotoolkit.gml.xml.AbstractGeometry; import org.geotoolkit.gml.xml.Envelope; import org.geotoolkit.gml.xml.LineString; import org.geotoolkit.gml.xml.Point; import org.geotoolkit.gml.xml.Polygon; import org.geotoolkit.lucene.filter.LuceneOGCFilter; import org.geotoolkit.lucene.filter.SerialChainFilter; import org.geotoolkit.ogc.xml.v110.AbstractIdType; import org.geotoolkit.ogc.xml.v110.BBOXType; import org.geotoolkit.ogc.xml.v110.BinaryComparisonOpType; import org.geotoolkit.ogc.xml.v110.ComparisonOpsType; import org.geotoolkit.ogc.xml.v110.FilterType; import org.geotoolkit.ogc.xml.v110.LogicOpsType; import org.geotoolkit.ogc.xml.v110.LowerBoundaryType; import org.geotoolkit.ogc.xml.v110.PropertyIsBetweenType; import org.geotoolkit.ogc.xml.v110.SpatialOpsType; import org.geotoolkit.ogc.xml.v110.TemporalOpsType; import org.geotoolkit.ogc.xml.v110.UpperBoundaryType; import org.opengis.filter.BinaryComparisonOperator; import org.opengis.filter.FilterFactory2; import org.opengis.filter.PropertyIsEqualTo; import org.opengis.filter.PropertyIsGreaterThan; import org.opengis.filter.PropertyIsGreaterThanOrEqualTo; import org.opengis.filter.PropertyIsLessThan; import org.opengis.filter.PropertyIsLessThanOrEqualTo; import org.opengis.filter.PropertyIsLike; import org.opengis.filter.PropertyIsNotEqualTo; import org.opengis.filter.PropertyIsNull; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.Literal; import org.opengis.filter.expression.PropertyName; import org.opengis.filter.spatial.BinarySpatialOperator; import org.opengis.filter.spatial.DistanceBufferOperator; import org.opengis.filter.temporal.After; import org.opengis.filter.temporal.Before; import org.opengis.filter.temporal.BinaryTemporalOperator; import org.opengis.filter.temporal.During; import org.opengis.filter.temporal.TEquals; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.util.FactoryException; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.namespace.QName; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import static org.geotoolkit.lucene.filter.LuceneOGCFilter.GEOMETRY_PROPERTY; import static org.geotoolkit.lucene.filter.LuceneOGCFilter.wrap; import static org.geotoolkit.ogc.xml.FilterXmlFactory.buildPropertyIsEquals; import static org.geotoolkit.ogc.xml.FilterXmlFactory.buildPropertyIsGreaterThan; import static org.geotoolkit.ogc.xml.FilterXmlFactory.buildPropertyIsGreaterThanOrEqualTo; import static org.geotoolkit.ogc.xml.FilterXmlFactory.buildPropertyIsLessThan; import static org.geotoolkit.ogc.xml.FilterXmlFactory.buildPropertyIsLessThanOrEqualTo; import static org.geotoolkit.ogc.xml.FilterXmlFactory.buildPropertyIsNotEquals; import static org.geotoolkit.ows.xml.OWSExceptionCode.INVALID_PARAMETER_VALUE; import static org.geotoolkit.ows.xml.OWSExceptionCode.NO_APPLICABLE_CODE; import static org.geotoolkit.ows.xml.OWSExceptionCode.OPERATION_NOT_SUPPORTED; // JAXB dependencies // Apache Lucene dependencies // Geotoolkit dependencies // GeoAPI dependencies // JTS dependencies /** * Abstract class used to parse OGC filter and transform them into the specific implementation filter language. * * @author Guilhem Legal (Geomatys) */ public abstract class FilterParser { protected static final String QUERY_CONSTRAINT = "QueryConstraint"; protected static final FilterFactory2 FF = (FilterFactory2) FactoryFinder.getFilterFactory(new Hints(Hints.FILTER_FACTORY,FilterFactory2.class)); /** * use for debugging purpose */ protected static final Logger LOGGER = Logging.getLogger("org.constellation.metadata"); protected static final String PARSE_ERROR_MSG = "The service was unable to parse the Date: "; protected static final String UNKNOW_CRS_ERROR_MSG = "Unknow Coordinate Reference System: "; protected static final String INCORRECT_BBOX_DIM_ERROR_MSG = "The dimensions of the bounding box are incorrect: "; protected static final String FACTORY_BBOX_ERROR_MSG = "Factory exception while parsing spatial filter BBox: "; /** * Build a Filter with the specified CQL query * * @param cqlQuery A well-formed CQL query . */ public static FilterType cqlToFilter(final String cqlQuery) throws CQLException, JAXBException { final FilterType result; final Object newFilter = CQL.parseFilter(cqlQuery, new FilterFactoryImpl()); if (!(newFilter instanceof FilterType)) { result = new FilterType(newFilter); } else { result = (FilterType) newFilter; } return result; } /** * Build a CQL query with the specified Filter. * * @param filter A well-formed Filter . */ public static String filterToCql(final FilterType filter) throws CQLException, JAXBException { return CQL.write(filter); } /** * Build a request from the specified constraint * * @param constraint a constraint expressed in CQL or FilterType */ public Object getQuery(final QueryConstraint constraint, final Map<String, QName> variables, final Map<String, String> prefixs, final List<QName> typeNames) throws FilterParserException { //if the constraint is null we make a null filter if (constraint == null) { return getNullFilter(typeNames); } else { final FilterType filter = getFilterFromConstraint(constraint); return getQuery(filter, variables, prefixs, typeNames); } } /** * Return a filter matching for all the records. * * @return a filter matching for all the records. */ protected abstract Object getNullFilter(final List<QName> typeNames); protected abstract Object getQuery(final FilterType constraint, final Map<String, QName> variables, final Map<String, String> prefixs, final List<QName> typeNames) throws FilterParserException; /** * Build a piece of query with the specified logical filter. * * @param jbLogicOps A logical filter. * @return * @throws FilterParserException */ protected abstract Object treatLogicalOperator(final JAXBElement<? extends LogicOpsType> jbLogicOps) throws FilterParserException; /** * Build a piece of query with the specified Comparison filter. * * @param jbComparisonOps A comparison filter. * @return * @throws org.constellation.coverage.web.FilterParserException */ protected String treatComparisonOperator(final ComparisonOpsType comparisonOps) throws FilterParserException { final StringBuilder response = new StringBuilder(); if (comparisonOps instanceof PropertyIsLike ) { final PropertyIsLike pil = (PropertyIsLike) comparisonOps; final PropertyName propertyName; //we get the field if (pil.getExpression() != null && pil.getLiteral() != null) { propertyName = (PropertyName) pil.getExpression(); } else { throw new FilterParserException("An operator propertyIsLike must specified the propertyName and a literal value.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } //we format the value by replacing the specified special char by the lucene special char final String brutValue = translateSpecialChar(pil); addComparisonFilter(response, propertyName, brutValue, "LIKE"); } else if (comparisonOps instanceof PropertyIsNull) { final PropertyIsNull pin = (PropertyIsNull) comparisonOps; //we get the field if (pin.getExpression() != null) { addComparisonFilter(response, (PropertyName) pin.getExpression(), null, "IS NULL "); } else { throw new FilterParserException("An operator propertyIsNull must specified the propertyName.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } } else if (comparisonOps instanceof PropertyIsBetweenType) { final PropertyIsBetweenType pib = (PropertyIsBetweenType) comparisonOps; final PropertyName propertyName = (PropertyName) pib.getExpression(); final LowerBoundaryType low = pib.getLowerBoundary(); Literal lowLit = null; if (low != null) { lowLit = low.getLiteral(); } final UpperBoundaryType upp = pib.getUpperBoundary(); Literal uppLit = null; if (upp != null) { uppLit = upp.getLiteral(); } if (propertyName == null || lowLit == null || uppLit == null) { throw new FilterParserException("A PropertyIsBetween operator must be constitued of a lower boundary containing a literal, " + "an upper boundary containing a literal and a property name.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } else { addComparisonFilter(response, propertyName, (String)lowLit.getValue(), ">="); addComparisonFilter(response, propertyName, (String)uppLit.getValue(), "<="); } } else if (comparisonOps instanceof BinaryComparisonOperator) { final BinaryComparisonOperator bc = (BinaryComparisonOperator) comparisonOps; final PropertyName propertyName = (PropertyName) bc.getExpression1(); final Literal literal = (Literal) bc.getExpression2(); if (propertyName == null || literal == null) { throw new FilterParserException("A binary comparison operator must be constitued of a literal and a property name.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } else { final Object literalValue = literal.getValue(); if (bc instanceof PropertyIsEqualTo) { addComparisonFilter(response, propertyName, literalValue, "="); } else if (bc instanceof PropertyIsNotEqualTo) { addComparisonFilter(response, propertyName, literalValue, "!="); } else if (bc instanceof PropertyIsGreaterThanOrEqualTo) { addComparisonFilter(response, propertyName, literalValue, ">="); } else if (bc instanceof PropertyIsGreaterThan) { addComparisonFilter(response, propertyName, literalValue, ">"); } else if (bc instanceof PropertyIsLessThan) { addComparisonFilter(response, propertyName, literalValue, "<"); } else if (bc instanceof PropertyIsLessThanOrEqualTo) { addComparisonFilter(response, propertyName, literalValue, "<="); } else { final String operator = bc.getClass().getSimpleName(); throw new FilterParserException("Unkwnow comparison operator: " + operator, INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } } } return response.toString(); } /** * Build a piece of query with the specified Comparison filter. * * @param jbComparisonOps A comparison filter. * @return * @throws org.constellation.coverage.web.FilterParserException */ protected String treatTemporalOperator(final TemporalOpsType temporalOps) throws FilterParserException { final StringBuilder response = new StringBuilder(); if (temporalOps instanceof BinaryTemporalOperator) { final BinaryTemporalOperator bc = (BinaryTemporalOperator) temporalOps; final PropertyName propertyName = (PropertyName) bc.getExpression1(); final Literal literal = (Literal) bc.getExpression2(); if (propertyName == null || literal == null) { throw new FilterParserException("A binary temporal operator must be constitued of a TimeObject and a property name.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } else { final Object literalValue = literal.getValue(); if (bc instanceof TEquals) { addComparisonFilter(response, propertyName, literalValue, "="); } else if (bc instanceof After) { addComparisonFilter(response, propertyName, literalValue, ">"); } else if (bc instanceof Before) { addComparisonFilter(response, propertyName, literalValue, "<"); } else if (bc instanceof During) { throw new FilterParserException("TODO during", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } else { final String operator = bc.getClass().getSimpleName(); throw new FilterParserException("Unsupported temporal operator: " + operator, INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } } } return response.toString(); } /** * Add to the StringBuilder a piece of query with the specified operator. * * @param response A stringBuilder containing the query. * @param propertyName The name of the property to filter. * @param literalValue The value of the filter. * @param operator The comparison operator. * * @throws FilterParserException */ protected abstract void addComparisonFilter(final StringBuilder response, final PropertyName propertyName, final Object literalValue, final String operator) throws FilterParserException; /** * Extract and format a date representation from the specified String. * If the string is not a well formed date it will raise an exception. * * @param literal A Date representation. * @return A formatted date representation. * @throws FilterParserException if the specified string can not be parsed. */ protected abstract String extractDateValue(final Object literal) throws FilterParserException; /** * Replace The special character in a literal value for a propertyIsLike filter, * with the implementation specific value. * * @param pil A propertyIsLike filter. * @param wildchar The character replacing the filter wildChar. * @param SingleChar The character replacing the filter singleChar. * @param escapeChar The character replacing the filter escapeChar. * * @return A formatted value. */ protected String translateSpecialChar(final PropertyIsLike pil, final String wildchar, final String singleChar, final String escapeChar) { String brutValue = pil.getLiteral(); brutValue = brutValue.replace(pil.getWildCard(), wildchar); brutValue = brutValue.replace(pil.getSingleChar(), singleChar); brutValue = brutValue.replace(pil.getEscape(), escapeChar); //for a date we remove the '-' if (isDateField((PropertyName) pil.getExpression())) { brutValue = brutValue.replaceAll("-", ""); brutValue = brutValue.replace("Z", ""); } return brutValue; } /** * Replace The special character in a literal value for a propertyIsLike filter. * * @param pil propertyIsLike filter. * @return A formatted value. */ protected abstract String translateSpecialChar(final PropertyIsLike pil); /** * Return a piece of query for An Id filter. * * @param jbIdsOps an Id filter * @return a piece of query. */ protected String treatIDOperator(final List<JAXBElement<? extends AbstractIdType>> jbIdsOps) { //TODO if (true) { throw new UnsupportedOperationException("Not supported yet."); } return ""; } /** * Extract a OCG filter from the query constraint of the received request. * * @param constraint * @return * @throws FilterParserException */ protected FilterType getFilterFromConstraint(final QueryConstraint constraint) throws FilterParserException { //The null case must be trreated before calling this method if (constraint == null) { throw new IllegalArgumentException("The null case must be already treated!"); // both constraint type are filled we throw an exception } else if (constraint.getCqlText() != null && constraint.getFilter() != null) { throw new FilterParserException("The query constraint must be in Filter or CQL but not both.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); // none constraint type are filled we throw an exception } else if ((constraint.getCqlText() == null || constraint.getCqlText().isEmpty()) && constraint.getFilter() == null) { throw new FilterParserException("The query constraint must contain a Filter or a CQL query (not empty).", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); // for a CQL request we transform it in Filter } else if (constraint.getCqlText() != null) { try { return cqlToFilter(constraint.getCqlText()); } catch (JAXBException ex) { LOGGER.log(Level.SEVERE, ex.getMessage(), ex); throw new FilterParserException("JAXBException while parsing CQL query: " + ex.getMessage(), NO_APPLICABLE_CODE, QUERY_CONSTRAINT); } catch (CQLException ex) { throw new FilterParserException("The CQL query is malformed: " + ex.getMessage(), INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } catch (UnsupportedOperationException ex) { throw new FilterParserException("The CQL query is not supported: " + ex.getMessage(), INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } // for a filter we return directly it } else { return constraint.getFilter(); } } /** * Return A single Filter concatening the list of specified Filter. * * @param logicalOperand A logical operator. * @param filters A List of lucene filter. * * @return A single Filter. */ protected Filter getSpatialFilterFromList(final int logicalOperand, final List<Filter> filters) { Filter spatialFilter = null; if (filters.size() == 1) { if (logicalOperand == SerialChainFilter.NOT) { final int[] filterType = {SerialChainFilter.NOT}; spatialFilter = new SerialChainFilter(filters, filterType); } else { spatialFilter = filters.get(0); } } else if (filters.size() > 1) { final int[] filterType = new int[filters.size() - 1]; for (int i = 0; i < filterType.length; i++) { filterType[i] = logicalOperand; } spatialFilter = new SerialChainFilter(filters, filterType); } return spatialFilter; } /** * Build a lucene Filter query with the specified Spatial filter. * * @param JBlogicOps a spatial filter. * @return * @throws org.constellation.coverage.web.FilterParserException */ protected Filter treatSpatialOperator(final JAXBElement<? extends SpatialOpsType> jbSpatialOps) throws FilterParserException { LuceneOGCFilter spatialfilter = null; final SpatialOpsType spatialOps = jbSpatialOps.getValue(); if (spatialOps instanceof BBOXType) { final BBOXType bbox = (BBOXType) spatialOps; final String propertyName = bbox.getPropertyName(); final String crsName = bbox.getSRS(); //we verify that all the parameters are specified if (propertyName == null) { throw new FilterParserException("An operator BBOX must specified the propertyName.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } else if (!propertyName.contains("BoundingBox")) { throw new FilterParserException("An operator the propertyName BBOX must be geometry valued. The property :" + propertyName + " is not.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } if (bbox.getEnvelope() == null && bbox.getEnvelopeWithTimePeriod() == null) { throw new FilterParserException("An operator BBOX must specified an envelope.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } if (crsName == null) { throw new FilterParserException("An operator BBOX must specified a CRS (coordinate Reference system) fot the envelope.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } //we transform the EnvelopeType in GeneralEnvelope spatialfilter = wrap(FF.bbox(GEOMETRY_PROPERTY, bbox.getMinX(), bbox.getMinY(),bbox.getMaxX(),bbox.getMaxY(),crsName)); } else if (spatialOps instanceof DistanceBufferOperator) { final DistanceBufferOperator dist = (DistanceBufferOperator) spatialOps; final double distance = dist.getDistance(); final String units = dist.getDistanceUnits(); final Expression geom = dist.getExpression2(); final String operator = jbSpatialOps.getName().getLocalPart(); //we verify that all the parameters are specified if (dist.getExpression1() == null) { throw new FilterParserException("An distanceBuffer operator must specified the propertyName.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } if (units == null) { throw new FilterParserException("An distanceBuffer operator must specified the ditance units.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } if (geom == null) { throw new FilterParserException("An distanceBuffer operator must specified a geometric object.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } Geometry geometry = null; //String propName = dist.getPropertyName().getPropertyName(); String crsName = null; // we transform the gml geometry in treatable geometry try { if (geom instanceof AbstractGeometry) { final Point gmlGeom = (Point) geom; crsName = gmlGeom.getSrsName(); geometry = GeometrytoJTS.toJTS(gmlGeom); } else if (geom instanceof Envelope) { final Envelope gmlEnvelope = (Envelope) geom; crsName = gmlEnvelope.getSrsName(); geometry = GeometrytoJTS.toJTS(gmlEnvelope); } if (geometry != null) { final int srid = SRIDGenerator.toSRID(crsName, Version.V1); geometry.setSRID(srid); } if ("DWithin".equals(operator)) { spatialfilter = wrap(FF.dwithin(GEOMETRY_PROPERTY,FF.literal(geometry),distance, units)); } else if ("Beyond".equals(operator)) { spatialfilter = wrap(FF.beyond(GEOMETRY_PROPERTY,FF.literal(geometry),distance, units)); } else { throw new FilterParserException("Unknow DistanceBuffer operator.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } } catch (NoSuchAuthorityCodeException e) { throw new FilterParserException(UNKNOW_CRS_ERROR_MSG + crsName, INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } catch (FactoryException e) { throw new FilterParserException(FACTORY_BBOX_ERROR_MSG + e.getMessage(), INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } catch (IllegalArgumentException e) { throw new FilterParserException(INCORRECT_BBOX_DIM_ERROR_MSG+ e.getMessage(), INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } } else if (spatialOps instanceof BinarySpatialOperator) { final BinarySpatialOperator binSpatial = (BinarySpatialOperator) spatialOps; String propertyName = null; String operator = jbSpatialOps.getName().getLocalPart(); operator = operator.toUpperCase(); Object gmlGeometry = null; // the propertyName if (binSpatial.getExpression1() != null) { propertyName = ((PropertyName)binSpatial.getExpression1()).getPropertyName(); } // geometric object: envelope if (binSpatial.getExpression2() instanceof Envelope) { gmlGeometry = binSpatial.getExpression2(); } if (binSpatial.getExpression2() instanceof AbstractGeometry) { final AbstractGeometry ab = (AbstractGeometry)binSpatial.getExpression2(); // supported geometric object: point, line, polygon : if (ab instanceof Point || ab instanceof LineString || ab instanceof Polygon) { gmlGeometry = ab; } else if (ab == null) { throw new IllegalArgumentException("null value in BinarySpatialOp type"); } else { throw new IllegalArgumentException("unknow BinarySpatialOp type:" + ab.getClass().getSimpleName()); } } if (propertyName == null && gmlGeometry == null) { throw new FilterParserException("An Binarary spatial operator must specified a propertyName and a geometry.", INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } SpatialFilterType filterType = null; try { filterType = SpatialFilterType.valueOf(operator); } catch (IllegalArgumentException ex) { LOGGER.severe("unknow spatial filter Type"); } if (filterType == null) { throw new FilterParserException("Unknow FilterType: " + operator, INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } String crsName = "undefined CRS"; try { Geometry filterGeometry = null; if (gmlGeometry instanceof Envelope) { //we transform the EnvelopeType in GeneralEnvelope final Envelope gmlEnvelope = (Envelope)gmlGeometry; crsName = gmlEnvelope.getSrsName(); filterGeometry = GeometrytoJTS.toJTS(gmlEnvelope); } else if (gmlGeometry instanceof AbstractGeometry) { final AbstractGeometry gmlGeom = (AbstractGeometry)gmlGeometry; crsName = gmlGeom.getSrsName(); filterGeometry = GeometrytoJTS.toJTS(gmlGeom); } if (filterGeometry != null) { final int srid = SRIDGenerator.toSRID(crsName, Version.V1); filterGeometry.setSRID(srid); } switch (filterType) { case CONTAINS : spatialfilter = wrap(FF.contains(GEOMETRY_PROPERTY, FF.literal(filterGeometry))); break; case CROSSES : spatialfilter = wrap(FF.crosses(GEOMETRY_PROPERTY, FF.literal(filterGeometry))); break; case DISJOINT : spatialfilter = wrap(FF.disjoint(GEOMETRY_PROPERTY, FF.literal(filterGeometry))); break; case EQUALS : spatialfilter = wrap(FF.equal(GEOMETRY_PROPERTY, FF.literal(filterGeometry))); break; case INTERSECTS : spatialfilter = wrap(FF.intersects(GEOMETRY_PROPERTY, FF.literal(filterGeometry))); break; case OVERLAPS : spatialfilter = wrap(FF.overlaps(GEOMETRY_PROPERTY, FF.literal(filterGeometry))); break; case TOUCHES : spatialfilter = wrap(FF.touches(GEOMETRY_PROPERTY, FF.literal(filterGeometry))); break; case WITHIN : spatialfilter = wrap(FF.within(GEOMETRY_PROPERTY, FF.literal(filterGeometry))); break; default : LOGGER.info("using default filter within"); spatialfilter = wrap(FF.within(GEOMETRY_PROPERTY, FF.literal(filterGeometry))); break; } } catch (NoSuchAuthorityCodeException e) { throw new FilterParserException(UNKNOW_CRS_ERROR_MSG + crsName, e, INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } catch (FactoryException e) { throw new FilterParserException(FACTORY_BBOX_ERROR_MSG + e.getMessage(), e, INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } catch (IllegalArgumentException e) { throw new FilterParserException(INCORRECT_BBOX_DIM_ERROR_MSG + e.getMessage(), e, INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } } return spatialfilter; } /** * Return true is the specified property has to be treated as a date Field. * * @param propertyName A property name extract from a filter. * @return true is the specified property has to be treated as a date Field. */ protected boolean isDateField(final PropertyName pName) { if (pName != null && pName.getPropertyName() != null) { String propertyName = pName.getPropertyName(); final int semicolonPos = propertyName.lastIndexOf(':'); if (semicolonPos != -1) { propertyName = propertyName.substring(semicolonPos + 1); } return propertyName.contains("Date") || propertyName.contains("Modified") || propertyName.contains("date") || propertyName.equalsIgnoreCase("TempExtent_begin") || propertyName.equalsIgnoreCase("TempExtent_end"); } return false; } /** * In the case of a NOT operator containing a comparison operator, the easiest way is to * reverse the comparison operator. * example: NOT PropertyIsLessOrEqualsThan => PropertyIsGreaterThan * NOT PropertyIsLessThan => PropertyIsGreaterOrEqualsThan * * @param c The comparison operator to reverse. * @return The reversed comparison Operator * * @throws FilterParserException */ protected ComparisonOpsType reverseComparisonOperator(final ComparisonOpsType c) throws FilterParserException { String operator; if (c != null) { operator = c.getClass().getSimpleName(); } else { operator = "null"; } if (c instanceof BinaryComparisonOpType) { final BinaryComparisonOpType bc = (BinaryComparisonOpType) c; if (c instanceof PropertyIsEqualTo) { return (ComparisonOpsType) buildPropertyIsNotEquals("1.1.0", bc.getPropertyName(), bc.getLiteral(), Boolean.TRUE); } else if (c instanceof PropertyIsNotEqualTo) { return (ComparisonOpsType) buildPropertyIsEquals("1.1.0", bc.getPropertyName(), bc.getLiteral(), Boolean.TRUE); } else if (c instanceof PropertyIsGreaterThanOrEqualTo) { return (ComparisonOpsType) buildPropertyIsLessThan("1.1.0", bc.getPropertyName(), bc.getLiteral(), Boolean.TRUE); } else if (c instanceof PropertyIsGreaterThan) { return (ComparisonOpsType) buildPropertyIsLessThanOrEqualTo("1.1.0", bc.getPropertyName(), bc.getLiteral(), Boolean.TRUE); } else if (c instanceof PropertyIsLessThan) { return (ComparisonOpsType) buildPropertyIsGreaterThanOrEqualTo("1.1.0", bc.getPropertyName(), bc.getLiteral(), Boolean.TRUE); } else if (c instanceof PropertyIsLessThanOrEqualTo) { return (ComparisonOpsType) buildPropertyIsGreaterThan("1.1.0", bc.getPropertyName(), bc.getLiteral(), Boolean.TRUE); } else { throw new FilterParserException("Unkwnow comparison operator: " + operator, INVALID_PARAMETER_VALUE, QUERY_CONSTRAINT); } } else { throw new FilterParserException("Unsupported combinaison NOT + " + operator, OPERATION_NOT_SUPPORTED, QUERY_CONSTRAINT); } } }