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.GuardedBy;
21 import net.jcip.annotations.ThreadSafe;
22
23 import java.io.Serializable;
24 import java.util.Collection;
25 import java.util.Iterator;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.concurrent.ConcurrentMap;
29 import java.util.concurrent.locks.Lock;
30 import java.util.concurrent.locks.ReentrantLock;
31
32
33
34
35
36
37
38
39
40
41 @ThreadSafe
42 abstract class AbstractCopyOnWriteMap<K, V, M extends Map<K, V>> implements ConcurrentMap<K, V>, Serializable {
43 private static final long serialVersionUID = 4508989182041753878L;
44
45 @GuardedBy("lock")
46 private volatile M delegate;
47 private final transient EntrySet entrySet = new EntrySet();
48 private final transient KeySet keySet = new KeySet();
49 private final transient Values values = new Values();
50
51
52 private final transient Lock lock = new ReentrantLock();
53
54
55
56
57
58
59
60
61
62 protected <N extends Map<? extends K, ? extends V>> AbstractCopyOnWriteMap(final N map) {
63 this.delegate = notNull("delegate", copy(notNull("map", map)));
64 }
65
66
67
68
69
70
71
72
73 @GuardedBy("lock")
74 abstract <N extends Map<? extends K, ? extends V>> M copy(N map);
75
76
77
78
79
80 public final void clear() {
81 lock.lock();
82 try {
83 final M map = copy();
84 map.clear();
85 set(map);
86 } finally {
87 lock.unlock();
88 }
89 }
90
91 public final V remove(final Object key) {
92 lock.lock();
93 try {
94
95 if (!delegate.containsKey(key)) {
96 return null;
97 }
98 final M map = copy();
99 final V result = map.remove(key);
100 set(map);
101 return result;
102 } finally {
103 lock.unlock();
104 }
105 }
106
107 public boolean remove(final Object key, final Object value) {
108 lock.lock();
109 try {
110 if (delegate.containsKey(key) && equals(value, delegate.get(key))) {
111 final M map = copy();
112 map.remove(key);
113 set(map);
114 return true;
115 } else {
116 return false;
117 }
118 } finally {
119 lock.unlock();
120 }
121 }
122
123 public boolean replace(final K key, final V oldValue, final V newValue) {
124 lock.lock();
125 try {
126 if (delegate.containsKey(key) && equals(oldValue, delegate.get(key))) {
127 final M map = copy();
128 map.put(key, newValue);
129 set(map);
130 return true;
131 } else {
132 return false;
133 }
134 } finally {
135 lock.unlock();
136 }
137 };
138
139 public V replace(final K key, final V value) {
140 lock.lock();
141 try {
142 if (delegate.containsKey(key)) {
143 final M map = copy();
144 try {
145 return map.put(key, value);
146 } finally {
147 set(map);
148 }
149 } else {
150 return null;
151 }
152 } finally {
153 lock.unlock();
154 }
155 };
156
157 public final V put(final K key, final V value) {
158 lock.lock();
159 try {
160 final M map = copy();
161 final V result = map.put(key, value);
162 set(map);
163 return result;
164 } finally {
165 lock.unlock();
166 }
167 }
168
169 public V putIfAbsent(final K key, final V value) {
170 lock.lock();
171 try {
172 if (!delegate.containsKey(key)) {
173 final M map = copy();
174 final V result = map.put(key, value);
175 set(map);
176 return result;
177 }
178 return delegate.get(key);
179 } finally {
180 lock.unlock();
181 }
182 };
183
184 public final void putAll(final Map<? extends K, ? extends V> t) {
185 lock.lock();
186 try {
187 final M map = copy();
188 map.putAll(t);
189 set(map);
190 } finally {
191 lock.unlock();
192 }
193 }
194
195 protected M copy() {
196 lock.lock();
197 try {
198 return copy(delegate);
199 } finally {
200 lock.unlock();
201 }
202 }
203
204 @GuardedBy("lock")
205 protected void set(final M map) {
206 delegate = map;
207 }
208
209
210
211
212
213 public final Set<Map.Entry<K, V>> entrySet() {
214 return entrySet;
215 }
216
217 public final Set<K> keySet() {
218 return keySet;
219 }
220
221 public final Collection<V> values() {
222 return values;
223 }
224
225
226
227
228
229 public final boolean containsKey(final Object key) {
230 return delegate.containsKey(key);
231 }
232
233 public final boolean containsValue(final Object value) {
234 return delegate.containsValue(value);
235 }
236
237 public final V get(final Object key) {
238 return delegate.get(key);
239 }
240
241 public final boolean isEmpty() {
242 return delegate.isEmpty();
243 }
244
245 public final int size() {
246 return delegate.size();
247 }
248
249 @Override
250 public final boolean equals(final Object o) {
251 return delegate.equals(o);
252 }
253
254 @Override
255 public final int hashCode() {
256 return delegate.hashCode();
257 }
258
259 protected final M getDelegate() {
260 return delegate;
261 }
262
263 @Override
264 public String toString() {
265 return delegate.toString();
266 }
267
268
269
270
271
272 private class KeySet extends CollectionView<K> implements Set<K> {
273
274 @Override
275 Collection<K> getDelegate() {
276 return delegate.keySet();
277 }
278
279
280
281
282
283 public void clear() {
284 lock.lock();
285 try {
286 final M map = copy();
287 map.keySet().clear();
288 set(map);
289 } finally {
290 lock.unlock();
291 }
292 }
293
294 public boolean remove(final Object o) {
295 return AbstractCopyOnWriteMap.this.remove(o) != null;
296 }
297
298 public boolean removeAll(final Collection<?> c) {
299 lock.lock();
300 try {
301 final M map = copy();
302 final boolean result = map.keySet().removeAll(c);
303 set(map);
304 return result;
305 } finally {
306 lock.unlock();
307 }
308 }
309
310 public boolean retainAll(final Collection<?> c) {
311 lock.lock();
312 try {
313 final M map = copy();
314 final boolean result = map.keySet().retainAll(c);
315 set(map);
316 return result;
317 } finally {
318 lock.unlock();
319 }
320 }
321 }
322
323 private final class Values extends CollectionView<V> {
324
325 @Override
326 Collection<V> getDelegate() {
327 return delegate.values();
328 }
329
330 public void clear() {
331 lock.lock();
332 try {
333 final M map = copy();
334 map.values().clear();
335 set(map);
336 } finally {
337 lock.unlock();
338 }
339 }
340
341 public boolean remove(final Object o) {
342 lock.lock();
343 try {
344 if (!contains(o)) {
345 return false;
346 }
347 final M map = copy();
348 final boolean result = map.values().remove(o);
349 set(map);
350 return result;
351 } finally {
352 lock.unlock();
353 }
354 }
355
356 public boolean removeAll(final Collection<?> c) {
357 lock.lock();
358 try {
359 final M map = copy();
360 final boolean result = map.values().removeAll(c);
361 set(map);
362 return result;
363 } finally {
364 lock.unlock();
365 }
366 }
367
368 public boolean retainAll(final Collection<?> c) {
369 lock.lock();
370 try {
371 final M map = copy();
372 final boolean result = map.values().retainAll(c);
373 set(map);
374 return result;
375 } finally {
376 lock.unlock();
377 }
378 }
379 }
380
381 private class EntrySet extends CollectionView<Entry<K, V>> implements Set<Map.Entry<K, V>> {
382
383 @Override
384 Collection<java.util.Map.Entry<K, V>> getDelegate() {
385 return delegate.entrySet();
386 }
387
388 public void clear() {
389 lock.lock();
390 try {
391 final M map = copy();
392 map.entrySet().clear();
393 set(map);
394 } finally {
395 lock.unlock();
396 }
397 }
398
399 public boolean remove(final Object o) {
400 lock.lock();
401 try {
402 if (!contains(o)) {
403 return false;
404 }
405 final M map = copy();
406 final boolean result = map.entrySet().remove(o);
407 set(map);
408 return result;
409 } finally {
410 lock.unlock();
411 }
412 }
413
414 public boolean removeAll(final Collection<?> c) {
415 lock.lock();
416 try {
417 final M map = copy();
418 final boolean result = map.entrySet().removeAll(c);
419 set(map);
420 return result;
421 } finally {
422 lock.unlock();
423 }
424 }
425
426 public boolean retainAll(final Collection<?> c) {
427 lock.lock();
428 try {
429 final M map = copy();
430 final boolean result = map.entrySet().retainAll(c);
431 set(map);
432 return result;
433 } finally {
434 lock.unlock();
435 }
436 }
437 }
438
439 private static class UnmodifiableIterator<T> implements Iterator<T> {
440 private final Iterator<T> delegate;
441
442 public UnmodifiableIterator(final Iterator<T> delegate) {
443 this.delegate = delegate;
444 }
445
446 public boolean hasNext() {
447 return delegate.hasNext();
448 }
449
450 public T next() {
451 return delegate.next();
452 }
453
454 public void remove() {
455 throw new UnsupportedOperationException();
456 }
457 }
458
459 protected static abstract class CollectionView<E> implements Collection<E> {
460
461 abstract Collection<E> getDelegate();
462
463
464
465
466
467 public final boolean contains(final Object o) {
468 return getDelegate().contains(o);
469 }
470
471 public final boolean containsAll(final Collection<?> c) {
472 return getDelegate().containsAll(c);
473 }
474
475 public final Iterator<E> iterator() {
476 return new UnmodifiableIterator<E>(getDelegate().iterator());
477 }
478
479 public final boolean isEmpty() {
480 return getDelegate().isEmpty();
481 }
482
483 public final int size() {
484 return getDelegate().size();
485 }
486
487 public final Object[] toArray() {
488 return getDelegate().toArray();
489 }
490
491 public final <T> T[] toArray(final T[] a) {
492 return getDelegate().toArray(a);
493 }
494
495 @Override
496 public int hashCode() {
497 return getDelegate().hashCode();
498 }
499
500 @Override
501 public boolean equals(final Object obj) {
502 return getDelegate().equals(obj);
503 }
504
505 @Override
506 public String toString() {
507 return getDelegate().toString();
508 }
509
510
511
512
513
514 public final boolean add(final E o) {
515 throw new UnsupportedOperationException();
516 }
517
518 public final boolean addAll(final Collection<? extends E> c) {
519 throw new UnsupportedOperationException();
520 }
521 }
522
523 private boolean equals(final Object o1, final Object o2) {
524 if (o1 == null) {
525 return o2 == null;
526 }
527 return o1.equals(o2);
528 }
529 }