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 }