2 * Copyright 2005-2010 the original author or authors.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org.wamblee.support.persistence;
18 import java.sql.Connection;
19 import java.sql.PreparedStatement;
20 import java.sql.ResultSet;
21 import java.sql.SQLException;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.logging.Logger;
26 import javax.sql.DataSource;
28 import junit.framework.TestCase;
30 import org.dbunit.DataSourceDatabaseTester;
31 import org.dbunit.IDatabaseTester;
32 import org.dbunit.database.DatabaseConnection;
33 import org.dbunit.database.DatabaseSequenceFilter;
34 import org.dbunit.database.IDatabaseConnection;
35 import org.dbunit.dataset.FilteredDataSet;
36 import org.dbunit.dataset.IDataSet;
37 import org.dbunit.dataset.filter.ITableFilter;
38 import org.dbunit.dataset.filter.ITableFilterSimple;
39 import org.dbunit.operation.DatabaseOperation;
42 * Database utilities is a simple support class for common tasks in working with
45 public class DatabaseUtils {
47 public static interface TableSet {
48 boolean contains(String aTableName);
51 public static interface JdbcUnitOfWork<T> {
52 T execute(Connection aConnection) throws Exception;
55 public static interface TableSetOperation {
56 void execute(String aTable) throws Exception;
59 private static final Logger LOG = Logger.getLogger(DatabaseUtils.class
65 private static final String SCHEMA_PATTERN = "%";
66 private DataSource dataSource;
67 private ITableFilterSimple tables;
69 public DatabaseUtils(DataSource aDataSource, ITableFilterSimple aTables) {
70 dataSource = aDataSource;
74 public IDatabaseTester createDbTester() throws Exception {
75 return createDbTester(getTableNames(tables));
78 public IDatabaseTester createDbTester(String[] aTables) throws Exception {
79 IDatabaseTester dbtester = new DataSourceDatabaseTester(dataSource);
80 dbtester.setDataSet(dbtester.getConnection().createDataSet(aTables));
84 public void cleanDatabase() throws Exception {
85 cleanDatabase(tables);
88 public void executeOnTables(ITableFilterSimple aTables,
89 final TableSetOperation aOperation) throws Exception {
90 final String[] tables = getTableNames(aTables);
91 executeInTransaction(new JdbcUnitOfWork<Void>() {
92 public Void execute(Connection aConnection) throws Exception {
93 for (int i = tables.length-1; i >= 0; i--) {
94 aOperation.execute(tables[i]);
101 public void cleanDatabase(ITableFilterSimple aSelection) throws Exception {
103 final String[] tables = getTableNames(aSelection);
104 executeInTransaction(new JdbcUnitOfWork<Void>() {
106 public Void execute(Connection aConnection) throws Exception {
107 IDatabaseConnection connection = new DatabaseConnection(
109 ITableFilter filter = new DatabaseSequenceFilter(connection,
111 IDataSet dataset = new FilteredDataSet(filter, connection
112 .createDataSet(tables));
113 DatabaseOperation.DELETE_ALL.execute(connection, dataset);
120 public <T> T executeInTransaction(JdbcUnitOfWork<T> aCallback)
122 Connection connection = dataSource.getConnection();
124 T value = aCallback.execute(connection);
132 public String[] getTableNames() throws Exception {
133 return getTableNames(tables);
137 * @throws SQLException
139 public String[] getTableNames(ITableFilterSimple aSelection)
142 List<String> result = new ArrayList<String>();
143 LOG.fine("Getting database table names to clean (schema: '" +
144 SCHEMA_PATTERN + "'");
146 Connection connection = dataSource.getConnection();
148 ResultSet tables = connection.getMetaData().getTables(null,
149 SCHEMA_PATTERN, "%", new String[] { "TABLE" });
150 while (tables.next()) {
151 String table = tables.getString("TABLE_NAME");
152 if (aSelection.accept(table)) {
156 return (String[]) result.toArray(new String[0]);
162 public void emptyTables() throws Exception {
163 executeOnTables(tables, new TableSetOperation() {
164 public void execute(String aTable) throws Exception {
172 * @throws SQLException
174 public void emptyTables(final ITableFilterSimple aSelection)
176 executeOnTables(aSelection, new TableSetOperation() {
177 public void execute(String aTable) throws Exception {
185 * @throws SQLException
187 public void emptyTable(String aTable) throws Exception {
188 executeSql("delete from " + aTable);
191 public void dropTables() throws Exception {
195 public void dropTables(ITableFilterSimple aTables) throws Exception {
196 final String[] tables = getTableNames(aTables);
197 String[] sortedTables = executeInTransaction(new JdbcUnitOfWork<String[]>() {
199 public String[] execute(Connection aConnection) throws Exception {
200 IDatabaseConnection connection = new DatabaseConnection(
202 ITableFilter filter = new DatabaseSequenceFilter(connection,
204 IDataSet dataset = new FilteredDataSet(filter, connection
205 .createDataSet(tables));
206 return dataset.getTableNames();
209 for (int i = sortedTables.length-1; i >= 0; i--) {
210 dropTable(sortedTables[i]);
216 * @throws SQLException
218 public void dropTable(final String aTable) throws Exception {
219 executeInTransaction(new JdbcUnitOfWork<Void>() {
220 public Void execute(Connection aConnection) throws Exception {
221 executeUpdate(aConnection, "drop table " + aTable);
229 * Executes an SQL statement within a transaction.
233 * @return Return code of the corresponding JDBC call.
235 public int executeSql(final String aSql) throws Exception {
236 return executeSql(aSql, new Object[0]);
240 * Executes an SQL statement within a transaction. See
241 * {@link #setPreparedParam(int, PreparedStatement, Object)}for details on
242 * supported argument types.
247 * Argument of the sql statement.
248 * @return Return code of the corresponding JDBC call.
250 public int executeSql(final String aSql, final Object aArg)
252 return executeSql(aSql, new Object[] { aArg });
256 * Executes an sql statement. See
257 * {@link #setPreparedParam(int, PreparedStatement, Object)}for details on
258 * supported argument types.
261 * SQL query to execute.
264 * @return Number of rows updated.
266 public int executeSql(final String aSql, final Object[] aArgs)
268 return executeInTransaction(new JdbcUnitOfWork<Integer>() {
269 public Integer execute(Connection aConnection) throws Exception {
270 PreparedStatement stmt = aConnection.prepareStatement(aSql);
271 setPreparedParams(aArgs, stmt);
272 return stmt.executeUpdate();
278 * Executes an SQL query.
282 * @return Result set.
284 public ResultSet executeQuery(Connection aConnection, String aSql) {
285 return executeQuery(aConnection, aSql, new Object[0]);
289 * Executes a query with a single argument. See
290 * {@link #setPreparedParam(int, PreparedStatement, Object)}for details on
291 * supported argument types.
297 * @return Result set.
299 public ResultSet executeQuery(Connection aConnection, String aSql,
301 return executeQuery(aConnection, aSql, new Object[] { aArg });
305 * Executes a query. See
306 * {@link #setPreparedParam(int, PreparedStatement, Object)}for details on
307 * supported argument types.
312 * Arguments to the query.
313 * @return Result set.
315 public ResultSet executeQuery(Connection aConnection, final String aSql,
316 final Object[] aArgs) {
318 PreparedStatement statement = aConnection.prepareStatement(aSql);
319 setPreparedParams(aArgs, statement);
321 return statement.executeQuery();
322 } catch (SQLException e) {
323 throw new RuntimeException(e);
327 public int executeUpdate(Connection aConnection, final String aSql,
328 final Object... aArgs) {
330 PreparedStatement statement = aConnection.prepareStatement(aSql);
331 setPreparedParams(aArgs, statement);
333 return statement.executeUpdate();
334 } catch (SQLException e) {
335 throw new RuntimeException(e);
340 * Sets the values of a prepared statement. See
341 * {@link #setPreparedParam(int, PreparedStatement, Object)}for details on
342 * supported argument types.
345 * Arguments to the prepared statement.
348 * @throws SQLException
350 private void setPreparedParams(final Object[] aArgs,
351 PreparedStatement aStatement) throws SQLException {
352 for (int i = 1; i <= aArgs.length; i++) {
353 setPreparedParam(i, aStatement, aArgs[i - 1]);
358 * Sets a prepared statement parameter.
361 * Index of the parameter.
363 * Prepared statement.
365 * Value Must be of type Integer, Long, or String.
366 * @throws SQLException
368 private void setPreparedParam(int aIndex, PreparedStatement aStatement,
369 Object aObject) throws SQLException {
370 if (aObject instanceof Integer) {
371 aStatement.setInt(aIndex, ((Integer) aObject).intValue());
372 } else if (aObject instanceof Long) {
373 aStatement.setLong(aIndex, ((Long) aObject).longValue());
374 } else if (aObject instanceof String) {
375 aStatement.setString(aIndex, (String) aObject);
377 TestCase.fail("Unsupported object type for prepared statement: " +
378 aObject.getClass() + " value: " + aObject + " statement: " +
385 * @throws SQLException
387 public int getTableSize(final String aTable) throws Exception {
388 return executeInTransaction(new JdbcUnitOfWork<Integer>() {
389 public Integer execute(Connection aConnection) throws Exception {
390 ResultSet resultSet = executeQuery(aConnection,
391 "select count(*) from " + aTable);
393 return resultSet.getInt(1);
399 public int countResultSet(ResultSet aResultSet) throws SQLException {
402 while (aResultSet.next()) {