Package org.geotools.filter.function

Source Code of org.geotools.filter.function.RecodeFunction

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2008, 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.filter.function;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.geotools.factory.CommonFactoryFinder;
import org.geotools.filter.FilterAttributeExtractor;
import org.geotools.filter.capability.FunctionNameImpl;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.capability.FunctionName;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.ExpressionVisitor;
import org.opengis.filter.expression.Function;
import org.opengis.filter.expression.Literal;

/**
* This is an implemenation of the Recode function as defined by
* the OGC Symbology Encoding (SE) 1.1 specification.
* <p>
* The Recode function provides a lookup table facility (think HashTable)
* where both keys and values can be any {@code Expression}. The first
* parameter to the function specifies the source of the value to lookup,
* e.g. the name of a feature property as a {@code Literal}. The remaining
* parameters define the lookup table as key:value pairs. Thus there should
* be an odd number of parameters in total: the lookup value parameter plus
* the set of key value pairs.
* <p>
* Where the lookup involves {@code String} values, comparisons are done
* case-insensitively.
* <p>
* If the lookup value does not match any of the keys defined this function
* returns {@code null}.
*
* @author Johann Sorel (Geomatys)
* @author Michael Bedward
*
*
* @source $URL$
* @version $Id$
*/
public class RecodeFunction implements Function {

    private static final FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);

    private final List<Expression> parameters;
   
    private boolean staticTable = true;
   
    volatile private Map fastLookup = null;
   
    private Class lastKeyType = null;
   
    private Class lastContextType = null;

    private final Literal fallback;

    /**
     * Make the instance of FunctionName available in a consistent spot.
     */
    public static final FunctionName NAME = new FunctionNameImpl("Recode", "LookupValue", "Data 1",
        "Value 1", "Data 2", "Value 2");

    public RecodeFunction() {
        this(new ArrayList<Expression>(), null);
    }

    public RecodeFunction(List<Expression> parameters, Literal fallback) {
        this.parameters = parameters;
        this.fallback = fallback;
       
        // check inputs
        if (parameters.size() % 2 != 1 && parameters.size() != 0) {
            throw new IllegalArgumentException(
                    "There must be an equal number of lookup data and return values");
        }
       
        // see if the table is full of attribute independent expressions
        FilterAttributeExtractor extractor = new FilterAttributeExtractor();
        for (int i = 1; i < parameters.size(); i++) {
            Expression expression = parameters.get(i);
            if(expression != null) {
                extractor.clear();
                expression.accept(extractor, null);
                if(!extractor.isConstantExpression()) {
                    staticTable = false;
                    break;
                }
            }
        }
       
    }

    public String getName() {
        return "Recode";
    }
    public FunctionName getFunctionName() {
        return NAME;
    }
    public List<Expression> getParameters() {
        return Collections.unmodifiableList(parameters);
    }

    public Object accept(ExpressionVisitor visitor, Object extraData) {
        return visitor.visit(this, extraData);
    }

    public Object evaluate(Object object) {
        return evaluate(object, Object.class);
    }

    public <T> T evaluate(Object object, Class<T> context) {
        final Expression lookupExp = parameters.get(0);
        final List<Expression> pairList = parameters.subList(1, parameters.size());

        // fast lookup path
        if(staticTable) {
            Object lookup = lookupExp.evaluate(object);
            if(lookup != null) {
                if(fastLookup == null) {
                    synchronized (this) {
                        if(fastLookup == null) {
                            // build the fast lookup map
                            fastLookup = new HashMap();
                            lastKeyType = lookup.getClass();
                            lastContextType = context;
                            for (int i = 0; i < pairList.size(); i += 2) {
                                Object key = pairList.get(i).evaluate(object, lastKeyType);
                                Object value = pairList.get(i + 1).evaluate(object, context);
                                fastLookup.put(key, value);
                            }
                        }
                    }
                }
               
                if(fastLookup != null && lookup.getClass() == lastKeyType && context == lastContextType) {
                    T result = (T) fastLookup.get(lookup);
                    return result;
                }
            }
        }
           
        // dynamic evaluation path
        for (int i = 0; i < pairList.size(); i += 2) {
            Expression keyExpr = pairList.get(i);
            Expression valueExpr = pairList.get(i + 1);
            // we are going to test our propertyNameExpression against the keyExpression
            // if they are equal we will return the valueExpression
            //
            org.opengis.filter.Filter compareFilter = ff.equal(lookupExp, keyExpr, false);

            if (compareFilter.evaluate(object)) {
                return valueExpr.evaluate(object, context);
            }
        }
       
        return null;
    }

    public Literal getFallbackValue() {
        return fallback;
    }

}
TOP

Related Classes of org.geotools.filter.function.RecodeFunction

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.