You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by rg...@apache.org on 2009/10/10 16:44:01 UTC

svn commit: r823862 - in /commons/proper/configuration/branches/configuration2_experimental/src: main/java/org/apache/commons/configuration2/reloading/ test/java/org/apache/commons/configuration2/ test/java/org/apache/commons/configuration2/reloading/ ...

Author: rgoers
Date: Sat Oct 10 14:44:00 2009
New Revision: 823862

URL: http://svn.apache.org/viewvc?rev=823862&view=rev
Log:
Remove VFSFileMonitorReloadingStrategy. Add VFSFileChangedReloadingStrategy

Added:
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/reloading/VFSFileChangedReloadingStrategy.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/reloading/TestVFSFileChangedReloadingStrategy.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testFileReloadConfigurationBuilder.xml
    commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration.xsd
    commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_3001.xml
    commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_3002.xml
    commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testVFSMultiTenentConfigurationBuilder1.xml
    commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testVFSMultiTenentConfigurationBuilder2.xml
Removed:
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/reloading/VFSFileMonitorReloadingStrategy.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/reloading/TestVFSFileMonitorReloadingStrategy.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testFileMonitorConfigurationBuilder.xml
    commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testFileMonitorConfigurationBuilder2.xml
Modified:
    commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestVFSConfigurationBuilder.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestWebdavConfigurationBuilder.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_default.xml

Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/reloading/VFSFileChangedReloadingStrategy.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/reloading/VFSFileChangedReloadingStrategy.java?rev=823862&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/reloading/VFSFileChangedReloadingStrategy.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/reloading/VFSFileChangedReloadingStrategy.java Sat Oct 10 14:44:00 2009
@@ -0,0 +1,204 @@
+/*
+ * 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.commons.configuration2.reloading;
+
+import org.apache.commons.configuration2.FileConfiguration;
+import org.apache.commons.configuration2.fs.FileSystemBased;
+import org.apache.commons.configuration2.fs.FileSystem;
+import org.apache.commons.configuration2.ConfigurationRuntimeException;
+import org.apache.commons.vfs.FileSystemManager;
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.VFS;
+import org.apache.commons.vfs.FileSystemException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * <p>A reloading strategy that will reload the configuration every time its
+ * underlying file is changed.</p>
+ * <p>This reloading strategy does not actively monitor a configuration file,
+ * but is triggered by its associated configuration whenever properties are
+ * accessed. It then checks the configuration file's last modification date
+ * and causes a reload if this has changed.</p>
+ * <p>To avoid permanent disc access on successive property lookups a refresh
+ * delay can be specified. This has the effect that the configuration file's
+ * last modification date is only checked once in this delay period. The default
+ * value for this refresh delay is 5 seconds.</p>
+ * <p>This strategy only works with FileConfiguration instances.</p>
+ *
+ * @author Emmanuel Bourg
+ * @version $Revision: 819418 $, $Date: 2009-09-27 15:28:16 -0700 (Sun, 27 Sep 2009) $
+ * @since 1.1
+ */
+public class VFSFileChangedReloadingStrategy implements ReloadingStrategy
+{
+    /** Constant for the default refresh delay.*/
+    private static final int DEFAULT_REFRESH_DELAY = 5000;
+
+    /** Stores a reference to the configuration to be monitored.*/
+    protected FileConfiguration configuration;
+
+    /** The last time the configuration file was modified. */
+    protected long lastModified;
+
+    /** The last time the file was checked for changes. */
+    protected long lastChecked;
+
+    /** The minimum delay in milliseconds between checks. */
+    protected long refreshDelay = DEFAULT_REFRESH_DELAY;
+
+    /** A flag whether a reload is required.*/
+    private boolean reloading;
+
+    /** Stores the logger.*/
+    private Log log = LogFactory.getLog(getClass());
+
+    public void setConfiguration(FileConfiguration configuration)
+    {
+        this.configuration = configuration;
+    }
+
+    public void init()
+    {
+        if (configuration.getURL() == null && configuration.getFileName() == null)
+        {
+            return;
+        }
+        if (this.configuration == null)
+        {
+            throw new IllegalStateException("No configuration has been set for this strategy");
+        }
+        updateLastModified();
+    }
+
+    public boolean reloadingRequired()
+    {
+        if (!reloading)
+        {
+            long now = System.currentTimeMillis();
+
+            if (now > lastChecked + refreshDelay)
+            {
+                lastChecked = now;
+                if (hasChanged())
+                {
+                    reloading = true;
+                }
+            }
+        }
+
+        return reloading;
+    }
+
+    public void reloadingPerformed()
+    {
+        updateLastModified();
+    }
+
+    /**
+     * Return the minimal time in milliseconds between two reloadings.
+     *
+     * @return the refresh delay (in milliseconds)
+     */
+    public long getRefreshDelay()
+    {
+        return refreshDelay;
+    }
+
+    /**
+     * Set the minimal time between two reloadings.
+     *
+     * @param refreshDelay refresh delay in milliseconds
+     */
+    public void setRefreshDelay(long refreshDelay)
+    {
+        this.refreshDelay = refreshDelay;
+    }
+
+    /**
+     * Update the last modified time.
+     */
+    protected void updateLastModified()
+    {
+        FileObject file = getFile();
+        if (file != null)
+        {
+            try
+            {
+                lastModified = file.getContent().getLastModifiedTime();
+            }
+            catch (FileSystemException fse)
+            {
+                log.error("Unable to get last modified time for" + file.getName().getURI());
+            }
+        }
+        reloading = false;
+    }
+
+    /**
+     * Check if the configuration has changed since the last time it was loaded.
+     *
+     * @return a flag whether the configuration has changed
+     */
+    protected boolean hasChanged()
+    {
+        FileObject file = getFile();
+        try
+        {
+            if (file == null || !file.exists())
+            {
+                return false;
+            }
+
+            return file.getContent().getLastModifiedTime() > lastModified;
+        }
+        catch (FileSystemException ex)
+        {
+            log.error("Unable to get last modified time for" + file.getName().getURI());
+            return false;
+        }
+    }
+
+    /**
+     * Returns the file that is monitored by this strategy. Note that the return
+     * value can be <b>null </b> under some circumstances.
+     *
+     * @return the monitored file
+     */
+    protected FileObject getFile()
+    {
+        try
+        {
+            FileSystemManager fsManager = VFS.getManager();
+            FileSystem fs = ((FileSystemBased) configuration).getFileSystem();
+            String uri = fs.getPath(null, configuration.getURL(), configuration.getBasePath(),
+                configuration.getFileName());
+            if (uri == null)
+            {
+                throw new ConfigurationRuntimeException("Unable to determine file to monitor");
+            }
+            return fsManager.resolveFile(uri);
+        }
+        catch (FileSystemException fse)
+        {
+            String msg = "Unable to monitor " + configuration.getURL().toString();
+            log.error(msg);
+            throw new ConfigurationRuntimeException(msg, fse);
+        }
+    }
+}

