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