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 }