Author: oheger
Date: Mon Oct 12 20:35:07 2009
New Revision: 824486

URL: http://svn.apache.org/viewvc?rev=824486&view=rev
Log:
Added a default implementation for the LocatorSupport interface.

Added:
    
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/DefaultLocatorSupport.java
   (with props)
    
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestDefaultLocatorSupport.java
   (with props)

Added: 
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/DefaultLocatorSupport.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/DefaultLocatorSupport.java?rev=824486&view=auto
==============================================================================
--- 
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/DefaultLocatorSupport.java
 (added)
+++ 
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/DefaultLocatorSupport.java
 Mon Oct 12 20:35:07 2009
@@ -0,0 +1,439 @@
+/*
+ * 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.base;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+
+import org.apache.commons.configuration2.ConfigurationException;
+import org.apache.commons.configuration2.fs.FileSystem;
+import org.apache.commons.configuration2.fs.FileSystemBased;
+import org.apache.commons.configuration2.fs.Locator;
+
+/**
+ * <p>
+ * A default implementation of the {...@code LocatorSupport} interface.
+ * </p>
+ * <p>
+ * This class implements all the various load() and save() methods defined by
+ * the {...@code LocatorSupport} interface by delegating to a
+ * {...@link StreamBasedSource} instance that was passed at construction time. 
This
+ * basically means that all load() operations are eventually mapped to a 
{...@code
+ * Reader}, and all save() operations are eventually mapped to a {...@code 
Writer}.
+ * The encoding and a default {...@link Locator} are also maintained as member
+ * fields.
+ * </p>
+ * <p>
+ * {...@code DefaultLocatorSupport} implements the {...@link FileSystemBased}
+ * interface. Thus a specific {...@link FileSystem} can be set which is used 
for
+ * resolving the URLs obtained from {...@link Locator} instances. By providing
+ * corresponding {...@link FileSystem} implementations various types of URLs 
can be
+ * supported.
+ * </p>
+ * <p>
+ * Using this class greatly simplifies adding support for enhanced file
+ * operations to different {...@link ConfigurationSource} implementations. 
Because
+ * the delegation principle is used no complex inheritance structures are
+ * necessary.
+ * </p>
+ *
+ * @author Commons Configuration team
+ * @version $Id$
+ */
+public class DefaultLocatorSupport implements LocatorSupport, FileSystemBased
+{
+    /** Stores the underlying stream-based source. */
+    private final StreamBasedSource streamBasedSource;
+
+    /** Stores the default locator. */
+    private Locator locator;
+
+    /** The file system used by this object. */
+    private FileSystem fileSystem = FileSystem.getDefaultFileSystem();
+
+    /** Stores the default encoding. */
+    private String encoding;
+
+    /**
+     * Creates a new instance of {...@code DefaultLocatorSupport} and 
initializes
+     * it with the specified {...@code StreamBasedSource}. All load() and 
save()
+     * operations performed on this instance are eventually delegated to this
+     * source.
+     *
+     * @param source the {...@code StreamBasedSource} (must not be <b>null</b>)
+     * @throws IllegalArgumentException if the {...@code StreamBasedSource} is
+     *         <b>null</b>
+     */
+    public DefaultLocatorSupport(StreamBasedSource source)
+    {
+        if (source == null)
+        {
+            throw new IllegalArgumentException(
+                    "StreamBasedSource must not be null!");
+        }
+        streamBasedSource = source;
+    }
+
+    /**
+     * Returns the underlying {...@code StreamBasedSource}.
+     *
+     * @return the {...@code StreamBasedSource}
+     */
+    public StreamBasedSource getStreamBasedSource()
+    {
+        return streamBasedSource;
+    }
+
+    /**
+     * Returns the encoding.
+     *
+     * @return the encoding
+     */
+    public String getEncoding()
+    {
+        return encoding;
+    }
+
+    /**
+     * Returns the default {...@code Locator}.
+     *
+     * @return the {...@code Locator}
+     */
+    public Locator getLocator()
+    {
+        return locator;
+    }
+
+    /**
+     * Loads data from the default {...@code Locator}. The {...@link Locator} 
must
+     * have been set before using the {...@link #setLocator(Locator)} method;
+     * otherwise an exception is thrown.
+     *
+     * @throws ConfigurationException in case of an error
+     * @throws IllegalStateException if no {...@link Locator} has been set
+     */
+    public void load() throws ConfigurationException
+    {
+        if (getLocator() == null)
+        {
+            throw new IllegalStateException(
+                    "A default Locator must be set before calling load()!");
+        }
+
+        load(getLocator());
+    }
+
+    /**
+     * Loads data from the specified {...@code Locator}. This implementation
+     * obtains the input URL from the {...@code Locator}. It then uses the 
{...@code
+     * FileSystem} to obtain an input stream for this URL. This stream is then
+     * loaded.
+     *
+     * @param loc the {...@code Locator} to load from (must not be <b>null</b>)
+     * @throws ConfigurationException if an error occurs
+     * @throws IllegalArgumentException if the {...@code Locator} is 
<b>null</b>
+     */
+    public void load(Locator loc) throws ConfigurationException
+    {
+        if (loc == null)
+        {
+            throw new IllegalArgumentException("Locator must not be null!");
+        }
+
+        InputStream in = getFileSystem().getInputStream(loc.getURL(false));
+        try
+        {
+            load(in);
+        }
+        finally
+        {
+            close(in);
+        }
+    }
+
+    /**
+     * Loads data from the specified {...@code Reader}. This implementation
+     * directly delegates to the underlying {...@code StreamBasedSource}.
+     *
+     * @param reader the reader to read from
+     * @throws ConfigurationException if an error occurs
+     */
+    public void load(Reader reader) throws ConfigurationException
+    {
+        try
+        {
+            getStreamBasedSource().load(reader);
+        }
+        catch (IOException ioex)
+        {
+            throw new ConfigurationException(ioex);
+        }
+    }
+
+    /**
+     * Loads data from the specified {...@code InputStream} using the given
+     * encoding. This implementation creates a {...@code Reader} for the 
specified
+     * stream and delegates to {...@link #load(Reader)}.
+     *
+     * @param in the input stream
+     * @param encoding the encoding (can be <b>null</b>), then no specific
+     *        encoding is set
+     * @throws ConfigurationException if an error occurs
+     */
+    public void load(InputStream in, String encoding)
+            throws ConfigurationException
+    {
+        Reader reader = null;
+
+        if (encoding != null)
+        {
+            try
+            {
+                reader = new InputStreamReader(in, encoding);
+            }
+            catch (UnsupportedEncodingException e)
+            {
+                throw new ConfigurationException(
+                        "The requested encoding is not supported, try the 
default encoding.",
+                        e);
+            }
+        }
+
+        if (reader == null)
+        {
+            reader = new InputStreamReader(in);
+        }
+
+        load(reader);
+    }
+
+    /**
+     * Loads data from the specified {...@code InputStream} using the default
+     * encoding. This implementation calls {...@link #getEncoding()} to obtain 
the
+     * current default encoding (which may be undefined) and then delegates to
+     * {...@link #load(InputStream, String)}.
+     *
+     * @param in the input stream
+     * @throws ConfigurationException if an error occurs
+     */
+    public void load(InputStream in) throws ConfigurationException
+    {
+        load(in, getEncoding());
+    }
+
+    /**
+     * Saves data to the default {...@link Locator}. A {...@link Locator} must 
have
+     * been set using {...@link #setLocator(Locator)}; otherwise an exception 
is
+     * thrown.
+     *
+     * @throws ConfigurationException if an error occurs
+     * @throws IllegalStateException if no {...@link Locator} is set
+     */
+    public void save() throws ConfigurationException
+    {
+        if (getLocator() == null)
+        {
+            throw new IllegalStateException(
+                    "A default Locator must be set before calling save()!");
+        }
+
+        save(getLocator());
+    }
+
+    /**
+     * Saves data to the specified {...@code Locator}. This implementation 
obtains
+     * the output URL from the given {...@code Locator} and uses the
+     * {...@link FileSystem} to create an output stream for it. Then it 
delegates
+     * to {...@link #save(OutputStream)}.
+     *
+     * @param loc the {...@code Locator} (must not be <b>null</b>)
+     * @throws ConfigurationException if an error occurs
+     * @throws IllegalArgumentException if the {...@code Locator} is 
<b>null</b>
+     */
+    public void save(Locator loc) throws ConfigurationException
+    {
+        if (loc == null)
+        {
+            throw new IllegalArgumentException("Locator must not be null!");
+        }
+
+        OutputStream out = getFileSystem().getOutputStream(loc.getURL(true));
+        try
+        {
+            save(out);
+        }
+        finally
+        {
+            close(out);
+        }
+    }
+
+    /**
+     * Saves data to the specified {...@code Writer}. This implementation 
directly
+     * delegates to the underlying {...@code StreamBasedSource}.
+     *
+     * @param writer the writer
+     * @throws ConfigurationException if an error occurs
+     * @see StreamBasedSource#save(Writer)
+     */
+    public void save(Writer writer) throws ConfigurationException
+    {
+        try
+        {
+            getStreamBasedSource().save(writer);
+        }
+        catch (IOException ioex)
+        {
+            throw new ConfigurationException(ioex);
+        }
+    }
+
+    /**
+     * Saves data to the specified output stream using the given encoding. This
+     * implementation creates a writer for this output stream and delegates to
+     * {...@link #save(Writer)}.
+     *
+     * @param out the output stream
+     * @param encoding the encoding (can be <b>null</b>, then the
+     *        platform-specific default encoding is used)
+     * @throws ConfigurationException if an error occurs
+     */
+    public void save(OutputStream out, String encoding)
+            throws ConfigurationException
+    {
+        Writer writer = null;
+
+        if (encoding != null)
+        {
+            try
+            {
+                writer = new OutputStreamWriter(out, encoding);
+            }
+            catch (UnsupportedEncodingException e)
+            {
+                throw new ConfigurationException(
+                        "The requested encoding is not supported, try the 
default encoding.",
+                        e);
+            }
+        }
+
+        if (writer == null)
+        {
+            writer = new OutputStreamWriter(out);
+        }
+
+        save(writer);
+    }
+
+    /**
+     * Saves data to the specified output stream using the default encoding.
+     * This method calls {...@link #getEncoding()} to obtain the default 
encoding
+     * (which may be undefined). Then it delegates to
+     * {...@link #save(OutputStream, String)}.
+     *
+     * @param out the output stream
+     * @throws ConfigurationException if an error occurs
+     */
+    public void save(OutputStream out) throws ConfigurationException
+    {
+        save(out, getEncoding());
+    }
+
+    /**
+     * Sets the default encoding. This encoding is used when reading data from
+     * streams and no explicit encoding is specified.
+     *
+     * @param the default encoding
+     */
+    public void setEncoding(String enc)
+    {
+        encoding = enc;
+    }
+
+    /**
+     * Sets the {...@code Locator}. This {...@code Locator} is used by the 
{...@code
+     * load()} method that takes no arguments.
+     *
+     * @param locator the {...@code Locator}
+     */
+    public void setLocator(Locator locator)
+    {
+        this.locator = locator;
+    }
+
+    /**
+     * Returns the {...@code FileSystem} used by this object.
+     *
+     * @return the {...@code FileSyste}
+     */
+    public FileSystem getFileSystem()
+    {
+        return fileSystem;
+    }
+
+    /**
+     * Resets the {...@code FileSystem} used by this object to the default 
{...@code
+     * FileSystem}.
+     */
+    public void resetFileSystem()
+    {
+        fileSystem = FileSystem.getDefaultFileSystem();
+    }
+
+    /**
+     * Sets the {...@code FileSystem} to be used by this object. The {...@code
+     * FileSystem} is used for resolving URLs returned by {...@code Locator}
+     * objects.
+     *
+     * @param fileSystem the new {...@code FileSystem} (must not be 
<b>null</b>)
+     * @throws IllegalArgumentException if the {...@code FileSystem} is 
<b>null</b>
+     */
+    public void setFileSystem(FileSystem fileSystem)
+    {
+        if (fileSystem == null)
+        {
+            throw new IllegalArgumentException("FileSystem must not be null!");
+        }
+        this.fileSystem = fileSystem;
+    }
+
+    /**
+     * Helper method for closing the specified object. Exceptions are rethrown
+     * as configuration exceptions.
+     *
+     * @param c the object to be closed
+     * @throws ConfigurationException if an I/O error occurs
+     */
+    static void close(Closeable c) throws ConfigurationException
+    {
+        try
+        {
+            c.close();
+        }
+        catch (IOException ioex)
+        {
+            throw new ConfigurationException("Error when closing stream", 
ioex);
+        }
+    }
+}

