[jbosscache-commits] JBoss Cache SVN: r7854 - in core/branches/flat/src: test/java/org/horizon/loader/bdbje and 1 other directory.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Wed Mar 4 21:09:04 EST 2009


Author: adriancole
Date: 2009-03-04 21:09:04 -0500 (Wed, 04 Mar 2009)
New Revision: 7854

Added:
   core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeResourceFactory.java
   core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreTest.java
   core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeResourceFactoryTest.java
Modified:
   core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStore.java
   core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfig.java
   core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfigTest.java
   core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreIntegrationTest.java
   core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeLearningTest.java
Log:
added test cases and cleaned code

Modified: core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStore.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStore.java	2009-03-05 00:23:55 UTC (rev 7853)
+++ core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStore.java	2009-03-05 02:09:04 UTC (rev 7854)
@@ -1,11 +1,17 @@
 package org.horizon.loader.bdbje;
 
-import com.sleepycat.bind.EntryBinding;
-import com.sleepycat.bind.serial.SerialBinding;
 import com.sleepycat.bind.serial.StoredClassCatalog;
 import com.sleepycat.collections.CurrentTransaction;
 import com.sleepycat.collections.StoredMap;
-import com.sleepycat.je.*;
+import com.sleepycat.je.Cursor;
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseEntry;
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Environment;
+import com.sleepycat.je.EnvironmentConfig;
+import com.sleepycat.je.JEVersion;
+import com.sleepycat.je.OperationStatus;
+import com.sleepycat.je.Transaction;
 import com.sleepycat.util.ExceptionUnwrapper;
 import org.horizon.Cache;
 import org.horizon.loader.AbstractCacheStore;
@@ -17,7 +23,6 @@
 import org.horizon.logging.LogFactory;
 import org.horizon.marshall.Marshaller;
 import org.horizon.util.ReflectionUtil;
-import org.horizon.util.concurrent.WithinThreadExecutor;
 
 import java.io.File;
 import java.io.ObjectInput;
@@ -28,8 +33,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 
 /**
  * An Oracle SleepyCat JE implementation of a {@link org.horizon.loader.CacheStore}.  <p/>This implementation uses two
@@ -62,34 +65,37 @@
 
    private BdbjeCacheStoreConfig cfg;
    private Cache cache;
-   private Marshaller m;
 
    private Environment env;
-   private String cacheDbName;
-   private String catalogDbName;
    private StoredClassCatalog catalog;
    private Database cacheDb;
    private StoredMap<Object, StoredEntry> cacheMap;
 
    private PreparableTransactionRunner transactionRunner;
    private Map<javax.transaction.Transaction, Transaction> txnMap;
-   private ExecutorService purgerService;
    private CurrentTransaction currentTransaction;
+   private BdbjeResourceFactory factory;
 
    /**
-    * {@inheritDoc} This implementation expects config to be an instance of {@link BdbjeCacheStoreConfig}
+    * {@inheritDoc} This implementation expects config to be an instance of {@link BdbjeCacheStoreConfig} <p /> note
+    * that the <code>m</code> is not currently used as SleepyCat has its own efficient solution.
     *
     * @see BdbjeCacheStoreConfig
     */
    public void init(CacheLoaderConfig config, Cache cache, Marshaller m) {
+      BdbjeCacheStoreConfig cfg = (BdbjeCacheStoreConfig) config;
+      init(cfg, new BdbjeResourceFactory(cfg), cache);
+   }
+
+   public void init(BdbjeCacheStoreConfig cfg, BdbjeResourceFactory factory, Cache cache) {
       if (trace) log.trace("initializing BdbjeCacheStore");
       printLicense();
-      this.cfg = (BdbjeCacheStoreConfig) config;
+      super.init(cfg, cache, null);
+      this.cfg = cfg;
+      this.factory = factory;
       this.cache = cache;
-      this.m = m;
    }
 
-
    /**
     * {@inheritDoc}
     *
@@ -101,39 +107,49 @@
 
    /**
     * {@inheritDoc} Validates configuration, configures and opens the {@link Environment}, then {@link
-    * org.horizon.loader.bdbje.BdbjeCacheStore#openDatabases() opens the databases}.  When this is finished,
-    * transactional services are instantiated.
+    * org.horizon.loader.bdbje.BdbjeCacheStore#openSleepyCatResources() opens the databases}.  When this is finished,
+    * transactional and purging services are instantiated.
     */
    public void start() throws CacheLoaderException {
       if (trace) log.trace("starting BdbjeCacheStore");
-      checkNotOpen();
 
-      if (cache == null) {
-         throw new IllegalStateException(
-               "A non-null Cache property (CacheSPI object) is required");
-      }
+      openSleepyCatResources();
+      openTransactionServices();
+      super.start();
 
-      String configStr = cfg.getLocation();
+      log.debug("started cache store {1}", this);
+   }
 
-      if (cfg.isPurgeSynchronously()) {
-         purgerService = new WithinThreadExecutor();
-      } else {
-         purgerService = Executors.newSingleThreadExecutor();
-      }
+   private void openTransactionServices() {
+      txnMap = new ConcurrentHashMap<javax.transaction.Transaction, Transaction>();
+      currentTransaction = factory.createCurrentTransaction(env);
+      transactionRunner = factory.createPreparableTransactionRunner(env);
+   }
 
