    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 */
    017package org.apache.commons.configuration2.tree;
    018
    019import java.util.ArrayList;
    020import java.util.Collection;
    021import java.util.Collections;
    022import java.util.HashMap;
    023import java.util.Map;
    024
    025/**
    026 * <p>
    027 * A simple data class used by node models to store parameters of an update operation.
    028 * </p>
    029 * <p>
    030 * The {@code Configuration} interface provides a method for setting the value of a given key. The passed in value can
    031 * be a single object or a collection of values. This makes an update operation rather complicated because a collection
    032 * of query results selected by the passed in key has to be matched to another collection of values - and both
    033 * collections can have different sizes. Therefore, an update operation may involve changing of existing nodes, adding
    034 * new nodes (if there are more values than currently existing nodes), and removing nodes (if there are more existing
    035 * nodes than provided values). This class collects all this information making it possible to actually perform the
    036 * update based on a passed in instance.
    037 * </p>
    038 *
    039 * @since 2.0
    040 * @param <T> the type of nodes involved in this update operation
    041 */
    042public class NodeUpdateData<T> {
    043    /** The map with the query results whose value has to be changed. */
    044    private final Map<QueryResult<T>, Object> changedValues;
    045
    046    /** The collection with the new values to be added. */
    047    private final Collection<Object> newValues;
    048
    049    /** The collection with query results about the nodes to be removed. */
    050    private final Collection<QueryResult<T>> removedNodes;
    051
    052    /** The key of the current update operation. */
    053    private final String key;
    054
    055    /**
    056     * Creates a new instance of {@code NodeUpdateData} and initializes all its properties. All passed in collections are
    057     * optional and can be <b>null</b>.
    058     *
    059     * @param changedValues the map defining the changed values
    060     * @param newValues the collection with the new values
    061     * @param removedNodes the collection with the nodes to be removed
    062     * @param key the key of the update operation
    063     */
    064    public NodeUpdateData(final Map<QueryResult<T>, Object> changedValues, final Collection<Object> newValues, final Collection<QueryResult<T>> removedNodes,
    065        final String key) {
    066        this.changedValues = copyMap(changedValues);
    067        this.newValues = copyCollection(newValues);
    068        this.removedNodes = copyCollection(removedNodes);
    069        this.key = key;
    070    }
    071
    072    /**
    073     * Gets an unmodifiable map with the values to be changed. The keys of the map are the query results for the nodes
    074     * affected, the values are the new values to be assigned to these nodes.
    075     *
    076     * @return the map with values to be changed
    077     */
    078    public Map<QueryResult<T>, Object> getChangedValues() {
    079        return changedValues;
    080    }
    081
    082    /**
    083     * Gets a collection with the values to be newly added. For these values new nodes have to be created and added under
    084     * the key stored in this object.
    085     *
    086     * @return the collection with new values
    087     */
    088    public Collection<Object> getNewValues() {
    089        return newValues;
    090    }
    091
    092    /**
    093     * Adds a collection with the nodes to be removed. These nodes are no longer needed and have to be removed from the node
    094     * model processing this request.
    095     *
    096     * @return the collection with nodes to be removed
    097     */
    098    public Collection<QueryResult<T>> getRemovedNodes() {
    099        return removedNodes;
    100    }
    101
    102    /**
    103     * Gets the key for this update operation.
    104     *
    105     * @return the key for this operation
    106     */
    107    public String getKey() {
    108        return key;
    109    }
    110
    111    /**
    112     * Creates an unmodifiable defensive copy of the passed in map which may be null.
    113     *
    114     * @param map the map to be copied
    115     * @param <K> the type of the keys involved
    116     * @param <V> the type of the values involved
    117     * @return the unmodifiable copy
    118     */
    119    private static <K, V> Map<K, V> copyMap(final Map<? extends K, ? extends V> map) {
    120        if (map == null) {
    121            return Collections.emptyMap();
    122        }
    123        return Collections.unmodifiableMap(new HashMap<>(map));
    124    }
    125
    126    /**
    127     * Creates an unmodifiable defensive copy of the passed in collection with may be null.
    128     *
    129     * @param col the collection to be copied
    130     * @param <T> the element type of the collection
    131     * @return the unmodifiable copy
    132     */
    133    private static <T> Collection<T> copyCollection(final Collection<? extends T> col) {
    134        if (col == null) {
    135            return Collections.emptySet();
    136        }
    137        return Collections.unmodifiableCollection(new ArrayList<>(col));
    138    }
    139}