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