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/03/23 19:17:33 UTC

svn commit: r757482 [1/3] - in /commons/proper/configuration/branches/configuration2_experimental: ./ src/main/java/org/apache/commons/configuration2/ src/main/java/org/apache/commons/configuration2/reloading/ src/test/java/org/apache/commons/configura...

Author: rgoers
Date: Mon Mar 23 18:17:32 2009
New Revision: 757482

URL: http://svn.apache.org/viewvc?rev=757482&view=rev
Log:
CONFIGURATION-340 Support for multiple FileSystem types

Added:
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DefaultFileSystem.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileOptionsProvider.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileSystem.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileSystemBased.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/HttpOutputStream.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VFSFileSystem.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VFSURLStreamHandler.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VerifiableOutputStream.java
    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/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/java/org/apache/commons/configuration2/reloading/TestVFSFileMonitorReloadingStrategy.java
Modified:
    commons/proper/configuration/branches/configuration2_experimental/pom.xml
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/AbstractFileConfiguration.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/AbstractHierarchicalFileConfiguration.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/ConfigurationUtils.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DefaultConfigurationBuilder.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DynamicCombinedConfiguration.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/MultiFileHierarchicalConfiguration.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/PropertiesConfiguration.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDefaultConfigurationBuilder.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDynamicCombinedConfiguration.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestMultiFileHierarchicalConfiguration.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestPatternSubtreeConfiguration.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestXMLConfiguration.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/tree/TestDefaultConfigurationNode.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_1001.xml
    commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiConfiguration_default.xml
    commons/proper/configuration/branches/configuration2_experimental/src/test/resources/testMultiTenentConfigurationBuilder.xml
    commons/proper/configuration/branches/configuration2_experimental/xdocs/changes.xml

Modified: commons/proper/configuration/branches/configuration2_experimental/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/pom.xml?rev=757482&r1=757481&r2=757482&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/pom.xml (original)
+++ commons/proper/configuration/branches/configuration2_experimental/pom.xml Mon Mar 23 18:17:32 2009
@@ -216,6 +216,27 @@
     </dependency>
 
     <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-vfs</artifactId>
+      <version>2.0-SNAPSHOT</version>
+      <optional>true</optional>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>1.5.6</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <version>1.5.6</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
       <groupId>javax.mail</groupId>
       <artifactId>mail</artifactId>
       <version>1.4</version>
@@ -351,6 +372,9 @@
           <artifactId>maven-surefire-plugin</artifactId>
           <configuration>
             <forkMode>once</forkMode>
+            <excludes>
+              <exclude>**/TestWebdavConfigurationBuilder.java</exclude>
+            </excludes>
             <additionalClasspathElements>
               <additionalClasspathElement>src/test/resources/resources.jar</additionalClasspathElement>
             </additionalClasspathElements>
@@ -393,7 +417,46 @@
         </plugin>  -->
       </plugins>
     </build>
-
+    <profiles>
+      <profile>
+        <id>webdav</id>
+        <activation>
+          <activeByDefault>false</activeByDefault>
+        </activation>
+        <dependencies>
+          <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-webdav</artifactId>
+            <version>1.5.2</version>
+            <scope>test</scope>
+          </dependency>
+        </dependencies>
+        <build>
+          <plugins>
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-surefire-plugin</artifactId>
+              <configuration>
+                <forkMode>once</forkMode>
+                <systemProperties>
+                  <property>
+                    <name>java.awt.headless</name>
+                    <value>true</value>
+                  </property>
+                  <property>
+                    <name>test.webdav.base</name>
+                    <value>${test.webdav.base}</value>
+                  </property>
+                </systemProperties>
+                <includes>
+                  <include>**/TestWebdavConfigurationBuilder.java</include>
+                </includes>
+              </configuration>
+            </plugin>
+          </plugins>
+        </build>
+      </profile>
+    </profiles>
     <reporting>
       <plugins>
         <plugin>

Modified: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/AbstractFileConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/AbstractFileConfiguration.java?rev=757482&r1=757481&r2=757482&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/AbstractFileConfiguration.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/AbstractFileConfiguration.java Mon Mar 23 18:17:32 2009
@@ -18,7 +18,6 @@
 package org.apache.commons.configuration2;
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -27,10 +26,7 @@
 import java.io.Reader;
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
 import java.net.URL;
-import java.net.URLConnection;
 import java.util.Iterator;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -81,7 +77,9 @@
  * @version $Revision$, $Date$
  * @since 1.0-rc2
  */
