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:
*
* - Derby: AN inmemory derby. Provided by {@link DerbyDatabaseProvider}. This is the default.
*
* - External: An arbitrary external database configured using system properties or environment variables
* in the usual way using a JDBC URL, username, and password.
*
*
*
* The DatabaseBuilder
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 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 getSupportedDatabases() {
initLoader();
List descriptions = new ArrayList();
for (DatabaseProvider db : LOADER) {
descriptions.add(db.getDescription());
}
return descriptions;
}
private static void initLoader() {
if (LOADER == null) {
LOADER = ServiceLoader.load(DatabaseProvider.class);
}
}
}