Modified: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestVFSConfigurationBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestVFSConfigurationBuilder.java?rev=823862&r1=823861&r2=823862&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestVFSConfigurationBuilder.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestVFSConfigurationBuilder.java Sat Oct 10 14:44:00 2009
@@ -35,7 +35,6 @@
 import org.apache.commons.configuration2.fs.FileSystemBased;
 import org.apache.commons.configuration2.fs.VFSFileSystem;
 import org.apache.commons.configuration2.reloading.FileChangedReloadingStrategy;
-import org.apache.commons.configuration2.reloading.VFSFileMonitorReloadingStrategy;
 import org.apache.commons.configuration2.tree.DefaultConfigurationNode;
 import org.apache.commons.configuration2.tree.xpath.XPathExpressionEngine;
 
@@ -90,14 +89,14 @@
     private static final File FILESYSTEM_FILE = ConfigurationAssert
             .getTestFile("testFileSystem.xml");
 
-    private static final File FILEMONITOR_FILE = ConfigurationAssert
-            .getTestFile("testFileMonitorConfigurationBuilder.xml");
+    private static final File FILERELOAD_FILE = ConfigurationAssert
+            .getTestFile("testFileReloadConfigurationBuilder.xml");
 
-    private static final File FILEMONITOR2_FILE = ConfigurationAssert
-            .getTestFile("testFileMonitorConfigurationBuilder2.xml");
+    private static final File MULTI_RELOAD_FILE1 = ConfigurationAssert
+            .getTestFile("testVFSMultiTenentConfigurationBuilder1.xml");
 
-    private static final String FILEMONITOR_URI = "file://" + System.getProperty("user.dir")
-            + "/target/test-classes/testFileMonitorConfigurationBuilder2.xml";
+    private static final File MULTI_RELOAD_FILE2 = ConfigurationAssert
+            .getTestFile("testVFSMultiTenentConfigurationBuilder2.xml");
 
     /** Constant for the name of an optional configuration.*/
     private static final String OPTIONAL_NAME = "optionalConfig";
@@ -112,7 +111,6 @@
     {
         super();
         //System.setProperty("log4j.configuration", "log4j-test.xml");
-        VFSFileMonitorReloadingStrategy.stopMonitor();
     }
 
     @Override
