1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package de.smartics.properties.spi.config.support;
17
18 import java.io.IOException;
19 import java.io.ObjectInputStream;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.UUID;
29 import java.util.concurrent.locks.Lock;
30 import java.util.concurrent.locks.ReentrantReadWriteLock;
31
32 import javax.annotation.concurrent.ThreadSafe;
33
34 import de.smartics.properties.api.config.domain.ConfigurationProperties;
35 import de.smartics.properties.api.config.domain.ConfigurationPropertiesManagement;
36 import de.smartics.properties.api.config.domain.ConfigurationRepositoryManagement;
37 import de.smartics.properties.api.config.domain.DuplicateConfigurationException;
38 import de.smartics.properties.api.config.domain.MissingConfigurationException;
39 import de.smartics.properties.api.config.domain.key.ConfigurationKey;
40 import de.smartics.properties.api.config.domain.key.KeyListBuilder;
41 import de.smartics.properties.api.core.domain.PropertyDescriptorRegistry;
42 import de.smartics.properties.spi.config.cache.Cache;
43 import de.smartics.properties.spi.config.cache.CacheManagerFactory;
44 import de.smartics.properties.spi.config.domain.key.ConfigurationKeyContextManager;
45 import de.smartics.util.lang.NullArgumentException;
46
47
48
49
50 @ThreadSafe
51 public final class InMemoryConfigurationRepositoryManagement implements
52 ConfigurationRepositoryManagement
53 {
54
55
56
57
58
59
60
61
62
63
64
65 private final String id = createId();
66
67
68
69
70
71
72 private final PropertyDescriptorRegistry registry;
73
74
75
76
77
78
79
80 private final ConfigurationPropertiesManagementFactory factory;
81
82
83
84
85
86 private final Map<ConfigurationKey<?>, ConfigurationPropertiesManagement> permanentStore =
87 Collections
88 .synchronizedMap(new HashMap<ConfigurationKey<?>, ConfigurationPropertiesManagement>());
89
90
91
92
93
94
95 private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
96
97
98
99
100
101
102 private final Lock readLock = lock.readLock();
103
104
105
106
107
108
109 private final Lock writeLock = lock.writeLock();
110
111
112
113
114
115
116
117
118
119
120
121
122 public InMemoryConfigurationRepositoryManagement(
123 final PropertyDescriptorRegistry registry,
124 final ConfigurationPropertiesManagementFactory factory)
125 {
126 this.registry = registry;
127 this.factory = factory;
128 }
129
130
131
132
133
134
135
136 private static String createId()
137 {
138 final UUID uuid = UUID.randomUUID();
139 final String id = "Management:ConfigurationPropertiesManagement/" + uuid;
140 return id;
141 }
142
143
144
145
146
147
148
149
150 @Override
151 public PropertyDescriptorRegistry getRegistry()
152 {
153 return registry;
154 }
155
156
157
158 @Override
159 public ConfigurationProperties getProperties(final ConfigurationKey<?> key)
160 throws NullArgumentException, MissingConfigurationException
161 {
162 return getPropertiesManagementWithDefaults(key);
163 }
164
165 @Override
166 public ConfigurationPropertiesManagement getPropertiesManagementWithDefaults(
167 final ConfigurationKey<?> key) throws NullArgumentException,
168 MissingConfigurationException
169 {
170 writeLock.lock();
171
172 try
173 {
174 return constructConfigurationWithDefaults(key);
175 }
176 finally
177 {
178 writeLock.unlock();
179 }
180 }
181
182 @Override
183 public ConfigurationPropertiesManagement getPropertiesManagement(
184 final ConfigurationKey<?> key) throws NullArgumentException,
185 MissingConfigurationException
186 {
187 readLock.lock();
188
189 try
190 {
191 final ConfigurationPropertiesManagement config = getCachedOrCreate(key);
192 if (config == null)
193 {
194 throw new MissingConfigurationException(key);
195 }
196 return config;
197 }
198 finally
199 {
200 readLock.unlock();
201 }
202 }
203
204 @Override
205 public boolean hasPropertiesManagement(final ConfigurationKey<?> key)
206 throws NullArgumentException
207 {
208 readLock.lock();
209 try
210 {
211 final ConfigurationPropertiesManagement config = getCachedOrCreate(key);
212 return config != null;
213 }
214 finally
215 {
216 readLock.unlock();
217 }
218 }
219
220
221
222
223 private ConfigurationPropertiesManagement constructConfigurationWithDefaults(
224 final ConfigurationKey<?> key)
225 {
226 final KeyListBuilder builder =
227 ConfigurationKeyContextManager.INSTANCE.context().keyListBuilder();
228
229 final List<ConfigurationKey<?>> keySet = builder.createKeyList(key);
230 final List<ConfigurationPropertiesManagement> defaults =
231 new ArrayList<ConfigurationPropertiesManagement>(keySet.size());
232 for (final ConfigurationKey<?> current : keySet)
233 {
234 final ConfigurationPropertiesManagement config =
235 getCachedOrCreate(current);
236 if (config != null)
237 {
238 defaults.add(config);
239 }
240 }
241
242 if (defaults.isEmpty())
243 {
244 return null;
245 }
246 if (defaults.size() == 1)
247 {
248 return defaults.get(0);
249 }
250 return new ConfigurationPropertiesManagementWithDefaults(defaults);
251 }
252
253 @SuppressWarnings({ "unchecked", "rawtypes" })
254 private ConfigurationPropertiesManagement getCachedOrCreate(
255 final ConfigurationKey<?> key)
256 {
257 final Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement> cache =
258 (Cache) CacheManagerFactory.getInstance().getManager(factory.getId())
259 .getConfigurationsCache(id);
260 ConfigurationPropertiesManagement config = getCached(key, cache);
261 if (config == null)
262 {
263 config = factory.create(key);
264 putInCache(key, config);
265 }
266 return config;
267 }
268
269 private ConfigurationPropertiesManagement getCached(
270 final ConfigurationKey<?> key,
271 final Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement> cache)
272 {
273 ConfigurationPropertiesManagement config;
274 if (!permOnly() && key.hasActiveDynamicParts())
275 {
276 config = cache.get(key);
277 }
278 else
279 {
280 config = permanentStore.get(key);
281 }
282 return config;
283 }
284
285
286
287
288
289
290 public static final String PERM_ONLY = "store.permonly";
291
292 private static boolean permOnly()
293 {
294
295 final boolean permOnly = "true".equals(System.getProperty(PERM_ONLY));
296 return permOnly;
297 }
298
299
300
301 @SuppressWarnings({ "unchecked", "rawtypes" })
302 private void putInCache(final ConfigurationKey<?> key,
303 final ConfigurationPropertiesManagement config)
304 {
305 if (!permOnly() && key.hasActiveDynamicParts())
306 {
307 final Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement> cache =
308 (Cache) CacheManagerFactory.getInstance().getManager(factory.getId())
309 .getConfigurationsCache(id);
310 cache.put(key, config);
311 }
312 else
313 {
314 permanentStore.put(key, config);
315 }
316 }
317
318 @Override
319 public void registerProperties(final ConfigurationKey<?> key,
320 final ConfigurationPropertiesManagement configurationProperties)
321 throws NullArgumentException, DuplicateConfigurationException
322 {
323 writeLock.lock();
324 try
325 {
326 final ConfigurationPropertiesManagement current = getCachedOrCreate(key);
327 if (current != null)
328 {
329 throw new DuplicateConfigurationException(key, current,
330 configurationProperties);
331 }
332 putInCache(key, configurationProperties);
333 }
334 finally
335 {
336 writeLock.unlock();
337 }
338 }
339
340 @SuppressWarnings("unchecked")
341 @Override
342 public ConfigurationPropertiesManagement deregisterProperties(
343 final ConfigurationKey<?> key) throws NullArgumentException
344 {
345 writeLock.lock();
346 try
347 {
348 if (!permOnly() && key.hasActiveDynamicParts())
349 {
350 final Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement> cache =
351 (Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement>) CacheManagerFactory
352 .getInstance().getManager(factory.getId())
353 .getConfigurationsCache(id);
354 return cache.remove(key);
355 }
356 else
357 {
358 return permanentStore.remove(key);
359 }
360 }
361 finally
362 {
363 writeLock.unlock();
364 }
365 }
366
367 @SuppressWarnings({ "unchecked", "rawtypes" })
368 @Override
369 public Collection<ConfigurationKey<?>> getKeys()
370 {
371 readLock.lock();
372 try
373 {
374 final Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement> cache =
375 (Cache) CacheManagerFactory.getInstance().getManager(factory.getId())
376 .getConfigurationsCache(id);
377 final Set<ConfigurationKey<?>> keys =
378 new HashSet<ConfigurationKey<?>>(cache.keySet());
379 keys.addAll(permanentStore.keySet());
380 return keys;
381 }
382 finally
383 {
384 readLock.unlock();
385 }
386 }
387
388 @Override
389 public void release()
390 {
391 CacheManagerFactory.getInstance().createManager().discard(id);
392 }
393
394
395
396
397
398
399
400
401
402
403 private void readObject(final ObjectInputStream in) throws IOException,
404 ClassNotFoundException
405 {
406 in.defaultReadObject();
407 }
408
409
410
411
412
413
414 @SuppressWarnings({ "unchecked", "rawtypes" })
415 @Override
416 public String toString()
417 {
418 readLock.lock();
419 final StringBuilder buffer = new StringBuilder();
420 final Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement> cache =
421 (Cache) CacheManagerFactory.getInstance().getManager(factory.getId())
422 .getConfigurationsCache(id);
423 buffer.append("The cache contains ")
424 .append(cache.size() + permanentStore.size()).append(" entries.");
425 try
426 {
427 for (final ConfigurationKey<?> key : permanentStore.keySet())
428 {
429 buffer.append("\n ").append(key);
430 }
431 for (final ConfigurationKey<?> key : cache.keySet())
432 {
433 buffer.append("\n ").append(key);
434 }
435 }
436 finally
437 {
438 readLock.unlock();
439 }
440
441 return buffer.toString();
442 }
443 }