Package org.vfny.geoserver.global

Source Code of org.vfny.geoserver.global.GeoServerFeatureSource

/* Copyright (c) 2001, 2003 TOPP - www.openplans.org.  All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.vfny.geoserver.global;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;

import org.geotools.data.DataSourceException;
import org.geotools.data.DataStore;
import org.geotools.data.DefaultQuery;
import org.geotools.data.FeatureListener;
import org.geotools.data.FeatureLocking;

import org.geotools.data.FeatureSource;
import org.geotools.data.FeatureStore;
import org.geotools.data.Query;

import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureType;
import org.geotools.filter.AbstractFilter;
import org.geotools.filter.Filter;
import org.geotools.filter.FilterFactory;
import org.geotools.filter.LogicFilter;

import com.vividsolutions.jts.geom.Envelope;


/**
* GeoServer wrapper for backend Geotools2 DataStore.
*
* <p>
* Support FeatureSource decorator for FeatureTypeInfo that takes care of
* mapping the FeatureTypeInfo's FeatureSource with the schema and definition
* query configured for it.
* </p>
*
* <p>
* Because GeoServer requires that attributes always be returned in the same
* order we need a way to smoothly inforce this. Could we use this class to do
* so?
* </p>
*
* @author Gabriel Rold�n
* @version $Id: GeoServerFeatureSource.java,v 1.8 2004/02/13 18:45:50 dmzwiers Exp $
*/
public class GeoServerFeatureSource implements FeatureSource {
    /** Shared package logger */
    private static final Logger LOGGER = Logger.getLogger(
            "org.vfny.geoserver.global");

    /** FeatureSource being served up */
    protected FeatureSource source;

    /**
     * GeoTools2 Schema information
     *
     * <p>
     * Is this the same as source.getSchema() or is it used supply the order
     * that GeoServer requires attributes to be returned in?
     * </p>
     */
    private FeatureType schema;

    /** Used to constrain the Feature made available to GeoServer. */
    private Filter definitionQuery = Filter.NONE;

    /**
     * Creates a new GeoServerFeatureSource object.
     *
     * @param source GeoTools2 FeatureSource
     * @param schema FeatureType returned by this FeatureSource
     * @param definitionQuery Filter used to limit results
     */
    GeoServerFeatureSource(FeatureSource source, FeatureType schema,
        Filter definitionQuery) {
        this.source = source;
        this.schema = schema;
        this.definitionQuery = definitionQuery;

        if (this.definitionQuery == null) {
            this.definitionQuery = Filter.NONE;
        }
    }

    /**
     * Factory that make the correct decorator for the provided featureSource.
     *
     * <p>
     * This factory method is public and will be used to create all required
     * subclasses. By comparison the constructors for this class have package
     * visibiliy.
     * </p>
     *
     * @param featureSource
     * @param schema DOCUMENT ME!
     * @param definitionQuery DOCUMENT ME!
     *
     * @return
     */
    public static GeoServerFeatureSource create(FeatureSource featureSource,
        FeatureType schema, Filter definitionQuery) {
        if (featureSource instanceof FeatureLocking) {
            return new GeoServerFeatureLocking((FeatureLocking) featureSource,
                schema, definitionQuery);
        } else if (featureSource instanceof FeatureStore) {
            return new GeoServerFeatureStore((FeatureStore) featureSource,
                schema, definitionQuery);
        }

        return new GeoServerFeatureSource(featureSource, schema, definitionQuery);
    }

    /**
     * Takes a query and adapts it to match re definitionQuery filter
     * configured for a feature type.
     *
     * @param query Query against this DataStore
     *
     * @return Query restricted to the limits of definitionQuery
     *
     * @throws IOException See DataSourceException
     * @throws DataSourceException If query could not meet the restrictions of
     *         definitionQuery
     */
    protected Query makeDefinitionQuery(Query query) throws IOException {
        if ((query == Query.ALL) || query.equals(Query.ALL)) {
            return query;
        }

        try {
            String handle = query.getHandle();
            int maxFeatures = query.getMaxFeatures();
            String typeName = query.getTypeName();
            String[] propNames = extractAllowedAttributes(query);
            Filter filter = query.getFilter();
            filter = makeDefinitionFilter(filter);

            return new DefaultQuery(typeName, filter, maxFeatures, propNames,
                handle);
        } catch (Exception ex) {
            throw new DataSourceException(
                "Could not restrict the query to the definition criteria: "
                + ex.getMessage(), ex);
        }
    }

