Index: gs2-extensions/tdb/trunk/src/java/org/greenstone/tdbjava/TDBJava.java
===================================================================
--- gs2-extensions/tdb/trunk/src/java/org/greenstone/tdbjava/TDBJava.java	(revision 30269)
+++ gs2-extensions/tdb/trunk/src/java/org/greenstone/tdbjava/TDBJava.java	(revision 30270)
@@ -23,4 +23,5 @@
 import java.lang.System;
 import java.util.Enumeration;
+import java.util.HashMap;
 
 import org.greenstone.tdbjava.TDBJavaException;
@@ -52,9 +53,55 @@
     implements Closeable
 {
+
+    /** A cache of TDBJava objects that have been created keyed by filepath */
+    private static HashMap<String, TDBJava> connection_cache;
+
     static
     {
 	// Load native library mapping at runtime (libTDBJava.so)
 	System.loadLibrary("TDBJava");
-    }
+	connection_cache = new HashMap<String, TDBJava>();
+    }
+
+    /** @function getConnection(String)
+     * Factory method - uses an existing cached TDBJava otherwise creates
+     * a new one.  This should get around the issue with a single process of
+     * the libTDBJava.so above throwing EBUSY errors when trying to open
+     * multiple copies of the same database.
+     */
+    public static TDBJava getConnection(String filename)
+	throws TDBJavaException
+    {
+	TDBJava the_connection = connection_cache.get(filename);
+	if (null == the_connection) {
+	    the_connection = new TDBJava(filename);
+	    connection_cache.put(filename, the_connection);
+	}
+	// Keep track of the number of times this connection has been
+	// handed out
+	the_connection.registerCaller();
+	return the_connection;
+    }
+    /** getConnection(String) **/
+
+    public static TDBJava newConnection(String filename)
+	throws TDBJavaException
+    {
+	TDBJava the_connection = connection_cache.get(filename);
+	if (null == the_connection) {
+	    the_connection = new TDBJava(filename);
+	    connection_cache.put(filename, the_connection);
+	}
+	// delete all the records in an open connection
+	Enumeration keys = the_connection.keys();
+	while (keys.hasMoreElements()) {
+	    the_connection.delete((String) keys.nextElement());
+	}
+	// Keep track of the number of times this connection has been
+	// handed out
+	the_connection.registerCaller();
+	return the_connection;
+    }
+    /** newConnection(String) **/
 
     /* ===== Declare mappings to native methods ===== */
@@ -144,4 +191,9 @@
     private int    open_flags;
 
+    /** We need to keep a reference of the number of times this connection
+     * has been opened, and not process a close until they have *all* asked
+     * to close. */
+    private int caller_count;
+
     /** The TDB handle for the database file, or 0 if the database has
      * been closed.  Java doesn't understand it, but it stores it and
@@ -153,20 +205,34 @@
      *
      * @param filename the disk filename in which the data will be stored
-     * @param flags any of TDB_DEFAULT, TDB_CLEAR_IF_FIRST, TDB_INTERNAL, and
-     * TDB_NOLOCK
-     *
      */
     public TDBJava(String filename)
 	throws TDBJavaException
     {
-	this(filename, TDBJava.TDB_DEFAULT, TDBJava.O_DEFAULT);
-    }
-
+	this.filename = filename;
+	this.tdb_flags = TDBJava.TDB_DEFAULT;
+	this.open_flags = TDBJava.O_DEFAULT;
+	this.dbf = this.tdbOpen(this.filename, this.tdb_flags, this.open_flags);
+	this.caller_count = 0;
+	// Replacement for System.runFinalizersOnExit(true);
+	Thread shutdown_thread = new TDBJavaShutdownThread(this);
+	Runtime.getRuntime().addShutdownHook(shutdown_thread);
+    }
+    /** TDBJava(String) **/
+
+    /** @function TDBJava(String, int)
+     * @param filename the disk filename in which the data will be stored
+     * @param tdb_flags any of TDB_DEFAULT, TDB_CLEAR_IF_FIRST, TDB_INTERNAL,
+     *                  and TDB_NOLOCK
+     */
+    /*
     public TDBJava(String filename, int tdb_flags)
 	throws TDBJavaException
     {
-	this(filename, tdb_flags, TDBJava.O_DEFAULT);
-    }
-
+    }
+    */
+    /** **/
+
+    /* disabled for now to simplify caching
+     *
     public TDBJava(String filename, int tdb_flags, int open_flags)
 	throws TDBJavaException
@@ -180,4 +246,13 @@
 	Runtime.getRuntime().addShutdownHook(shutdown_thread);
     }
+    */
+
+    /** @function registerCaller()
+     */
+    public synchronized void registerCaller()
+    {
+	this.caller_count++;
+    }
+    /** registerCaller() **/
 
     /** Close the database file if it is still open.
@@ -187,9 +262,16 @@
     {
 	if (this.dbf != 0) {
-	    this.tdbClose(this.dbf);
-	}
-	// opened or created
-	this.dbf = 0;
-    }
+	    if (this.caller_count == 1) {
+		this.tdbClose(this.dbf);
+		this.dbf = 0;
+		// And remove from the cache
+		connection_cache.remove(this.filename);
+	    }
+	    else {
+		this.caller_count--;
+	    }
+	}
+    }
+    /** close() **/
 
     /** Close the database when the TDBJava is garbage-collected.
@@ -198,4 +280,6 @@
 	throws TDBJavaException
     {
+	// If we've got here, then we can't have any callers left
+	this.caller_count = 0;
 	this.close();
     }