Propchange: 
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/DefaultLocatorSupport.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/DefaultLocatorSupport.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/DefaultLocatorSupport.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestDefaultLocatorSupport.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestDefaultLocatorSupport.java?rev=824486&view=auto
==============================================================================
--- 
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestDefaultLocatorSupport.java
 (added)
+++ 
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestDefaultLocatorSupport.java
 Mon Oct 12 20:35:07 2009
@@ -0,0 +1,660 @@
+/*
+ * 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.base;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URL;
+import java.nio.charset.Charset;
+
+import org.apache.commons.configuration2.ConfigurationAssert;
+import org.apache.commons.configuration2.ConfigurationException;
+import org.apache.commons.configuration2.fs.FileSystem;
+import org.apache.commons.configuration2.fs.Locator;
+import org.apache.commons.configuration2.fs.URLLocator;
+import org.apache.commons.configuration2.fs.VFSFileSystem;
+import org.easymock.EasyMock;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Test class for {...@code DefaultLocatorSupport}.
+ *
+ * @author Commons Configuration team
+ * @version $Id$
+ */
+public class TestDefaultLocatorSupport
+{
+    /** Constant defining some test data to be loaded or stored. */
+    private static final String TEST_DATA = "Test data for 
TestDefaultLocatorSupport";
+
+    /** Constant for the name of the test file. */
+    private static final String TEST_FILE = "TestDefaultLocatorSupport.txt";
+
+    /** Constant for the encoding. */
+    private static final String ENCODING = "UTF8";
+
+    /** The input locator to the test file. */
+    private static Locator inputLocator;
+
+    /** The output locator for the test file. */
+    private static Locator outputLocator;
+
+    /** The stream based source used for testing. */
+    private StreamBasedSourceTestImpl source;
+
+    /** The object to be tested. */
+    private DefaultLocatorSupport locatorSupport;
+
+    /** A test file. */
+    private File testFile;
+
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception
+    {
+        URL url = ConfigurationAssert.getOutURL(TEST_FILE);
+        URL urlNonExisting = ConfigurationAssert
+                .getOutURL("NonExistingFile.txt");
+        inputLocator = new URLLocator(url, urlNonExisting);
+        outputLocator = new URLLocator(urlNonExisting, url);
+    }
+
+    @Before
+    public void setUp() throws Exception
+    {
+        testFile = ConfigurationAssert.getOutFile(TEST_FILE);
+        source = new StreamBasedSourceTestImpl();
+        locatorSupport = new DefaultLocatorSupport(source);
+    }
+
+    /**
+     * Performs cleanup. Removes the test file if it exists.
+     */
+    @After
+    public void tearDown() throws Exception
+    {
+        if (testFile != null && testFile.exists())
+        {
+            assertTrue("Cannot remove test file", testFile.delete());
+        }
+    }
+
+    /**
+     * Helper method for reading the content of a reader into a string.
+     *
+     * @param reader the reader to read
+     * @return the content of the reader as string
+     * @throws IOException if an I/O error occurs
+     */
+    private static String read(Reader reader) throws IOException
+    {
+        StringBuilder buf = new StringBuilder();
+        BufferedReader in = new BufferedReader(reader);
+        String line;
+        while ((line = in.readLine()) != null)
+        {
+            buf.append(line);
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Helper method for writing test data into the given writer.
+     *
+     * @param writer the writer
+     * @throws IOException if an I/O error occurs
+     */
+    private static void write(Writer writer) throws IOException
+    {
+        PrintWriter out = new PrintWriter(writer);
+        out.print(TEST_DATA);
+        out.flush();
+    }
+
+    /**
+     * Helper method for checking the encoding that was passed to the source.
+     *
+     * @param expEnc the expected encoding
+     */
+    private void checkEncoding(String expEnc)
+    {
+        Charset expected = (expEnc == null) ? Charset.defaultCharset()
+                : Charset.forName(expEnc);
+        Charset actual = Charset.forName(source.encoding);
+        assertEquals("Wrong encoding", expected, actual);
+    }
+
+    /**
+     * Tests whether the test file was correctly written.
+     *
+     * @throws IOException if an error occurs
+     */
+    private void checkTestFile() throws IOException
+    {
+        FileReader in = new FileReader(testFile);
+        try
+        {
+            assertEquals("Wrong content of file", TEST_DATA, read(in));
+        }
+        finally
+        {
+            in.close();
+        }
+    }
+
+    /**
+     * Creates a test file with test data.
+     *
+     * @throws IOException if an I/O error occurs
+     */
+    private void createTestFile() throws IOException
+    {
+        FileWriter writer = new FileWriter(testFile);
+        try
+        {
+            write(writer);
+        }
+        finally
+        {
+            writer.close();
+        }
+    }
+
+    /**
+     * Tries to create an instance without a source. This should cause an
+     * exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testInitNoSource()
+    {
+        new DefaultLocatorSupport(null);
+    }
+
+    /**
+     * Tests a newly created instance.
+     */
+    @Test
+    public void testInit()
+    {
+        assertNull("Got an encoding", locatorSupport.getEncoding());
+        assertNull("Got a locator", locatorSupport.getLocator());
+        assertEquals("Wrong file system", FileSystem.getDefaultFileSystem(),
+                locatorSupport.getFileSystem());
+    }
+
+    /**
+     * Tests whether a file system can be set.
+     */
+    @Test
+    public void testSetFileSystem()
+    {
+        VFSFileSystem fs = new VFSFileSystem();
+        locatorSupport.setFileSystem(fs);
+        assertEquals("FileSystem not changed", fs, locatorSupport
+                .getFileSystem());
+    }
+
+    /**
+     * Tries to set a null file system. This should cause an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testSetFileSystemNull()
+    {
+        locatorSupport.setFileSystem(null);
+    }
+
+    /**
+     * Tests whether the file system can be reset to the default one.
+     */
+    @Test
+    public void testResetFileSystem()
+    {
+        locatorSupport.setFileSystem(new VFSFileSystem());
+        locatorSupport.resetFileSystem();
+        assertEquals("Wrong file system", FileSystem.getDefaultFileSystem(),
+                locatorSupport.getFileSystem());
+    }
+
+    /**
+     * Tests the close() method if an exception occurs.
+     */
+    @Test
+    public void testCloseEx() throws IOException
+    {
+        Closeable c = EasyMock.createMock(Closeable.class);
+        c.close();
+        IOException ioex = new IOException();
+        EasyMock.expectLastCall().andThrow(ioex);
+        EasyMock.replay(c);
+        try
+        {
+            DefaultLocatorSupport.close(c);
+            fail("Exception not thrown!");
+        }
+        catch (ConfigurationException cex)
+        {
+            assertEquals("Wrong cause", ioex, cex.getCause());
+            EasyMock.verify(c);
+        }
+    }
+
+    /**
+     * Helper method for testing the results of a load operation.
+     *
+     * @param expEnc the expected encoding
+     */
+    private void checkLoad(String expEnc)
+    {
+        assertEquals("Wrong data", TEST_DATA, source.loadData);
+        checkEncoding(expEnc);
+    }
+
+    /**
+     * Tests the load() method if no locator was set. This should cause an
+     * exception.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testLoadNoLocator() throws ConfigurationException
+    {
+        locatorSupport.load();
+    }
+
+    /**
+     * Tests loading data from the default locator.
+     */
+    @Test
+    public void testLoadDefLocator() throws IOException, ConfigurationException
+    {
+        createTestFile();
+        locatorSupport.setLocator(inputLocator);
+        locatorSupport.load();
+        checkLoad(null);
+    }
+
+    /**
+     * Tests whether data from a specific locator can be loaded.
+     */
+    @Test
+    public void testLoadSpecificLocator() throws IOException,
+            ConfigurationException
+    {
+        Locator defloc = EasyMock.createMock(Locator.class);
+        EasyMock.replay(defloc);
+        locatorSupport.setLocator(defloc);
+        createTestFile();
+        locatorSupport.load(inputLocator);
+        checkLoad(null);
+        EasyMock.verify(defloc);
+    }
+
+    /**
+     * Tests whether the encoding is taken into account when loading from a
+     * locator.
+     */
+    @Test
+    public void testLoadLocatorEnc() throws IOException, ConfigurationException
+    {
+        createTestFile();
+        locatorSupport.setEncoding(ENCODING);
+        locatorSupport.setLocator(inputLocator);
+        locatorSupport.load();
+        checkLoad(ENCODING);
+    }
+
+    /**
+     * Tries to load data from a null locator. This should cause an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testLoadLocatorNull() throws ConfigurationException
+    {
+        locatorSupport.load((Locator) null);
+    }
+
+    /**
+     * Tests whether exceptions are correctly handled when loading data from a
+     * locator.
+     */
+    @Test
+    public void testLoadLocatorEx() throws IOException, ConfigurationException
+    {
+        createTestFile();
+        source.ex = new IOException();
+        try
+        {
+            locatorSupport.load(inputLocator);
+            fail("Exception not thrown!");
+        }
+        catch (ConfigurationException cex)
+        {
+            assertEquals("Wrong cause", source.ex, cex.getCause());
+        }
+    }
+
+    /**
+     * Tests whether a stream can be loaded if the encoding is specified.
+     */
+    @Test
+    public void testLoadStreamEnc() throws ConfigurationException, IOException
+    {
+        createTestFile();
+        FileInputStream in = new FileInputStream(testFile);
+        try
+        {
+            locatorSupport.load(in, ENCODING);
+            checkLoad(ENCODING);
+        }
+        finally
+        {
+            in.close();
+        }
+    }
+
+    /**
+     * Tests whether a stream can be loaded with the default encoding.
+     */
+    @Test
+    public void testLoadStreamDefEnc() throws IOException,
+            ConfigurationException
+    {
+        createTestFile();
+        locatorSupport.setEncoding(ENCODING);
+        FileInputStream in = new FileInputStream(testFile);
+        try
+        {
+            locatorSupport.load(in);
+            checkLoad(ENCODING);
+        }
+        finally
+        {
+            in.close();
+        }
+    }
+
+    /**
+     * Tries to load data using an unsupported encoding.
+     */
+    @Test
+    public void testLoadStreamUnsupportedEnc() throws IOException,
+            ConfigurationException
+    {
+        createTestFile();
+        locatorSupport.setEncoding("an unsupported encoding!");
+        FileInputStream in = new FileInputStream(testFile);
+        try
+        {
+            locatorSupport.load(in);
+            fail("Unsupported encoding not detected!");
+        }
+        catch (ConfigurationException cex)
+        {
+            // ok
+        }
+        finally
+        {
+            in.close();
+        }
+    }
+
+    /**
+     * Tests whether IOExceptions thrown by the source on reading are converted
+     * to configuration exceptions.
+     */
+    @Test
+    public void testLoadReaderEx()
+    {
+        source.ex = new IOException();
+        try
+        {
+            locatorSupport.load(new StringReader(TEST_DATA));
+            fail("Exception not thrown!");
+        }
+        catch (ConfigurationException cex)
+        {
+            assertEquals("Wrong cause", source.ex, cex.getCause());
+        }
+    }
+
+    /**
+     * Tests whether IOExceptions thrown by the source on writing are converted
+     * to configuration exceptions.
+     */
+    @Test
+    public void testSaveWriterEx()
+    {
+        source.ex = new IOException();
+        try
+        {
+            locatorSupport.save(new StringWriter());
+            fail("Exception not thrown!");
+        }
+        catch (ConfigurationException cex)
+        {
+            assertEquals("Wrong cause", source.ex, cex.getCause());
+        }
+    }
+
+    /**
+     * Tests whether data can be saved to a stream if the encoding is 
specified.
+     */
+    @Test
+    public void testSaveStreamEnc() throws IOException, ConfigurationException
+    {
+        FileOutputStream out = new FileOutputStream(testFile);
+        try
+        {
+            locatorSupport.save(out, ENCODING);
+        }
+        finally
+        {
+            out.close();
+        }
+        checkTestFile();
+        checkEncoding(ENCODING);
+    }
+
+    /**
+     * Tests whether the default encoding is taken into account when saving to 
a
+     * stream.
+     */
+    @Test
+    public void testSaveStreamDefEnc() throws IOException,
+            ConfigurationException
+    {
+        locatorSupport.setEncoding(ENCODING);
+        FileOutputStream out = new FileOutputStream(testFile);
+        try
+        {
+            locatorSupport.save(out);
+        }
+        finally
+        {
+            out.close();
+        }
+        checkTestFile();
+        checkEncoding(ENCODING);
+    }
+
+    /**
+     * Tries to save to a stream with an unsupported encoding. This should 
cause
+     * an exception.
+     */
+    @Test
+    public void testSaveStreamUnsupportedEnc() throws IOException,
+            ConfigurationException
+    {
+        FileOutputStream out = new FileOutputStream(testFile);
+        try
+        {
+            locatorSupport.save(out, "an unknown encoding!");
+            fail("Unsupported encoding not detected!");
+        }
+        catch (ConfigurationException cex)
+        {
+            // ok
+        }
+        finally
+        {
+            out.close();
+        }
+    }
+
+    /**
+     * Tries to save data is no locator is specified. This should cause an
+     * exception.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testSaveNoLocator() throws ConfigurationException
+    {
+        locatorSupport.save();
+    }
+
+    /**
+     * Tries to save data to a null locator. This should cause an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testSaveLocatorNull() throws ConfigurationException
+    {
+        locatorSupport.save((Locator) null);
+    }
+
+    /**
+     * Tests the behavior of save(Locator) if an exception is thrown.
+     */
+    @Test
+    public void testSaveLocatorEx()
+    {
+        locatorSupport.setLocator(outputLocator);
+        source.ex = new IOException();
+        try
+        {
+            locatorSupport.save();
+            fail("Exception not thrown!");
+        }
+        catch (ConfigurationException cex)
+        {
+            assertEquals("Wrong cause", source.ex, cex.getCause());
+        }
+    }
+
+    /**
+     * Tests whether data can be saved using the default locator.
+     */
+    @Test
+    public void testSaveDefLocator() throws ConfigurationException, IOException
+    {
+        locatorSupport.setLocator(outputLocator);
+        locatorSupport.save();
+        checkTestFile();
+        checkEncoding(null);
+    }
+
+    /**
+     * Tests whether data can be saved using a specific locator.
+     */
+    @Test
+    public void testSaveSpecificLocator() throws ConfigurationException,
+            IOException
+    {
+        Locator defLoc = EasyMock.createMock(Locator.class);
+        EasyMock.replay(defLoc);
+        locatorSupport.setLocator(defLoc);
+        locatorSupport.save(outputLocator);
+        checkTestFile();
+        checkEncoding(null);
+        EasyMock.verify(defLoc);
+    }
+
+    /**
+     * Tests whether the encoding is taken into account when saving to a
+     * locator.
+     */
+    @Test
+    public void testSaveLocatorEnc() throws ConfigurationException, IOException
+    {
+        locatorSupport.setLocator(outputLocator);
+        locatorSupport.setEncoding(ENCODING);
+        locatorSupport.save();
+        checkTestFile();
+        checkEncoding(ENCODING);
+    }
+
+    /**
+     * A simple test implementation of the {...@code StreamBasedSource} 
interface.
+     * This implementation implements the load() operation by the reading in an
+     * internal buffer. save() is implemented by writing a test text into the
+     * writer.
+     */
+    private static class StreamBasedSourceTestImpl implements StreamBasedSource
+    {
+        /** Stores text read by the load() method. */
+        String loadData;
+
+        /** Stores the encoding used by load() or save(). */
+        String encoding;
+
+        /** An exception to be thrown. */
+        IOException ex;
+
+        public void load(Reader reader) throws ConfigurationException,
+                IOException
+        {
+            if (ex != null)
+            {
+                throw ex;
+            }
+            loadData = read(reader);
+            if (reader instanceof InputStreamReader)
+            {
+                encoding = ((InputStreamReader) reader).getEncoding();
+            }
+        }
+
+        public void save(Writer writer) throws ConfigurationException,
+                IOException
+        {
+            if (ex != null)
+            {
+                throw ex;
+            }
+            write(writer);
+            if (writer instanceof OutputStreamWriter)
+            {
+                encoding = ((OutputStreamWriter) writer).getEncoding();
+            }
+        }
+    }
+}

Propchange: 
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestDefaultLocatorSupport.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestDefaultLocatorSupport.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestDefaultLocatorSupport.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain


Reply via email to