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.io.FileInputStream;
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      /** Constant for the configuration table. */
45      public static final String TABLE = "configuration";
46  
47      /** Constant for the multi configuration table. */
48      public static final String TABLE_MULTI = "configurations";
49  
50      /** Constant for the column with the keys. */
51      public static final String COL_KEY = "key";
52  
53      /** Constant for the column with the values. */
54      public static final String COL_VALUE = "value";
55  
56      /** Constant for the column with the configuration name. */
57      public static final String COL_NAME = "name";
58  
59      /** Constant for the name of the test configuration. */
60      public static final String CONFIG_NAME = "test";
61  
62      /** Constant for the JDBC driver class. */
63      public final String DATABASE_DRIVER = "org.hsqldb.jdbcDriver";
64  
65      /** Constant for the connection URL. */
66      public final String DATABASE_URL = "jdbc:hsqldb:mem:testdb";
67  
68      /** Constant for the DB user name. */
69      public final String DATABASE_USERNAME = "sa";
70  
71      /** Constant for the DB password. */
72      public final String DATABASE_PASSWORD = "";
73  
74      /** Stores the in-process database. */
75      private HsqlDB hsqlDB;
76  
77      /** The data source. */
78      private DataSource datasource;
79  
80      /**
81       * The auto-commit mode for the configuration instances created by this helper.
82       */
83      private boolean autoCommit;
84  
85      /**
86       * Creates a configuration instance of the specified class with the given parameters.
87       *
88       * @param <T> the type of the result configuration
89       * @param configCls the configuration class
90       * @param params the parameters object
91       * @return the newly created configuration instance
92       * @throws ConfigurationException if an error occurs
93       */
94      public <T extends DatabaseConfiguration> T createConfig(final Class<T> configCls, final DatabaseBuilderParameters params) throws ConfigurationException {
95          return new BasicConfigurationBuilder<>(configCls).configure(params).getConfiguration();
96      }
97  
98      /**
99       * Returns the {@code DataSource} managed by this class. The data source is created on first access.
100      *
101      * @return the {@code DataSource}
102      */
103     public DataSource getDatasource() {
104         if (datasource == null) {
105             try {
106                 datasource = setUpDataSource();
107             } catch (final Exception ex) {
108                 throw new ConfigurationRuntimeException("Could not create data source", ex);
109             }
110         }
111         return datasource;
112     }
113 
114     /**
115      * Returns the auto-commit mode of the configuration instances created by this helper.
116      *
117      * @return the auto-commit mode
118      */
119     public boolean isAutoCommit() {
120         return autoCommit;
121     }
122 
123     /**
124      * Sets the auto-commit mode of the configuration instances created by this helper.
125      *
126      * @param autoCommit the auto-commit mode
127      */
128     public void setAutoCommit(final boolean autoCommit) {
129         this.autoCommit = autoCommit;
130     }
131 
132     /**
133      * Initializes this helper object. This method can be called from a {@code setUp()} method of a unit test class. It
134      * creates the database instance if necessary.
135      *
136      * @throws Exception if an error occurs
137      */
138     public void setUp() throws Exception {
139         final File script = ConfigurationAssert.getTestFile("testdb.script");
140         hsqlDB = new HsqlDB(DATABASE_URL, DATABASE_DRIVER, script.getAbsolutePath());
141     }
142 
143     /**
144      * Creates a database configuration with default settings.
145      *
146      * @return the configuration
147      * @throws ConfigurationException if an error occurs
148      */
149     public DatabaseConfiguration setUpConfig() throws ConfigurationException {
150         return setUpConfig(DatabaseConfiguration.class);
151     }
152 
153     /**
154      * Creates a database configuration with default settings of the specified class.
155      *
156      * @param <T> the type of the result configuration
157      * @param configCls the configuration class
158      * @return the newly created configuration instance
159      * @throws ConfigurationException if an error occurs
160      */
161     public <T extends DatabaseConfiguration> T setUpConfig(final Class<T> configCls) throws ConfigurationException {
162         return createConfig(configCls, setUpDefaultParameters());
163     }
164 
165     /**
166      * Creates the internal data source. This method also initializes the database.
167      *
168      * @return the data source
169      * @throws Exception if an error occurs
170      */
171     private DataSource setUpDataSource() throws Exception {
172         final BasicDataSource ds = new BasicDataSource();
173         ds.setDriverClassName(DATABASE_DRIVER);
174         ds.setUrl(DATABASE_URL);
175         ds.setUsername(DATABASE_USERNAME);
176         ds.setPassword(DATABASE_PASSWORD);
177         ds.setDefaultAutoCommit(!isAutoCommit());
178 
179         // prepare the database
180         final Connection conn = ds.getConnection();
181         final IDatabaseConnection connection = new DatabaseConnection(conn);
182         final IDataSet dataSet = new XmlDataSet(new FileInputStream(ConfigurationAssert.getTestFile("dataset.xml")));
183 
184         try {
185             DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
186         } finally {
187             if (!isAutoCommit()) {
188                 conn.commit();
189             }
190             connection.close();
191         }
192 
193         return ds;
194     }
195 
196     /**
197      * Returns a parameters object with default settings.
198      *
199      * @return the parameters object
200      */
201     public DatabaseBuilderParameters setUpDefaultParameters() {
202         return new Parameters().database().setDataSource(getDatasource()).setTable(TABLE).setKeyColumn(COL_KEY).setValueColumn(COL_VALUE)
203             .setAutoCommit(isAutoCommit());
204     }
205 
206     /**
207      * Creates a database configuration that supports multiple configurations in a table with default values.
208      *
209      * @return the configuration
210      * @throws ConfigurationException if an error occurs
211      */
212     public DatabaseConfiguration setUpMultiConfig() throws ConfigurationException {
213         return setUpMultiConfig(DatabaseConfiguration.class, null);
214     }
215 
216     /**
217      * Creates a configuration with support for multiple configuration instances in a single table of the specified class.
218      *
219      * @param <T> the type of the result configuration
220      * @param configCls the configuration class
221      * @param configName the name of the configuration instance or <b>null</b> for the default name
222      * @return the newly created configuration instance
223      * @throws ConfigurationException if an error occurs
224      */
225     public <T extends DatabaseConfiguration> T setUpMultiConfig(final Class<T> configCls, final String configName) throws ConfigurationException {
226         return createConfig(configCls, setUpMultiParameters(configName));
227     }
228 
229     /**
230      * Returns a parameters object with settings for a configuration table containing the data of multiple configurations.
231      *
232      * @param configName the name of the configuration instance or <b>null</b> for the default name
233      * @return the parameters object
234      */
235     public DatabaseBuilderParameters setUpMultiParameters(final String configName) {
236         return setUpDefaultParameters().setTable(TABLE_MULTI).setConfigurationNameColumn(COL_NAME)
237             .setConfigurationName(configName != null ? configName : CONFIG_NAME);
238     }
239 
240     /**
241      * Frees the resources used by this helper class. This method can be called by a {@code tearDown()} method of a unit
242      * test class.
243      *
244      * @throws Exception if an error occurs
245      */
246     public void tearDown() throws Exception {
247         if (datasource != null) {
248             datasource.getConnection().close();
249         }
250         hsqlDB.close();
251     }
252 }