Author: oheger
Date: Wed Oct 22 23:24:25 2008
New Revision: 707290
URL: http://svn.apache.org/viewvc?rev=707290&view=rev
Log:
Refactoring of DatabaseConfiguration to simplify JDBC-related code.
Removed the deprecated getConnection() method.
Modified:
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DatabaseConfiguration.java
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDatabaseConfiguration.java
Modified:
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DatabaseConfiguration.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DatabaseConfiguration.java?rev=707290&r1=707289&r2=707290&view=diff
==============================================================================
---
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DatabaseConfiguration.java
(original)
+++
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DatabaseConfiguration.java
Wed Oct 22 23:24:25 2008
@@ -28,6 +28,7 @@
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
+
import javax.sql.DataSource;
/**
@@ -81,6 +82,21 @@
*/
public class DatabaseConfiguration extends AbstractConfiguration
{
+ /** Constant for the statement used by getProperty.*/
+ private static final String SQL_GET_PROPERTY = "SELECT * FROM %s WHERE %s
=?";
+
+ /** Constant for the statement used by isEmpty.*/
+ private static final String SQL_IS_EMPTY = "SELECT count(*) FROM %s WHERE
1 = 1";
+
+ /** Constant for the statement used by clearProperty.*/
+ private static final String SQL_CLEAR_PROPERTY = "DELETE FROM %s WHERE %s
=?";
+
+ /** Constant for the statement used by clear.*/
+ private static final String SQL_CLEAR = "DELETE FROM %s WHERE 1 = 1";
+
+ /** Constant for the statement used by getKeys.*/
+ private static final String SQL_GET_KEYS = "SELECT DISTINCT %s FROM %s
WHERE 1 = 1";
+
/** The datasource to connect to the database. */
private DataSource datasource;
@@ -145,66 +161,45 @@
* @param key the key of the desired property
* @return the value of this property
*/
- public Object getProperty(String key)
+ public Object getProperty(final String key)
{
- Object result = null;
-
- // build the query
- StringBuilder query = new StringBuilder("SELECT * FROM ");
- query.append(table).append(" WHERE ");
- query.append(keyColumn).append("=?");
- if (nameColumn != null)
- {
- query.append(" AND " + nameColumn + "=?");
- }
-
- Connection conn = null;
- PreparedStatement pstmt = null;
-
- try
+ JdbcOperation op = new JdbcOperation(EVENT_READ_PROPERTY, key, null)
{
- conn = getConnection();
-
- // bind the parameters
- pstmt = conn.prepareStatement(query.toString());
- pstmt.setString(1, key);
- if (nameColumn != null)
+ @Override
+ protected Object performOperation() throws SQLException
{
- pstmt.setString(2, name);
- }
+ PreparedStatement pstmt = initStatement(String.format(
+ SQL_GET_PROPERTY, table, keyColumn), true, key);
+ ResultSet rs = pstmt.executeQuery();
- ResultSet rs = pstmt.executeQuery();
+ List<Object> results = new ArrayList<Object>();
+ while (rs.next())
+ {
+ Object value = rs.getObject(valueColumn);
+ if (isDelimiterParsingDisabled())
+ {
+ results.add(value);
+ }
+ else
+ {
+ // Split value if it contains the list delimiter
+ results.addAll(PropertyConverter.flatten(value,
+ getListDelimiter()));
+ }
+ }
- List<Object> results = new ArrayList<Object>();
- while (rs.next())
- {
- Object value = rs.getObject(valueColumn);
- if (isDelimiterParsingDisabled())
+ if (!results.isEmpty())
{
- results.add(value);
+ return (results.size() > 1) ? results : results.get(0);
}
else
{
- // Split value if it contains the list delimiter
- results.addAll(PropertyConverter.flatten(value,
getListDelimiter()));
+ return null;
}
}
+ };
- if (!results.isEmpty())
- {
- result = (results.size() > 1) ? results : results.get(0);
- }
- }
- catch (SQLException e)
- {
- fireError(EVENT_READ_PROPERTY, key, null, e);
- }
- finally
- {
- close(conn, pstmt);
- }
-
- return result;
+ return op.execute();
}
/**
@@ -217,47 +212,40 @@
* @param key the property key
* @param obj the value of the property to add
*/
- protected void addPropertyDirect(String key, Object obj)
+ @Override
+ protected void addPropertyDirect(final String key, final Object obj)
{
- // build the query
- StringBuilder query = new StringBuilder("INSERT INTO " + table);
- if (nameColumn != null)
+ new JdbcOperation(EVENT_ADD_PROPERTY, key, obj)
{
- query.append(" (" + nameColumn + ", " + keyColumn + ", " +
valueColumn + ") VALUES (?, ?, ?)");
- }
- else
- {
- query.append(" (" + keyColumn + ", " + valueColumn + ") VALUES (?,
?)");
- }
-
- Connection conn = null;
- PreparedStatement pstmt = null;
+ @Override
+ protected Object performOperation() throws SQLException
+ {
+ StringBuilder query = new StringBuilder("INSERT INTO ");
+ query.append(table).append(" (");
+ query.append(keyColumn).append(", ");
+ query.append(valueColumn);
+ if (nameColumn != null)
+ {
+ query.append(", ").append(nameColumn);
+ }
+ query.append(") VALUES (?, ?");
+ if (nameColumn != null)
+ {
+ query.append(", ?");
+ }
+ query.append(")");
- try
- {
- conn = getConnection();
+ PreparedStatement pstmt = initStatement(query.toString(),
+ false, key, String.valueOf(obj));
+ if (nameColumn != null)
+ {
+ pstmt.setString(3, name);
+ }
- // bind the parameters
- pstmt = conn.prepareStatement(query.toString());
- int index = 1;
- if (nameColumn != null)
- {
- pstmt.setString(index++, name);
+ pstmt.executeUpdate();
+ return null;
}
- pstmt.setString(index++, key);
- pstmt.setString(index++, String.valueOf(obj));
-
- pstmt.executeUpdate();
- }
- catch (SQLException e)
- {
- fireError(EVENT_ADD_PROPERTY, key, obj, e);
- }
- finally
- {
- // clean up
- close(conn, pstmt);
- }
+ }.execute();
}
/**
@@ -272,6 +260,7 @@
* @param key the key of the new property
* @param value the value to be added
*/
+ @Override
public void addProperty(String key, Object value)
{
boolean parsingFlag = isDelimiterParsingDisabled();
@@ -300,242 +289,127 @@
*/
public boolean isEmpty()
{
- boolean empty = true;
-
- // build the query
- StringBuilder query = new StringBuilder("SELECT count(*) FROM " +
table);
- if (nameColumn != null)
- {
- query.append(" WHERE " + nameColumn + "=?");
- }
-
- Connection conn = null;
- PreparedStatement pstmt = null;
-
- try
+ JdbcOperation op = new JdbcOperation(EVENT_READ_PROPERTY, null, null)
{
- conn = getConnection();
-
- // bind the parameters
- pstmt = conn.prepareStatement(query.toString());
- if (nameColumn != null)
+ @Override
+ protected Object performOperation() throws SQLException
{
- pstmt.setString(1, name);
- }
-
- ResultSet rs = pstmt.executeQuery();
+ PreparedStatement ps = initStatement(String.format(
+ SQL_IS_EMPTY, table), true);
+ ResultSet rs = ps.executeQuery();
- if (rs.next())
- {
- empty = rs.getInt(1) == 0;
+ return rs.next() ? rs.getInt(1) : null;
}
- }
- catch (SQLException e)
- {
- fireError(EVENT_READ_PROPERTY, null, null, e);
- }
- finally
- {
- // clean up
- close(conn, pstmt);
- }
+ };
- return empty;
+ Integer count = (Integer) op.execute();
+ return count == null || count.intValue() == 0;
}
/**
* Checks whether this configuration contains the specified key. If this
* causes a database error, an error event will be generated of type
- * <code>EVENT_READ_PROPERTY</code> with the causing exception. The
- * event's <code>propertyName</code> will be set to the passed in key, the
+ * <code>EVENT_READ_PROPERTY</code> with the causing exception. The event's
+ * <code>propertyName</code> will be set to the passed in key, the
* <code>propertyValue</code> will be undefined.
*
* @param key the key to be checked
* @return a flag whether this key is defined
*/
- public boolean containsKey(String key)
+ public boolean containsKey(final String key)
{
- boolean found = false;
-
- // build the query
- StringBuilder query = new StringBuilder("SELECT * FROM " + table + "
WHERE " + keyColumn + "=?");
- if (nameColumn != null)
- {
- query.append(" AND " + nameColumn + "=?");
- }
-
- Connection conn = null;
- PreparedStatement pstmt = null;
-
- try
+ JdbcOperation op = new JdbcOperation(EVENT_READ_PROPERTY, key, null)
{
- conn = getConnection();
-
- // bind the parameters
- pstmt = conn.prepareStatement(query.toString());
- pstmt.setString(1, key);
- if (nameColumn != null)
+ @Override
+ protected Object performOperation() throws SQLException
{
- pstmt.setString(2, name);
- }
-
- ResultSet rs = pstmt.executeQuery();
+ PreparedStatement pstmt = initStatement(String.format(
+ SQL_GET_PROPERTY, table, keyColumn), true, key);
+ ResultSet rs = pstmt.executeQuery();
- found = rs.next();
- }
- catch (SQLException e)
- {
- fireError(EVENT_READ_PROPERTY, key, null, e);
- }
- finally
- {
- // clean up
- close(conn, pstmt);
- }
+ return rs.next();
+ }
+ };
- return found;
+ Boolean result = (Boolean) op.execute();
+ return result != null && result.booleanValue();
}
/**
* Removes the specified value from this configuration. If this causes a
* database error, an error event will be generated of type
- * <code>EVENT_CLEAR_PROPERTY</code> with the causing exception. The
- * event's <code>propertyName</code> will be set to the passed in key, the
+ * <code>EVENT_CLEAR_PROPERTY</code> with the causing exception. The
event's
+ * <code>propertyName</code> will be set to the passed in key, the
* <code>propertyValue</code> will be undefined.
*
* @param key the key of the property to be removed
*/
- public void clearProperty(String key)
+ @Override
+ public void clearProperty(final String key)
{
- // build the query
- StringBuilder query = new StringBuilder("DELETE FROM " + table + "
WHERE " + keyColumn + "=?");
- if (nameColumn != null)
+ new JdbcOperation(EVENT_CLEAR_PROPERTY, key, null)
{
- query.append(" AND " + nameColumn + "=?");
- }
-
- Connection conn = null;
- PreparedStatement pstmt = null;
-
- try
- {
- conn = getConnection();
-
- // bind the parameters
- pstmt = conn.prepareStatement(query.toString());
- pstmt.setString(1, key);
- if (nameColumn != null)
+ @Override
+ protected Object performOperation() throws SQLException
{
- pstmt.setString(2, name);
+ PreparedStatement ps = initStatement(String.format(
+ SQL_CLEAR_PROPERTY, table, keyColumn), true, key);
+ return ps.executeUpdate();
}
-
- pstmt.executeUpdate();
- }
- catch (SQLException e)
- {
- fireError(EVENT_CLEAR_PROPERTY, key, null, e);
- }
- finally
- {
- // clean up
- close(conn, pstmt);
- }
+ }.execute();
}
/**
* Removes all entries from this configuration. If this causes a database
- * error, an error event will be generated of type
- * <code>EVENT_CLEAR</code> with the causing exception. Both the
- * event's <code>propertyName</code> and the <code>propertyValue</code>
- * will be undefined.
+ * error, an error event will be generated of type <code>EVENT_CLEAR</code>
+ * with the causing exception. Both the event's <code>propertyName</code>
+ * and the <code>propertyValue</code> will be undefined.
*/
+ @Override
public void clear()
{
- // build the query
- StringBuilder query = new StringBuilder("DELETE FROM " + table);
- if (nameColumn != null)
- {
- query.append(" WHERE " + nameColumn + "=?");
- }
-
- Connection conn = null;
- PreparedStatement pstmt = null;
-
- try
+ new JdbcOperation(EVENT_CLEAR, null, null)
{
- conn = getConnection();
-
- // bind the parameters
- pstmt = conn.prepareStatement(query.toString());
- if (nameColumn != null)
+ @Override
+ protected Object performOperation() throws SQLException
{
- pstmt.setString(1, name);
+ PreparedStatement ps = initStatement(String.format(SQL_CLEAR,
+ table), true);
+ return ps.executeUpdate();
}
-
- pstmt.executeUpdate();
- }
- catch (SQLException e)
- {
- fireError(EVENT_CLEAR, null, null, e);
- }
- finally
- {
- // clean up
- close(conn, pstmt);
- }
+ }.execute();
}
/**
* Returns an iterator with the names of all properties contained in this
- * configuration. If this causes a database
- * error, an error event will be generated of type
- * <code>EVENT_READ_PROPERTY</code> with the causing exception. Both the
- * event's <code>propertyName</code> and the <code>propertyValue</code>
- * will be undefined.
- * @return an iterator with the contained keys (an empty iterator in case
- * of an error)
+ * configuration. If this causes a database error, an error event will be
+ * generated of type <code>EVENT_READ_PROPERTY</code> with the causing
+ * exception. Both the event's <code>propertyName</code> and the
+ * <code>propertyValue</code> will be undefined.
+ *
+ * @return an iterator with the contained keys (an empty iterator in case
of
+ * an error)
*/
public Iterator<String> getKeys()
{
- Collection<String> keys = new ArrayList<String>();
+ final Collection<String> keys = new ArrayList<String>();
- // build the query
- StringBuilder query = new StringBuilder("SELECT DISTINCT " + keyColumn
+ " FROM " + table);
- if (nameColumn != null)
+ new JdbcOperation(EVENT_READ_PROPERTY, null, null)
{
- query.append(" WHERE " + nameColumn + "=?");
- }
-
- Connection conn = null;
- PreparedStatement pstmt = null;
-
- try
- {
- conn = getConnection();
-
- // bind the parameters
- pstmt = conn.prepareStatement(query.toString());
- if (nameColumn != null)
+ @Override
+ protected Object performOperation() throws SQLException
{
- pstmt.setString(1, name);
- }
-
- ResultSet rs = pstmt.executeQuery();
+ PreparedStatement ps = initStatement(String.format(
+ SQL_GET_KEYS, keyColumn, table), true);
+ ResultSet rs = ps.executeQuery();
- while (rs.next())
- {
- keys.add(rs.getString(1));
+ while (rs.next())
+ {
+ keys.add(rs.getString(1));
+ }
+ return null;
}
- }
- catch (SQLException e)
- {
- fireError(EVENT_READ_PROPERTY, null, null, e);
- }
- finally
- {
- // clean up
- close(conn, pstmt);
- }
+ }.execute();
return keys.iterator();
}
@@ -552,22 +426,6 @@
}
/**
- * Returns a <code>Connection</code> object. This method is called when
- * ever the database is to be accessed. This implementation returns a
- * connection from the current <code>DataSource</code>.
- *
- * @return the <code>Connection</code> object to be used
- * @throws SQLException if an error occurs
- * @since 1.4
- * @deprecated Use a custom data source to change the connection used by
the
- * class. To be removed in Commons Configuration 2.0
- */
- protected Connection getConnection() throws SQLException
- {
- return getDatasource().getConnection();
- }
-
- /**
* Close a <code>Connection</code> and, <code>Statement</code>.
* Avoid closing if null and hide any SQLExceptions that occur.
*
@@ -600,4 +458,156 @@
getLogger().log(Level.SEVERE, "An error occured on closing the
connection", e);
}
}
+
+ /**
+ * An internally used helper class for simplifying database access through
+ * plain JDBC. This class provides a simple framework for creating and
+ * executing a JDBC statement. It especially takes care of proper handling
+ * of JDBC resources even in case of an error.
+ */
+ private abstract class JdbcOperation
+ {
+ /** Stores the connection. */
+ private Connection conn;
+
+ /** Stores the statement. */
+ private PreparedStatement pstmt;
+
+ /** The type of the event to send in case of an error. */
+ private final int errorEventType;
+
+ /** The property name for an error event. */
+ private final String errorPropertyName;
+
+ /** The property value for an error event. */
+ private final Object errorPropertyValue;
+
+ /**
+ * Creates a new instance of <code>JdbcOperation</code> and initializes
+ * the properties related to the error event.
+ *
+ * @param errEvType the type of the error event
+ * @param errPropName the property name for the error event
+ * @param errPropVal the property value for the error event
+ */
+ protected JdbcOperation(int errEvType, String errPropName,
+ Object errPropVal)
+ {
+ errorEventType = errEvType;
+ errorPropertyName = errPropName;
+ errorPropertyValue = errPropVal;
+ }
+
+ /**
+ * Executes this operation. This method obtains a database connection
+ * and then delegates to <code>performOperation()</code>. Afterwards it
+ * performs the necessary clean up. Exceptions that are thrown during
+ * the JDBC operation are caught and transformed into configuration
+ * error events.
+ *
+ * @return the result of the operation
+ */
+ public Object execute()
+ {
+ Object result = null;
+
+ try
+ {
+ conn = getDatasource().getConnection();
+ result = performOperation();
+ }
+ catch (SQLException e)
+ {
+ fireError(errorEventType, errorPropertyName,
+ errorPropertyValue, e);
+ }
+ finally
+ {
+ close(conn, pstmt);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the current connection. This method can be called while
+ * <code>execute()</code> is running. It returns <b>null</b> otherwise.
+ *
+ * @return the current connection
+ */
+ protected Connection getConnection()
+ {
+ return conn;
+ }
+
+ /**
+ * Creates a <code>PreparedStatement</code> object for executing the
+ * specified SQL statement.
+ *
+ * @param sql the statement to be executed
+ * @param nameCol a flag whether the name column should be taken into
+ * account
+ * @return the prepared statement object
+ * @throws SQLException if an SQL error occurs
+ */
+ protected PreparedStatement createStatement(String sql, boolean
nameCol)
+ throws SQLException
+ {
+ String statement;
+ if (nameCol && nameColumn != null)
+ {
+ StringBuilder buf = new StringBuilder(sql);
+ buf.append(" AND ").append(nameColumn).append("=?");
+ statement = buf.toString();
+ }
+ else
+ {
+ statement = sql;
+ }
+
+ pstmt = getConnection().prepareStatement(statement);
+ return pstmt;
+ }
+
+ /**
+ * Creates an initializes a <code>PreparedStatement</code> object for
+ * executing an SQL statement. This method first calls
+ * <code>createStatement()</code> for creating the statement and then
+ * initializes the statement's parameters.
+ *
+ * @param sql the statement to be executed
+ * @param nameCol a flag whether the name column should be taken into
+ * account
+ * @param params the parameters for the statement
+ * @return the initialized statement object
+ * @throws SQLException if an SQL error occurs
+ */
+ protected PreparedStatement initStatement(String sql, boolean nameCol,
+ Object... params) throws SQLException
+ {
+ PreparedStatement ps = createStatement(sql, nameCol);
+
+ int idx = 1;
+ for (Object param : params)
+ {
+ ps.setObject(idx++, param);
+ }
+ if (nameCol && nameColumn != null)
+ {
+ ps.setString(idx, name);
+ }
+
+ return ps;
+ }
+
+ /**
+ * Performs the JDBC operation. This method is called by
+ * <code>execute()</code> after this object has been fully initialized.
+ * Here the actual JDBC logic has to be placed.
+ *
+ * @return the result of the operation
+ * @throws SQLException if an SQL error occurs
+ */
+ protected abstract Object performOperation() throws SQLException;
+ }
}
Modified:
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDatabaseConfiguration.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDatabaseConfiguration.java?rev=707290&r1=707289&r2=707290&view=diff
==============================================================================
---
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDatabaseConfiguration.java
(original)
+++
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDatabaseConfiguration.java
Wed Oct 22 23:24:25 2008
@@ -24,16 +24,17 @@
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
+
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
import javax.sql.DataSource;
+import junit.framework.TestCase;
+
import org.apache.commons.configuration2.event.ConfigurationErrorListener;
import org.apache.commons.configuration2.test.HsqlDB;
import org.apache.commons.dbcp.BasicDataSource;
-
-import junit.framework.TestCase;
import org.codehaus.spice.jndikit.DefaultNameParser;
import org.codehaus.spice.jndikit.DefaultNamespace;
import org.codehaus.spice.jndikit.memory.MemoryContext;
@@ -53,7 +54,7 @@
public class TestDatabaseConfiguration extends TestCase
{
public final String DATABASE_DRIVER = "org.hsqldb.jdbcDriver";
- public final String DATABASE_URL =
"jdbc:hsqldb:target/test-classes/testdb";
+ public final String DATABASE_URL = "jdbc:hsqldb:mem:testdb";
public final String DATABASE_USERNAME = "sa";
public final String DATABASE_PASSWORD = "";
@@ -77,11 +78,12 @@
private static HsqlDB hsqlDB = null;
- private DataSource datasource;
+ private PotentialErrorDataSource datasource;
/** An error listener for testing whether internal errors occurred.*/
private ConfigurationErrorListenerImpl listener;
+ @Override
protected void setUp() throws Exception
{
/*
@@ -98,7 +100,7 @@
hsqlDB = new HsqlDB(DATABASE_URL, DATABASE_DRIVER,
script.getAbsolutePath());
}
- BasicDataSource datasource = new BasicDataSource();
+ PotentialErrorDataSource datasource = new PotentialErrorDataSource();
datasource.setDriverClassName(DATABASE_DRIVER);
datasource.setUrl(DATABASE_URL);
datasource.setUsername(DATABASE_USERNAME);
@@ -120,6 +122,7 @@
}
}
+ @Override
protected void tearDown() throws Exception{
datasource.getConnection().commit();
datasource.getConnection().close();
@@ -137,9 +140,9 @@
*
* @return the configuration
*/
- private PotentialErrorDatabaseConfiguration setUpConfig()
+ private DatabaseConfiguration setUpConfig()
{
- return new PotentialErrorDatabaseConfiguration(datasource, TABLE,
COL_KEY, COL_VALUE);
+ return new DatabaseConfiguration(datasource, TABLE, COL_KEY,
COL_VALUE);
}
/**
@@ -158,13 +161,13 @@
*
* @param config the configuration
*/
- private void setUpErrorListener(PotentialErrorDatabaseConfiguration config)
+ private void setUpErrorListener(DatabaseConfiguration config)
{
// remove log listener to avoid exception longs
config.removeErrorListener((ConfigurationErrorListener)
config.getErrorListeners().iterator().next());
listener = new ConfigurationErrorListenerImpl();
config.addErrorListener(listener);
- config.failOnConnect = true;
+ datasource.failOnConnect = true;
}
/**
@@ -173,9 +176,9 @@
*
* @return the initialized configuration
*/
- private PotentialErrorDatabaseConfiguration setUpErrorConfig()
+ private DatabaseConfiguration setUpErrorConfig()
{
- PotentialErrorDatabaseConfiguration config = setUpConfig();
+ DatabaseConfiguration config = setUpConfig();
setUpErrorListener(config);
return config;
}
@@ -491,10 +494,10 @@
{
public static DataSource datasource;
- public Context getInitialContext(Hashtable environment) throws
NamingException
+ public Context getInitialContext(Hashtable<?, ?> environment) throws
NamingException
{
DefaultNamespace namespace = new DefaultNamespace(new
DefaultNameParser());
- MemoryContext context = new MemoryContext(namespace, new
Hashtable(), null);
+ MemoryContext context = new MemoryContext(namespace, new
Hashtable<Object, Object>(), null);
context.createSubcontext("java:comp").createSubcontext("env").createSubcontext("jdbc").bind("configuration",
datasource);
return context;
@@ -502,25 +505,21 @@
}
/**
- * A specialized database configuration implementation that can be
- * configured to throw an exception when obtaining a connection. This way
- * database exceptions can be simulated.
+ * A specialized DataSource implementation that can be configured to throw
+ * an exception when obtaining a connection. This way database exceptions
+ * can be simulated.
*/
- static class PotentialErrorDatabaseConfiguration extends
DatabaseConfiguration
+ private static class PotentialErrorDataSource extends BasicDataSource
{
/** A flag whether a getConnection() call should fail. */
boolean failOnConnect;
- public PotentialErrorDatabaseConfiguration(DataSource datasource,
- String table, String keyColumn, String valueColumn)
- {
- super(datasource, table, keyColumn, valueColumn);
- }
-
- protected Connection getConnection() throws SQLException
+ @Override
+ public Connection getConnection() throws SQLException
{
if (failOnConnect)
{
+ failOnConnect = false; // fail only once
throw new SQLException("Simulated DB error");
}
return super.getConnection();