View Javadoc
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 }