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 * @version $Id: AbstractHierarchicalConfiguration.java 1842194 2018-09-27 22:24:23Z ggregory $
173 * @since 2.0
174 * @param <T> the type of the nodes managed by this hierarchical configuration
175 */
176public abstract class AbstractHierarchicalConfiguration<T> extends AbstractConfiguration
177    implements Cloneable, NodeKeyResolver<T>, HierarchicalConfiguration<T>
178{
179    /** The model for managing the data stored in this configuration. */
180    private NodeModel<T> model;
181
182    /** Stores the expression engine for this instance.*/
183    private ExpressionEngine expressionEngine;
184
185    /**
186     * Creates a new instance of {@code AbstractHierarchicalConfiguration} and
187     * sets the {@code NodeModel} to be used.
188     *
189     * @param nodeModel the {@code NodeModel}
190     */
191    protected AbstractHierarchicalConfiguration(final NodeModel<T> nodeModel)
192    {
193        model = nodeModel;
194    }
195
196    /**
197     * {@inheritDoc} This implementation handles synchronization and delegates
198     * to {@code getRootElementNameInternal()}.
199     */
200    @Override
201    public final String getRootElementName()
202    {
203        beginRead(false);
204        try
205        {
206            return getRootElementNameInternal();
207        }
208        finally
209        {
210            endRead();
211        }
212    }
213
214    /**
215     * Actually obtains the name of the root element. This method is called by
216     * {@code getRootElementName()}. It just returns the name of the root node.
217     * Subclasses that treat the root element name differently can override this
218     * method.
219     *
220     * @return the name of this configuration's root element
221     */
222    protected String getRootElementNameInternal()
223    {
224        final NodeHandler<T> nodeHandler = getModel().getNodeHandler();
225        return nodeHandler.nodeName(nodeHandler.getRootNode());
226    }
227
228    /**
229     * {@inheritDoc} This implementation returns the configuration's
230     * {@code NodeModel}. It is guarded by the current {@code Synchronizer}.
231     */
232    @Override
233    public NodeModel<T> getNodeModel()
234    {
235        beginRead(false);
236        try
237        {
238            return getModel();
239        }
240        finally
241        {
242            endRead();
243        }
244    }
245
246    /**
247     * Returns the expression engine used by this configuration. This method
248     * will never return <b>null</b>; if no specific expression engine was set,
249     * the default expression engine will be returned.
250     *
251     * @return the current expression engine
252     * @since 1.3
253     */
254    @Override
255    public ExpressionEngine getExpressionEngine()
256    {
257        return (expressionEngine != null) ? expressionEngine
258                : DefaultExpressionEngine.INSTANCE;
259    }
260
261    /**
262     * Sets the expression engine to be used by this configuration. All property
263     * keys this configuration has to deal with will be interpreted by this
264     * engine.
265     *
266     * @param expressionEngine the new expression engine; can be <b>null</b>,
267     * then the default expression engine will be used
268     * @since 1.3
269     */
270    @Override
271    public void setExpressionEngine(final ExpressionEngine expressionEngine)
272    {
273        this.expressionEngine = expressionEngine;
274    }
275
276    /**
277     * Fetches the specified property. This task is delegated to the associated
278     * expression engine.
279     *
280     * @param key the key to be looked up
281     * @return the found value
282     */
283    @Override
284    protected Object getPropertyInternal(final String key)
285    {
286        final List<QueryResult<T>> results = fetchNodeList(key);
287
288        if (results.isEmpty())
289        {
290            return null;
291        }
292        final NodeHandler<T> handler = getModel().getNodeHandler();
293        final List<Object> list = new ArrayList<>();
294        for (final QueryResult<T> result : results)
295        {
296            final Object value = valueFromResult(result, handler);
297            if (value != null)
298            {
299                list.add(value);
300            }
301        }
302
303        if (list.size() < 1)
304        {
305            return null;
306        }
307        return (list.size() == 1) ? list.get(0) : list;
308    }
309
310    /**
311     * Adds the property with the specified key. This task will be delegated to
312     * the associated {@code ExpressionEngine}, so the passed in key
313     * must match the requirements of this implementation.
314     *
315     * @param key the key of the new property
316     * @param obj the value of the new property
317     */
318    @Override
319    protected void addPropertyInternal(final String key, final Object obj)
320    {
321        addPropertyToModel(key, getListDelimiterHandler().parse(obj));
322    }
323
324    /**
325     * {@inheritDoc} This method is not called in the normal way (via
326     * {@code addProperty()} for hierarchical configurations because all values
327     * to be added for the property have to be passed to the model in a single
328     * step. However, to allow derived classes to add an arbitrary value as an
329     * object, a special implementation is provided here. The passed in object
330     * is not parsed as a list, but passed directly as only value to the model.
331     */
332    @Override
333    protected void addPropertyDirect(final String key, final Object value)
334    {
335        addPropertyToModel(key, Collections.singleton(value));
336    }
337
338    /**
339     * Helper method for executing an add property operation on the model.
340     *
341     * @param key the key of the new property
342     * @param values the values to be added for this property
343     */
344    private void addPropertyToModel(final String key, final Iterable<?> values)
345    {
346        getModel().addProperty(key, values, this);
347    }
348
349    /**
350     * Adds a collection of nodes at the specified position of the configuration
351     * tree. This method works similar to {@code addProperty()}, but
352     * instead of a single property a whole collection of nodes can be added -
353     * and thus complete configuration sub trees. E.g. with this method it is
354     * possible to add parts of another {@code BaseHierarchicalConfiguration}
355     * object to this object. If the passed in key refers to
356     * an existing and unique node, the new nodes are added to this node.
357     * Otherwise a new node will be created at the specified position in the
358     * hierarchy. Implementation node: This method performs some book-keeping
359     * and then delegates to {@code addNodesInternal()}.
360     *
361     * @param key the key where the nodes are to be added; can be <b>null</b>,
362     * then they are added to the root node
363     * @param nodes a collection with the {@code Node} objects to be
364     * added
365     */
366    @Override
367    public final void addNodes(final String key, final Collection<? extends T> nodes)
368    {
369        if (nodes == null || nodes.isEmpty())
370        {
371            return;
372        }
373
374        beginWrite(false);
375        try
376        {
377            fireEvent(ConfigurationEvent.ADD_NODES, key, nodes, true);
378            addNodesInternal(key, nodes);
379            fireEvent(ConfigurationEvent.ADD_NODES, key, nodes, false);
380        }
381        finally
382        {
383            endWrite();
384        }
385    }
386
387    /**
388     * Actually adds a collection of new nodes to this configuration. This
389     * method is called by {@code addNodes()}. It can be overridden by
390     * subclasses that need to adapt this operation.
391     *
392     * @param key the key where the nodes are to be added; can be <b>null</b>,
393     *        then they are added to the root node
394     * @param nodes a collection with the {@code Node} objects to be added
395     * @since 2.0
396     */
397    protected void addNodesInternal(final String key, final Collection<? extends T> nodes)
398    {
399        getModel().addNodes(key, nodes, this);
400    }
401
402    /**
403     * Checks if this configuration is empty. Empty means that there are no keys
404     * with any values, though there can be some (empty) nodes.
405     *
406     * @return a flag if this configuration is empty
407     */
408    @Override
409    protected boolean isEmptyInternal()
410    {
411        return !nodeDefined(getModel().getNodeHandler().getRootNode());
412    }
413
414    /**
415     * Checks if the specified key is contained in this configuration. Note that
416     * for this configuration the term &quot;contained&quot; means that the key
417     * has an associated value. If there is a node for this key that has no
418     * value but children (either defined or undefined), this method will still
419     * return <b>false </b>.
420     *
421     * @param key the key to be checked
422     * @return a flag if this key is contained in this configuration
423     */
424    @Override
425    protected boolean containsKeyInternal(final String key)
426    {
427        return getPropertyInternal(key) != null;
428    }
429
430    /**
431     * Sets the value of the specified property.
432     *
433     * @param key the key of the property to set
434     * @param value the new value of this property
435     */
436    @Override
437    protected void setPropertyInternal(final String key, final Object value)
438    {
439        getModel().setProperty(key, value, this);
440    }
441
442    /**
443     * {@inheritDoc} This implementation delegates to the expression engine.
444     */
445    @Override
446    public List<QueryResult<T>> resolveKey(final T root, final String key,
447            final NodeHandler<T> handler)
448    {
449        return getExpressionEngine().query(root, key, handler);
450    }
451
452    /**
453     * {@inheritDoc} This implementation delegates to {@code resolveKey()} and
454     * then filters out attribute results.
455     */
456    @Override
457    public List<T> resolveNodeKey(final T root, final String key, final NodeHandler<T> handler)
458    {
459        final List<QueryResult<T>> results = resolveKey(root, key, handler);
460        final List<T> targetNodes = new LinkedList<>();
461        for (final QueryResult<T> result : results)
462        {
463            if (!result.isAttributeResult())
464            {
465                targetNodes.add(result.getNode());
466            }
467        }
468        return targetNodes;
469    }
470
471    /**
472     * {@inheritDoc} This implementation delegates to the expression engine.
473     */
474    @Override
475    public NodeAddData<T> resolveAddKey(final T root, final String key,
476            final NodeHandler<T> handler)
477    {
478        return getExpressionEngine().prepareAdd(root, key, handler);
479    }
480
481    /**
482     * {@inheritDoc} This implementation executes a query for the given key and
483     * constructs a {@code NodeUpdateData} object based on the results. It
484     * determines which nodes need to be changed and whether new ones need to be
485     * added or existing ones need to be removed.
486     */
487    @Override
488    public NodeUpdateData<T> resolveUpdateKey(final T root, final String key,
489            final Object newValue, final NodeHandler<T> handler)
490    {
491        final Iterator<QueryResult<T>> itNodes = fetchNodeList(key).iterator();
492        final Iterator<?> itValues = getListDelimiterHandler().parse(newValue).iterator();
493        final Map<QueryResult<T>, Object> changedValues =
494                new HashMap<>();
495        Collection<Object> additionalValues = null;
496        Collection<QueryResult<T>> removedItems = null;
497
498        while (itNodes.hasNext() && itValues.hasNext())
499        {
500            changedValues.put(itNodes.next(), itValues.next());
501        }
502
503        // Add additional nodes if necessary
504        if (itValues.hasNext())
505        {
506            additionalValues = new LinkedList<>();
507            while (itValues.hasNext())
508            {
509                additionalValues.add(itValues.next());
510            }
511        }
512
513        // Remove remaining nodes
514        if (itNodes.hasNext())
515        {
516            removedItems = new LinkedList<>();
517            while (itNodes.hasNext())
518            {
519                removedItems.add(itNodes.next());
520            }
521        }
522
523        return new NodeUpdateData<>(changedValues, additionalValues,
524                removedItems, key);
525    }
526
527    /**
528     * {@inheritDoc} This implementation uses the expression engine to generate a
529     * canonical key for the passed in node. For this purpose, the path to the
530     * root node has to be traversed. The cache is used to store and access keys
531     * for nodes encountered on the path.
532     */
533    @Override
534    public String nodeKey(final T node, final Map<T, String> cache, final NodeHandler<T> handler)
535    {
536        final List<T> path = new LinkedList<>();
537        T currentNode = node;
538        String key = cache.get(node);
539        while (key == null && currentNode != null)
540        {
541            path.add(0, currentNode);
542            currentNode = handler.getParent(currentNode);
543            key = cache.get(currentNode);
544        }
545
546        for (final T n : path)
547        {
548            final String currentKey = getExpressionEngine().canonicalKey(n, key, handler);
549            cache.put(n, currentKey);
550            key = currentKey;
551        }
552
553        return key;
554    }
555
556    /**
557     * Clears this configuration. This is a more efficient implementation than
558     * the one inherited from the base class. It delegates to the node model.
559     */
560    @Override
561    protected void clearInternal()
562    {
563        getModel().clear(this);
564    }
565
566    /**
567     * Removes all values of the property with the given name and of keys that
568     * start with this name. So if there is a property with the key
569     * &quot;foo&quot; and a property with the key &quot;foo.bar&quot;, a call
570     * of {@code clearTree("foo")} would remove both properties.
571     *
572     * @param key the key of the property to be removed
573     */
574    @Override
575    public final void clearTree(final String key)
576    {
577        beginWrite(false);
578        try
579        {
580            fireEvent(ConfigurationEvent.CLEAR_TREE, key, null, true);
581            final Object nodes = clearTreeInternal(key);
582            fireEvent(ConfigurationEvent.CLEAR_TREE, key, nodes, false);
583        }
584        finally
585        {
586            endWrite();
587        }
588    }
589
590    /**
591     * Actually clears the tree of elements referenced by the given key. This
592     * method is called by {@code clearTree()}. Subclasses that need to adapt
593     * this operation can override this method. This base implementation
594     * delegates to the node model.
595     *
596     * @param key the key of the property to be removed
597     * @return an object with information about the nodes that have been removed
598     *         (this is needed for firing a meaningful event of type
599     *         CLEAR_TREE)
600     * @since 2.0
601     */
602    protected Object clearTreeInternal(final String key)
603    {
604        return getModel().clearTree(key, this);
605    }
606
607    /**
608     * Removes the property with the given key. Properties with names that start
609     * with the given key (i.e. properties below the specified key in the
610     * hierarchy) won't be affected. This implementation delegates to the node+
611     * model.
612     *
613     * @param key the key of the property to be removed
614     */
615    @Override
616    protected void clearPropertyDirect(final String key)
617    {
618        getModel().clearProperty(key, this);
619    }
620
621    /**
622     * {@inheritDoc} This implementation is slightly more efficient than the
623     * default implementation. It does not iterate over the key set, but
624     * directly queries its size after it has been constructed. Note that
625     * constructing the key set is still an O(n) operation.
626     */
627    @Override
628    protected int sizeInternal()
629    {
630        return visitDefinedKeys().getKeyList().size();
631    }
632
633    /**
634     * Returns an iterator with all keys defined in this configuration.
635     * Note that the keys returned by this method will not contain any
636     * indices. This means that some structure will be lost.
637     *
638     * @return an iterator with the defined keys in this configuration
639     */
640    @Override
641    protected Iterator<String> getKeysInternal()
642    {
643        return visitDefinedKeys().getKeyList().iterator();
644    }
645
646    /**
647     * Creates a {@code DefinedKeysVisitor} and visits all defined keys with it.
648     *
649     * @return the visitor after all keys have been visited
650     */
651    private DefinedKeysVisitor visitDefinedKeys()
652    {
653        final DefinedKeysVisitor visitor = new DefinedKeysVisitor();
654        final NodeHandler<T> nodeHandler = getModel().getNodeHandler();
655        NodeTreeWalker.INSTANCE.walkDFS(nodeHandler.getRootNode(), visitor,
656                nodeHandler);
657        return visitor;
658    }
659
660    /**
661     * Returns an iterator with all keys defined in this configuration that
662     * start with the given prefix. The returned keys will not contain any
663     * indices. This implementation tries to locate a node whose key is the same
664     * as the passed in prefix. Then the subtree of this node is traversed, and
665     * the keys of all nodes encountered (including attributes) are added to the
666     * result set.
667     *
668     * @param prefix the prefix of the keys to start with
669     * @return an iterator with the found keys
670     */
671    @Override
672    protected Iterator<String> getKeysInternal(final String prefix)
673    {
674        final DefinedKeysVisitor visitor = new DefinedKeysVisitor(prefix);
675        if (containsKey(prefix))
676        {
677            // explicitly add the prefix
678            visitor.getKeyList().add(prefix);
679        }
680
681        final List<QueryResult<T>> results = fetchNodeList(prefix);
682        final NodeHandler<T> handler = getModel().getNodeHandler();
683
684        for (final QueryResult<T> result : results)
685        {
686            if (!result.isAttributeResult())
687            {
688                for (final T c : handler.getChildren(result.getNode()))
689                {
690                    NodeTreeWalker.INSTANCE.walkDFS(c, visitor, handler);
691                }
692                visitor.handleAttributeKeys(prefix, result.getNode(), handler);
693            }
694        }
695
696        return visitor.getKeyList().iterator();
697    }
698
699    /**
700     * Returns the maximum defined index for the given key. This is useful if
701     * there are multiple values for this key. They can then be addressed
702     * separately by specifying indices from 0 to the return value of this
703     * method. If the passed in key is not contained in this configuration,
704     * result is -1.
705     *
706     * @param key the key to be checked
707     * @return the maximum defined index for this key
708     */
709    @Override
710    public final int getMaxIndex(final String key)
711    {
712        beginRead(false);
713        try
714        {
715            return getMaxIndexInternal(key);
716        }
717        finally
718        {
719            endRead();
720        }
721    }
722
723    /**
724     * Actually retrieves the maximum defined index for the given key. This
725     * method is called by {@code getMaxIndex()}. Subclasses that need to adapt
726     * this operation have to override this method.
727     *
728     * @param key the key to be checked
729     * @return the maximum defined index for this key
730     * @since 2.0
731     */
732    protected int getMaxIndexInternal(final String key)
733    {
734        return fetchNodeList(key).size() - 1;
735    }
736
737    /**
738     * Creates a copy of this object. This new configuration object will contain
739     * copies of all nodes in the same structure. Registered event listeners
740     * won't be cloned; so they are not registered at the returned copy.
741     *
742     * @return the copy
743     * @since 1.2
744     */
745    @Override
746    public Object clone()
747    {
748        beginRead(false);
749        try
750        {
751            @SuppressWarnings("unchecked") // clone returns the same type
752            final
753            AbstractHierarchicalConfiguration<T> copy =
754                    (AbstractHierarchicalConfiguration<T>) super.clone();
755            copy.setSynchronizer(NoOpSynchronizer.INSTANCE);
756            copy.cloneInterpolator(this);
757            copy.setSynchronizer(ConfigurationUtils.cloneSynchronizer(getSynchronizer()));
758            copy.model = cloneNodeModel();
759
760            return copy;
761        }
762        catch (final CloneNotSupportedException cex)
763        {
764            // should not happen
765            throw new ConfigurationRuntimeException(cex);
766        }
767        finally
768        {
769            endRead();
770        }
771    }
772
773    /**
774     * Creates a clone of the node model. This method is called by
775     * {@code clone()}.
776     *
777     * @return the clone of the {@code NodeModel}
778     * @since 2.0
779     */
780    protected abstract NodeModel<T> cloneNodeModel();
781
782    /**
783     * Helper method for resolving the specified key.
784     *
785     * @param key the key
786     * @return a list with all results selected by this key
787     */
788    protected List<QueryResult<T>> fetchNodeList(final String key)
789    {
790        final NodeHandler<T> nodeHandler = getModel().getNodeHandler();
791        return resolveKey(nodeHandler.getRootNode(), key, nodeHandler);
792    }
793
794    /**
795     * Checks if the specified node is defined.
796     *
797     * @param node the node to be checked
798     * @return a flag if this node is defined
799     */
800    protected boolean nodeDefined(final T node)
801    {
802        final DefinedVisitor<T> visitor = new DefinedVisitor<>();
803        NodeTreeWalker.INSTANCE.walkBFS(node, visitor, getModel().getNodeHandler());
804        return visitor.isDefined();
805    }
806
807    /**
808     * Returns the {@code NodeModel} used by this configuration. This method is
809     * intended for internal use only. Access to the model is granted without
810     * any synchronization. This is in contrast to the &quot;official&quot;
811     * {@code getNodeModel()} method which is guarded by the configuration's
812     * {@code Synchronizer}.
813     *
814     * @return the node model
815     */
816    protected NodeModel<T> getModel()
817    {
818        return model;
819    }
820
821    /**
822     * Extracts the value from a query result.
823     *
824     * @param result the {@code QueryResult}
825     * @param handler the {@code NodeHandler}
826     * @return the value of this result (may be <b>null</b>)
827     */
828    private Object valueFromResult(final QueryResult<T> result, final NodeHandler<T> handler)
829    {
830        return result.isAttributeResult() ? result.getAttributeValue(handler)
831                : handler.getValue(result.getNode());
832    }
833
834    /**
835     * A specialized visitor that checks if a node is defined.
836     * &quot;Defined&quot; in this terms means that the node or at least one of
837     * its sub nodes is associated with a value.
838     *
839     * @param <T> the type of the nodes managed by this hierarchical configuration
840     */
841    private static class DefinedVisitor<T> extends
842            ConfigurationNodeVisitorAdapter<T>
843    {
844        /** Stores the defined flag. */
845        private boolean defined;
846
847        /**
848         * Checks if iteration should be stopped. This can be done if the first
849         * defined node is found.
850         *
851         * @return a flag if iteration should be stopped
852         */
853        @Override
854        public boolean terminate()
855        {
856            return isDefined();
857        }
858
859        /**
860         * Visits the node. Checks if a value is defined.
861         *
862         * @param node the actual node
863         */
864        @Override
865        public void visitBeforeChildren(final T node, final NodeHandler<T> handler)
866        {
867            defined =
868                    handler.getValue(node) != null
869                            || !handler.getAttributes(node).isEmpty();
870        }
871
872        /**
873         * Returns the defined flag.
874         *
875         * @return the defined flag
876         */
877        public boolean isDefined()
878        {
879            return defined;
880        }
881    }
882
883    /**
884     * A specialized visitor that fills a list with keys that are defined in a
885     * node hierarchy.
886     */
887    private class DefinedKeysVisitor extends
888            ConfigurationNodeVisitorAdapter<T>
889    {
890        /** Stores the list to be filled. */
891        private final Set<String> keyList;
892
893        /** A stack with the keys of the already processed nodes. */
894        private final Stack<String> parentKeys;
895
896        /**
897         * Default constructor.
898         */
899        public DefinedKeysVisitor()
900        {
901            keyList = new LinkedHashSet<>();
902            parentKeys = new Stack<>();
903        }
904
905        /**
906         * Creates a new {@code DefinedKeysVisitor} instance and sets the
907         * prefix for the keys to fetch.
908         *
909         * @param prefix the prefix
910         */
911        public DefinedKeysVisitor(final String prefix)
912        {
913            this();
914            parentKeys.push(prefix);
915        }
916
917        /**
918         * Returns the list with all defined keys.
919         *
920         * @return the list with the defined keys
921         */
922        public Set<String> getKeyList()
923        {
924            return keyList;
925        }
926
927        /**
928         * {@inheritDoc} This implementation removes this
929         * node's key from the stack.
930         */
931        @Override
932        public void visitAfterChildren(final T node, final NodeHandler<T> handler)
933        {
934            parentKeys.pop();
935        }
936
937        /**
938         * {@inheritDoc} If this node has a value, its key is added
939         * to the internal list.
940         */
941        @Override
942        public void visitBeforeChildren(final T node, final NodeHandler<T> handler)
943        {
944            final String parentKey = parentKeys.isEmpty() ? null
945                    : parentKeys.peek();
946            final String key = getExpressionEngine().nodeKey(node, parentKey, handler);
947            parentKeys.push(key);
948            if (handler.getValue(node) != null)
949            {
950                keyList.add(key);
951            }
952            handleAttributeKeys(key, node, handler);
953        }
954
955        /**
956         * Appends all attribute keys of the current node.
957         *
958         * @param parentKey the parent key
959         * @param node the current node
960         * @param handler the {@code NodeHandler}
961         */
962        public void handleAttributeKeys(final String parentKey, final T node,
963                final NodeHandler<T> handler)
964        {
965            for (final String attr : handler.getAttributes(node))
966            {
967                keyList.add(getExpressionEngine().attributeKey(parentKey, attr));
968            }
969        }
970    }
971
972    @Override
973    public String toString()
974    {
975        return super.toString() + "(" + getRootElementNameInternal() + ")";
976    }
977}