Author: rgoers Date: Wed Oct 21 05:41:59 2009 New Revision: 827888 URL: http://svn.apache.org/viewvc?rev=827888&view=rev Log: Default file won't reload if it is being accessed from a second thread.
Added: commons/proper/configuration/trunk/conf/testMultiDynamic_default.xml - copied, changed from r823891, commons/proper/configuration/trunk/conf/testMultiConfiguration_default.xml commons/proper/configuration/trunk/conf/testMultiDynamic_default2.xml commons/proper/configuration/trunk/conf/testMultiTenentConfigurationBuilder5.xml - copied, changed from r823891, commons/proper/configuration/trunk/conf/testMultiTenentConfigurationBuilder3.xml Modified: commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDynamicCombinedConfiguration.java Copied: commons/proper/configuration/trunk/conf/testMultiDynamic_default.xml (from r823891, commons/proper/configuration/trunk/conf/testMultiConfiguration_default.xml) URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/conf/testMultiDynamic_default.xml?p2=commons/proper/configuration/trunk/conf/testMultiDynamic_default.xml&p1=commons/proper/configuration/trunk/conf/testMultiConfiguration_default.xml&r1=823891&r2=827888&rev=827888&view=diff ============================================================================== --- commons/proper/configuration/trunk/conf/testMultiConfiguration_default.xml (original) +++ commons/proper/configuration/trunk/conf/testMultiDynamic_default.xml Wed Oct 21 05:41:59 2009 @@ -8,6 +8,13 @@ <link normal="#040404" visited="#404040"/> <default>${colors.default}</default> </colors> + <Product> + <FIIndex> + <FI id="123456781">ID0001</FI> + <FI id="AUTO01">IDAUTO01</FI> + <FI id="AUTO02">IDAUTO02</FI> + </FIIndex> + </Product> <rowsPerPage>50</rowsPerPage> <buttons> <name>OK-4,Cancel-4,Help-4</name> Added: commons/proper/configuration/trunk/conf/testMultiDynamic_default2.xml URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/conf/testMultiDynamic_default2.xml?rev=827888&view=auto ============================================================================== --- commons/proper/configuration/trunk/conf/testMultiDynamic_default2.xml (added) +++ commons/proper/configuration/trunk/conf/testMultiDynamic_default2.xml Wed Oct 21 05:41:59 2009 @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://commons.apache.org/testMultiConfiguration.xsd"> + <colors> + <background>#40404040</background> + <text>#000000</text> + <header>#444444</header> + <link normal="#040404" visited="#404040"/> + <default>${colors.default}</default> + </colors> + <Product> + <FIIndex> + <FI id="123456781">ID0001</FI> + <FI id="123456782">ID0002</FI> + <FI id="AUTO01">IDAUTO01</FI> + <FI id="AUTO02">IDAUTO02</FI> + </FIIndex> + </Product> + <rowsPerPage>25</rowsPerPage> + <buttons> + <name>OK-4,Cancel-4,Help-4</name> + </buttons> + <numberFormat pattern="###\,###.##"/> + <!-- Comma delimited lists --> + <split> + <list1>a,b,c</list1> + <list2>a\,b\,c</list2> + <list3 values="a,b,c"/> + <list4 values="a\,b\,c"/> + </split> + <Channels> + <Channel id="1"> + <Name>Channel 1</Name> + <ChannelData>test 1 data</ChannelData> + </Channel> + <Channel id="2"> + <Name>Channel 2</Name> + <ChannelData>test 2 data</ChannelData> + </Channel> + </Channels> +</configuration> \ No newline at end of file Copied: commons/proper/configuration/trunk/conf/testMultiTenentConfigurationBuilder5.xml (from r823891, commons/proper/configuration/trunk/conf/testMultiTenentConfigurationBuilder3.xml) URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/conf/testMultiTenentConfigurationBuilder5.xml?p2=commons/proper/configuration/trunk/conf/testMultiTenentConfigurationBuilder5.xml&p1=commons/proper/configuration/trunk/conf/testMultiTenentConfigurationBuilder3.xml&r1=823891&r2=827888&rev=827888&view=diff ============================================================================== --- commons/proper/configuration/trunk/conf/testMultiTenentConfigurationBuilder3.xml (original) +++ commons/proper/configuration/trunk/conf/testMultiTenentConfigurationBuilder5.xml Wed Oct 21 05:41:59 2009 @@ -18,14 +18,14 @@ </header> <override> <multifile filePattern="testwrite/testMultiConfiguration_$$${sys:Id}.xml" - config-name="clientConfig" delimiterParsingDisabled="true" schemaValidation="true"> + config-name="clientConfig" delimiterParsingDisabled="true" schemaValidation="false"> <expressionEngine config-class="org.apache.commons.configuration.tree.xpath.XPathExpressionEngine"/> <reloadingStrategy refreshDelay="500" config-class="org.apache.commons.configuration.reloading.FileChangedReloadingStrategy"/> </multifile> - <xml fileName="testMultiConfiguration_default.xml" - config-name="defaultConfig" delimiterParsingDisabled="true" schemaValidation="true"> + <xml fileName="testwrite/testMultiDynamic_default.xml" + config-name="defaultConfig" delimiterParsingDisabled="true" schemaValidation="false"> <expressionEngine config-class="org.apache.commons.configuration.tree.xpath.XPathExpressionEngine"/> <reloadingStrategy refreshDelay="500" Modified: commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java?rev=827888&r1=827887&r2=827888&view=diff ============================================================================== --- commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java (original) +++ commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java Wed Oct 21 05:41:59 2009 @@ -302,14 +302,17 @@ private boolean reload(boolean checkReload) { - setDetailEvents(false); - try - { - return delegate.reload(checkReload); - } - finally + synchronized(delegate.getReloadLock()) { - setDetailEvents(true); + setDetailEvents(false); + try + { + return delegate.reload(checkReload); + } + finally + { + setDetailEvents(true); + } } } Modified: commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDynamicCombinedConfiguration.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDynamicCombinedConfiguration.java?rev=827888&r1=827887&r2=827888&view=diff ============================================================================== --- commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDynamicCombinedConfiguration.java (original) +++ commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDynamicCombinedConfiguration.java Wed Oct 21 05:41:59 2009 @@ -18,6 +18,11 @@ package org.apache.commons.configuration; import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.io.FileReader; +import java.io.Writer; +import java.io.FileWriter; import junit.framework.TestCase; import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; @@ -30,7 +35,9 @@ private static String DEFAULT_FILE = "target/test-classes/testMultiConfiguration_default.xml"; private static final File MULTI_TENENT_FILE = new File( "conf/testMultiTenentConfigurationBuilder4.xml"); - + private static final File MULTI_DYNAMIC_FILE = new File( + "conf/testMultiTenentConfigurationBuilder5.xml"); + public void testConfiguration() throws Exception { DynamicCombinedConfiguration config = new DynamicCombinedConfiguration(); @@ -158,6 +165,55 @@ assertTrue(totalFailures + " failures Occurred", totalFailures == 0); } + public void testConcurrentGetAndReloadFile() throws Exception + { + final int threadCount = 25; + System.getProperties().remove("Id"); + // create a new configuration + File input = new File("target/test-classes/testMultiDynamic_default.xml"); + File output = new File("target/test-classes/testwrite/testMultiDynamic_default.xml"); + output.delete(); + output.getParentFile().mkdir(); + copyFile(input, output); + + DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); + factory.setFile(MULTI_DYNAMIC_FILE); + CombinedConfiguration config = factory.getConfiguration(true); + + assertEquals(config.getString("Product/FIIndex/f...@id='123456781']"), "ID0001"); + + ReaderThread testThreads[] = new ReaderThread[threadCount]; + for (int i = 0; i < testThreads.length; ++i) + { + testThreads[i] = new ReaderThread(config); + testThreads[i].start(); + } + + Thread.sleep(2000); + + input = new File("target/test-classes/testMultiDynamic_default2.xml"); + copyFile(input, output); + + Thread.sleep(2000); + String id = config.getString("Product/FIIndex/f...@id='123456782']"); + assertNotNull("File did not reload, id is null", id); + String rows = config.getString("rowsPerPage"); + assertTrue("Incorrect value for rowsPerPage", "25".equals(rows)); + + for (int i = 0; i < testThreads.length; ++i) + { + testThreads[i].shutdown(); + testThreads[i].join(); + } + for (int i = 0; i < testThreads.length; ++i) + { + assertFalse(testThreads[i].failed()); + } + assertEquals("ID0002", config.getString("Product/FIIndex/f...@id='123456782']")); + output.delete(); + } + + private class ReloadThread extends Thread { CombinedConfiguration combined; @@ -205,12 +261,69 @@ } } + private class ReaderThread extends Thread + { + private boolean running = true; + private boolean failed = false; + CombinedConfiguration combined; + + public ReaderThread(CombinedConfiguration c) + { + combined = c; + } + + public void run() + { + while (running) + { + String bcId = combined.getString("Product/FIIndex/f...@id='123456781']"); + if ("ID0001".equalsIgnoreCase(bcId)) + { + if (failed) + { + System.out.println("Thread failed, but recovered"); + } + failed = false; + } + else + { + failed = true; + } + } + } + + public boolean failed() + { + return failed; + } + + public void shutdown() + { + running = false; + } + + } + private void verify(String key, DynamicCombinedConfiguration config, int rows) { System.setProperty("Id", key); assertTrue(config.getInt("rowsPerPage") == rows); } + private void copyFile(File input, File output) throws IOException + { + Reader reader = new FileReader(input); + Writer writer = new FileWriter(output); + char[] buffer = new char[4096]; + int n = 0; + while (-1 != (n = reader.read(buffer))) + { + writer.write(buffer, 0, n); + } + reader.close(); + writer.close(); + } + public static class ThreadLookup extends StrLookup { private static ThreadLocal id = new ThreadLocal();