commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ohe...@apache.org
Subject svn commit: r802387 - in /commons/proper/configuration/branches/configuration2_experimental/src: main/java/org/apache/commons/configuration2/base/ test/java/org/apache/commons/configuration2/base/
Date Sat, 08 Aug 2009 15:04:21 GMT
Author: oheger
Date: Sat Aug  8 15:04:21 2009
New Revision: 802387

URL: http://svn.apache.org/viewvc?rev=802387&view=rev
Log:
Added ConfigurationSourceEventWrapper class which allows adding support for event notifications
to an arbitrary ConfigurationSource implementation.

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

Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/ConfigurationSourceEventWrapper.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/ConfigurationSourceEventWrapper.java?rev=802387&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/ConfigurationSourceEventWrapper.java
(added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/ConfigurationSourceEventWrapper.java
Sat Aug  8 15:04:21 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.base;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * <p>
+ * A specialized implementation of {@code ConfigurationSource} that allows
+ * adding support for event notifications to a wrapped {@code
+ * ConfigurationSource}.
+ * </p>
+ * <p>
+ * This class is a wrapper around another {@code ConfigurationSource}. The
+ * methods defined by the {@code ConfigurationSource} interface are - to the
+ * major part - implemented by delegating to the wrapped source. If a method
+ * requires firing an event, the event is fired by this class before and after
+ * the wrapped source is invoked. This way support for event notifications can
+ * be added to arbitrary {@code ConfigurationSource} implementations
+ * transparently.
+ * </p>
+ *
+ * @author Commons Configuration team
+ * @version $Id$
+ */
+public class ConfigurationSourceEventWrapper implements ConfigurationSource
+{
+    /** Stores the wrapped configuration source. */
+    private final ConfigurationSource wrappedSource;
+
+    /** The list with the event listeners that have been registered. */
+    private final List<ConfigurationSourceListener> listeners;
+
+    /**
+     * Creates a new instance of {@code ConfigurationSourceEventWrapper} and
+     * sets the source to be wrapped.
+     *
+     * @param wrapped the source to be wrapped (must not be <b>null</b>)
+     * @throws IllegalArgumentException if the wrapped source is <b>null</b>
+     */
+    public ConfigurationSourceEventWrapper(ConfigurationSource wrapped)
+    {
+        if (wrapped == null)
+        {
+            throw new IllegalArgumentException(
+                    "Wrapped source must not be null!");
+        }
+
+        wrappedSource = wrapped;
+        listeners = new CopyOnWriteArrayList<ConfigurationSourceListener>();
+    }
+
+    /**
+     * Returns the {@code ConfigurationSource} that is wrapped by this object.
+     *
+     * @return the wrapped source
+     */
+    public ConfigurationSource getWrappedSource()
+    {
+        return wrappedSource;
+    }
+
+    /**
+     * Adds a new {@code ConfigurationSourceListener} to this source.
+     * Implementation note: It is safe to call this method concurrently from
+     * multiple threads.
+     *
+     * @param l the listener to be added (must not be <b>null</b>)
+     * @throws IllegalArgumentException if the listener is <b>null</b>
+     */
+    public void addConfigurationSourceListener(ConfigurationSourceListener l)
+    {
+        if (l == null)
+        {
+            throw new IllegalArgumentException(
+                    "ConfigurationSourceListener must not be null!");
+        }
+
+        listeners.add(l);
+    }
+
+    /**
+     * Adds a new property to this {@code ConfigurationSource}. This method
+     * delegates to the wrapped source. It also produces the correct events for
+     * adding a property.
+     *
+     * @param key the key of the new property
+     * @param value the value of the new property
+     */
+    public void addProperty(String key, Object value)
+    {
+        fireEvent(ConfigurationSourceEvent.Type.ADD_PROPERTY, key, value, true);
+        getWrappedSource().addProperty(key, value);
+        fireEvent(ConfigurationSourceEvent.Type.ADD_PROPERTY, key, value, false);
+    }
+
+    /**
+     * Clears this {@code ConfigurationSource}. This implementation delegates to
+     * the wrapped source. It also produces the correct events for clearing the
+     * source.
+     */
+    public void clear()
+    {
+        fireEvent(ConfigurationSourceEvent.Type.CLEAR_SOURCE, null, null, true);
+        getWrappedSource().clear();
+        fireEvent(ConfigurationSourceEvent.Type.CLEAR_SOURCE, null, null, false);
+    }
+
+    /**
+     * Removes the specified property from this {@code ConfigurationSource}.
+     * This implementation delegates to the wrapped source. It also produces the
+     * correct events for removing a property.
+     *
+     * @param key the key of the property to be removed
+     */
+    public void clearProperty(String key)
+    {
+        fireEvent(ConfigurationSourceEvent.Type.CLEAR_PROPERTY, key, null, true);
+        getWrappedSource().clearProperty(key);
+        fireEvent(ConfigurationSourceEvent.Type.CLEAR_PROPERTY, key, null,
+                false);
+    }
+
+    /**
+     * Tests whether the specified key is contained in this {@code
+     * ConfigurationSource}. This implementation delegates to the wrapped
+     * source.
+     *
+     * @param key the key in question
+     * @return a flag whether this key is contained in this {@code
+     *         ConfigurationSource}
+     */
+    public boolean containsKey(String key)
+    {
+        return getWrappedSource().containsKey(key);
+    }
+
+    /**
+     * Returns an iterator with all keys contained in this {@code
+     * ConfigurationSource}. This implementation delegates to the wrapped
+     * source.
+     *
+     * @return an iterator with the keys of this {@code ConfigurationSource}
+     */
+    public Iterator<String> getKeys()
+    {
+        return getWrappedSource().getKeys();
+    }
+
+    /**
+     * Returns an iterator with all keys contained in this {@code
+     * ConfigurationSource} starting with the given prefix. This implementation
+     * delegates to the wrapped source.
+     *
+     * @param prefix the prefix of the searched keys
+     * @return an iterator with all keys starting with this prefix
+     */
+    public Iterator<String> getKeys(String prefix)
+    {
+        return getWrappedSource().getKeys(prefix);
+    }
+
+    /**
+     * Returns the value of the specified property. This implementation
+     * delegates to the wrapped source.
+     *
+     * @param key the key of the property
+     * @return the value of this property or <b>null</b> if it cannot be found
+     */
+    public Object getProperty(String key)
+    {
+        return getWrappedSource().getProperty(key);
+    }
+
+    /**
+     * Tests whether this {@code ConfigurationSource} is empty. This
+     * implementation delegates to the wrapped source.
+     *
+     * @return <b>true</b> if this {@code ConfigurationSource} is empty,
+     *         <b>false</b> otherwise
+     */
+    public boolean isEmpty()
+    {
+        return getWrappedSource().isEmpty();
+    }
+
+    /**
+     * Removes the specified {@code ConfigurationSourceListener} from this
+     * {@code ConfigurationSource}.
+     *
+     * @param l the listener to be removed
+     * @return a flag whether this listener could be removed
+     */
+    public boolean removeConfigurationSourceListener(
+            ConfigurationSourceListener l)
+    {
+        return listeners.remove(l);
+    }
+
+    /**
+     * Sets the value of a property. This implementation delegates to the
+     * wrapped source. It also produces the correct events for modifying a
+     * property.
+     *
+     * @param key the key of the property to be set
+     * @param value the new value of this property
+     */
+    public void setProperty(String key, Object value)
+    {
+        fireEvent(ConfigurationSourceEvent.Type.MODIFY_PROPERTY, key, value,
+                true);
+        getWrappedSource().setProperty(key, value);
+        fireEvent(ConfigurationSourceEvent.Type.MODIFY_PROPERTY, key, value,
+                false);
+    }
+
+    /**
+     * Returns the size of this {@code ConfigurationSource}. This implementation
+     * delegates to the wrapped source.
+     *
+     * @return the size of this {@code ConfigurationSource}
+     */
+    public int size()
+    {
+        return getWrappedSource().size();
+    }
+
+    /**
+     * Returns the number of values stored for the property with the given key.
+     * This implementation delegates to the wrapped source.
+     *
+     * @param key the key of the property in question
+     * @return the number of values stored for this property
+     */
+    public int valueCount(String key)
+    {
+        return getWrappedSource().valueCount(key);
+    }
+
+    /**
+     * Helper method for sending an event to all listeners currently registered
+     * at this object.
+     *
+     * @param type the type of the event
+     * @param key the property key
+     * @param value the property value
+     * @param before the before update flag
+     */
+    private void fireEvent(ConfigurationSourceEvent.Type type, String key,
+            Object value, boolean before)
+    {
+        ConfigurationSourceEvent event = null; // lazy creation
+
+        for (ConfigurationSourceListener l : listeners)
+        {
+            if (event == null)
+            {
+                event = new ConfigurationSourceEvent(this, type, key, value,
+                        null, before);
+            }
+
+            l.configurationSourceChanged(event);
+        }
+    }
+}

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

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

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

Added: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestConfigurationSourceEventWrapper.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestConfigurationSourceEventWrapper.java?rev=802387&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestConfigurationSourceEventWrapper.java
(added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestConfigurationSourceEventWrapper.java
Sat Aug  8 15:04:21 2009
@@ -0,0 +1,364 @@
+/*
+ * 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.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+
+/**
+ * Test class for {@code ConfigurationSourceEventWrapper}.
+ *
+ * @author Commons Configuration team
+ * @version $Id$
+ */
+public class TestConfigurationSourceEventWrapper extends TestCase
+{
+    /** Constant for a property name. */
+    private static final String PROPERTY = "testProperty";
+
+    /** Constant for a test value. */
+    private static final Object VALUE = 42;
+
+    /** Stores a mock for the wrapped source. */
+    private ConfigurationSource wrappedSource;
+
+    /** A test listener. */
+    private ConfigurationSourceListenerImpl listener;
+
+    /** The source to be tested. */
+    private ConfigurationSourceEventWrapper wrapper;
+
+    @Override
+    protected void setUp() throws Exception
+    {
+        wrappedSource = EasyMock.createMock(ConfigurationSource.class);
+        wrapper = new ConfigurationSourceEventWrapper(wrappedSource);
+        listener = new ConfigurationSourceListenerImpl();
+        wrapper.addConfigurationSourceListener(listener);
+    }
+
+    /**
+     * Tests whether the correct wrapped source is returned.
+     */
+    public void testGetWrappedSource()
+    {
+        assertEquals("Wrong wrapped source", wrappedSource, wrapper
+                .getWrappedSource());
+    }
+
+    /**
+     * Tries to create an instance without a wrapped source. This should cause
+     * an exception.
+     */
+    public void testInitNullSource()
+    {
+        try
+        {
+            new ConfigurationSourceEventWrapper(null);
+            fail("Could create instance without a wrapped source!");
+        }
+        catch (IllegalArgumentException iex)
+        {
+            // ok
+        }
+    }
+
+    /**
+     * Tests whether a property can be added and the expected events are
+     * generated.
+     */
+    public void testAddProperty()
+    {
+        wrappedSource.addProperty(PROPERTY, VALUE);
+        EasyMock.replay(wrappedSource);
+        wrapper.addProperty(PROPERTY, VALUE);
+        EasyMock.verify(wrappedSource);
+        listener.checkEvent(ConfigurationSourceEvent.Type.ADD_PROPERTY,
+                PROPERTY, VALUE);
+        listener.checkDone();
+    }
+
+    /**
+     * Tests the clear() implementation and the events generated by it.
+     */
+    public void testClear()
+    {
+        wrappedSource.clear();
+        EasyMock.replay(wrappedSource);
+        wrapper.clear();
+        EasyMock.verify(wrappedSource);
+        listener.checkEvent(ConfigurationSourceEvent.Type.CLEAR_SOURCE, null,
+                null);
+        listener.checkDone();
+    }
+
+    /**
+     * Tests whether a property can be removed and the expected events are
+     * generated.
+     */
+    public void testClearProperty()
+    {
+        wrappedSource.clearProperty(PROPERTY);
+        EasyMock.replay(wrappedSource);
+        wrapper.clearProperty(PROPERTY);
+        EasyMock.verify(wrappedSource);
+        listener.checkEvent(ConfigurationSourceEvent.Type.CLEAR_PROPERTY,
+                PROPERTY, null);
+        listener.checkDone();
+    }
+
+    /**
+     * Tests the containsKey() implementation.
+     */
+    public void testContainsKey()
+    {
+        EasyMock.expect(wrappedSource.containsKey(PROPERTY)).andReturn(
+                Boolean.TRUE);
+        EasyMock.expect(wrappedSource.containsKey(PROPERTY)).andReturn(
+                Boolean.FALSE);
+        EasyMock.replay(wrappedSource);
+        assertTrue("Wrong result (1)", wrapper.containsKey(PROPERTY));
+        assertFalse("Wrong result (2)", wrapper.containsKey(PROPERTY));
+        listener.checkDone();
+    }
+
+    /**
+     * Tests the getKeys() implementation.
+     */
+    public void testGetKeys()
+    {
+        List<String> keyList = Collections.singletonList(PROPERTY);
+        Iterator<String> it = keyList.iterator();
+        EasyMock.expect(wrappedSource.getKeys()).andReturn(it);
+        EasyMock.replay(wrappedSource);
+        assertSame("Wrong iterator", it, wrapper.getKeys());
+        EasyMock.verify(wrappedSource);
+        listener.checkDone();
+    }
+
+    /**
+     * Tests the getKeys() implementation that takes a prefix.
+     */
+    public void testGetKeysPrefix()
+    {
+        List<String> keyList = Collections.singletonList(PROPERTY);
+        Iterator<String> it = keyList.iterator();
+        EasyMock.expect(wrappedSource.getKeys(PROPERTY)).andReturn(it);
+        EasyMock.replay(wrappedSource);
+        assertSame("Wrong iterator", it, wrapper.getKeys(PROPERTY));
+        EasyMock.verify(wrappedSource);
+        listener.checkDone();
+    }
+
+    /**
+     * Tests whether a property can be queried.
+     */
+    public void testGetProperty()
+    {
+        EasyMock.expect(wrappedSource.getProperty(PROPERTY)).andReturn(VALUE);
+        EasyMock.replay(wrappedSource);
+        assertEquals("Wrong value", VALUE, wrapper.getProperty(PROPERTY));
+        EasyMock.verify(wrappedSource);
+        listener.checkDone();
+    }
+
+    /**
+     * Tests the isEmpty() implementation.
+     */
+    public void testIsEmpty()
+    {
+        EasyMock.expect(wrappedSource.isEmpty()).andReturn(Boolean.TRUE);
+        EasyMock.expect(wrappedSource.isEmpty()).andReturn(Boolean.FALSE);
+        EasyMock.replay(wrappedSource);
+        assertTrue("Wrong result (1)", wrapper.isEmpty());
+        assertFalse("Wrong result (2)", wrapper.isEmpty());
+        EasyMock.verify(wrappedSource);
+        listener.checkDone();
+    }
+
+    /**
+     * Tests whether a property can be set and whether the correct events are
+     * generated.
+     */
+    public void testSetProperty()
+    {
+        wrappedSource.setProperty(PROPERTY, VALUE);
+        EasyMock.replay(wrappedSource);
+        wrapper.setProperty(PROPERTY, VALUE);
+        EasyMock.verify(wrappedSource);
+        listener.checkEvent(ConfigurationSourceEvent.Type.MODIFY_PROPERTY,
+                PROPERTY, VALUE);
+        listener.checkDone();
+    }
+
+    /**
+     * Tests the size() implementation.
+     */
+    public void testSize()
+    {
+        final int size = 112;
+        EasyMock.expect(wrappedSource.size()).andReturn(size);
+        EasyMock.replay(wrappedSource);
+        assertEquals("Wrong size", size, wrapper.size());
+        EasyMock.verify(wrappedSource);
+        listener.checkDone();
+    }
+
+    /**
+     * Tests the valueCount() implementation.
+     */
+    public void testValueCount()
+    {
+        final int count = 3;
+        EasyMock.expect(wrappedSource.valueCount(PROPERTY)).andReturn(count);
+        EasyMock.replay(wrappedSource);
+        assertEquals("Wrong count", count, wrapper.valueCount(PROPERTY));
+        EasyMock.verify(wrappedSource);
+        listener.checkDone();
+    }
+
+    /**
+     * Tries to add a null listener. This should cause an exception.
+     */
+    public void testAddConfigurationSourceListenerNull()
+    {
+        try
+        {
+            wrapper.addConfigurationSourceListener(null);
+            fail("Could add a null listener!");
+        }
+        catch (IllegalArgumentException iex)
+        {
+            // ok
+        }
+    }
+
+    /**
+     * Tests whether listeners can be removed.
+     */
+    public void testRemoveConfigurationSourceListener()
+    {
+        wrappedSource.clearProperty(PROPERTY);
+        wrappedSource.addProperty(PROPERTY, VALUE);
+        wrappedSource.clear();
+        EasyMock.replay(wrappedSource);
+        ConfigurationSourceListenerImpl l = new ConfigurationSourceListenerImpl();
+        wrapper.addConfigurationSourceListener(l);
+        wrapper.clearProperty(PROPERTY);
+        assertTrue("Cannot remove listener (1)", wrapper
+                .removeConfigurationSourceListener(l));
+        wrapper.addProperty(PROPERTY, VALUE);
+        assertTrue("Cannot remove listener (2)", wrapper
+                .removeConfigurationSourceListener(listener));
+        wrapper.clear();
+        EasyMock.verify(wrappedSource);
+        l.checkEvent(ConfigurationSourceEvent.Type.CLEAR_PROPERTY, PROPERTY,
+                null);
+        l.checkDone();
+        listener.checkEvent(ConfigurationSourceEvent.Type.CLEAR_PROPERTY,
+                PROPERTY, null);
+        listener.checkEvent(ConfigurationSourceEvent.Type.ADD_PROPERTY,
+                PROPERTY, VALUE);
+        listener.checkDone();
+    }
+
+    /**
+     * Tries to remove a listener that was not registered.
+     */
+    public void testRemoveConfigurationSourceListenerNonExisting()
+    {
+        assertTrue("Could not remove listener", wrapper
+                .removeConfigurationSourceListener(listener));
+        assertFalse("Could remove listener again", wrapper
+                .removeConfigurationSourceListener(listener));
+        assertFalse("Could remove null listener", wrapper
+                .removeConfigurationSourceListener(null));
+    }
+
+    /**
+     * A test configuration source listener implementation used for testing the
+     * events generated by the source.
+     */
+    private class ConfigurationSourceListenerImpl implements
+            ConfigurationSourceListener
+    {
+        /** A list with the received events. */
+        private final List<ConfigurationSourceEvent> events = new LinkedList<ConfigurationSourceEvent>();
+
+        /**
+         * Records this invocation.
+         */
+        public void configurationSourceChanged(ConfigurationSourceEvent event)
+        {
+            events.add(event);
+        }
+
+        /**
+         * Tests the next pair of events received by this listener. This method
+         * expects that there are two identical events in sequence that only
+         * differ in their before update flag.
+         *
+         * @param type the expected event type
+         * @param prop the expected property name
+         * @param value the expected property value
+         */
+        public void checkEvent(ConfigurationSourceEvent.Type type, String prop,
+                Object value)
+        {
+            checkEvent(type, prop, value, true);
+            checkEvent(type, prop, value, false);
+        }
+
+        /**
+         * Tests the next event received by this listener. The properties are
+         * compared to the event's data.
+         *
+         * @param type the expected event type
+         * @param prop the expected property name
+         * @param value the expected property value
+         * @param before the before update flag
+         */
+        public void checkEvent(ConfigurationSourceEvent.Type type, String prop,
+                Object value, boolean before)
+        {
+            assertFalse("Too few events", events.isEmpty());
+            ConfigurationSourceEvent event = events.remove(0);
+            assertEquals("Wrong source", wrapper, event.getSource());
+            assertEquals("Wrong type", type, event.getType());
+            assertEquals("Wrong property", prop, event.getPropertyName());
+            assertEquals("Wrong value", value, event.getPropertyValue());
+            assertEquals("Wrong before update flag", before, event
+                    .isBeforeUpdate());
+            assertNull("Got additional data", event.getData());
+        }
+
+        /**
+         * Tests whether all events have been checked. This method should be
+         * called to verify that there are no additional events.
+         */
+        public void checkDone()
+        {
+            assertTrue("Too many events: " + events, events.isEmpty());
+        }
+    }
+}

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

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

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



Mime
View raw message