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