View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.configuration2;
18  
19  import java.io.File;
20  import java.nio.file.Files;
21  import java.sql.Connection;
22  
23  import javax.sql.DataSource;
24  
25  import org.apache.commons.configuration2.builder.BasicConfigurationBuilder;
26  import org.apache.commons.configuration2.builder.fluent.DatabaseBuilderParameters;
27  import org.apache.commons.configuration2.builder.fluent.Parameters;
28  import org.apache.commons.configuration2.ex.ConfigurationException;
29  import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
30  import org.apache.commons.configuration2.test.HsqlDB;
31  import org.apache.commons.dbcp2.BasicDataSource;
32  import org.dbunit.database.DatabaseConnection;
33  import org.dbunit.database.IDatabaseConnection;
34  import org.dbunit.dataset.IDataSet;
35  import org.dbunit.dataset.xml.XmlDataSet;
36  import org.dbunit.operation.DatabaseOperation;
37  
38  /**
39   * A helper class for performing tests for {@link DatabaseConfiguration}. This class maintains an in-process database
40   * that stores configuration data and can be accessed from a {@link DatabaseConfiguration} instance. Constants for table
41   * and column names and database connection settings are provided, too.
42   */
43  public class DatabaseConfigurationTestHelper {
44  
45      /** Constant for the configuration table. */
46      public static final String TABLE = "configuration";
47  
48      /** Constant for the multi configuration table. */
49      public static final String TABLE_MULTI = "configurations";
50  
51      /** Constant for the column with the keys. */
52      public static final String COL_KEY = "key";
53  
54      /** Constant for the column with the values. */
55      public static final String COL_VALUE = "value";
56  
57      /** Constant for the column with the configuration name. */
58      public static final String COL_NAME = "name";
59  
60      /** Constant for the name of the test configuration. */
61      public static final String CONFIG_NAME = "test";
62  
63      /** Constant for the JDBC driver class. */
64      public static final String DATABASE_DRIVER = "org.hsqldb.jdbcDriver";
65  
66      /** Constant for the connection URL. */
67      public static final String DATABASE_URL = "jdbc:hsqldb:mem:testdb";
68  
69      /** Constant for the DB user name. */
70      public static final String DATABASE_USERNAME = "sa";
71  
72      /** Constant for the DB password. */
73      public static final String DATABASE_PASSWORD = "";
74  
75      /** Stores the in-process database. */
76      private HsqlDB hsqlDB;
77  
78      /** The data source. */
79      private DataSource dataSource;
80  
81      /**
82       * The auto-commit mode for the configuration instances created by this helper.
83       */
84      private boolean autoCommit;
85  
86      /**
87       * Creates a configuration instance of the specified class with the given parameters.
88       *
89       * @param <T> the type of the result configuration
90       * @param configCls the configuration class
91       * @param params the parameters object
92       * @return the newly created configuration instance
93       * @throws ConfigurationException if an error occurs
94       */
95      public <T extends DatabaseConfiguration> T createConfiguration(final Class<T> configCls, final DatabaseBuilderParameters params)
96              throws ConfigurationException {
97          return new BasicConfigurationBuilder<>(configCls).configure(params).getConfiguration();
98      }
99  
100     /**
101      * Returns the {@code DataSource} managed by this class. The data source is created on first access.
102      *
103      * @return the {@code DataSource}
104      */
105     public DataSource getDataSource() {
106         if (dataSource == null) {
107             try {
108                 dataSource = setUpDataSource();
109             } catch (final Exception ex) {
110                 throw new ConfigurationRuntimeException("Could not create data source", ex);
111             }
112         }
113         return dataSource;
114     }
115 
116     /**
117      * Returns the auto-commit mode of the configuration instances created by this helper.
118      *
119      * @return the auto-commit mode
120      */
121     public boolean isAutoCommit() {
122         return autoCommit;
123     }
124 
125     /**
126      * Sets the auto-commit mode of the configuration instances created by this helper.
127      *
128      * @param autoCommit the auto-commit mode
129      */
130     public void setAutoCommit(final boolean autoCommit) {
131         this.autoCommit = autoCommit;
132     }
133 
134     /**
135      * Initializes this helper object. This method can be called from a {@code setUp()} method of a unit test class. It
136      * creates the database instance if necessary.
137      *
138      * @throws Exception if an error occurs
139      */
140     public void setUp() throws Exception {
141         final File script = ConfigurationAssert.getTestFile("testdb.script");
142         hsqlDB = new HsqlDB(DATABASE_URL, DATABASE_DRIVER, script.getAbsolutePath());
143     }
144 
145     /**
146      * Creates a database configuration with default settings.
147      *
148      * @return the configuration
149      * @throws ConfigurationException if an error occurs
150      */
151     public DatabaseConfiguration setUpConfig() throws ConfigurationException {
152         return setUpConfig(DatabaseConfiguration.class);
153     }
154 
155     /**
156      * Creates a database configuration with default settings of the specified class.
157      *
158      * @param <T> the type of the result configuration
159      * @param configCls the configuration class
160      * @return the newly created configuration instance
161      * @throws ConfigurationException if an error occurs
162      */
163     public <T extends DatabaseConfiguration> T setUpConfig(final Class<T> configCls) throws ConfigurationException {
164         return createConfiguration(configCls, setUpDefaultParameters());
165     }
166 
167     /**
168      * Creates the internal data source. This method also initializes the database.
169      *
170      * @return the data source
171      * @throws Exception if an error occurs
172      */
173     private DataSource setUpDataSource() throws Exception {
174         final BasicDataSource ds = new BasicDataSource();
175         ds.setDriverClassName(DATABASE_DRIVER);
176         ds.setUrl(DATABASE_URL);
177         ds.setUsername(DATABASE_USERNAME);
178         ds.setPassword(DATABASE_PASSWORD);
179         ds.setDefaultAutoCommit(!isAutoCommit());
180 
181         // prepare the database
182         final Connection conn = ds.getConnection();
183         final IDatabaseConnection connection = new DatabaseConnection(conn);
184         final IDataSet dataSet = new XmlDataSet(Files.newInputStream(ConfigurationAssert.getTestPath("dataset.xml")));
185 
186         try {
187             DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
188         } finally {
189             if (!isAutoCommit()) {
190                 conn.commit();
191             }
192             connection.close();
193         }
194 
195         return ds;
196     }
197 
198     /**
199      * Returns a parameters object with default settings.
200      *
201      * @return the parameters object
202      */
203     public DatabaseBuilderParameters setUpDefaultParameters() {
204         return new Parameters().database().setDataSource(getDataSource()).setTable(TABLE).setKeyColumn(COL_KEY).setValueColumn(COL_VALUE)
205             .setAutoCommit(isAutoCommit());
206     }
207 
208     /**
209      * Creates a database configuration that supports multiple configurations in a table with default values.
210      *
211      * @return the configuration
212      * @throws ConfigurationException if an error occurs
213      */
214     public DatabaseConfiguration setUpMultiConfig() throws ConfigurationException {
215         return setUpMultiConfig(DatabaseConfiguration.class, null);
216     }
217 
218     /**
219      * Creates a configuration with support for multiple configuration instances in a single table of the specified class.
220      *
221      * @param <T> the type of the result configuration
222      * @param configCls the configuration class
223      * @param configName the name of the configuration instance or <strong>null</strong> for the default name
224      * @return the newly created configuration instance
225      * @throws ConfigurationException if an error occurs
226      */
227     public <T extends DatabaseConfiguration> T setUpMultiConfig(final Class<T> configCls, final String configName) throws ConfigurationException {
228         return createConfiguration(configCls, setUpMultiParameters(configName));
229     }
230 
231     /**
232      * Returns a parameters object with settings for a configuration table containing the data of multiple configurations.
233      *
234      * @param configName the name of the configuration instance or <strong>null</strong> for the default name
235      * @return the parameters object
236      */
237     public DatabaseBuilderParameters setUpMultiParameters(final String configName) {
238         return setUpDefaultParameters().setTable(TABLE_MULTI).setConfigurationNameColumn(COL_NAME)
239             .setConfigurationName(configName != null ? configName : CONFIG_NAME);
240     }
241 
242     /**
243      * Frees the resources used by this helper class. This method can be called by a {@code tearDown()} method of a unit
244      * test class.
245      *
246      * @throws Exception if an error occurs
247      */
248     public void tearDown() throws Exception {
249         if (dataSource != null) {
250             dataSource.getConnection().close();
251         }
252         hsqlDB.close();
253     }
254 }