    /**
     * List of allowed attributes.
     *
     * <p>
     * Creates a list of FeatureTypeInfo's attribute names based on the
     * attributes requested by <code>query</code> and making sure they not
     * contain any non exposed attribute.
     * </p>
     *
     * <p>
     * Exposed attributes are those configured in the "attributes" element of
     * the FeatureTypeInfo's configuration
     * </p>
     *
     * @param query User's origional query
     *
     * @return List of allowed attribute types
     */
    private String[] extractAllowedAttributes(Query query) {
        String[] propNames = null;

        if (query.retrieveAllProperties()) {
            propNames = new String[schema.getAttributeCount()];

            for (int i = 0; i < schema.getAttributeCount(); i++) {
                propNames[i] = schema.getAttributeType(i).getName();
            }
        } else {
            String[] queriedAtts = query.getPropertyNames();
            int queriedAttCount = queriedAtts.length;
            List allowedAtts = new LinkedList();

            for (int i = 0; i < queriedAttCount; i++) {
                if (schema.getAttributeType(queriedAtts[i]) != null) {
                    allowedAtts.add(queriedAtts[i]);
                } else {
                    LOGGER.info("queried a not allowed property: "
                        + queriedAtts[i] + ". Ommitting it from query");
                }
            }

            propNames = (String[]) allowedAtts.toArray(new String[allowedAtts
                    .size()]);
        }

        return propNames;
    }

    /**
     * If a definition query has been configured for the FeatureTypeInfo, makes
     * and return a new Filter that contains both the query's filter and the
     * layer's definition one, by logic AND'ing them.
     *
     * @param filter Origional user supplied Filter
     *
     * @return Filter adjusted to the limitations of definitionQuery
     *
     * @throws DataSourceException If the filter could not meet the limitations
     *         of definitionQuery
     */
    protected Filter makeDefinitionFilter(Filter filter)
        throws DataSourceException {
        Filter newFilter = filter;

        try {
            if (definitionQuery != Filter.NONE) {
                FilterFactory ff = FilterFactory.createFilterFactory();
                newFilter = ff.createLogicFilter(AbstractFilter.LOGIC_AND);
                ((LogicFilter) newFilter).addFilter(definitionQuery);
                ((LogicFilter) newFilter).addFilter(filter);
            }
        } catch (Exception ex) {
            throw new DataSourceException("Can't create the definition filter",
                ex);
        }

        return newFilter;
    }

    /**
     * Implement getDataStore.
     *
     * <p>
     * Description ...
     * </p>
     *
     * @return
     *
     * @see org.geotools.data.FeatureSource#getDataStore()
     */
    public DataStore getDataStore() {
        return source.getDataStore();
    }

    /**
     * Implement addFeatureListener.
     *
     * <p>
     * Description ...
     * </p>
     *
     * @param listener
     *
     * @see org.geotools.data.FeatureSource#addFeatureListener(org.geotools.data.FeatureListener)
     */
    public void addFeatureListener(FeatureListener listener) {
        source.addFeatureListener(listener);
    }

    /**
     * Implement removeFeatureListener.
     *
     * <p>
     * Description ...
     * </p>
     *
     * @param listener
     *
     * @see org.geotools.data.FeatureSource#removeFeatureListener(org.geotools.data.FeatureListener)
     */
    public void removeFeatureListener(FeatureListener listener) {
        source.removeFeatureListener(listener);
    }

