View Javadoc
1   /*
2    *
3    * The DbUnit Database Testing Framework
4    * Copyright (C)2002-2004, DbUnit.org
5    *
6    * This library is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Lesser General Public
8    * License as published by the Free Software Foundation; either
9    * version 2.1 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public
17   * License along with this library; if not, write to the Free Software
18   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   *
20   */
21  
22  package org.dbunit;
23  
24  import java.io.File;
25  import java.io.FileReader;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.sql.Connection;
29  import java.sql.DriverManager;
30  import java.util.Properties;
31  import java.util.concurrent.Callable;
32  
33  import org.dbunit.database.DatabaseConfig;
34  import org.dbunit.database.DatabaseConnection;
35  import org.dbunit.database.IDatabaseConnection;
36  import org.dbunit.dataset.IDataSet;
37  import org.dbunit.dataset.xml.XmlDataSet;
38  import org.dbunit.testutil.TestUtils;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  /**
43   * @author Manuel Laflamme
44   * @version $Revision$
45   * @since Feb 18, 2002
46   */
47  public class DatabaseEnvironment
48  {
49      private static final String DBUNIT_PROPERTIES_FILENAME =
50              "dbunit.properties";
51  
52      private static final Logger logger =
53              LoggerFactory.getLogger(DatabaseEnvironment.class);
54  
55      private static DatabaseEnvironment INSTANCE = null;
56  
57      private DatabaseProfile _profile = null;
58      private IDatabaseConnection _connection = null;
59      private IDataSet _dataSet = null;
60      private IDatabaseTester _databaseTester = null;
61  
62      /**
63       * Optional "dbunit.properties" is loaded (if present and the
64       * "dbunit.profile" property is null) and merged with System properties and
65       * the whole set is returned.
66       * <p>
67       * If absent (which is the normal scenario), only System properties are
68       * returned.
69       * <p>
70       * "dbunit.properties" is useful for environment which make it difficult if
71       * not impossible to use Maven's profiles. Example is IntelliJ IDEA which
72       * when calling Junit tests, bypass Maven completely. Since profiles are not
73       * used, database configuration is not properly set and tests fail.
74       * "dbunit.properties" contains the missing properties which a profile would
75       * set.
76       * <p>
77       * Following is a few properties as an example of the content of
78       * "dbunit.properties":
79       * <p>
80       *
81       * <pre>
82       * database.profile=h2
83       * dbunit.profile.driverClass=org.hsqldb.jdbcDriver
84       * dbunit.profile.url=jdbc:hsqldb:mem:.
85       * </pre>
86       * <p>
87       * Simply create "dbunit.properties" under "src/test/resources".
88       *
89       * @return Merged DbUnit and System properties.
90       * @throws IOException
91       *             Thrown if an error occurs when attempting to read
92       *             "dbunit.properties".
93       */
94      protected static Properties getProperties() throws IOException
95      {
96          final Properties properties = System.getProperties();
97  
98          final String profileName =
99                  properties.getProperty(DatabaseProfile.DATABASE_PROFILE);
100 
101         // only load from file if not already set
102         if (profileName == null)
103         {
104             loadDbunitPropertiesFromFile(properties);
105         }
106 
107         return properties;
108     }
109 
110     protected static void loadDbunitPropertiesFromFile(
111             final Properties properties) throws IOException
112     {
113         final InputStream inputStream =
114                 DatabaseEnvironment.class.getClassLoader()
115                         .getResourceAsStream(DBUNIT_PROPERTIES_FILENAME);
116         if (inputStream != null)
117         {
118             logger.info("Loaded properties from file '{}'",
119                     DBUNIT_PROPERTIES_FILENAME);
120             properties.load(inputStream);
121             inputStream.close();
122         }
123     }
124 
125     public static DatabaseEnvironment getInstance() throws Exception
126     {
127         if (INSTANCE == null)
128         {
129             final DatabaseProfile profile =
130                     new DatabaseProfile(getProperties());
131 
132             final String profileName = profile.getActiveProfile();
133             if (profileName == null || profileName.equals("hsqldb"))
134             {
135                 INSTANCE = new HypersonicEnvironment(profile);
136             } else if (profileName.equals("oracle"))
137             {
138                 INSTANCE = new OracleEnvironment(profile);
139             } else if (profileName.equals("oracle10"))
140             {
141                 INSTANCE = new Oracle10Environment(profile);
142             } else if (profileName.equals("postgresql"))
143             {
144                 INSTANCE = new PostgresqlEnvironment(profile);
145             } else if (profileName.equals("mysql"))
146             {
147                 INSTANCE = new MySqlEnvironment(profile);
148             } else if (profileName.equals("derby"))
149             {
150                 INSTANCE = new DerbyEnvironment(profile);
151             } else if (profileName.equals("h2"))
152             {
153                 INSTANCE = new H2Environment(profile);
154             } else if (profileName.equals("mssql"))
155             {
156                 INSTANCE = new MsSqlEnvironment(profile);
157             } else
158             {
159                 INSTANCE = new DatabaseEnvironment(profile);
160             }
161         }
162 
163         return INSTANCE;
164     }
165 
166     public DatabaseEnvironment(final DatabaseProfile profile,
167             final Callable<Void> preDdlFunction) throws Exception
168     {
169         if (null != preDdlFunction)
170         {
171             preDdlFunction.call();
172         }
173 
174         _profile = profile;
175         final File file = TestUtils.getFile("xml/dataSetTest.xml");
176         _dataSet = new XmlDataSet(new FileReader(file));
177         _databaseTester = new JdbcDatabaseTester(_profile.getDriverClass(),
178                 _profile.getConnectionUrl(), _profile.getUser(),
179                 _profile.getPassword(), _profile.getSchema());
180 
181         DdlExecutor.execute("sql/" + _profile.getProfileDdl(),
182                 getConnection().getConnection(),
183                 profile.getProfileMultilineSupport(), true);
184     }
185 
186     public DatabaseEnvironment(final DatabaseProfile profile) throws Exception
187     {
188         this(profile, null);
189     }
190 
191     public IDatabaseConnection getConnection() throws Exception
192     {
193         // First check if the current connection is still valid and open
194         // The connection may have been closed by a consumer
195         if (_connection != null && _connection.getConnection().isClosed())
196         {
197             // Reset the member so that a new connection will be created
198             _connection = null;
199         }
200 
201         if (_connection == null)
202         {
203             final String name = _profile.getDriverClass();
204             Class.forName(name);
205             final Connection connection =
206                     DriverManager.getConnection(_profile.getConnectionUrl(),
207                             _profile.getUser(), _profile.getPassword());
208             _connection =
209                     new DatabaseConnection(connection, _profile.getSchema());
210         }
211         return _connection;
212     }
213 
214     protected void setupDatabaseConfig(final DatabaseConfig config)
215     {
216         // Override in subclasses as necessary.
217     }
218 
219     public IDatabaseTester getDatabaseTester()
220     {
221         return _databaseTester;
222     }
223 
224     public void closeConnection() throws Exception
225     {
226         if (_connection != null)
227         {
228             _connection.close();
229             _connection = null;
230         }
231     }
232 
233     public IDataSet getInitDataSet() throws Exception
234     {
235         return _dataSet;
236     }
237 
238     public DatabaseProfile getProfile() throws Exception
239     {
240         return _profile;
241     }
242 
243     public boolean support(final TestFeature feature)
244     {
245         final String[] unsupportedFeatures = _profile.getUnsupportedFeatures();
246         for (int i = 0; i < unsupportedFeatures.length; i++)
247         {
248             final String unsupportedFeature = unsupportedFeatures[i];
249             if (feature.toString().equals(unsupportedFeature))
250             {
251                 return false;
252             }
253         }
254 
255         return true;
256     }
257 
258     /**
259      * Returns the string converted as an identifier according to the metadata
260      * rules of the database environment. Most databases convert all metadata
261      * identifiers to uppercase. PostgreSQL converts identifiers to lowercase.
262      * MySQL preserves case.
263      *
264      * @param str
265      *            The identifier.
266      * @return The identifier converted according to database rules.
267      */
268     public String convertString(final String str)
269     {
270         return str == null ? null : str.toUpperCase();
271     }
272 
273     @Override
274     public String toString()
275     {
276         final StringBuffer sb = new StringBuffer();
277         sb.append(getClass().getName()).append("[");
278         sb.append("_profile=").append(_profile);
279         sb.append(", _connection=").append(_connection);
280         sb.append(", _dataSet=").append(_dataSet);
281         sb.append(", _databaseTester=").append(_databaseTester);
282         sb.append("]");
283         return sb.toString();
284     }
285 }