@@ -992,7 +990,7 @@
         }
     }
 
-    public void testFileMonitor1() throws Exception
+    public void testFileReload1() throws Exception
     {
 
         // create a new configuration
@@ -1000,124 +998,146 @@
         File output = new File("target/test-classes/testwrite/testMultiConfiguration_1001.xml");
         output.getParentFile().mkdir();
         copyFile(input, output);
+        // Sleep to make sure the file timestamp is not in the same second as "now".
+        Thread.sleep(1100);
 
-        factory.setFile(FILEMONITOR_FILE);
+        factory.setFile(FILERELOAD_FILE);
         FileSystem.resetDefaultFileSystem();
         System.getProperties().remove("Id");
 
         CombinedConfiguration config = factory.getConfiguration(true);
         assertNotNull(config);
-        config.addConfigurationListener(this);
         verify("1001", config, 15);
-
-        // Allow time for FileMonitor to set up.
-        Thread.sleep(1000);
         XMLConfiguration x = new XMLConfiguration(output);
         x.setProperty("rowsPerPage", "50");
         x.save();
-
-        waitForChange();
         verify("1001", config, 50);
         output.delete();
-        VFSFileMonitorReloadingStrategy.stopMonitor();
     }
 
-    public void testFileMonitor2() throws Exception
+    public void testFileReload2() throws Exception
     {
         // create a new configuration
         File input = new File("target/test-classes/testMultiConfiguration_1002.xml");
         File output = new File("target/test-classes/testwrite/testMultiConfiguration_1002.xml");
         output.delete();
 
-        factory.setFile(FILEMONITOR_FILE);
+        factory.setFile(FILERELOAD_FILE);
         FileSystem.resetDefaultFileSystem();
         System.getProperties().remove("Id");
 
         CombinedConfiguration config = factory.getConfiguration(true);
-        config.addConfigurationListener(this);
         assertNotNull(config);
 
         verify("1002", config, 50);
-        Thread.sleep(1000);
+        Thread.sleep(1100);
 
         output.getParentFile().mkdir();
         copyFile(input, output);
-
-        // Allow time for the monitor to notice the change.
-        //Thread.sleep(2000);
-        waitForChange();
-        try
-        {
-            verify("1002", config, 25);
-        }
-        finally
-        {
-            output.delete();
-            VFSFileMonitorReloadingStrategy.stopMonitor();
-        }
+        verify("1002", config, 25);
+        output.delete();
     }
 
 
-    public void testFileMonitor3() throws Exception
+    public void testFileReload3() throws Exception
     {
         // create a new configuration
         File input = new File("target/test-classes/testMultiConfiguration_1001.xml");
         File output = new File("target/test-classes/testwrite/testMultiConfiguration_1001.xml");
         output.delete();
         output.getParentFile().mkdir();
-        copyFile(input, output);
 
-        factory.setFile(FILEMONITOR2_FILE);
+        factory.setFile(FILERELOAD_FILE);
         FileSystem.resetDefaultFileSystem();
         System.getProperties().remove("Id");
 
         CombinedConfiguration config = factory.getConfiguration(true);
-        //config.setLogger(logger);
         assertNotNull(config);
-        config.addConfigurationListener(this);
-        verify("1001", config, 15);
-
+        verify("1001", config, 50);
+        copyFile(input, output);
         // Allow time for FileMonitor to set up.
-        Thread.sleep(1000);
+        Thread.sleep(1100);
+        verify("1001", config, 15);
         XMLConfiguration x = new XMLConfiguration(output);
-        x.setProperty("rowsPerPage", "50");
+        x.setProperty("rowsPerPage", "25");
         x.save();
-        // Let FileMonitor detect the change.
-        //Thread.sleep(2000);
-        waitForChange();
-        verify("1001", config, 50);
+        Thread.sleep(1100);
+        verify("1001", config, 25);
         output.delete();
-        VFSFileMonitorReloadingStrategy.stopMonitor();
     }
 
