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

org.geotools.data.store.ContentDataStore 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) 2011-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.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import org.geotools.data.DataAccess;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFactorySpi;
import org.geotools.data.DefaultServiceInfo;
import org.geotools.data.FeatureReader;
import org.geotools.data.FeatureWriter;
import org.geotools.data.InProcessLockingManager;
import org.geotools.data.LockingManager;
import org.geotools.data.Query;
import org.geotools.data.ServiceInfo;
import org.geotools.data.Transaction;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureTypes;
import org.geotools.feature.NameImpl;
import org.locationtech.jts.geom.GeometryFactory;
import org.opengis.feature.FeatureFactory;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.FeatureTypeFactory;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.util.TypeName;

/**
 * Abstract base class for data stores.
 *
 * 

A datastore contains a set of entries ({@link ContentEntry}). Each entry corresponds to a * "real world dataset". For instance, a shapefile datastore would contain a single entry which * would represent the shapefile on disk. A postgis datastore could contain many entries, one for * each table in the database. * *

Each entry is identified by a name ({@link Name}). The name can be qualified with a namespace * uri, or unqualified (in which the namespace uri is null). An example of a datastore that might * use qualified names is WFS, where in each entry corresponds to a WFS "Feature Type", which have * namespace qualified name. Other datastores (such as databases) use unqualified names. * *

When entry names of a datastore are unqualified, a default namespace uri can be set "globally" * on the datastore itself, see {@link #setNamespaceURI(String)}. When this value is set, * unqualified entry names are implicitly qualified with the global namespace uri. * *

Subclasses

* *

At a minimum subclasses must implement the following methods: * *

    *
  • {@link #createTypeNames()} *
  • {@link #createFeatureSource(ContentEntry)} *
* * The following methods may also be overriden: * *
    *
  • {@link #createContentState(ContentEntry)} *
* * The following methods may be overriden but only to narrow the return type to a specific * subclass of {@link ContentFeatureSource}. * *
    *
  • {@link #getFeatureSource(String)} *
  • {@link #getFeatureSource(String, Transaction)} *
  • {@link #getFeatureSource(Name, Transaction)} *
* * @author Jody Garnett, Refractions Research Inc. * @author Justin Deoliveira, The Open Planning Project * @author Niels Charlier */ public abstract class ContentDataStore implements DataStore { /** * When joining feature types, the UserData of the joined attribute descriptors will contain * their full feature type under this key */ public static final String JOINED_FEATURE_TYPE = "JoinedFeatureType"; /** Flag writer for adding new content */ protected static final int WRITER_ADD = 0x01 << 0; /** Flag writer for updating content in place */ protected static final int WRITER_UPDATE = 0x01 << 1; /** Flag writer for commit (AUTO_COMMIT with no events) */ protected static final int WRITER_COMMIT = 0x01 << 2; /** name, entry map */ protected final Map entries; /** logger */ protected final Logger LOGGER; /** Factory used to create feature types */ protected FeatureTypeFactory typeFactory; /** Factory used to create features */ protected FeatureFactory featureFactory; /** Factory used to create filters */ protected FilterFactory filterFactory; /** Factory used to create geometries */ protected GeometryFactory geometryFactory; /** namespace uri of the datastore itself, or default namespace */ protected String namespaceURI; /** locking manager */ protected LockingManager lockingManager = new InProcessLockingManager(); /** factory used to create the datastore */ protected DataStoreFactorySpi dataStoreFactory; public ContentDataStore() { // get a concurrent map so that we can do reads in parallel with writes (writes vs writes // are actually synchronized to prevent double work, see getEntry()). this.entries = new ConcurrentHashMap(); // grabbing the logger here makes the logger name polymorphic (the name of the actual // subclass will be used this.LOGGER = org.geotools.util.logging.Logging.getLogger(getClass()); // default setFilterFactory(CommonFactoryFinder.getFilterFactory()); } // // Property accessors // /** The factory used to create feature types. */ public FeatureTypeFactory getFeatureTypeFactory() { return typeFactory; } /** Sets the factory used to create feature types. */ public void setFeatureTypeFactory(FeatureTypeFactory typeFactory) { this.typeFactory = typeFactory; } /** Sets the factory used to create features. */ public void setFeatureFactory(FeatureFactory featureFactory) { this.featureFactory = featureFactory; } /** The factory used to create filters. */ public FilterFactory getFilterFactory() { return filterFactory; } /** The factory used to create features. */ public FeatureFactory getFeatureFactory() { return featureFactory; } /** Sets the factory used to create filters. */ public void setFilterFactory(FilterFactory filterFactory) { this.filterFactory = filterFactory; } /** The factory used to create geometries. */ public GeometryFactory getGeometryFactory() { return geometryFactory; } /** Sets the factory used to create geometries. */ public void setGeometryFactory(GeometryFactory geometryFactory) { this.geometryFactory = geometryFactory; } /** * Returns the factory used to create the data store. * * @return The data store factory, possibly null. */ public DataStoreFactorySpi getDataStoreFactory() { return dataStoreFactory; } /** * Sets the data store factory used to create the datastore. * *

WARNING: This property should only be set in cases where the datastore factory is * stateless and does not maintain any references to created datastores. Setting this property * in such a case will result in a memory leak. */ public void setDataStoreFactory(DataStoreFactorySpi dataStoreFactory) { this.dataStoreFactory = dataStoreFactory; } /** * The namespace uri of the datastore. * * @return The namespace uri, may be null. */ public String getNamespaceURI() { return namespaceURI; } /** * Sets the namespace uri of the datastore. * *

This will be used to qualify the entries or types of the datastore. * * @param namespaceURI The namespace uri, may be null. */ public void setNamespaceURI(String namespaceURI) { this.namespaceURI = namespaceURI; } /** The logger for the datastore. */ public Logger getLogger() { return LOGGER; } // // DataStore API // public ServiceInfo getInfo() { DefaultServiceInfo info = new DefaultServiceInfo(); info.setDescription("Features from " + getClass().getSimpleName()); info.setSchema(FeatureTypes.DEFAULT_NAMESPACE); return info; } /** * Returns the names of all entries or types provided by the datastore. * *

This method is marked final and delegates to {@link #createTypeNames()}, which subclasses * are intended to implement. * * @see DataStore#getTypeNames() */ public final String[] getTypeNames() throws IOException { List typeNames = createTypeNames(); String[] names = new String[typeNames.size()]; for (int i = 0; i < typeNames.size(); i++) { Name typeName = typeNames.get(i); names[i] = typeName.getLocalPart(); } return names; } /** * Creates a new schema in the datastore. * *

This implementation throws a{@link UnsupportedOperationException}. Subclasses should * override to support schema creation. * * @see DataStore#createSchema(FeatureType) */ public void createSchema(SimpleFeatureType featureType) throws IOException { throw new UnsupportedOperationException(); } /** * Returns the feature type or schema matching the specified name. * *

This method calls through to getFeatureSource(typeName).getSchema() * * @see DataStore#getSchema(String) */ public final SimpleFeatureType getSchema(String typeName) throws IOException { ContentFeatureSource featureSource = getFeatureSource(typeName); return featureSource.getSchema(); } /** * Returns the feature source matching the specified name. * *

Subclasses should not implement this method. However overriding in order to perform a type * narrowing to a subclasses of {@link ContentFeatureSource} is acceptable. * * @see DataStore#getFeatureSource(String) */ public ContentFeatureSource getFeatureSource(String typeName) throws IOException { return getFeatureSource(new NameImpl(null, typeName), Transaction.AUTO_COMMIT); } /** * Returns the feature source matching the specified name and explicitly specifies a * transaction. * *

Subclasses should not implement this method. However overriding in order to perform a type * narrowing to a subclasses of {@link ContentFeatureSource} is acceptable. * * @see DataStore#getFeatureSource(String) */ public ContentFeatureSource getFeatureSource(String typeName, Transaction tx) throws IOException { return getFeatureSource(new NameImpl(null, typeName), tx); } /** * Returns the feature source matching the specified name and explicitly specifies a * transaction. * *

Subclasses should not implement this method. However overriding in order to perform a type * narrowing to a subclasses of {@link ContentFeatureSource} is acceptable. * * @see DataStore#getFeatureSource(String) */ public ContentFeatureSource getFeatureSource(Name typeName, Transaction tx) throws IOException { ContentEntry entry = ensureEntry(typeName); ContentFeatureSource featureSource = createFeatureSource(entry); featureSource.setTransaction(tx); // if ( tx != Transaction.AUTO_COMMIT ) { // //setup the transaction state // synchronized (tx) { // if ( tx.getState( typeName ) == null ) { // tx.putState( typeName, createTransactionState(featureSource) ); // } // } // } return featureSource; } /** * Returns a feature reader for the specified query and transaction. * *

This method is not intended to be overridden and is marked final. This implementation * delegates to {@link FeatureCollection} and wraps an iterator in a {@link FeatureReader}. */ public FeatureReader getFeatureReader( Query query, Transaction tx) throws IOException { if (query.getTypeName() == null) { throw new IllegalArgumentException("Query does not specify type."); } return getFeatureSource(query.getTypeName(), tx).getReader(query); } /** * Returns a feature writer for the specified query and transaction. * *

This method is not intended to be overridden and is marked final. This implementation * delegates to {@link FeatureCollection} and wraps an iterator in a {@link FeatureWriter}. */ public FeatureWriter getFeatureWriter( String typeName, Filter filter, Transaction tx) throws IOException { ContentFeatureStore featureStore = ensureFeatureStore(typeName, tx); return featureStore.getWriter(filter, WRITER_UPDATE | WRITER_ADD); } /** * Helper method which gets a feature source ensuring that it is a feature store as well. If not * it throws an IOException. * * @param typeName The name of the feature source. * @param tx A transaction handle. * @throws IOException If the feature source is not a store. */ protected final ContentFeatureStore ensureFeatureStore(String typeName, Transaction tx) throws IOException { ContentFeatureSource featureSource = getFeatureSource(typeName, tx); if (!(featureSource instanceof ContentFeatureStore)) { throw new IOException(typeName + " is read only"); } return (ContentFeatureStore) featureSource; } /** * Returns a feature writer for the specified type name and transaction. * *

This method is convenience for getFeatureWriter(typeName,Filter.INCLUDE,tx). */ public final FeatureWriter getFeatureWriter( String typeName, Transaction tx) throws IOException { return getFeatureWriter(typeName, Filter.INCLUDE, tx); } /** * Returns an appending feature writer for the specified type name and transaction. * *

This method is not intended to be overridden and is marked final. This implementation * delegates to {@link FeatureCollection} and wraps an iterator in a {@link FeatureWriter}. */ public final FeatureWriter getFeatureWriterAppend( String typeName, Transaction tx) throws IOException { ContentFeatureStore featureStore = ensureFeatureStore(typeName, tx); FeatureWriter writer = featureStore.getWriter(Filter.INCLUDE, WRITER_ADD); // ensure we are at the "end" as we are being asked to return this in "append" mode while (writer.hasNext()) { writer.next(); } return writer; } public final LockingManager getLockingManager() { return lockingManager; } public final void updateSchema(String typeName, SimpleFeatureType featureType) throws IOException { throw new UnsupportedOperationException(); } public void dispose() { for (ContentEntry entry : entries.values()) { entry.dispose(); } entries.clear(); } /** Returns the entry for a specified name, or null if no such entry exists. */ public ContentEntry getEntry(Name name) { return entries.get(name); } // // Internal API // /** * Instantiates a new content state for the entry. * *

Subclasses may override this method to return a specific subclass of {@link ContentState}. * * @param entry The entry. * @return A new instance of {@link ContentState} for the entry. */ protected ContentState createContentState(ContentEntry entry) { return new ContentState(entry); } /** Helper method to wrap a non-qualified name. */ protected final Name name(String typeName) { return new NameImpl(namespaceURI, typeName); } /** * Helper method to look up an entry in the datastore. * *

This method will create a new instance of {@link ContentEntry} if one does not exist. * *

In the event that the name does not map to an entry and one cannot be created null * will be returned. Note that {@link #ensureEntry(TypeName)} will throw an exception in * this case. * * @param name The name of the entry. * @return The entry, or null if it does not exist. */ protected final ContentEntry entry(Name name) throws IOException { ContentEntry entry = null; boolean found = entries.containsKey(name); boolean unqualifiedSearch = name.getNamespaceURI() == null; if (!found && unqualifiedSearch && this.namespaceURI != null) { Name defaultNsName = new NameImpl(namespaceURI, name.getLocalPart()); if (entries.containsKey(defaultNsName)) { name = defaultNsName; found = true; } } if (!found) { // refresh the entries (calling createTypeNames() can be quite expensive, // make it count) and do namespace-less matches as required List typeNames = createTypeNames(); for (Name tn : typeNames) { synchronized (this) { if (!entries.containsKey(tn)) { entry = new ContentEntry(this, tn); entries.put(tn, entry); } } // do namespace-less matching if necessary if (!found && (tn.equals(name) || (unqualifiedSearch && tn.getLocalPart().equals(name.getLocalPart())))) { name = tn; found = true; } } } return entries.get(name); } /** * Helper method to look up an entry in the datastore which throws an {@link IOException} in the * event that the entry does not exist. * * @param name The name of the entry. * @return The entry. * @throws IOException If the entry does not exist, or if there was an error looking it up. */ protected final ContentEntry ensureEntry(Name name) throws IOException { ContentEntry entry = entry(name); if (entry == null) { throw new IOException("Schema '" + name + "' does not exist."); } return entry; } /** * Helper method to remove an entry from the cached entry map. * * @param name The name of the entry. */ protected final void removeEntry(Name name) { if (entries.containsKey(name)) { entries.remove(name); } } /** * Creates a set of qualified names corresponding to the types that the datastore provides. * *

Namespaces may be left null for data stores which do not support namespace * qualified type names. * * @return A list of {@link Name}. * @throws IOException Any errors occuring connecting to data. */ protected abstract List createTypeNames() throws IOException; /** * Instantiates new feature source for the entry. * *

Subclasses should override this method to return a specific subclass of {@link * ContentFeatureSource}. * * @param entry The entry. * @return An new instance of {@link ContentFeatureSource} for the entry. */ protected abstract ContentFeatureSource createFeatureSource(ContentEntry entry) throws IOException; /** * Instantiates a new transaction state object. * *

Subclasses should override method to return a specific instance of {@link * Transaction.State}. * * @param SimpleFeatureSource The feature source / store for the new transaction state. */ // protected abstract Transaction.State createTransactionState(ContentSimpleFeatureSource // featureSource) // throws IOException; /** * Delegates to {@link #getFeatureSource(Name, Transaction)} * * @since 2.5 * @see DataAccess#getFeatureSource(Name) */ public SimpleFeatureSource getFeatureSource(Name typeName) throws IOException { return getFeatureSource(typeName, Transaction.AUTO_COMMIT); } /** * Returns the same list of names than {@link #getTypeNames()} meaning the returned Names have * no namespace set. * * @since 2.5 * @see DataAccess#getNames() */ public List getNames() throws IOException { String[] typeNames = getTypeNames(); List names = new ArrayList(typeNames.length); for (String typeName : typeNames) { names.add(new NameImpl(typeName)); } return names; } /** * Delegates to {@link #getSchema(String)} with {@code name.getLocalPart()} * * @since 2.5 * @see DataAccess#getSchema(Name) */ public SimpleFeatureType getSchema(Name name) throws IOException { return getSchema(name.getLocalPart()); } /** * Delegates to {@link #updateSchema(String, SimpleFeatureType)} with {@code * name.getLocalPart()} * * @since 2.5 * @see DataAccess#getFeatureSource(Name) */ public void updateSchema(Name typeName, SimpleFeatureType featureType) throws IOException { updateSchema(typeName.getLocalPart(), featureType); } /** @see DataAccess#removeSchema(Name) */ public void removeSchema(Name typeName) throws IOException { throw new UnsupportedOperationException("Schema removal not supported"); } /** @see DataStore#removeSchema(String) */ public void removeSchema(String typeName) throws IOException { throw new UnsupportedOperationException("Schema removal not supported"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy