001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.util; 021 022import java.util.Collection; 023import java.util.HashMap; 024import java.util.Map; 025import java.util.Set; 026 027/** 028 * A thread-safe version of {@link Map} in which all operations that change the 029 * Map are implemented by making a new copy of the underlying Map. 030 * 031 * While the creation of a new Map can be expensive, this class is designed for 032 * cases in which the primary function is to read data from the Map, not to 033 * modify the Map. Therefore the operations that do not cause a change to this 034 * class happen quickly and concurrently. 035 * 036 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 037 */ 038public class CopyOnWriteMap<K, V> implements Map<K, V>, Cloneable { 039 private volatile Map<K, V> internalMap; 040 041 /** 042 * Creates a new instance of CopyOnWriteMap. 043 * 044 */ 045 public CopyOnWriteMap() { 046 internalMap = new HashMap<K, V>(); 047 } 048 049 /** 050 * Creates a new instance of CopyOnWriteMap with the specified initial size 051 * 052 * @param initialCapacity 053 * The initial size of the Map. 054 */ 055 public CopyOnWriteMap(int initialCapacity) { 056 internalMap = new HashMap<K, V>(initialCapacity); 057 } 058 059 /** 060 * Creates a new instance of CopyOnWriteMap in which the 061 * initial data being held by this map is contained in 062 * the supplied map. 063 * 064 * @param data 065 * A Map containing the initial contents to be placed into 066 * this class. 067 */ 068 public CopyOnWriteMap(Map<K, V> data) { 069 internalMap = new HashMap<K, V>(data); 070 } 071 072 /** 073 * Adds the provided key and value to this map. 074 * 075 * @see java.util.Map#put(java.lang.Object, java.lang.Object) 076 */ 077 public V put(K key, V value) { 078 synchronized (this) { 079 Map<K, V> newMap = new HashMap<K, V>(internalMap); 080 V val = newMap.put(key, value); 081 internalMap = newMap; 082 return val; 083 } 084 } 085 086 /** 087 * Removed the value and key from this map based on the 088 * provided key. 089 * 090 * @see java.util.Map#remove(java.lang.Object) 091 */ 092 public V remove(Object key) { 093 synchronized (this) { 094 Map<K, V> newMap = new HashMap<K, V>(internalMap); 095 V val = newMap.remove(key); 096 internalMap = newMap; 097 return val; 098 } 099 } 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 * @return 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 * @return 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 * @return 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 * @return 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 * @return 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}