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.Serializable;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.Iterator;
23 import java.util.LinkedHashMap;
24 import java.util.LinkedList;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Properties;
28
29 import org.apache.commons.lang.ObjectUtils;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import de.smartics.properties.api.config.domain.ConfigurationException;
34 import de.smartics.properties.api.config.domain.DuplicatePropertyException;
35 import de.smartics.properties.api.config.domain.Property;
36 import de.smartics.properties.api.config.domain.PropertyLocation;
37 import de.smartics.properties.api.config.domain.PropertyProvider;
38 import de.smartics.properties.api.config.domain.key.ConfigurationKey;
39
40
41
42
43 class MultiSourceProperties implements Serializable
44 {
45
46
47
48
49
50
51
52
53
54
55 private static final long serialVersionUID = 1L;
56
57
58
59
60 private static final Logger LOG = LoggerFactory
61 .getLogger(MultiSourceProperties.class);
62
63
64
65
66
67
68
69
70 private final ConfigurationKey<?> configurationKey;
71
72
73
74
75
76
77
78 private final List<ConfigurationException> exceptions;
79
80
81
82
83
84
85 private final Map<PropertyLocation, PropertyProvider> propertiesMap =
86 new LinkedHashMap<PropertyLocation, PropertyProvider>();
87
88
89
90
91
92
93
94
95
96
97
98 MultiSourceProperties(final ConfigurationKey<?> configurationKey)
99 {
100 this(configurationKey, new ArrayList<ConfigurationException>());
101 }
102
103
104
105
106
107
108
109
110 MultiSourceProperties(final ConfigurationKey<?> configurationKey,
111 final List<ConfigurationException> exceptions)
112 {
113 this.configurationKey = configurationKey;
114 this.exceptions = exceptions;
115 }
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 public ConfigurationKey<?> getConfigurationKey()
131 {
132 return configurationKey;
133 }
134
135
136
137
138
139
140
141 public List<ConfigurationException> getExceptions()
142 {
143 if (exceptions != null)
144 {
145 return exceptions;
146 }
147 else
148 {
149 return Collections.emptyList();
150 }
151 }
152
153
154
155 void add(final PropertyLocation source, final Properties properties)
156 {
157 if (propertiesMap.containsKey(source))
158 {
159 LOG.warn("Properties from '{}' already added.", source);
160 return;
161 }
162
163 for (final Iterator<Object> i = properties.keySet().iterator(); i.hasNext();)
164 {
165 final Object key = i.next();
166 final Object value = properties.get(key);
167 if (contains(source, key, value))
168 {
169 LOG.info("Duplicate property '{}' of '{}' removed.", key, source);
170 i.remove();
171 }
172 }
173
174 final PropertiesPropertyProvider provider =
175 new PropertiesPropertyProvider(configurationKey, source, properties);
176 propertiesMap.put(source, provider);
177 }
178
179 void addProviders(final Collection<PropertyProvider> providers)
180 {
181 for (final PropertyProvider provider : providers)
182 {
183 if (configurationKey.equals(provider.getConfigurationKey()))
184 {
185 addProvider(provider);
186 }
187 }
188 }
189
190 void addProvider(final PropertyProvider provider)
191 {
192 final PropertyLocation source = provider.getSourceId();
193 if (propertiesMap.containsKey(source))
194 {
195 LOG.warn("Properties from '{}' already added.", source);
196 return;
197 }
198
199 propertiesMap.put(source, provider);
200 }
201
202 private boolean contains(final PropertyLocation newSource, final Object key,
203 final Object newValue)
204 {
205 boolean contains = false;
206 for (final Map.Entry<PropertyLocation, PropertyProvider> entry : propertiesMap
207 .entrySet())
208 {
209 final PropertyLocation currentSource = entry.getKey();
210 final PropertyProvider currentProperties = entry.getValue();
211
212 final String name = ObjectUtils.toString(key, null);
213 if (currentProperties.containsKey(name))
214 {
215 final Property property = currentProperties.getProperty(name);
216 final String currentValue =
217 property != null ? property.getValue() : null;
218 final String currentValueString =
219 ObjectUtils.toString(currentValue, null);
220 final String newValueString = ObjectUtils.toString(newValue, null);
221 if (!ObjectUtils.equals(currentValueString, newValueString))
222 {
223 if (exceptions != null)
224 {
225 addException(newSource, currentSource, name, currentValueString,
226 newValueString);
227 }
228 else
229 {
230 warnDuplicateWithDifferentValue(newSource, newValue, currentSource,
231 name, currentValue);
232 }
233 }
234 else
235 {
236 warnDuplicateWithSameValue(name, currentSource, newSource,
237 currentValue);
238 }
239
240 contains = true;
241 }
242 }
243
244 return contains;
245 }
246
247 private void addException(final PropertyLocation newSource,
248 final PropertyLocation currentSource, final String name,
249 final String currentValueString, final String newValueString)
250 {
251 final DuplicatePropertyException e =
252 new DuplicatePropertyException(configurationKey,
253 new Property(currentSource, ObjectUtils.toString(name, null),
254 currentValueString), new Property(newSource,
255 ObjectUtils.toString(name, null), newValueString));
256 exceptions.add(e);
257 }
258
259 private void warnDuplicateWithDifferentValue(
260 final PropertyLocation newSource, final Object newValue,
261 final PropertyLocation currentSource, final String name,
262 final String currentValue)
263 {
264 LOG.warn("Duplicate key '{}' with new value '{}' in\n '{}'."
265 + "\nAlready found in\n '{}'\nwith value '{}' (active).",
266 new Object[] { name, newValue, newSource, currentSource, currentValue });
267 }
268
269 private void warnDuplicateWithSameValue(final String name,
270 final PropertyLocation currentSource, final PropertyLocation newSource,
271 final Object commonValue)
272 {
273 LOG.warn("Duplicate key '{}' with same value '{}' in\n '{}'\n and in\n"
274 + " '{}'.", new Object[] { name, commonValue, currentSource,
275 newSource });
276 }
277
278 Property getValue(final String key)
279 {
280 return getValue(key, false);
281 }
282
283 Property getValue(final String key, final boolean excludeLazies)
284 {
285 final List<Property> properties = new LinkedList<Property>();
286 for (final Map.Entry<PropertyLocation, PropertyProvider> entry : propertiesMap
287 .entrySet())
288 {
289 final PropertyProvider currentProperties = entry.getValue();
290
291 if(excludeLazies && currentProperties.isLazy())
292 {
293 continue;
294 }
295
296 if (currentProperties.containsKey(key))
297 {
298 final Property property = currentProperties.getProperty(key);
299 properties.add(property);
300 }
301 }
302
303 if (properties.isEmpty())
304 {
305 return null;
306 }
307 else if (properties.size() == 1)
308 {
309 return properties.get(0);
310 }
311 else
312 {
313 LOG.warn("Duplicate key '{}' in\n {}.", new Object[] { key, properties });
314 return properties.get(0);
315 }
316 }
317
318
319
320
321
322
323
324 @Override
325 public String toString()
326 {
327 final StringBuilder buffer = new StringBuilder();
328
329 buffer.append(configurationKey).append('=');
330
331 for (final PropertyLocation source : propertiesMap.keySet())
332 {
333 buffer.append(' ').append(source);
334 }
335
336 if (exceptions != null)
337 {
338 buffer.append("Exceptions:");
339 for (final Exception e : exceptions)
340 {
341 buffer.append('\n').append(e.getMessage());
342 }
343 }
344
345 return buffer.toString();
346 }
347 }