1
2
3
4
5 package com.tomgibara.pronto.config.source;
6
7 import java.util.HashMap;
8 import java.util.Map;
9
10 import com.tomgibara.pronto.config.ConfigSource;
11 import com.tomgibara.pronto.util.Arguments;
12
13 /**
14 * <p>
15 * This class provides a simple way of combining the properties from two
16 * configuration sources into one. This implementation is thread-safe iff both
17 * original sources are threadsafe. Changes to the properties of either original
18 * source will be immediately reflected in the properties returned by this
19 * source.
20 * </p>
21 *
22 * <p>
23 * To combine more than two configuration sources consider chaining multiple
24 * instances of this class.
25 * </p>
26 *
27 * @author Tom Gibara.
28 *
29 */
30
31 public class CompositeConfigSource implements ConfigSource {
32
33
34
35 private final ConfigSource primarySource;
36
37 private final ConfigSource secondarySource;
38
39
40
41 /**
42 * Constructs a new composite configuration source from two existing
43 * sources. Where the same property is defined by both sources, the value
44 * provided by the primary source dominates.
45 *
46 * @param primarySource
47 * the primary source of configuration properties, not null
48 * @param secondarySource
49 * the secondary source of configuration properties, not null
50 */
51
52 public CompositeConfigSource(final ConfigSource primarySource, final ConfigSource secondarySource) {
53 Arguments.notNull(primarySource, "primarySource");
54 Arguments.notNull(secondarySource, "secondarySource");
55
56 this.primarySource = primarySource;
57 this.secondarySource = secondarySource;
58 }
59
60
61
62 /**
63 * @return the primary source with which this object was constructed, never
64 * null
65 */
66
67 public ConfigSource getPrimarySource() {
68 return primarySource;
69 }
70
71 /**
72 * @return the secondary source with which this object was constructed,
73 * never null
74 */
75
76 public ConfigSource getSecondarySource() {
77 return secondarySource;
78 }
79
80
81
82 /**
83 * Returns the latest time at which either of the underlying configuration
84 * sources was last modified.
85 *
86 * @return the time this source's properties were last modified
87 * @throws RuntimeException
88 * if either underlying source throws a RuntimeException
89 */
90
91 public long lastModified() throws RuntimeException {
92 return Math.max(primarySource.lastModified(), secondarySource.lastModified());
93 }
94
95 /**
96 * Returns the union of the properties from both underlying sources. Where
97 * the same property is defined by both sources, the value provided by the
98 * primary source dominates.
99 *
100 * @return the current properties for this source
101 * @throws RuntimeException
102 * if either underlying source throws a RuntimeException
103 */
104
105 public Map<String, String> getProperties() throws RuntimeException {
106 Map<String, String> primaryProps = primarySource.getProperties();
107 Map<String, String> secondaryProps = secondarySource.getProperties();
108 if (primaryProps.isEmpty()) return secondaryProps;
109 if (secondaryProps.isEmpty()) return primaryProps;
110 int size = primaryProps.size() + secondaryProps.size();
111
112
113 HashMap<String, String> properties = new HashMap<String, String>(size * 4 / 3);
114 properties.putAll(secondaryProps);
115 properties.putAll(primaryProps);
116 return properties;
117 }
118
119 }