Package org.geotools.filter.visitor

Source Code of org.geotools.filter.visitor.LiteralDemultiplyingFilterVisitor

package org.geotools.filter.visitor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.opengis.filter.BinaryComparisonOperator;
import org.opengis.filter.Filter;
import org.opengis.filter.MultiValuedFilter;
import org.opengis.filter.MultiValuedFilter.MatchAction;
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.PropertyIsNotEqualTo;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Literal;
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;

/**
* This visitor gets rid of equations that contain literals with multiple values (collections)
* and creates instead multiple singe value equations,
* replacing the ANY, ALL, ONE logic by AND, OR, NOT logic
*
* @author Niels Charlier
*
*/
public class LiteralDemultiplyingFilterVisitor extends DuplicatingFilterVisitor {
   
    /**
     * This interface is in support of a generic function (demultiply) that gets rid of the multi-valued literals, with any type of filter
     * that takes two expressions.
     */
    protected static interface FilterReplacer<F extends MultiValuedFilter> {
               
        public Expression getExpression1(F filter);
       
        public Expression getExpression2(F filter);
       
        /**
         * Replace the expressions in a filter
         */
        public Filter replaceExpressions(F filter, Expression expression1, Expression expression2);
       
    }
   
    /**
     * An implementation for Binary Comparison Operators
     * Takes the method name in the FilterFactory to create the filter
     *
     */
    protected class BinaryComparisonOperatorReplacer implements FilterReplacer<BinaryComparisonOperator> {
       
        protected Method method;
       
