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