/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2014 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wms.dimension; import java.util.ArrayList; import java.util.List; import org.geotools.filter.visitor.SimplifyingFilterVisitor; import org.geotools.util.Range; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory; import org.opengis.filter.expression.Literal; import org.opengis.filter.expression.PropertyName; /** * Helper class that builds dimension related filters against reference objects that can be point * ones (date, number, string) or range types (DateRange, NumberRange) * * @author Andrea Aime - GeoSolutions * */ public class DimensionFilterBuilder { Filter filter = null; FilterFactory ff; public DimensionFilterBuilder(FilterFactory ff) { this.ff = ff; } public void appendFilters(String startAttributeName, String endAttributeName, List<Object> ranges) { if (ranges == null || ranges.size() == 0) { return; } final List<Filter> timeFilters = new ArrayList<Filter>(); final PropertyName attribute = ff.property(startAttributeName); final PropertyName endAttribute = endAttributeName == null ? null : ff .property(endAttributeName); for (Object datetime : ranges) { timeFilters.add(buildDimensionFilter(datetime, attribute, endAttribute)); } final int size = timeFilters.size(); Filter result; if (size > 1) { result = ff.or(timeFilters); } else { result = timeFilters.get(0); } if (filter == null) { filter = result; } else { filter = ff.and(filter, result); } } /** * Build a filter for a single value based on an attribute and optional endAttribute. The value * is either a Range or object that can be used as a literal (Date,Number). * * @param value * @param attribute * @param endAttribute * */ Filter buildDimensionFilter(Object value, PropertyName attribute, PropertyName endAttribute) { Filter filter; if (value == null) { filter = Filter.INCLUDE; } else if (value instanceof Range) { Range range = (Range) value; if (endAttribute == null) { filter = ff.between(attribute, ff.literal(range.getMinValue()), ff.literal(range.getMaxValue())); } else { // Range intersects valid range of feature // @todo adding another option to dimensionInfo allows contains, versus intersects Literal qlower = ff.literal(range.getMinValue()); Literal qupper = ff.literal(range.getMaxValue()); Filter lower = ff.lessOrEqual(attribute, qupper); Filter upper = ff.greaterOrEqual(endAttribute, qlower); return ff.and(lower, upper); } } else { // Single element is equal to if (endAttribute == null) { filter = ff.equal(attribute, ff.literal(value), true); } else { // Single element is contained by valid range of feature Filter lower = ff.greaterOrEqual(ff.literal(value), attribute); Filter upper = ff.lessOrEqual(ff.literal(value), endAttribute); filter = ff.and(lower, upper); } } return filter; } public Filter getFilter() { if (filter == null) { return Filter.INCLUDE; } SimplifyingFilterVisitor visitor = new SimplifyingFilterVisitor(); return (Filter) filter.accept(visitor, null); } }