/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2011, 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 org.geotools.data.DataSourceException; import org.geotools.data.Diff; import org.geotools.data.FeatureWriter; import org.geotools.data.Transaction; import org.geotools.data.TransactionStateDiff; import org.geotools.factory.Hints; import org.geotools.geometry.jts.ReferencedEnvelope; import org.opengis.feature.IllegalAttributeException; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.Name; import org.opengis.filter.Filter; /** * Transaction state responsible for holding an in memory {@link Diff} of any modifications. */ class DiffTransactionState implements Transaction.State { Diff diff; /** The transaction (ie session) associated with this state */ Transaction transaction; /** * ContentState for this transaction used to hold information for * FeatureReader implementations */ ContentState state; /** * Transaction state responsible for holding an in memory {@link Diff}. * * @param state ContentState for the transaction */ public DiffTransactionState(ContentState state) { this.state = state; this.diff = new Diff(); } /** * Access the in memory Diff. * @return in memory diff. */ public Diff getDiff() { return this.diff; } @Override /** * We are already holding onto our transaction from * ContentState; however this method does check that * the transaction is correct. */ public synchronized void setTransaction(Transaction transaction) { this.transaction = transaction; } @Override /** * Will apply differences to store. * * @see org.geotools.data.Transaction.State#commit() */ public synchronized void commit() throws IOException { applyDiff(); } @Override /** * @see org.geotools.data.Transaction.State#rollback() */ public synchronized void rollback() throws IOException { diff.clear(); // rollback differences state.fireBatchFeatureEvent(false); } @Override /** * @see org.geotools.data.Transaction.State#addAuthorization(java.lang.String) */ public synchronized void addAuthorization(String AuthID) throws IOException { // not required for TransactionStateDiff } /** * Called by commit() to apply one set of diff * * <p> * The provided <code> will be modified as the differences are applied, * If the operations are all successful diff will be empty at * the end of this process. * </p> * * <p> * diff can be used to represent the following operations: * </p> * * <ul> * <li> * fid|null: represents a fid being removed</li> * * <li> * fid|feature: where fid exists, represents feature modification</li> * <li> * fid|feature: where fid does not exist, represents feature being modified</li> * </ul> * * * @param typeName typeName being updated * @param diff differences to apply to FeatureWriter * * @throws IOException If the entire diff cannot be writen out * @throws DataSourceException If the entire diff cannot be writen out */ void applyDiff() throws IOException { if (diff.isEmpty()) { return; // nothing to do } FeatureWriter<SimpleFeatureType, SimpleFeature> writer; ContentFeatureStore store; ContentEntry entry = state.getEntry(); Name name = entry.getName(); ContentDataStore dataStore = entry.getDataStore(); ContentFeatureSource source = (ContentFeatureSource) dataStore.getFeatureSource(name); if (source instanceof ContentFeatureStore) { store = (ContentFeatureStore) dataStore.getFeatureSource(name); writer = store.getWriter(Filter.INCLUDE); } else { throw new UnsupportedOperationException("not writable"); } SimpleFeature feature; SimpleFeature update; Throwable cause = null; try { while (writer.hasNext()) { feature = (SimpleFeature) writer.next(); String fid = feature.getID(); if (diff.getModified().containsKey(fid)) { update = (SimpleFeature) diff.getModified().get(fid); if (update == TransactionStateDiff.NULL) { writer.remove(); // notify state.fireFeatureRemoved(store, feature); } else { try { feature.setAttributes(update.getAttributes()); writer.write(); // notify ReferencedEnvelope bounds = ReferencedEnvelope.reference(feature .getBounds()); state.fireFeatureUpdated(store, update, bounds); } catch (IllegalAttributeException e) { throw new DataSourceException("Could update " + fid, e); } } } } SimpleFeature addedFeature; SimpleFeature nextFeature; synchronized (diff) { for (String fid : diff.getAddedOrder()) { addedFeature = diff.getAdded().get(fid); nextFeature = (SimpleFeature) writer.next(); if (nextFeature == null) { throw new DataSourceException("Could not add " + fid); } else { try { nextFeature.setAttributes(addedFeature.getAttributes()); // if( Boolean.TRUE.equals( // addedFeature.getUserData().get(Hints.USE_PROVIDED_FID)) ){ nextFeature.getUserData().put(Hints.USE_PROVIDED_FID, true); if (addedFeature.getUserData().containsKey(Hints.PROVIDED_FID)) { String providedFid = (String) addedFeature.getUserData().get( Hints.PROVIDED_FID); nextFeature.getUserData().put(Hints.PROVIDED_FID, providedFid); } else { nextFeature.getUserData().put(Hints.PROVIDED_FID, addedFeature.getID()); } // } writer.write(); // notify state.fireFeatureAdded(store, nextFeature); } catch (IllegalAttributeException e) { throw new DataSourceException("Could update " + fid, e); } } } } } catch (IOException e) { cause = e; throw e; } catch (RuntimeException e) { cause = e; throw e; } finally { try { writer.close(); state.fireBatchFeatureEvent(true); diff.clear(); } catch (IOException e) { if (cause != null) { e.initCause(cause); } throw e; } catch (RuntimeException e) { if (cause != null) { e.initCause(cause); } throw e; } } } }