-      // JBCACHE-1448 db name parsing fix courtesy of Ciro Cavani
-      /* Parse config string. */
-      int offset = configStr.indexOf('#');
-      if (offset >= 0 && offset < configStr.length() - 1) {
-         cacheDbName = configStr.substring(offset + 1);
-         configStr = configStr.substring(0, offset);
-      } else {
-         cacheDbName = cache.getName();
-         if (cacheDbName == null) cacheDbName = "CacheInstance-" + System.identityHashCode(cache);
+   /**
+    * Opens the SleepyCat environment and all databases.  A {@link StoredMap} instance is provided which persists the
+    * CacheStore.
+    */
+   private void openSleepyCatResources() throws CacheLoaderException {
+      if (trace) log.trace("creating je environment with home dir {0}", cfg.getLocation());
+
+      if (cfg.getCacheDbName() == null) cfg.setCacheDbName(cache.getName());
+      if (cfg.getCatalogDbName() == null) cfg.setCatalogDbName(cfg.getCacheDbName() + "_class_catalog");
+
+      File location = verifyOrCreateEnvironmentDirectory(new File(cfg.getLocation()));
+      try {
+         env = factory.createEnvironment(location);
+         cacheDb = factory.createDatabase(env, cfg.getCacheDbName());
+         Database catalogDb = factory.createDatabase(env, cfg.getCatalogDbName());
+         catalog = factory.createStoredClassCatalog(catalogDb);
+         cacheMap = factory.createStoredMapViewOfDatabase(cacheDb, catalog);
+      } catch (DatabaseException e) {
+         throw convertToCacheLoaderException("could not open sleepycat je resource", e);
       }
+   }
 
-      // datafile location
-      File location = new File(configStr);
+   // not private so that this can be unit tested
+   File verifyOrCreateEnvironmentDirectory(File location) throws CacheLoaderException {
       if (!location.exists()) {
          boolean created = location.mkdirs();
          if (!created) throw new CacheLoaderException("Unable to create cache loader location " + location);
@@ -142,120 +158,61 @@
       if (!location.isDirectory()) {
          throw new CacheLoaderException("Cache loader location [" + location + "] is not a directory!");
       }
-
-      catalogDbName = cacheDbName + "_class_catalog";
-
-      try {
-         /* Open the environment, creating it if it doesn't exist. */
-         EnvironmentConfig envConfig = new EnvironmentConfig();
-         envConfig.setAllowCreate(true);
-         envConfig.setTransactional(true);
-         /* lock timeout is in microseconds */
-         envConfig.setLockTimeout(cfg.getLockAcquistionTimeout() * 1000);
-         if (log.isDebugEnabled()) {
-            envConfig.setConfigParam("je.txn.deadlockStackTrace", "true");
-            envConfig.setConfigParam("je.txn.dumpLocks", "true");
-         }
-         if (trace) log.trace("creating je environment with home dir {0}", location);
-         env = new Environment(location, envConfig);
-         log.debug("created je environment {0} for cache store {1}", env, this);
-         /* Open cache and catalog databases. */
-         openDatabases();
-      }
-      catch (DatabaseException e) {
-         throw new CacheLoaderException("could not open the sleepycat database", e);
-      }
-      txnMap = new ConcurrentHashMap<javax.transaction.Transaction, Transaction>();
-      currentTransaction = CurrentTransaction.getInstance(env);
-      transactionRunner = new PreparableTransactionRunner(env);
-      transactionRunner.setMaxRetries(cfg.getMaxTxRetries());
-      log.debug("started cache store {1}", this);
+      return location;
    }
 
-
    /**
-    * Opens all databases and initializes database related information.  A {@link StoredMap} instance is {@link
-    * BdbjeCacheStore#createStoredMapViewOfDatabase(com.sleepycat.je.Database, com.sleepycat.bind.serial.StoredClassCatalog)
-    * associated} with the stored entry and class catalog databases.
+    * Stops transaction and purge processing and closes the SleepyCat environment.  The environment and databases are
+    * not removed from the file system. Exceptions during close of databases are ignored as closing the environment will
+    * ensure the databases are also.
     */
-   private void openDatabases() throws DatabaseException {
-      if (trace) log.trace("opening databases");
-      /* Use a generic database config, with no duplicates allowed. */
-      DatabaseConfig dbConfig = new DatabaseConfig();
-      dbConfig.setTransactional(true);
-      dbConfig.setAllowCreate(true);
+   public void stop() throws CacheLoaderException {
+      if (trace) log.trace("stopping BdbjeCacheStore");
+      super.stop();
+      closeTransactionServices();
+      closeSleepyCatResources();
+      log.debug("started cache store {1}", this);
+   }
 
-      if (trace) log.trace("opening or creating stored entry database {0}", cacheDbName);
-      cacheDb = env.openDatabase(null, cacheDbName, dbConfig);
-      log.debug("opened stored entry database {0}", cacheDbName);
-
-      if (trace) log.trace("opening or creating class catalog database {0}", catalogDbName);
-      Database catalogDb = env.openDatabase(null, catalogDbName, dbConfig);
-      catalog = new StoredClassCatalog(catalogDb);
-      log.debug("created stored class catalog from database {0}", catalogDbName);
-
-      cacheMap = createStoredMapViewOfDatabase(cacheDb, catalog);
+   private void closeTransactionServices() {
+      transactionRunner = null;
+      currentTransaction = null;
+      txnMap = null;
    }
 
-   /**
-    * create a {@link StoredMap} persisted by the <code>database</code>
-    *
-    * @param database     where entries in the StoredMap are persisted
-    * @param classCatalog location to store class descriptions
-    * @return StoredMap backed by the database and classCatalog
-    * @throws DatabaseException if the StoredMap cannot be opened.
-    */
-   private StoredMap createStoredMapViewOfDatabase(Database database, StoredClassCatalog classCatalog) throws DatabaseException {
-      EntryBinding storedEntryKeyBinding =
-            new SerialBinding(classCatalog, Object.class);
-      EntryBinding storedEntryValueBinding =
-            new SerialBinding(classCatalog, StoredEntry.class);
-      try {
-         return new StoredMap<Object, StoredEntry>(database,
-                                                   storedEntryKeyBinding, storedEntryValueBinding, true);
-      } catch (Exception caught) {
-         caught = ExceptionUnwrapper.unwrap(caught);
-         throw new DatabaseException("error opening stored map", caught);
-      }
+   private void closeSleepyCatResources() throws CacheLoaderException {
+      cacheMap = null;
+      closeDatabases();
+      closeEnvironment();
    }
 
    /**
-    * Closes the JE databases and their associated {@link StoredMap}, and nulls references to them. The databases are
-    * not removed from the file system. Exceptions during close are ignored.
+    * Exceptions are ignored so that {@link org.horizon.loader.bdbje.BdbjeCacheStore#closeEnvironment()}  will execute.
     */
    private void closeDatabases() {
       if (trace) log.trace("closing databases");
       try {
          cacheDb.close();
+      } catch (Exception e) {
+         log.error("Error closing database", e);
+      }
+      try {
          catalog.close();
-      } catch (DatabaseException e) {
-         log.error("Error closing databases", e);
+      } catch (Exception e) {
+         log.error("Error closing catalog", e);
       }
-      cacheDb = null;
-      catalog = null;
       cacheMap = null;
+      catalog = null;
+      cacheDb = null;
    }
 
-
-   /**
-    * {@link org.horizon.loader.bdbje.BdbjeCacheStore#closeDatabases() Closes the JE databases} and the {@link
-    * Environment}.  The environment and databases are not removed from the file system. Exceptions during close are
-    * ignored.
-    */
-   public void stop() throws CacheLoaderException {
-      checkOpen();
-      if (trace) log.trace("stopping BdbjeCacheStore");
-      transactionRunner = null;
-      currentTransaction = null;
-      txnMap = null;
-      closeDatabases();
+   private void closeEnvironment() throws CacheLoaderException {
       if (env != null) {
          try {
             env.close();
+         } catch (DatabaseException e) {
+            throw new CacheLoaderException("Unexpected exception closing cacheStore", e);
          }
-         catch (Exception shouldNotOccur) {
-            log.warn("Unexpected exception closing cacheStore", shouldNotOccur);
-         }
       }
       env = null;
    }
@@ -281,30 +238,27 @@
     */
    @Override
    protected void applyModifications(List<? extends Modification> mods) throws CacheLoaderException {
-      checkOpen();
-      checkNonNull(mods, "modifications");
-      log.debug("performing one phase transaction");
+      if (trace) log.trace("performing one phase transaction");
       try {
          transactionRunner.run(new ModificationsTransactionWorker(this, mods));
-      } catch (Exception e) {
-         throw new CacheLoaderException("Problem committing modifications: " + mods, e);
+      } catch (Exception caught) {
+         throw convertToCacheLoaderException("Problem committing modifications: " + mods, caught);
       }
    }
 
    /**
     * Looks up the {@link Transaction SleepyCat transaction} associated with <code>tx</code>.  Creates a {@link
     * org.horizon.loader.bdbje.ModificationsTransactionWorker} instance from <code>mods</code>.  Then prepares the
-    * transaction via {@link PreparableTransactionRunner#prepare(com.sleepycat.collections.TransactionWorker)}.
+    * transaction via {@link PreparableTransactionRunner#prepare(com.sleepycat.collections.TransactionWorker)}. Finally,
+    * it invalidates {@link com.sleepycat.collections.CurrentTransaction#getTransaction()} so that no other thread can
+    * accidentally commit this.
     *
     * @param mods modifications to be applied
     * @param tx   transaction identifier
     * @throws CacheLoaderException in the event of problems writing to the store
     */
    protected void prepare(List<? extends Modification> mods, javax.transaction.Transaction tx) throws CacheLoaderException {
-      checkOpen();
-      checkNonNull(mods, "modifications");
-      checkNonNull(tx, "tx");
-      log.debug("preparing transaction {0}", tx);
+      if (trace) log.trace("preparing transaction {0}", tx);
       try {
          transactionRunner.prepare(new ModificationsTransactionWorker(this, mods));
          Transaction txn = currentTransaction.getTransaction();
@@ -312,7 +266,7 @@
          txnMap.put(tx, txn);
          ReflectionUtil.setValue(currentTransaction, "localTrans", new ThreadLocal());
       } catch (Exception e) {
-         throw new CacheLoaderException("Problem preparing transaction", e);
+         throw convertToCacheLoaderException("Problem preparing transaction", e);
       }
    }
 
@@ -343,26 +297,23 @@
 
    /**
     * Looks up the SleepyCat transaction associated with the parameter <code>tx</code>.  If there is no associated
-    * sleepycat transaction, an error is logged.  If this transaction is the {@link
-    * com.sleepycat.collections.CurrentTransaction#getTransaction()}  current transaction}, it calls {@link
-    * BdbjeCacheStore#completeCurrentTransaction(boolean)} passing the argument <code>commit</code>.  Otherwise, {@link
-    * BdbjeCacheStore#completeTransaction(com.sleepycat.je.Transaction, boolean) completeTransaction} is called, passing
-    * the SleepyCat transaction and <code>commit</code> as arguments.
+    * sleepycat transaction, an error is logged.
     *
     * @param tx     java transaction used to lookup a SleepyCat transaction
     * @param commit true to commit false to abort
     * @throws CacheLoaderException if there are problems committing or aborting the transaction
     */
    protected void completeTransaction(javax.transaction.Transaction tx, boolean commit) throws CacheLoaderException {
-      checkOpen();
-      checkNonNull(tx, "tx");
       Transaction txn = txnMap.remove(tx);
       if (txn != null) {
-         log.debug("transaction {0} == sleepycat transaction {1}", tx, txn);
-         if (currentTransaction.getTransaction() == txn) {
-            completeCurrentTransaction(commit);
-         } else {
-            completeTransaction(txn, commit);
+         if (trace) log.trace("{0} sleepycat transaction {1}", commit ? "committing" : "aborting", txn);
+         try {
+            if (commit)
+               txn.commit();
+            else
+               txn.abort();
+         } catch (Exception caught) {
+            throw convertToCacheLoaderException("Problem completing transaction", caught);
          }
       } else {
          if (trace) log.trace("no sleepycat transaction associated  transaction {0}", tx);
@@ -370,24 +321,6 @@
    }
 
    /**
-    * commits or aborts the {@link  Transaction}
-    *
-    * @param commit true to commit, false to abort
-    * @throws CacheLoaderException if there was a problem completing the transaction
-    */
-   private void completeTransaction(Transaction txn, boolean commit) throws CacheLoaderException {
-      try {
-         log.debug("{0} sleepycat transaction {1}", commit ? "committing" : "aborting", txn);
-         if (commit)
-            txn.commit();
-         else
-            txn.abort();
-      } catch (DatabaseException e) {
-         throw new CacheLoaderException("Problem completing transaction", e);
-      }
-   }
-
-   /**
     * commits or aborts the {@link com.sleepycat.collections.CurrentTransaction#getTransaction() current transaction}
     *
     * @param commit true to commit, false to abort
@@ -395,13 +328,14 @@
     */
    private void completeCurrentTransaction(boolean commit) throws CacheLoaderException {
       try {
-         log.debug("{0} current sleepycat transaction {1}", commit ? "committing" : "aborting", currentTransaction.getTransaction());
+         if (trace)
+            log.trace("{0} current sleepycat transaction {1}", commit ? "committing" : "aborting", currentTransaction.getTransaction());
          if (commit)
             currentTransaction.commitTransaction();
          else
             currentTransaction.abortTransaction();
-      } catch (DatabaseException e) {
-         throw new CacheLoaderException("Problem completing transaction", e);
+      } catch (Exception caught) {
+         throw convertToCacheLoaderException("Problem completing transaction", caught);
       }
    }
 
@@ -409,19 +343,15 @@
     * {@inheritDoc} This implementation delegates to {@link StoredMap#remove(Object)}
     */
    public boolean remove(Object key) throws CacheLoaderException {
-      checkOpen();
-      checkNonNull(key, "key");
-      if (trace) log.trace("Removing key {0}", key);
       try {
          if (cacheMap.containsKey(key)) {
             cacheMap.remove(key);
             return true;
          }
-      } catch (Exception caught) {
-         caught = ExceptionUnwrapper.unwrap(caught);
-         throw new CacheLoaderException("error removing key " + key, caught);
+         return false;
+      } catch (RuntimeException caught) {
+         throw convertToCacheLoaderException("error removing key " + key, caught);
       }
-      return false;
    }
 
    /**
@@ -429,36 +359,26 @@
     * not be returned.
     */
    public StoredEntry load(Object key) throws CacheLoaderException {
-      checkOpen();
-      checkNonNull(key, "key");
-      if (trace) log.trace("Loading key {0}", key);
       try {
          StoredEntry s = cacheMap.get(key);
-         if (s == null)
-            return null;
-         if (!s.isExpired())
-            return s;
-         else
+         if (s != null && s.isExpired()) {
             cacheMap.remove(key);
-      } catch (Exception caught) {
-         caught = ExceptionUnwrapper.unwrap(caught);
-         throw new CacheLoaderException("error loading key " + key, caught);
+            s = null;
+         }
+         return s;
+      } catch (RuntimeException caught) {
+         throw convertToCacheLoaderException("error loading key " + key, caught);
       }
-      return null;
    }
 
    /**
     * {@inheritDoc} This implementation delegates to {@link StoredMap#put(Object, Object)}
     */
    public void store(StoredEntry ed) throws CacheLoaderException {
-      checkOpen();
-      checkNonNull(ed, "entry");
-      if (trace) log.trace("Storing entry {0}", ed);
       try {
          cacheMap.put(ed.getKey(), ed);
-      } catch (Exception caught) {
-         caught = ExceptionUnwrapper.unwrap(caught);
-         throw new CacheLoaderException("error storing entry " + ed, caught);
+      } catch (RuntimeException caught) {
+         throw convertToCacheLoaderException("error storing entry " + ed, caught);
       }
    }
 
@@ -466,11 +386,10 @@
     * {@inheritDoc} This implementation delegates to {@link StoredMap#clear()}
     */
    public void clear() throws CacheLoaderException {
-      checkOpen();
-      if (trace) log.trace("Clearing store");
-      try {cacheMap.clear(); } catch (Exception caught) {
-         caught = ExceptionUnwrapper.unwrap(caught);
-         throw new CacheLoaderException("error clearing store", caught);
+      try {
+         cacheMap.clear();
+      } catch (RuntimeException caught) {
+         throw convertToCacheLoaderException("error clearing store", caught);
       }
    }
 
@@ -478,13 +397,10 @@
     * {@inheritDoc} This implementation returns a Set from {@link StoredMap#values()}
     */
    public Set<StoredEntry> loadAll() throws CacheLoaderException {
-      checkOpen();
-      if (trace) log.trace("Loading all entries");
       try {
          return new HashSet(cacheMap.values());
-      } catch (Exception caught) {
-         caught = ExceptionUnwrapper.unwrap(caught);
-         throw new CacheLoaderException("error loading all entries ", caught);
+      } catch (RuntimeException caught) {
+         throw convertToCacheLoaderException("error loading all entries", caught);
       }
    }
 
@@ -497,13 +413,10 @@
     * @see BdbjeCacheStore#toStream(java.io.ObjectOutput)
     */
    public void fromStream(ObjectInput ois) throws CacheLoaderException {
-      checkOpen();
-      log.info("Clearing all entries and loading from input");
       try {
          long recordCount = ois.readLong();
-         log.info("reading {0} records from stream", recordCount);
-         log.info("clearing all records");
          currentTransaction.beginTransaction(null);
+         log.debug("clearing and reading {0} records from stream", recordCount);
          cacheMap.clear();
          Cursor cursor = null;
          try {
@@ -520,13 +433,10 @@
             if (cursor != null) cursor.close();
          }
          completeCurrentTransaction(true);
-      }
-      catch (Exception caught) {
+      } catch (Exception caught) {
          completeCurrentTransaction(false);
-         caught = ExceptionUnwrapper.unwrap(caught);
-         CacheLoaderException cle = (caught instanceof CacheLoaderException) ? (CacheLoaderException) caught :
-               new CacheLoaderException("Problems reading from stream", caught);
-         throw cle;
+         clear();
+         throw convertToCacheLoaderException("Problems reading from stream", caught);
       }
    }
 
@@ -537,103 +447,69 @@
     * This implementation holds a transaction open to ensure that we see no new records added while iterating.
     */
    public void toStream(ObjectOutput oos) throws CacheLoaderException {
-      checkOpen();
-      if (trace) log.trace("dumping current database to outputstream");
-      Cursor cursor = null;
       try {
          currentTransaction.beginTransaction(null);
          long recordCount = cacheDb.count();
-         log.debug("writing {0} records to stream", recordCount);
+         if (trace) log.trace("writing {0} records to stream", recordCount);
          oos.writeLong(recordCount);
-
-         cursor = cacheDb.openCursor(currentTransaction.getTransaction(), null);
-         DatabaseEntry key = new DatabaseEntry();
-         DatabaseEntry data = new DatabaseEntry();
-         int recordsWritten = 0;
-         while (cursor.getNext(key, data, null) ==
-               OperationStatus.SUCCESS) {
-            oos.writeObject(key.getData());
-            oos.writeObject(data.getData());
-            recordsWritten++;
-         }
-         log.debug("wrote {0} records to stream", recordsWritten);
-         if (recordsWritten != recordCount)
-            log.warn("expected to write {0} records, but wrote {1}", recordCount, recordsWritten);
-         cursor.close();
-         cursor = null;
-         currentTransaction.commitTransaction();
-      } catch (Exception caught) {
+         Cursor cursor = null;
          try {
-            currentTransaction.abortTransaction();
-         } catch (DatabaseException e) {
-            log.error("error aborting transaction", e);
+            cursor = cacheDb.openCursor(currentTransaction.getTransaction(), null);
+            DatabaseEntry key = new DatabaseEntry();
+            DatabaseEntry data = new DatabaseEntry();
+            int recordsWritten = 0;
+            while (cursor.getNext(key, data, null) ==
+                  OperationStatus.SUCCESS) {
+               oos.writeObject(key.getData());
+               oos.writeObject(data.getData());
+               recordsWritten++;
+            }
+            if (trace) log.trace("wrote {0} records to stream", recordsWritten);
+            if (recordsWritten != recordCount)
+               log.warn("expected to write {0} records, but wrote {1}", recordCount, recordsWritten);
+         } finally {
+            if (cursor != null) cursor.close();
          }
-         caught = ExceptionUnwrapper.unwrap(caught);
-         CacheLoaderException cle = (caught instanceof CacheLoaderException) ? (CacheLoaderException) caught :
-               new CacheLoaderException("Problems writing to stream", caught);
-         throw cle;
+         completeCurrentTransaction(true);
+      } catch (Exception caught) {
+         completeCurrentTransaction(false);
+         throw convertToCacheLoaderException("Problems writing to stream", caught);
       }
-      finally {
-         if (cursor != null) try {
-            cursor.close();
-         } catch (DatabaseException e) {
-            throw new CacheLoaderException("Error closing cursor", e);
-         }
-      }
    }
 
    /**
-    * {@inheritDoc} If there is a {@link com.sleepycat.collections.CurrentTransaction#getTransaction() transaction in
-    * progress}, this method will invoke {@link #doPurgeExpired()} Otherwise, it will purge expired entries,
-    * autocommitting each.
+    * In order to adhere to APIs which do not throw checked exceptions, BDBJE wraps IO and DatabaseExceptions inside
+    * RuntimeExceptions.  These special Exceptions implement {@link com.sleepycat.util.ExceptionWrapper}.  This method
+    * will look for any of that type of Exception and encapsulate it into a CacheLoaderException.  In doing so, the real
+    * root cause can be obtained.
     *
-    * @see org.horizon.loader.bdbje.BdbjeCacheStoreConfig#isPurgeSynchronously()
-    * @see org.horizon.loader.bdbje.BdbjeCacheStoreConfig#setMaxTxRetries(int)
+    * @param message what to attach to the CacheLoaderException
+    * @param caught  exception to parse
+    * @return CacheLoaderException with the correct cause
     */
-   public void purgeExpired() throws CacheLoaderException {
-      checkOpen();
-      if (currentTransaction.getTransaction() != null) {
-         doPurgeExpired();
-      } else {
-         purgerService.execute(new Runnable() {
-            public void run() {
-               try {
-                  doPurgeExpired();
-               } catch (Exception e) {
-                  log.error("error purging expired entries", e);
-               }
-            }
-         });
-      }
+   CacheLoaderException convertToCacheLoaderException(String message, Exception caught) {
+      caught = ExceptionUnwrapper.unwrap(caught);
+      return (caught instanceof CacheLoaderException) ? (CacheLoaderException) caught :
+            new CacheLoaderException(message, caught);
    }
 
    /**
     * Iterate through {@link com.sleepycat.collections.StoredMap#entrySet()} and remove, if expired.
     */
-   private void doPurgeExpired() {
-      log.info("purging expired from database");
-      Iterator<Map.Entry<Object, StoredEntry>> i = cacheMap.entrySet().iterator();
-      while (i.hasNext()) {
-         if (i.next().getValue().isExpired())
-            i.remove();
+   @Override
+   protected void purgeInternal() throws CacheLoaderException {
+      try {
+         Iterator<Map.Entry<Object, StoredEntry>> i = cacheMap.entrySet().iterator();
+         while (i.hasNext()) {
+            if (i.next().getValue().isExpired())
+               i.remove();
+         }
+      } catch (RuntimeException caught) {
+         throw convertToCacheLoaderException("error purging expired entries", caught);
       }
    }
 
    /**
-    * @return the name of the SleepyCat database persisting this  store
-    */
-   public String getCacheDbName() {
-      return cacheDbName;
-   }
-
-   /**
-    * @return the name of the SleepyCat database persisting the class information for objects in this store
-    */
-   public String getCatalogDbName() {
-      return catalogDbName;
-   }
-
-   /**
     * prints terms of use for Berkeley DB JE
     */
    public void printLicense() {
@@ -652,34 +528,4 @@
       System.out.println(license);
    }
 
-   /**
-    * Throws an exception if the environment is not open.
-    */
-   private void checkNotOpen() {
-      if (env != null) {
-         throw new IllegalStateException(
-               "Operation not allowed after calling create()");
-      }
-   }
-
-   /**
-    * Throws an exception if the environment is not open.
-    */
-   private void checkOpen() {
-      if (env == null) {
-         throw new IllegalStateException(
-               "Operation not allowed before calling create()");
-      }
-   }
-
-   /**
-    * Throws an exception if the parameter is null.
-    */
-   private void checkNonNull(Object param, String paramName) {
-      if (param == null) {
-         throw new NullPointerException(
-               "Parameter must not be null: " + paramName);
-      }
-   }
-
 }

Modified: core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfig.java	2009-03-05 00:23:55 UTC (rev 7853)
+++ core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfig.java	2009-03-05 02:09:04 UTC (rev 7854)
@@ -1,30 +1,37 @@
 package org.horizon.loader.bdbje;
 
-import org.horizon.loader.AbstractCacheLoaderConfig;
+import org.horizon.loader.AbstractCacheStoreConfig;
 
 /**
  * Configures {@link org.horizon.loader.bdbje.BdbjeCacheStore}.  This allows you to tune a number of characteristics of
  * the {@link BdbjeCacheStore}.
  * <p/>
  * <ul> <li><tt>location</tt> - a location on disk where the store can write internal files.  This defaults to
- * <tt>Horizon-BdbjeCacheStore</tt> in the current working directory.</li> <li><tt>purgeSynchronously</tt> - whether {@link
- * org.horizon.loader.CacheStore#purgeExpired()} calls happen synchronously or not.  By default, this is set to
- * <tt>false</tt>.</li> <li><tt>lockAcquistionTimeout</tt> - the length of time, in milliseconds, to wait for locks
+ * <tt>Horizon-BdbjeCacheStore</tt> in the current working directory.</li> <li><tt>lockAcquistionTimeout</tt> - the length of time, in milliseconds, to wait for locks
  * before timing out and throwing an exception.  By default, this is set to <tt>60000</tt>.</li>
  * <li><tt>maxTxRetries</tt> - the number of times transaction prepares will attempt to resolve a deadlock before
- * throwing an exception.  By default, this is set to <tt>5</tt>.</li> </ul>
+ * throwing an exception.  By default, this is set to <tt>5</tt>.</li>
+ * <p/>
+ * <li><tt>cacheDbName</tt> - the name of the SleepyCat database persisting this store.  This defaults to <tt>{@link
+ * org.horizon.Cache#getName()} cache#name}</tt>.</li> <li><tt>catalogDbName</tt> - the name of the SleepyCat database
+ * persisting the class information for objects in this store.  This defaults to <tt>{@link org.horizon.Cache#getName()}
+ * cache#name}_class_catalog</tt>.</li>
+ * <p/>
+ * </ul>
  *
+ * Please see {@link AbstractCacheStoreConfig} for more configuration parameters.
+ * 
  * @author Adrian Cole
  * @version $Id: $
  * @since 1.0
  */
-public class BdbjeCacheStoreConfig extends AbstractCacheLoaderConfig {
+public class BdbjeCacheStoreConfig extends AbstractCacheStoreConfig {
    private String location = "Horizon-BdbjeCacheStore";
-   private boolean purgeSynchronously;
    private long lockAcquistionTimeout = 60 * 1000;
    private int maxTxRetries = 5;
+   private String cacheDbName;
+   private String catalogDbName;
 
-
    public BdbjeCacheStoreConfig() {
       setClassName(BdbjeCacheStore.class.getName());
    }
@@ -55,12 +62,21 @@
       this.location = location;
    }
 
-   public boolean isPurgeSynchronously() {
-      return purgeSynchronously;
+
+   public String getCacheDbName() {
+      return cacheDbName;
    }
 
-   public void setPurgeSynchronously(boolean purgeSynchronously) {
-      this.purgeSynchronously = purgeSynchronously;
+   public void setCacheDbName(String cacheDbName) {
+      this.cacheDbName = cacheDbName;
    }
 
+   public String getCatalogDbName() {
+      return catalogDbName;
+   }
+
+   public void setCatalogDbName(String catalogDbName) {
+      this.catalogDbName = catalogDbName;
+   }
+
 }

Added: core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeResourceFactory.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeResourceFactory.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeResourceFactory.java	2009-03-05 02:09:04 UTC (rev 7854)
@@ -0,0 +1,107 @@
+package org.horizon.loader.bdbje;
+
+import com.sleepycat.bind.EntryBinding;
+import com.sleepycat.bind.serial.SerialBinding;
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.collections.CurrentTransaction;
+import com.sleepycat.collections.StoredMap;
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseConfig;
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Environment;
+import com.sleepycat.je.EnvironmentConfig;
+import com.sleepycat.util.ExceptionUnwrapper;
+import org.horizon.loader.StoredEntry;
+import org.horizon.logging.Log;
+import org.horizon.logging.LogFactory;
+
+import java.io.File;
+
+/**
+ * Factory that assembles objects specific to the SleepyCat JE API.
+ *
+ * @author Adrian Cole
+ * @version $Id: $
+ * @since 1.0
+ */
+public class BdbjeResourceFactory {
+   private static final Log log = LogFactory.getLog(BdbjeResourceFactory.class);
+   private static final boolean trace = log.isTraceEnabled();
+
+   private BdbjeCacheStoreConfig config;
+
+   public BdbjeResourceFactory(BdbjeCacheStoreConfig config) {
+      this.config = config;
+   }
+
+   /**
+    * @return PreparableTransactionRunner that will try to resolve deadlocks maximum of {@link BdbjeCacheStoreConfig#getMaxTxRetries()} times.
+    */
+   public PreparableTransactionRunner createPreparableTransactionRunner(Environment env) {
+      return new PreparableTransactionRunner(env, config.getMaxTxRetries(), null);
+   }
+
+   public CurrentTransaction createCurrentTransaction(Environment env) {
+      return CurrentTransaction.getInstance(env);
+   }
+
+   /**
+    * Open the environment, creating it if it doesn't exist.
+    * @param envLocation base directory where the Environment will write files
+    * @return open Environment with a lock timeout of {@link org.horizon.loader.bdbje.BdbjeCacheStoreConfig#getLockAcquistionTimeout()} milliseconds.
+    */
+   public Environment createEnvironment(File envLocation) throws DatabaseException {
+      EnvironmentConfig envConfig = new EnvironmentConfig();
+      envConfig.setAllowCreate(true);
+      envConfig.setTransactional(true);
+      /* lock timeout is in microseconds */
+      envConfig.setLockTimeout(config.getLockAcquistionTimeout() * 1000);
+      if (trace) log.trace("opening or creating je environment at {0}", envLocation);
+      Environment env = new Environment(envLocation, envConfig);
+      log.debug("opened je environment at {0}", envLocation);
+      return env;
+   }
+
+   public StoredClassCatalog createStoredClassCatalog(Database catalogDb) throws DatabaseException {
+      StoredClassCatalog catalog = new StoredClassCatalog(catalogDb);
+      log.debug("created stored class catalog from database {0}", config.getCatalogDbName());
+      return catalog;
+   }
+
+   /**
+    * Open the database, creating it if it doesn't exist.
+    * @return open transactional Database
+    */
+   public Database createDatabase(Environment env, String name) throws DatabaseException {
+      DatabaseConfig dbConfig = new DatabaseConfig();
+      dbConfig.setTransactional(true);
+      dbConfig.setAllowCreate(true);
+      if (trace) log.trace("opening or creating database {0}", name);
+      Database db = env.openDatabase(null, name, dbConfig);
+      log.debug("opened database {0}", name);
+      return db;
+   }
+
+   /**
+    * create a {@link com.sleepycat.collections.StoredMap} persisted by the <code>database</code>
+    *
+    * @param database     where entries in the StoredMap are persisted
+    * @param classCatalog location to store class descriptions
+    * @return StoredMap backed by the database and classCatalog
+    * @throws com.sleepycat.je.DatabaseException
+    *          if the StoredMap cannot be opened.
+    */
+   public StoredMap createStoredMapViewOfDatabase(Database database, StoredClassCatalog classCatalog) throws DatabaseException {
+      EntryBinding storedEntryKeyBinding =
+            new SerialBinding(classCatalog, Object.class);
+      EntryBinding storedEntryValueBinding =
+            new SerialBinding(classCatalog, StoredEntry.class);
+      try {
+         return new StoredMap<Object, StoredEntry>(database,
+                                                   storedEntryKeyBinding, storedEntryValueBinding, true);
+      } catch (Exception caught) {
+         caught = ExceptionUnwrapper.unwrap(caught);
+         throw new DatabaseException("error opening stored map", caught);
+      }
+   }
+}
\ No newline at end of file

Modified: core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfigTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfigTest.java	2009-03-05 00:23:55 UTC (rev 7853)
+++ core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfigTest.java	2009-03-05 02:09:04 UTC (rev 7854)
@@ -67,13 +67,15 @@
    }
 
    @Test
-   public void testIsPurgeSynchronously() {
-      assert !config.isPurgeSynchronously();
+   public void testSetCacheDb() {
+      config.setCacheDbName("foo");
+      assert config.getCacheDbName().equals("foo");
    }
 
    @Test
-   public void testSetPurgeSynchronously() {
-      config.setPurgeSynchronously(true);
-      assert config.isPurgeSynchronously();
+   public void testSetCatalogDb() {
+      config.setCatalogDbName("foo");
+      assert config.getCatalogDbName().equals("foo");
    }
+   
 }

Modified: core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreIntegrationTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreIntegrationTest.java	2009-03-05 00:23:55 UTC (rev 7853)
+++ core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreIntegrationTest.java	2009-03-05 02:09:04 UTC (rev 7854)
@@ -23,6 +23,7 @@
  */
 @Test(groups = "unit", enabled = true, testName = "loader.bdbje.BdbjeCacheStoreIntegrationTest")
 public class BdbjeCacheStoreIntegrationTest extends BaseCacheStoreTest {
+
    protected CacheStore createCacheStore() throws CacheLoaderException {
       CacheStore cs = new BdbjeCacheStore();
       String tmpDir = TestingUtil.TEST_FILES;

Added: core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreTest.java	2009-03-05 02:09:04 UTC (rev 7854)
@@ -0,0 +1,358 @@
+package org.horizon.loader.bdbje;
+
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.collections.CurrentTransaction;
+import com.sleepycat.collections.StoredMap;
+import com.sleepycat.collections.TransactionWorker;
+import com.sleepycat.je.Cursor;
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Environment;
+import com.sleepycat.util.RuntimeExceptionWrapper;
+import static org.easymock.classextension.EasyMock.*;
+import org.horizon.Cache;
+import org.horizon.loader.CacheLoaderException;
+import org.horizon.loader.StoredEntry;
+import org.horizon.loader.modifications.Store;
+import org.horizon.util.ReflectionUtil;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.transaction.Transaction;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.lang.ref.WeakReference;
+import java.util.Collections;
+
+/**
+ * @author Adrian Cole
+ * @version $Id: $
+ * @since 1.0
+ */
+ at Test(groups = "unit", enabled = true, testName = "loader.bdbje.BdbjeCacheStoreTest")
+public class BdbjeCacheStoreTest {
+   private BdbjeCacheStore cs;
+   private BdbjeCacheStoreConfig cfg;
+   private BdbjeResourceFactory factory;
+   private Cache cache;
+   private Environment env;
+   private Database cacheDb;
+   private Database catalogDb;
+   private StoredClassCatalog catalog;
+   private StoredMap cacheMap;
+   private PreparableTransactionRunner runner;
+   private CurrentTransaction currentTransaction;
+
+   private class MockBdbjeResourceFactory extends BdbjeResourceFactory {
+
+      @Override
+      public PreparableTransactionRunner createPreparableTransactionRunner(Environment env) {
+         return runner;
+      }
+
+      @Override
+      public CurrentTransaction createCurrentTransaction(Environment env) {
+         return currentTransaction;
+      }
+
+      @Override
+      public Environment createEnvironment(File envLocation) throws DatabaseException {
+         return env;
+      }
+
+      @Override
+      public StoredClassCatalog createStoredClassCatalog(Database catalogDb) throws DatabaseException {
+         return catalog;
+      }
+
+      @Override
+      public Database createDatabase(Environment env, String name) throws DatabaseException {
+         if (name.equals(cfg.getCacheDbName()))
+            return cacheDb;
+         else
+            return catalogDb;
+      }
+
+      @Override
+      public StoredMap createStoredMapViewOfDatabase(Database database, StoredClassCatalog classCatalog) throws DatabaseException {
+         return cacheMap;
+      }
+
+      public MockBdbjeResourceFactory(BdbjeCacheStoreConfig config) {
+         super(config);
+      }
+   }
+
+   @BeforeMethod
+   public void setUp() throws Exception {
+      cfg = new BdbjeCacheStoreConfig();
+      factory = new MockBdbjeResourceFactory(cfg);
+      cache = createMock(Cache.class);
+      cs = new BdbjeCacheStore();
+      env = createMock(Environment.class);
+      cacheDb = createMock(Database.class);
+      catalogDb = createMock(Database.class);
+      catalog = createMock(StoredClassCatalog.class);
+      cacheMap = createMock(StoredMap.class);
+      currentTransaction = createMock(CurrentTransaction.class);
+      WeakReference<Environment> envRef = new WeakReference<Environment>(env);
+      ReflectionUtil.setValue(currentTransaction,"envRef",envRef);
+      ThreadLocal localTrans = new ThreadLocal();
+      ReflectionUtil.setValue(currentTransaction,"localTrans",localTrans);
+      runner = createMock(PreparableTransactionRunner.class);
+   }
+
+   @AfterMethod
+   public void tearDown() throws CacheLoaderException {
+      runner = null;
+      currentTransaction = null;
+      cacheMap = null;
+      catalogDb = null;
+      cacheDb = null;
+      env = null;
+      factory = null;
+      cache = null;
+      cfg = null;
+      cs = null;
+   }
+
+   void start() throws DatabaseException, CacheLoaderException {
+      cs.init(cfg, factory, cache);
+      expect(cache.getName()).andReturn("cache");
+   }
+
+   @Test
+   public void testGetConfigurationClass() throws Exception {
+      replayAll();
+      assert cs.getConfigurationClass().equals(BdbjeCacheStoreConfig.class);
+      verifyAll();
+   }
+
+   void replayAll() throws Exception {
+      replay(runner);
+      replay(currentTransaction);
+      replay(cacheMap);
+      replay(catalog);
+      replay(catalogDb);
+      replay(cacheDb);
+      replay(env);
+      replay(cache);
+   }
+
+   void verifyAll() throws Exception {
+      verify(runner);
+      verify(currentTransaction);
+      verify(cacheMap);
+      verify(catalog);
+      verify(catalogDb);
+      verify(env);
+      verify(cache);
+   }
+
+   @Test
+   public void testInitNoMock() throws Exception {
+      replayAll();
+      cs.init(cfg, cache, null);
+      assert cfg.equals(ReflectionUtil.getValue(cs, "cfg"));
+      assert cache.equals(ReflectionUtil.getValue(cs, "cache"));
+      assert ReflectionUtil.getValue(cs, "factory") instanceof BdbjeResourceFactory;
+      verifyAll();
+   }
+
+   @Test
+   void testExceptionClosingCacheDatabaseDoesntPreventEnvironmentFromClosing() throws Exception {
+      start();
+      cacheDb.close();
+      expectLastCall().andThrow(new DatabaseException());
+      catalog.close();
+      env.close();
+      replayAll();
+      cs.start();
+      cs.stop();
+
+      verifyAll();
+   }
+
+   @Test
+   void testExceptionClosingCatalogDoesntPreventEnvironmentFromClosing() throws Exception {
+      start();
+      cacheDb.close();
+      catalog.close();
+      expectLastCall().andThrow(new DatabaseException());
+      env.close();
+      replayAll();
+      cs.start();
+      cs.stop();
+      verifyAll();
+   }
+
+   @Test(expectedExceptions = CacheLoaderException.class)
+   void testExceptionClosingEnvironment() throws Exception {
+      start();
+      cacheDb.close();
+      catalog.close();
+      env.close();
+      expectLastCall().andThrow(new DatabaseException());
+      replayAll();
+      cs.start();
+      cs.stop();
+      verifyAll();
+   }
+
+
+   @Test(expectedExceptions = CacheLoaderException.class)
+   void testThrowsCorrectExceptionOnStartForDatabaseException() throws Exception {
+      factory = new MockBdbjeResourceFactory(cfg) {
+         @Override
+         public StoredClassCatalog createStoredClassCatalog(Database catalogDb) throws DatabaseException {
+            throw new DatabaseException();
+         }
+      };
+      start();
+      replayAll();
+      cs.start();
+
+   }
+
+   @Test(expectedExceptions = CacheLoaderException.class)
+   void testEnvironmentDirectoryExistsButNotAFile() throws Exception {
+      File file = createMock(File.class);
+      expect(file.exists()).andReturn(true);
+      expect(file.isDirectory()).andReturn(false);
+      replay(file);
+      cs.verifyOrCreateEnvironmentDirectory(file);
+   }
+
+   @Test(expectedExceptions = CacheLoaderException.class)
+   void testCantCreateEnvironmentDirectory() throws Exception {
+      File file = createMock(File.class);
+      expect(file.exists()).andReturn(false);
+      expect(file.mkdirs()).andReturn(false);
+      replay(file);
+      cs.verifyOrCreateEnvironmentDirectory(file);
+   }
+
+   @Test
+   void testCanCreateEnvironmentDirectory() throws Exception {
+      File file = createMock(File.class);
+      expect(file.exists()).andReturn(false);
+      expect(file.mkdirs()).andReturn(true);
+      expect(file.isDirectory()).andReturn(true);
+      replay(file);
+      assert file.equals(cs.verifyOrCreateEnvironmentDirectory(file));
+   }
+
+   @Test
+   public void testNoExceptionOnRollback() throws Exception {
+      start();
+      Transaction tx = createMock(Transaction.class);
+      replayAll();
+      cs.start();
+      cs.rollback(tx);
+      verifyAll();
+   }
+
+   @Test
+   protected void testApplyModificationsThrowsOriginalDatabaseException() throws Exception {
+      start();
+      DatabaseException ex = new DatabaseException();
+      runner.run(isA(TransactionWorker.class));
+      expectLastCall().andThrow(new RuntimeExceptionWrapper(ex));
+      replayAll();
+      cs.start();
+      try {
+         cs.applyModifications(Collections.singletonList(new Store(new StoredEntry("k", "v"))));
+         assert false : "should have gotten an exception";
+      } catch (CacheLoaderException e) {
+         assert ex.equals(e.getCause());
+         verifyAll();
+         return;
+      }
+      assert false : "should have returned";
+
+   }
+
+   @Test
+   protected void testCommitThrowsOriginalDatabaseException() throws Exception {
+      start();
+      DatabaseException ex = new DatabaseException();
+      com.sleepycat.je.Transaction txn = createMock(com.sleepycat.je.Transaction.class);
+      expect(currentTransaction.beginTransaction(null)).andReturn(txn);
+      runner.prepare(isA(TransactionWorker.class));
+      txn.commit();
+      expectLastCall().andThrow(new RuntimeExceptionWrapper(ex));
+      replayAll();
+      replay(txn);
+      cs.start();
+      try {
+         txn = currentTransaction.beginTransaction(null);
+         Transaction t = createMock(Transaction.class);
+         cs.prepare(Collections.singletonList(new Store(new StoredEntry("k", "v"))), t,false);
+         cs.commit(t);
+         assert false : "should have gotten an exception";
+      } catch (CacheLoaderException e) {
+         assert ex.equals(e.getCause());
+         verifyAll();
+         return;
+      }
+      assert false : "should have returned";
+
+   }
+            
+   @Test
+   protected void testPrepareThrowsOriginalDatabaseException() throws Exception {
+      start();
+      DatabaseException ex = new DatabaseException();
+      runner.prepare(isA(TransactionWorker.class));
+      expectLastCall().andThrow(new RuntimeExceptionWrapper(ex));
+      replayAll();
+      cs.start();
+      try {
+         cs.prepare(Collections.singletonList(new Store(new StoredEntry("k", "v"))), createMock(Transaction.class),false);
+         assert false : "should have gotten an exception";
+      } catch (CacheLoaderException e) {
+         assert ex.equals(e.getCause());
+         verifyAll();
+         return;
+      }
+      assert false : "should have returned";
+
+   }
+
+   @Test
+   void testClearOnAbortFromStream() throws Exception {
+      start();
+      StoredEntry entry = new StoredEntry();
+      expect(cacheMap.put(entry.getKey(), entry)).andReturn(null);
+      ObjectInput ois = createMock(ObjectInput.class);
+      expect(ois.readLong()).andReturn(new Long(1));
+      com.sleepycat.je.Transaction txn = createMock( com.sleepycat.je.Transaction.class);
+      expect(currentTransaction.beginTransaction(null)).andReturn(txn);
+      cacheMap.clear();
+      Cursor cursor = createMock(Cursor.class);
+      expect(cacheDb.openCursor(txn, null)).andReturn(cursor);
+      IOException ex = new IOException();
+      expect(ois.readObject()).andReturn(new byte[0]);
+      expectLastCall().andThrow(ex);
+      txn.abort();
+      cacheMap.clear();
+      replay(ois);
+      replay(txn);
+      replayAll();
+      cs.start();
+      try {
+         cs.store(entry);
+         cs.fromStream(ois);
+         assert false : "should have gotten an exception";
+      } catch (CacheLoaderException e) {
+         assert ex.equals(e.getCause());
+         verifyAll();
+         verify(ois);
+         verify(txn);
+         return;
+      }
+      assert false : "should have returned";
+   }
+}

Modified: core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeLearningTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeLearningTest.java	2009-03-05 00:23:55 UTC (rev 7853)
+++ core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeLearningTest.java	2009-03-05 02:09:04 UTC (rev 7854)
@@ -662,6 +662,7 @@
       assert expected.isEmpty();
    }
 
+   @Test (enabled = false)
    public void testConcurrency() throws Throwable {
       int numThreads = 3;
       final int loops = 500;

Added: core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeResourceFactoryTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeResourceFactoryTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeResourceFactoryTest.java	2009-03-05 02:09:04 UTC (rev 7854)
@@ -0,0 +1,48 @@
+package org.horizon.loader.bdbje;
+
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Environment;
+import static org.easymock.classextension.EasyMock.createMock;
+import org.horizon.loader.CacheLoaderException;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ * @version $Id: $
+ * @since 1.0
+ */
+ at Test(groups = "unit", enabled = true, testName = "loader.bdbje.BdbjeResourceFactoryTest")
+public class BdbjeResourceFactoryTest {
+   private BdbjeCacheStoreConfig cfg;
+   private Environment env;
+   private BdbjeResourceFactory factory;
+   private Database cacheDb;
+   private StoredClassCatalog catalog;
+
+   @BeforeMethod
+   public void setUp() throws Exception {
+      cfg = new BdbjeCacheStoreConfig();
+      factory = new BdbjeResourceFactory(cfg);
+      env = createMock(Environment.class);
+      cacheDb = createMock(Database.class);
+      catalog = createMock(StoredClassCatalog.class);
+   }
+
+   @AfterMethod
+   public void tearDown() throws CacheLoaderException {
+      env = null;
+      factory = null;
+      cfg = null;
+      cacheDb = null;
+      catalog = null;
+   }
+
+   @Test(expectedExceptions = DatabaseException.class)
+   public void testCreateStoredMapViewOfDatabaseThrowsException() throws DatabaseException {
+      factory.createStoredMapViewOfDatabase(cacheDb, catalog);
+   }
+}




More information about the jbosscache-commits mailing list