| /* |
| |
| Derby - Class org.apache.derbyTesting.functionsTests.tests.memorydb.MemoryDbManager |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to you under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| */ |
| package org.apache.derbyTesting.functionTests.tests.memorydb; |
| |
| import java.sql.Connection; |
| import java.sql.DriverManager; |
| import java.sql.PreparedStatement; |
| import java.sql.SQLException; |
| import java.sql.SQLWarning; |
| import java.sql.Statement; |
| import java.util.ArrayList; |
| |
| import org.apache.derbyTesting.junit.BaseJDBCTestCase; |
| |
| /** |
| * Collection of convenience methods for dealing with in-memory databases. |
| * The class will keep track of databases, connections and statements |
| * created through its methods, and will delete / close these when the |
| * clean up method is invoked. This is very much the same as what |
| * {@code BaseJDBCTestCase} does, with the exception of deleting the |
| * databases. |
| * <p> |
| * Note: It may be possible to integrate this functionality into the existing |
| * JUnit framework, for instance if you want to run the entire test suite with |
| * the in-memory back end. |
| */ |
| public class MemoryDbManager { |
| |
| private static final String ATTR_CREATE = ";create=true"; |
| |
| /** JDBC protocl prefix used for in-memory databases. */ |
| private static final String JDBC_PREFIX = "jdbc:derby:memory:"; |
| /** Shared manager instance. */ |
| private static final MemoryDbManager DBM = new MemoryDbManager(); |
| |
| /** |
| * Returns a shared manager instance. |
| * |
| * @return The shared manager instance. |
| */ |
| public static MemoryDbManager getSharedInstance() { |
| return DBM; |
| } |
| |
| /** List of openend statements, closed at clean up. */ |
| private final ArrayList<Statement> STATEMENTS = new ArrayList<Statement>(); |
| /** List of openend connections, closed at clean up. */ |
| private final ArrayList<Connection> CONNECTIONS = new ArrayList<Connection>(); |
| /** List of created databases, deleted at clean up. */ |
| private final ArrayList<String> DATABASES = new ArrayList<String>(); |
| |
| public MemoryDbManager() { } |
| |
| /** |
| * Creates a new connection to the specified database (url). |
| * <p> |
| * Note that the specified URL will be appended to a fixed JDBC protcol |
| * prefix. |
| * |
| * @param dbNameAndAttributes database name and any JDBC url attributes |
| * @return A connection to the specified database. |
| * @throws SQLException if connecting to the database fails |
| */ |
| public Connection getConnection(String dbNameAndAttributes) |
| throws SQLException { |
| final String url = JDBC_PREFIX + dbNameAndAttributes; |
| try { |
| DriverManager.getDriver(url); |
| } catch (SQLException sqle) { |
| // Rely on logic in the default method for obtaining a |
| // connection to load the driver. |
| new BaseJDBCTestCase("dummy") {}.getConnection(); |
| } |
| Connection con = DriverManager.getConnection(url); |
| if (!CONNECTIONS.contains(con)) { |
| CONNECTIONS.add(con); |
| } |
| return con; |
| } |
| |
| /** |
| * Creates a new statement from the given connection and keeps track of |
| * it and closes it when the clean up is invoked. |
| * |
| * @param con the connection to use for creation |
| * @return A new statement. |
| * @throws SQLException if creating the statement fails |
| * @see #cleanUp() |
| */ |
| public Statement createStatement(Connection con) |
| throws SQLException { |
| Statement stmt = con.createStatement(); |
| STATEMENTS.add(stmt); |
| if (!CONNECTIONS.contains(con)) { |
| CONNECTIONS.add(con); |
| } |
| return stmt; |
| } |
| |
| /** |
| * Creates a new prepared statement from the given connection and keeps |
| * track of it and closes it when the clean up is invoked. |
| * |
| * @param con the connection to use for creation |
| * @param sql the sql text to prepare |
| * @return A new prepared statement. |
| * @throws SQLException if creating the statement fails |
| * @see #cleanUp() |
| */ |
| public PreparedStatement prepareStatement(Connection con, String sql) |
| throws SQLException { |
| PreparedStatement pStmt = con.prepareStatement(sql); |
| STATEMENTS.add(pStmt); |
| if (!CONNECTIONS.contains(con)) { |
| CONNECTIONS.add(con); |
| } |
| return pStmt; |
| } |
| |
| /** |
| * Drops the specified database. |
| * <p> |
| * Note that the specified URL will be appended to a fixed JDBC protcol |
| * prefix. |
| * |
| * @param dbNameAndAttributes the database name and any attributes |
| * required to access the database (<em>excluding</em> the delete |
| * attribute, which is added by this method) |
| * @throws SQLException if deleting the database fails |
| */ |
| public void dropDatabase(String dbNameAndAttributes) |
| throws SQLException { |
| String url = JDBC_PREFIX + dbNameAndAttributes + ";drop=true"; |
| try { |
| DriverManager.getConnection(url); |
| BaseJDBCTestCase.fail("Dropping database should raise exception."); |
| } catch (SQLException sqle) { |
| if (sqle.getSQLState().equals("08006")) { |
| // Database was deleted. |
| } else if (sqle.getSQLState().equals("XJ004")) { |
| // Database didn't exist. Already dropped? |
| } else { |
| BaseJDBCTestCase.assertSQLState("Dropping database failed: (" + |
| sqle.getSQLState() + ") "+ sqle.getMessage(), |
| "08006", sqle); |
| } |
| } |
| } |
| |
| /** |
| * Creates a new database and keeps track of it to delete it when the |
| * clean up is invoked. |
| * <p> |
| * If the database already exists, a connection to the existing |
| * database is returned. |
| * |
| * @param dbName the database name |
| * @return A connection to the database. |
| * @throws SQLException if creating or connecting to the database fails |
| */ |
| public Connection createDatabase(String dbName) |
| throws SQLException { |
| return createDatabase(dbName, null, null, null); |
| } |
| |
| /** |
| * Creates a new database and keeps track of it to delete it when the |
| * clean up is invoked. |
| * <p> |
| * If the database already exists, a connection to the existing |
| * database is returned. |
| * |
| * @param dbName the database name |
| * @param dbAttributes database attributes (i.e. encryption) |
| * @param user user name |
| * @param password user password |
| * @return A connection to the database. |
| * @throws SQLException if creating or connecting to the database fails |
| */ |
| public Connection createDatabase(String dbName, String dbAttributes, |
| String user, String password) |
| throws SQLException { |
| String userAttr = ""; |
| if (user != null) { |
| userAttr = ";user=" + user; |
| } |
| if (password != null) { |
| userAttr += ";password=" + password; |
| } |
| String url = dbName; |
| if (dbAttributes != null) { |
| url += ";" + dbAttributes; |
| } |
| if (!userAttr.equals("")) { |
| url += userAttr; |
| } |
| if (url.indexOf(ATTR_CREATE) == -1) { |
| url += ATTR_CREATE; |
| } |
| Connection con = getConnection(url); |
| if (con.getWarnings() != null) { |
| // See if there are more than one warning. |
| SQLWarning w = con.getWarnings(); |
| String warnings = w.getMessage(); |
| while ((w = w.getNextWarning()) != null) { |
| warnings += " || " + w.getMessage(); |
| } |
| BaseJDBCTestCase.fail( |
| "Warning(s) when creating database: " + warnings); |
| } |
| // Keep track of the database we just created, so that we can |
| // delete it. |
| DATABASES.add(dbName + userAttr); |
| return con; |
| |
| } |
| |
| /** |
| * Cleans up database resources by closing known statements and |
| * connection, and deleting known in-memory databases. |
| * @throws SQLException |
| */ |
| public void cleanUp() |
| throws SQLException { |
| // Close all known statements. |
| for (int i=STATEMENTS.size() -1; i >= 0; i--) { |
| Statement stmt = STATEMENTS.remove(i); |
| stmt.close(); |
| } |
| // Close all known connections. |
| for (int i=CONNECTIONS.size() -1; i >= 0; i--) { |
| Connection con = CONNECTIONS.remove(i); |
| try { |
| con.rollback(); |
| } catch (SQLException sqle) { |
| // Ignore this exception. |
| } |
| con.close(); |
| } |
| // Delete all known databases. |
| for (int i=DATABASES.size() -1; i >= 0; i--) { |
| dropDatabase(DATABASES.remove(i)); |
| } |
| } |
| } |