Package org.geoserver.filter.function

Source Code of org.geoserver.filter.function.QueryFunction$GeometryCRSFilter

/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
*/
package org.geoserver.filter.function;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.feature.FeatureIterator;
import org.geotools.filter.FunctionImpl;
import org.geotools.filter.capability.FunctionNameImpl;
import org.geotools.filter.text.ecql.ECQL;
import org.opengis.feature.Feature;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.feature.type.Name;
import org.opengis.feature.type.PropertyDescriptor;
import org.opengis.filter.Filter;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Literal;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryComponentFilter;

/**
* Queries a GeoServer layer and extracts the value(s) of an attribute TODO: add sorting
*
* @author Andrea Aime - GeoSolutions
*/
public class QueryFunction extends FunctionImpl {

    Catalog catalog;

    int maxResults;
   
    boolean single;

    public QueryFunction(Name name, Catalog catalog, List<Expression> args, Literal fallback,
            boolean single, int maxResults) {
        this.catalog = catalog;
        this.maxResults = maxResults;
        this.single = single;

        functionName = new FunctionNameImpl(name, args != null ? args.size() : -1);
        setName(name.getLocalPart());
        setFallbackValue(fallback);
        setParameters(args);
       
        if (args.size() < 3 || args.size() > 4) {
            throw new IllegalArgumentException(
                    "QuerySingle function requires 3 or 4 arguments (feature type qualified name, "
                            + "cql filter, extracted attribute name and sort by clause");
        }
    }

    @Override
    public Object evaluate(Object object) {
        FeatureIterator fi = null;
        try {
            // extract layer
            String layerName = getParameters().get(0).evaluate(object, String.class);
            if (layerName == null) {
                throw new IllegalArgumentException(
                        "The first argument should be a vector layer name");
            }
            FeatureTypeInfo ft = catalog.getFeatureTypeByName(layerName);
            if (ft == null) {
                throw new IllegalArgumentException("Could not find vector layer " + layerName
                        + " in the GeoServer catalog");
            }

            // extract and check the attribute
            String attribute = getParameters().get(1).evaluate(object, String.class);
            if (attribute == null) {
                throw new IllegalArgumentException("The second argument of the query "
                        + "function should be the attribute name");
            }
            CoordinateReferenceSystem crs = null;
            PropertyDescriptor ad = ft.getFeatureType().getDescriptor(attribute);
            if (ad == null) {
                throw new IllegalArgumentException("Attribute " + attribute
                        + " could not be found in layer " + layerName);
            } else if(ad instanceof GeometryDescriptor) {
                crs = ((GeometryDescriptor) ad).getCoordinateReferenceSystem();
                if(crs == null) {
                    crs = ft.getCRS();
                }
            }

            // extract and check the filter
            String cql = getParameters().get(2).evaluate(object, String.class);
            if (cql == null) {
                throw new IllegalArgumentException("The third argument of the query "
                        + "function should be a valid (E)CQL filter");
            }
            Filter filter;
            try {
                filter = (Filter) ECQL.toFilter(cql);
            } catch (Exception e) {
                throw new IllegalArgumentException("The third argument of the query "
                        + "function should be a valid (E)CQL filter", e);
            }

            // perform the query
            Query query = new Query(null, filter, new String[] { attribute });
            // .. just enough to judge if we went beyond the limit
            query.setMaxFeatures(maxResults + 1);
            FeatureSource fs = ft.getFeatureSource(null, null);
            fi = fs.getFeatures(query).features();
            List<Object> results = new ArrayList<Object>(maxResults);
            while (fi.hasNext()) {
                Feature f = fi.next();
                Object value = f.getProperty(attribute).getValue();
                if(value instanceof Geometry && crs != null) {
                    // if the crs is not associated with the geometry do so, this
                    // way other code will get to know the crs (e.g. for reprojection purposes)
                    Geometry geom = (Geometry) value;
                    geom.apply(new GeometryCRSFilter(crs));
                }
                results.add(value);
            }

            if (results.size() == 0) {
                return null;
            }
            if (maxResults > 0 && results.size() > maxResults && !single) {
                throw new IllegalStateException("The query in " + getName() + " returns too many "
                        + "features, the limit is " + maxResults);
            }
            if (maxResults == 1) {
                return results.get(0);
            } else {
                return results;
            }

        } catch (IOException e) {
            throw new RuntimeException("Failed to evaluated the query: " + e.getMessage(), e);
        } finally {
            if (fi != null) {
                fi.close();
            }
        }

    }
   
    /**
     * Applies the CRS to all geometry components
     * @author aaime
     *
     */
    static final class GeometryCRSFilter implements GeometryComponentFilter {
        CoordinateReferenceSystem crs;
       
        public GeometryCRSFilter(CoordinateReferenceSystem crs) {
            this.crs = crs;
        }
       
        @Override
        public void filter(Geometry g) {
            g.setUserData(crs);

        }
    }

}
TOP

Related Classes of org.geoserver.filter.function.QueryFunction$GeometryCRSFilter

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.