All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geotools.data.store.ContentFeatureCollection Maven / Gradle / Ivy

Go to download

The main module contains the GeoTools public interfaces that are used by other GeoTools modules (and GeoTools applications). Where possible we make use industry standard terms as provided by OGC and ISO standards. The formal GeoTools public api consists of gt-metadata, jts and the gt-main module. The main module contains the default implementations that are available provided to other GeoTools modules using our factory system. Factories are obtained from an appropriate FactoryFinder, giving applications a chance configure the factory used using the Factory Hints facilities. FilterFactory ff = CommonFactoryFinder.getFilterFactory(); Expression expr = ff.add( expression1, expression2 ); If you find yourself using implementation specific classes chances are you doing it wrong: Expression expr = new AddImpl( expression1, expressiom2 );

The newest version!
/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *    (C) 2002-2015, 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.data.store;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geotools.data.DataUtilities;
import org.geotools.data.FeatureReader;
import org.geotools.data.Join;
import org.geotools.data.Query;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.FeatureTypes;
import org.geotools.feature.SchemaException;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.util.logging.Logging;
import org.locationtech.jts.geom.Point;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.filter.Filter;

/**
 * A FeatureCollection that completely delegates to a backing FetaureSource#getReader
 *
 * @author Jody Garnett (Refractions Research, Inc.)
 */
public class ContentFeatureCollection implements SimpleFeatureCollection {

    protected static final Logger LOGGER = Logging.getLogger(ContentFeatureCollection.class);
    /** feature store the collection originated from. */
    protected ContentFeatureSource featureSource;

    protected Query query;

    /** feature (possibly retyped from feautre source original) type */
    protected SimpleFeatureType featureType;
    /** state of the feature source */
    protected ContentState state;

    protected ContentFeatureCollection(ContentFeatureSource featureSource, Query query) {
        this.featureSource = featureSource;
        this.query = query;

        this.featureType = featureSource.getSchema();

        // retype feature type if necessary
        if (query.getPropertyNames() != Query.ALL_NAMES) {
            this.featureType =
                    SimpleFeatureTypeBuilder.retype(this.featureType, query.getPropertyNames());
        }
        // Check for change in coordinate reference system
        // (Even if featureSource.canReproject the feature reader, we will need to adjust the
        //  featureType generated here to be correct)
        try {
            if (query.getCoordinateSystemReproject() != null) {
                this.featureType =
                        FeatureTypes.transform(
                                this.featureType, query.getCoordinateSystemReproject());
            } else if (query.getCoordinateSystem() != null) {
                this.featureType =
                        FeatureTypes.transform(this.featureType, query.getCoordinateSystem());
            }
        } catch (SchemaException e) {
            LOGGER.log(
                    Level.FINER,
                    "Problem handling Query change of CoordinateReferenceSystem:" + e,
                    e);
        }

        // check for join and expand attributes as necessary
        if (!query.getJoins().isEmpty()) {
            SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
            tb.init(this.featureType);

            for (Join join : query.getJoins()) {
                try {
                    String typeName = join.getTypeName();
                    tb.userData(
                            ContentDataStore.JOINED_FEATURE_TYPE,
                            featureSource.getDataStore().getSchema(typeName));
                } catch (Exception e) {
                    LOGGER.log(Level.WARNING, "Failed to retrieve the joined feature type");
                }

                tb.add(join.attributeName(), SimpleFeature.class);
            }
            this.featureType = tb.buildFeatureType();
        }
    }

    public SimpleFeatureType getSchema() {
        return featureType;
    }

    // Visitors
    public void accepts(
            org.opengis.feature.FeatureVisitor visitor, org.opengis.util.ProgressListener progress)
            throws IOException {
        featureSource.accepts(query, visitor, progress);
    }

    // Iterators
    public static class WrappingFeatureIterator implements SimpleFeatureIterator {

        FeatureReader delegate;

        public WrappingFeatureIterator(FeatureReader delegate) {
            this.delegate = delegate;
        }