-    public void testFileMonitor4() throws Exception
+    public void testReloadDefault() throws Exception
     {
         // create a new configuration
-        File input = new File("target/test-classes/testMultiConfiguration_1002.xml");
-        File output = new File("target/test-classes/testwrite/testMultiConfiguration_1002.xml");
-        output.delete();
+        String defaultName = "target/test-classes/testMultiConfiguration_default.xml";
+        File input = new File(defaultName);
 
-        factory.setFileName(FILEMONITOR_URI);
-        FileSystem.resetDefaultFileSystem();
         System.getProperties().remove("Id");
-
+        factory.setFile(MULTI_RELOAD_FILE1);
         CombinedConfiguration config = factory.getConfiguration(true);
         assertNotNull(config);
-        config.addConfigurationListener(this);
+        verify("3001", config, 15);
+        verify("3002", config, 25);
+        System.setProperty("Id", "3002");
+        config.addProperty("/ TestProp", "Test");
+        assertTrue("Property not added", "Test".equals(config.getString("TestProp")));
+        System.getProperties().remove("Id");
+        //Sleep so refreshDelay elapses
+        Thread.sleep(600);
+        long time = System.currentTimeMillis();
+        long original = input.lastModified();
+        input.setLastModified(time);
+        File defaultFile = new File(defaultName);
+        long newTime = defaultFile.lastModified();
+        assertTrue("time mismatch", original != newTime);
+        Thread.sleep(600);
+        verify("3001", config, 15);
+        verify("3002", config, 25);
+        System.setProperty("Id", "3002");
+        String test = config.getString("TestProp");
+        assertNull("Property was not cleared by reload", test);
+    }
 
-        verify("1002", config, 50);
-        Thread.sleep(1000);
+    /* Test doesn't pass yet.
+    public void testFileReloadSchemaValidationError() throws Exception
+    {
+        System.getProperties().remove("Id");
+        factory.setFile(MULTI_RELOAD_FILE2);
+        CombinedConfiguration config = factory.getConfiguration(true);
 
+        // create a new configuration
+        File input = new File("target/test-classes/testMultiConfiguration_3001.xml");
+        File output = new File("target/test-classes/testwrite/testMultiConfiguration_3001.xml");
+        output.delete();
         output.getParentFile().mkdir();
         copyFile(input, output);
 
-        // Allow time for the monitor to notice the change.
-        //Thread.sleep(2000);
-        waitForChange();
-        verify("1002", config, 25);
+        assertNotNull(config);
+        verify("3001", config, 15);
+        Thread.sleep(1100);
+        XMLConfiguration x = new XMLConfiguration();
+        x.setFile(output);
+        x.setAttributeSplittingDisabled(true);
+        x.setDelimiterParsingDisabled(true);
+        x.load();
+        x.setProperty("rowsPerPage", "test");
+        //Insure orginal timestamp and new timestamp aren't the same second.
+        Thread.sleep(1100);
+        x.save();
+        System.setProperty("Id", "3001");
+        try
+        {
+            config.getInt("rowsPerPage");
+            fail("No exception was thrown");
+        }
+        catch (Exception ex)
+        {
+
+        }
+
         output.delete();
-        VFSFileMonitorReloadingStrategy.stopMonitor();
-    }
+    } */
+
 
     private void copyFile(File input, File output) throws IOException
     {

Modified: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestWebdavConfigurationBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestWebdavConfigurationBuilder.java?rev=823862&r1=823861&r2=823862&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestWebdavConfigurationBuilder.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestWebdavConfigurationBuilder.java Sat Oct 10 14:44:00 2009
@@ -31,7 +31,6 @@
 
 import org.apache.commons.configuration2.beanutils.BeanHelper;
 import org.apache.commons.configuration2.reloading.FileChangedReloadingStrategy;
-import org.apache.commons.configuration2.reloading.VFSFileMonitorReloadingStrategy;
 import org.apache.commons.configuration2.tree.DefaultConfigurationNode;
 import org.apache.commons.configuration2.tree.xpath.XPathExpressionEngine;
 import org.apache.commons.configuration2.event.ConfigurationEvent;
@@ -91,13 +90,13 @@
     private static final String MULTI_TENENT_FILE =
             "testMultiTenentConfigurationBuilder.xml";
 
-    private static final String FILEMONITOR2_FILE =
-            "testFileMonitorConfigurationBuilder2.xml";
+    private static final String FILERELOAD2_FILE =
+            "testFileReloadConfigurationBuilder2.xml";
 
-    private static final String FILEMONITOR_1001_FILE =
+    private static final String FILERELOAD_1001_FILE =
             "testwrite/testMultiConfiguration_1001.xml";
 
-    private static final String FILEMONITOR_1002_FILE =
+    private static final String FILERELOAD_1002_FILE =
             "testwrite/testMultiConfiguration_1002.xml";
 
     private static final String TEST_PROPERTIES = "test.properties.xml";
@@ -883,16 +882,16 @@
         verify("1005", config, 50);
     }
 
