package mil.nga.giat.geowave.adapter.vector.plugin.lock; import java.io.IOException; import java.lang.reflect.Constructor; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; import mil.nga.giat.geowave.adapter.vector.plugin.GeoWavePluginConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.geotools.data.FeatureLock; import org.geotools.data.Transaction; /** * Simplifies Lock management from the more complex Geotools approach which is * used in several different scenarios (e.g. directory management, wfs-t, etc.) * * Implementers implement three abstract methods. The Geotools still helps with * management, providing a locking source. * * */ public abstract class AbstractLockingManagement implements LockingManagement { private final static Logger LOGGER = LoggerFactory.getLogger(AbstractLockingManagement.class); public static final String LOCKING_MANAGEMENT_CLASS = "GEOWAVE_LM"; public static final Object LOCKING_MANAGEMENT_CLASS_LCK = new Object(); public static AbstractLockingManagement getLockingManagement( GeoWavePluginConfig pluginConfig ) { synchronized (LOCKING_MANAGEMENT_CLASS_LCK) { String val = System.getenv(LOCKING_MANAGEMENT_CLASS); if (val == null) { return new MemoryLockManager( pluginConfig); } else { try { Class<? extends AbstractLockingManagement> lockManagerClass = (Class<? extends AbstractLockingManagement>) Class .forName(val); if (!AbstractLockingManagement.class.isAssignableFrom(lockManagerClass)) { throw new IllegalArgumentException( "Invalid LockManagement class " + val); } else { Constructor cons = lockManagerClass.getConstructor(GeoWavePluginConfig.class); return (AbstractLockingManagement) cons.newInstance(pluginConfig); } } catch (Exception ex) { // HP Fortify "Log Forging" false positive // What Fortify considers "user input" comes only // from users with OS-level access anyway LOGGER.error( "Cannot instantiate lock management class " + val, ex); return new MemoryLockManager( pluginConfig); } } } } private static Set<String> EMPTY_SET = new HashSet<String>(); @Override public void lock( Transaction transaction, String featureID ) { lock( transaction, featureID, transaction == Transaction.AUTO_COMMIT ? EMPTY_SET : transaction.getAuthorizations(), 1 /* minutes */); } private void lock( Transaction transaction, String featureID, Set<String> authorizations, long expiryInMinutes ) { AuthorizedLock lock = transaction == Transaction.AUTO_COMMIT ? null : (AuthorizedLock) transaction .getState(this); if (lock == null) { lock = new AuthorizedLock( this, authorizations, expiryInMinutes); if (transaction != Transaction.AUTO_COMMIT) transaction.putState( this, lock); } lock( lock, featureID); } private void unlock( Transaction transaction, String featureID, Set<String> authorizations, long expiryInMinutes ) { AuthorizedLock lock = transaction == Transaction.AUTO_COMMIT ? null : (AuthorizedLock) transaction .getState(this); if (lock == null) { lock = new AuthorizedLock( this, authorizations, expiryInMinutes); if (transaction != Transaction.AUTO_COMMIT) transaction.putState( this, lock); } unlock( lock, featureID); } @Override public void lockFeatureID( String typeName, String featureID, Transaction transaction, FeatureLock featureLock ) { Set<String> set = new LinkedHashSet<String>(); set.add(featureLock.getAuthorization()); this.lock( transaction, featureID, set, featureLock.getDuration()); } @Override public void unLockFeatureID( String typeName, String featureID, Transaction transaction, FeatureLock featureLock ) throws IOException { Set<String> set = new LinkedHashSet<String>(); set.add(featureLock.getAuthorization()); this.unlock( transaction, featureID, set, featureLock.getDuration()); } @Override public boolean release( String authID, Transaction transaction ) throws IOException { AuthorizedLock lock = transaction == Transaction.AUTO_COMMIT ? null : (AuthorizedLock) transaction .getState(this); if (lock == null) lock = new AuthorizedLock( this, authID, 1 /* minutes */); releaseAll(lock); return true; } @Override public boolean refresh( String authID, Transaction transaction ) throws IOException { AuthorizedLock lock = transaction == Transaction.AUTO_COMMIT ? null : (AuthorizedLock) transaction .getState(this); if (lock == null) lock = new AuthorizedLock( this, authID, 1 /* minutes */); resetAll(lock); return true; } /** * If already locked and request lock has proper authorization * {@link AuthorizedLock#isAuthorized(AuthorizedLock)}, then return. If * already locked and request does not have proper authorization, block * until the lock is released or expired. If not already locked, create the * lock. * * Make sure there is some mechanism for expired locks to be discovered and * released so that clients are not blocked indefinitely. * * @param lock * @param featureID */ public abstract void lock( AuthorizedLock lock, String featureID ); /** * * If authorized {@link AuthorizedLock#isAuthorized(AuthorizedLock)}, unlock * the featureID * * @param lock * @param featureID */ public abstract void unlock( AuthorizedLock lock, String featureID ); /** * Release all locks associated with a transaction or associated * authorizations. Occurs on commit and rollback. Basically, call * {@link TransactionLock#invalidate())} for all authorized locks * {@link AuthorizedLock#isAuthorized(AuthorizedLock)} * * @param lock */ public abstract void releaseAll( AuthorizedLock lock ); /** * Reset all locks associated with a transaction. Occurs on commit and * rollback. Basically, call {@link AuthorizedLock#resetExpireTime()} for * all authorized locks {@link AuthorizedLock#isAuthorized(AuthorizedLock)} * * @param lock */ public abstract void resetAll( AuthorizedLock lock ); }