package mil.nga.giat.geowave.adapter.vector.plugin.transaction; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import mil.nga.giat.geowave.adapter.vector.plugin.GeoWaveDataStoreComponents; import mil.nga.giat.geowave.adapter.vector.plugin.lock.LockingManagement; import org.geotools.data.DataSourceException; import org.geotools.data.Transaction; /** * Implements the transaction state protocol with Geotools. * */ public class GeoWaveTransactionManagementState implements GeoWaveTransactionState { private final GeoWaveDataStoreComponents components; private final LockingManagement lockingManager; private Transaction transaction; private final String txID; private final int transactionBufferSize; /** * Map of differences by typeName. * * <p> * Differences are stored as a Map of Feature by fid, and are reset during a * commit() or rollback(). * </p> */ private final Map<String, GeoWaveTransactionManagement> typeNameDiff = new HashMap<String, GeoWaveTransactionManagement>(); public GeoWaveTransactionManagementState( final int transactionBufferSize, final GeoWaveDataStoreComponents components, final Transaction transaction, final LockingManagement lockingManager ) throws IOException { this.transactionBufferSize = transactionBufferSize; this.components = components; this.transaction = transaction; this.lockingManager = lockingManager; txID = components.getTransaction(); } @Override public synchronized void setTransaction( final Transaction transaction ) { if (transaction != null) { // configure this.transaction = transaction; } else { this.transaction = null; if (typeNameDiff != null) { for (final Iterator<GeoWaveTransactionManagement> i = typeNameDiff.values().iterator(); i.hasNext();) { final GeoWaveTransactionManagement diff = i.next(); diff.clear(); } typeNameDiff.clear(); } } } @Override public synchronized GeoWaveTransactionManagement getGeoWaveTransaction( final String typeName ) throws IOException { if (!exists(typeName)) { throw new RuntimeException( typeName + " not defined"); } if (typeNameDiff.containsKey(typeName)) { return typeNameDiff.get(typeName); } else { final GeoWaveTransactionManagement transX = new GeoWaveTransactionManagement( transactionBufferSize, components, typeName, transaction, lockingManager, txID); typeNameDiff.put( typeName, transX); return transX; } } boolean exists( final String typeName ) throws IOException { String[] types; types = components.getGTstore().getTypeNames(); Arrays.sort(types); return Arrays.binarySearch( types, typeName) != -1; } /** * @see org.geotools.data.Transaction.State#addAuthorization(java.lang.String) */ @Override public synchronized void addAuthorization( final String AuthID ) throws IOException { // not required } /** * Will apply differences to store. * * @see org.geotools.data.Transaction.State#commit() */ @Override public synchronized void commit() throws IOException { try { for (final Iterator<Entry<String, GeoWaveTransactionManagement>> i = typeNameDiff.entrySet().iterator(); i .hasNext();) { final Map.Entry<String, GeoWaveTransactionManagement> entry = i.next(); final String typeName = entry.getKey(); final GeoWaveTransactionManagement diff = entry.getValue(); applyDiff( typeName, diff); diff.clear(); } } finally { components.releaseTransaction(txID); } } /** * 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( final String typeName, final GeoWaveTransactionManagement diff ) throws IOException { IOException cause = null; if (diff.isEmpty()) { return; } try { diff.commit(); } catch (final IOException e) { cause = e; throw e; } catch (final RuntimeException e) { cause = new IOException( e); throw e; } finally { try { components.getGTstore().getListenerManager().fireChanged( typeName, transaction, true); diff.clear(); } catch (final RuntimeException e) { if (cause != null) { e.initCause(cause); } throw e; } } } /** * @see org.geotools.data.Transaction.State#rollback() */ @Override public synchronized void rollback() throws IOException { Entry<String, GeoWaveTransactionManagement> entry; try { for (final Iterator<Entry<String, GeoWaveTransactionManagement>> i = typeNameDiff.entrySet().iterator(); i .hasNext();) { entry = i.next(); final String typeName = entry.getKey(); final GeoWaveTransactionManagement diff = entry.getValue(); diff.rollback(); components.getGTstore().getListenerManager().fireChanged( typeName, transaction, false); } } finally { components.releaseTransaction(txID); } } @Override public String toString() { return "GeoWaveTransactionManagementState [components=" + components + ", lockingManager=" + lockingManager + ", transaction=" + transaction + ", txID=" + txID + ", typeNameDiff=" + typeNameDiff + "]"; } }