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