1   /**
2    * Copyright 2008 Atlassian Pty Ltd 
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); 
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at 
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0 
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
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   * Abstract base class for COW {@link Map} implementations that delegate to an
37   * internal map.
38   * 
39   * @param <K> The key type
40   * @param <V> The value type
41   * @param <M> the internal {@link Map} or extension for things like sorted and
42   * navigable maps.
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      // import edu.umd.cs.findbugs.annotations.@SuppressWarnings
52      private final transient Lock lock = new ReentrantLock();
53  
54      // private final transient EntrySet entrySet = new EntrySet();
55      // private final transient KeySet keySet = new KeySet();
56      // private final transient Values values = new Values();
57      // private final View.Type viewType;
58      private final View<K, V> view;
59  
60      /**
61       * Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to
62       * initialize the values.
63       * 
64       * @param map the initial map to initialize with
65       * @param viewType for writable or read-only key, value and entrySet views
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       * Copy function, implemented by sub-classes.
74       * 
75       * @param <N> the map to copy and return.
76       * @param map the initial values of the newly created map.
77       * @return a new map. Will never be modified after construction.
78       */
79      @GuardedBy("lock")
80      abstract <N extends Map<? extends K, ? extends V>> M copy(N map);
81  
82      //
83      // mutable operations
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              // short circuit if key doesn't exist
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     // Collection views
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     // delegate operations
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     // inner classes
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         // mutable operations
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         // delegate operations
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         // unsupported operations
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      * Provides access to the views of the underlying key, value and entry
556      * collections.
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          * The different types of {@link View} available
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 }