View Javadoc

1   /*
2    * Created on 22-Sep-2006
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      // fields
34  
35      private final ConfigSource primarySource;
36  
37      private final ConfigSource secondarySource;
38  
39      // constructors
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      // accessors
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      // config source methods
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         // here we adjust the size by the reciprocal of the hash map's default
112         // load-factor
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 }