-    public void testFileMonitor1() throws Exception
+    public void testFileChanged() throws Exception
     {
         // create a new configuration
         File input = new File("target/test-classes/testMultiConfiguration_1001.xml");
-        FileObject output = getFile(getBasePath() + FILEMONITOR_1001_FILE);
+        FileObject output = getFile(getBasePath() + FILERELOAD_1001_FILE);
         output.delete();
         output.getParent().createFolder();
         copyFile(input, output);
 
-        factory.setFileName(getBasePath() + FILEMONITOR2_FILE);
+        factory.setFileName(getBasePath() + FILERELOAD2_FILE);
         System.getProperties().remove("Id");
 
         CombinedConfiguration config = factory.getConfiguration(true);
@@ -902,7 +901,7 @@
 
         // Allow time for FileMonitor to set up.
         Thread.sleep(1000);
-        XMLConfiguration x = new XMLConfiguration(getBasePath() + FILEMONITOR_1001_FILE);
+        XMLConfiguration x = new XMLConfiguration(getBasePath() + FILERELOAD_1001_FILE);
         x.setProperty("rowsPerPage", "50");
         x.save();
         // Let FileMonitor detect the change.
@@ -910,17 +909,16 @@
         waitForChange();
         verify("1001", config, 50);
         output.delete();
-        VFSFileMonitorReloadingStrategy.stopMonitor();
     }
 
-    public void testFileMonitor2() throws Exception
+    public void testFileChanged2() throws Exception
     {
         // create a new configuration
         File input = new File("target/test-classes/testMultiConfiguration_1002.xml");
-        FileObject output = getFile(getBasePath() + FILEMONITOR_1002_FILE);
+        FileObject output = getFile(getBasePath() + FILERELOAD_1002_FILE);
         output.delete();
 
-        factory.setFileName(getBasePath() + FILEMONITOR2_FILE);
+        factory.setFileName(getBasePath() + FILERELOAD2_FILE);
         System.getProperties().remove("Id");
 
         CombinedConfiguration config = factory.getConfiguration(true);
@@ -938,7 +936,6 @@
         waitForChange();
         verify("1002", config, 25);
         output.delete();
-        VFSFileMonitorReloadingStrategy.stopMonitor();
     }
 
 

Added: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/reloading/TestVFSFileChangedReloadingStrategy.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/reloading/TestVFSFileChangedReloadingStrategy.java?rev=823862&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/reloading/TestVFSFileChangedReloadingStrategy.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/reloading/TestVFSFileChangedReloadingStrategy.java Sat Oct 10 14:44:00 2009
@@ -0,0 +1,148 @@
+/*
+ * 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.commons.configuration2.reloading;
+
+import java.io.File;
+import java.io.FileWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration2.ConfigurationException;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.apache.commons.configuration2.fs.FileSystem;
+import org.apache.commons.configuration2.fs.VFSFileSystem;
+
+/**
+ * Test case for the VFSFileMonitorReloadingStrategy class.
+ *
+ * @author Ralph Goers
+ * @version $Revision: 819418 $
+ */
+public class TestVFSFileChangedReloadingStrategy extends TestCase
+{
+    /** Constant for the name of a test properties file.*/
+    private static final String TEST_FILE = "test.properties";
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        FileSystem.setDefaultFileSystem(new VFSFileSystem());
+    }
+
+    protected void tearDown() throws Exception
+    {
+        FileSystem.resetDefaultFileSystem();
+        super.tearDown();
+    }
+
+    public void testAutomaticReloading() throws Exception
+    {
+        // create a new configuration
+        File file = new File("target/testReload.properties");
+
+        if (file.exists())
+        {
+            file.delete();
+        }
+
+        // create the configuration file
+        FileWriter out = new FileWriter(file);
+        out.write("string=value1");
+        out.flush();
+        out.close();
+
+        // load the configuration
+        PropertiesConfiguration config = new PropertiesConfiguration("target/testReload.properties");
+        VFSFileChangedReloadingStrategy strategy = new VFSFileChangedReloadingStrategy();
+        strategy.setRefreshDelay(500);
+        config.setReloadingStrategy(strategy);
+        assertEquals("Initial value", "value1", config.getString("string"));
+
+        Thread.sleep(2000);
+
+        // change the file
+        out = new FileWriter(file);
+        out.write("string=value2");
+        out.flush();
+        out.close();
+
+        // test the automatic reloading
+        assertEquals("Modified value with enabled reloading", "value2", config.getString("string"));
+    }
+
+    public void testNewFileReloading() throws Exception
+    {
+        // create a new configuration
+        File file = new File("target/testReload.properties");
+
+        if (file.exists())
+        {
+            file.delete();
+        }
+
+        PropertiesConfiguration config = new PropertiesConfiguration();
+        config.setFile(file);
+        VFSFileChangedReloadingStrategy strategy = new VFSFileChangedReloadingStrategy();
+        strategy.setRefreshDelay(500);
+        config.setReloadingStrategy(strategy);
+
+        assertNull("Initial value", config.getString("string"));
+
+        // change the file
+        FileWriter out = new FileWriter(file);
+        out.write("string=value1");
+        out.flush();
+        out.close();
+
+        Thread.sleep(2000);
+
+        // test the automatic reloading
+        assertEquals("Modified value with enabled reloading", "value1", config.getString("string"));
+    }
+
+    public void testGetRefreshDelay() throws Exception
+    {
+        VFSFileChangedReloadingStrategy strategy = new VFSFileChangedReloadingStrategy();
+        strategy.setRefreshDelay(500);
+        assertEquals("refresh delay", 500, strategy.getRefreshDelay());
+    }
+
+    /**
+     * Tests calling reloadingRequired() multiple times before a reload actually
+     * happens. This test is related to CONFIGURATION-302.
+     */
+    public void testReloadingRequiredMultipleTimes()
+            throws ConfigurationException
+    {
+        VFSFileChangedReloadingStrategy strategy = new VFSFileChangedReloadingStrategy()
+        {
+            protected boolean hasChanged()
+            {
+                // signal always a change
+                return true;
+            }
+        };
+        strategy.setRefreshDelay(100000);
+        PropertiesConfiguration config = new PropertiesConfiguration(TEST_FILE);
+        config.setReloadingStrategy(strategy);
+        assertTrue("Reloading not required", strategy.reloadingRequired());
+        assertTrue("Reloading no more required", strategy.reloadingRequired());
+        strategy.reloadingPerformed();
+        assertFalse("Reloading still required", strategy.reloadingRequired());
+    }
+}
\ No newline at end of file

