1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.atlassian.util.concurrent;
18
19 import static com.atlassian.util.concurrent.Assertions.notNull;
20 import net.jcip.annotations.ThreadSafe;
21
22 import java.io.Serializable;
23 import java.util.Collection;
24 import java.util.Iterator;
25 import java.util.Map;
26 import java.util.Set;
27
28 @ThreadSafe abstract class AbstractCopyOnWriteMap<K, V, M extends Map<K, V>> implements Map<K, V>, Serializable {
29 private static final long serialVersionUID = 4508989182041753878L;
30
31 private volatile M delegate;
32 private final transient EntrySet entrySet = new EntrySet();
33 private final transient KeySet keySet = new KeySet();
34 private final transient Values values = new Values();
35
36
37
38
39
40
41
42
43 protected <N extends Map<? extends K, ? extends V>> AbstractCopyOnWriteMap(final N map) {
44 this.delegate = notNull("delegate", copy(notNull("map", map)));
45 }
46
47 abstract <N extends Map<? extends K, ? extends V>> M copy(N map);
48
49
50
51
52
53 public synchronized final void clear() {
54 final M map = copy();
55 map.clear();
56 set(map);
57 }
58
59 public synchronized final V remove(final Object key) {
60
61 if (!delegate.containsKey(key)) {
62 return null;
63 }
64 final M map = copy();
65 final V result = map.remove(key);
66 set(map);
67 return result;
68 }
69
70 public synchronized final V put(final K key, final V value) {
71 final M map = copy();
72 final V result = map.put(key, value);
73 set(map);
74 return result;
75 }
76
77 public synchronized final void putAll(final Map<? extends K, ? extends V> t) {
78 final M map = copy();
79 map.putAll(t);
80 set(map);
81 }
82
83 protected synchronized void removeAll(final Collection<K> keys) {
84 final M map = copy();
85 for (final K k : keys) {
86 map.remove(k);
87 }
88 set(map);
89 }
90
91 protected synchronized M copy() {
92 return copy(delegate);
93 }
94
95 protected synchronized void set(final M map) {
96 delegate = map;
97 }
98
99
100
101
102
103 public final Set<Map.Entry<K, V>> entrySet() {
104 return entrySet;
105 }
106
107 public final Set<K> keySet() {
108 return keySet;
109 }
110
111 public final Collection<V> values() {
112 return values;
113 }
114
115
116
117
118
119 public final boolean containsKey(final Object key) {
120 return delegate.containsKey(key);
121 }
122
123 public final boolean containsValue(final Object value) {
124 return delegate.containsValue(value);
125 }
126
127 public final V get(final Object key) {
128 return delegate.get(key);
129 }
130
131 public final boolean isEmpty() {
132 return delegate.isEmpty();
133 }
134
135 public final int size() {
136 return delegate.size();
137 }
138
139 @Override public final boolean equals(final Object o) {
140 return delegate.equals(o);
141 }
142
143 @Override public final int hashCode() {
144 return delegate.hashCode();
145 }
146
147 protected final M getDelegate() {
148 return delegate;
149 }
150
151 @Override public String toString() {
152 return delegate.toString();
153 }
154
155
156
157
158
159
160
161
162
163 protected interface CopyFunction<M extends Map<?, ?>> {
164
165
166
167
168
169
170
171
172 M copy(M map);
173 }
174
175
176
177
178
179 private class KeySet extends CollectionView<K> implements Set<K> {
180
181 @Override Collection<K> getDelegate() {
182 return delegate.keySet();
183 }
184
185
186
187
188
189 public void clear() {
190 synchronized (AbstractCopyOnWriteMap.this) {
191 final M map = copy();
192 map.keySet().clear();
193 set(map);
194 }
195 }
196
197 public boolean remove(final Object o) {
198 return AbstractCopyOnWriteMap.this.remove(o) != null;
199 }
200
201 public boolean removeAll(final Collection<?> c) {
202 synchronized (AbstractCopyOnWriteMap.this) {
203 final M map = copy();
204 final boolean result = map.keySet().removeAll(c);
205 set(map);
206 return result;
207 }
208 }
209
210 public boolean retainAll(final Collection<?> c) {
211 synchronized (AbstractCopyOnWriteMap.this) {
212 final M map = copy();
213 final boolean result = map.keySet().retainAll(c);
214 set(map);
215 return result;
216 }
217 }
218 }
219
220 private final class Values extends CollectionView<V> implements Collection<V> {
221
222 @Override Collection<V> getDelegate() {
223 return delegate.values();
224 }
225
226 public void clear() {
227 synchronized (AbstractCopyOnWriteMap.this) {
228 final M map = copy();
229 map.values().clear();
230 set(map);
231 }
232 }
233
234 public boolean remove(final Object o) {
235 synchronized (AbstractCopyOnWriteMap.this) {
236 if (!contains(o)) {
237 return false;
238 }
239 final M map = copy();
240 final boolean result = map.values().remove(o);
241 set(map);
242 return result;
243 }
244 }
245
246 public boolean removeAll(final Collection<?> c) {
247 synchronized (AbstractCopyOnWriteMap.this) {
248 final M map = copy();
249 final boolean result = map.values().removeAll(c);
250 set(map);
251 return result;
252 }
253 }
254
255 public boolean retainAll(final Collection<?> c) {
256 synchronized (AbstractCopyOnWriteMap.this) {
257 final M map = copy();
258 final boolean result = map.values().retainAll(c);
259 set(map);
260 return result;
261 }
262 }
263 }
264
265 private class EntrySet extends CollectionView<Entry<K, V>> implements Set<Map.Entry<K, V>> {
266
267 @Override Collection<java.util.Map.Entry<K, V>> getDelegate() {
268 return delegate.entrySet();
269 }
270
271 public void clear() {
272 synchronized (AbstractCopyOnWriteMap.this) {
273 final M map = copy();
274 map.entrySet().clear();
275 set(map);
276 }
277 }
278
279 public boolean remove(final Object o) {
280 synchronized (AbstractCopyOnWriteMap.this) {
281 if (!contains(o)) {
282 return false;
283 }
284 final M map = copy();
285 final boolean result = map.entrySet().remove(o);
286 set(map);
287 return result;
288 }
289 }
290
291 public boolean removeAll(final Collection<?> c) {
292 synchronized (AbstractCopyOnWriteMap.this) {
293 final M map = copy();
294 final boolean result = map.entrySet().removeAll(c);
295 set(map);
296 return result;
297 }
298 }
299
300 public boolean retainAll(final Collection<?> c) {
301 synchronized (AbstractCopyOnWriteMap.this) {
302 final M map = copy();
303 final boolean result = map.entrySet().retainAll(c);
304 set(map);
305 return result;
306 }
307 }
308 }
309
310 private static class UnmodifiableIterator<T> implements Iterator<T> {
311 private final Iterator<T> delegate;
312
313 public UnmodifiableIterator(final Iterator<T> delegate) {
314 this.delegate = delegate;
315 }
316
317 public boolean hasNext() {
318 return delegate.hasNext();
319 }
320
321 public T next() {
322 return delegate.next();
323 }
324
325 public void remove() {
326 throw new UnsupportedOperationException();
327 }
328 }
329
330 protected static abstract class CollectionView<E> implements Collection<E> {
331
332 abstract Collection<E> getDelegate();
333
334
335
336
337
338 public final boolean contains(final Object o) {
339 return getDelegate().contains(o);
340 }
341
342 public final boolean containsAll(final Collection<?> c) {
343 return getDelegate().containsAll(c);
344 }
345
346 public final Iterator<E> iterator() {
347 return new UnmodifiableIterator<E>(getDelegate().iterator());
348 }
349
350 public final boolean isEmpty() {
351 return getDelegate().isEmpty();
352 }
353
354 public final int size() {
355 return getDelegate().size();
356 }
357
358 public final Object[] toArray() {
359 return getDelegate().toArray();
360 }
361
362 public final <T> T[] toArray(final T[] a) {
363 return getDelegate().toArray(a);
364 }
365
366 @Override public int hashCode() {
367 return getDelegate().hashCode();
368 }
369
370 @Override public boolean equals(final Object obj) {
371 return getDelegate().equals(obj);
372 }
373
374
375
376
377
378 public final boolean add(final E o) {
379 throw new UnsupportedOperationException();
380 }
381
382 public final boolean addAll(final Collection<? extends E> c) {
383 throw new UnsupportedOperationException();
384 }
385 }
386 }