001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the License. 004 * 005 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 006 * specific language governing permission and limitations under the License. 007 * 008 * When distributing Covered Software, include this CDDL Header Notice in each file and include 009 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 010 * Header, with the fields enclosed by brackets [] replaced by your own identifying 011 * information: "Portions copyright [year] [name of copyright owner]". 012 * 013 * Copyright 2015 ForgeRock AS. 014 */ 015 016package org.forgerock.util; 017 018// Java SE 019import java.util.Collection; 020import java.util.Map; 021import java.util.Set; 022 023/** 024 * A map with lazy initialization. The factory is called to initialize the map 025 * on the first call to one of this object's methods. 026 * 027 * @param <K> 028 * The type of key. 029 * @param <V> 030 * The type of value. 031 */ 032public class LazyMap<K, V> implements Map<K, V> { 033 034 /** The map that this lazy map exposes, once initialized. */ 035 private Map<K, V> map; 036 037 /** Factory to create the instance of the map to expose. */ 038 protected Factory<Map<K, V>> factory; 039 040 /** 041 * Constructs a new lazy map. Allows factory to be set in subclass 042 * constructor. 043 */ 044 protected LazyMap() { 045 } 046 047 /** 048 * Constructs a new lazy map. 049 * 050 * @param factory 051 * factory to create the map instance to expose. 052 */ 053 public LazyMap(Factory<Map<K, V>> factory) { 054 this.factory = factory; 055 } 056 057 /** 058 * Performs lazy initialization of the map if not already performed, and 059 * returns the initialized map. 060 */ 061 private Map<K, V> lazy() { 062 if (map == null) { 063 synchronized (this) { 064 if (map == null) { 065 map = factory.newInstance(); 066 } 067 } 068 } 069 return map; 070 } 071 072 /** 073 * Returns the number of key-value mappings in this map. 074 */ 075 @Override 076 public int size() { 077 return lazy().size(); 078 } 079 080 /** 081 * Returns {@code true} if the map contains no key-value mappings. 082 */ 083 @Override 084 public boolean isEmpty() { 085 return lazy().isEmpty(); 086 } 087 088 /** 089 * Returns {@code true} if this map contains a mapping for the specified 090 * key. 091 * 092 * @param key 093 * the key whose presence in this map is to be tested. 094 * @return {@code true} if this map contains a mapping for the specified 095 * key. 096 */ 097 @Override 098 public boolean containsKey(Object key) { 099 return lazy().containsKey(key); 100 } 101 102 /** 103 * Returns {@code true} if the map maps one or more keys to the specified 104 * value. 105 * 106 * @param value 107 * the value whose presence in the map is to be tested. 108 * @return {@code true} if the map maps one or more keys to the specified 109 * value. 110 */ 111 @Override 112 public boolean containsValue(Object value) { 113 return lazy().containsValue(value); 114 } 115 116 /** 117 * Returns the value to which the specified key is mapped, or {@code null} 118 * if the map contains no mapping for the key. 119 * 120 * @param key 121 * the key whose associated value is to be returned. 122 * @return the value to which the specified key is mapped, or {@code null} 123 * if no mapping. 124 */ 125 @Override 126 public V get(Object key) { 127 return lazy().get(key); 128 } 129 130 /** 131 * Associates the specified value with the specified key in the map. 132 * 133 * @param key 134 * key with which the specified value is to be associated. 135 * @param value 136 * value to be associated with the specified key. 137 * @return the previous value associated with key, or {@code null} if no 138 * mapping. 139 */ 140 @Override 141 public V put(K key, V value) { 142 return lazy().put(key, value); 143 } 144 145 /** 146 * Removes the mapping for a key from the map if it is present. 147 * 148 * @param key 149 * key whose mapping is to be removed from the map. 150 * @return the previous value associated with key, or {@code null} if no 151 * mapping. 152 */ 153 @Override 154 public V remove(Object key) { 155 return lazy().remove(key); 156 } 157 158 /** 159 * Copies all of the mappings from the specified map to the map. 160 * 161 * @param m 162 * mappings to be stored in the map. 163 */ 164 @Override 165 public void putAll(Map<? extends K, ? extends V> m) { 166 lazy().putAll(m); 167 } 168 169 /** 170 * Removes all of the mappings from the map. 171 */ 172 @Override 173 public void clear() { 174 lazy().clear(); 175 } 176 177 /** 178 * Returns a {@link Set} view of the keys contained in the map. 179 */ 180 @Override 181 public Set<K> keySet() { 182 return lazy().keySet(); 183 } 184 185 /** 186 * Returns a {@link Collection} view of the values contained in the map. 187 */ 188 @Override 189 public Collection<V> values() { 190 return lazy().values(); 191 } 192 193 /** 194 * Returns a {@link Set} view of the mappings contained in the map. 195 */ 196 @Override 197 public Set<Map.Entry<K, V>> entrySet() { 198 return lazy().entrySet(); 199 } 200 201 /** 202 * Returns the hash code value for the map. 203 */ 204 @Override 205 public int hashCode() { 206 return lazy().hashCode(); 207 } 208 209 /** 210 * Compares the specified object with the map for equality. 211 * 212 * @param o 213 * object to be compared for equality with the map. 214 * @return {@code true} if the specified object is equal to the map. 215 */ 216 @Override 217 public boolean equals(Object o) { 218 return lazy().equals(o); 219 } 220}