1 /*
2 Copyright 2007 Ramon Servadei
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16 package fulmine.util.reference;
17
18 import java.util.Collection;
19 import java.util.Map;
20 import java.util.Set;
21
22 import fulmine.util.collection.CollectionFactory;
23 import fulmine.util.collection.CollectionUtils;
24
25 /**
26 * This implementation manages a {@link Map} of objects against their key. When
27 * the store is requested for an object, identified by its key, it returns the
28 * cached object. The store uses an internal {@link IObjectBuilder} to create
29 * instances of objects that do not exist.
30 * <p>
31 * This is thread safe; all methods are synchronized and return a copy of the
32 * collection where appropriate.
33 *
34 * @author Ramon Servadei
35 *
36 * @param <KEY>
37 * The type of the key used to access objects in this store
38 * @param <TYPE>
39 * The type of canonical objects this returns
40 */
41 public final class AutoCreatingStore<KEY, TYPE> implements
42 IAutoCreatingStore<KEY, TYPE>
43 {
44 /** The builder to create the canonical object for each key */
45 private final IObjectBuilder<KEY, TYPE> builder;
46
47 /** The registry of canonical objects against their canonical representation */
48 private final Map<KEY, TYPE> registry = CollectionFactory.newMap(1);
49
50 /**
51 * Standard constructor
52 *
53 * @param builder
54 * the builder to use when constructing new canonical object
55 * instances
56 */
57 public AutoCreatingStore(IObjectBuilder<KEY, TYPE> builder)
58 {
59 super();
60 this.builder = builder;
61 }
62
63 public synchronized TYPE get(KEY key)
64 {
65 if (!registry.containsKey(key))
66 {
67 registry.put(key, builder.create(key));
68 }
69 return registry.get(key);
70 }
71
72 public synchronized TYPE remove(KEY key)
73 {
74 if (registry.containsKey(key))
75 {
76 return registry.remove(key);
77 }
78 return null;
79 }
80
81 public synchronized boolean containsKey(KEY key)
82 {
83 return registry.containsKey(key);
84 }
85
86 public synchronized void clear()
87 {
88 this.registry.clear();
89 }
90
91 public synchronized Set<KEY> keySet()
92 {
93 return CollectionFactory.newSet(this.registry.keySet());
94 }
95
96 public synchronized Collection<TYPE> values()
97 {
98 return CollectionFactory.newList(this.registry.values());
99 }
100
101 public synchronized void destroy()
102 {
103 this.registry.clear();
104 }
105
106 @Override
107 public synchronized String toString()
108 {
109 return getClass().getSimpleName()
110 + CollectionUtils.toFormattedString(this.registry);
111 }
112
113 @Override
114 public synchronized int hashCode()
115 {
116 final int prime = 31;
117 int result = 1;
118 result =
119 prime * result + ((registry == null) ? 0 : registry.hashCode());
120 return result;
121 }
122
123 @SuppressWarnings("unchecked")
124 @Override
125 public synchronized boolean equals(Object obj)
126 {
127 if (is.same(this, obj))
128 {
129 return true;
130 }
131 if (is.differentClass(this, obj))
132 {
133 return false;
134 }
135 final AutoCreatingStore other = (AutoCreatingStore) obj;
136 return is.eq(this.registry, other.registry);
137 }
138 }