/*
* 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.data;
import java.awt.RenderingHints;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.util.Set;
import org.geotools.feature.FeatureCollection;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;
/**
* Highlevel API for Features from a specific location.
*
* <p>
* Individual Shapefiles, databases tables , etc. are referenced through this
* interface. Compare and constrast with DataStore.
* </p>
*
* <p>
* Differences from DataStore:
* </p>
*
* <ul>
* <li>
* This is a prototype DataSource replacement, the Transaction methods have
* been moved to an external object, and the locking api has been intergrated.
* </li>
* <li>
* FeatureCollection<SimpleFeatureType, SimpleFeature> has been replaced with FeatureResult as we do not wish to
* indicate that results can be stored in memory.
* </li>
* <li>
* FeatureSource<SimpleFeatureType, SimpleFeature> has been split into three interfaces, the intention is to use
* the instanceof opperator to check capabilities rather than the previous
* DataSourceMetaData.
* </li>
* </ul>
*
*
* @author Jody Garnett
* @author Ray Gallagher
* @author Rob Hranac, TOPP
* @author Chris Holmes, TOPP
* @source $URL$
* @version $Id$
*/
public interface FeatureSource<T extends FeatureType, F extends Feature>{
/**
* Returns the qualified name for the Features this FeatureSource serves.
* <p>
* Note this is different from {@code getSchema().getType().getName()} (that
* is, the feature type name), this name specifies the
* {@link PropertyDescriptor#getName() AttributeDescriptor name} for the
* Features served by this source. So,
* {@code FeatureSoruce.getName() == FeatureSource.getFeatures().next().getAttributeDescriptor().getName()}.
* </p>
* <p>
* Though it's a common practice when dealing with {@link SimpleFeatureType}
* and {@link SimpleFeature} to assume they're equal. There's no conflict
* (as per the dynamic typing system the {@code org.opengis.feature} package
* defines) in a Feature and its type sharing the same name, as well as in a
* GML schema an element declaration and a type definition may be named the
* same. Yet, the distinction becomes important as we get rid of that
* assumption and thus allow to reuse a type definition for different
* FeatureSoruces, decoupling the descriptor (homologous to the Feature
* element declaration in a GML schema) from its type definition.
* </p>
* <p>
* So, even if implementors are allowed to delegate to
* {@code getSchema().getName()} if they want to call the fatures and their
* type the same, client code asking a
* {@link DataAccess#getFeatureSource(Name)} shall use this name to request
* for a FeatureSource, rather than the type name, as used in pre 2.5
* versions of GeoTools. For example, if we have a FeatureSource named
* {@code Roads} and its type is named {@code Roads_Type}, the
* {@code DataAccess} shall be queried through {@code Roads}, not
* {@code Roads_Type}.
* </p>
*
* @since 2.5
* @return the name of the AttributeDescriptor for the Features served by
* this FeatureSource
*/
Name getName();
/**
* Information describing the contents of this resoruce.
* <p>
* Please note that for FeatureContent:
* <ul>
* <li>name - unqiue with in the context of a Service
* <li>schema - used to identify the type of resource; usually gml schema; although it may be more specific
* <ul>
*/
ResourceInfo getInfo();
/**
* Access to the DataStore implementing this FeatureStore.
*
* @return DataStore implementing this FeatureStore
*/
DataAccess<T, F> getDataStore();
/**
* Returns and indication of what query capabilities this FeatureSource
* supports natively.
*
* @return a QueryCapabilities object containing the native query capabilities.
* @since 2.5
*/
QueryCapabilities getQueryCapabilities();
/**
* Adds a listener to the list that's notified each time a change to the
* FeatureStore occurs.
*
* @param listener FeatureListener
*/
void addFeatureListener(FeatureListener listener);
/**
* Removes a listener from the list that's notified each time a change to
* the FeatureStore occurs.
*
* @param listener FeatureListener
*/
void removeFeatureListener(FeatureListener listener);
/**
* Loads features from the datasource into the returned FeatureResults,
* based on the passed query.
*
* @param query a datasource query object. It encapsulates requested
* information, such as typeName, maxFeatures and filter.
*
* @return Collection The collection to put the features into.
*
* @throws IOException For all data source errors.
*
* @see Query
*/
FeatureCollection<T, F> getFeatures(Query query) throws IOException;
/**
* Loads features from the datasource into the returned FeatureResults,
* based on the passed filter.
*
* @param filter An OpenGIS filter; specifies which features to retrieve.
* <tt>null</tt> is not allowed, use Filter.INCLUDE instead.
*
* @return Collection The collection to put the features into.
*
* @throws IOException For all data source errors.
*/
FeatureCollection<T, F> getFeatures(Filter filter) throws IOException;
/**
* Loads all features from the datasource into the return FeatureResults.
*
* <p>
* Filter.INCLUDE can also be used to get all features. Calling this function
* is equivalent to using {@link Query#ALL}
* </p>
*
* @return Collection The collection to put the features into.
*
* @throws IOException For all data source errors.
*/
FeatureCollection<T, F> getFeatures() throws IOException;
/**
* Retrieves the featureType that features extracted from this datasource
* will be created with.
*
* <p>
* The schema returned is the LCD supported by all available Features. In
* the common case of shapfiles and database table this schema will match
* that of every feature available. In the degenerate GML case this will
* simply reflect the gml:AbstractFeatureType.
* </p>
*
* @return the schema of features created by this datasource.
*
* @task REVISIT: Our current FeatureType model is not yet advanced enough
* to handle multiple featureTypes. Should getSchema take a
* typeName now that a query takes a typeName, and thus DataSources
* can now support multiple types? Or just wait until we can
* programmatically make powerful enough schemas?
* @task REVISIT: we could also just use DataStore to capture multi
* FeatureTypes?
*/
T getSchema();
/**
* Gets the bounding box of this datasource.
*
* <p>
* With getBounds(Query) this becomes a convenience method for
* getBounds(Query.ALL), that is the bounds for all features contained
* here.
* </p>
*
* <p>
* If getBounds() returns <code>null</code> due to expense consider using
* <code>getFeatures().getBounds()</code> as a an alternative.
* </p>
*
* @return The bounding box of the datasource or null if unknown and too
* expensive for the method to calculate.
*
* @throws IOException if there are errors getting the bounding box.
*
* @task REVISIT: Do we need this or can we use getBounds( Query.ALL )?
*/
ReferencedEnvelope getBounds() throws IOException;
/**
* Gets the bounding box of the features that would be returned by this
* query.
*
* <p>
* To retrieve the bounds of the DataSource please use <code>getBounds(
* Query.ALL )</code>.
* </p>
*
* <p>
* This method is needed if we are to stream features to a gml out, since a
* FeatureCollection<SimpleFeatureType, SimpleFeature> must have a boundedBy element.
* </p>
*
* <p>
* If getBounds(Query) returns <code>null</code> due to expense consider
* using <code>getFeatures(Query).getBounds()</code> as a an alternative.
* </p>
*
* @param query Contains the Filter, and optionally MaxFeatures and StartIndex to
* find the bounds for.
*
* @return The bounding box of the datasource or null if unknown and too
* expensive for the method to calculate or any errors occur.
*
* @throws IOException DOCUMENT ME!
*/
ReferencedEnvelope getBounds(Query query) throws IOException;
/**
* Gets the number of the features that would be returned by this query.
*
* <p>
* If getBounds(Query) returns <code>-1</code> due to expense consider
* using <code>getFeatures(Query).getCount()</code> as a an alternative.
* </p>
* <p>
* This method should take into account the Query's {@link Query#getMaxFeatures() maxFeatures}
* and {@link Query#getStartIndex() startIndex}, if present, in order to
* consistently return the number of features the query would return.
* </p>
*
* @param query Contains the Filter, and optionally MaxFeatures and StartIndex to
* find the count for.
*
* @return The number of Features provided by the Query or <code>-1</code>
* if count is too expensive to calculate or any errors or occur.
*
* @throws IOException if there are errors getting the count
*/
int getCount(Query query) throws IOException;
/**
* Returns the set of hints this {@link FeatureSource} is able to support.<p>
* Hints are to be specified in the {@link Query}, for each data access where they
* may be required.<br>
* Depending on the actual value provide by the user, the {@link FeatureSource}
* may decide not to honor the hint.
* @return a set of {@link RenderingHints#Key} objects (eventually empty, never null).
*/
public Set<RenderingHints.Key> getSupportedHints();
// FeatureReader getFeatureReader( Query query ); // ask justin for proposal
}