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

org.apache.commons.configuration2.tree.ReferenceTracker Maven / Gradle / Ivy

Go to download

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

The 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.tree;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * 

* A class which allows an {@link InMemoryNodeModel} to associate arbitrary objects with nodes. *

*

* Some special configuration implementations need additional data to be stored with their nodes structure. We call such * data "references" because objects required by a configuration are referenced. In such constellations, it is * necessary to keep track about the nodes associated with references even if they are replaced by others during an * update operation of the model. This is the task of this class. *

*

* Basically, an instance manages a map associating nodes with reference objects. When a node is replaced the map gets * updated. References becoming orphans because the nodes pointing to them were removed are tracked, too. They may be of * importance for special configuration implementations as they might require additional updates. A concrete use case * for this class is {@code XMLConfiguration} which stores the DOM nodes represented by configuration nodes as * references. *

*

* Implementation note: This class is intended to work in a concurrent environment. Instances are immutable. The * represented state can be updated by creating new instances which are then stored by the owning node model. *

*/ final class ReferenceTracker { /** A map with reference data. */ private final Map references; /** A list with the removed references. */ private final List removedReferences; /** * Creates a new instance of {@code ReferenceTracker}. This instance does not yet contain any data about references. */ public ReferenceTracker() { this(Collections.emptyMap(), Collections.emptyList()); } /** * Creates a new instance of {@code ReferenceTracker} and sets the data to be managed. This constructor is used * internally when references are updated. * * @param refs the references * @param removedRefs the removed references */ private ReferenceTracker(final Map refs, final List removedRefs) { references = refs; removedReferences = removedRefs; } /** * Adds all references stored in the passed in map to the managed references. A new instance is created managing this * new set of references. * * @param refs the references to be added * @return the new instance */ public ReferenceTracker addReferences(final Map refs) { final Map newRefs = new HashMap<>(references); newRefs.putAll(refs); return new ReferenceTracker(newRefs, removedReferences); } /** * Gets the reference object associated with the given node. * * @param node the node * @return the reference object for this node or null */ public Object getReference(final ImmutableNode node) { return references.get(node); } /** * Gets the list with removed references. This list is immutable. * * @return the list with removed references */ public List getRemovedReferences() { return Collections.unmodifiableList(removedReferences); } /** * Updates the references managed by this object at the end of a model transaction. This method is called by the * transaction with the nodes that have been replaced by others and the nodes that have been removed. The internal data * structures are updated correspondingly. * * @param replacedNodes the map with nodes that have been replaced * @param removedNodes the list with nodes that have been removed * @return the new instance */ public ReferenceTracker updateReferences(final Map replacedNodes, final Collection removedNodes) { if (!references.isEmpty()) { Map newRefs = null; for (final Map.Entry e : replacedNodes.entrySet()) { final Object ref = references.get(e.getKey()); if (ref != null) { if (newRefs == null) { newRefs = new HashMap<>(references); } newRefs.put(e.getValue(), ref); newRefs.remove(e.getKey()); } } List newRemovedRefs = newRefs != null ? new LinkedList<>(removedReferences) : null; for (final ImmutableNode node : removedNodes) { final Object ref = references.get(node); if (ref != null) { if (newRefs == null) { newRefs = new HashMap<>(references); } newRefs.remove(node); if (newRemovedRefs == null) { newRemovedRefs = new LinkedList<>(removedReferences); } newRemovedRefs.add(ref); } } if (newRefs != null) { return new ReferenceTracker(newRefs, newRemovedRefs); } } return this; } }