/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2004-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.store; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.logging.Logger; import org.geotools.data.DataAccess; import org.geotools.data.DataStore; import org.geotools.data.DefaultServiceInfo; import org.geotools.data.EmptyFeatureWriter; import org.geotools.data.FeatureReader; import org.geotools.data.FeatureSource; import org.geotools.data.FeatureWriter; import org.geotools.data.FilteringFeatureWriter; 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.view.DefaultView; import org.geotools.feature.FeatureTypes; import org.geotools.feature.NameImpl; import org.geotools.feature.SchemaException; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.Name; import org.opengis.filter.Filter; /** * Represents a stating point for implementing your own DataStore. * * <p> * The goal is to have this class provide <b>everything</b> else if you only * need to provide: * </p> * * <ul> * <li> * Set getContents() - set of TypeEntry * </li> * <li> * FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader( typeName ) * </li> * </ul> * * To support writing: * <ul> * <li>set isWritable to true * <li>implement FeatureWriter getFeatureWriter( typeName ) * </ul> * * <p> * All remaining functionality is implemented against these methods, including * Transaction and Locking Support. These implementations will not be optimal * but they will work. * </p> * * To support custom query optimizations: * <ul> * <li> Filter getUnsupportedFilter(String typeName, Filter filter) * <li> FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader(String typeName, Query query) * </ul> * * To provide high-level writing optimizations: * <ul> * <li> Override createFeatureSource to use your own custom FeatureSource * </ul> * * To provide low-level writing optimizations: * <ul> * <li> FeatureWriter getFeatureWriterAppend( typeName, transaction ) * <li> FeatureWriter getFeatureWriterAppend( typeName, Filter, transaction ) * <li> * </ul> * * To provide high-level writing optimizations: * <ul> * <li> Stop using FeatureWriter completely * <li> Override createFeatureStore to use your own custom FeatureStore * </ul> * <p> * Pleae note that there may be a better place for you to start out from, (like * JDBCDataStore). * </p> * * @author jgarnett * @source $URL$ */ public class AbstractDataStore2 implements DataStore { /** The logger for the data module. */ protected static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.data"); /** * Manages InProcess locks for FeatureLocking implementations. * * <p> * May be null if subclass is providing real locking. * </p> */ private InProcessLockingManager lockingManager; /** Default (Writeable) DataStore */ public AbstractDataStore2() { lockingManager = createLockingManager(); } /** List<ActiveTypeEntry> subclass control provided by createContents */ private List contents = null; /** * Currently returns an InProcessLockingManager. * * <p> * Subclasses that implement real locking may override this method to * return <code>null</code>. * </p> * * @return InProcessLockingManager or null. */ protected InProcessLockingManager createLockingManager() { return new InProcessLockingManager(); } /** List of ActiveTypeEntry entries - one for each featureType provided by this Datastore */ public List entries() { if( contents == null ) { contents = createContents(); } return Collections.unmodifiableList( contents ); } /** * Subclass must overrride to connet to contents. * <p> * An implementation that has any doubt about its contents should aquire * them during object creation (where an IOException can be thrown). * </p> * <p> * This method is lazyly called to create a List of ActiveTypeEntry for * each FeatureCollection<SimpleFeatureType, SimpleFeature> in this DataStore. * </p> * @return List<ActiveTypeEntry>. */ protected List createContents() { throw new UnsupportedOperationException("createContent not implemented"); } /** Convience method for retriving all the names from the Catalog Entires */ public String[] getTypeNames() { List all = entries(); String names[] = new String[ all.size() ]; int index = 0; for( Iterator i=all.iterator(); i.hasNext(); index++ ) { ActiveTypeEntry entry = (ActiveTypeEntry) i.next(); names[ index ] = entry.getTypeName(); } return names; } public ActiveTypeEntry entry( String typeName ) { if( typeName == null ) return null; for( Iterator i=entries().iterator(); i.hasNext(); ) { ActiveTypeEntry entry = (ActiveTypeEntry) i.next(); if( typeName.equals( entry.getTypeName() ) ) { return entry; } } return null; } public ServiceInfo getInfo() { DefaultServiceInfo info = new DefaultServiceInfo(); info.setDescription("Features from "+getClass().getSimpleName() ); info.setSchema( FeatureTypes.DEFAULT_NAMESPACE ); return null; } /** Retrive schema information for typeName */ public SimpleFeatureType getSchema(String typeName) throws IOException{ return entry( typeName ).getFeatureType(); } /** * Subclass should implement to provide for creation. * * @param featureType Requested FeatureType * * @throws IOException Subclass may throw IOException * @throws UnsupportedOperationException Subclass may implement */ public void createSchema(SimpleFeatureType featureType) throws IOException { throw new UnsupportedOperationException("Schema creation not supported"); } /** * Subclass should implement to provide modification support. */ public void updateSchema(String typeName, SimpleFeatureType featureType) throws IOException { throw new UnsupportedOperationException("Schema modification not supported"); } // Jody - This is my recomendation for DataStore in order to support CS reprojection and override /** * Create a FeatureSource<SimpleFeatureType, SimpleFeature> that represents your Query. * <p> * If we can make this part of the public API, we can phase out FeatureResults. * (and reduce the number of classes people need to know about). * </p> */ public FeatureSource<SimpleFeatureType, SimpleFeature> getView(final Query query) throws IOException, SchemaException { return new DefaultView( getFeatureSource( query.getTypeName() ), query ); } /** * Aqure FeatureSource<SimpleFeatureType, SimpleFeature> for indicated typeName. * <p> * Note this API is not sufficient; Namespace needs to be used as well. * </p> */ public FeatureSource<SimpleFeatureType, SimpleFeature> getFeatureSource( final String typeName ) throws IOException { return entry( typeName ).createFeatureSource(); } /** * Access a FeatureReader<SimpleFeatureType, SimpleFeature> providing access to Feature information. * <p> * This implementation passes off responsibility to the following overrideable methods: * <ul> * <li>getFeatureReader(String typeName) - subclass *required* to implement * </ul> * </p> * <p>If you can handle some aspects of Query natively (say expressions or reprojection) override the following: * <li> * <li>getFeatureReader(typeName, query) - override to handle query natively * <li>getUnsupportedFilter(typeName, filter) - everything you cannot handle natively * <li>getFeatureReader(String typeName) - you must implement this, but you could point it back to getFeatureReader( typeName, Query.ALL ); * </ul> * </p> */ public FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader(Query query, Transaction transaction) throws IOException { if( query.getTypeName() == null ){ throw new NullPointerException( "getFeatureReader requires typeName: " + "use getTypeNames() for a list of available types"); } ActiveTypeEntry entry = entry( query.getTypeName() ); return entry.reader( query, transaction ); } /* (non-Javadoc) * @see org.geotools.data.DataStore#getFeatureWriter(java.lang.String, org.geotools.filter.Filter, org.geotools.data.Transaction) */ public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriter(String typeName, Filter filter, Transaction transaction) throws IOException { if (filter == null) { throw new NullPointerException("getFeatureReader requires Filter: " + "did you mean Filter.INCLUDE?"); } if (filter == Filter.EXCLUDE) { SimpleFeatureType featureType = getSchema(typeName); return new EmptyFeatureWriter(featureType); } FeatureWriter<SimpleFeatureType, SimpleFeature> writer = getFeatureWriter(typeName, transaction); if (filter != Filter.INCLUDE) { writer = new FilteringFeatureWriter(writer, filter); } return writer; } /** * TODO summary sentence for getFeatureWriter ... * * @see org.geotools.data.DataStore#getFeatureWriter(java.lang.String, org.geotools.data.Transaction) * @param typeName * @param transaction * @return FeatureWriter * @throws IOException */ public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriter( String typeName, Transaction transaction ) throws IOException { return entry( typeName ).writer( transaction ); } /** * FeatureWriter setup to add new content. * * @see org.geotools.data.DataStore#getFeatureWriterAppend(java.lang.String, org.geotools.data.Transaction) * @param typeName * @param transaction * @return FeatureWriter already skipped to the end * @throws IOException */ public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriterAppend( String typeName, Transaction transaction ) throws IOException { return entry( typeName ).createAppend( transaction ); } /** * Locking manager used for this DataStore. * * <p> * By default AbstractDataStore makes use of InProcessLockingManager. * </p> * * * @see org.geotools.data.DataStore#getLockingManager() */ public LockingManager getLockingManager() { return lockingManager; } /** * Dummy implementation, it's a no-op. Subclasses holding to system resources must * override this method and release them. */ public void dispose() { // nothing to do } /** * Delegates to {@link #getFeatureSource(String)} with * {@code name.getLocalPart()} * * @since 2.5 * @see DataAccess#getFeatureSource(Name) */ public FeatureSource<SimpleFeatureType, SimpleFeature> getFeatureSource(Name typeName) throws IOException { return getFeatureSource(typeName.getLocalPart()); } /** * 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<Name> getNames() throws IOException { String[] typeNames = getTypeNames(); List<Name> names = new ArrayList<Name>(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); } }