Author: oheger
Date: Tue Apr 6 20:29:51 2010
New Revision: 931307
URL: http://svn.apache.org/viewvc?rev=931307&view=rev
Log:
CONFIGURATION-412: DatabaseConfiguration can now be instructed to perform
commits after database updates.
Modified:
commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DatabaseConfiguration.java
commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/DatabaseConfigurationTestHelper.java
commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDatabaseConfiguration.java
commons/proper/configuration/trunk/xdocs/changes.xml
Modified:
commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DatabaseConfiguration.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DatabaseConfiguration.java?rev=931307&r1=931306&r2=931307&view=diff
==============================================================================
---
commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DatabaseConfiguration.java
(original)
+++
commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DatabaseConfiguration.java
Tue Apr 6 20:29:51 2010
@@ -74,6 +74,12 @@ import org.apache.commons.logging.LogFac
* Configuration config2 = new DatabaseConfiguration(datasource, "myconfigs",
"name", "key", "value", "config2");
* String value2 = conf.getString("key2");
* </pre>
+ * The configuration can be instructed to perform commits after database
updates.
+ * This is achieved by setting the <code>commits</code> parameter of the
+ * constructors to <b>true</b>. If commits should not be performed (which is
the
+ * default behavior), it should be ensured that the connections returned by the
+ * <code>DataSource</code> are in auto-commit mode.
+ *
* <h1>Note: Like JDBC itself, protection against SQL injection is left to the
user.</h1>
* @since 1.0
*
@@ -100,8 +106,12 @@ public class DatabaseConfiguration exten
/** The name of the configuration. */
private String name;
+ /** A flag whether commits should be performed by this configuration. */
+ private final boolean doCommits;
+
/**
* Build a configuration from a table containing multiple configurations.
+ * No commits are performed by the new configuration instance.
*
* @param datasource the datasource to connect to the database
* @param table the name of the table containing the configurations
@@ -113,18 +123,39 @@ public class DatabaseConfiguration exten
public DatabaseConfiguration(DataSource datasource, String table, String
nameColumn,
String keyColumn, String valueColumn, String name)
{
+ this(datasource, table, nameColumn, keyColumn, valueColumn, name,
false);
+ }
+
+ /**
+ * Creates a new instance of <code>DatabaseConfiguration</code> that
operates on
+ * a database table containing multiple configurations.
+ *
+ * @param datasource the <code>DataSource</code> to connect to the database
+ * @param table the name of the table containing the configurations
+ * @param nameColumn the column containing the name of the configuration
+ * @param keyColumn the column containing the keys of the configuration
+ * @param valueColumn the column containing the values of the configuration
+ * @param name the name of the configuration
+ * @param commits a flag whether the configuration should perform a commit
+ * after a database update
+ */
+ public DatabaseConfiguration(DataSource datasource, String table,
+ String nameColumn, String keyColumn, String valueColumn,
+ String name, boolean commits)
+ {
this.datasource = datasource;
this.table = table;
this.nameColumn = nameColumn;
this.keyColumn = keyColumn;
this.valueColumn = valueColumn;
this.name = name;
+ doCommits = commits;
setLogger(LogFactory.getLog(getClass()));
addErrorLogListener(); // log errors per default
}
/**
- * Build a configuration from a table.-
+ * Build a configuration from a table.
*
* @param datasource the datasource to connect to the database
* @param table the name of the table containing the configurations
@@ -137,6 +168,35 @@ public class DatabaseConfiguration exten
}
/**
+ * Creates a new instance of <code>DatabaseConfiguration</code> that
+ * operates on a database table containing a single configuration only.
+ *
+ * @param datasource the <code>DataSource</code> to connect to the database
+ * @param table the name of the table containing the configurations
+ * @param keyColumn the column containing the keys of the configuration
+ * @param valueColumn the column containing the values of the configuration
+ * @param name the name of the configuration
+ * @param commits a flag whether the configuration should perform a commit
+ * after a database update
+ */
+ public DatabaseConfiguration(DataSource datasource, String table,
+ String keyColumn, String valueColumn, boolean commits)
+ {
+ this(datasource, table, null, keyColumn, valueColumn, null, commits);
+ }
+
+ /**
+ * Returns a flag whether this configuration performs commits after
database
+ * updates.
+ *
+ * @return a flag whether commits are performed
+ */
+ public boolean isDoCommits()
+ {
+ return doCommits;
+ }
+
+ /**
* Returns the value of the specified property. If this causes a database
* error, an error event will be generated of type
* <code>EVENT_READ_PROPERTY</code> with the causing exception. The
@@ -249,6 +309,7 @@ public class DatabaseConfiguration exten
pstmt.setString(index++, String.valueOf(obj));
pstmt.executeUpdate();
+ commitIfRequired(conn);
}
catch (SQLException e)
{
@@ -431,6 +492,7 @@ public class DatabaseConfiguration exten
}
pstmt.executeUpdate();
+ commitIfRequired(conn);
}
catch (SQLException e)
{
@@ -475,6 +537,7 @@ public class DatabaseConfiguration exten
}
pstmt.executeUpdate();
+ commitIfRequired(conn);
}
catch (SQLException e)
{
@@ -603,4 +666,20 @@ public class DatabaseConfiguration exten
getLogger().error("An error occured on closing the connection", e);
}
}
+
+ /**
+ * Performs a commit if needed. This method is called after updates of the
+ * managed database table. If the configuration should perform commits, it
+ * does so now.
+ *
+ * @param conn the active connection
+ * @throws SQLException if an error occurs
+ */
+ private void commitIfRequired(Connection conn) throws SQLException
+ {
+ if (isDoCommits())
+ {
+ conn.commit();
+ }
+ }
}
Modified:
commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/DatabaseConfigurationTestHelper.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/DatabaseConfigurationTestHelper.java?rev=931307&r1=931306&r2=931307&view=diff
==============================================================================
---
commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/DatabaseConfigurationTestHelper.java
(original)
+++
commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/DatabaseConfigurationTestHelper.java
Tue Apr 6 20:29:51 2010
@@ -17,6 +17,7 @@
package org.apache.commons.configuration;
import java.io.FileInputStream;
+import java.sql.Connection;
import javax.sql.DataSource;
@@ -69,48 +70,49 @@ public class DatabaseConfigurationTestHe
public static final String CONFIG_NAME = "test";
/** Stores the in-process database. */
- private static HsqlDB hsqlDB = null;
+ private HsqlDB hsqlDB;
/** The data source. */
private DataSource datasource;
/**
+ * The auto-commit mode for the connections created by the managed data
+ * source.
+ */
+ private boolean autoCommit = true;
+
+ /**
+ * Returns the auto-commit mode of the connections created by the managed
+ * data source.
+ *
+ * @return the auto-commit mode
+ */
+ public boolean isAutoCommit()
+ {
+ return autoCommit;
+ }
+
+ /**
+ * Sets the auto-commit mode of the connections created by the managed data
+ * source.
+ *
+ * @param autoCommit the auto-commit mode
+ */
+ public void setAutoCommit(boolean autoCommit)
+ {
+ this.autoCommit = autoCommit;
+ }
+
+ /**
* Initializes this helper object. This method can be called from a
* <code>setUp()</code> method of a unit test class. It creates the
database
- * instance if necessary and populates it with test data.
+ * instance if necessary.
*
* @throws Exception if an error occurs
*/
public void setUp() throws Exception
{
- if (hsqlDB == null)
- {
- hsqlDB = new HsqlDB(DATABASE_URL, DATABASE_DRIVER,
- "conf/testdb.script");
- }
-
- BasicDataSource datasource = new BasicDataSource();
- datasource.setDriverClassName(DATABASE_DRIVER);
- datasource.setUrl(DATABASE_URL);
- datasource.setUsername(DATABASE_USERNAME);
- datasource.setPassword(DATABASE_PASSWORD);
-
- this.datasource = datasource;
-
- // prepare the database
- IDatabaseConnection connection = new DatabaseConnection(datasource
- .getConnection());
- IDataSet dataSet = new XmlDataSet(new FileInputStream(
- "conf/dataset.xml"));
-
- try
- {
- DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
- }
- finally
- {
- connection.close();
- }
+ hsqlDB = new HsqlDB(DATABASE_URL, DATABASE_DRIVER,
"conf/testdb.script");
}
/**
@@ -121,8 +123,11 @@ public class DatabaseConfigurationTestHe
*/
public void tearDown() throws Exception
{
- datasource.getConnection().commit();
- datasource.getConnection().close();
+ if (datasource != null)
+ {
+ datasource.getConnection().close();
+ }
+ hsqlDB.close();
}
/**
@@ -132,7 +137,8 @@ public class DatabaseConfigurationTestHe
*/
public DatabaseConfiguration setUpConfig()
{
- return new DatabaseConfiguration(datasource, TABLE, COL_KEY,
COL_VALUE);
+ return new DatabaseConfiguration(getDatasource(), TABLE, COL_KEY,
+ COL_VALUE, !isAutoCommit());
}
/**
@@ -143,17 +149,80 @@ public class DatabaseConfigurationTestHe
*/
public DatabaseConfiguration setUpMultiConfig()
{
- return new DatabaseConfiguration(datasource, TABLE_MULTI, COL_NAME,
- COL_KEY, COL_VALUE, CONFIG_NAME);
+ return setUpMultiConfig(CONFIG_NAME);
+ }
+
+ /**
+ * Creates a database configuration that supports multiple configurations
in
+ * a table and sets the specified configuration name.
+ *
+ * @param configName the name of the configuration
+ * @return the configuration
+ */
+ public DatabaseConfiguration setUpMultiConfig(String configName)
+ {
+ return new DatabaseConfiguration(getDatasource(), TABLE_MULTI,
+ COL_NAME, COL_KEY, COL_VALUE, configName, !isAutoCommit());
}
/**
- * Returns the <code>DataSource</code> managed by this class.
+ * Returns the <code>DataSource</code> managed by this class. The data
+ * source is created on first access.
*
* @return the <code>DataSource</code>
*/
public DataSource getDatasource()
{
+ if (datasource == null)
+ {
+ try
+ {
+ datasource = setUpDataSource();
+ }
+ catch (Exception ex)
+ {
+ throw new ConfigurationRuntimeException(
+ "Could not create data source", ex);
+ }
+ }
return datasource;
}
+
+ /**
+ * Creates the internal data source. This method also initializes the
+ * database.
+ *
+ * @return the data source
+ * @throws Exception if an error occurs
+ */
+ private DataSource setUpDataSource() throws Exception
+ {
+ BasicDataSource ds = new BasicDataSource();
+ ds.setDriverClassName(DATABASE_DRIVER);
+ ds.setUrl(DATABASE_URL);
+ ds.setUsername(DATABASE_USERNAME);
+ ds.setPassword(DATABASE_PASSWORD);
+ ds.setDefaultAutoCommit(isAutoCommit());
+
+ // prepare the database
+ Connection conn = ds.getConnection();
+ IDatabaseConnection connection = new DatabaseConnection(conn);
+ IDataSet dataSet = new XmlDataSet(new FileInputStream(
+ "conf/dataset.xml"));
+
+ try
+ {
+ DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
+ }
+ finally
+ {
+ if (!isAutoCommit())
+ {
+ conn.commit();
+ }
+ connection.close();
+ }
+
+ return ds;
+ }
}
Modified:
commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDatabaseConfiguration.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDatabaseConfiguration.java?rev=931307&r1=931306&r2=931307&view=diff
==============================================================================
---
commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDatabaseConfiguration.java
(original)
+++
commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDatabaseConfiguration.java
Tue Apr 6 20:29:51 2010
@@ -37,6 +37,9 @@ import org.apache.commons.configuration.
*/
public class TestDatabaseConfiguration extends TestCase
{
+ /** Constant for another configuration name. */
+ private static final String CONFIG_NAME2 = "anotherTestConfig";
+
/** An error listener for testing whether internal errors occurred.*/
private ConfigurationErrorListenerImpl listener;
@@ -83,17 +86,6 @@ public class TestDatabaseConfiguration e
}
/**
- * Creates a database configuration that supports multiple configurations
in
- * a table with default values.
- *
- * @return the configuration
- */
- private DatabaseConfiguration setUpMultiConfig()
- {
- return helper.setUpMultiConfig();
- }
-
- /**
* Creates an error listener and adds it to the specified configuration.
*
* @param config the configuration
@@ -139,17 +131,55 @@ public class TestDatabaseConfiguration e
listener = null; // mark as checked
}
+ /**
+ * Tests the default value of the doCommits property.
+ */
+ public void testDoCommitsDefault()
+ {
+ DatabaseConfiguration config = new DatabaseConfiguration(helper
+ .getDatasource(), DatabaseConfigurationTestHelper.TABLE,
+ DatabaseConfigurationTestHelper.COL_KEY,
+ DatabaseConfigurationTestHelper.COL_VALUE);
+ assertFalse("Wrong commits flag", config.isDoCommits());
+ }
+
+ /**
+ * Tests the default value of the doCommits property for multiple
+ * configurations in a table.
+ */
+ public void testDoCommitsDefaultMulti()
+ {
+ DatabaseConfiguration config = new DatabaseConfiguration(helper
+ .getDatasource(), DatabaseConfigurationTestHelper.TABLE,
+ DatabaseConfigurationTestHelper.COL_NAME,
+ DatabaseConfigurationTestHelper.COL_KEY,
+ DatabaseConfigurationTestHelper.COL_VALUE,
+ DatabaseConfigurationTestHelper.CONFIG_NAME);
+ assertFalse("Wrong commits flag", config.isDoCommits());
+ }
+
public void testAddPropertyDirectSingle()
{
- DatabaseConfiguration config = setUpConfig();
+ DatabaseConfiguration config = helper.setUpConfig();
config.addPropertyDirect("key", "value");
assertTrue("missing property", config.containsKey("key"));
}
+ /**
+ * Tests whether a commit is performed after a property was added.
+ */
+ public void testAddPropertyDirectCommit()
+ {
+ helper.setAutoCommit(false);
+ DatabaseConfiguration config = helper.setUpConfig();
+ config.addPropertyDirect("key", "value");
+ assertTrue("missing property", config.containsKey("key"));
+ }
+
public void testAddPropertyDirectMultiple()
{
- DatabaseConfiguration config = setUpMultiConfig();
+ DatabaseConfiguration config = helper.setUpMultiConfig();
config.addPropertyDirect("key", "value");
assertTrue("missing property", config.containsKey("key"));
@@ -157,7 +187,7 @@ public class TestDatabaseConfiguration e
public void testAddNonStringProperty()
{
- DatabaseConfiguration config = setUpConfig();
+ DatabaseConfiguration config = helper.setUpConfig();
config.addPropertyDirect("boolean", Boolean.TRUE);
assertTrue("missing property", config.containsKey("boolean"));
@@ -174,7 +204,7 @@ public class TestDatabaseConfiguration e
public void testGetPropertyDirectMultiple()
{
- Configuration config = setUpMultiConfig();
+ Configuration config = helper.setUpMultiConfig();
assertEquals("property1", "value1", config.getProperty("key1"));
assertEquals("property2", "value2", config.getProperty("key2"));
@@ -183,23 +213,49 @@ public class TestDatabaseConfiguration e
public void testClearPropertySingle()
{
- Configuration config = setUpConfig();
- config.clearProperty("key");
+ Configuration config = helper.setUpConfig();
+ config.clearProperty("key1");
- assertFalse("property not cleared", config.containsKey("key"));
+ assertFalse("property not cleared", config.containsKey("key1"));
}
public void testClearPropertyMultiple()
{
- Configuration config = setUpMultiConfig();
- config.clearProperty("key");
+ Configuration config = helper.setUpMultiConfig();
+ config.clearProperty("key1");
+
+ assertFalse("property not cleared", config.containsKey("key1"));
+ }
+
+ /**
+ * Tests that another configuration is not affected when clearing
+ * properties.
+ */
+ public void testClearPropertyMultipleOtherConfig()
+ {
+ DatabaseConfiguration config = helper.setUpMultiConfig();
+ DatabaseConfiguration config2 = helper.setUpMultiConfig(CONFIG_NAME2);
+ config2.addProperty("key1", "some test");
+ config.clearProperty("key1");
+ assertFalse("property not cleared", config.containsKey("key1"));
+ assertTrue("Property cleared in other config", config2
+ .containsKey("key1"));
+ }
- assertFalse("property not cleared", config.containsKey("key"));
+ /**
+ * Tests whether a commit is performed after a property was cleared.
+ */
+ public void testClearPropertyCommit()
+ {
+ helper.setAutoCommit(false);
+ Configuration config = helper.setUpConfig();
+ config.clearProperty("key1");
+ assertFalse("property not cleared", config.containsKey("key1"));
}
public void testClearSingle()
{
- Configuration config = setUpConfig();
+ Configuration config = helper.setUpConfig();
config.clear();
assertTrue("configuration is not cleared", config.isEmpty());
@@ -207,12 +263,23 @@ public class TestDatabaseConfiguration e
public void testClearMultiple()
{
- Configuration config = setUpMultiConfig();
+ Configuration config = helper.setUpMultiConfig();
config.clear();
assertTrue("configuration is not cleared", config.isEmpty());
}
+ /**
+ * Tests whether a commit is performed after a clear operation.
+ */
+ public void testClearCommit()
+ {
+ helper.setAutoCommit(false);
+ Configuration config = helper.setUpConfig();
+ config.clear();
+ assertTrue("configuration is not cleared", config.isEmpty());
+ }
+
public void testGetKeysSingle()
{
Configuration config = setUpConfig();
@@ -224,7 +291,7 @@ public class TestDatabaseConfiguration e
public void testGetKeysMultiple()
{
- Configuration config = setUpMultiConfig();
+ Configuration config = helper.setUpMultiConfig();
Iterator it = config.getKeys();
assertEquals("1st key", "key1", it.next());
@@ -240,7 +307,7 @@ public class TestDatabaseConfiguration e
public void testContainsKeyMultiple()
{
- Configuration config = setUpMultiConfig();
+ Configuration config = helper.setUpMultiConfig();
assertTrue("missing key1", config.containsKey("key1"));
assertTrue("missing key2", config.containsKey("key2"));
}
@@ -253,7 +320,7 @@ public class TestDatabaseConfiguration e
public void testIsEmptyMultiple()
{
- Configuration config1 = setUpMultiConfig();
+ Configuration config1 = helper.setUpMultiConfig();
assertFalse("The configuration named 'test' is empty",
config1.isEmpty());
Configuration config2 = new
DatabaseConfiguration(helper.getDatasource(),
DatabaseConfigurationTestHelper.TABLE_MULTI,
DatabaseConfigurationTestHelper.COL_NAME,
DatabaseConfigurationTestHelper.COL_KEY,
DatabaseConfigurationTestHelper.COL_VALUE, "testIsEmpty");
@@ -407,7 +474,7 @@ public class TestDatabaseConfiguration e
*/
public void testSetPropertyWithDelimiter()
{
- DatabaseConfiguration config = setUpMultiConfig();
+ DatabaseConfiguration config = helper.setUpMultiConfig();
config.setListDelimiter(';');
config.setProperty("keyList", "1;2;3");
String[] values = config.getStringArray("keyList");
Modified: commons/proper/configuration/trunk/xdocs/changes.xml
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/xdocs/changes.xml?rev=931307&r1=931306&r2=931307&view=diff
==============================================================================
--- commons/proper/configuration/trunk/xdocs/changes.xml (original)
+++ commons/proper/configuration/trunk/xdocs/changes.xml Tue Apr 6 20:29:51
2010
@@ -26,6 +26,11 @@
<action dev="oheger" type="fix" issue="CONFIGURATION-413"
due-to="Alexander Prishchepov">
SubsetConfiguration now produces correct events.
</action>
+ <action dev="oheger" type="add" issue="CONFIGURATION-412">
+ DatabaseConfiguration can now be instructed to perform a commit after
an
+ update of the managed database table. This makes it usable in
+ environments where the connections do not use auto-commit mode.
+ </action>
<action dev="oheger" type="fix" issue="CONFIGURATION-409">
HierarchicalINIConfiguration now correctly saves sections whose name
contains delimiter characters.