d8807c389717b36a65142bf0ac44b7a222ad7f29
[utils] / test / enterprise / src / main / java / org / wamblee / support / persistence / DatabaseBuilder.java
1 /*
2  * Copyright 2005-2010 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */ 
16 package org.wamblee.support.persistence;
17
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.List;
21 import java.util.ServiceLoader;
22 import java.util.logging.Logger;
23
24 /**
25  * DatabaseBuilder is used from unit test to obtain a reference to a database
26  * from unit test. This database is either an inmemory database or represents an
27  * external database. Purpose of this utility is to make test code independent
28  * of the particular database used and specifically to be able to run database
29  * tests without any configuration at all (using an inmemory database).
30  * 
31  * The type of database to use can be overridden by specifying either a system
32  * property or an environment variable ({@link #DB_CAPABILITIES_PROP}) that
33  * contains the comma-separated capabilities of the database. Each database type
34  * provides its own capabilities (see {@link DatabaseProvider} implementations}.
35  * 
36  * 
37  * There are currently two database types available:
38  * <ul>
39  * <li>Derby: AN inmemory derby. Provided by {@link DerbyDatabaseProvider}. This
40  * is the default.</li>
41  * <li>External: An arbitrary external database configured using system
42  * properties or environment variables in the usual way using a JDBC URL,
43  * username, and password.</li>
44  * </ul>
45  * 
46  * The <code>DatabaseBuilder</code> uses the {@link ServiceLoader} mechanism to
47  * find implementations of {@link DatabaseProvider} on the classpath. In the
48  * {@link #getDatabase(String...)} method a number of capabilities are passed.
49  * The database providers are then searched in (arbitrary) order and the first
50  * one that has all required capabilities is returned.
51  * 
52  * {@link #getSupportedDatabases()} gives a list of all available databases.
53  */
54 public class DatabaseBuilder {
55
56     private static final Logger LOGGER = Logger.getLogger(DatabaseBuilder.class
57         .getName());
58
59     /**
60      * Environmment variable by which capabilities of the requested database can
61      * be defined
62      */
63     private static final String DB_CAPABILITIES_PROP = "TEST_DB_CAPABILITIES";
64
65     private static ServiceLoader<DatabaseProvider> LOADER = 
66         ServiceLoader.load(DatabaseProvider.class);
67
68     private DatabaseBuilder() {
69         // Empty.
70     }
71
72     private static String[] parseCapabilities(String aValue) {
73         return aValue.split(",");
74     }
75
76     /**
77      * Gets the first database that has all required capabilities.
78      * 
79      * @param aCapabilities
80      *            Capabilities.
81      * @return Database to use.
82      */
83     public static Database getDatabase(String... aCapabilities) {
84         if (aCapabilities.length == 0) {
85             LOGGER.info("Examining database capabilities");
86             LOGGER.info("  Checking system property " + DB_CAPABILITIES_PROP);
87             String capabilities = System.getProperty(DB_CAPABILITIES_PROP);
88             if (capabilities != null) {
89                 aCapabilities = parseCapabilities(capabilities);
90             } else {
91                 LOGGER.info("  Checking environment variable " +
92                     DB_CAPABILITIES_PROP);
93                 capabilities = System.getenv(DB_CAPABILITIES_PROP);
94                 if (capabilities != null) {
95                     aCapabilities = parseCapabilities(capabilities);
96                 } else {
97                     LOGGER.info("  Using default capabilities");
98                     aCapabilities = new String[] { DatabaseProvider.CAPABILITY_IN_MEMORY };
99                 }
100             }
101             LOGGER.info("Using capabilities: " + Arrays.asList(aCapabilities));
102         }
103         synchronized (DatabaseBuilder.class) {
104             for (DatabaseProvider db : LOADER) {
105                 if (db.supportsCapabilities(aCapabilities)) {
106                     return db.create();
107                 }
108             }
109         }
110         throw new RuntimeException(
111             "No database found that satisfies capabilities: " +
112                 Arrays.asList(aCapabilities));
113     }
114
115     /**
116      * Gets a list of available databases.
117      * 
118      * @return List of databases.
119      */
120     public static List<DatabaseDescription> getSupportedDatabases() {
121         List<DatabaseDescription> descriptions = new ArrayList<DatabaseDescription>();
122         for (DatabaseProvider db : LOADER) {
123             descriptions.add(db.getDescription());
124         }
125         return descriptions;
126     }
127
128 }