package mil.nga.giat.geowave.core.store.metadata; import java.nio.charset.Charset; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import mil.nga.giat.geowave.core.index.ByteArrayId; import mil.nga.giat.geowave.core.index.Persistable; import mil.nga.giat.geowave.core.store.DataStoreOperations; /** * This abstract class does most of the work for storing persistable objects in * Geowave datastores and can be easily extended for any object that needs to be * persisted. * * There is an LRU cache associated with it so staying in sync with external * updates is not practical - it assumes the objects are not updated often or at * all. The objects are stored in their own table. * * @param <T> * The type of persistable object that this stores */ public abstract class AbstractGeowavePersistence<T extends Persistable> { private final static Logger LOGGER = LoggerFactory.getLogger(AbstractGeowavePersistence.class); // TODO: should we concern ourselves with multiple distributed processes // updating and looking up objects simultaneously that would require some // locking/synchronization mechanism, and even possibly update // notifications? protected static final int MAX_ENTRIES = 100; public final static String METADATA_TABLE = "GEOWAVE_METADATA"; private final DataStoreOperations operations; protected final Map<ByteArrayId, T> cache = Collections.synchronizedMap(new LinkedHashMap<ByteArrayId, T>( MAX_ENTRIES + 1, .75F, true) { private static final long serialVersionUID = 1L; @Override public boolean removeEldestEntry( final Map.Entry<ByteArrayId, T> eldest ) { return size() > MAX_ENTRIES; } }); public AbstractGeowavePersistence( final DataStoreOperations operations ) { this.operations = operations; } abstract protected String getPersistenceTypeName(); protected ByteArrayId getSecondaryId( final T persistedObject ) { // this is the default implementation, if the persistence store requires // secondary indices, return null; } abstract protected ByteArrayId getPrimaryId( final T persistedObject ); protected String getTablename() { return METADATA_TABLE; } public void removeAll() { cache.clear(); } protected ByteArrayId getCombinedId( final ByteArrayId primaryId, final ByteArrayId secondaryId ) { // the secondaryId is optional so check for null if (secondaryId != null) { return new ByteArrayId( primaryId.getString() + "_" + secondaryId.getString()); } return primaryId; } protected void addObjectToCache( final ByteArrayId primaryId, final ByteArrayId secondaryId, final T object ) { final ByteArrayId combinedId = getCombinedId( primaryId, secondaryId); cache.put( combinedId, object); } protected Object getObjectFromCache( final ByteArrayId primaryId, final ByteArrayId secondaryId ) { final ByteArrayId combinedId = getCombinedId( primaryId, secondaryId); return cache.get(combinedId); } protected boolean deleteObjectFromCache( final ByteArrayId primaryId, final ByteArrayId secondaryId ) { final ByteArrayId combinedId = getCombinedId( primaryId, secondaryId); return (cache.remove(combinedId) != null); } public void remove( final ByteArrayId adapterId ) { deleteObject( adapterId, null); } protected boolean deleteObject( final ByteArrayId primaryId, final ByteArrayId secondaryId, final String... authorizations ) { return deleteObjectFromCache( primaryId, secondaryId) && deleteObjects( primaryId, secondaryId, authorizations); } protected void addObject( final T object ) { addObject( getPrimaryId(object), getSecondaryId(object), object); } protected String getColumnQualifier( final ByteArrayId secondaryId ) { if (secondaryId != null) { return secondaryId.getString(); } return null; } protected String getColumnQualifier( final T persistedObject ) { return getColumnQualifier(getSecondaryId(persistedObject)); } protected byte[] getVisibility( final T entry ) { return null; } protected String getColumnFamily() { return getPersistenceTypeName(); } protected abstract void addObject( final ByteArrayId id, final ByteArrayId secondaryId, final T object ); protected abstract boolean deleteObjects( final ByteArrayId primaryId, final ByteArrayId secondaryId, final String... authorizations ); protected byte[] toBytes( final String s ) { if (s == null) { return null; } return s.getBytes(Charset.forName("UTF-8")); } }