/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2003-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.io.IOException; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.geotools.data.simple.SimpleFeatureStore; import org.geotools.factory.Hints; import org.geotools.feature.FeatureCollection; import org.geotools.feature.IllegalAttributeException; import org.geotools.feature.NameImpl; import org.geotools.filter.identity.FeatureIdImpl; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.AttributeDescriptor; import org.opengis.feature.type.Name; import org.opengis.filter.Filter; import org.opengis.filter.identity.FeatureId; /** * This is a starting point for providing your own FeatureStore implementation. * * @author Jody Garnett, Refractions Research * * @source $URL$ */ public abstract class AbstractFeatureStore extends AbstractFeatureSource implements SimpleFeatureStore { /** Current Transaction this SimpleFeatureSource is opperating against */ protected Transaction transaction = Transaction.AUTO_COMMIT; public AbstractFeatureStore() { // just to keep the default constructor around } /** * This constructors allows to set the supported hints * @param hints */ public AbstractFeatureStore(Set hints) { super(hints); } /** * Retrieve the Transaction this SimpleFeatureSource is opperating against. * * @return Transaction SimpleFeatureSource is operating against */ public Transaction getTransaction() { return transaction; } // // FeatureStore implementation against DataStore API // /** * Modifies features matching <code>filter</code>. * * <p> * Equivelent to: * </p> * <pre><code> * FeatureWriter<SimpleFeatureType, SimpleFeature> writer = dataStore.getFeatureWriter( typeName, filter, transaction ); * while( writer.hasNext() ){ * feature = writer.next(); * feature.setAttribute( type.getName(), value ); * writer.write(); * } * writer.close(); * </code> * </pre> * * <p> * Subclasses may override this method to perform the appropriate * optimization for this result. * </p> * * @param type Attribute to modify * @param value Modification being made to type * @param filter Identifies features to modify * * @throws IOException If modification could not be made */ public final void modifyFeatures(AttributeDescriptor type, Object value, Filter filter) throws IOException { Name attributeName = type.getName(); modifyFeatures( attributeName, value, filter); } public void modifyFeatures(Name attributeName, Object attributeValue, Filter filter) throws IOException { modifyFeatures(new Name[] { attributeName, }, new Object[] { attributeValue, }, filter); } public void modifyFeatures(String name, Object attributeValue, Filter filter) throws IOException { modifyFeatures(new Name[] { new NameImpl( name ), }, new Object[] { attributeValue, }, filter); } public void modifyFeatures(String[] names, Object[] values, Filter filter) throws IOException { Name attributeNames[] = new Name[ names.length ]; for( int i=0; i < names.length; i ++){ attributeNames[i] = new NameImpl(names[i]); } modifyFeatures( attributeNames, values, filter ); } /** * Modifies features matching <code>filter</code>. * * <p> * Equivelent to: * </p> * <pre><code> * FeatureWriter<SimpleFeatureType, SimpleFeature> writer = dataStore.getFeatureWriter( typeName, filter, transaction ); * Feature feature; * while( writer.hasNext() ){ * feature = writer.next(); * feature.setAttribute( type[0].getName(), value[0] ); * feature.setAttribute( type[1].getName(), value[1] ); * ... * feature.setAttribute( type[N].getName(), value[N] ); * writer.write(); * } * writer.close(); * </code> * </pre> * * <p> * Subclasses may override this method to perform the appropriate * optimization for this result. * </p> * * @param type Attributes to modify * @param value Modifications being made to type * @param filter Identifies features to modify * * @throws IOException If we could not modify Feature * @throws DataSourceException See IOException */ public final void modifyFeatures(AttributeDescriptor[] type, Object[] value, Filter filter) throws IOException { Name attributeNames[] = new Name[ type.length ]; for( int i=0; i < type.length; i ++){ attributeNames[i] = type[i].getName(); } modifyFeatures( attributeNames, value, filter ); } public void modifyFeatures(Name[] attributeNames, Object[] attributeValues, Filter filter) throws IOException{ String typeName = getSchema().getTypeName(); if ( filter == null ) { String msg = "Must specify a filter, must not be null."; throw new IllegalArgumentException( msg ); } FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ((DataStore) getDataStore()) .getFeatureWriter(typeName, filter, getTransaction()); SimpleFeature feature; for( Name attributeName : attributeNames ){ if( getSchema().getDescriptor( attributeName) == null ){ throw new DataSourceException("Cannot modify "+attributeName+" as it is not an attribute of "+getSchema().getName() ); } } try { while (writer.hasNext()) { feature = writer.next(); for (int i = 0; i < attributeNames.length; i++) { try { feature.setAttribute(attributeNames[i], attributeValues[i]); } catch (Exception e) { throw new DataSourceException( "Could not update feature " + feature.getID() + " with " + attributeNames[i] + "=" + attributeValues[i], e); } } writer.write(); } } finally { writer.close(); } } /** * Add Features from reader to this FeatureStore. * * <p> * Equivelent to: * </p> * <pre><code> * Set set = new HashSet(); * FeatureWriter<SimpleFeatureType, SimpleFeature> writer = dataStore.getFeatureWriter( typeName, true, transaction ); * Featrue feature, newFeature; * while( reader.hasNext() ){ * feature = reader.next(); * newFeature = writer.next(); * newFeature.setAttributes( feature.getAttribtues( null ) ); * writer.write(); * set.add( newfeature.getID() ); * } * reader.close(); * writer.close(); * * return set; * </code> * </pre> * * <p> * (If you don't have a FeatureReader<SimpleFeatureType, SimpleFeature> handy DataUtilities.reader() may be * able to help out) * </p> * * <p> * Subclasses may override this method to perform the appropriate * optimization for this result. * </p> * * @param reader * * @return The Set of FeatureIDs added * * @throws IOException If we encounter a problem encounter writing content * @throws DataSourceException See IOException * * @see org.geotools.data.FeatureStore#addFeatures(org.geotools.data.FeatureReader) */ public Set<String> addFeatures(FeatureReader <SimpleFeatureType, SimpleFeature> reader) throws IOException { Set<String> addedFids = new HashSet<String>(); String typeName = getSchema().getTypeName(); SimpleFeature feature = null; SimpleFeature newFeature; FeatureWriter<SimpleFeatureType, SimpleFeature> writer = getDataStore() .getFeatureWriterAppend(typeName, getTransaction()); try { while (reader.hasNext()) { try { feature = reader.next(); } catch (Exception e) { throw new DataSourceException("Could not add Features, problem with provided reader", e); } newFeature = (SimpleFeature)writer.next(); try { newFeature.setAttributes(feature.getAttributes()); } catch (Exception writeProblem) { throw new DataSourceException("Could not create " + typeName + " out of provided feature: " + feature.getID(), writeProblem); } boolean useExisting = Boolean.TRUE.equals(feature.getUserData().get(Hints.USE_PROVIDED_FID)); if(getQueryCapabilities().isUseProvidedFIDSupported() && useExisting) { ((FeatureIdImpl) newFeature.getIdentifier()).setID(feature.getID()); } writer.write(); addedFids.add(newFeature.getID()); } } finally { reader.close(); writer.close(); } return addedFids; } public List<FeatureId> addFeatures(FeatureCollection<SimpleFeatureType,SimpleFeature> collection) throws IOException { List<FeatureId> addedFids = new LinkedList<FeatureId>(); String typeName = getSchema().getTypeName(); SimpleFeature feature = null; SimpleFeature newFeature; FeatureWriter<SimpleFeatureType, SimpleFeature> writer = getDataStore() .getFeatureWriterAppend(typeName, getTransaction()); Iterator iterator = collection.iterator(); try { while (iterator.hasNext()) { feature = (SimpleFeature) iterator.next(); newFeature = (SimpleFeature)writer.next(); try { newFeature.setAttributes(feature.getAttributes()); } catch (Exception writeProblem) { throw new DataSourceException("Could not create " + typeName + " out of provided feature: " + feature.getID(), writeProblem); } boolean useExisting = Boolean.TRUE.equals(feature.getUserData().get(Hints.USE_PROVIDED_FID)); if(getQueryCapabilities().isUseProvidedFIDSupported() && useExisting) { ((FeatureIdImpl) newFeature.getIdentifier()).setID(feature.getID()); } writer.write(); addedFids.add(newFeature.getIdentifier()); } } finally { collection.close( iterator ); writer.close(); } return addedFids; } /** * Removes features indicated by provided filter. * * <p> * Equivelent to: * </p> * <pre><code> * FeatureWriter<SimpleFeatureType, SimpleFeature> writer = dataStore.getFeatureWriter( typeName, filter, transaction ); * Feature feature; * while( writer.hasNext() ){ * feature = writer.next(); * writer.remove(); * } * writer.close(); * </code> * </pre> * * <p> * Subclasses may override this method to perform the appropriate * optimization for this result. * </p> * * @param filter Identifies features to remove * * @throws IOException */ public void removeFeatures(Filter filter) throws IOException { String typeName = getSchema().getTypeName(); FeatureWriter<SimpleFeatureType, SimpleFeature> writer = getDataStore().getFeatureWriter(typeName, filter, getTransaction()); try { while (writer.hasNext()) { writer.next(); writer.remove(); } } finally { writer.close(); } } /** * Replace with contents of reader. * * <p> * Equivelent to: * </p> * <pre><code> * FeatureWriter<SimpleFeatureType, SimpleFeature> writer = dataStore.getFeatureWriter( typeName, false, transaction ); * Feature feature, newFeature; * while( writer.hasNext() ){ * feature = writer.next(); * writer.remove(); * } * while( reader.hasNext() ){ * newFeature = reader.next(); * feature = writer.next(); * newFeature.setAttributes( feature.getAttributes( null ) ); * writer.write(); * } * reader.close(); * writer.close(); * </code> * </pre> * * <p> * Subclasses may override this method to perform the appropriate * optimization for this result. * </p> * * @param reader Contents to replace with * * @throws IOException if anything goes wrong during replacement * @throws DataSourceException See IOException */ public void setFeatures(FeatureReader <SimpleFeatureType, SimpleFeature> reader) throws IOException { String typeName = getSchema().getTypeName(); FeatureWriter<SimpleFeatureType, SimpleFeature> writer = getDataStore().getFeatureWriter(typeName, getTransaction()); SimpleFeature feature; SimpleFeature newFeature; try { while (writer.hasNext()) { feature = writer.next(); writer.remove(); } while (reader.hasNext()) { try { feature = reader.next(); } catch (Exception readProblem) { throw new DataSourceException("Could not add Features, problem with provided reader", readProblem); } newFeature = (SimpleFeature)writer.next(); try { newFeature.setAttributes(feature.getAttributes()); } catch (IllegalAttributeException writeProblem) { throw new DataSourceException("Could not create " + typeName + " out of provided feature: " + feature.getID(), writeProblem); } writer.write(); } } finally { reader.close(); writer.close(); } } public void setTransaction(Transaction transaction) { if (transaction == null) { throw new IllegalArgumentException( "Transaction cannot be null, did you mean Transaction.AUTO_COMMIT?"); } this.transaction = transaction; } }