    /**
     * Implement getFeatures.
     *
     * <p>
     * Description ...
     * </p>
     *
     * @param query
     *
     * @return
     *
     * @throws IOException
     *
     * @see org.geotools.data.FeatureSource#getFeatures(org.geotools.data.Query)
     */
    public FeatureCollection getFeatures(Query query) throws IOException {
        Query newQuery = makeDefinitionQuery(query);
       
        // see if the CRS got xfered over
           // a. old had a CRS, new doesnt
        boolean requireXferCRS = (newQuery.getCoordinateSystem() == null) && (query.getCoordinateSystem() != null);
        if ((newQuery.getCoordinateSystem() != null) && (query.getCoordinateSystem() != null))
        {
           //b. both have CRS, but they're different
          requireXferCRS = !(newQuery.getCoordinateSystem().equals(query.getCoordinateSystem()));
        }
         
        if ( requireXferCRS )
        {
          //carry along the CRS
          if (!(newQuery instanceof DefaultQuery))
            newQuery = new DefaultQuery(newQuery);
          ((DefaultQuery)newQuery).setCoordinateSystem( query.getCoordinateSystem());
        }

        return source.getFeatures(newQuery);
    }

    /**
     * Implement getFeatures.
     *
     * <p>
     * Description ...
     * </p>
     *
     * @param filter
     *
     * @return
     *
     * @throws IOException
     *
     * @see org.geotools.data.FeatureSource#getFeatures(org.geotools.filter.Filter)
     */
    public FeatureCollection getFeatures(Filter filter) throws IOException {
        filter = makeDefinitionFilter(filter);

        return source.getFeatures(filter);
    }

    /**
     * Implement getFeatures.
     *
     * <p>
     * Description ...
     * </p>
     *
     * @return
     *
     * @throws IOException
     *
     * @see org.geotools.data.FeatureSource#getFeatures()
     */
    public FeatureCollection getFeatures() throws IOException {
        if (definitionQuery == Filter.NONE) {
            return source.getFeatures();
        } else {
            return source.getFeatures(definitionQuery);
        }
    }

    /**
     * Implement getSchema.
     *
     * <p>
     * Description ...
     * </p>
     *
     * @return
     *
     * @see org.geotools.data.FeatureSource#getSchema()
     */
    public FeatureType getSchema() {
        return schema;
    }

    /**
     * Retrieves the total extent of this FeatureSource.
     *
     * <p>
     * Please note this extent will reflect the provided definitionQuery.
     * </p>
     *
     * @return Extent of this FeatureSource, or <code>null</code> if no
     *         optimizations exist.
     *
     * @throws IOException If bounds of definitionQuery
     */
    public Envelope getBounds() throws IOException {
        if (definitionQuery == Filter.NONE) {
            return source.getBounds();
        } else {
            Query query = new DefaultQuery(getSchema().getTypeName(),
                    definitionQuery);

            return source.getBounds(query);
        }
    }

    /**
     * Retrive the extent of the Query.
     *
     * <p>
     * This method provides access to an optimized getBounds opperation. If no
     * optimized opperation is available <code>null</code> will be returned.
     * </p>
     *
     * <p>
     * You may still make use of getFeatures( Query ).getCount() which will
     * return the correct answer (even if it has to itterate through all the
     * results to do so.
     * </p>
     *
     * @param query User's query
     *
     * @return Extend of Query or <code>null</code> if no optimization is
     *         available
     *
     * @throws IOException If a problem is encountered with source
     */
    public Envelope getBounds(Query query) throws IOException {
        try {
            query = makeDefinitionQuery(query);
        } catch (IOException ex) {
            return null;
        }

        return source.getBounds(query);
    }

    /**
     * Adjust query and forward to source.
     *
     * <p>
     * This method provides access to an optimized getCount opperation. If no
     * optimized opperation is available <code>-1</code> will be returned.
     * </p>
     *
     * <p>
     * You may still make use of getFeatures( Query ).getCount() which will
     * return the correct answer (even if it has to itterate through all the
     * results to do so).
     * </p>
     *
     * @param query User's query.
     *
     * @return Number of Features for Query, or -1 if no optimization is
     *         available.
     */
    public int getCount(Query query) {
        try {
            query = makeDefinitionQuery(query);
        } catch (IOException ex) {
            return -1;
        }
        try{
          return source.getCount(query);
        }catch(IOException e){return 0;}
    }
}
TOP

Related Classes of org.vfny.geoserver.global.GeoServerFeatureSource

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.