        public BinaryComparisonOperatorReplacer(String methodName){
           
            try {
                method = ff.getClass().getMethod(methodName, Expression.class, Expression.class, boolean.class, MatchAction.class)
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public Expression getExpression1(BinaryComparisonOperator filter) {
            return filter.getExpression1();           
        }

        @Override
        public Expression getExpression2(BinaryComparisonOperator filter) {
            return filter.getExpression2();
        }

        @Override
        public Filter replaceExpressions(BinaryComparisonOperator filter, Expression expression1, Expression expression2) {           
            try {
                return (Filter) method.invoke (ff, expression1, expression2, filter.isMatchingCase(), filter.getMatchAction() );
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
       
    }
   
    /**
     * An implementation for Binary Spatial Operators
     * Takes the method name in the FilterFactory to create the filter
     *
     */
    protected class BinarySpatialOperatorReplacer implements FilterReplacer<BinarySpatialOperator> {
       
        protected Method method;
       
        public BinarySpatialOperatorReplacer(String methodName){
           
            try {
                method = ff.getClass().getMethod(methodName, Expression.class, Expression.class, MatchAction.class)
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public Expression getExpression1(BinarySpatialOperator filter) {
            return filter.getExpression1();           
        }

        @Override
        public Expression getExpression2(BinarySpatialOperator filter) {
            return filter.getExpression2();
        }

        @Override
        public Filter replaceExpressions(BinarySpatialOperator filter, Expression expression1,  Expression expression2) {           
            try {
                return (Filter) method.invoke (ff, expression1, expression2, filter.getMatchAction() );
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
       
    }
   
    /**
     * An implementation for Binary Temporal Operators
     * Takes the method name in the FilterFactory to create the filter
     *
     */
    protected class BinaryTemporalOperatorReplacer implements FilterReplacer<BinaryTemporalOperator> {
       
        protected Method method;
       
        public BinaryTemporalOperatorReplacer(String methodName){
           
            try {
                method = ff.getClass().getMethod(methodName, Expression.class, Expression.class, MatchAction.class)
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public Expression getExpression1(BinaryTemporalOperator filter) {
            return filter.getExpression1();           
        }

        @Override
        public Expression getExpression2(BinaryTemporalOperator filter) {
            return filter.getExpression2();
        }

        @Override
        public Filter replaceExpressions(BinaryTemporalOperator filter, Expression expression1,  Expression expression2) {           
            try {
                return (Filter) method.invoke (ff, expression1, expression2, filter.getMatchAction() );
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
       
    }
   
    /**
     * demultiplies the first expression
     *
     * @param filter The filter
     * @param replacer The filter replacer
     * @return the new filter
     */
    protected<T extends MultiValuedFilter> Filter demultiplyFirst( T filter, FilterReplacer<T> replacer) {
       
        Expression one = replacer.getExpression1(filter);
        Expression two = replacer.getExpression2(filter);
               
        if (one instanceof Literal) {
            Literal l = (Literal) one;
            Object value = l.getValue();
            if (value instanceof Collection) { //demultiplying is necessary
                List<Filter> filters = new ArrayList<Filter>(); //list of all filters
                for (Object valueElement : (Collection) value) {
                    //create a single-valued new filter
                    filters.add(replacer.replaceExpressions(filter, ff.literal(valueElement), two));
                }
                //merge the filters depending on match action
                if (filter.getMatchAction() == MatchAction.ANY) {
                    return ff.or(filters);
                } else if (filter.getMatchAction() == MatchAction.ALL) {
                    return ff.and(filters);
                } else if (filter.getMatchAction() == MatchAction.ONE) {
                    List<Filter> filters2 = new ArrayList<Filter>();
                    for (int i = 0; i < filters.size(); i++) {
                        List<Filter> filters3 = new ArrayList<Filter>();                       
                        for (int j = 0; j < filters.size(); j++) {
                            if (i==j) {
                                filters3.add(filters.get(j));
                            } else {
                                filters3.add(ff.not(filters.get(j)));
                            }
                        }
                        filters2.add(ff.and(filters3));              
                    }
                    return ff.or(filters2);
                }
            }
        }
       
        return filter;
    }
   
    /**
     * Demultiplies first and second expression
     *
     * @param filter
     * @param replacer
     * @return
     */
    protected<T extends MultiValuedFilter> Filter demultiply( T filter, FilterReplacer<T> replacer) {
        
        Expression one = replacer.getExpression1(filter);
        Expression two = replacer.getExpression2(filter);
       
        if (two instanceof Literal) {
            Literal l = (Literal) two;
            Object value = l.getValue();
            if (value instanceof Collection) { //demultiplying is necessary
                List<Filter> filters = new ArrayList<Filter>(); //list of all filters
                for (Object valueElement : (Collection) value) { 
                    //create a single-valued new filter
                    filters.add(demultiplyFirst((T) replacer.replaceExpressions(filter, one, ff.literal(valueElement)), replacer));
                }
              //merge the filters depending on match action
                if (filter.getMatchAction() == MatchAction.ANY) { 
                    return ff.or(filters);
                } else if (filter.getMatchAction() == MatchAction.ALL) {
                    return ff.and(filters);
                } else if (filter.getMatchAction() == MatchAction.ONE) {
                    List<Filter> filters2 = new ArrayList<Filter>();
                    for (int i = 0; i < filters.size(); i++) {
                        List<Filter> filters3 = new ArrayList<Filter>();                       
                        for (int j = 0; j < filters.size(); j++) {
                            if (i==j) {
                                filters3.add(filters.get(j));
                            } else {
                                filters3.add(ff.not(filters.get(j)));
                            }
                        }
                        filters2.add(ff.and(filters3));              
                    }
                    return ff.or(filters2);
                }
            }
        }        
       
        return demultiplyFirst(filter, replacer);
    }
   
    @Override
    public Object visit(PropertyIsBetween filter, Object extraData) {
        // TODO: support ProperyIsBetween (there are three expressions here)       
        return super.visit(filter, extraData);
    }

    @Override
    public Object visit(PropertyIsEqualTo filter, Object extraData) {
        return demultiply(filter, new BinaryComparisonOperatorReplacer("equal"));
    }

    @Override
    public Object visit(PropertyIsNotEqualTo filter, Object extraData) {
        return demultiply(filter, new BinaryComparisonOperatorReplacer("notEqual"));
    }

    @Override
    public Object visit(PropertyIsGreaterThan filter, Object extraData) {
        return demultiply(filter, new BinaryComparisonOperatorReplacer("greater"));
    }

    @Override
    public Object visit(PropertyIsGreaterThanOrEqualTo filter, Object extraData) {
        return demultiply(filter, new BinaryComparisonOperatorReplacer("greaterOrEqual"));
    }

    @Override
    public Object visit(PropertyIsLessThan filter, Object extraData) {
        return demultiply(filter, new BinaryComparisonOperatorReplacer("less"));
    }

    @Override
    public Object visit(PropertyIsLessThanOrEqualTo filter, Object extraData) {
        return demultiply(filter, new BinaryComparisonOperatorReplacer("lessOrEqual"));
    }

    @Override
    public Object visit(BBOX filter, Object extraData) {
        return demultiply(filter, new BinarySpatialOperatorReplacer("bbox"));
    }

    @Override
    public Object visit(Beyond filter, Object extraData) {
        return demultiply(filter, new FilterReplacer<Beyond>(){ //beyond filter takes extra properties, therefore needs its own filterreplacer

            @Override
            public Expression getExpression1(Beyond filter) {
                return filter.getExpression1();
            }

            @Override
            public Expression getExpression2(Beyond filter) {
                return filter.getExpression2();
            }

            @Override
            public Filter replaceExpressions(Beyond filter, Expression expression1,  Expression expression2) {
                return ff.beyond(expression1, expression2, filter.getDistance(), filter.getDistanceUnits(), filter.getMatchAction());
            }
           
        });
    }

    @Override
    public Object visit(Contains filter, Object extraData) {
        return demultiply(filter, new BinarySpatialOperatorReplacer("contains"));
    }

    @Override
    public Object visit(Crosses filter, Object extraData) {
        return demultiply(filter, new BinarySpatialOperatorReplacer("crosses"));
    }

    @Override
    public Object visit(Disjoint filter, Object extraData) {
        return demultiply(filter, new BinarySpatialOperatorReplacer("disjoint"));
    }

    @Override
    public Object visit(DWithin filter, Object extraData) {
        return demultiply(filter, new FilterReplacer<DWithin>(){ //DWithin filter takes extra properties, therefore needs its own filterreplacer

            @Override
            public Expression getExpression1(DWithin filter) {
                return filter.getExpression1();
            }

            @Override
            public Expression getExpression2(DWithin filter) {
                return filter.getExpression2();
            }

            @Override
            public Filter replaceExpressions(DWithin filter, Expression expression1,  Expression expression2) {
                return ff.dwithin(expression1, expression2, filter.getDistance(), filter.getDistanceUnits(), filter.getMatchAction());
            }
           
        });
    }

    @Override
    public Object visit(Equals filter, Object extraData) {
        return demultiply(filter, new BinarySpatialOperatorReplacer("equal"));
    }

    @Override
    public Object visit(Intersects filter, Object extraData) {
        return demultiply(filter, new BinarySpatialOperatorReplacer("intersects"));
    }

    @Override
    public Object visit(Overlaps filter, Object extraData) {
        return demultiply(filter, new BinarySpatialOperatorReplacer("overlaps"));
    }

    @Override
    public Object visit(Touches filter, Object extraData) {
        return demultiply(filter, new BinarySpatialOperatorReplacer("touches"));
    }

    @Override
    public Object visit(Within filter, Object extraData) {
        return demultiply(filter, new BinarySpatialOperatorReplacer("within"));
    }

    @Override
    public Object visit(After after, Object extraData) {
        return demultiply(after, new BinaryTemporalOperatorReplacer("after"));
    }

    @Override
    public Object visit(AnyInteracts anyInteracts, Object extraData) {
        return demultiply(anyInteracts, new BinaryTemporalOperatorReplacer("anyInteracts"));
    }

    @Override
    public Object visit(Before before, Object extraData) {
        return demultiply(before, new BinaryTemporalOperatorReplacer("before"));
    }

    @Override
    public Object visit(Begins begins, Object extraData) {
        return demultiply(begins, new BinaryTemporalOperatorReplacer("begins"));
    }

    @Override
    public Object visit(BegunBy begunBy, Object extraData) {
        return demultiply(begunBy, new BinaryTemporalOperatorReplacer("begunBy"));
    }

    @Override
    public Object visit(During during, Object extraData) {
        return demultiply(during, new BinaryTemporalOperatorReplacer("during"));
    }

    @Override
    public Object visit(EndedBy endedBy, Object extraData) {
        return demultiply(endedBy, new BinaryTemporalOperatorReplacer("endedBy"));
    }

    @Override
    public Object visit(Ends ends, Object extraData) {
        return demultiply(ends, new BinaryTemporalOperatorReplacer("ends"));
    }

    @Override
    public Object visit(Meets meets, Object extraData) {
        return demultiply(meets, new BinaryTemporalOperatorReplacer("meets"));
    }

    @Override
    public Object visit(MetBy metBy, Object extraData) {
        return demultiply(metBy, new BinaryTemporalOperatorReplacer("metBy"));
    }

    @Override
    public Object visit(OverlappedBy overlappedBy, Object extraData) {
        return demultiply(overlappedBy, new BinaryTemporalOperatorReplacer("overlappedBy"));
    }

    @Override
    public Object visit(TContains contains, Object extraData) {
        return demultiply(contains, new BinaryTemporalOperatorReplacer("tcontains"));
    }

    @Override
    public Object visit(TEquals equals, Object extraData) {
        return demultiply(equals, new BinaryTemporalOperatorReplacer("tequals"));
    }

    @Override
    public Object visit(TOverlaps overlaps, Object extraData) {
        return demultiply(overlaps, new BinaryTemporalOperatorReplacer("toverlaps"));
    }
   
   

}
TOP

Related Classes of org.geotools.filter.visitor.LiteralDemultiplyingFilterVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.