    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 *     https://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 * @param <T> the type of nodes involved in this update operation
    040 * @since 2.0
    041 */
    042public class NodeUpdateData<T> {
    043
    044    /**
    045     * Creates an unmodifiable defensive copy of the passed in collection with may be null.
    046     *
    047     * @param col the collection to be copied
    048     * @param <T> the element type of the collection
    049     * @return the unmodifiable copy
    050     */
    051    private static <T> Collection<T> copyCollection(final Collection<? extends T> col) {
    052        if (col == null) {
    053            return Collections.emptySet();
    054        }
    055        return Collections.unmodifiableCollection(new ArrayList<>(col));
    056    }
    057
    058    /**
    059     * Creates an unmodifiable defensive copy of the passed in map which may be null.
    060     *
    061     * @param map the map to be copied
    062     * @param <K> the type of the keys involved
    063     * @param <V> the type of the values involved
    064     * @return the unmodifiable copy
    065     */
    066    private static <K, V> Map<K, V> copyMap(final Map<? extends K, ? extends V> map) {
    067        if (map == null) {
    068            return Collections.emptyMap();
    069        }
    070        return Collections.unmodifiableMap(new HashMap<>(map));
    071    }
    072
    073    /** The map with the query results whose value has to be changed. */
    074    private final Map<QueryResult<T>, Object> changedValues;
    075
    076    /** The collection with the new values to be added. */
    077    private final Collection<Object> newValues;
    078
    079    /** The collection with query results about the nodes to be removed. */
    080    private final Collection<QueryResult<T>> removedNodes;
    081
    082    /** The key of the current update operation. */
    083    private final String key;
    084
    085    /**
    086     * Creates a new instance of {@code NodeUpdateData} and initializes all its properties. All passed in collections are
    087     * optional and can be <strong>null</strong>.
    088     *
    089     * @param changedValues the map defining the changed values
    090     * @param newValues the collection with the new values
    091     * @param removedNodes the collection with the nodes to be removed
    092     * @param key the key of the update operation
    093     */
    094    public NodeUpdateData(final Map<QueryResult<T>, Object> changedValues, final Collection<Object> newValues, final Collection<QueryResult<T>> removedNodes,
    095        final String key) {
    096        this.changedValues = copyMap(changedValues);
    097        this.newValues = copyCollection(newValues);
    098        this.removedNodes = copyCollection(removedNodes);
    099        this.key = key;
    100    }
    101
    102    /**
    103     * Gets an unmodifiable map with the values to be changed. The keys of the map are the query results for the nodes
    104     * affected, the values are the new values to be assigned to these nodes.
    105     *
    106     * @return the map with values to be changed
    107     */
    108    public Map<QueryResult<T>, Object> getChangedValues() {
    109        return changedValues;
    110    }
    111
    112    /**
    113     * Gets the key for this update operation.
    114     *
    115     * @return the key for this operation
    116     */
    117    public String getKey() {
    118        return key;
    119    }
    120
    121    /**
    122     * Gets a collection with the values to be newly added. For these values new nodes have to be created and added under
    123     * the key stored in this object.
    124     *
    125     * @return the collection with new values
    126     */
    127    public Collection<Object> getNewValues() {
    128        return newValues;
    129    }
    130
    131    /**
    132     * Adds a collection with the nodes to be removed. These nodes are no longer needed and have to be removed from the node
    133     * model processing this request.
    134     *
    135     * @return the collection with nodes to be removed
    136     */
    137    public Collection<QueryResult<T>> getRemovedNodes() {
    138        return removedNodes;
    139    }
    140}