DataStore¶
The core data access model for vector information in GeoTools is built around the DataStore class.
Here is a quick example of accessing a shapefile:
File file = new File("example.shp");
Map map = new HashMap();
map.put( "url", file.toURL() );
DataStore dataStore = DataStoreFinder.getDataStore(map );
References:
gt-main DataStore Code Examples
javadoc: DataStore
javadoc: FeatureSource
javadoc: SimpleFeatureSource
DataAccess¶
DataAccess represents a storage location or service for spatial data.
The DataAccess<T,F> defined as:
T:FeatureType- class used to describe content.Currently
FeatureTypeandSimpleFeatureTypeare available)F:Feature- class used to represent content.Currently
FeatureandSimpleFeatureare available.DataStoreis a short hand forDataAccess<SimpleFeatureType,SimpleFeature>with a few extra methods allowing the contents to be accessed using a type name defined as a simple String
You can use the DataAccess interface to get a list of the contents, retrieve a little bit of information about the contents (such as their name, bounds and description). To actually retrieve the data contents you will ask the DataAccess interface for a FeatureSource based on the content Name (using the Name) of the features that you want. We will discuss FeatureSource in the next section.
Here are two examples of these ideas in action:
ShapeFileDataStorerepresents the file on disk,FeatureSourcerepresents the contents of the filePostGISDataStorerepresents the database, while aFeatureSourcerepresents a table in the database
The key differences is between the file and the contents of the file. If you find it easier you can think of it as the difference between:
DataStore: the information contained in the file header (name, bounds, description) that describe the entire contentsFeatureSource: the information contained in the file itself (lots of little features)
Here is a quick review of the DataAccess methods:
DataAccess.getInfo()Access a quick description of the service or file publishing information.:
ServiceInfo info = dataStore.getInfo(); // Human readable name and description String title = info.getTitle(); String text = info.getDescription(); // keywords (dublin core keywords like a web page) Set<String> keywords = info.getKeywords(); // formal metadata URI publisher = info.getPublisher(); // authority publishing data URI schema = info.getSchema(); // used for data conforming to a standard URI source = info.getSource(); // location where information is published from
Some
DataStores, like Web Feature Server, may provide additional information in the object they return fromgetInfo().DataAccess.createSchema(FeatureType)Used to define the contents of a shapefile, or add a new table to database. Not supported by all
DataStores.SimpleFeatureType schema = DataUtilities.createType("LINE", "centerline:LineString,name:\"\",id:0"); dataStore.createSchema(schema);
DataAccess.updateSchema(Name, FeatureType)Used to modify the contents of a shapefile, or alter an existing table. Not supported by all
dataStores.DataAccess.removeSchema(Name)Used to remove an existing table. Not supported by all
dataStores.Name schemaName = new NameImpl("myTable"); dataStore.removeSchema(schemaName);
DataAccess.getNames()DataAccess.getSchema(Name)DataAccess.getFeatureSource(Name): FeatureSource<FeatureType,Feature>DataAccess.dispose()Used to clean up any internal connections or memory used by the DataStore. Should be called prior to your application exiting.:
if( dataStore != null ){ dataStore.dispose(); dataStore = null; }
DataStore¶
The DataStore interface is a DataAccess subclass that provides to explicitly work with content providers that only know how to deal with SimpleFeature and SimpleFeatureType.
DataStore.updateSchema(String, SimpleFeatureType)DataStore.removeSchema(String)DataStore.getTypeNames()Access an
String[]ofName.getLocalName()DataStore.getSchema(String)Access to
SimpleFeatureTypebased on name.DataStore.getFeatureSource(String)DataStore.getFeatureSource(Name)You can access
SimpleFeatureSourcebased on a type name supplied as aNameor aString.DataStore.getFeatureReader(Query, Transaction)DataStore.getFeatureWriter(String, Filter, Transaction)DataStore.getFeatureWriter(String, Transaction)DataStore.getFeatureWriterAppend(String, Transaction)Access to a low-level
FeatureReaderandFeatureWriterclass allowing direct access toDataStorecontents (complete withIOExceptions).The various
FeatureWritermethods require aTransaction(i.e. session) to perform their work on, and allow existing content to be updated or new content to be appended.DataStore.getLockingManager()Access to the
LockingManagerused to sort out any time based locks acquired on to restrict access when multiple threads are working on the same information.
FeatureSource¶
A FeatureSource is used to provide access to the contents of a DataStore.
Approach
As you can see FeatureSource provides different subclasses depending on the
level of access available. So a read-only file will be an instanceof FeatureSource
while a writable file will be able to return a FeatureStore.
To check if the contents of a file are writable you can use an instanceof check:
SimpleFeatureSource featureSource = dataStore.getFeatureSource( "roads" );
if( featureSource instanceof SimpleFeatureStore ){
SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
Transaction session = new DefaultTransaction("Adding");
featureStore.setTransaction( session );
try {
List<FeatureId> added = featureStore.addFeatures( featureCollection );
System.out.println( "Added "+added );
session.commit();
}
catch (Throwable t){
System.out.println( "Failed to add features: "+t );
session.rollback();
}
}
This approach is nice in that you cannot accidentally modify a read-only file (as your
would get a ClassCastException):
// ClassCastException if "roads" is not writable!
SimpleFeatureStore featureStore = (SimpleFeatureStore) dataStore.getFeatureSource( "roads" );
store.addFeatures( newFeatures );
In a similar fashion you can check if locking is supported between threads:
if( featureStore instanceof SimpleFeatureLocking ){
// locking supported
}
SimpleFeatureSource¶
SimpleFeatueSource is the extension of FeatureSource returned by DataStore to explicitly work with
SimpleFeature and SimpleFeatureCollection.
Access to basic name and schema information:
FeatureSource.getName()FeatureSource.getSchema()FeatureSource.getDataStore()
Access to contents:
FeatureSource.getFeatures()FeatureSource.getFeatures(Filter)FeatureSource.getFeatures(Query)SimpleFeatureSource.getFeatures()SimpleFeatureSource.getFeatures( Filter )SimpleFeatureSource.getFeatures( Query )In the case of
SimpleFeatureSourcethese methods will return aSimpleFeatureCollection.
Access to metadata describing the contents and capabilities available.
FeatureSource.getInfo()FeatureSource.getSupportedHints()FeatureSource.getQueryCapabilities()
You can listen to changes made to the contents:
FeatureSource.addFeatureListener(FeatureListener)FeatureSource.removeFeatureListener(FeatureListener)
Summary information:
FeatureSource.getBounds()FeatureSource.getBounds(Query)May return null if the bounds are unknown or too costly to calculate.
FeatureSource.getCount(Query)May return -1 if the information is not readily available. Formats such as shapefile keep this information available in the header for handy reference. WFS does not provide any way to ask for this information and thus always returns -1.
Where a request is captured by a Query:
QueryUsed to stage a request for information, identifying a set of features using a filter, the attributes requested along with any additional hints for processing.
There are two predefined types of
Queryavailable:Query.ALL- to request all contentQuery.FIDS- To request only the feature IDs with no content
The
typeNameinformation must match yourfeatureSource(and explicitly required when sending aQuerydirectly to aDataStore).Query.getTypeName()Query.setTypeName(String)
Namespacecan be overridden.Query.getNamespace()Query.setNamespace(URI)Override to request a specific namespace, or use
Query.NON_NAMESPACE.
Simple string “handle” to identify this query in any logs or error messages.
Query.getHandle()Query.setHandle(String)
Paging support is available using a start and maximum features as part of your Query.
Query.getMaxFeatures()Query.isMaxFeaturesUnlimited()Query.setMaxFeatures(int)Query.getStartIndex()Query.setStartIndex(Integer)
Specify the set of requested attributes to return:
Query.getPropertyNames()Query.setPropertyNames(String[])Query.setPropertyNames(List<String>)Query.retrieveAllProperties()
There are a couple well defined constants:
Query.NO_NAMESQuery.ALL_NAMES
The same options are available using
PropertyNamein order to support XPath expressions with namespace information.Query.getProperties()Query.setProperties(List<PropertyName>)There are a couple of well defined constants:
Query.NO_PROPERTIESQuery.ALL_PROPERTIES
Query.getFilter()Query.setFilter(Filter)
When working with versioned data you ask for a specific version.
Query.getVersion()Query.setVersion(String)
Override this value in the event the
DataSourceis incorrect and your user knows the correctCoordinateReferenceSystem.Query.getCoordinateSystem()Query.setCoordinateSystem(CoordinateReferenceSystem)
Used to transform the information to requested
CoordinateReferenceSystem.Query.getCoordinateSystemReproject()Query.setCoordinateSystemReproject(CoordinateReferenceSystem)
Ask for the results to be sorted as indicated
Query.getSortBy()Query.setSortBy(SortBy[])
Open ended hints (check
getSupportedHints()for details)Query.getHints()Query.setHints(Hints)Example:
query.setHints( new Hints( Query.INCLUDE_MANDITORY_PROPS, Boolean.TRUE ) );
Examples:
How to count the number of features.
Because the
getCountmethod just checks the file or database header information it is designed to be very fast. Not all implementations have access to this information making it a bit tricky to count the number of available features.The following code shows how to quickly count all the features available:
int count = featureSource.getCount(Query.ALL); if (count == -1) { count = featureSource.getFeatures().size(); }
You can modify this to use your own Query:
Query query = new Query("typeName", CQL.toFilter("REGION = 3")); int count = featureSource.getCount(query); if (count == -1) { count = featureSource.getFeatures(query).size(); }
SimpleFeatureStore¶
SimpleFeatureStore is an extension to FeatureStore returning SimpleFeatureCollection as expected and allowing the contents
to be modified using a simple String to indicate attribute.
Ability to add and remove features:
FeatureStore.addFeatures(FeatureCollection<T, F>)FeatureStore.removeFeatures(Filter)
Ability to modify feature attributes in place using a Filter to select the content to modify:
FeatureStore.modifyFeatures(Name[], Object[], Filter)FeatureStore.modifyFeatures(AttributeDescriptor[], Object[], Filter)FeatureStore.modifyFeatures(Name, Object, Filter)FeatureStore.modifyFeatures(AttributeDescriptor, Object, Filter)SimpleFeatureStore.modifyFeatures(String, Object, Filter)SimpleFeatureStore.modifyFeatures(String[], Object[], Filter)SimpleFeatureStoreallows attribute information to be represented as a simpleString.
Transaction control:
FeatureStore.setTransaction(Transaction)FeatureStore.getTransaction()
Reset the entire contents of the FeatureStore:
FeatureStore.setFeatures(FeatureReader<T, F>)
Session information is captured using a Transaction:
TransactionUsed to control the current editing process and close the transaction when it is completed.
Transaction.commit()Transaction.rollback()Transaction.close()
Transaction properties used to hold values for the duration of a transaction.
Transaction.putProperty(Object, Object)Transaction.getProperty(Object)
Authorizationacquired using aFeatureLockrequest *Transaction.addAuthorization(String)*Transaction.getAuthorizations()There is also a placeholder
Transaction.AUTO_COMMITavailable to configure aFeatureStoreto write out each change as it occurs.For internal use
Transactionalso holds session information for commit and rollback.Transaction.putState(Object, State)Transaction.removeState(Object)Transaction.getState(Object)
SimpleFeatureLocking¶
FeatureLocking adds a couple of methods to support the idea of time based locking. Each lock request
is made for a specific duration, if attempt to modify the locked features requires an authorization
code. Any modifications made without the authorization code will result in an error. Authorization
codes can be configured per transaction (and may in fact apply to more than one DataStore).
Here are the methods for FeatureLocking:
FeatureLocking.setFeatureLock(FeatureLock)Set the
FeatureLockbeing requested.FeatureLocking.lockFeatures(Query)FeatureLocking.lockFeatures(Filter)FeatureLocking.lockFeatures()Lock all features, or limit the features being locked with a filter or query.
FeatureLocking.unLockFeatures()FeatureLocking.unLockFeatures(Filter)FeatureLocking.unLockFeatures(Query)Called to release features.
Session information for FeatureLocking is captured with a FeatureLock. This represents the request being
made with each call to lockFeatures.
FeatureLockUsed to configure a
FeatureLockingto request that features be locked for a set duration of time.FeatureLock.getDuration()
Resulting in a set of authorization
Strings. These strings can be used to configure aTransactionallowing locked features to be operated on.FeatureLock.getAuthorization()
DataAccessFactorySpi¶
To create a DataStore GeoTools uses a plugin system based around the DataStoreFactorySpi class.
For most purposes this class is an internal detail, however if you want to look at all the supported formats on the CLASSPATH you can ask DataStoreFinder for the complete list.:
for( Iterator i=DataStoreFinder.getAvailableDataStores(); i.hasNext(); ){
DataStoreFactorySpi factory = (DataStoreFactorySpi) i.next();
System.out.println( factory.getDisplayName() );
}
DataAccessFactory.createDataStore(Map<String, ?>)DataStoreFactorySpi.createDataStore(Map<String, ?>)Used to create a
DataStoreusing the provided map of connection parameters. Please note this is used to connect to an existing source of information such as an existing shapefile or an existing web feature server.DataStoreFactorySpi.createNewDataStore(Map<String, ?>)Used to create a new storage location (example a new shapefile).
DataAccessFactory.getDisplayName()DataAccessFactory.getDescription()Human readable name and description.
DataAccessFactory.getParametersInfo()Description of connection parameters.
DataAccessFactory.canProcess(Map<String, ?>)Used to check the required connection parameters and confirm they can be processed into a DataStore. Note the DataStore may still not work (if for example the username and password were incorrect).
This method confirms the required information is available.
DataAccessFactory.isAvailable()Some formats require additional jars to be available on the
CLASSPATH. As an example database formats often require a JDBC driver to be present.This method will perform a check and confirm that the needed dependencies are available providing a smooth way for the
DataAccessFactoryto report if it is unable to connect.