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 }