1 /*
2 * The contents of this file are subject to the terms of the Common Development and
3 * Distribution License (the License). You may not use this file except in compliance with the
4 * License.
5 *
6 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7 * specific language governing permission and limitations under the License.
8 *
9 * When distributing Covered Software, include this CDDL Header Notice in each file and include
10 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11 * Header, with the fields enclosed by brackets [] replaced by your own identifying
12 * information: "Portions copyright [year] [name of copyright owner]".
13 *
14 * Copyright 2015-2016 ForgeRock AS.
15 */
16
17 package org.forgerock.util;
18
19 // Java SE
20 import java.util.Collection;
21 import java.util.Map;
22 import java.util.Set;
23
24 /**
25 * A map with lazy initialization. The factory is called to initialize the map
26 * on the first call to one of this object's methods.
27 *
28 * @param <K>
29 * The type of key.
30 * @param <V>
31 * The type of value.
32 */
33 public class LazyMap<K, V> implements Map<K, V> {
34
35 /** The map that this lazy map exposes, once initialized. */
36 private Map<K, V> map;
37
38 /** Factory to create the instance of the map to expose. */
39 protected Factory<Map<K, V>> factory;
40
41 /**
42 * Constructs a new lazy map. Allows factory to be set in subclass
43 * constructor.
44 */
45 protected LazyMap() {
46 }
47
48 /**
49 * Constructs a new lazy map.
50 *
51 * @param factory
52 * factory to create the map instance to expose.
53 */
54 public LazyMap(Factory<Map<K, V>> factory) {
55 this.factory = factory;
56 }
57
58 /**
59 * Performs lazy initialization of the map if not already performed, and
60 * returns the initialized map.
61 */
62 private Map<K, V> lazy() {
63 if (map == null) {
64 synchronized (this) {
65 if (map == null) {
66 map = factory.newInstance();
67 }
68 }
69 }
70 return map;
71 }
72
73 /**
74 * Returns the number of key-value mappings in this map.
75 */
76 @Override
77 public int size() {
78 return lazy().size();
79 }
80
81 /**
82 * Returns {@code true} if the map contains no key-value mappings.
83 */
84 @Override
85 public boolean isEmpty() {
86 return lazy().isEmpty();
87 }
88
89 /**
90 * Returns {@code true} if this map contains a mapping for the specified
91 * key.
92 *
93 * @param key
94 * the key whose presence in this map is to be tested.
95 * @return {@code true} if this map contains a mapping for the specified
96 * key.
97 */
98 @Override
99 public boolean containsKey(Object key) {
100 return lazy().containsKey(key);
101 }
102
103 /**
104 * Returns {@code true} if the map maps one or more keys to the specified
105 * value.
106 *
107 * @param value
108 * the value whose presence in the map is to be tested.
109 * @return {@code true} if the map maps one or more keys to the specified
110 * value.
111 */
112 @Override
113 public boolean containsValue(Object value) {
114 return lazy().containsValue(value);
115 }
116
117 /**
118 * Returns the value to which the specified key is mapped, or {@code null}
119 * if the map contains no mapping for the key.
120 *
121 * @param key
122 * the key whose associated value is to be returned.
123 * @return the value to which the specified key is mapped, or {@code null}
124 * if no mapping.
125 */
126 @Override
127 public V get(Object key) {
128 return lazy().get(key);
129 }
130
131 /**
132 * Associates the specified value with the specified key in the map.
133 *
134 * @param key
135 * key with which the specified value is to be associated.
136 * @param value
137 * value to be associated with the specified key.
138 * @return the previous value associated with key, or {@code null} if no
139 * mapping.
140 */
141 @Override
142 public V put(K key, V value) {
143 return lazy().put(key, value);
144 }
145
146 /**
147 * Removes the mapping for a key from the map if it is present.
148 *
149 * @param key
150 * key whose mapping is to be removed from the map.
151 * @return the previous value associated with key, or {@code null} if no
152 * mapping.
153 */
154 @Override
155 public V remove(Object key) {
156 return lazy().remove(key);
157 }
158
159 /**
160 * Copies all of the mappings from the specified map to the map.
161 *
162 * @param m
163 * mappings to be stored in the map.
164 */
165 @Override
166 public void putAll(Map<? extends K, ? extends V> m) {
167 lazy().putAll(m);
168 }
169
170 /**
171 * Removes all of the mappings from the map.
172 */
173 @Override
174 public void clear() {
175 lazy().clear();
176 }
177
178 /**
179 * Returns a {@link Set} view of the keys contained in the map.
180 */
181 @Override
182 public Set<K> keySet() {
183 return lazy().keySet();
184 }
185
186 /**
187 * Returns a {@link Collection} view of the values contained in the map.
188 */
189 @Override
190 public Collection<V> values() {
191 return lazy().values();
192 }
193
194 /**
195 * Returns a {@link Set} view of the mappings contained in the map.
196 */
197 @Override
198 public Set<Map.Entry<K, V>> entrySet() {
199 return lazy().entrySet();
200 }
201
202 /**
203 * Returns the hash code value for the map.
204 */
205 @Override
206 public int hashCode() {
207 return lazy().hashCode();
208 }
209
210 /**
211 * Compares the specified object with the map for equality.
212 *
213 * @param o
214 * object to be compared for equality with the map.
215 * @return {@code true} if the specified object is equal to the map.
216 */
217 @Override
218 public boolean equals(Object o) {
219 return lazy().equals(o);
220 }
221 }