View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.util;
21  
22  import java.util.Collection;
23  import java.util.HashMap;
24  import java.util.Map;
25  import java.util.Set;
26  
27  /**
28   * A thread-safe version of {@link Map} in which all operations that change the
29   * Map are implemented by making a new copy of the underlying Map.
30   *
31   * While the creation of a new Map can be expensive, this class is designed for
32   * cases in which the primary function is to read data from the Map, not to
33   * modify the Map.  Therefore the operations that do not cause a change to this
34   * class happen quickly and concurrently.
35   * 
36   * @param <K> The key type
37   * @param <V> The value type
38   *
39   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
40   */
41  public class CopyOnWriteMap<K, V> implements Map<K, V>, Cloneable {
42      private volatile Map<K, V> internalMap;
43  
44      /**
45       * Creates a new instance of CopyOnWriteMap.
46       */
47      public CopyOnWriteMap() {
48          internalMap = new HashMap<>();
49      }
50  
51      /**
52       * Creates a new instance of CopyOnWriteMap with the specified initial size
53       *
54       * @param initialCapacity The initial size of the Map.
55       */
56      public CopyOnWriteMap(int initialCapacity) {
57          internalMap = new HashMap<>(initialCapacity);
58      }
59  
60      /**
61       * Creates a new instance of CopyOnWriteMap in which the
62       * initial data being held by this map is contained in
63       * the supplied map.
64       *
65       * @param data A Map containing the initial contents to be placed into
66       *  this class.
67       */
68      public CopyOnWriteMap(Map<K, V> data) {
69          internalMap = new HashMap<>(data);
70      }
71  
72      /**
73       * Adds the provided key and value to this map.
74       *
75       * @see java.util.Map#put(java.lang.Object, java.lang.Object)
76       */
77      @Override
78      public V put(K key, V value) {
79          synchronized (this) {
80              Map<K, V> newMap = new HashMap<>(internalMap);
81              V val = newMap.put(key, value);
82              internalMap = newMap;
83              
84              return val;
85          }
86      }
87  
88      /**
89       * Removed the value and key from this map based on the
90       * provided key.
91       *
92       * @see java.util.Map#remove(java.lang.Object)
93       */
94      @Override
95      public V remove(Object key) {
96          synchronized (this) {
97              Map<K, V> newMap = new HashMap<>(internalMap);
98              V val = newMap.remove(key);
99              internalMap = newMap;
100             
101             return val;
102         }
103     }
104 
105     /**
106      * Inserts all the keys and values contained in the
107      * provided map to this map.
108      *
109      * @see java.util.Map#putAll(java.util.Map)
110      */
111     @Override
112     public void putAll(Map<? extends K, ? extends V> newData) {
113         synchronized (this) {
114             Map<K, V> newMap = new HashMap<>(internalMap);
115             newMap.putAll(newData);
116             internalMap = newMap;
117         }
118     }
119 
120     /**
121      * Removes all entries in this map.
122      *
123      * @see java.util.Map#clear()
124      */
125     @Override
126     public void clear() {
127         synchronized (this) {
128             internalMap = new HashMap<>();
129         }
130     }
131 
132     // ==============================================
133     // ==== Below are methods that do not modify ====
134     // ====         the internal Maps            ====
135     // ==============================================
136     /**
137      * @return the number of key/value pairs in this map.
138      *
139      * @see java.util.Map#size()
140      */
141     @Override
142     public int size() {
143         return internalMap.size();
144     }
145 
146     /**
147      * @return true if this map is empty, otherwise false.
148      *
149      * @see java.util.Map#isEmpty()
150      */
151     @Override
152     public boolean isEmpty() {
153         return internalMap.isEmpty();
154     }
155 
156     /**
157      * @return true if this map contains the provided key, otherwise
158      * this method return false.
159      *
160      * @see java.util.Map#containsKey(java.lang.Object)
161      */
162     @Override
163     public boolean containsKey(Object key) {
164         return internalMap.containsKey(key);
165     }
166 
167     /**
168      * @return true if this map contains the provided value, otherwise
169      * this method returns false.
170      *
171      * @see java.util.Map#containsValue(java.lang.Object)
172      */
173     @Override
174     public boolean containsValue(Object value) {
175         return internalMap.containsValue(value);
176     }
177 
178     /**
179      * @return the value associated with the provided key from this
180      * map.
181      *
182      * @see java.util.Map#get(java.lang.Object)
183      */
184     @Override
185     public V get(Object key) {
186         return internalMap.get(key);
187     }
188 
189     /**
190      * This method will return a read-only {@link Set}.
191      */
192     @Override
193     public Set<K> keySet() {
194         return internalMap.keySet();
195     }
196 
197     /**
198      * This method will return a read-only {@link Collection}.
199      */
200     @Override
201     public Collection<V> values() {
202         return internalMap.values();
203     }
204 
205     /**
206      * This method will return a read-only {@link Set}.
207      */
208     @Override
209     public Set<Entry<K, V>> entrySet() {
210         return internalMap.entrySet();
211     }
212 
213     @Override
214     public Object clone() {
215         try {
216             return super.clone();
217         } catch (CloneNotSupportedException e) {
218             throw new InternalError();
219         }
220     }
221 }