Added: commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testFileReloadConfigurationBuilder.xml
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testFileReloadConfigurationBuilder.xml?rev=823862&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testFileReloadConfigurationBuilder.xml (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testFileReloadConfigurationBuilder.xml Sat Oct 10 14:44:00 2009
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!-- Test configuration definition file that demonstrates complex initialization -->
+<configuration>
+  <header>
+    <result delimiterParsingDisabled="true" forceReloadCheck="true"
+            config-class="org.apache.commons.configuration2.DynamicCombinedConfiguration"
+            keyPattern="$${sys:Id}">
+      <nodeCombiner config-class="org.apache.commons.configuration2.tree.MergeCombiner"/>
+      <expressionEngine
+          config-class="org.apache.commons.configuration2.tree.xpath.XPathExpressionEngine"/>
+    </result>
+    <fileSystem config-class="org.apache.commons.configuration2.fs.VFSFileSystem"/>
+    <providers>
+      <provider config-tag="multifile"
+         config-class="org.apache.commons.configuration2.DefaultConfigurationBuilder$FileConfigurationProvider"
+         configurationClass="org.apache.commons.configuration2.MultiFileHierarchicalConfiguration"/>
+    </providers>
+  </header>
+  <override>
+    <multifile filePattern="testwrite/testMultiConfiguration_$$${sys:Id}.xml"
+               config-name="clientConfig" delimiterParsingDisabled="true" schemaValidation="false">
+       <expressionEngine
+          config-class="org.apache.commons.configuration2.expr.xpath.XPathExpressionEngine"/>
+       <reloadingStrategy refreshDelay="0"
+          config-class="org.apache.commons.configuration2.reloading.VFSFileChangedReloadingStrategy"/>
+    </multifile>
+    <xml fileName="testMultiConfiguration_default.xml"
+         config-name="defaultConfig" delimiterParsingDisabled="true">
+      <expressionEngine
+          config-class="org.apache.commons.configuration2.expr.xpath.XPathExpressionEngine"/>
+      <reloadingStrategy refreshDelay="0"
+          config-class="org.apache.commons.configuration2.reloading.VFSFileChangedReloadingStrategy"/>
+    </xml>
+  </override>
+</configuration>
\ No newline at end of file

Added: commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration.xsd
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration.xsd?rev=823862&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration.xsd (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration.xsd Sat Oct 10 14:44:00 2009
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+  <xs:element name="configuration" type="configurationType"/>
+  <xs:complexType name="configurationType">
+    <xs:sequence>
+      <xs:element type="colorsType" name="colors" minOccurs="0"/>
+      <xs:element type="xs:integer" name="rowsPerPage" minOccurs="0"/>
+      <xs:element type="buttonsType" name="buttons" minOccurs="0"/>
+      <xs:element type="numberFormatType" name="numberFormat" minOccurs="0"/>
+      <xs:element type="splitType" name="split" minOccurs="0">
+        <xs:annotation>
+          <xs:documentation>Comma delimited lists</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+      <xs:element type="ChannelsType" name="Channels" minOccurs="0"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="splitType">
+    <xs:sequence>
+      <xs:element type="xs:string" name="list1" minOccurs="0"/>
+      <xs:element type="xs:string" name="list2" minOccurs="0"/>
+      <xs:element type="list3Type" name="list3" minOccurs="0"/>
+      <xs:element type="list4Type" name="list4" minOccurs="0"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="colorsType">
+    <xs:sequence>
+      <xs:element type="xs:string" name="background" minOccurs="0"/>
+      <xs:element type="xs:string" name="text" minOccurs="0"/>
+      <xs:element type="xs:string" name="header" minOccurs="0"/>
+      <xs:element type="linkType" name="link" minOccurs="0"/>
+      <xs:element type="xs:string" name="default" minOccurs="0"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="list4Type">
+    <xs:simpleContent>
+      <xs:extension base="xs:string">
+        <xs:attribute type="xs:string" name="values"/>
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
+  <xs:complexType name="linkType">
+    <xs:simpleContent>
+      <xs:extension base="xs:string">
+        <xs:attribute type="xs:string" name="normal"/>
+        <xs:attribute type="xs:string" name="visited"/>
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
+  <xs:complexType name="list3Type">
+    <xs:simpleContent>
+      <xs:extension base="xs:string">
+        <xs:attribute type="xs:string" name="values"/>
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
+  <xs:complexType name="buttonsType">
+    <xs:sequence>
+      <xs:element type="xs:string" name="name" minOccurs="0"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="numberFormatType">
+    <xs:simpleContent>
+      <xs:extension base="xs:string">
+        <xs:attribute type="xs:string" name="pattern"/>
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
+  <xs:complexType name="ChannelType">
+    <xs:sequence>
+      <xs:element name="Name" minOccurs="0">
+        <xs:simpleType>
+          <xs:restriction base="xs:string">
+          </xs:restriction>
+        </xs:simpleType>
+      </xs:element>
+      <xs:element name="ChannelData" minOccurs="0">
+        <xs:simpleType>
+          <xs:restriction base="xs:string">
+          </xs:restriction>
+        </xs:simpleType>
+      </xs:element>
+      <xs:element name="MoreChannelData" minOccurs="0">
+        <xs:simpleType>
+          <xs:restriction base="xs:string">
+          </xs:restriction>
+        </xs:simpleType>
+      </xs:element>
+    </xs:sequence>
+    <xs:attribute type="xs:string" name="id" use="optional"/>
+  </xs:complexType>
+  <xs:complexType name="ChannelsType">
+    <xs:choice maxOccurs="unbounded" minOccurs="0">
+      <xs:element type="ChannelType" name="Channel" minOccurs="0"/>
+    </xs:choice>
+  </xs:complexType>
+</xs:schema>
\ No newline at end of file

Added: commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_3001.xml
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_3001.xml?rev=823862&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_3001.xml (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_3001.xml Sat Oct 10 14:44:00 2009
@@ -0,0 +1,24 @@
+<?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>#808080</background>
+    <text>#000000</text>
+    <header>#008000</header>
+    <link normal="#000080" visited="#800080"/>
+    <default>${colors.header}</default>
+  </colors>
+  <rowsPerPage>15</rowsPerPage>
+  <buttons>
+    <name>OK,Cancel,Help</name>
+  </buttons>
+  <numberFormat pattern="###\,###.##"/>
+  <Channels>
+    <Channel id="1">
+      <Name>My Channel</Name>
+    </Channel>
+    <Channel id="2">
+      <MoreChannelData>more test 2 data</MoreChannelData>
+    </Channel>
+  </Channels>
+</configuration>

Added: commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_3002.xml
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_3002.xml?rev=823862&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_3002.xml (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_3002.xml Sat Oct 10 14:44:00 2009
@@ -0,0 +1,16 @@
+<?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>#2222222</background>
+    <text>#000000</text>
+    <header>#222222</header>
+    <link normal="#020202" visited="#202020"/>
+    <default>${colors.header3}</default>
+  </colors>
+  <rowsPerPage>25</rowsPerPage>
+  <buttons>
+    <name>OK-2,Cancel-2,Help-2</name>
+  </buttons>
+  <numberFormat pattern="###\,###.##"/>
+</configuration>

Modified: commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_default.xml
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_default.xml?rev=823862&r1=823861&r2=823862&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_default.xml (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_default.xml Sat Oct 10 14:44:00 2009
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="ISO-8859-1" ?>
-<configuration>
+<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>

Added: commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testVFSMultiTenentConfigurationBuilder1.xml
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testVFSMultiTenentConfigurationBuilder1.xml?rev=823862&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testVFSMultiTenentConfigurationBuilder1.xml (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testVFSMultiTenentConfigurationBuilder1.xml Sat Oct 10 14:44:00 2009
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!-- Test configuration definition file that demonstrates complex initialization -->
+<configuration>
+  <header>
+    <result delimiterParsingDisabled="true" forceReloadCheck="true" loggerName="TestLogger"
+            config-class="org.apache.commons.configuration2.DynamicCombinedConfiguration"
+            keyPattern="$${sys:Id}">
+      <nodeCombiner config-class="org.apache.commons.configuration2.tree.MergeCombiner"/>
+      <expressionEngine
+          config-class="org.apache.commons.configuration2.tree.xpath.XPathExpressionEngine"/>
+    </result>
+    <fileSystem config-class="org.apache.commons.configuration2.fs.VFSFileSystem"/>
+    <entity-resolver catalogFiles="catalog.xml"/>
+    <providers>
+      <provider config-tag="multifile"
+         config-class="org.apache.commons.configuration2.DefaultConfigurationBuilder$FileConfigurationProvider"
+         configurationClass="org.apache.commons.configuration2.MultiFileHierarchicalConfiguration"/>
+    </providers>
+  </header>
+  <override>
+    <multifile filePattern="testMultiConfiguration_$$${sys:Id}.xml"
+               config-name="clientConfig" delimiterParsingDisabled="true" schemaValidation="true">
+       <expressionEngine
+          config-class="org.apache.commons.configuration2.expr.xpath.XPathExpressionEngine"/>
+       <reloadingStrategy refreshDelay="500"
+          config-class="org.apache.commons.configuration2.reloading.VFSFileChangedReloadingStrategy"/>
+    </multifile>
+    <xml fileName="testMultiConfiguration_default.xml"
+         config-name="defaultConfig" delimiterParsingDisabled="true" schemaValidation="true">
+      <expressionEngine
+          config-class="org.apache.commons.configuration2.expr.xpath.XPathExpressionEngine"/>
+      <reloadingStrategy refreshDelay="500"
+          config-class="org.apache.commons.configuration2.reloading.VFSFileChangedReloadingStrategy"/>
+    </xml>
+  </override>
+</configuration>
\ No newline at end of file

Added: commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testVFSMultiTenentConfigurationBuilder2.xml
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testVFSMultiTenentConfigurationBuilder2.xml?rev=823862&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testVFSMultiTenentConfigurationBuilder2.xml (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testVFSMultiTenentConfigurationBuilder2.xml Sat Oct 10 14:44:00 2009
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!-- Test configuration definition file that demonstrates complex initialization -->
+<configuration>
+  <header>
+    <result delimiterParsingDisabled="true" forceReloadCheck="true" loggerName="TestLogger"
+            config-class="org.apache.commons.configuration2.DynamicCombinedConfiguration"
+            keyPattern="$${sys:Id}">
+      <nodeCombiner config-class="org.apache.commons.configuration2.tree.MergeCombiner"/>
+      <expressionEngine
+          config-class="org.apache.commons.configuration2.tree.xpath.XPathExpressionEngine"/>
+    </result>
+    <fileSystem config-class="org.apache.commons.configuration2.fs.VFSFileSystem"/>
+    <entity-resolver catalogFiles="catalog.xml"/>
+    <providers>
+      <provider config-tag="multifile"
+         config-class="org.apache.commons.configuration2.DefaultConfigurationBuilder$FileConfigurationProvider"
+         configurationClass="org.apache.commons.configuration2.MultiFileHierarchicalConfiguration"/>
+    </providers>
+  </header>
+  <override>
+    <multifile filePattern="testwrite/testMultiConfiguration_$$${sys:Id}.xml"
+               config-name="clientConfig" delimiterParsingDisabled="true" schemaValidation="true">
+       <expressionEngine
+          config-class="org.apache.commons.configuration2.expr.xpath.XPathExpressionEngine"/>
+       <reloadingStrategy refreshDelay="500"
+          config-class="org.apache.commons.configuration2.reloading.VFSFileChangedReloadingStrategy"/>
+    </multifile>
+    <xml fileName="testMultiConfiguration_default.xml"
+         config-name="defaultConfig" delimiterParsingDisabled="true" schemaValidation="true">
+      <expressionEngine
+          config-class="org.apache.commons.configuration2.expr.xpath.XPathExpressionEngine"/>
+      <reloadingStrategy refreshDelay="500"
+          config-class="org.apache.commons.configuration2.reloading.VFSFileChangedReloadingStrategy"/>
+    </xml>
+  </override>
+</configuration>
\ No newline at end of file