1   package com.atlassian.plugin.util.concurrent;
2   
3   import java.util.Collections;
4   import java.util.HashMap;
5   import java.util.LinkedHashMap;
6   import java.util.Map;
7   import java.util.TreeMap;
8   import java.util.WeakHashMap;
9   
10  /**
11   * A thread-safe variant of {@link Map} in which all mutative operations (the
12   * "destructive" operations described by {@link Map} put, remove and so on) are
13   * implemented by making a fresh copy of the underlying map.
14   * <p>
15   * This is ordinarily too costly, but may be <em>more</em> efficient than
16   * alternatives when traversal operations vastly out-number mutations, and is
17   * useful when you cannot or don't want to synchronize traversals, yet need to
18   * preclude interference among concurrent threads. The "snapshot" style
19   * iterators on the collections returned by {@link #entrySet()},
20   * {@link #keySet()} and {@link #values()} use a reference to the internal map
21   * at the point that the iterator was created. This map never changes during the
22   * lifetime of the iterator, so interference is impossible and the iterator is
23   * guaranteed not to throw <tt>ConcurrentModificationException</tt>. The
24   * iterators will not reflect additions, removals, or changes to the list since
25   * the iterator was created. Removing elements via these iterators is not
26   * supported. The mutable operations on these collections (remove, retain etc.)
27   * are supported but as with the {@link Map} interface, add and addAll are not
28   * and throw {@link UnsupportedOperationException}.
29   * <p>
30   * The actual copy is performed by an abstract {@link #copy(Map)} method. The
31   * method is responsible for the underlying Map implementation (for instance a
32   * {@link HashMap}, {@link TreeMap}, {@link LinkedHashMap} etc.) and therefore
33   * the semantics of what this map will cope with as far as null keys and values,
34   * iteration ordering etc. See the note below about suitable candidates for
35   * underlying Map implementations
36   * <p>
37   * There are supplied implementations for the common Collections {@link Map}
38   * implementations via the {@link CopyOnWriteMaps} static factory methods.
39   * <p>
40   * Collection views of the keys, values and entries are modifiable and will
41   * cause a copy.
42   * <p>
43   * <strong>Please note</strong> that the thread-safety guarantees are limited to
44   * the thread-safety of the non-mutative (non-destructive) operations of the
45   * underlying map implementation. For instance some implementations such as
46   * {@link WeakHashMap} and {@link LinkedHashMap} with access ordering are
47   * actually structurally modified by the {@link #get(Object)} method and are
48   * therefore not suitable candidates as delegates for this class.
49   * 
50   * @param <K> the key type
51   * @param <V> the value type
52   * @author Jed Wesley-Smith
53   */
54  public abstract class CopyOnWriteMap<K, V> extends AbstractCopyOnWriteMap<K, V, Map<K, V>>
55  {
56      private static final long serialVersionUID = 7935514534647505917L;
57  
58      /**
59       * Creates a new {@link CopyOnWriteMap} with an underlying {@link HashMap}.
60       */
61      public static <K, V> CopyOnWriteMap<K, V> newHashMap()
62      {
63          return new CopyOnWriteMap<K, V>()
64          {
65              private static final long serialVersionUID = 5221824943734164497L;
66  
67              @Override
68              public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map)
69              {
70                  return new HashMap<K, V>(map);
71              }
72          };
73      }
74  
75      /**
76       * Creates a new {@link CopyOnWriteMap} with an underlying {@link HashMap}
77       * using the supplied map as the initial values.
78       */
79      public static <K, V> CopyOnWriteMap<K, V> newHashMap(final Map<? extends K, ? extends V> map)
80      {
81          return new CopyOnWriteMap<K, V>(map)
82          {
83              private static final long serialVersionUID = -7616159260882572421L;
84  
85              @Override
86              public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map)
87              {
88                  return new HashMap<K, V>(map);
89              }
90          };
91      }
92  
93      /**
94       * Creates a new {@link CopyOnWriteMap} with an underlying
95       * {@link LinkedHashMap}. Iterators for this map will be return elements in
96       * insertion order.
97       */
98      public static <K, V> CopyOnWriteMap<K, V> newLinkedMap()
99      {
100         return new CopyOnWriteMap<K, V>()
101         {
102             private static final long serialVersionUID = -4597421704607601676L;
103 
104             @Override
105             public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map)
106             {
107                 return new LinkedHashMap<K, V>(map);
108             }
109         };
110     }
111 
112     /**
113      * Creates a new {@link CopyOnWriteMap} with an underlying
114      * {@link LinkedHashMap} using the supplied map as the initial values.
115      * Iterators for this map will be return elements in insertion order.
116      */
117     public static <K, V> CopyOnWriteMap<K, V> newLinkedMap(final Map<? extends K, ? extends V> map)
118     {
119         return new CopyOnWriteMap<K, V>(map)
120         {
121             private static final long serialVersionUID = -8659999465009072124L;
122 
123             @Override
124             public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map)
125             {
126                 return new LinkedHashMap<K, V>(map);
127             }
128         };
129     }
130 
131     //
132     // constructors
133     //
134 
135     /**
136      * Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to
137      * initialize the values.
138      * 
139      * @param map the initial map to initialize with
140      */
141     public CopyOnWriteMap(final Map<? extends K, ? extends V> map)
142     {
143         super(map);
144     }
145 
146     /**
147      * Create a new empty {@link CopyOnWriteMap}.
148      */
149     public CopyOnWriteMap()
150     {
151         super(Collections.<K, V> emptyMap());
152     }
153 
154     @Override
155     protected abstract <N extends Map<? extends K, ? extends V>> Map<K, V> copy(N map);
156 }