        public boolean hasNext() {
            try {
                return delegate.hasNext();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        public SimpleFeature next() throws java.util.NoSuchElementException {
            try {
                return delegate.next();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        public void close() {
            try {
                delegate.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public SimpleFeatureIterator features() {
        try {
            return new WrappingFeatureIterator(featureSource.getReader(query));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public ReferencedEnvelope getBounds() {
        FeatureReader reader = null;
        try {
            ReferencedEnvelope result = featureSource.getBounds(query);
            if (result != null) {
                return result;
            }

            // ops, we have to compute the results by hand. Let's load just the
            // geometry attributes though
            Query q = new Query(query);
            List geometries = new ArrayList();
            for (AttributeDescriptor ad : getSchema().getAttributeDescriptors()) {
                if (ad instanceof GeometryDescriptor) {
                    geometries.add(ad.getLocalName());
                }
            }
            // no geometries, no bounds
            if (geometries.size() == 0) {
                return new ReferencedEnvelope();
            } else {
                q.setPropertyNames(geometries);
            }
            // grab the features and scan through them
            reader = featureSource.getReader(q);
            while (reader.hasNext()) {
                SimpleFeature f = reader.next();
                ReferencedEnvelope featureBounds = ReferencedEnvelope.reference(f.getBounds());
                if (result == null) {
                    result = featureBounds;
                } else if (featureBounds != null) {
                    result.expandToInclude(featureBounds);
                }
            }
            // return the results if we got any, or return an empty one otherwise
            if (result != null) {
                return result;
            } else {
                return ReferencedEnvelope.create(getSchema().getCoordinateReferenceSystem());
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException ex) {
                    // we tried...
                }
            }
        }
    }

    public int size() {
        FeatureReader fr = null;
        try {
            int size = featureSource.getCount(query);
            if (size >= 0) {
                return size;
            } else {
                // we have to iterate, probably best if we do a minimal query that
                // only loads a short attribute
                AttributeDescriptor chosen = getSmallAttributeInSchema();

                // build the minimal query
                Query q = new Query(query);
                if (chosen != null) {
                    q.setPropertyNames(Collections.singletonList(chosen.getLocalName()));
                }
                // bean counting...
                fr = featureSource.getReader(q);
                int count = 0;
                while (fr.hasNext()) {
                    fr.next();
                    count++;
                }
                return count;
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    private AttributeDescriptor getSmallAttributeInSchema() {
        AttributeDescriptor chosen = null;
        for (AttributeDescriptor ad : getSchema().getAttributeDescriptors()) {
            if (chosen == null || size(ad) < size(chosen)) {
                chosen = ad;
            }
        }
        return chosen;
    }

    /**
     * Quick heuristic used to find a small attribute to use when scanning over the entire
     * collection just to get the size of the collection. The result is indicative, just an
     * heuristic to quickly compare attributes in order to find a suitably small one, it's not meant
     * to be the actual size of an attribute in bytes.
     */
    int size(AttributeDescriptor ad) {
        Class binding = ad.getType().getBinding();
        if (binding.isPrimitive()
                || Number.class.isAssignableFrom(binding)
                || Date.class.isAssignableFrom(binding)) {
            return 4;
        } else if (binding.equals(String.class)) {
            int fieldLen = FeatureTypes.getFieldLength(ad);
            if (fieldLen > 0) {
                return fieldLen * 2;
            } else {
                return Integer.MAX_VALUE;
            }
        } else if (Point.class.isAssignableFrom(binding)) {
            return 4 * 3;
        } else {
            return Integer.MAX_VALUE;
        }
    }

    public boolean isEmpty() {
        // build a minimal query
        Query notEmptyQuery = new Query(query);
        notEmptyQuery.setMaxFeatures(1);

        AttributeDescriptor smallAttribute = getSmallAttributeInSchema();
        if (smallAttribute != null) {
            notEmptyQuery.setPropertyNames(
                    Collections.singletonList(smallAttribute.getLocalName()));
        }

        try {
            FeatureReader fr = featureSource.getReader(notEmptyQuery);
            try {
                return !fr.hasNext();
            } finally {
                fr.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    ContentFeatureStore ensureFeatureStore() {
        if (featureSource instanceof ContentFeatureStore) {
            return (ContentFeatureStore) featureSource;
        }
        throw new UnsupportedOperationException("read only");
    }

    public SimpleFeatureCollection sort(org.opengis.filter.sort.SortBy sort) {
        Query query = new Query();
        query.setSortBy(new org.opengis.filter.sort.SortBy[] {sort});

        query = DataUtilities.mixQueries(this.query, query, null);
        return new ContentFeatureCollection(featureSource, query);
    }

    public SimpleFeatureCollection subCollection(Filter filter) {
        Query query = new Query();
        query.setFilter(filter);

        query = DataUtilities.mixQueries(this.query, query, null);
        return new ContentFeatureCollection(featureSource, query);
    }

    //
    // The following were slated to be unsupported by a proposal from
    // jdeolive; since it has not been accepted the following
    // implementations are provided but not recommended
    //
    // There are completely implemented in terms of reader.
    /**
     * Returns true if this collection contains the specified element. .
     *
     * 

This implementation iterates over the elements in the collection, checking each element in * turn for equality with the specified element. * * @param o object to be checked for containment in this collection. * @return true if this collection contains the specified element. */ public boolean contains(Object o) { // TODO: base this on reader SimpleFeatureIterator e = null; try { e = this.features(); if (o == null) { while (e.hasNext()) { if (e.next() == null) { return true; } } } else { while (e.hasNext()) { if (o.equals(e.next())) { return true; } } } return false; } finally { if (e != null) { e.close(); } } } /** * Returns true if this collection contains all of the elements in the specified * collection. * *

* * @param c collection to be checked for containment in this collection. * @return true if this collection contains all of the elements in the specified * collection. * @throws NullPointerException if the specified collection is null. * @see #contains(Object) */ public boolean containsAll(Collection c) { Iterator e = c.iterator(); try { while (e.hasNext()) { if (!contains(e.next())) { return false; } } return true; } finally { if (e instanceof FeatureIterator) { ((FeatureIterator) e).close(); } } } public boolean remove(Object o) { // if( featureSource instanceof SimpleFeatureStore){ // SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource; // if( o instanceof SimpleFeature ){ // SimpleFeature feature = (SimpleFeature) o; // FeatureId fid = feature.getIdentifier(); // FilterFactory ff = CommonFactoryFinder.getFilterFactory(null); // Set ids = Collections.singleton(fid); // Filter remove = ff.id(ids); // try { // featureStore.removeFeatures( remove ); // return true; // } catch (IOException e) { // //LOGGER.log(Level.FINER, e.getMessage(), e); // return false; // unable to remove // } // } // else { // return false; // nothing to do; we can only remove features // } // } throw new UnsupportedOperationException( "Content is not writable; FeatureStore not available"); } /** * Array of all the elements. * * @return an array containing all of the elements in this collection. */ public Object[] toArray() { // code based on AbstractFeatureCollection // TODO: base this on reader ArrayList array = new ArrayList(); FeatureIterator e = null; try { e = features(); while (e.hasNext()) { array.add(e.next()); } return array.toArray(new SimpleFeature[array.size()]); } finally { if (e != null) { e.close(); } } } @SuppressWarnings("unchecked") public T[] toArray(T[] array) { int size = size(); if (array.length < size) { array = (T[]) java.lang.reflect.Array.newInstance( array.getClass().getComponentType(), size); } FeatureIterator it = features(); try { Object[] result = array; for (int i = 0; it.hasNext() && i < size; i++) { result[i] = it.next(); } if (array.length > size) { array[size] = null; } return array; } finally { if (it != null) { it.close(); } } } public String getID() { return null; // Only useful for XML Content } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy