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