001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.util;
021
022import java.util.Collection;
023import java.util.HashMap;
024import java.util.Map;
025import java.util.Set;
026
027/**
028 * A thread-safe version of {@link Map} in which all operations that change the
029 * Map are implemented by making a new copy of the underlying Map.
030 *
031 * While the creation of a new Map can be expensive, this class is designed for
032 * cases in which the primary function is to read data from the Map, not to
033 * modify the Map.  Therefore the operations that do not cause a change to this
034 * class happen quickly and concurrently.
035 *
036 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
037 */
038public class CopyOnWriteMap<K, V> implements Map<K, V>, Cloneable {
039    private volatile Map<K, V> internalMap;
040
041    /**
042     * Creates a new instance of CopyOnWriteMap.
043     *
044     */
045    public CopyOnWriteMap() {
046        internalMap = new HashMap<K, V>();
047    }
048
049    /**
050     * Creates a new instance of CopyOnWriteMap with the specified initial size
051     *
052     * @param initialCapacity
053     *  The initial size of the Map.
054     */
055    public CopyOnWriteMap(int initialCapacity) {
056        internalMap = new HashMap<K, V>(initialCapacity);
057    }
058
059    /**
060     * Creates a new instance of CopyOnWriteMap in which the
061     * initial data being held by this map is contained in
062     * the supplied map.
063     *
064     * @param data
065     *  A Map containing the initial contents to be placed into
066     *  this class.
067     */
068    public CopyOnWriteMap(Map<K, V> data) {
069        internalMap = new HashMap<K, V>(data);
070    }
071
072    /**
073     * Adds the provided key and value to this map.
074     *
075     * @see java.util.Map#put(java.lang.Object, java.lang.Object)
076     */
077    public V put(K key, V value) {
078        synchronized (this) {
079            Map<K, V> newMap = new HashMap<K, V>(internalMap);
080            V val = newMap.put(key, value);
081            internalMap = newMap;
082            return val;
083        }
084    }
085
086    /**
087     * Removed the value and key from this map based on the
088     * provided key.
089     *
090     * @see java.util.Map#remove(java.lang.Object)
091     */
092    public V remove(Object key) {
093        synchronized (this) {
094            Map<K, V> newMap = new HashMap<K, V>(internalMap);
095            V val = newMap.remove(key);
096            internalMap = newMap;
097            return val;
098        }
099    }
100
101    /**
102     * Inserts all the keys and values contained in the
103     * provided map to this map.
104     *
105     * @see java.util.Map#putAll(java.util.Map)
106     */
107    public void putAll(Map<? extends K, ? extends V> newData) {
108        synchronized (this) {
109            Map<K, V> newMap = new HashMap<K, V>(internalMap);
110            newMap.putAll(newData);
111            internalMap = newMap;
112        }
113    }
114
115    /**
116     * Removes all entries in this map.
117     *
118     * @see java.util.Map#clear()
119     */
120    public void clear() {
121        synchronized (this) {
122            internalMap = new HashMap<K, V>();
123        }
124    }
125
126    // ==============================================
127    // ==== Below are methods that do not modify ====
128    // ====         the internal Maps            ====
129    // ==============================================
130    /**
131     * @return the number of key/value pairs in this map.
132     *
133     * @see java.util.Map#size()
134     */
135    public int size() {
136        return internalMap.size();
137    }
138
139    /**
140     * @return true if this map is empty, otherwise false.
141     *
142     * @see java.util.Map#isEmpty()
143     */
144    public boolean isEmpty() {
145        return internalMap.isEmpty();
146    }
147
148    /**
149     * @return true if this map contains the provided key, otherwise
150     * this method return false.
151     *
152     * @see java.util.Map#containsKey(java.lang.Object)
153     */
154    public boolean containsKey(Object key) {
155        return internalMap.containsKey(key);
156    }
157
158    /**
159     * @return true if this map contains the provided value, otherwise
160     * this method returns false.
161     *
162     * @see java.util.Map#containsValue(java.lang.Object)
163     */
164    public boolean containsValue(Object value) {
165        return internalMap.containsValue(value);
166    }
167
168    /**
169     * @return the value associated with the provided key from this
170     * map.
171     *
172     * @see java.util.Map#get(java.lang.Object)
173     */
174    public V get(Object key) {
175        return internalMap.get(key);
176    }
177
178    /**
179     * This method will return a read-only {@link Set}.
180     */
181    public Set<K> keySet() {
182        return internalMap.keySet();
183    }
184
185    /**
186     * This method will return a read-only {@link Collection}.
187     */
188    public Collection<V> values() {
189        return internalMap.values();
190    }
191
192    /**
193     * This method will return a read-only {@link Set}.
194     */
195    public Set<Entry<K, V>> entrySet() {
196        return internalMap.entrySet();
197    }
198
199    @Override
200    public Object clone() {
201        try {
202            return super.clone();
203        } catch (CloneNotSupportedException e) {
204            throw new InternalError();
205        }
206    }
207}