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 }