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.getConfigurationsCache(id);
259 ConfigurationPropertiesManagement config = getCached(key, cache);
260 if (config == null)
261 {
262 config = factory.create(key);
263 putInCache(key, config);
264 }
265 return config;
266 }
267
268 private ConfigurationPropertiesManagement getCached(
269 final ConfigurationKey<?> key,
270 final Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement> cache)
271 {
272 ConfigurationPropertiesManagement config;
273 if (!permOnly() && key.hasActiveDynamicParts())
274 {
275 config = cache.get(key);
276 }
277 else
278 {
279 config = permanentStore.get(key);
280 }
281 return config;
282 }
283
284
285
286
287
288
289 public static final String PERM_ONLY = "store.permonly";
290
291 private static boolean permOnly()
292 {
293
294 final boolean permOnly = "true".equals(System.getProperty(PERM_ONLY));
295 return permOnly;
296 }
297
298
299
300 @SuppressWarnings({ "unchecked", "rawtypes" })
301 private void putInCache(final ConfigurationKey<?> key,
302 final ConfigurationPropertiesManagement config)
303 {
304 if (!permOnly() && key.hasActiveDynamicParts())
305 {
306 final Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement> cache =
307 (Cache) CacheManagerFactory.getConfigurationsCache(id);
308 cache.put(key, config);
309 }
310 else
311 {
312 permanentStore.put(key, config);
313 }
314 }
315
316 @Override
317 public void registerProperties(final ConfigurationKey<?> key,
318 final ConfigurationPropertiesManagement configurationProperties)
319 throws NullArgumentException, DuplicateConfigurationException
320 {
321 writeLock.lock();
322 try
323 {
324 final ConfigurationPropertiesManagement current = getCachedOrCreate(key);
325 if (current != null)
326 {
327 throw new DuplicateConfigurationException(key, current,
328 configurationProperties);
329 }
330 putInCache(key, configurationProperties);
331 }
332 finally
333 {
334 writeLock.unlock();
335 }
336 }
337
338 @SuppressWarnings("unchecked")
339 @Override
340 public ConfigurationPropertiesManagement deregisterProperties(
341 final ConfigurationKey<?> key) throws NullArgumentException
342 {
343 writeLock.lock();
344 try
345 {
346 if (!permOnly() && key.hasActiveDynamicParts())
347 {
348 final Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement> cache =
349 (Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement>) CacheManagerFactory
350 .getConfigurationsCache(id);
351 return cache.remove(key);
352 }
353 else
354 {
355 return permanentStore.remove(key);
356 }
357 }
358 finally
359 {
360 writeLock.unlock();
361 }
362 }
363
364 @SuppressWarnings({ "unchecked", "rawtypes" })
365 @Override
366 public Collection<ConfigurationKey<?>> getKeys()
367 {
368 readLock.lock();
369 try
370 {
371 final Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement> cache =
372 (Cache) CacheManagerFactory.getConfigurationsCache(id);
373 final Set<ConfigurationKey<?>> keys =
374 new HashSet<ConfigurationKey<?>>(cache.keySet());
375 keys.addAll(permanentStore.keySet());
376 return keys;
377 }
378 finally
379 {
380 readLock.unlock();
381 }
382 }
383
384 @Override
385 public void release()
386 {
387 CacheManagerFactory.discard(id);
388 }
389
390
391
392
393
394
395
396
397
398
399 private void readObject(final ObjectInputStream in) throws IOException,
400 ClassNotFoundException
401 {
402 in.defaultReadObject();
403 }
404
405
406
407
408
409
410 @SuppressWarnings({ "unchecked", "rawtypes" })
411 @Override
412 public String toString()
413 {
414 readLock.lock();
415 final StringBuilder buffer = new StringBuilder();
416 final Cache<ConfigurationKey<?>, ConfigurationPropertiesManagement> cache =
417 (Cache) CacheManagerFactory.getConfigurationsCache(id);
418 buffer.append("The cache contains ")
419 .append(cache.size() + permanentStore.size()).append(" entries.");
420 try
421 {
422 for (final ConfigurationKey<?> key : permanentStore.keySet())
423 {
424 buffer.append("\n ").append(key);
425 }
426 for (final ConfigurationKey<?> key : cache.keySet())
427 {
428 buffer.append("\n ").append(key);
429 }
430 }
431 finally
432 {
433 readLock.unlock();
434 }
435
436 return buffer.toString();
437 }
438 }