001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.configuration2;
019
020import java.util.ArrayList;
021import java.util.Collection;
022import java.util.Collections;
023import java.util.HashMap;
024import java.util.Iterator;
025import java.util.LinkedHashSet;
026import java.util.LinkedList;
027import java.util.List;
028import java.util.Map;
029import java.util.Set;
030import java.util.Stack;
031
032import org.apache.commons.configuration2.event.ConfigurationEvent;
033import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
034import org.apache.commons.configuration2.sync.NoOpSynchronizer;
035import org.apache.commons.configuration2.tree.ConfigurationNodeVisitorAdapter;
036import org.apache.commons.configuration2.tree.DefaultExpressionEngine;
037import org.apache.commons.configuration2.tree.ExpressionEngine;
038import org.apache.commons.configuration2.tree.NodeAddData;
039import org.apache.commons.configuration2.tree.NodeHandler;
040import org.apache.commons.configuration2.tree.NodeKeyResolver;
041import org.apache.commons.configuration2.tree.NodeModel;
042import org.apache.commons.configuration2.tree.NodeTreeWalker;
043import org.apache.commons.configuration2.tree.NodeUpdateData;
044import org.apache.commons.configuration2.tree.QueryResult;
045
046/**
047 * <p>
048 * A specialized configuration class that extends its base class by the ability
049 * of keeping more structure in the stored properties.
050 * </p>
051 * <p>
052 * There are some sources of configuration data that cannot be stored very well
053 * in a {@code BaseConfiguration} object because then their structure is lost.
054 * This is for instance true for XML documents. This class can deal with such
055 * structured configuration sources by storing the properties in a tree-like
056 * organization. The exact storage structure of the underlying data does not
057 * matter for the configuration instance; it uses a {@link NodeModel} object for
058 * accessing it.
059 * </p>
060 * <p>
061 * The hierarchical organization allows for a more sophisticated access to
062 * single properties. As an example consider the following XML document:
063 * </p>
064 *
065 * <pre>
066 * &lt;database&gt;
067 *   &lt;tables&gt;
068 *     &lt;table&gt;
069 *       &lt;name&gt;users&lt;/name&gt;
070 *       &lt;fields&gt;
071 *         &lt;field&gt;
072 *           &lt;name&gt;lid&lt;/name&gt;
073 *           &lt;type&gt;long&lt;/name&gt;
074 *         &lt;/field&gt;
075 *         &lt;field&gt;
076 *           &lt;name&gt;usrName&lt;/name&gt;
077 *           &lt;type&gt;java.lang.String&lt;/type&gt;
078 *         &lt;/field&gt;
079 *        ...
080 *       &lt;/fields&gt;
081 *     &lt;/table&gt;
082 *     &lt;table&gt;
083 *       &lt;name&gt;documents&lt;/name&gt;
084 *       &lt;fields&gt;
085 *         &lt;field&gt;
086 *           &lt;name&gt;docid&lt;/name&gt;
087 *           &lt;type&gt;long&lt;/type&gt;
088 *         &lt;/field&gt;
089 *         ...
090 *       &lt;/fields&gt;
091 *     &lt;/table&gt;
092 *     ...
093 *   &lt;/tables&gt;
094 * &lt;/database&gt;
095 * </pre>
096 *
097 * <p>
098 * If this document is parsed and stored in a hierarchical configuration object
099 * (which can be done by one of the sub classes), there are enhanced
100 * possibilities of accessing properties. Per default, the keys for querying
101 * information can contain indices that select a specific element if there are
102 * multiple hits.
103 * </p>
104 * <p>
105 * For instance the key {@code tables.table(0).name} can be used to find out the
106 * name of the first table. In opposite {@code tables.table.name} would return a
107 * collection with the names of all available tables. Similarly the key
108 * {@code tables.table(1).fields.field.name} returns a collection with the names
109 * of all fields of the second table. If another index is added after the
110 * {@code field} element, a single field can be accessed:
111 * {@code tables.table(1).fields.field(0).name}.
112 * </p>
113 * <p>
114 * There is a {@code getMaxIndex()} method that returns the maximum allowed
115 * index that can be added to a given property key. This method can be used to
116 * iterate over all values defined for a certain property.
117 * </p>
118 * <p>
119 * Since the 1.3 release of <em>Commons Configuration</em> hierarchical
120 * configurations support an <em>expression engine</em>. This expression engine
121 * is responsible for evaluating the passed in configuration keys and map them
122 * to the stored properties. The examples above are valid for the default
123 * expression engine, which is used when a new
124 * {@code AbstractHierarchicalConfiguration} instance is created. With the
125 * {@code setExpressionEngine()} method a different expression engine can be
126 * set. For instance with
127 * {@link org.apache.commons.configuration2.tree.xpath.XPathExpressionEngine}
128 * there is an expression engine available that supports configuration keys in
129 * XPATH syntax.
130 * </p>
131 * <p>
132 * In addition to the events common for all configuration classes, hierarchical
133 * configurations support some more events that correspond to some specific
134 * methods and features. For those events specific event type constants in
135 * {@code ConfigurationEvent} exist:
136 * </p>
137 * <dl>
138 * <dt><em>ADD_NODES</em></dt>
139 * <dd>The {@code addNodes()} method was called; the event object contains the
140 * key, to which the nodes were added, and a collection with the new nodes as
141 * value.</dd>
142 * <dt><em>CLEAR_TREE</em></dt>
143 * <dd>The {@code clearTree()} method was called; the event object stores the
144 * key of the removed sub tree.</dd>
145 * <dt><em>SUBNODE_CHANGED</em></dt>
146 * <dd>A {@code SubnodeConfiguration} that was created from this configuration
147 * has been changed. The value property of the event object contains the
148 * original event object as it was sent by the subnode configuration.</dd>
149 * </dl>
150 * <p>
151 * Whether an {@code AbstractHierarchicalConfiguration} object is thread-safe or
152 * not depends on the underlying {@code NodeModel} and the
153 * {@link org.apache.commons.configuration2.sync.Synchronizer Synchronizer}
154 * it is associated with. Some {@code NodeModel} implementations are inherently
155 * thread-safe; they do not require a special {@code Synchronizer}. (Per
156 * default, a dummy {@code Synchronizer} is used which is not thread-safe!) The
157 * methods for querying or updating configuration data invoke this
158 * {@code Synchronizer} accordingly. When accessing the configuration's root
159 * node directly, the client application is responsible for proper
160 * synchronization. This is achieved by calling the methods
161 * {@link #lock(org.apache.commons.configuration2.sync.LockMode) lock()},
162 * and {@link #unlock(org.apache.commons.configuration2.sync.LockMode) unlock()} with a proper
163 * {@link org.apache.commons.configuration2.sync.LockMode LockMode} argument.
164 * In any case, it is recommended to not access the
165 * root node directly, but to use corresponding methods for querying or updating
166 * configuration data instead. Direct manipulations of a configuration's node
167 * structure circumvent many internal mechanisms and thus can cause undesired
168 * effects. For concrete subclasses dealing with specific node structures, this
169 * situation may be different.
170 * </p>
171 *
172 * @since 2.0
173 * @param <T> the type of the nodes managed by this hierarchical configuration
174 */
175public abstract class AbstractHierarchicalConfiguration<T> extends AbstractConfiguration
176    implements Cloneable, NodeKeyResolver<T>, HierarchicalConfiguration<T>
177{
178    /** The model for managing the data stored in this configuration. */
179    private NodeModel<T> model;
180
181    /** Stores the expression engine for this instance.*/
182    private ExpressionEngine expressionEngine;
183
184    /**
185     * Creates a new instance of {@code AbstractHierarchicalConfiguration} and
186     * sets the {@code NodeModel} to be used.
187     *
188     * @param nodeModel the {@code NodeModel}
189     */
190    protected AbstractHierarchicalConfiguration(final NodeModel<T> nodeModel)
191    {
192        model = nodeModel;
193    }
194
195    /**
196     * {@inheritDoc} This implementation handles synchronization and delegates
197     * to {@code getRootElementNameInternal()}.
198     */
199    @Override
200    public final String getRootElementName()
201    {
202        beginRead(false);
203        try
204        {
205            return getRootElementNameInternal();
206        }
207        finally
208        {
209            endRead();
210        }
211    }
212
213    /**
214     * Actually obtains the name of the root element. This method is called by
215     * {@code getRootElementName()}. It just returns the name of the root node.
216     * Subclasses that treat the root element name differently can override this
217     * method.
218     *
219     * @return the name of this configuration's root element
220     */
221    protected String getRootElementNameInternal()
222    {
223        final NodeHandler<T> nodeHandler = getModel().getNodeHandler();
224        return nodeHandler.nodeName(nodeHandler.getRootNode());
225    }
226
227    /**
228     * {@inheritDoc} This implementation returns the configuration's
229     * {@code NodeModel}. It is guarded by the current {@code Synchronizer}.
230     */
231    @Override
232    public NodeModel<T> getNodeModel()
233    {
234        beginRead(false);
235        try
236        {
237            return getModel();
238        }
239        finally
240        {
241            endRead();
242        }
243    }
244
245    /**
246     * Returns the expression engine used by this configuration. This method
247     * will never return <b>null</b>; if no specific expression engine was set,
248     * the default expression engine will be returned.
249     *
250     * @return the current expression engine
251     * @since 1.3
252     */
253    @Override
254    public ExpressionEngine getExpressionEngine()
255    {
256        return expressionEngine != null ? expressionEngine
257                : DefaultExpressionEngine.INSTANCE;
258    }
259
260    /**
261     * Sets the expression engine to be used by this configuration. All property
262     * keys this configuration has to deal with will be interpreted by this
263     * engine.
264     *
265     * @param expressionEngine the new expression engine; can be <b>null</b>,
266     * then the default expression engine will be used
267     * @since 1.3
268     */
269    @Override
270    public void setExpressionEngine(final ExpressionEngine expressionEngine)
271    {
272        this.expressionEngine = expressionEngine;
273    }
274
275    /**
276     * Fetches the specified property. This task is delegated to the associated
277     * expression engine.
278     *
279     * @param key the key to be looked up
280     * @return the found value
281     */
282    @Override
283    protected Object getPropertyInternal(final String key)
284    {
285        final List<QueryResult<T>> results = fetchNodeList(key);
286
287        if (results.isEmpty())
288        {
289            return null;
290        }
291        final NodeHandler<T> handler = getModel().getNodeHandler();
292        final List<Object> list = new ArrayList<>();
293        for (final QueryResult<T> result : results)
294        {
295            final Object value = valueFromResult(result, handler);
296            if (value != null)
297            {
298                list.add(value);
299            }
300        }
301
302        if (list.size() < 1)
303        {
304            return null;
305        }
306        return list.size() == 1 ? list.get(0) : list;
307    }
308
309    /**
310     * Adds the property with the specified key. This task will be delegated to
311     * the associated {@code ExpressionEngine}, so the passed in key
312     * must match the requirements of this implementation.
313     *
314     * @param key the key of the new property
315     * @param obj the value of the new property
316     */
317    @Override
318    protected void addPropertyInternal(final String key, final Object obj)
319    {
320        addPropertyToModel(key, getListDelimiterHandler().parse(obj));
321    }
322
323    /**
324     * {@inheritDoc} This method is not called in the normal way (via
325     * {@code addProperty()} for hierarchical configurations because all values
326     * to be added for the property have to be passed to the model in a single
327     * step. However, to allow derived classes to add an arbitrary value as an
328     * object, a special implementation is provided here. The passed in object
329     * is not parsed as a list, but passed directly as only value to the model.
330     */
331    @Override
332    protected void addPropertyDirect(final String key, final Object value)
333    {
334        addPropertyToModel(key, Collections.singleton(value));
335    }
336
337    /**
338     * Helper method for executing an add property operation on the model.
339     *
340     * @param key the key of the new property
341     * @param values the values to be added for this property
342     */
343    private void addPropertyToModel(final String key, final Iterable<?> values)
344    {
345        getModel().addProperty(key, values, this);
346    }
347
348    /**
349     * Adds a collection of nodes at the specified position of the configuration
350     * tree. This method works similar to {@code addProperty()}, but
351     * instead of a single property a whole collection of nodes can be added -
352     * and thus complete configuration sub trees. E.g. with this method it is
353     * possible to add parts of another {@code BaseHierarchicalConfiguration}
354     * object to this object. If the passed in key refers to
355     * an existing and unique node, the new nodes are added to this node.
356     * Otherwise a new node will be created at the specified position in the
357     * hierarchy. Implementation node: This method performs some book-keeping
358     * and then delegates to {@code addNodesInternal()}.
359     *
360     * @param key the key where the nodes are to be added; can be <b>null</b>,
361     * then they are added to the root node
362     * @param nodes a collection with the {@code Node} objects to be
363     * added
364     */
365    @Override
366    public final void addNodes(final String key, final Collection<? extends T> nodes)
367    {
368        if (nodes == null || nodes.isEmpty())
369        {
370            return;
371        }
372
373        beginWrite(false);
374        try
375        {
376            fireEvent(ConfigurationEvent.ADD_NODES, key, nodes, true);
377            addNodesInternal(key, nodes);
378            fireEvent(ConfigurationEvent.ADD_NODES, key, nodes, false);
379        }
380        finally
381        {
382            endWrite();
383        }
384    }
385
386    /**
387     * Actually adds a collection of new nodes to this configuration. This
388     * method is called by {@code addNodes()}. It can be overridden by
389     * subclasses that need to adapt this operation.
390     *
391     * @param key the key where the nodes are to be added; can be <b>null</b>,
392     *        then they are added to the root node
393     * @param nodes a collection with the {@code Node} objects to be added
394     * @since 2.0
395     */
396    protected void addNodesInternal(final String key, final Collection<? extends T> nodes)
397    {
398        getModel().addNodes(key, nodes, this);
399    }
400
401    /**
402     * Checks if this configuration is empty. Empty means that there are no keys
403     * with any values, though there can be some (empty) nodes.
404     *
405     * @return a flag if this configuration is empty
406     */
407    @Override
408    protected boolean isEmptyInternal()
409    {
410        return !nodeDefined(getModel().getNodeHandler().getRootNode());
411    }
412
413    /**
414     * Checks if the specified key is contained in this configuration. Note that
415     * for this configuration the term &quot;contained&quot; means that the key
416     * has an associated value. If there is a node for this key that has no
417     * value but children (either defined or undefined), this method will still
418     * return <b>false </b>.
419     *
420     * @param key the key to be checked
421     * @return a flag if this key is contained in this configuration
422     */
423    @Override
424    protected boolean containsKeyInternal(final String key)
425    {
426        return getPropertyInternal(key) != null;
427    }
428
429    /**
430     * Sets the value of the specified property.
431     *
432     * @param key the key of the property to set
433     * @param value the new value of this property
434     */
435    @Override
436    protected void setPropertyInternal(final String key, final Object value)
437    {
438        getModel().setProperty(key, value, this);
439    }
440
441    /**
442     * {@inheritDoc} This implementation delegates to the expression engine.
443     */
444    @Override
445    public List<QueryResult<T>> resolveKey(final T root, final String key,
446            final NodeHandler<T> handler)
447    {
448        return getExpressionEngine().query(root, key, handler);
449    }
450
451    /**
452     * {@inheritDoc} This implementation delegates to {@code resolveKey()} and
453     * then filters out attribute results.
454     */
455    @Override
456    public List<T> resolveNodeKey(final T root, final String key, final NodeHandler<T> handler)
457    {
458        final List<QueryResult<T>> results = resolveKey(root, key, handler);
459        final List<T> targetNodes = new LinkedList<>();
460        for (final QueryResult<T> result : results)
461        {
462            if (!result.isAttributeResult())
463            {
464                targetNodes.add(result.getNode());
465            }
466        }
467        return targetNodes;
468    }
469
470    /**
471     * {@inheritDoc} This implementation delegates to the expression engine.
472     */
473    @Override
474    public NodeAddData<T> resolveAddKey(final T root, final String key,
475            final NodeHandler<T> handler)
476    {
477        return getExpressionEngine().prepareAdd(root, key, handler);
478    }
479
480    /**
481     * {@inheritDoc} This implementation executes a query for the given key and
482     * constructs a {@code NodeUpdateData} object based on the results. It
483     * determines which nodes need to be changed and whether new ones need to be
484     * added or existing ones need to be removed.
485     */
486    @Override
487    public NodeUpdateData<T> resolveUpdateKey(final T root, final String key,
488            final Object newValue, final NodeHandler<T> handler)
489    {
490        final Iterator<QueryResult<T>> itNodes = fetchNodeList(key).iterator();
491        final Iterator<?> itValues = getListDelimiterHandler().parse(newValue).iterator();
492        final Map<QueryResult<T>, Object> changedValues =
493                new HashMap<>();
494        Collection<Object> additionalValues = null;
495        Collection<QueryResult<T>> removedItems = null;
496
497        while (itNodes.hasNext() && itValues.hasNext())
498        {
499            changedValues.put(itNodes.next(), itValues.next());
500        }
501
502        // Add additional nodes if necessary
503        if (itValues.hasNext())
504        {
505            additionalValues = new LinkedList<>();
506            while (itValues.hasNext())
507            {
508                additionalValues.add(itValues.next());
509            }
510        }
511
512        // Remove remaining nodes
513        if (itNodes.hasNext())
514        {
515            removedItems = new LinkedList<>();
516            while (itNodes.hasNext())
517            {
518                removedItems.add(itNodes.next());
519            }
520        }
521
522        return new NodeUpdateData<>(changedValues, additionalValues,
523                removedItems, key);
524    }
525
526    /**
527     * {@inheritDoc} This implementation uses the expression engine to generate a
528     * canonical key for the passed in node. For this purpose, the path to the
529     * root node has to be traversed. The cache is used to store and access keys
530     * for nodes encountered on the path.
531     */
532    @Override
533    public String nodeKey(final T node, final Map<T, String> cache, final NodeHandler<T> handler)
534    {
535        final List<T> path = new LinkedList<>();
536        T currentNode = node;
537        String key = cache.get(node);
538        while (key == null && currentNode != null)
539        {
540            path.add(0, currentNode);
541            currentNode = handler.getParent(currentNode);
542            key = cache.get(currentNode);
543        }
544
545        for (final T n : path)
546        {
547            final String currentKey = getExpressionEngine().canonicalKey(n, key, handler);
548            cache.put(n, currentKey);
549            key = currentKey;
550        }
551
552        return key;
553    }
554
555    /**
556     * Clears this configuration. This is a more efficient implementation than
557     * the one inherited from the base class. It delegates to the node model.
558     */
559    @Override
560    protected void clearInternal()
561    {
562        getModel().clear(this);
563    }
564
565    /**
566     * Removes all values of the property with the given name and of keys that
567     * start with this name. So if there is a property with the key
568     * &quot;foo&quot; and a property with the key &quot;foo.bar&quot;, a call
569     * of {@code clearTree("foo")} would remove both properties.
570     *
571     * @param key the key of the property to be removed
572     */
573    @Override
574    public final void clearTree(final String key)
575    {
576        beginWrite(false);
577        try
578        {
579            fireEvent(ConfigurationEvent.CLEAR_TREE, key, null, true);
580            final Object nodes = clearTreeInternal(key);
581            fireEvent(ConfigurationEvent.CLEAR_TREE, key, nodes, false);
582        }
583        finally
584        {
585            endWrite();
586        }
587    }
588
589    /**
590     * Actually clears the tree of elements referenced by the given key. This
591     * method is called by {@code clearTree()}. Subclasses that need to adapt
592     * this operation can override this method. This base implementation
593     * delegates to the node model.
594     *
595     * @param key the key of the property to be removed
596     * @return an object with information about the nodes that have been removed
597     *         (this is needed for firing a meaningful event of type
598     *         CLEAR_TREE)
599     * @since 2.0
600     */
601    protected Object clearTreeInternal(final String key)
602    {
603        return getModel().clearTree(key, this);
604    }
605
606    /**
607     * Removes the property with the given key. Properties with names that start
608     * with the given key (i.e. properties below the specified key in the
609     * hierarchy) won't be affected. This implementation delegates to the node+
610     * model.
611     *
612     * @param key the key of the property to be removed
613     */
614    @Override
615    protected void clearPropertyDirect(final String key)
616    {
617        getModel().clearProperty(key, this);
618    }
619
620    /**
621     * {@inheritDoc} This implementation is slightly more efficient than the
622     * default implementation. It does not iterate over the key set, but
623     * directly queries its size after it has been constructed. Note that
624     * constructing the key set is still an O(n) operation.
625     */
626    @Override
627    protected int sizeInternal()
628    {
629        return visitDefinedKeys().getKeyList().size();
630    }
631
632    /**
633     * Returns an iterator with all keys defined in this configuration.
634     * Note that the keys returned by this method will not contain any
635     * indices. This means that some structure will be lost.
636     *
637     * @return an iterator with the defined keys in this configuration
638     */
639    @Override
640    protected Iterator<String> getKeysInternal()
641    {
642        return visitDefinedKeys().getKeyList().iterator();
643    }
644
645    /**
646     * Creates a {@code DefinedKeysVisitor} and visits all defined keys with it.
647     *
648     * @return the visitor after all keys have been visited
649     */
650    private DefinedKeysVisitor visitDefinedKeys()
651    {
652        final DefinedKeysVisitor visitor = new DefinedKeysVisitor();
653        final NodeHandler<T> nodeHandler = getModel().getNodeHandler();
654        NodeTreeWalker.INSTANCE.walkDFS(nodeHandler.getRootNode(), visitor,
655                nodeHandler);
656        return visitor;
657    }
658
659    /**
660     * Returns an iterator with all keys defined in this configuration that
661     * start with the given prefix. The returned keys will not contain any
662     * indices. This implementation tries to locate a node whose key is the same
663     * as the passed in prefix. Then the subtree of this node is traversed, and
664     * the keys of all nodes encountered (including attributes) are added to the
665     * result set.
666     *
667     * @param prefix the prefix of the keys to start with
668     * @return an iterator with the found keys
669     */
670    @Override
671    protected Iterator<String> getKeysInternal(final String prefix)
672    {
673        final DefinedKeysVisitor visitor = new DefinedKeysVisitor(prefix);
674        if (containsKey(prefix))
675        {
676            // explicitly add the prefix
677            visitor.getKeyList().add(prefix);
678        }
679
680        final List<QueryResult<T>> results = fetchNodeList(prefix);
681        final NodeHandler<T> handler = getModel().getNodeHandler();
682
683        for (final QueryResult<T> result : results)
684        {
685            if (!result.isAttributeResult())
686            {
687                for (final T c : handler.getChildren(result.getNode()))
688                {
689                    NodeTreeWalker.INSTANCE.walkDFS(c, visitor, handler);
690                }
691                visitor.handleAttributeKeys(prefix, result.getNode(), handler);
692            }
693        }
694
695        return visitor.getKeyList().iterator();
696    }
697
698    /**
699     * Returns the maximum defined index for the given key. This is useful if
700     * there are multiple values for this key. They can then be addressed
701     * separately by specifying indices from 0 to the return value of this
702     * method. If the passed in key is not contained in this configuration,
703     * result is -1.
704     *
705     * @param key the key to be checked
706     * @return the maximum defined index for this key
707     */
708    @Override
709    public final int getMaxIndex(final String key)
710    {
711        beginRead(false);
712        try
713        {
714            return getMaxIndexInternal(key);
715        }
716        finally
717        {
718            endRead();
719        }
720    }
721
722    /**
723     * Actually retrieves the maximum defined index for the given key. This
724     * method is called by {@code getMaxIndex()}. Subclasses that need to adapt
725     * this operation have to override this method.
726     *
727     * @param key the key to be checked
728     * @return the maximum defined index for this key
729     * @since 2.0
730     */
731    protected int getMaxIndexInternal(final String key)
732    {
733        return fetchNodeList(key).size() - 1;
734    }
735
736    /**
737     * Creates a copy of this object. This new configuration object will contain
738     * copies of all nodes in the same structure. Registered event listeners
739     * won't be cloned; so they are not registered at the returned copy.
740     *
741     * @return the copy
742     * @since 1.2
743     */
744    @Override
745    public Object clone()
746    {
747        beginRead(false);
748        try
749        {
750            @SuppressWarnings("unchecked") // clone returns the same type
751            final
752            AbstractHierarchicalConfiguration<T> copy =
753                    (AbstractHierarchicalConfiguration<T>) super.clone();
754            copy.setSynchronizer(NoOpSynchronizer.INSTANCE);
755            copy.cloneInterpolator(this);
756            copy.setSynchronizer(ConfigurationUtils.cloneSynchronizer(getSynchronizer()));
757            copy.model = cloneNodeModel();
758
759            return copy;
760        }
761        catch (final CloneNotSupportedException cex)
762        {
763            // should not happen
764            throw new ConfigurationRuntimeException(cex);
765        }
766        finally
767        {
768            endRead();
769        }
770    }
771
772    /**
773     * Creates a clone of the node model. This method is called by
774     * {@code clone()}.
775     *
776     * @return the clone of the {@code NodeModel}
777     * @since 2.0
778     */
779    protected abstract NodeModel<T> cloneNodeModel();
780
781    /**
782     * Helper method for resolving the specified key.
783     *
784     * @param key the key
785     * @return a list with all results selected by this key
786     */
787    protected List<QueryResult<T>> fetchNodeList(final String key)
788    {
789        final NodeHandler<T> nodeHandler = getModel().getNodeHandler();
790        return resolveKey(nodeHandler.getRootNode(), key, nodeHandler);
791    }
792
793    /**
794     * Checks if the specified node is defined.
795     *
796     * @param node the node to be checked
797     * @return a flag if this node is defined
798     */
799    protected boolean nodeDefined(final T node)
800    {
801        final DefinedVisitor<T> visitor = new DefinedVisitor<>();
802        NodeTreeWalker.INSTANCE.walkBFS(node, visitor, getModel().getNodeHandler());
803        return visitor.isDefined();
804    }
805
806    /**
807     * Returns the {@code NodeModel} used by this configuration. This method is
808     * intended for internal use only. Access to the model is granted without
809     * any synchronization. This is in contrast to the &quot;official&quot;
810     * {@code getNodeModel()} method which is guarded by the configuration's
811     * {@code Synchronizer}.
812     *
813     * @return the node model
814     */
815    protected NodeModel<T> getModel()
816    {
817        return model;
818    }
819
820    /**
821     * Extracts the value from a query result.
822     *
823     * @param result the {@code QueryResult}
824     * @param handler the {@code NodeHandler}
825     * @return the value of this result (may be <b>null</b>)
826     */
827    private Object valueFromResult(final QueryResult<T> result, final NodeHandler<T> handler)
828    {
829        return result.isAttributeResult() ? result.getAttributeValue(handler)
830                : handler.getValue(result.getNode());
831    }
832
833    /**
834     * A specialized visitor that checks if a node is defined.
835     * &quot;Defined&quot; in this terms means that the node or at least one of
836     * its sub nodes is associated with a value.
837     *
838     * @param <T> the type of the nodes managed by this hierarchical configuration
839     */
840    private static class DefinedVisitor<T> extends
841            ConfigurationNodeVisitorAdapter<T>
842    {
843        /** Stores the defined flag. */
844        private boolean defined;
845
846        /**
847         * Checks if iteration should be stopped. This can be done if the first
848         * defined node is found.
849         *
850         * @return a flag if iteration should be stopped
851         */
852        @Override
853        public boolean terminate()
854        {
855            return isDefined();
856        }
857
858        /**
859         * Visits the node. Checks if a value is defined.
860         *
861         * @param node the actual node
862         */
863        @Override
864        public void visitBeforeChildren(final T node, final NodeHandler<T> handler)
865        {
866            defined =
867                    handler.getValue(node) != null
868                            || !handler.getAttributes(node).isEmpty();
869        }
870
871        /**
872         * Returns the defined flag.
873         *
874         * @return the defined flag
875         */
876        public boolean isDefined()
877        {
878            return defined;
879        }
880    }
881
882    /**
883     * A specialized visitor that fills a list with keys that are defined in a
884     * node hierarchy.
885     */
886    private class DefinedKeysVisitor extends
887            ConfigurationNodeVisitorAdapter<T>
888    {
889        /** Stores the list to be filled. */
890        private final Set<String> keyList;
891
892        /** A stack with the keys of the already processed nodes. */
893        private final Stack<String> parentKeys;
894
895        /**
896         * Default constructor.
897         */
898        public DefinedKeysVisitor()
899        {
900            keyList = new LinkedHashSet<>();
901            parentKeys = new Stack<>();
902        }
903
904        /**
905         * Creates a new {@code DefinedKeysVisitor} instance and sets the
906         * prefix for the keys to fetch.
907         *
908         * @param prefix the prefix
909         */
910        public DefinedKeysVisitor(final String prefix)
911        {
912            this();
913            parentKeys.push(prefix);
914        }
915
916        /**
917         * Returns the list with all defined keys.
918         *
919         * @return the list with the defined keys
920         */
921        public Set<String> getKeyList()
922        {
923            return keyList;
924        }
925
926        /**
927         * {@inheritDoc} This implementation removes this
928         * node's key from the stack.
929         */
930        @Override
931        public void visitAfterChildren(final T node, final NodeHandler<T> handler)
932        {
933            parentKeys.pop();
934        }
935
936        /**
937         * {@inheritDoc} If this node has a value, its key is added
938         * to the internal list.
939         */
940        @Override
941        public void visitBeforeChildren(final T node, final NodeHandler<T> handler)
942        {
943            final String parentKey = parentKeys.isEmpty() ? null
944                    : parentKeys.peek();
945            final String key = getExpressionEngine().nodeKey(node, parentKey, handler);
946            parentKeys.push(key);
947            if (handler.getValue(node) != null)
948            {
949                keyList.add(key);
950            }
951            handleAttributeKeys(key, node, handler);
952        }
953
954        /**
955         * Appends all attribute keys of the current node.
956         *
957         * @param parentKey the parent key
958         * @param node the current node
959         * @param handler the {@code NodeHandler}
960         */
961        public void handleAttributeKeys(final String parentKey, final T node,
962                final NodeHandler<T> handler)
963        {
964            for (final String attr : handler.getAttributes(node))
965            {
966                keyList.add(getExpressionEngine().attributeKey(parentKey, attr));
967            }
968        }
969    }
970
971    @Override
972    public String toString()
973    {
974        return super.toString() + "(" + getRootElementNameInternal() + ")";
975    }
976}