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   * @author The Apache MINA Project (dev@mina.apache.org)
37   */
38  public class CopyOnWriteMap<K, V> implements Map<K, V>, Cloneable {
39      private volatile Map<K, V> internalMap;
40  
41      /**
42       * Creates a new instance of CopyOnWriteMap.
43       *
44       */
45      public CopyOnWriteMap() {
46          internalMap = new HashMap<K, V>();
47      }
48  
49      /**
50       * Creates a new instance of CopyOnWriteMap with the specified initial size
51       *
52       * @param initialCapacity
53       *  The initial size of the Map.
54       */
55      public CopyOnWriteMap(int initialCapacity) {
56          internalMap = new HashMap<K, V>(initialCapacity);
57      }
58  
59      /**
60       * Creates a new instance of CopyOnWriteMap in which the
61       * initial data being held by this map is contained in
62       * the supplied map.
63       *
64       * @param data
65       *  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<K, V>(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      public V put(K key, V value) {
78          synchronized (this) {
79              Map<K, V> newMap = new HashMap<K, V>(internalMap);
80              V val = newMap.put(key, value);
81              internalMap = newMap;
82              return val;
83          }
84      }
85  
86      /**
87       * Removed the value and key from this map based on the
88       * provided key.
89       *
90       * @see java.util.Map#remove(java.lang.Object)
91       */
92      public V remove(Object key) {
93          synchronized (this) {
94              Map<K, V> newMap = new HashMap<K, V>(internalMap);
95              V val = newMap.remove(key);
96              internalMap = newMap;
97              return val;
98          }
99      }
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      * Returns 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      * Returns 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      * Returns 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      * Returns 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      * Returns 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 }