You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2008/03/28 20:04:44 UTC

svn commit: r642335 - in /commons/proper/configuration/branches/configuration2_experimental/src: main/java/org/apache/commons/configuration2/combined/ test/java/org/apache/commons/configuration2/combined/

Author: oheger
Date: Fri Mar 28 12:04:41 2008
New Revision: 642335

URL: http://svn.apache.org/viewvc?rev=642335&view=rev
Log:
New NodeHandler implementation for combined configurations

Added:
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/combined/CombinedConfigurationNodeHandler.java   (with props)
    commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/combined/TestCombinedConfigurationNodeHandler.java   (with props)

Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/combined/CombinedConfigurationNodeHandler.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/combined/CombinedConfigurationNodeHandler.java?rev=642335&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/combined/CombinedConfigurationNodeHandler.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/combined/CombinedConfigurationNodeHandler.java Fri Mar 28 12:04:41 2008
@@ -0,0 +1,472 @@
+/*
+ * 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.combined;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.configuration2.ConfigurationRuntimeException;
+import org.apache.commons.configuration2.expr.NodeHandler;
+import org.apache.commons.configuration2.expr.NodeHandlerRegistry;
+
+/**
+ * <p>
+ * A special <code>NodeHandler</code> implementation that is used by a
+ * <code>CombinedConfiguration</code>.
+ * </p>
+ * <p>
+ * Depending on the contained configurations, a
+ * <code>CombinedConfiguration</code> may have to deal with different node
+ * objects at the same time. Thus it requires a powerful
+ * <code>NodeHandler</code>. This class implements such a
+ * <code>NodeHandler</code> that acts as a wrapper for multiple other concrete
+ * <code>NodeHandler</code> implementations.
+ * </p>
+ * <p>
+ * The basic idea is that the possible node types (that are currently contained
+ * in the associated combined configuration) are registered at this class
+ * together with the corresponding handlers. When then a
+ * <code>NodeHandler</code> method is invoked, the class determines the
+ * <code>NodeHandler</code> responsible for the affected node and delegates
+ * the method call to it. That way a <code>CombinedConfiguration</code> can
+ * deal with heterogeneous node structures in a transparent way making use of a
+ * single node handler only.
+ * </p>
+ * <p>
+ * In addition to the <code>NodeHandler</code> interface this class also
+ * implements the <code>NodeHandlerRegistry</code> interface, which allows the
+ * lookup of node handlers for given node objects. Supporting this interface is
+ * important especially when combined configurations are contained in other
+ * combined configurations. Because node handler registries can be combined to
+ * hierarchical structures, too, it is then possible to query suitable node
+ * handlers everywhere in the complex nodes hierarchy.
+ * </p>
+ *
+ * @author <a href="http://commons.apache.org/configuration/team-list.html">Commons
+ *         Configuration team</a>
+ * @version $Id$
+ */
+class CombinedConfigurationNodeHandler implements NodeHandler<Object>,
+        NodeHandlerRegistry
+{
+    /**
+     * Stores the currently known node handlers.
+     */
+    private Map<Class<?>, NodeHandler<?>> handlers;
+
+    /** Stores the added sub registries. */
+    private List<NodeHandlerRegistry> subRegistries;
+
+    /** Stores the reference to the parent registry. */
+    private NodeHandlerRegistry parentRegistry;
+
+    /**
+     * Creates a new instance of <code>CombinedConfigurationNodeHandler</code>.
+     */
+    public CombinedConfigurationNodeHandler()
+    {
+        subRegistries = new ArrayList<NodeHandlerRegistry>();
+    }
+
+    /**
+     * Returns a map with the currently known node handlers.
+     *
+     * @return a map with the known node handlers
+     */
+    public Map<Class<?>, NodeHandler<?>> getHandlers()
+    {
+        return handlers;
+    }
+
+    /**
+     * Sets a map with the currently known node handlers. This map allows to
+     * query a node handler based on the class of a configuration node.
+     *
+     * @param handlers the map with the handlers
+     */
+    public void setHandlers(Map<Class<?>, NodeHandler<?>> handlers)
+    {
+        this.handlers = handlers;
+    }
+
+    /**
+     * Returns the parent <code>NodeHandlerRegistry</code>. This can be
+     * <b>null</b> if none has been set.
+     *
+     * @return the parent node handler registry
+     */
+    public NodeHandlerRegistry getParentRegistry()
+    {
+        return parentRegistry;
+    }
+
+    /**
+     * Adds a value to an attribute. This implementation delegates to the node
+     * handler responsible for the passed in node.
+     *
+     * @param node the node
+     * @param name the name of the attribute
+     * @param value the value to add
+     */
+    public void addAttributeValue(Object node, String name, Object value)
+    {
+        fetchHandler(node).addAttributeValue(node, name, value);
+    }
+
+    /**
+     * Adds a new child node to a given node. This implementation delegates to
+     * the node handler responsible for the passed in node.
+     *
+     * @param node the node
+     * @param name the name of the new child node
+     * @return the newly created child node
+     */
+    public Object addChild(Object node, String name)
+    {
+        return fetchHandler(node).addChild(node, name);
+    }
+
+    /**
+     * Returns the value of the specified attribute of the given node. This
+     * implementation delegates to the node handler responsible for the passed
+     * in node.
+     *
+     * @param node the node
+     * @param name the name of the attribute
+     * @return the value of this attribute
+     */
+    public Object getAttributeValue(Object node, String name)
+    {
+        return fetchHandler(node).getAttributeValue(node, name);
+    }
+
+    /**
+     * Returns a list with the names of all attributes defined for the specified
+     * node. This implementation delegates to the node handler responsible for
+     * the passed in node.
+     *
+     * @param node the node
+     * @return a list with the names of the attributes
+     */
+    public List<String> getAttributes(Object node)
+    {
+        return fetchHandler(node).getAttributes(node);
+    }
+
+    /**
+     * Returns the child node at the given index from the specified node. This
+     * implementation delegates to the node handler responsible for the passed
+     * in node.
+     *
+     * @param node the node
+     * @param index the index of the desired child
+     * @return the child node at this index
+     */
+    public Object getChild(Object node, int index)
+    {
+        return fetchHandler(node).getChild(node, index);
+    }
+
+    /**
+     * Returns a list with all children of the specified node. This
+     * implementation delegates to the node handler responsible for the passed
+     * in node.
+     *
+     * @param node the node
+     * @return a list with all children of this node
+     */
+    public List<Object> getChildren(Object node)
+    {
+        return fetchHandler(node).getChildren(node);
+    }
+
+    /**
+     * Returns a list with the child nodes of the specified node with the given
+     * name. This implementation delegates to the node handler responsible for
+     * the passed in node.
+     *
+     * @param node the node
+     * @param name the name of the desired children
+     * @return a list with all child nodes with this name
+     */
+    public List<Object> getChildren(Object node, String name)
+    {
+        return fetchHandler(node).getChildren(node, name);
+    }
+
+    /**
+     * Returns the number of child nodes of the specified node with the given
+     * name. This implementation delegates to the node handler responsible for
+     * the passed in node.
+     *
+     * @param node the node
+     * @param name the name of the children
+     * @return the number of the selected children
+     */
+    public int getChildrenCount(Object node, String name)
+    {
+        return fetchHandler(node).getChildrenCount(node, name);
+    }
+
+    /**
+     * Returns the parent node of the given node. This implementation delegates
+     * to the node handler responsible for the passed in node.
+     *
+     * @param node the node
+     * @return the parent node of this node
+     */
+    public Object getParent(Object node)
+    {
+        return fetchHandler(node).getParent(node);
+    }
+
+    /**
+     * Returns the value of the specified node. This implementation delegates to
+     * the node handler responsible for the passed in node.
+     *
+     * @param node the node
+     * @return the value of this node
+     */
+    public Object getValue(Object node)
+    {
+        return fetchHandler(node).getValue(node);
+    }
+
+    /**
+     * Returns a flag whether the specified node has any attributes. This
+     * implementation delegates to the node handler responsible for the passed
+     * in node.
+     *
+     * @param node the node
+     * @return a flag whether this node has attributes
+     */
+    public boolean hasAttributes(Object node)
+    {
+        return fetchHandler(node).hasAttributes(node);
+    }
+
+    /**
+     * Initializes the reference to the parent node handler registry. If a non
+     * <b>null</b> is passed in, this object will register itself as a sub
+     * registry.
+     *
+     * @param registry the parent registry
+     */
+    public void initNodeHandlerRegistry(NodeHandlerRegistry registry)
+    {
+        parentRegistry = registry;
+        if (registry != null)
+        {
+            registry.addSubRegistry(this);
+        }
+    }
+
+    /**
+     * Tests whether the given node is defined. This implementation delegates to
+     * the node handler responsible for the passed in node.
+     *
+     * @param node the node
+     * @return a flag whether this node is defined
+     */
+    public boolean isDefined(Object node)
+    {
+        return fetchHandler(node).isDefined(node);
+    }
+
+    /**
+     * Returns the name of the specified node. This implementation delegates to
+     * the node handler responsible for the passed in node.
+     *
+     * @param node the node
+     * @return the name of this node
+     */
+    public String nodeName(Object node)
+    {
+        return fetchHandler(node).nodeName(node);
+    }
+
+    /**
+     * Removes an attribute from the specified node. This implementation
+     * delegates to the node handler responsible for the passed in node.
+     *
+     * @param node the node
+     * @param name the name of the attribute to remove
+     */
+    public void removeAttribute(Object node, String name)
+    {
+        fetchHandler(node).removeAttribute(node, name);
+    }
+
+    /**
+     * Removes a child node from the specified node. This implementation
+     * delegates to the node handler responsible for the passed in node.
+     *
+     * @param node the node
+     * @param child the child node to be removed
+     */
+    public void removeChild(Object node, Object child)
+    {
+        fetchHandler(node).removeChild(node, child);
+    }
+
+    /**
+     * Sets the value of an attribute of the specified node. This implementation
+     * delegates to the node handler responsible for the passed in node.
+     *
+     * @param node the node
+     * @param name the name of the attribute to set
+     * @param value the new value
+     */
+    public void setAttributeValue(Object node, String name, Object value)
+    {
+        fetchHandler(node).setAttributeValue(node, name, value);
+    }
+
+    /**
+     * Sets the value of the specified node. This implementation delegates to
+     * the node handler responsible for the passed in node.
+     *
+     * @param node the node
+     * @param value the new value
+     */
+    public void setValue(Object node, Object value)
+    {
+        fetchHandler(node).setValue(node, value);
+    }
+
+    /**
+     * Adds a new sub registry to this node handler registry.
+     *
+     * @param subreg the registry to add
+     */
+    public void addSubRegistry(NodeHandlerRegistry subreg)
+    {
+        subRegistries.add(subreg);
+    }
+
+    /**
+     * Searches for a handler for the specified node in the internal map and the
+     * registered sub registries.
+     *
+     * @param node the node in question
+     * @param subClass a flag whether derived class are to be taken into account
+     * @return the found handler or <b>null</b>
+     */
+    public NodeHandler<?> lookupHandler(Object node, boolean subClass)
+    {
+        NodeHandler<?> result = getHandlers().get(node.getClass());
+
+        if (result == null && subClass)
+        {
+            // check for sub classes
+            for (Class<?> cls : getHandlers().keySet())
+            {
+                if (cls.isInstance(node))
+                {
+                    result = getHandlers().get(cls);
+                    // store directly in map for faster access the next time
+                    getHandlers().put(node.getClass(), result);
+                    break;
+                }
+            }
+        }
+
+        if (result == null)
+        {
+            result = searchSubRegistries(node, subClass);
+        }
+
+        return result;
+    }
+
+    /**
+     * Tries to find a <code>NodeHandler</code> for the specified node. If a
+     * parent registry is set, this call is delegated to it. Otherwise
+     * <code>lookupHandler()</code> is called (first with a
+     * <code>subClass</code> parameter of <b>false</b> and then <b>true</b>).
+     * If the handler cannot be found in the local handler mapping and in the
+     * sub registries either, an exception is thrown.
+     *
+     * @param node the node in question
+     * @return a <code>NodeHandler</code> for this node
+     * @throws ConfigurationRuntimeException if no compatible handler can be
+     *         found
+     */
+    public NodeHandler<?> resolveHandler(Object node)
+    {
+        if (getParentRegistry() != null)
+        {
+            return getParentRegistry().resolveHandler(node);
+        }
+
+        else
+        {
+            NodeHandler<?> result = lookupHandler(node, false);
+            if (result == null)
+            {
+                result = lookupHandler(node, true);
+                if (result == null)
+                {
+                    throw new ConfigurationRuntimeException(
+                            "Cannot find a compatible node handler for node "
+                                    + node);
+                }
+            }
+
+            return result;
+        }
+    }
+
+    /**
+     * Searches the sub registries for a handler for the specified node.
+     *
+     * @param node the node
+     * @param subClass the sub class flag
+     * @return the found handler or <b>null</b>
+     */
+    private NodeHandler<?> searchSubRegistries(Object node, boolean subClass)
+    {
+        for (NodeHandlerRegistry nhr : subRegistries)
+        {
+            NodeHandler<?> h = nhr.lookupHandler(node, subClass);
+            if (h != null)
+            {
+                return h;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Helper method for obtaining a node handler for a given node. This method
+     * casts the handler returned by <code>resolveHandler()</code> to a
+     * <code>NodeHandler&lt;Object&gt;</code>, so it can be invoked directly
+     * by other methods.
+     *
+     * @param node the affected node
+     * @return the node handler for this node
+     * @throws ConfigurationRuntimeException if no compatible handler can be
+     *         found
+     */
+    @SuppressWarnings("unchecked")
+    private NodeHandler<Object> fetchHandler(Object node)
+    {
+        return (NodeHandler<Object>) resolveHandler(node);
+    }
+}

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

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

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

Added: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/combined/TestCombinedConfigurationNodeHandler.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/combined/TestCombinedConfigurationNodeHandler.java?rev=642335&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/combined/TestCombinedConfigurationNodeHandler.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/combined/TestCombinedConfigurationNodeHandler.java Fri Mar 28 12:04:41 2008
@@ -0,0 +1,443 @@
+/*
+ * 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.combined;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.configuration2.ConfigurationRuntimeException;
+import org.apache.commons.configuration2.expr.ConfigurationNodeHandler;
+import org.apache.commons.configuration2.expr.NodeHandler;
+import org.apache.commons.configuration2.expr.NodeHandlerRegistry;
+import org.apache.commons.configuration2.tree.ConfigurationNode;
+import org.apache.commons.configuration2.tree.DefaultConfigurationNode;
+import org.easymock.EasyMock;
+
+import junit.framework.TestCase;
+
+/**
+ * Test class for CombinedConfigurationNodeHandler.
+ *
+ * @author <a href="http://commons.apache.org/configuration/team-list.html">Commons
+ *         Configuration team</a>
+ * @version $Id$
+ */
+public class TestCombinedConfigurationNodeHandler extends TestCase
+{
+    /** Constant for the name of an attribute or child node. */
+    private static final String SUB_NAME = "element";
+
+    /** Constant for a value passed to the handler. */
+    private static final Object VALUE = "A value";
+
+    /** Constant for a test node. */
+    private static final Object NODE = EasyMock
+            .createNiceMock(ConfigurationNode.class);
+
+    /** A mock object for a (sub) node handler. */
+    private NodeHandler<Object> subHandler;
+
+    /** The handler to be tested. */
+    private CombinedConfigurationNodeHandler handler;
+
+    @Override
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        handler = new CombinedConfigurationNodeHandler();
+        setUpHandlerMap();
+    }
+
+    /**
+     * Initializes a map with test node handlers.
+     */
+    @SuppressWarnings("unchecked")
+    private void setUpHandlerMap()
+    {
+        Map<Class<?>, NodeHandler<?>> handlers = new HashMap<Class<?>, NodeHandler<?>>();
+        subHandler = EasyMock.createMock(NodeHandler.class);
+        handlers.put(ConfigurationNode.class, new ConfigurationNodeHandler());
+        handlers.put(getClass(), subHandler);
+        handler.setHandlers(handlers);
+    }
+
+    /**
+     * Tests the resolveHandler() method when there is no parent registry. In
+     * this case only the local map with handlers should be searched.
+     */
+    public void testResolveHandlerNoParentDirect()
+    {
+        NodeHandler<?> h = handler.resolveHandler(this);
+        assertEquals("Wrong handler returned", subHandler, h);
+    }
+
+    /**
+     * Tests the resolveHandler() method when there is no parent registry and
+     * only a handler for a super interface is registered.
+     */
+    public void testResolveHandlerNoParentSubClass()
+    {
+        NodeHandler<?> h = handler
+                .resolveHandler(new DefaultConfigurationNode());
+        assertTrue("Wrong handler returned",
+                h instanceof ConfigurationNodeHandler);
+    }
+
+    /**
+     * Tests the resolveHandler() method when a parent registry is set. In this
+     * case only this parent should be invoked.
+     */
+    public void testResolveHandlerParent()
+    {
+        NodeHandlerRegistry reg = EasyMock
+                .createMock(NodeHandlerRegistry.class);
+        reg.addSubRegistry(handler);
+        EasyMock.expect(reg.resolveHandler(this));
+        EasyMock.expectLastCall().andReturn(subHandler);
+        EasyMock.replay(reg);
+        handler.initNodeHandlerRegistry(reg);
+        assertEquals("Wrong handler returned", subHandler, handler
+                .resolveHandler(this));
+        EasyMock.verify(reg);
+    }
+
+    /**
+     * Tests the resolveHandler() method when no parent registry is set, but
+     * there are sub registries that can resolve the node class.
+     */
+    public void testResolveHandlerNoParentSubRegistry()
+    {
+        NodeHandlerRegistry subReg1 = EasyMock
+                .createMock(NodeHandlerRegistry.class);
+        NodeHandlerRegistry subReg2 = EasyMock
+                .createMock(NodeHandlerRegistry.class);
+        NodeHandlerRegistry subReg3 = EasyMock
+                .createMock(NodeHandlerRegistry.class);
+        final Object testNode = 42; // a test "node" object of class Integer
+        EasyMock.expect(subReg1.lookupHandler(testNode, false)).andReturn(null);
+        EasyMock.expect(subReg2.lookupHandler(testNode, false));
+        EasyMock.expectLastCall().andReturn(subHandler);
+        EasyMock.replay(subReg1, subReg2, subReg3);
+        handler.addSubRegistry(subReg1);
+        handler.addSubRegistry(subReg2);
+        handler.addSubRegistry(subReg3);
+        assertEquals("Wrong handler returned", subHandler, handler
+                .resolveHandler(testNode));
+        EasyMock.verify(subReg1, subReg2, subReg3);
+    }
+
+    /**
+     * Tests the resolveHandler() method when no parent registry is set, but
+     * there are sub registries that know a super class of the passed in node.
+     */
+    public void testResolveHandlerNoParentSubRegistrySubClass()
+    {
+        NodeHandlerRegistry subReg1 = EasyMock
+                .createMock(NodeHandlerRegistry.class);
+        NodeHandlerRegistry subReg2 = EasyMock
+                .createMock(NodeHandlerRegistry.class);
+        NodeHandlerRegistry subReg3 = EasyMock
+                .createMock(NodeHandlerRegistry.class);
+        final Object testNode = 42; // a test "node" object of class Integer
+        EasyMock.expect(subReg1.lookupHandler(testNode, false)).andReturn(null);
+        EasyMock.expect(subReg2.lookupHandler(testNode, false)).andReturn(null);
+        EasyMock.expect(subReg3.lookupHandler(testNode, false)).andReturn(null);
+        EasyMock.expect(subReg1.lookupHandler(testNode, true)).andReturn(null);
+        EasyMock.expect(subReg2.lookupHandler(testNode, true));
+        EasyMock.expectLastCall().andReturn(subHandler);
+        EasyMock.replay(subReg1, subReg2, subReg3);
+        handler.addSubRegistry(subReg1);
+        handler.addSubRegistry(subReg2);
+        handler.addSubRegistry(subReg3);
+        assertEquals("Wrong handler returned", subHandler, handler
+                .resolveHandler(testNode));
+        EasyMock.verify(subReg1, subReg2, subReg3);
+    }
+
+    /**
+     * Tests the resolveHandler() method when there is a parent registry and sub
+     * registries. In this case only the parent is invoked.
+     */
+    public void testResolveHandlerParentAndSubRegistry()
+    {
+        NodeHandlerRegistry reg = EasyMock
+                .createMock(NodeHandlerRegistry.class);
+        NodeHandlerRegistry subReg = EasyMock
+                .createMock(NodeHandlerRegistry.class);
+        reg.addSubRegistry(handler);
+        EasyMock.expect(reg.resolveHandler(this));
+        EasyMock.expectLastCall().andReturn(subHandler);
+        EasyMock.replay(reg, subReg);
+        handler.initNodeHandlerRegistry(reg);
+        handler.addSubRegistry(subReg);
+        assertEquals("Wrong handler returned", subHandler, handler
+                .resolveHandler(this));
+        EasyMock.verify(reg, subReg);
+    }
+
+    /**
+     * Tests resolving a node, for which no handler can be found. This should
+     * cause an exception.
+     */
+    public void testResolveHandlerNoParentUnknown()
+    {
+        NodeHandlerRegistry subReg = EasyMock
+                .createMock(NodeHandlerRegistry.class);
+        final Object testNode = 42;
+        EasyMock.expect(subReg.lookupHandler(testNode, false)).andReturn(null);
+        EasyMock.expect(subReg.lookupHandler(testNode, true)).andReturn(null);
+        EasyMock.replay(subReg);
+        handler.addSubRegistry(subReg);
+        try
+        {
+            handler.resolveHandler(testNode);
+            fail("No exception for unknown node type!");
+        }
+        catch (ConfigurationRuntimeException crex)
+        {
+            // ok
+        }
+    }
+
+    /**
+     * Tests setting the node handler registry to null.
+     */
+    public void testInitNodeHandlerRegistryNull()
+    {
+        handler.initNodeHandlerRegistry(null);
+        assertNull("A parent registry is set", handler.getParentRegistry());
+    }
+
+    /**
+     * Tests initializing the node handler factory. The handler should register
+     * itself as a sub registry.
+     */
+    public void testInitNodeHandlerRegistry()
+    {
+        NodeHandlerRegistry registry = EasyMock
+                .createMock(NodeHandlerRegistry.class);
+        registry.addSubRegistry(handler);
+        EasyMock.replay(registry);
+        handler.initNodeHandlerRegistry(registry);
+        assertEquals("Parent registry not set", registry, handler
+                .getParentRegistry());
+        EasyMock.verify(registry);
+    }
+
+    /**
+     * Tests the addAttributeValue() implementation.
+     */
+    public void testAddAttributeValue()
+    {
+        subHandler.addAttributeValue(this, SUB_NAME, VALUE);
+        EasyMock.replay(subHandler);
+        handler.addAttributeValue(this, SUB_NAME, VALUE);
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the addChild() implementation.
+     */
+    public void testAddChild()
+    {
+        subHandler.addChild(this, SUB_NAME);
+        EasyMock.expectLastCall().andReturn(NODE);
+        EasyMock.replay(subHandler);
+        assertEquals("Wrong child node", NODE, handler.addChild(this, SUB_NAME));
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the getAttributeValue() implementation.
+     */
+    public void testGetAttributeValue()
+    {
+        EasyMock.expect(subHandler.getAttributeValue(this, SUB_NAME))
+                .andReturn(VALUE);
+        EasyMock.replay(subHandler);
+        assertEquals("Wrong attribute value", VALUE, handler.getAttributeValue(
+                this, SUB_NAME));
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the getAttributes() implementation.
+     */
+    public void testGetAttributes()
+    {
+        List<String> attrs = new ArrayList<String>();
+        attrs.add(SUB_NAME);
+        EasyMock.expect(subHandler.getAttributes(this)).andReturn(attrs);
+        EasyMock.replay(subHandler);
+        assertSame("Wrong attribute list", attrs, handler.getAttributes(this));
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the getChild() implementation.
+     */
+    public void testGetChild()
+    {
+        EasyMock.expect(subHandler.getChild(this, 1)).andReturn(NODE);
+        EasyMock.replay(subHandler);
+        assertEquals("Wrong child node", NODE, handler.getChild(this, 1));
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the getChildren() implementation.
+     */
+    public void testGetChildren()
+    {
+        List<Object> children = new ArrayList<Object>();
+        children.add(NODE);
+        EasyMock.expect(subHandler.getChildren(this)).andReturn(children);
+        EasyMock.replay(subHandler);
+        assertSame("Wrong children list", children, handler.getChildren(this));
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the getChildren(String) implementation.
+     */
+    public void testGetChildrenName()
+    {
+        List<Object> children = new ArrayList<Object>();
+        children.add(NODE);
+        EasyMock.expect(subHandler.getChildren(this, SUB_NAME)).andReturn(
+                children);
+        EasyMock.replay(subHandler);
+        assertSame("Wrong children list", children, handler.getChildren(this,
+                SUB_NAME));
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the getChildrenCount() implementation.
+     */
+    public void testGetChildrenCount()
+    {
+        final int count = 10;
+        EasyMock.expect(subHandler.getChildrenCount(this, SUB_NAME)).andReturn(
+                count);
+        EasyMock.replay(subHandler);
+        assertEquals("Wrong number of child nodes", count, handler
+                .getChildrenCount(this, SUB_NAME));
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the getParent() implementation.
+     */
+    public void testGetParent()
+    {
+        EasyMock.expect(subHandler.getParent(this)).andReturn(NODE);
+        EasyMock.replay(subHandler);
+        assertEquals("Wrong parent node", NODE, handler.getParent(this));
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the getValue() implementation.
+     */
+    public void testGetValue()
+    {
+        EasyMock.expect(subHandler.getValue(this)).andReturn(VALUE);
+        EasyMock.replay(subHandler);
+        assertEquals("Wrong value", VALUE, handler.getValue(this));
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the hasAttributes() implementation.
+     */
+    public void testHasAttributes()
+    {
+        EasyMock.expect(subHandler.hasAttributes(this)).andReturn(Boolean.TRUE);
+        EasyMock.replay(subHandler);
+        assertTrue("No attributes", handler.hasAttributes(this));
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the isDefined() implementation.
+     */
+    public void testIsDefined()
+    {
+        EasyMock.expect(subHandler.isDefined(this)).andReturn(Boolean.TRUE);
+        EasyMock.replay(subHandler);
+        assertTrue("Not defined", handler.isDefined(this));
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the nodeName() implementation.
+     */
+    public void testNodeName()
+    {
+        EasyMock.expect(subHandler.nodeName(this)).andReturn(SUB_NAME);
+        EasyMock.replay(subHandler);
+        assertEquals("Wrong node name", SUB_NAME, handler.nodeName(this));
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the removeAttribute() implementation.
+     */
+    public void testRemoveAttribute()
+    {
+        subHandler.removeAttribute(this, SUB_NAME);
+        EasyMock.replay(subHandler);
+        handler.removeAttribute(this, SUB_NAME);
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the removeChild() implementation.
+     */
+    public void testRemoveChild()
+    {
+        subHandler.removeChild(this, NODE);
+        EasyMock.replay(subHandler);
+        handler.removeChild(this, NODE);
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the setAttributeValue() implementation.
+     */
+    public void testSetAttributeValue()
+    {
+        subHandler.setAttributeValue(this, SUB_NAME, VALUE);
+        EasyMock.replay(subHandler);
+        handler.setAttributeValue(this, SUB_NAME, VALUE);
+        EasyMock.verify(subHandler);
+    }
+
+    /**
+     * Tests the setValue() implementation.
+     */
+    public void testSetValue()
+    {
+        subHandler.setValue(this, VALUE);
+        EasyMock.replay(subHandler);
+        handler.setValue(this, VALUE);
+        EasyMock.verify(subHandler);
+    }
+}

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

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

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