1 package org.wamblee.support.persistence;
3 import java.sql.Connection;
4 import java.sql.PreparedStatement;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
7 import java.util.ArrayList;
9 import java.util.logging.Logger;
11 import javax.sql.DataSource;
13 import junit.framework.TestCase;
15 import org.dbunit.DataSourceDatabaseTester;
16 import org.dbunit.IDatabaseTester;
17 import org.dbunit.database.DatabaseConnection;
18 import org.dbunit.database.DatabaseSequenceFilter;
19 import org.dbunit.database.IDatabaseConnection;
20 import org.dbunit.dataset.FilteredDataSet;
21 import org.dbunit.dataset.IDataSet;
22 import org.dbunit.dataset.filter.ITableFilter;
23 import org.dbunit.dataset.filter.ITableFilterSimple;
24 import org.dbunit.operation.DatabaseOperation;
27 * Database utilities is a simple support class for common tasks in working with
30 public class DatabaseUtils {
32 public static interface TableSet {
33 boolean contains(String aTableName);
36 public static interface JdbcUnitOfWork<T> {
37 T execute(Connection aConnection) throws Exception;
40 public static interface TableSetOperation {
41 void execute(String aTable) throws Exception;
44 private static final Logger LOG = Logger.getLogger(DatabaseUtils.class
50 private static final String SCHEMA_PATTERN = "%";
51 private DataSource dataSource;
52 private ITableFilterSimple tables;
55 public DatabaseUtils(DataSource aDataSource, ITableFilterSimple aTables) {
56 dataSource = aDataSource;
60 public IDatabaseTester createDbTester() throws Exception {
61 return createDbTester(getTableNames(tables));
64 public IDatabaseTester createDbTester(String[] aTables) throws Exception {
65 IDatabaseTester dbtester = new DataSourceDatabaseTester(dataSource);
66 dbtester.setDataSet(dbtester.getConnection().createDataSet(aTables));
70 public void cleanDatabase() throws Exception {
71 cleanDatabase(tables);
74 public void executeOnTables(ITableFilterSimple aTables,
75 final TableSetOperation aOperation) throws Exception {
76 final String[] tables = getTableNames(aTables);
77 executeInTransaction(new JdbcUnitOfWork<Void>() {
78 public Void execute(Connection aConnection) throws Exception {
79 for (int i = tables.length - 1; i >= 0; i--) {
80 aOperation.execute(tables[i]);
85 for (String table : tables) {
90 public void cleanDatabase(ITableFilterSimple aSelection) throws Exception {
92 final String[] tables = getTableNames(aSelection);
93 executeInTransaction(new JdbcUnitOfWork<Void>() {
95 public Void execute(Connection aConnection) throws Exception {
96 IDatabaseConnection connection = new DatabaseConnection(
98 ITableFilter filter = new DatabaseSequenceFilter(connection,
100 IDataSet dataset = new FilteredDataSet(filter, connection
101 .createDataSet(tables));
102 DatabaseOperation.DELETE_ALL.execute(connection, dataset);
109 public <T> T executeInTransaction(JdbcUnitOfWork<T> aCallback)
111 Connection connection = dataSource.getConnection();
113 T value = aCallback.execute(connection);
121 public String[] getTableNames() throws Exception {
122 return getTableNames(tables);
126 * @throws SQLException
128 public String[] getTableNames(ITableFilterSimple aSelection)
131 List<String> result = new ArrayList<String>();
132 LOG.fine("Getting database table names to clean (schema: '"
133 + SCHEMA_PATTERN + "'");
135 ResultSet tables = dataSource.getConnection().getMetaData().getTables(
136 null, SCHEMA_PATTERN, "%", new String[] { "TABLE" });
137 while (tables.next()) {
138 String table = tables.getString("TABLE_NAME");
139 if (aSelection.accept(table)) {
143 return (String[]) result.toArray(new String[0]);
146 public void emptyTables() throws Exception {
147 executeOnTables(tables, new TableSetOperation() {
148 public void execute(String aTable) throws Exception {
156 * @throws SQLException
158 public void emptyTables(final ITableFilterSimple aSelection)
160 executeOnTables(aSelection, new TableSetOperation() {
161 public void execute(String aTable) throws Exception {
169 * @throws SQLException
171 public void emptyTable(String aTable) throws Exception {
172 executeSql("delete from " + aTable);
175 public void dropTables() throws Exception {
176 executeOnTables(tables, new TableSetOperation() {
178 public void execute(String aTable) throws Exception {
185 public void dropTables(ITableFilterSimple aTables) throws Exception {
186 executeOnTables(aTables, new TableSetOperation() {
188 public void execute(String aTable) throws Exception {
196 * @throws SQLException
198 public void dropTable(final String aTable) throws Exception {
199 executeInTransaction(new JdbcUnitOfWork<Void>() {
200 public Void execute(Connection aConnection) throws Exception {
201 executeUpdate(aConnection, "drop table " + aTable);
209 * Executes an SQL statement within a transaction.
213 * @return Return code of the corresponding JDBC call.
215 public int executeSql(final String aSql) throws Exception {
216 return executeSql(aSql, new Object[0]);
220 * Executes an SQL statement within a transaction. See
221 * {@link #setPreparedParam(int, PreparedStatement, Object)}for details on
222 * supported argument types.
227 * Argument of the sql statement.
228 * @return Return code of the corresponding JDBC call.
230 public int executeSql(final String aSql, final Object aArg)
232 return executeSql(aSql, new Object[] { aArg });
236 * Executes an sql statement. See
237 * {@link #setPreparedParam(int, PreparedStatement, Object)}for details on
238 * supported argument types.
241 * SQL query to execute.
244 * @return Number of rows updated.
246 public int executeSql(final String aSql, final Object[] aArgs)
248 return executeInTransaction(new JdbcUnitOfWork<Integer>() {
249 public Integer execute(Connection aConnection) throws Exception {
250 PreparedStatement stmt = aConnection.prepareStatement(aSql);
251 setPreparedParams(aArgs, stmt);
252 return stmt.executeUpdate();
258 * Executes an SQL query.
262 * @return Result set.
264 public ResultSet executeQuery(Connection aConnection, String aSql) {
265 return executeQuery(aConnection, aSql, new Object[0]);
269 * Executes a query with a single argument. See
270 * {@link #setPreparedParam(int, PreparedStatement, Object)}for details on
271 * supported argument types.
277 * @return Result set.
279 public ResultSet executeQuery(Connection aConnection, String aSql,
281 return executeQuery(aConnection, aSql, new Object[] { aArg });
285 * Executes a query. See
286 * {@link #setPreparedParam(int, PreparedStatement, Object)}for details on
287 * supported argument types.
292 * Arguments to the query.
293 * @return Result set.
295 public ResultSet executeQuery(Connection aConnection, final String aSql,
296 final Object[] aArgs) {
298 PreparedStatement statement = aConnection.prepareStatement(aSql);
299 setPreparedParams(aArgs, statement);
301 return statement.executeQuery();
302 } catch (SQLException e) {
303 throw new RuntimeException(e);
307 public int executeUpdate(Connection aConnection, final String aSql,
308 final Object... aArgs) {
310 PreparedStatement statement = aConnection.prepareStatement(aSql);
311 setPreparedParams(aArgs, statement);
313 return statement.executeUpdate();
314 } catch (SQLException e) {
315 throw new RuntimeException(e);
320 * Sets the values of a prepared statement. See
321 * {@link #setPreparedParam(int, PreparedStatement, Object)}for details on
322 * supported argument types.
325 * Arguments to the prepared statement.
328 * @throws SQLException
330 private void setPreparedParams(final Object[] aArgs,
331 PreparedStatement aStatement) throws SQLException {
332 for (int i = 1; i <= aArgs.length; i++) {
333 setPreparedParam(i, aStatement, aArgs[i - 1]);
338 * Sets a prepared statement parameter.
341 * Index of the parameter.
343 * Prepared statement.
345 * Value Must be of type Integer, Long, or String.
346 * @throws SQLException
348 private void setPreparedParam(int aIndex, PreparedStatement aStatement,
349 Object aObject) throws SQLException {
350 if (aObject instanceof Integer) {
351 aStatement.setInt(aIndex, ((Integer) aObject).intValue());
352 } else if (aObject instanceof Long) {
353 aStatement.setLong(aIndex, ((Integer) aObject).longValue());
354 } else if (aObject instanceof String) {
355 aStatement.setString(aIndex, (String) aObject);
357 TestCase.fail("Unsupported object type for prepared statement: "
358 + aObject.getClass() + " value: " + aObject
359 + " statement: " + aStatement);
365 * @throws SQLException
367 public int getTableSize(final String aTable) throws Exception {
368 return executeInTransaction(new JdbcUnitOfWork<Integer>() {
369 public Integer execute(Connection aConnection) throws Exception {
370 ResultSet resultSet = executeQuery(aConnection,
371 "select count(*) from " + aTable);
373 return resultSet.getInt(1);
379 public int countResultSet(ResultSet aResultSet) throws SQLException {
382 while (aResultSet.next()) {