/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2007-2011, Open Source Geospatial Foundation (OSGeo) * * This library 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; * version 2.1 of the License. * * This library 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. */ package org.geotools.data.complex.filter; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.XMLConstants; import javax.xml.namespace.QName; import org.geotools.data.complex.AttributeMapping; import org.geotools.data.complex.FeatureTypeMapping; import org.geotools.data.complex.filter.XPath.Step; import org.geotools.data.complex.filter.XPath.StepList; import org.geotools.factory.CommonFactoryFinder; import org.geotools.filter.NestedAttributeExpression; import org.opengis.feature.type.AttributeDescriptor; import org.opengis.feature.type.Name; import org.opengis.filter.And; import org.opengis.filter.BinaryComparisonOperator; import org.opengis.filter.BinaryLogicOperator; import org.opengis.filter.ExcludeFilter; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.Id; import org.opengis.filter.IncludeFilter; import org.opengis.filter.MultiValuedFilter.MatchAction; import org.opengis.filter.Not; import org.opengis.filter.Or; import org.opengis.filter.PropertyIsBetween; 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.Add; import org.opengis.filter.expression.BinaryExpression; import org.opengis.filter.expression.Divide; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.ExpressionVisitor; import org.opengis.filter.expression.Function; import org.opengis.filter.expression.Literal; import org.opengis.filter.expression.Multiply; import org.opengis.filter.expression.NilExpression; import org.opengis.filter.expression.PropertyName; import org.opengis.filter.expression.Subtract; import org.opengis.filter.identity.Identifier; import org.opengis.filter.spatial.BBOX; import org.opengis.filter.spatial.Beyond; import org.opengis.filter.spatial.BinarySpatialOperator; import org.opengis.filter.spatial.Contains; import org.opengis.filter.spatial.Crosses; import org.opengis.filter.spatial.DWithin; import org.opengis.filter.spatial.Disjoint; import org.opengis.filter.spatial.Equals; import org.opengis.filter.spatial.Intersects; import org.opengis.filter.spatial.Overlaps; import org.opengis.filter.spatial.Touches; import org.opengis.filter.spatial.Within; import org.opengis.filter.temporal.After; import org.opengis.filter.temporal.AnyInteracts; import org.opengis.filter.temporal.Before; import org.opengis.filter.temporal.Begins; import org.opengis.filter.temporal.BegunBy; import org.opengis.filter.temporal.BinaryTemporalOperator; import org.opengis.filter.temporal.During; import org.opengis.filter.temporal.EndedBy; import org.opengis.filter.temporal.Ends; import org.opengis.filter.temporal.Meets; import org.opengis.filter.temporal.MetBy; import org.opengis.filter.temporal.OverlappedBy; import org.opengis.filter.temporal.TContains; import org.opengis.filter.temporal.TEquals; import org.opengis.filter.temporal.TOverlaps; import org.xml.sax.helpers.NamespaceSupport; /** * A Filter visitor that traverse a Filter or Expression made against a complex FeatureType, and * that uses the attribute and type mapping information given by a * {@linkplain org.geotools.data.complex.FeatureTypeMapping} object to produce an equivalent Filter * that operates against the original FeatureType. * <p> * Usage: * * <pre> * <code> * Filter filterOnTargetType = ... * FeatureTypeMappings schemaMapping = .... * * UnMappingFilterVisitor visitor = new UnmappingFilterVisitor(schemaMapping); * Filter filterOnSourceType = (Filter)filterOnTargetType.accept(visitor, null); * * </code> * </pre> * * </p> * * @author Gabriel Roldan (Axios Engineering) * @author Rini Angreani (CSIRO Earth Science and Resource Engineering) * @version $Id$ * * * @source $URL$ * http://svn.osgeo.org/geotools/trunk/modules/unsupported/app-schema/app-schema/src/main * /java/org/geotools/data/complex/filter/UnmappingFilterVisitor.java $ * @since 2.4 */ public class UnmappingFilterVisitor implements org.opengis.filter.FilterVisitor, ExpressionVisitor { private static final Logger LOGGER = org.geotools.util.logging.Logging .getLogger(UnmappingFilterVisitor.class.getPackage().getName()); private FeatureTypeMapping mappings; private static final FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); /** * visit(*Expression) holds the unmapped expression here. Package visible just for unit tests */ public UnmappingFilterVisitor(FeatureTypeMapping mappings) { this.mappings = mappings; } /** * Used by methods that visited a filter that produced one or more filters over the surrogate * feature type to combine them in an Or filter if necessary. * * @param combinedFilters * @return */ private Filter combineOred(List combinedFilters) { switch (combinedFilters.size()) { case 0: throw new IllegalArgumentException("No filters to combine"); case 1: return (Filter) combinedFilters.get(0); default: return ff.or(combinedFilters); } } /** * Returns a CompareFilter of the same type than <code>filter</code>, but built on the unmapped * expressions pointing to the surrogate type attributes. * * @return the scalar product of the evaluation of both expressions */ public Expression[][] visitBinaryComparisonOperator(BinaryComparisonOperator filter) { Expression left = filter.getExpression1(); Expression right = filter.getExpression2(); List leftExpressions = (List) left.accept(this, null); List rightExpressions = (List) right.accept(this, null); if (leftExpressions.size() == 0) { throw new IllegalStateException(left + " mapping not found"); } if (rightExpressions.size() == 0) { throw new IllegalStateException(right + " mapping not found"); } Expression[][] product = buildExpressionsMatrix(leftExpressions, rightExpressions); return product; } private Expression[][] buildExpressionsMatrix(List leftExpressions, List rightExpressions) { Expression left; Expression right; Expression[][] product = new Expression[leftExpressions.size() * rightExpressions.size()][2]; int index = 0; for (Iterator lefts = leftExpressions.iterator(); lefts.hasNext();) { left = (Expression) lefts.next(); for (Iterator rights = rightExpressions.iterator(); rights.hasNext();) { right = (Expression) rights.next(); product[index][0] = left; product[index][1] = right; } index++; } return product; } public Expression[][] visitBinarySpatialOp(BinarySpatialOperator filter) { Expression left = filter.getExpression1(); Expression right = filter.getExpression2(); List leftExpressions = (List) left.accept(this, null); List rightExpressions = (List) right.accept(this, null); if (leftExpressions.size() == 0) { throw new IllegalStateException(left + " mapping not found"); } if (rightExpressions.size() == 0) { throw new IllegalStateException(right + " mapping not found"); } Expression[][] product = buildExpressionsMatrix(leftExpressions, rightExpressions); return product; } public List/* <Filter> */visitBinaryLogicOp(BinaryLogicOperator filter) { List unrolledFilers = new ArrayList(); try { for (Iterator it = filter.getChildren().iterator(); it.hasNext();) { Filter next = (Filter) it.next(); Filter unrolled = (Filter) next.accept(this, null); unrolledFilers.add(unrolled); } } catch (Exception e) { throw (RuntimeException) new RuntimeException().initCause(e); } return unrolledFilers; } public Expression[][] visitBinaryExpression(BinaryExpression expression) { UnmappingFilterVisitor.LOGGER.finest(expression.toString()); Expression left = expression.getExpression1(); Expression right = expression.getExpression2(); List leftExpressions = (List) left.accept(this, null); List rightExpressions = (List) right.accept(this, null); Expression[][] product = buildExpressionsMatrix(leftExpressions, rightExpressions); return product; } public Object visit(ExcludeFilter filter, Object arg1) { return filter; } public Object visit(IncludeFilter filter, Object arg1) { return filter; } public Object visit(And filter, Object arg1) { List list = visitBinaryLogicOp(filter); Filter unrolled = ff.and(list); return unrolled; } public Object visit(Id filter, Object arg1) { Set fids = filter.getIdentifiers(); Name target = mappings.getTargetFeature().getName(); String namespace = target.getNamespaceURI(); if (namespace == null) { namespace = XMLConstants.NULL_NS_URI; } String name = target.getLocalPart(); Expression fidExpression = null; for (Iterator it = mappings.getAttributeMappings().iterator(); it.hasNext();) { AttributeMapping attMapping = (AttributeMapping) it.next(); StepList targetXPath = attMapping.getTargetXPath(); if (targetXPath.size() > 1) { continue; } Step step = (Step) targetXPath.get(0); QName stepName = step.getName(); if (namespace.equals(stepName.getNamespaceURI())) { if (name.equals(stepName.getLocalPart())) { fidExpression = attMapping.getIdentifierExpression(); break; } } } if (fidExpression == null) { throw new IllegalStateException("No FID expression found for type " + target + ". Did you mean Expression.NIL?"); } if (Expression.NIL.equals(fidExpression)) { return filter; } if (fidExpression instanceof Function) { Function fe = (Function) fidExpression; if ("getID".equalsIgnoreCase(fe.getName())) { LOGGER.finest("Fid mapping points to same ID as source"); return filter; } } UnmappingFilterVisitor.LOGGER.finest("fid mapping expression is " + fidExpression); Filter unrolled = null; List<Filter> filters=new ArrayList<Filter>(); try { for (Iterator it = fids.iterator(); it.hasNext();) { Identifier fid = (Identifier) it.next(); Filter comparison = UnmappingFilterVisitor.ff.equals(fidExpression, UnmappingFilterVisitor.ff.literal(fid.toString())); UnmappingFilterVisitor.LOGGER.finest("Adding unmapped fid filter " + comparison); filters.add(comparison); } unrolled=UnmappingFilterVisitor.ff.or(filters); } catch (Exception e) { UnmappingFilterVisitor.LOGGER.log(Level.SEVERE, "unrolling " + filter, e); throw new RuntimeException(e.getMessage()); } UnmappingFilterVisitor.LOGGER.finer("unrolled fid filter is " + unrolled); return unrolled; } public Object visit(Not filter, Object arg1) { Filter unrolled = (Filter) filter.getFilter().accept(this, null); unrolled = ff.not(unrolled); return unrolled; } public Object visit(Or filter, Object arg1) { List list = visitBinaryLogicOp(filter); Filter unrolled = ff.or(list); return unrolled; } public Object visit(PropertyIsBetween filter, Object arg1) { Expression expression = filter.getExpression(); Expression lower = filter.getLowerBoundary(); Expression upper = filter.getUpperBoundary(); List expressions = (List) expression.accept(this, null); List lowerExpressions = (List) lower.accept(this, null); List upperExpressions = (List) upper.accept(this, null); final int combinedSize = expressions.size() * lowerExpressions.size() * upperExpressions.size(); List combinedFilters = new ArrayList(combinedSize); for (Iterator lowers = lowerExpressions.iterator(); lowers.hasNext();) { Expression floor = (Expression) lowers.next(); for (Iterator exprs = expressions.iterator(); exprs.hasNext();) { Expression prop = (Expression) exprs.next(); for (Iterator uppers = upperExpressions.iterator(); uppers.hasNext();) { Expression roof = (Expression) uppers.next(); Filter newFilter = ff.between(prop, floor, roof, filter.getMatchAction()); combinedFilters.add(newFilter); } } } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(PropertyIsEqualTo filter, Object arg1) { Expression[][] expressions = visitBinaryComparisonOperator(filter); List combinedFilters = new ArrayList(expressions.length); for (int i = 0; i < expressions.length; i++) { Expression left = expressions[i][0]; Expression right = expressions[i][1]; Filter unrolled = ff.equal(left, right, filter.isMatchingCase(), filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(PropertyIsNotEqualTo filter, Object arg1) { Expression[][] expressions = visitBinaryComparisonOperator(filter); List combinedFilters = new ArrayList(expressions.length); for (int i = 0; i < expressions.length; i++) { Expression left = expressions[i][0]; Expression right = expressions[i][1]; Filter unrolled = ff.notEqual(left, right, filter.isMatchingCase(), filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(PropertyIsGreaterThan filter, Object arg1) { Expression[][] expressions = visitBinaryComparisonOperator(filter); List combinedFilters = new ArrayList(expressions.length); for (int i = 0; i < expressions.length; i++) { Expression left = expressions[i][0]; Expression right = expressions[i][1]; Filter unrolled = ff.greater(left, right, filter.isMatchingCase(), filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(PropertyIsGreaterThanOrEqualTo filter, Object arg1) { Expression[][] expressions = visitBinaryComparisonOperator(filter); List combinedFilters = new ArrayList(expressions.length); for (int i = 0; i < expressions.length; i++) { Expression left = expressions[i][0]; Expression right = expressions[i][1]; Filter unrolled = ff.greaterOrEqual(left, right, filter.isMatchingCase(), filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(PropertyIsLessThan filter, Object arg1) { Expression[][] expressions = visitBinaryComparisonOperator(filter); List combinedFilters = new ArrayList(expressions.length); for (int i = 0; i < expressions.length; i++) { Expression left = expressions[i][0]; Expression right = expressions[i][1]; Filter unrolled = ff.less(left, right, filter.isMatchingCase(), filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(PropertyIsLessThanOrEqualTo filter, Object arg1) { Expression[][] expressions = visitBinaryComparisonOperator(filter); List combinedFilters = new ArrayList(expressions.length); for (int i = 0; i < expressions.length; i++) { Expression left = expressions[i][0]; Expression right = expressions[i][1]; Filter unrolled = ff.lessOrEqual(left, right, filter.isMatchingCase(), filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(PropertyIsLike filter, Object arg1) { Expression value = filter.getExpression(); List unrolledValues = (List) value.accept(this, null); String literal = filter.getLiteral(); String wildcard = filter.getWildCard(); String single = filter.getSingleChar(); String escape = filter.getEscape(); boolean matchCase = filter.isMatchingCase(); MatchAction matchAction = filter.getMatchAction(); List combined = new ArrayList(unrolledValues.size()); for (Iterator it = unrolledValues.iterator(); it.hasNext();) { Expression sourceValue = (Expression) it.next(); Filter newFilter = ff.like(sourceValue, literal, wildcard, single, escape, matchCase, matchAction); combined.add(newFilter); } Filter unrolled = combineOred(combined); return unrolled; } public Object visit(PropertyIsNull filter, Object arg1) { Expression nullCheck = filter.getExpression(); List sourceChecks = (List) nullCheck.accept(this, null); List combined = new ArrayList(sourceChecks.size()); for (Iterator it = sourceChecks.iterator(); it.hasNext();) { Expression sourceValue = (Expression) it.next(); Filter newFilter = ff.isNull(sourceValue); combined.add(newFilter); } Filter unrolled = combineOred(combined); return unrolled; } public Object visit(BBOX filter, Object arg1) { String propertyName = filter.getPropertyName(); if (propertyName.length() < 1) { // see GetFeatureKvpRequestReader bboxFilter() // propertyName is meant to be empty, and it will get it from the feature // later (if not available, it will use feature's default geometry) // instead of always use the default geometry from the feature type return filter; } Expression name = ff.property(propertyName); final List sourceNames = (List) name.accept(this, null); final List combined = new ArrayList(sourceNames.size()); for (Iterator it = sourceNames.iterator(); it.hasNext();) { Expression sourceName = (Expression) it.next(); Filter unrolled = ff.bbox(sourceName, filter.getMinX(), filter.getMinY(), filter .getMaxX(), filter.getMaxY(), filter.getSRS(), filter.getMatchAction()); combined.add(unrolled); } Filter unrolled = combineOred(combined); return unrolled; } public Object visit(Beyond filter, Object arg1) { Expression[][] exps = visitBinarySpatialOp(filter); List combinedFilters = new ArrayList(exps.length); for (int i = 0; i < exps.length; i++) { Expression left = exps[i][0]; Expression right = exps[i][1]; Filter unrolled = ff.beyond(left, right, filter.getDistance(), filter .getDistanceUnits(), filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(Contains filter, Object arg1) { Expression[][] exps = visitBinarySpatialOp(filter); List combinedFilters = new ArrayList(exps.length); for (int i = 0; i < exps.length; i++) { Expression left = exps[i][0]; Expression right = exps[i][1]; Filter unrolled = ff.contains(left, right, filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(Crosses filter, Object arg1) { Expression[][] exps = visitBinarySpatialOp(filter); List combinedFilters = new ArrayList(exps.length); for (int i = 0; i < exps.length; i++) { Expression left = exps[i][0]; Expression right = exps[i][1]; Filter unrolled = ff.crosses(left, right, filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(Disjoint filter, Object arg1) { Expression[][] exps = visitBinarySpatialOp(filter); List combinedFilters = new ArrayList(exps.length); for (int i = 0; i < exps.length; i++) { Expression left = exps[i][0]; Expression right = exps[i][1]; Filter unrolled = ff.disjoint(left, right, filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(DWithin filter, Object arg1) { Expression[][] exps = visitBinarySpatialOp(filter); List combinedFilters = new ArrayList(exps.length); for (int i = 0; i < exps.length; i++) { Expression left = exps[i][0]; Expression right = exps[i][1]; Filter unrolled = ff.dwithin(left, right, filter.getDistance(), filter .getDistanceUnits(), filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(Equals filter, Object arg1) { Expression[][] exps = visitBinarySpatialOp(filter); List combinedFilters = new ArrayList(exps.length); for (int i = 0; i < exps.length; i++) { Expression left = exps[i][0]; Expression right = exps[i][1]; Filter unrolled = ff.equal(left, right, filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(Intersects filter, Object arg1) { Expression[][] exps = visitBinarySpatialOp(filter); List combinedFilters = new ArrayList(exps.length); for (int i = 0; i < exps.length; i++) { Expression left = exps[i][0]; Expression right = exps[i][1]; Filter unrolled = ff.intersects(left, right, filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(Overlaps filter, Object arg1) { Expression[][] exps = visitBinarySpatialOp(filter); List combinedFilters = new ArrayList(exps.length); for (int i = 0; i < exps.length; i++) { Expression left = exps[i][0]; Expression right = exps[i][1]; Filter unrolled = ff.overlaps(left, right, filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(Touches filter, Object arg1) { Expression[][] exps = visitBinarySpatialOp(filter); List combinedFilters = new ArrayList(exps.length); for (int i = 0; i < exps.length; i++) { Expression left = exps[i][0]; Expression right = exps[i][1]; Filter unrolled = ff.touches(left, right, filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visit(Within filter, Object arg1) { Expression[][] exps = visitBinarySpatialOp(filter); List combinedFilters = new ArrayList(exps.length); for (int i = 0; i < exps.length; i++) { Expression left = exps[i][0]; Expression right = exps[i][1]; Filter unrolled = ff.within(left, right, filter.getMatchAction()); combinedFilters.add(unrolled); } Filter unrolled = combineOred(combinedFilters); return unrolled; } public Object visitNullFilter(Object arg0) { return Filter.EXCLUDE; } public Object visit(NilExpression expr, Object arg1) { return Collections.singletonList(expr); } public Object visit(Add expr, Object arg1) { Expression[][] expressions = visitBinaryExpression(expr); List combinedExpressions = new ArrayList(expressions.length); for (int i = 0; i < expressions.length; i++) { Expression left = expressions[i][0]; Expression right = expressions[i][1]; Expression sourceExpression = ff.add(left, right); combinedExpressions.add(sourceExpression); } return combinedExpressions; } public Object visit(Divide expr, Object arg1) { Expression[][] expressions = visitBinaryExpression(expr); List combinedExpressions = new ArrayList(expressions.length); for (int i = 0; i < expressions.length; i++) { Expression left = expressions[i][0]; Expression right = expressions[i][1]; Expression sourceExpression = ff.divide(left, right); combinedExpressions.add(sourceExpression); } return combinedExpressions; } /** * @todo: support function arguments that map to more than one source expression. For example, * if the argumen <code>gml:name</code> maps to source expressions <code>name</code> and * <code>description</code> because the mapping has attribute mappings for both * <code>gml:name[1] = name</code> and <code>gml:name[2] = description</code>. */ public Object visit(Function function, Object arg1) { final List expressions = function.getParameters(); List arguments = new ArrayList(expressions.size()); for (Iterator it = expressions.iterator(); it.hasNext();) { Expression mappingExpression = (Expression) it.next(); List sourceExpressions = (List) mappingExpression.accept(this, null); if (sourceExpressions.size() > 1) { throw new UnsupportedOperationException("unrolling function arguments " + "that map to more than one source expressions " + "is not supported yet"); } Expression unrolledExpression = (Expression) sourceExpressions.get(0); arguments.add(unrolledExpression); } Expression[] unmapped = new Expression[arguments.size()]; unmapped = (Expression[]) arguments.toArray(unmapped); Function unmappedFunction = ff.function(function.getName(), unmapped); return Collections.singletonList(unmappedFunction); } public Object visit(Literal expr, Object arg1) { return Collections.singletonList(expr); } public Object visit(Multiply expr, Object arg1) { Expression[][] expressions = visitBinaryExpression(expr); List combinedExpressions = new ArrayList(expressions.length); for (int i = 0; i < expressions.length; i++) { Expression left = expressions[i][0]; Expression right = expressions[i][1]; Expression sourceExpression = ff.multiply(left, right); combinedExpressions.add(sourceExpression); } return combinedExpressions; } public Object visit(PropertyName expr, Object arg1) { String targetXPath = expr.getPropertyName(); NamespaceSupport namespaces = mappings.getNamespaces(); AttributeDescriptor root = mappings.getTargetFeature(); // break into single steps StepList simplifiedSteps = XPath.steps(root, targetXPath, namespaces); List<Expression> matchingMappings = mappings.findMappingsFor(simplifiedSteps); if (matchingMappings.isEmpty() && simplifiedSteps.size() > 1) { // means some attributes are probably mapped separately in feature chaining matchingMappings.add(new NestedAttributeExpression(targetXPath, mappings, this.mappings.getNamespaces())); } if (matchingMappings.size() == 0) { throw new IllegalArgumentException("Can't find source expression for: " + targetXPath); } return matchingMappings; } public Object visit(Subtract expr, Object arg1) { Expression[][] expressions = visitBinaryExpression(expr); List combinedExpressions = new ArrayList(expressions.length); for (int i = 0; i < expressions.length; i++) { Expression left = expressions[i][0]; Expression right = expressions[i][1]; Expression sourceExpression = ff.subtract(left, right); combinedExpressions.add(sourceExpression); } return combinedExpressions; } //temporal filters public Object visit(After after, Object extraData) { return visit((BinaryTemporalOperator)after, extraData); } public Object visit(AnyInteracts anyInteracts, Object extraData) { return visit((BinaryTemporalOperator)anyInteracts, extraData); } public Object visit(Before before, Object extraData) { return visit((BinaryTemporalOperator)before, extraData); } public Object visit(Begins begins, Object extraData) { return visit((BinaryTemporalOperator)begins, extraData); } public Object visit(BegunBy begunBy, Object extraData) { return visit((BinaryTemporalOperator)begunBy, extraData); } public Object visit(During during, Object extraData) { return visit((BinaryTemporalOperator)during, extraData); } public Object visit(EndedBy endedBy, Object extraData) { return visit((BinaryTemporalOperator)endedBy, extraData); } public Object visit(Ends ends, Object extraData) { return visit((BinaryTemporalOperator)ends, extraData); } public Object visit(Meets meets, Object extraData) { return visit((BinaryTemporalOperator)meets, extraData); } public Object visit(MetBy metBy, Object extraData) { return visit((BinaryTemporalOperator)metBy, extraData); } public Object visit(OverlappedBy overlappedBy, Object extraData) { return visit((BinaryTemporalOperator)overlappedBy, extraData); } public Object visit(TContains contains, Object extraData) { return visit((BinaryTemporalOperator)contains, extraData); } public Object visit(TEquals equals, Object extraData) { return visit((BinaryTemporalOperator)equals, extraData); } public Object visit(TOverlaps contains, Object extraData) { return visit((BinaryTemporalOperator)contains, extraData); } protected Object visit(BinaryTemporalOperator filter, Object data) { throw new UnsupportedOperationException("Temporal filters not supported"); } }