All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.configuration2.SubnodeConfiguration Maven / Gradle / Ivy

Go to download

Tools to assist in the reading of configuration/preferences files in various formats

There is a newer version: 2.10.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.configuration2;

import org.apache.commons.configuration2.tree.ImmutableNode;
import org.apache.commons.configuration2.tree.InMemoryNodeModel;
import org.apache.commons.configuration2.tree.InMemoryNodeModelSupport;
import org.apache.commons.configuration2.tree.NodeModel;
import org.apache.commons.configuration2.tree.NodeSelector;
import org.apache.commons.configuration2.tree.TrackedNodeModel;

/**
 * 

* A specialized hierarchical configuration class with a node model that uses a * tracked node of another node model as its root node. *

*

* Configurations of this type are initialized with a special {@link NodeModel} * operating on a specific tracked node of the parent configuration and the * corresponding {@link NodeSelector}. All property accessor methods are * evaluated relative to this root node. A good use case for a * {@code SubnodeConfiguration} is when multiple properties from a specific sub * tree of the whole configuration need to be accessed. Then a * {@code SubnodeConfiguration} can be created with the parent node of the * affected sub tree as root node. This allows for simpler property keys and is * also more efficient. *

*

* By making use of a tracked node as root node, a {@code SubnodeConfiguration} * and its parent configuration initially operate on the same hierarchy of * configuration nodes. So if modifications are performed at the subnode * configuration, these changes are immediately visible in the parent * configuration. Analogously will updates of the parent configuration affect * the {@code SubnodeConfiguration} if the sub tree spanned by the * {@code SubnodeConfiguration}'s root node is involved. *

*

* Note that by making use of a {@code NodeSelector} the * {@code SubnodeConfiguration} is not associated with a physical node instance, * but the selection criteria stored in the selector are evaluated after each * change of the nodes structure. As an example consider that the selector uses * a key with an index into a list element, say index 2. Now if an update occurs * on the underlying nodes structure which removes the first element in this * list structure, the {@code SubnodeConfiguration} still references the element * with index 2 which is now another one. *

*

* There are also possible changes of the underlying nodes structure which * completely detach the {@code SubnodeConfiguration} from its parent * configuration. For instance, the key referenced by the * {@code SubnodeConfiguration} could be removed in the parent configuration. If * this happens, the {@code SubnodeConfiguration} stays functional; however, it * now operates on a separate node model than its parent configuration. Changes * made by one configuration are no longer visible for the other one (as the * node models have no longer overlapping nodes, there is no way to have a * synchronization here). *

*

* When a subnode configuration is created, it inherits the settings of its * parent configuration, e.g. some flags like the * {@code throwExceptionOnMissing} flag or the settings for handling list * delimiters) or the expression engine. If these settings are changed later in * either the subnode or the parent configuration, the changes are not visible * for each other. So you could create a subnode configuration, and change its * expression engine without affecting the parent configuration. *

*

* Because the {@code SubnodeConfiguration} operates on the same nodes structure * as its parent it uses the same {@code Synchronizer} instance per default. * This means that locks held on one {@code SubnodeConfiguration} also impact * the parent configuration and all of its other {@code SubnodeConfiguration} * objects. You should not change this without a good reason! Otherwise, there * is the risk of data corruption when multiple threads access these * configuration concurrently. *

*

* From its purpose this class is quite similar to {@link SubsetConfiguration}. * The difference is that a subset configuration of a hierarchical configuration * may combine multiple configuration nodes from different sub trees of the * configuration, while all nodes in a subnode configuration belong to the same * sub tree. If an application can live with this limitation, it is recommended * to use this class instead of {@code SubsetConfiguration} because creating a * subset configuration is more expensive than creating a subnode configuration. *

*

* It is strongly recommended to create {@code SubnodeConfiguration} instances * only through the {@code configurationAt()} methods of a hierarchical * configuration. These methods ensure that all necessary initializations are * done. Creating instances manually without doing proper initialization may * break some of the functionality provided by this class. *

* * @since 1.3 */ public class SubnodeConfiguration extends BaseHierarchicalConfiguration { /** Stores the parent configuration. */ private final BaseHierarchicalConfiguration parent; /** The node selector selecting the root node of this configuration. */ private final NodeSelector rootSelector; /** * Creates a new instance of {@code SubnodeConfiguration} and initializes it * with all relevant properties. * * @param parent the parent configuration * @param model the {@code TrackedNodeModel} to be used for this configuration * @throws IllegalArgumentException if a required argument is missing */ public SubnodeConfiguration(final BaseHierarchicalConfiguration parent, final TrackedNodeModel model) { super(model); if (parent == null) { throw new IllegalArgumentException( "Parent configuration must not be null!"); } if (model == null) { throw new IllegalArgumentException("Node model must not be null!"); } this.parent = parent; rootSelector = model.getSelector(); } /** * Returns the parent configuration of this subnode configuration. * * @return the parent configuration */ public BaseHierarchicalConfiguration getParent() { return parent; } /** * Returns the selector to the root node of this configuration. * * @return the {@code NodeSelector} to the root node */ public NodeSelector getRootSelector() { return rootSelector; } /** * Closes this sub configuration. This method closes the underlying * {@link TrackedNodeModel}, thus causing the tracked node acting as root * node to be released. Per default, this happens automatically when the * model is claimed by the garbage collector. By calling this method * explicitly, it can be indicated that this configuration is no longer used * and that resources used by it can be freed immediately. */ public void close() { (getTrackedModel()).close(); } /** * {@inheritDoc} This implementation returns a newly created node model * with the correct root node set. Note that this model is not used for * property access, but only made available to clients that need to * operate on the node structure of this {@code SubnodeConfiguration}. * Be aware that the implementation of this method is not very efficient. */ @Override public InMemoryNodeModel getNodeModel() { final ImmutableNode root = getParent().getNodeModel().getTrackedNode(getRootSelector()); return new InMemoryNodeModel(root); } /** * Returns the node model of the root configuration. * {@code SubnodeConfiguration} instances created from a hierarchical * configuration operate on the same node model, using different nodes as * their local root nodes. With this method the top-level node model can be * obtained. It works even in constellations where a * {@code SubnodeConfiguration} has been created from another * {@code SubnodeConfiguration}. * * @return the root node model * @since 2.2 */ public InMemoryNodeModel getRootNodeModel() { if (getParent() instanceof SubnodeConfiguration) { return ((SubnodeConfiguration) getParent()).getRootNodeModel(); } return getParent().getNodeModel(); } /** * {@inheritDoc} This implementation returns a copy of the current node * model with the same settings. However, it has to be ensured that the * track count for the node selector is increased. * * @return the node model for the clone */ @Override protected NodeModel cloneNodeModel() { final InMemoryNodeModel parentModel = (InMemoryNodeModel) getParent().getModel(); parentModel.trackNode(getRootSelector(), getParent()); return new TrackedNodeModel(getParent(), getRootSelector(), true); } /** * {@inheritDoc} This implementation returns a sub selector of the selector * of this configuration. */ @Override protected NodeSelector getSubConfigurationNodeSelector(final String key) { return getRootSelector().subSelector(key); } /** * {@inheritDoc} This implementation returns the parent model of the * {@link TrackedNodeModel} used by this configuration. */ @Override protected InMemoryNodeModel getSubConfigurationParentModel() { return getTrackedModel().getParentModel(); } /** * {@inheritDoc} This implementation makes sure that the correct node model * (the one of the parent) is used for the new sub configuration. */ @Override protected SubnodeConfiguration createSubConfigurationForTrackedNode( final NodeSelector selector, final InMemoryNodeModelSupport parentModelSupport) { return super.createSubConfigurationForTrackedNode(selector, getParent()); } /** * Convenience method that returns the tracked model used by this sub * configuration. * * @return the {@code TrackedNodeModel} */ private TrackedNodeModel getTrackedModel() { return (TrackedNodeModel) getModel(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy