--- /dev/null
+package org.wamblee.support.persistence;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.logging.Logger;
+
+/**
+ * DatabaseBuilder is used from unit test to obtain a reference to a database
+ * from unit test. This database is either an inmemory database or represents an
+ * external database. Purpose of this utility is to make test code independent of the
+ * particular database used and specifically to be able to run database tests without
+ * any configuration at all (using an inmemory database).
+ *
+ * The type of database to use can be overridden by specifying either a system
+ * property or an environment variable ({@link #DB_CAPABILITIES_PROP}) that
+ * contains the comma-separated capabilities of the database. Each database type
+ * provides its own capabilities (see {@link DatabaseProvider} implementations}.
+ *
+ *
+ * There are currently two database types available:
+ * <ul>
+ * <li> Derby: AN inmemory derby. Provided by {@link DerbyDatabaseProvider}. This is the default.
+ * </li>
+ * <li> External: An arbitrary external database configured using system properties or environment variables
+ * in the usual way using a JDBC URL, username, and password.
+ * </li>
+ * </ul>
+ *
+ * The <code>DatabaseBuilder</code> uses the {@link ServiceLoader} mechanism to find implementations
+ * of {@link DatabaseProvider} on the classpath. In the {@link #getDatabase(String...)} method a number of
+ * capabilities are passed. The database providers are then searched in (arbitrary) order and the first one that
+ * has all required capabilities is returned.
+ *
+ * {@link #getSupportedDatabases()} gives a list of all available databases.
+ */
+public class DatabaseBuilder {
+
+ private static final Logger LOGGER = Logger.getLogger(DatabaseBuilder.class
+ .getName());
+
+ /**
+ * Environmment variable by which capabilities of the requested database can
+ * be defined
+ */
+ private static final String DB_CAPABILITIES_PROP = "TEST_DB_CAPABILITIES";
+
+ private static ServiceLoader<DatabaseProvider> LOADER = null;
+
+ private DatabaseBuilder() {
+ // Empty.
+ }
+
+ private static String[] parseCapabilities(String aValue) {
+ return aValue.split(",");
+ }
+
+ /**
+ * Gets the first database that has all required capabilities.
+ * @param aCapabilities Capabilities.
+ * @return Database to use.
+ */
+ public static Database getDatabase(String... aCapabilities) {
+ if (aCapabilities.length == 0) {
+ LOGGER.info("Examining database capabilities");
+ LOGGER.info(" Checking system property " + DB_CAPABILITIES_PROP);
+ String capabilities = System.getProperty(DB_CAPABILITIES_PROP);
+ if (capabilities != null) {
+ aCapabilities = parseCapabilities(capabilities);
+ } else {
+ LOGGER.info(" Checking environment variable "
+ + DB_CAPABILITIES_PROP);
+ capabilities = System.getenv(DB_CAPABILITIES_PROP);
+ if (capabilities != null) {
+ aCapabilities = parseCapabilities(capabilities);
+ } else {
+ LOGGER.info(" Using default capabilities");
+ aCapabilities = new String[] { DatabaseProvider.CAPABILITY_IN_MEMORY };
+ }
+ }
+ LOGGER.info("Using capabilities: " + aCapabilities);
+ }
+ synchronized (DatabaseBuilder.class) {
+ initLoader();
+ for (DatabaseProvider db : LOADER) {
+ if (db.supportsCapabilities(aCapabilities)) {
+ return db.create();
+ }
+ }
+ }
+ throw new RuntimeException(
+ "No database found that satisfies capabilities: "
+ + Arrays.asList(aCapabilities));
+ }
+
+ /**
+ * Gets a list of available databases.
+ * @return List of databases.
+ */
+ public static List<DatabaseDescription> getSupportedDatabases() {
+ initLoader();
+ List<DatabaseDescription> descriptions = new ArrayList<DatabaseDescription>();
+ for (DatabaseProvider db : LOADER) {
+ descriptions.add(db.getDescription());
+ }
+ return descriptions;
+ }
+
+ private static void initLoader() {
+ if (LOADER == null) {
+ LOADER = ServiceLoader.load(DatabaseProvider.class);
+ }
+ }
+
+}