-public abstract class AbstractFileConfiguration extends BaseConfiguration implements FileConfiguration
+public abstract class AbstractFileConfiguration
+extends BaseConfiguration
+implements FileConfiguration, FileSystemBased
 {
     /** Constant for the configuration reload event.*/
     public static final int EVENT_RELOAD = 20;
@@ -110,6 +108,9 @@
     /** A counter that prohibits reloading.*/
     private int noReload;
 
+    /** The FileSystem being used for this Configuration */
+    private FileSystem fileSystem = FileSystem.getDefaultFileSystem();
+
     /**
      * Default constructor
      *
@@ -181,6 +182,26 @@
         load();
     }
 
+    public void setFileSystem(FileSystem fileSystem)
+    {
+        if (fileSystem == null)
+        {
+            throw new NullPointerException("A valid FileSystem must be specified");
+        }
+        this.fileSystem = fileSystem;
+    }
+
+    public void resetFileSystem()
+    {
+        this.fileSystem = FileSystem.getDefaultFileSystem();
+    }
+
+    public FileSystem getFileSystem()
+    {
+        return this.fileSystem;
+    }
+
+
     /**
      * Load the configuration from the underlying location.
      *
@@ -210,7 +231,7 @@
     {
         try
         {
-            URL url = ConfigurationUtils.locate(basePath, fileName);
+            URL url = ConfigurationUtils.locate(this.fileSystem, basePath, fileName);
 
             if (url == null)
             {
@@ -272,18 +293,11 @@
             sourceURL = url;
         }
 
-        // throw an exception if the target URL is a directory
-        File file = ConfigurationUtils.fileFromURL(url);
-        if (file != null && file.isDirectory())
-        {
-            throw new ConfigurationException("Cannot load a configuration from a directory");
-        }
-
         InputStream in = null;
 
         try
         {
-            in = url.openStream();
+            in = fileSystem.getInputStream(url);
             load(in);
         }
         catch (ConfigurationException e)
@@ -395,12 +409,19 @@
     {
         try
         {
-            File file = ConfigurationUtils.getFile(basePath, fileName);
+            URL url = this.fileSystem.getURL(basePath, fileName);
+
+            if (url == null)
+            {
+                throw new ConfigurationException("Invalid file name for save: " + fileName);
+            }
+            save(url);
+            /*File file = ConfigurationUtils.getFile(basePath, fileName);
             if (file == null)
             {
                 throw new ConfigurationException("Invalid file name for save: " + fileName);
             }
-            save(file);
+            save(file); */
         }
         catch (ConfigurationException e)
         {
@@ -423,51 +444,24 @@
      */
     public void save(URL url) throws ConfigurationException
     {
-        // file URLs have to be converted to Files since FileURLConnection is
-        // read only (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4191800)
-        File file = ConfigurationUtils.fileFromURL(url);
-        if (file != null)
-        {
-            save(file);
-        }
-        else
+        OutputStream out = null;
+        try
         {
-            // for non file URLs save through an URLConnection
-            OutputStream out = null;
-            try
-            {
-                URLConnection connection = url.openConnection();
-                connection.setDoOutput(true);
-
-                // use the PUT method for http URLs
-                if (connection instanceof HttpURLConnection)
-                {
-                    HttpURLConnection conn = (HttpURLConnection) connection;
-                    conn.setRequestMethod("PUT");
-                }
-
-                out = connection.getOutputStream();
-                save(out);
-
-                // check the response code for http URLs and throw an exception if an error occured
-                if (connection instanceof HttpURLConnection)
-                {
-                    HttpURLConnection conn = (HttpURLConnection) connection;
-                    if (conn.getResponseCode() >= HttpURLConnection.HTTP_BAD_REQUEST)
-                    {
-                        throw new IOException("HTTP Error " + conn.getResponseCode() + " " + conn.getResponseMessage());
-                    }
-                }
-            }
-            catch (IOException e)
-            {
-                throw new ConfigurationException("Could not save to URL " + url, e);
-            }
-            finally
+            out = fileSystem.getOutputStream(url);
+            save(out);
+            if (out instanceof VerifiableOutputStream)
             {
-                closeSilent(out);
+                ((VerifiableOutputStream) out).verify();
             }
         }
+        catch (IOException e)
+        {
+            throw new ConfigurationException("Could not save to URL " + url, e);
+        }
+        finally
+        {
+            closeSilent(out);
+        }
     }
 
     /**
@@ -485,15 +479,9 @@
 
         try
         {
-            // create the file if necessary
-            createPath(file);
-            out = new FileOutputStream(file);
+            out = fileSystem.getOutputStream(file);
             save(out);
         }
-        catch (IOException e)
-        {
-            throw new ConfigurationException(e.getMessage(), e);
-        }
         finally
         {
             closeSilent(out);
@@ -654,36 +642,7 @@
      */
     public String getPath()
     {
-        String path = null;
-        File file = getFile();
-        // if resource was loaded from jar file may be null
-        if (file != null)
-        {
-            path = file.getAbsolutePath();
-        }
-
-        // try to see if file was loaded from a jar
-        if (path == null)
-        {
-            if (sourceURL != null)
-            {
-                path = sourceURL.getPath();
-            }
-            else
-            {
-                try
-                {
-                    path = ConfigurationUtils.getURL(getBasePath(), getFileName()).getPath();
-                }
-                catch (MalformedURLException e)
-                {
-                    // simply ignore it and return null
-                    ;
-                }
-            }
-        }
-
-        return path;
+        return fileSystem.getPath(getFile(), sourceURL, getBasePath(), getFileName());
     }
 
     /**
@@ -701,6 +660,11 @@
         setFile(new File(path));
     }
 
+    URL getSourceURL()
+    {
+        return sourceURL;
+    }
+
     /**
      * Return the URL where the configuration is stored.
      *
@@ -709,7 +673,7 @@
     public URL getURL()
     {
         return (sourceURL != null) ? sourceURL
-                : ConfigurationUtils.locate(getBasePath(), getFileName());
+                : ConfigurationUtils.locate(this.fileSystem, getBasePath(), getFileName());
     }
 
     /**
@@ -942,24 +906,6 @@
         return super.getKeys();
     }
 
-    /**
-     * Create the path to the specified file.
-     *
-     * @param file the target file
-     */
-    private void createPath(File file)
-    {
-        if (file != null && !file.exists())
-        {
-            // create the path to the file if the file doesn't exist
-            File parent = file.getParentFile();
-            if (parent != null && !parent.exists())
-            {
-                parent.mkdirs();
-            }
-        }
-    }
-
     public String getEncoding()
     {
         return encoding;
@@ -1005,7 +951,7 @@
      * @param out the output stream to be closed (may be <b>null</b>)
      * @since 1.5
      */
-    private void closeSilent(OutputStream out)
+    protected void closeSilent(OutputStream out)
     {
         try
         {

Modified: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/AbstractHierarchicalFileConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/AbstractHierarchicalFileConfiguration.java?rev=757482&r1=757481&r2=757482&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/AbstractHierarchicalFileConfiguration.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/AbstractHierarchicalFileConfiguration.java Mon Mar 23 18:17:32 2009
@@ -315,6 +315,13 @@
     }
 
     @Override
+    public Iterator getKeys()
+    {
+        reload();
+        return super.getKeys();
+    }
+
+    @Override
     public Iterator<String> getKeys(String prefix)
     {
         reload();
@@ -444,6 +451,32 @@
     }
 
     /**
+     * Set the FileSystem to be used for this Configuration.
+     * @param fileSystem The FileSystem to use.
+     */
+    public void setFileSystem(FileSystem fileSystem)
+    {
+        delegate.setFileSystem(fileSystem);
+    }
+
+    /**
+     * Reset the FileSystem to the default;
+     */
+    public void resetFileSystem()
+    {
+        delegate.resetFileSystem();
+    }
+
+    /**
+     * Retrieve the FileSystem being used.
+     * @return The FileSystem.
+     */
+    public FileSystem getFileSystem()
+    {
+        return delegate.getFileSystem();
+    }
+
+    /**
      * A special implementation of the <code>FileConfiguration</code> interface that is
      * used internally to implement the <code>FileConfiguration</code> methods
      * for hierarchical configurations.

Modified: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/ConfigurationUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/ConfigurationUtils.java?rev=757482&r1=757481&r2=757482&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/ConfigurationUtils.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/ConfigurationUtils.java Mon Mar 23 18:17:32 2009
@@ -18,8 +18,6 @@
 package org.apache.commons.configuration2;
 
 import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
 import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -288,28 +286,7 @@
      */
     public static URL getURL(String basePath, String file) throws MalformedURLException
     {
-        File f = new File(file);
-        if (f.isAbsolute()) // already absolute?
-        {
-            return f.toURI().toURL();
-        }
-
-        try
-        {
-            if (basePath == null)
-            {
-                return new URL(file);
-            }
-            else
-            {
-                URL base = new URL(basePath);
-                return new URL(base, file);
-            }
-        }
-        catch (MalformedURLException uex)
-        {
-            return constructFile(basePath, file).toURI().toURL();
-        }
+        return FileSystem.getDefaultFileSystem().getURL(basePath, file);
     }
 
     /**
@@ -323,7 +300,7 @@
      */
     static File constructFile(String basePath, String fileName)
     {
-        File file = null;
+        File file;
 
         File absolute = null;
         if (fileName != null)
@@ -391,6 +368,21 @@
      */
     public static URL locate(String base, String name)
     {
+        return locate(FileSystem.getDefaultFileSystem(), base, name);
+    }
+
+    /**
+     * Return the location of the specified resource by searching the user home
+     * directory, the current classpath and the system classpath.
+     *
+     * @param fileSystem the FileSystem to use.
+     * @param base the base path of the resource
+     * @param name the name of the resource
+     *
+     * @return the location of the resource
+     */
+    public static URL locate(FileSystem fileSystem, String base, String name)
+    {
         if (log.isLoggable(Level.FINE))
         {
             StringBuilder buf = new StringBuilder();
@@ -405,41 +397,9 @@
             return null;
         }
 
-        URL url = null;
-
         // attempt to create an URL directly
-        try
-        {
-            if (base == null)
-            {
-                url = new URL(name);
-            }
-            else
-            {
-                URL baseURL = new URL(base);
-                url = new URL(baseURL, name);
 
-                // check if the file exists
-                InputStream in = null;
-                try
-                {
-                    in = url.openStream();
-                }
-                finally
-                {
-                    if (in != null)
-                    {
-                        in.close();
-                    }
-                }
-            }
-
-            log.fine("Loading configuration from the URL " + url);
-        }
-        catch (IOException e)
-        {
-            url = null;
-        }
+        URL url = fileSystem.locateFromURL(base, name);
 
         // attempt to load from an absolute path
         if (url == null)

Modified: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DefaultConfigurationBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DefaultConfigurationBuilder.java?rev=757482&r1=757481&r2=757482&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DefaultConfigurationBuilder.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DefaultConfigurationBuilder.java Mon Mar 23 18:17:32 2009
@@ -499,6 +499,17 @@
     }
 
     /**
+     * Sets the FileSystem to use for the created CombinedConfiguration
+     * @param fileSystem The FileSystem to use.
+     */
+    public void setFileSystem(FileSystem fileSystem)
+    {
+        FileSystem.setDefaultFileSystem(fileSystem);
+    }
+
+
+
+    /**
      * Adds a configuration provider for the specified tag. Whenever this tag is
      * encountered in the configuration definition file this provider will be
      * called to create the configuration object.

Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DefaultFileSystem.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DefaultFileSystem.java?rev=757482&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DefaultFileSystem.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DefaultFileSystem.java Mon Mar 23 18:17:32 2009
@@ -0,0 +1,281 @@
+/*
+ * 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;
+
+import java.io.InputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+
+/**
+ * FileSystem that uses java.io.File or HttpClient
+ * @since 1.7
+ * @author <a
+ * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
+ */
+public class DefaultFileSystem extends FileSystem
+{
+    public InputStream getInputStream(String basePath, String fileName)
+        throws ConfigurationException
+    {
+        try
+        {
+            URL url = ConfigurationUtils.locate(this, basePath, fileName);
+
+            if (url == null)
+            {
+                throw new ConfigurationException("Cannot locate configuration source " + fileName);
+            }
+            return getInputStream(url);
+        }
+        catch (ConfigurationException e)
+        {
+            throw e;
+        }
+        catch (Exception e)
+        {
+            throw new ConfigurationException("Unable to load the configuration file " + fileName, e);
+        }
+    }
+
+    public InputStream getInputStream(URL url) throws ConfigurationException
+    {
+        // throw an exception if the target URL is a directory
+        File file = ConfigurationUtils.fileFromURL(url);
+        if (file != null && file.isDirectory())
+        {
+            throw new ConfigurationException("Cannot load a configuration from a directory");
+        }
+
+        try
+        {
+            return url.openStream();
+        }
+        catch (Exception e)
+        {
+            throw new ConfigurationException("Unable to load the configuration from the URL " + url, e);
+        }
+    }
+
+    public OutputStream getOutputStream(URL url) throws ConfigurationException
+    {
+        // file URLs have to be converted to Files since FileURLConnection is
+        // read only (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4191800)
+        File file = ConfigurationUtils.fileFromURL(url);
+        if (file != null)
+        {
+            return getOutputStream(file);
+        }
+        else
+        {
+            // for non file URLs save through an URLConnection
+            OutputStream out;
+            try
+            {
+                URLConnection connection = url.openConnection();
+                connection.setDoOutput(true);
+
+                // use the PUT method for http URLs
+                if (connection instanceof HttpURLConnection)
+                {
+                    HttpURLConnection conn = (HttpURLConnection) connection;
+                    conn.setRequestMethod("PUT");
+                }
+
+                out = connection.getOutputStream();
+
+                // check the response code for http URLs and throw an exception if an error occured
+                if (connection instanceof HttpURLConnection)
+                {
+                    out = new HttpOutputStream(out, (HttpURLConnection) connection);
+                }
+                return out;
+            }
+            catch (IOException e)
+            {
+                throw new ConfigurationException("Could not save to URL " + url, e);
+            }
+        }
+    }
+
+    public OutputStream getOutputStream(File file) throws ConfigurationException
+    {
+        try
+        {
+            // create the file if necessary
+            createPath(file);
+            return new FileOutputStream(file);
+        }
+        catch (FileNotFoundException e)
+        {
+            throw new ConfigurationException("Unable to save to file " + file, e);
+        }
+    }
+
+    public String getPath(File file, URL url, String basePath, String fileName)
+    {
+        String path = null;
+        // if resource was loaded from jar file may be null
+        if (file != null)
+        {
+            path = file.getAbsolutePath();
+        }
+
+        // try to see if file was loaded from a jar
+        if (path == null)
+        {
+            if (url != null)
+            {
+                path = url.getPath();
+            }
+            else
+            {
+                try
+                {
+                    path = getURL(basePath, fileName).getPath();
+                }
+                catch (Exception e)
+                {
+                    // simply ignore it and return null
+                    return null;
+                }
+            }
+        }
+
+        return path;
+    }
+
+    public String getBasePath(String path)
+    {
+        URL url;
+        try
+        {
+            url = getURL(null, path);
+            return ConfigurationUtils.getBasePath(url);
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    public String getFileName(String path)
+    {
+        URL url;
+        try
+        {
+            url = getURL(null, path);
+            return ConfigurationUtils.getFileName(url);
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+
+    public URL getURL(String basePath, String file) throws MalformedURLException
+    {
+        File f = new File(file);
+        if (f.isAbsolute()) // already absolute?
+        {
+            return f.toURI().toURL();
+        }
+
+        try
+        {
+            if (basePath == null)
+            {
+                return new URL(file);
+            }
+            else
+            {
+                URL base = new URL(basePath);
+                return new URL(base, file);
+            }
+        }
+        catch (MalformedURLException uex)
+        {
+            return ConfigurationUtils.constructFile(basePath, file).toURI().toURL();
+        }
+    }
+
+
+    public URL locateFromURL(String basePath, String fileName)
+    {
+        try
+        {
+            URL url;
+            if (basePath == null)
+            {
+                return new URL(fileName);
+                //url = new URL(name);
+            }
+            else
+            {
+                URL baseURL = new URL(basePath);
+                url = new URL(baseURL, fileName);
+
+                // check if the file exists
+                InputStream in = null;
+                try
+                {
+                    in = url.openStream();
+                }
+                finally
+                {
+                    if (in != null)
+                    {
+                        in.close();
+                    }
+                }
+                return url;
+            }
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
+    }
+
+    /**
+     * Create the path to the specified file.
+     *
+     * @param file the target file
+     */
+    private void createPath(File file)
+    {
+        if (file != null)
+        {
+            // create the path to the file if the file doesn't exist
+            if (!file.exists())
+            {
+                File parent = file.getParentFile();
+                if (parent != null && !parent.exists())
+                {
+                    parent.mkdirs();
+                }
+            }
+        }
+    }
+}

Modified: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DynamicCombinedConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DynamicCombinedConfiguration.java?rev=757482&r1=757481&r2=757482&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DynamicCombinedConfiguration.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/DynamicCombinedConfiguration.java Mon Mar 23 18:17:32 2009
@@ -239,7 +239,7 @@
     {
         for (int index = 0; index < getNumberOfConfigurations(); index++)
         {
-            if (( configurations.get(index)).getConfiguration() == config)
+            if ((configurations.get(index)).getConfiguration() == config)
             {
                 removeConfigurationAt(index);
 

Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileOptionsProvider.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileOptionsProvider.java?rev=757482&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileOptionsProvider.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileOptionsProvider.java Mon Mar 23 18:17:32 2009
@@ -0,0 +1,74 @@
+/*
+ * 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;
+
+import java.util.Map;
+
+/**
+ * Some FileSystems allow options to be passed on File operations. Users of commons
+ * configuration can implement this interface and register it with the FileSystem.
+ * @since 1.7
+ * @author <a
+ * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
+ */
+public interface FileOptionsProvider
+{
+    /**
+     * Key used to identify the user to be associated with the current file operations.
+     * The value associated with this key is a String identifying the current user.
+     */
+    String CURRENT_USER = "currentUser";
+
+    /**
+     * Key used to indicate whether Webdav versioning support should be enabled.
+     * The value associated with this key is a Boolean where True indicates versioning should
+     * be enabled.
+     */
+    String VERSIONING = "versioning";
+
+    /**
+     * Key used to identify the proxy host to connect through.
+     * The value associated with this key is a String identifying the host name of the proxy.
+     */
+    String PROXY_HOST = "proxyHost";
+
+    /**
+     * Key used to identify the proxy port to connect through.
+     * The value associated with this key is an Integer identifying the port on the proxy.
+     */
+    String PROXY_PORT = "proxyPort";
+
+    /**
+     * Key used to identify the maximum number of connections allowed to a single host.
+     * The value associated with this key is an Integer identifying the maximum number of
+     * connections allowed to a single host.
+     */
+    String MAX_HOST_CONNECTIONS = "maxHostConnections";
+
+    /**
+     * Key used to identify the maximum number of connections allowed to all hosts.
+     * The value associated with this key is an Integer identifying the maximum number of
+     * connections allowed to all hosts.
+     */
+    String MAX_TOTAL_CONNECTIONS = "maxTotalConnections";
+
+    /**
+     *
+     * @return Options to be used for this file.
+     */
+    Map<String, Object> getOptions();
+}

Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileSystem.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileSystem.java?rev=757482&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileSystem.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileSystem.java Mon Mar 23 18:17:32 2009
@@ -0,0 +1,177 @@
+/*
+ * 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;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.impl.NoOpLog;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.File;
+import java.net.URL;
+import java.net.MalformedURLException;
+
+/**
+ * Abstract layer to allow various types of file systems.
+ * @since 1.7
+ * @author <a
+ * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
+ */
+public abstract class FileSystem
+{
+    /** The name of the system property that can be used to set the file system class name */
+    private static final String FILE_SYSTEM = "org.apache.commons.configuration.filesystem";
+
+    /** The default file system */
+    private static FileSystem fileSystem;
+
+    /** The Logger */
+    private Log log;
+
+    /** FileSystem options provider */
+    private FileOptionsProvider optionsProvider;
+
+    public FileSystem()
+    {
+        setLogger(null);
+    }
+
+    /**
+     * Returns the logger used by this FileSystem.
+     *
+     * @return the logger
+     */
+    public Log getLogger()
+    {
+        return log;
+    }
+
+    /**
+     * Allows to set the logger to be used by this FileSystem. This
+     * method makes it possible for clients to exactly control logging behavior.
+     * Per default a logger is set that will ignore all log messages. Derived
+     * classes that want to enable logging should call this method during their
+     * initialization with the logger to be used.
+     *
+     * @param log the new logger
+     */
+    public void setLogger(Log log)
+    {
+        this.log = (log != null) ? log : new NoOpLog();
+    }
+
+    static
+    {
+        String fsClassName = System.getProperty(FILE_SYSTEM);
+        if (fsClassName != null)
+        {
+            Log log = LogFactory.getLog(FileSystem.class);
+
+            try
+            {
+                Class clazz = Class.forName(fsClassName);
+                if (FileSystem.class.isAssignableFrom(clazz))
+                {
+                    fileSystem = (FileSystem) clazz.newInstance();
+                    System.out.println("Using " + fsClassName);
+                }
+            }
+            catch (InstantiationException ex)
+            {
+                log.error("Unable to create " + fsClassName, ex);
+            }
+            catch (IllegalAccessException ex)
+            {
+                log.error("Unable to create " + fsClassName, ex);
+            }
+            catch (ClassNotFoundException ex)
+            {
+                log.error("Unable to create " + fsClassName, ex);
+            }
+        }
+
+        if (fileSystem == null)
+        {
+            fileSystem = new DefaultFileSystem();
+        }
+    }
+
+    /**
+     * Set the FileSystem to use.
+     * @param fs The FileSystem
+     * @throws NullPointerException if fs is null.
+     */
+    public static void setDefaultFileSystem(FileSystem fs) throws NullPointerException
+    {
+        if (fs == null)
+        {
+            throw new NullPointerException("A FileSystem implementation is required");
+        }
+        fileSystem = fs;
+    }
+
+    /**
+     * Reset the FileSystem to the default.
+     */
+    public static void resetDefaultFileSystem()
+    {
+        fileSystem = new DefaultFileSystem();
+    }
+
+    /**
+     * Retrieve the FileSystem being used.
+     * @return The FileSystem.
+     */
+    public static FileSystem getDefaultFileSystem()
+    {
+        return fileSystem;
+    }
+
+    /**
+     * Set the FileOptionsProvider
+     * @param provider The FileOptionsProvider
+     */
+    public void setFileOptionsProvider(FileOptionsProvider provider)
+    {
+        this.optionsProvider = provider;
+    }
+
+    public FileOptionsProvider getFileOptionsProvider()
+    {
+        return this.optionsProvider;
+    }
+
+    public abstract InputStream getInputStream(String basePath, String fileName)
+            throws ConfigurationException;
+
+    public abstract InputStream getInputStream(URL url) throws ConfigurationException;
+
+    public abstract OutputStream getOutputStream(URL url) throws ConfigurationException;
+
+    public abstract OutputStream getOutputStream(File file) throws ConfigurationException;
+
+    public abstract String getPath(File file, URL url, String basePath, String fileName);
+
+    public abstract String getBasePath(String path);
+
+    public abstract String getFileName(String path);
+
+    public abstract URL locateFromURL(String basePath, String fileName);
+
+    public abstract URL getURL(String basePath, String fileName) throws MalformedURLException;
+}

Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileSystemBased.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileSystemBased.java?rev=757482&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileSystemBased.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/FileSystemBased.java Mon Mar 23 18:17:32 2009
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+/**
+ * @since 1.7
+ * @author <a
+ * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
+ */
+public interface FileSystemBased
+{
+    void setFileSystem(FileSystem fileSystem);
+
+    void resetFileSystem();
+
+    FileSystem getFileSystem();
+}

Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/HttpOutputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/HttpOutputStream.java?rev=757482&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/HttpOutputStream.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/HttpOutputStream.java Mon Mar 23 18:17:32 2009
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+
+/**
+ * Wraps the output stream so errors can be detected in the HTTP response.
+ * @since 1.7
+ * @author <a
+ * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
+ */
+public class HttpOutputStream extends VerifiableOutputStream
+{
+    /** The wrapped OutputStream */
+    private final OutputStream stream;
+
+    /** The HttpURLConnection */
+    private final HttpURLConnection connection;
+
+    public HttpOutputStream(OutputStream stream, HttpURLConnection connection)
+    {
+        this.stream = stream;
+        this.connection = connection;
+    }
+
+    public void write(byte[] bytes) throws IOException
+    {
+        stream.write(bytes);
+    }
+
+    public void write(byte[] bytes, int i, int i1) throws IOException
+    {
+        stream.write(bytes, i, i1);
+    }
+
+    public void flush() throws IOException
+    {
+        stream.flush();
+    }
+
+    public void close() throws IOException
+    {
+        stream.close();
+    }
+
+    public void write(int i) throws IOException
+    {
+        stream.write(i);
+    }
+
+    public String toString()
+    {
+        return stream.toString();
+    }
+
+    public void verify() throws IOException
+    {
+        if (connection.getResponseCode() >= HttpURLConnection.HTTP_BAD_REQUEST)
+        {
+            throw new IOException("HTTP Error " + connection.getResponseCode()
+                    + " " + connection.getResponseMessage());
+        }
+    }
+}

Modified: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/MultiFileHierarchicalConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/MultiFileHierarchicalConfiguration.java?rev=757482&r1=757481&r2=757482&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/MultiFileHierarchicalConfiguration.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/MultiFileHierarchicalConfiguration.java Mon Mar 23 18:17:32 2009
@@ -25,8 +25,6 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.net.URL;
-import java.net.MalformedURLException;
-import java.io.FileNotFoundException;
 import java.io.Writer;
 import java.io.Reader;
 import java.io.File;
@@ -55,9 +53,6 @@
 public class MultiFileHierarchicalConfiguration extends AbstractHierarchicalFileConfiguration
     implements ConfigurationListener, ConfigurationErrorListener
 {
-    /** FILE URL prefix */
-    private static final String FILE_URL_PREFIX = "file:";
-
     /**
      * Prevent recursion while resolving unprefixed properties.
      */
@@ -121,20 +116,6 @@
         this.ignoreException = ignoreException;
     }
 
-    /**
-     * Creates the file configuration delegate, i.e. the object that implements
-     * functionality required by the <code>FileConfiguration</code> interface.
-     * This base implementation will return an instance of the
-     * <code>FileConfigurationDelegate</code> class. Derived classes may
-     * override it to create a different delegate object.
-     *
-     * @return the file configuration delegate
-     */
-    protected FileConfigurationDelegate createDelegate()
-    {
-        return new FileConfigurationDelegate();
-    }
-
     public void addProperty(String key, Object value)
     {
         this.getConfiguration().addProperty(key, value);
@@ -658,13 +639,15 @@
         XMLConfiguration configuration = new XMLConfiguration();
         try
         {
-            URL url = getURL(path);
-            configuration.setURL(url);
-            configuration.load();
+            configuration.setFileName(path);
             configuration.setExpressionEngine(getExpressionEngine());
             configuration.setReloadingStrategy(getReloadingStrategy());
+            configuration.setDelimiterParsingDisabled(isDelimiterParsingDisabled());
+            configuration.setDetailEvents(this.isDetailEvents());
+            configuration.setListDelimiter(getListDelimiter());
             configuration.addConfigurationListener(this);
             configuration.addErrorListener(this);
+            configuration.load();
             configurationsMap.putIfAbsent(path, configuration);
             configuration = configurationsMap.get(path);
         }
@@ -675,40 +658,7 @@
                 throw new ConfigurationRuntimeException(ce);
             }
         }
-        catch (FileNotFoundException fnfe)
-        {
-            if (!ignoreException)
-            {
-                 throw new ConfigurationRuntimeException(fnfe);
-            }                
-        }
 
         return configuration;
     }
-
-    private URL getURL(String resourceLocation) throws FileNotFoundException
-    {
-        if (resourceLocation == null)
-        {
-            throw new IllegalArgumentException("A path pattern must be configured");
-        }
-        try
-        {
-            // try URL
-            return ConfigurationUtils.getURL(getBasePath(), resourceLocation);
-        }
-        catch (MalformedURLException ex)
-        {
-            // no URL -> treat as file path
-            try
-            {
-                return new URL(FILE_URL_PREFIX + resourceLocation);
-            }
-            catch (MalformedURLException ex2)
-            {
-                throw new FileNotFoundException("Resource location [" + resourceLocation
-                        + "] is not a URL or a well-formed file path");
-            }
-        }
-    }
 }

Modified: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/PropertiesConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/PropertiesConfiguration.java?rev=757482&r1=757481&r2=757482&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/PropertiesConfiguration.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/PropertiesConfiguration.java Mon Mar 23 18:17:32 2009
@@ -1247,13 +1247,13 @@
      */
     private void loadIncludeFile(String fileName) throws ConfigurationException
     {
-        URL url = ConfigurationUtils.locate(getBasePath(), fileName);
+        URL url = ConfigurationUtils.locate(getFileSystem(), getBasePath(), fileName);
         if (url == null)
         {
             URL baseURL = getURL();
             if (baseURL != null)
             {
-                url = ConfigurationUtils.locate(baseURL.toString(), fileName);
+                url = ConfigurationUtils.locate(getFileSystem(), baseURL.toString(), fileName);
             }
         }
 

Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VFSFileSystem.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VFSFileSystem.java?rev=757482&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VFSFileSystem.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VFSFileSystem.java Mon Mar 23 18:17:32 2009
@@ -0,0 +1,393 @@
+/*
+ * 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;
+
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileName;
+import org.apache.commons.vfs.VFS;
+import org.apache.commons.vfs.FileSystemManager;
+import org.apache.commons.vfs.FileContent;
+import org.apache.commons.vfs.FileSystemException;
+import org.apache.commons.vfs.FileType;
+import org.apache.commons.vfs.FileSystemOptions;
+import org.apache.commons.vfs.provider.UriParser;
+import org.apache.commons.vfs.provider.http.HttpFileSystemConfigBuilder;
+import org.apache.commons.vfs.provider.webdav.WebdavFileSystemConfigBuilder;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.File;
+import java.net.URL;
+import java.net.URLStreamHandler;
+import java.net.MalformedURLException;
+import java.util.Map;
+
+/**
+ * FileSystem that uses Commons VFS
+ * @since 1.7
+ * @author <a
+ * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
+ */
+public class VFSFileSystem extends DefaultFileSystem
+{
+    /** The builder for Webdav options */
+    private final WebdavFileSystemConfigBuilder webdavBuilder;
+
+    /** The builder for Http optiosn */
+    private final HttpFileSystemConfigBuilder httpBuilder;
+
+    public VFSFileSystem()
+    {
+        WebdavFileSystemConfigBuilder wb = null;
+        try
+        {
+            FileSystemManager manager = VFS.getManager();
+            if (manager.hasProvider("webdav"))
+            {
+                wb = (WebdavFileSystemConfigBuilder) manager.getFileSystemConfigBuilder("webdav");
+            }
+        }
+        catch (FileSystemException e)
+        {
+            // Just ignore the error. Webdav won't have options.
+            wb = null;
+        }
+        webdavBuilder = wb;
+        HttpFileSystemConfigBuilder hb = null;
+        try
+        {
+            FileSystemManager manager = VFS.getManager();
+            if (manager.hasProvider("http"))
+            {
+                hb = (HttpFileSystemConfigBuilder) manager.getFileSystemConfigBuilder("http");
+            }
+        }
+        catch (FileSystemException e)
+        {
+            // Just ignore the error http won't have options.
+            hb = null;
+        }
+        httpBuilder = hb;
+    }
+
+    public InputStream getInputStream(String basePath, String fileName)
+        throws ConfigurationException
+    {
+        try
+        {
+            FileSystemManager manager = VFS.getManager();
+            FileName path;
+            if (basePath != null)
+            {
+                FileName base = manager.resolveURI(basePath);
+                path = manager.resolveName(base, fileName);
+            }
+            else
+            {
+                FileName file = manager.resolveURI(fileName);
+                FileName base = file.getParent();
+                path = manager.resolveName(base, file.getBaseName());
+            }
+            FileSystemOptions opts = getOptions(path.getScheme());
+            FileObject file = manager.resolveFile(path.getURI(), opts);
+            FileContent content = file.getContent();
+            if (content == null)
+            {
+                String msg = "Cannot access content of " + file.getName().getFriendlyURI();
+                throw new ConfigurationException(msg);
+            }
+            return content.getInputStream();
+        }
+        catch (ConfigurationException e)
+        {
+            throw e;
+        }
+        catch (Exception e)
+        {
+            throw new ConfigurationException("Unable to load the configuration file " + fileName, e);
+        }
+    }
+
+    public InputStream getInputStream(URL url) throws ConfigurationException
+    {
+        FileObject file;
+        try
+        {
+            FileSystemOptions opts = getOptions(url.getProtocol());
+            file = VFS.getManager().resolveFile(url.toString(), opts);
+            if (file.getType() != FileType.FILE)
+            {
+                throw new ConfigurationException("Cannot load a configuration from a directory");
+            }
+            FileContent content = file.getContent();
+            if (content == null)
+            {
+                String msg = "Cannot access content of " + file.getName().getFriendlyURI();
+                throw new ConfigurationException(msg);
+            }
+            return content.getInputStream();
+        }
+        catch (FileSystemException fse)
+        {
+            String msg = "Unable to access " + url.toString();
+            throw new ConfigurationException(msg, fse);
+        }
+    }
+
+    public OutputStream getOutputStream(URL url) throws ConfigurationException
+    {
+        try
+        {
+            FileSystemOptions opts = getOptions(url.getProtocol());
+            FileSystemManager fsManager = VFS.getManager();
+            FileObject file = fsManager.resolveFile(url.toString(), opts);
+            // throw an exception if the target URL is a directory
+            if (file == null || file.getType() == FileType.FOLDER)
+            {
+                throw new ConfigurationException("Cannot save a configuration to a directory");
+            }
+            FileContent content = file.getContent();
+
+            if (content == null)
+            {
+                throw new ConfigurationException("Cannot access content of " + url);
+            }
+            return content.getOutputStream();
+        }
+        catch (FileSystemException fse)
+        {
+            throw new ConfigurationException("Unable to access " + url, fse);
+        }
+    }
+
+    public String getPath(File file, URL url, String basePath, String fileName)
+    {
+        if (file != null)
+        {
+            return super.getPath(file, url, basePath, fileName);
+        }
+        try
+        {
+            FileSystemManager fsManager = VFS.getManager();
+            if (url != null)
+            {
+                FileName name = fsManager.resolveURI(url.toString());
+                if (name != null)
+                {
+                    return name.toString();
+                }
+            }
+
+            if (basePath != null)
+            {
+                FileName base = fsManager.resolveURI(basePath);
+                return fsManager.resolveName(base, fileName).getURI();
+            }
+            else
+            {
+                FileName name = fsManager.resolveURI(fileName);
+                FileName base = name.getParent();
+                return fsManager.resolveName(base, name.getBaseName()).getURI();
+            }
+        }
+        catch (FileSystemException fse)
+        {
+            fse.printStackTrace();
+            return null;
+        }
+    }
+
+    public String getBasePath(String path)
+    {
+        if (UriParser.extractScheme(path) == null)
+        {
+            return super.getBasePath(path);
+        }
+        try
+        {
+            FileSystemManager fsManager = VFS.getManager();
+            FileName name = fsManager.resolveURI(path);
+            return name.getParent().getURI();
+        }
+        catch (FileSystemException fse)
+        {
+            fse.printStackTrace();
+            return null;
+        }
+    }
+
+    public String getFileName(String path)
+    {
+        if (UriParser.extractScheme(path) == null)
+        {
+            return super.getFileName(path);
+        }
+        try
+        {
+            FileSystemManager fsManager = VFS.getManager();
+            FileName name = fsManager.resolveURI(path);
+            return name.getBaseName();
+        }
+        catch (FileSystemException fse)
+        {
+            fse.printStackTrace();
+            return null;
+        }
+    }
+
+    public URL getURL(String basePath, String file) throws MalformedURLException
+    {
+        if ((basePath != null && UriParser.extractScheme(basePath) == null)
+            || (basePath == null && UriParser.extractScheme(file) == null))
+        {
+            return super.getURL(basePath, file);
+        }
+        try
+        {
+            FileSystemManager fsManager = VFS.getManager();
+
+            FileName path;
+            if (basePath != null && UriParser.extractScheme(file) == null)
+            {
+                FileName base = fsManager.resolveURI(basePath);
+                path = fsManager.resolveName(base, file);
+            }
+            else
+            {
+                path = fsManager.resolveURI(file);
+            }
+
+            URLStreamHandler handler = new VFSURLStreamHandler(path);
+            return new URL(null, path.getURI(), handler);
+        }
+        catch (FileSystemException fse)
+        {
+            throw new ConfigurationRuntimeException("Could not parse basePath: " + basePath
+                + " and fileName: " + file, fse);
+        }
+    }
+
+    public URL locateFromURL(String basePath, String fileName)
+    {
+        if ((basePath != null && UriParser.extractScheme(basePath) == null)
+            || (basePath == null && UriParser.extractScheme(fileName) == null))
+        {
+            return super.locateFromURL(basePath, fileName);
+        }
+        try
+        {
+            FileSystemManager fsManager = VFS.getManager();
+
+            FileObject file;
+            if (basePath != null)
+            {
+                FileObject base = fsManager.resolveFile(basePath);
+                if (base.getType() == FileType.FILE)
+                {
+                    base = base.getParent();
+                }
+                file = fsManager.resolveFile(base, fileName);
+            }
+            else
+            {
+                file = fsManager.resolveFile(fileName);
+            }
+
+            if (!file.exists())
+            {
+                return null;
+            }
+            FileName path = file.getName();
+            URLStreamHandler handler = new VFSURLStreamHandler(path);
+            return new URL(null, path.getURI(), handler);
+        }
+        catch (FileSystemException fse)
+        {
+            return null;
+        }
+        catch (MalformedURLException ex)
+        {
+            return null;
+        }
+    }
+
+    private FileSystemOptions getOptions(String scheme)
+    {
+        FileSystemOptions opts = new FileSystemOptions();
+        FileOptionsProvider provider = getFileOptionsProvider();
+        if (provider != null)
+        {
+            Map<String, Object> map = provider.getOptions();
+            if (scheme.equals("webdav"))
+            {
+                return setWebdavOptions(opts, map);
+            }
+            if (scheme.equals("http"))
+            {
+                return setHttpOptions(opts, map);
+            }
+        }
+        return opts;
+    }
+
+    private FileSystemOptions setWebdavOptions(FileSystemOptions opts, Map<String, Object> map)
+    {
+        setHttpOptions(opts, map);
+        if (webdavBuilder == null || map == null)
+        {
+            return opts;
+        }
+        if (map.containsKey(FileOptionsProvider.VERSIONING))
+        {
+            boolean versioning = (Boolean) map.get(FileOptionsProvider.VERSIONING);
+            webdavBuilder.setVersioning(opts, versioning);
+        }
+        if (map.containsKey(FileOptionsProvider.CURRENT_USER))
+        {
+            webdavBuilder.setCreatorName(opts, (String) map.get(FileOptionsProvider.CURRENT_USER));
+        }
+        return opts;
+    }
+
+    private FileSystemOptions setHttpOptions(FileSystemOptions opts, Map<String, Object> map)
+    {
+        if (httpBuilder == null || map == null)
+        {
+            return opts;
+        }
+        if (map.containsKey(FileOptionsProvider.PROXY_PORT))
+        {
+            int port = (Integer) map.get(FileOptionsProvider.PROXY_PORT);
+            httpBuilder.setProxyPort(opts, port);
+        }
+        if (map.containsKey(FileOptionsProvider.PROXY_HOST))
+        {
+            httpBuilder.setProxyHost(opts, (String) map.get(FileOptionsProvider.PROXY_HOST));
+        }
+        if (map.containsKey(FileOptionsProvider.MAX_HOST_CONNECTIONS))
+        {
+            int max = (Integer) map.get(FileOptionsProvider.MAX_HOST_CONNECTIONS);
+            httpBuilder.setMaxConnectionsPerHost(opts, max);
+        }
+        if (map.containsKey(FileOptionsProvider.MAX_TOTAL_CONNECTIONS))
+        {
+            int max = (Integer) map.get(FileOptionsProvider.MAX_TOTAL_CONNECTIONS);
+            httpBuilder.setMaxTotalConnections(opts, max);
+        }
+        return opts;
+    }
+}

Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VFSURLStreamHandler.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VFSURLStreamHandler.java?rev=757482&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VFSURLStreamHandler.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VFSURLStreamHandler.java Mon Mar 23 18:17:32 2009
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import org.apache.commons.vfs.FileName;
+
+import java.net.URLStreamHandler;
+import java.net.URLConnection;
+import java.net.URL;
+import java.io.IOException;
+
+/**
+ * StreamHandler used only to all URLs to be created.
+ * @since 1.7
+ * @author <a
+ * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
+ */
+public class VFSURLStreamHandler extends URLStreamHandler
+{
+    /** The Protocol used */
+    private final String protocol;
+
+    public VFSURLStreamHandler(FileName file)
+    {
+        this.protocol = file.getScheme();
+    }
+
+    protected URLConnection openConnection(URL url) throws IOException
+    {
+        throw new IOException("VFS URLs can only be used with VFS APIs");
+    }
+}

Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VerifiableOutputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VerifiableOutputStream.java?rev=757482&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VerifiableOutputStream.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/VerifiableOutputStream.java Mon Mar 23 18:17:32 2009
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * OutputStream that can be checked for errors after it is written to.
+ * @since 1.7
+ * @author <a
+ * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
+ */
+public abstract class VerifiableOutputStream extends OutputStream
+{
+    public abstract void verify() throws IOException;
+}

Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/reloading/VFSFileMonitorReloadingStrategy.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/reloading/VFSFileMonitorReloadingStrategy.java?rev=757482&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/reloading/VFSFileMonitorReloadingStrategy.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/reloading/VFSFileMonitorReloadingStrategy.java Mon Mar 23 18:17:32 2009
@@ -0,0 +1,221 @@
+/*
+ * 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.ConfigurationRuntimeException;
+import org.apache.commons.configuration2.FileSystem;
+import org.apache.commons.configuration2.FileSystemBased;
+import org.apache.commons.vfs.impl.DefaultFileMonitor;
+import org.apache.commons.vfs.FileListener;
+import org.apache.commons.vfs.FileChangeEvent;
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.VFS;
+import org.apache.commons.vfs.FileSystemManager;
+import org.apache.commons.vfs.FileSystemException;
+
+import java.util.Map;
+import java.util.HashMap;
+
+
+/**
+ * <p>A reloading strategy that will reload the configuration every time its
+ * underlying file is changed.</p>
+ * @since 1.7
+ * @author <a
+ * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
+ */
+public class VFSFileMonitorReloadingStrategy implements ReloadingStrategy, FileListener
+{
+    /** Used to synchronize initialization of the monitor. */
+    private static final String INIT_GATE = "gate";
+
+    /** The FileMonitor */
+    private static DefaultFileMonitor fm;
+
+    /** The files being monitored */
+    private static Map<FileObject, VFSFileMonitorReloadingStrategy> strategies =
+            new HashMap<FileObject, VFSFileMonitorReloadingStrategy>();
+
+    /** Mimimum delay value */
+    private static final long DEFAULT_DELAY = 1000;
+
+    /** Stores a reference to the configuration to be monitored. */
+    protected FileConfiguration configuration;
+
+    /** The reload status */
+    private boolean reloadRequired;
+
+    /** Delay interval between checking the files. */
+    private long delay;
+
+    /**
+     * Return the current delay interval.
+     * @return The delay interval.
+     */
+    public long getDelay()
+    {
+        return fm.getDelay();
+    }
+
+    /**
+     * Request a new delay interval. If the interval specified is less than
+     * what the monitor is currently using the interval will be ignored. If
+     * this method is called after the strategy has started it will be ignored.
+     * @param delay The requested delay interval.
+     */
+    public void setDelay(long delay)
+    {
+        this.delay = delay;
+    }
+
+    /**
+     * Specify the configuration to monitor. The configuration must be set before
+     * init is called.
+     * @param configuration The configuration to monitor.
+     */
+    public void setConfiguration(FileConfiguration configuration)
+    {
+        if (configuration instanceof FileSystemBased)
+        {
+            this.configuration = configuration;
+        }
+        else
+        {
+            throw new ConfigurationRuntimeException("Configuration must be based on a FileSystem");
+        }
+    }
+
+    /**
+     * Initialize the ReloadingStrategy.
+     */
+    public void init()
+    {
+        if (this.configuration == null)
+        {
+            throw new IllegalStateException("No configuration has been set for this strategy");
+        }
+        synchronized (INIT_GATE)
+        {
+            if (fm == null)
+            {
+                fm = new DefaultFileMonitor(null);
+                long delayTime = (delay > DEFAULT_DELAY) ? delay : DEFAULT_DELAY;
+                fm.setDelay(delayTime);
+                fm.start();
+            }
+            else
+            {
+                long delayTime = fm.getDelay();
+                if (delay > delayTime)
+                {
+                    fm.setDelay(delay);
+                }
+            }
+        }
+
+        try
+        {
+            FileSystemManager fsManager = VFS.getManager();
+            FileSystem fs = ((FileSystemBased) configuration).getFileSystem();
+            String uri = fs.getPath(null, configuration.getURL(), configuration.getBasePath(),
+                configuration.getFileName());
+            FileObject file = fsManager.resolveFile(uri);
+            file.getFileSystem().addListener(file, this);
+            fm.addFile(file);
+            strategies.put(file, this);
+        }
+        catch (FileSystemException fse)
+        {
+            String msg = "Unable to monitor " + configuration.getURL().toString();
+            throw new ConfigurationRuntimeException(msg, fse);
+        }
+
+    }
+
+    /**
+     * Shutdown the reloading strategy
+     */
+    public void stopMonitor()
+    {
+        synchronized (INIT_GATE)
+        {
+            if (fm != null)
+            {
+                fm.stop();
+                fm = null;
+            }
+
+            for (Map.Entry<FileObject, VFSFileMonitorReloadingStrategy> entry : strategies.entrySet())
+            {
+                FileObject file = entry.getKey();
+                file.getFileSystem().removeListener(file, entry.getValue());
+            }
+            strategies.clear();
+        }
+    }
+
+    /**
+     * Tell if the evaluation of the strategy requires to reload the configuration.
+     *
+     * @return a flag whether a reload should be performed
+     */
+    public boolean reloadingRequired()
+    {
+        return reloadRequired;
+    }
+
+    /**
+     * Notify the strategy that the file has been reloaded.
+     */
+    public void reloadingPerformed()
+    {
+        reloadRequired = false;
+    }
+
+
+    /**
+     * Called when a file is created.
+     * @param event The event.
+     * @throws Exception If an error occurs.
+     */
+    public void fileCreated(FileChangeEvent event) throws Exception
+    {
+        reloadRequired = true;
+    }
+
+    /**
+     * Called when a file is deleted.
+     * @param event The event.
+     * @throws Exception If an error occurs.
+     */
+    public void fileDeleted(FileChangeEvent event) throws Exception
+    {
+        // Ignore this event
+    }
+
+    /**
+     * Called when a file is changed.
+     * @param event The event.
+     * @throws Exception If an exception occurs.
+     */
+    public void fileChanged(FileChangeEvent event) throws Exception
+    {
+        reloadRequired = true;
+    }
+
+}

Modified: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDefaultConfigurationBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDefaultConfigurationBuilder.java?rev=757482&r1=757481&r2=757482&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDefaultConfigurationBuilder.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDefaultConfigurationBuilder.java Mon Mar 23 18:17:32 2009
@@ -23,12 +23,15 @@
 import java.util.Set;
 import java.util.Map;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Iterator;
 
 import junit.framework.TestCase;
 
 import org.apache.commons.configuration2.beanutils.BeanHelper;
 import org.apache.commons.configuration2.reloading.FileChangedReloadingStrategy;
 import org.apache.commons.configuration2.tree.DefaultConfigurationNode;
+import org.apache.commons.configuration2.tree.ConfigurationNode;
 import org.apache.commons.configuration2.tree.xpath.XPathExpressionEngine;
 import org.apache.commons.lang.text.StrLookup;
 
@@ -877,6 +880,60 @@
         verify("1005", config, 50);
     }
 
+    /** This test doesn't pass and rightfully so. A new "MergeCombiner" needs to be
+     * created so it will.
+     * @throws Exception
+     */  /*
+    public void testMultiTenantConfigurationAt() throws Exception
+    {
+        factory.setFile(MULTI_TENENT_FILE);
+        System.setProperty("Id", "1001");
+        CombinedConfiguration config = factory.getConfiguration(true);
+        HierarchicalConfiguration sub1 = config.configurationAt("Channels/Channel[@id='1']");
+        assertEquals("My Channel", sub1.getString("Name"));
+        assertEquals("test 1 data", sub1.getString("ChannelData"));
+        HierarchicalConfiguration sub2 = config.configurationAt("Channels/Channel[@id='2']");
+        assertEquals("Channel 2", sub2.getString("Name"));
+        assertEquals("more test 2 data", sub2.getString("MoreChannelData"));
+    } */
+
+    public void testMerge() throws Exception
+    {
+        factory.setFile(MULTI_TENENT_FILE);
+        System.setProperty("Id", "1004");
+
+        CombinedConfiguration config = factory.getConfiguration(true);
+        assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration);
+
+        List list = config.configurationsAt("colors/*");
+        Iterator iter = list.iterator();
+        System.out.println("Color nodes");
+        while (iter.hasNext())
+        {
+            SubnodeConfiguration sub = (SubnodeConfiguration)iter.next();
+            ConfigurationNode node = sub.getRootNode();
+            String value = (node.getValue() == null) ? "null" : node.getValue().toString();
+            System.out.println(node.getName() + "=" + value);
+        }
+
+    }
+
+    public void testDelimiterParsingDisabled() throws Exception
+    {
+        factory.setFile(MULTI_TENENT_FILE);
+        System.setProperty("Id", "1004");
+
+        CombinedConfiguration config = factory.getConfiguration(true);
+        assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration);
+
+        assertEquals("a,b,c", config.getString("split/list3/@values"));
+        assertEquals(0, config.getMaxIndex("split/list3/@values"));
+        assertEquals("a\\,b\\,c", config.getString("split/list4/@values"));
+        assertEquals("a,b,c", config.getString("split/list1"));
+        assertEquals(0, config.getMaxIndex("split/list1"));
+        assertEquals("a\\,b\\,c", config.getString("split/list2"));
+    }
+
     private void verify(String key, CombinedConfiguration config, int rows)
     {
         System.setProperty("Id", key);

Modified: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDynamicCombinedConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDynamicCombinedConfiguration.java?rev=757482&r1=757481&r2=757482&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDynamicCombinedConfiguration.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestDynamicCombinedConfiguration.java Mon Mar 23 18:17:32 2009
@@ -20,6 +20,8 @@
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 
+import java.io.File;
+
 /**
  *
  */
@@ -50,16 +52,33 @@
     public void testConfiguration() throws Exception
     {
         DynamicCombinedConfiguration config = new DynamicCombinedConfiguration();
+        org.apache.commons.configuration2.tree.xpath.XPathExpressionEngine engine1 =
+            new  org.apache.commons.configuration2.tree.xpath.XPathExpressionEngine();
+        config.setExpressionEngine(engine1);
         config.setKeyPattern(PATTERN);
+        config.setDelimiterParsingDisabled(true);
         MultiFileHierarchicalConfiguration multi = new MultiFileHierarchicalConfiguration(PATTERN1);
+        org.apache.commons.configuration2.expr.xpath.XPathExpressionEngine engine2 =
+            new  org.apache.commons.configuration2.expr.xpath.XPathExpressionEngine();
+        multi.setExpressionEngine(engine2);
         config.addConfiguration(multi, "Multi");
-        XMLConfiguration xml = new XMLConfiguration(DEFAULT_FILE);
+        XMLConfiguration xml = new XMLConfiguration();
+        xml.setExpressionEngine(engine2);
+        xml.setDelimiterParsingDisabled(true);
+        xml.setFile(new File(DEFAULT_FILE));
+        xml.load();
         config.addConfiguration(xml, "Default");
 
         verify("1001", config, 15);
         verify("1002", config, 25);
         verify("1003", config, 35);
         verify("1004", config, 50);
+        assertEquals("a,b,c", config.getString("split/list3/@values"));
+        assertEquals(0, config.getMaxIndex("split/list3/@values"));
+        assertEquals("a\\,b\\,c", config.getString("split/list4/@values"));
+        assertEquals("a,b,c", config.getString("split/list1"));
+        assertEquals(0, config.getMaxIndex("split/list1"));
+        assertEquals("a\\,b\\,c", config.getString("split/list2"));
     }
 
     private void verify(String key, DynamicCombinedConfiguration config, int rows)

Modified: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestMultiFileHierarchicalConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestMultiFileHierarchicalConfiguration.java?rev=757482&r1=757481&r2=757482&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestMultiFileHierarchicalConfiguration.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestMultiFileHierarchicalConfiguration.java Mon Mar 23 18:17:32 2009
@@ -1,3 +1,19 @@
+/*
+ * 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;
 
 import junit.framework.Test;