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   * @version $Rev$, $Date$
38   */
39  public class CopyOnWriteMap<K, V> implements Map<K, V>, Cloneable {
40      private volatile Map<K, V> internalMap;
41  
42      /**
43       * Creates a new instance of CopyOnWriteMap.
44       *
45       */
46      public CopyOnWriteMap() {
47          internalMap = new HashMap<K, V>();
48      }
49  
50      /**
51       * Creates a new instance of CopyOnWriteMap with the specified initial size
52       *
53       * @param initialCapacity
54       *  The initial size of the Map.
55       */
56      public CopyOnWriteMap(int initialCapacity) {
57          internalMap = new HashMap<K, V>(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
66       *  A Map containing the initial contents to be placed into
67       *  this class.
68       */
69      public CopyOnWriteMap(Map<K, V> data) {
70          internalMap = new HashMap<K, V>(data);
71      }
72  
73      /**
74       * Adds the provided key and value to this map.
75       *
76       * @see java.util.Map#put(java.lang.Object, java.lang.Object)
77       */
78      public V put(K key, V value) {
79          synchronized (this) {
80              Map<K, V> newMap = new HashMap<K, V>(internalMap);
81              V val = newMap.put(key, value);
82              internalMap = newMap;
83              return val;
84          }
85      }
86  
87      /**
88       * Removed the value and key from this map based on the
89       * provided key.
90       *
91       * @see java.util.Map#remove(java.lang.Object)
92       */
93      public V remove(Object key) {
94          synchronized (this) {
95              Map<K, V> newMap = new HashMap<K, V>(internalMap);
96              V val = newMap.remove(key);
97              internalMap = newMap;
98              return val;
99          }
100     }
101 
102     /**
103      * Inserts all the keys and values contained in the
104      * provided map to this map.
105      *
106      * @see java.util.Map#putAll(java.util.Map)
107      */
108     public void putAll(Map<? extends K, ? extends V> newData) {
109         synchronized (this) {
110             Map<K, V> newMap = new HashMap<K, V>(internalMap);
111             newMap.putAll(newData);
112             internalMap = newMap;
113         }
114     }
115 
116     /**
117      * Removes all entries in this map.
118      *
119      * @see java.util.Map#clear()
120      */
121     public void clear() {
122         synchronized (this) {
123             internalMap = new HashMap<K, V>();
124         }
125     }
126 
127     // ==============================================
128     // ==== Below are methods that do not modify ====
129     // ====         the internal Maps            ====
130     // ==============================================
131     /**
132      * Returns the number of key/value pairs in this map.
133      *
134      * @see java.util.Map#size()
135      */
136     public int size() {
137         return internalMap.size();
138     }
139 
140     /**
141      * Returns true if this map is empty, otherwise false.
142      *
143      * @see java.util.Map#isEmpty()
144      */
145     public boolean isEmpty() {
146         return internalMap.isEmpty();
147     }
148 
149     /**
150      * Returns true if this map contains the provided key, otherwise
151      * this method return false.
152      *
153      * @see java.util.Map#containsKey(java.lang.Object)
154      */
155     public boolean containsKey(Object key) {
156         return internalMap.containsKey(key);
157     }
158 
159     /**
160      * Returns true if this map contains the provided value, otherwise
161      * this method returns false.
162      *
163      * @see java.util.Map#containsValue(java.lang.Object)
164      */
165     public boolean containsValue(Object value) {
166         return internalMap.containsValue(value);
167     }
168 
169     /**
170      * Returns the value associated with the provided key from this
171      * map.
172      *
173      * @see java.util.Map#get(java.lang.Object)
174      */
175     public V get(Object key) {
176         return internalMap.get(key);
177     }
178 
179     /**
180      * This method will return a read-only {@link Set}.
181      */
182     public Set<K> keySet() {
183         return internalMap.keySet();
184     }
185 
186     /**
187      * This method will return a read-only {@link Collection}.
188      */
189     public Collection<V> values() {
190         return internalMap.values();
191     }
192 
193     /**
194      * This method will return a read-only {@link Set}.
195      */
196     public Set<Entry<K, V>> entrySet() {
197         return internalMap.entrySet();
198     }
199 
200     @Override
201     public Object clone() {
202         try {
203             return super.clone();
204         } catch (CloneNotSupportedException e) {
205             throw new InternalError();
206         }
207     }
208 }