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.net.URL;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.concurrent.locks.Lock;
28 import java.util.concurrent.locks.ReentrantReadWriteLock;
29
30 import javax.annotation.concurrent.ThreadSafe;
31
32 import de.smartics.properties.api.config.app.FactoryConfiguration;
33 import de.smartics.properties.api.config.domain.CompoundConfigurationException;
34 import de.smartics.properties.api.config.domain.ConfigurationCode;
35 import de.smartics.properties.api.config.domain.ConfigurationException;
36 import de.smartics.properties.api.config.domain.ConfigurationProperties;
37 import de.smartics.properties.api.config.domain.ConfigurationPropertiesManagement;
38 import de.smartics.properties.api.config.domain.ConfigurationRepositoryManagement;
39 import de.smartics.properties.api.config.domain.PropertyProvider;
40 import de.smartics.properties.api.config.domain.key.ConfigurationKey;
41 import de.smartics.properties.api.core.domain.PropertyDescriptorRegistry;
42 import de.smartics.properties.resource.domain.ArtifactId;
43 import de.smartics.properties.resource.domain.ArtifactRef;
44 import de.smartics.properties.resource.domain.ClassPathEnvironment;
45 import de.smartics.properties.resource.repository.RepositoryException;
46 import de.smartics.properties.resource.repository.ResourceRepository;
47 import de.smartics.properties.resource.repository.ResourceRepositoryFactory;
48 import de.smartics.properties.spi.config.domain.key.ConfigurationKeyContextManager;
49 import de.smartics.properties.spi.core.registry.InMemoryPropertyDescriptorRegistry;
50 import de.smartics.util.lang.Arg;
51 import de.smartics.util.lang.NullArgumentException;
52
53
54
55
56
57
58 @ThreadSafe
59 public abstract class AbstractConfigurationPropertiesFactory<T extends ConfigurationPropertiesManagement>
60 implements ConfigurationPropertiesManagementFactory
61 {
62
63
64
65
66
67
68
69 private static final long serialVersionUID = 1L;
70
71
72
73
74
75
76
77
78 private final List<URL> rootLocations = new ArrayList<URL>();
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 private final List<PropertyProvider> rootPropertyProviders =
96 new ArrayList<PropertyProvider>();
97
98
99
100
101
102
103 private final FactoryConfiguration factoryConfiguration =
104 new FactoryConfiguration();
105
106
107
108
109
110
111
112 private final Map<ArtifactId, ClassPathEnvironment> artifactIds =
113 new LinkedHashMap<ArtifactId, ClassPathEnvironment>();
114
115
116
117
118
119
120 private transient ConfigurationRepositoryManagement cache;
121
122
123
124
125
126
127 private final PropertyDescriptorRegistry registry =
128 new InMemoryPropertyDescriptorRegistry();
129
130
131
132
133
134
135 private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
136
137
138
139
140
141
142 private final Lock readLock = lock.readLock();
143
144
145
146
147
148
149 private final Lock writeLock = lock.writeLock();
150
151
152
153
154
155
156 private volatile boolean initialized;
157
158
159
160
161
162
163
164
165 protected AbstractConfigurationPropertiesFactory()
166 {
167 this.cache =
168 new InMemoryConfigurationRepositoryManagement(registry, createFactory());
169 }
170
171
172 private ConfigurationPropertiesManagementFactory createFactory()
173 {
174 return new ConfigurationPropertiesManagementFactory()
175 {
176 private static final long serialVersionUID = 1L;
177
178 @Override
179 public final ConfigurationPropertiesManagement create(
180 final ConfigurationKey<?> key)
181 {
182 return AbstractConfigurationPropertiesFactory.this
183 .createNewConfiguration(key);
184 }
185
186 @Override
187 public ConfigurationPropertiesManagement remove(
188 final ConfigurationKey<?> key) throws NullPointerException
189 {
190 return AbstractConfigurationPropertiesFactory.this.remove(key);
191 }
192
193 @Override
194 public FactoryConfiguration getFactoryConfiguration()
195 {
196 return AbstractConfigurationPropertiesFactory.this
197 .getFactoryConfiguration();
198 }
199
200 @Override
201 public void addRootLocations(final Collection<URL> urls)
202 {
203 AbstractConfigurationPropertiesFactory.this.addRootLocations(urls);
204 }
205
206 @Override
207 public void addRootLocations(final URL... urls)
208 {
209 AbstractConfigurationPropertiesFactory.this.addRootLocations(urls);
210 }
211
212 @Override
213 public void addPropertyProviders(
214 final Collection<PropertyProvider> providers)
215 {
216 AbstractConfigurationPropertiesFactory.this
217 .addPropertyProviders(providers);
218 }
219
220 @Override
221 public void addPropertyProviders(final PropertyProvider... providers)
222 {
223 AbstractConfigurationPropertiesFactory.this
224 .addPropertyProviders(providers);
225 }
226
227 @Override
228 public ConfigurationPropertiesManagement createManagement(
229 final ConfigurationKey<?> key) throws NullPointerException,
230 ConfigurationException
231 {
232 return AbstractConfigurationPropertiesFactory.this
233 .createManagement(key);
234 }
235
236 @Override
237 public ConfigurationProperties createDefault()
238 throws ConfigurationException
239 {
240 return AbstractConfigurationPropertiesFactory.this.createDefault();
241 }
242
243 @Override
244 public ConfigurationPropertiesManagement createDefaultManagement()
245 throws ConfigurationException
246 {
247 return AbstractConfigurationPropertiesFactory.this
248 .createDefaultManagement();
249 }
250
251 @Override
252 public Collection<ConfigurationKey<?>> getRegisteredConfigurationKeys()
253 {
254 return AbstractConfigurationPropertiesFactory.this
255 .getRegisteredConfigurationKeys();
256 }
257
258 @Override
259 public PropertyDescriptorRegistry getRegistry()
260 {
261 return AbstractConfigurationPropertiesFactory.this.getRegistry();
262 }
263
264 @Override
265 public Collection<ConfigurationKey<?>> materialize()
266 {
267 return AbstractConfigurationPropertiesFactory.this.materialize();
268 }
269
270 @Override
271 public void release()
272 {
273 AbstractConfigurationPropertiesFactory.this.release();
274 }
275
276 @Override
277 public String addRootUrls(final ArtifactId artifactId)
278 throws NullArgumentException, RepositoryException,
279 CompoundConfigurationException
280 {
281 return AbstractConfigurationPropertiesFactory.this
282 .addRootUrls(artifactId);
283 }
284
285 @Override
286 public ArtifactRef getArtifactRef(final String artifactId)
287 throws NullPointerException
288 {
289 return AbstractConfigurationPropertiesFactory.this
290 .getArtifactRef(artifactId);
291 }
292 };
293 }
294
295
296
297
298
299
300
301
302
303
304
305 @Override
306 public final PropertyDescriptorRegistry getRegistry()
307 {
308 return registry;
309 }
310
311 @Override
312 public final FactoryConfiguration getFactoryConfiguration()
313 {
314 return factoryConfiguration;
315 }
316
317 @Override
318 public final void addRootLocations(final Collection<URL> urls)
319 {
320 if (urls != null && !urls.isEmpty())
321 {
322 writeLock.lock();
323 try
324 {
325 rootLocations.addAll(urls);
326 }
327 finally
328 {
329 writeLock.unlock();
330 }
331 }
332 }
333
334 @Override
335 public final void addRootLocations(final URL... urls)
336 {
337 if (urls != null && urls.length != 0)
338 {
339 writeLock.lock();
340 try
341 {
342 rootLocations.addAll(Arrays.asList(urls));
343 }
344 finally
345 {
346 writeLock.unlock();
347 }
348 }
349 }
350
351 @Override
352 public final void addPropertyProviders(
353 final Collection<PropertyProvider> providers)
354 {
355 if (providers != null && !providers.isEmpty())
356 {
357 writeLock.lock();
358 try
359 {
360 rootPropertyProviders.addAll(providers);
361 }
362 finally
363 {
364 writeLock.unlock();
365 }
366 }
367 }
368
369 @Override
370 public final void addPropertyProviders(final PropertyProvider... providers)
371 {
372 if (providers != null && providers.length != 0)
373 {
374 writeLock.lock();
375 try
376 {
377 rootPropertyProviders.addAll(Arrays.asList(providers));
378 }
379 finally
380 {
381 writeLock.unlock();
382 }
383 }
384 }
385
386
387
388 @Override
389 public final String addRootUrls(final ArtifactId artifactId)
390 throws NullArgumentException, RepositoryException,
391 CompoundConfigurationException
392 {
393 Arg.checkNotNull("artifactId", artifactId);
394
395 final ResourceRepositoryFactory factory = new ResourceRepositoryFactory();
396 final ResourceRepository repository = factory.create();
397 final ClassPathEnvironment resources = repository.resolve(artifactId);
398
399 synchronized (artifactIds)
400 {
401 artifactIds.put(artifactId, resources);
402 }
403
404 final List<URL> urls = resources.getUrls();
405 addRootLocations(urls);
406
407 return repository.getRemoteRepositoryUrl();
408 }
409
410 @Override
411 public final ArtifactRef getArtifactRef(final String artifactId)
412 throws NullPointerException
413 {
414 Arg.checkNotNull("artifactId", artifactId);
415
416 for (final ClassPathEnvironment env : artifactIds.values())
417 {
418 final ArtifactRef ref = env.getArtifactRef(artifactId);
419 if (ref != null)
420 {
421 return ref;
422 }
423 }
424
425 return null;
426 }
427
428 @Override
429 public final Collection<ConfigurationKey<?>> getRegisteredConfigurationKeys()
430 {
431 return cache.getKeys();
432 }
433
434 @Override
435 public final T create(final ConfigurationKey<?> key)
436 throws NullPointerException, ConfigurationException
437 {
438 return createManagement(key);
439 }
440
441 @Override
442 public final T createDefault()
443 {
444 final ConfigurationKey<?> key =
445 ConfigurationKeyContextManager.INSTANCE.context()
446 .configurationKeyFactory().createDefaultKey();
447 return create(key);
448 }
449
450 @Override
451 public final ConfigurationPropertiesManagement createDefaultManagement()
452 {
453 final ConfigurationKey<?> key =
454 ConfigurationKeyContextManager.INSTANCE.context()
455 .configurationKeyFactory().createDefaultKey();
456 return createManagement(key);
457 }
458
459 @Override
460 @SuppressWarnings("unchecked")
461 public final T createManagement(final ConfigurationKey<?> key)
462 throws NullPointerException, ConfigurationException
463 {
464 writeLock.lock();
465 try
466 {
467
468
469 return (T) getCachedOrCreate(key);
470 }
471 finally
472 {
473 writeLock.unlock();
474 }
475 }
476
477 private ConfigurationPropertiesManagement getCachedOrCreate(
478 final ConfigurationKey<?> key)
479 {
480 ConfigurationPropertiesManagement configuration = null;
481
482 if (!cache.hasPropertiesManagement(key))
483 {
484 configuration = createNewConfiguration(key);
485 }
486
487 initializeConfiguration();
488
489 final ConfigurationPropertiesManagement withDefaults =
490 cache.getPropertiesManagementWithDefaults(key);
491
492 if (withDefaults != null)
493 {
494 configuration = withDefaults;
495 }
496 else if (configuration != null)
497 {
498
499
500
501 cache.registerProperties(key, configuration);
502 }
503 else
504 {
505 throw new ConfigurationException(
506 ConfigurationCode.CONFIGURATION_ACCESS_FAILED, key);
507 }
508
509 return configuration;
510 }
511
512 private void initializeConfiguration()
513 {
514 if (!initialized)
515 {
516 final FactoryCache<T> factoryCache = new FactoryCache<T>(cache, this);
517
518 final ClassPathLoader<T> loader =
519 new ClassPathLoader<T>(factoryCache, false,
520 factoryConfiguration.isSkipClassPathPropertyLoading(),
521 factoryConfiguration.getDecrypter());
522
523 readLock.lock();
524 try
525 {
526 loader.addRootUrls(rootLocations);
527 loader.addRootProperties(rootPropertyProviders);
528 }
529 finally
530 {
531 readLock.unlock();
532 }
533
534 if (factoryConfiguration.isAddDefaultRootLocations())
535 {
536 loader.addDefaultRootUrls();
537 }
538 loader.load();
539
540 initialized = true;
541 }
542 }
543
544 @Override
545 public Collection<ConfigurationKey<?>> materialize()
546 {
547 writeLock.lock();
548 try
549 {
550 initializeConfiguration();
551 }
552 finally
553 {
554 writeLock.unlock();
555 }
556
557 final Collection<ConfigurationKey<?>> keys =
558 getRegisteredConfigurationKeys();
559 return keys;
560 }
561
562
563
564
565
566
567
568
569
570
571
572 protected abstract T createNewConfiguration(ConfigurationKey<?> key)
573 throws NullPointerException, ConfigurationException;
574
575
576
577 @Override
578 public void release()
579 {
580 cache.release();
581 }
582
583 @Override
584 public final ConfigurationPropertiesManagement remove(
585 final ConfigurationKey<?> key) throws NullPointerException
586 {
587 return cache.deregisterProperties(key);
588 }
589
590
591
592
593
594
595
596
597 private void readObject(final ObjectInputStream in) throws IOException,
598 ClassNotFoundException
599 {
600 in.defaultReadObject();
601
602 cache =
603 new InMemoryConfigurationRepositoryManagement(registry, createFactory());
604 }
605
606 @Override
607 public String toString()
608 {
609 final StringBuilder buffer = new StringBuilder(8192);
610 final Collection<ConfigurationKey<?>> keys = cache.getKeys();
611 buffer.append("The factory caches access to the following " + keys.size()
612 + " configurations:");
613 for (final ConfigurationKey<?> key : keys)
614 {
615 buffer.append("\n ").append(key);
616 }
617 buffer.append("\nDetails:");
618 for (final ConfigurationKey<?> key : keys)
619 {
620 final ConfigurationProperties config = cache.getProperties(key);
621 buffer.append("\n--> ").append(config);
622 }
623
624 synchronized (artifactIds)
625 {
626 for (final ArtifactId artifactId : artifactIds.keySet())
627 {
628 buffer.append(artifactId).append(' ');
629 }
630 }
631
632 return buffer.toString();
633 }
634 }