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.BufferedInputStream;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.URL;
22 import java.net.URLClassLoader;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Enumeration;
26 import java.util.List;
27 import java.util.Properties;
28 import java.util.Set;
29
30 import javax.annotation.concurrent.NotThreadSafe;
31
32 import org.apache.commons.io.IOUtils;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import de.smartics.properties.api.config.app.BootProperties;
37 import de.smartics.properties.api.config.domain.CompoundConfigurationException;
38 import de.smartics.properties.api.config.domain.ConfigurationException;
39 import de.smartics.properties.api.config.domain.ConfigurationPropertiesManagement;
40 import de.smartics.properties.api.config.domain.ConfigurationValidationException;
41 import de.smartics.properties.api.config.domain.Property;
42 import de.smartics.properties.api.config.domain.PropertyLocation;
43 import de.smartics.properties.api.config.domain.PropertyProvider;
44 import de.smartics.properties.api.core.domain.PropertiesContext;
45 import de.smartics.properties.api.core.domain.PropertyDescriptor;
46 import de.smartics.properties.spi.core.classpath.PropertiesFilesLoader;
47 import de.smartics.properties.spi.core.metadata.PropertyMetaDataParser;
48 import de.smartics.util.lang.Arg;
49 import de.smartics.util.lang.NullArgumentException;
50
51
52
53
54 @NotThreadSafe
55 public final class BootLoader
56 {
57
58
59
60
61
62
63
64 private static final Logger LOG = LoggerFactory.getLogger(BootLoader.class);
65
66
67
68
69
70
71 private final ConfigurationPropertiesManagement configuration;
72
73
74
75
76
77 private final Collection<URL> rootUrls;
78
79
80
81
82
83
84
85
86
87
88
89
90
91 public BootLoader(final ConfigurationPropertiesManagement configuration,
92 final ClassLoader classLoader) throws NullArgumentException
93 {
94 this.configuration = Arg.checkNotNull("configuration", configuration);
95 this.rootUrls = readRootUrls(Arg.checkNotNull("classLoader", classLoader));
96 }
97
98
99
100
101
102
103
104 private static List<URL> readRootUrls(final ClassLoader classLoader)
105 throws NullArgumentException
106 {
107 final List<URL> list = new ArrayList<URL>();
108 try
109 {
110 final Enumeration<URL> rootUrls =
111 UrlUtil.getResourceUrls(classLoader, "");
112
113 while (rootUrls.hasMoreElements())
114 {
115 final URL rootUrl = rootUrls.nextElement();
116 list.add(rootUrl);
117 }
118 extendClasspath(classLoader, list);
119 }
120 catch (final IOException e)
121 {
122 LOG.warn("Cannot determine class path roots for the given class loader.",
123 e);
124 }
125
126 return list;
127 }
128
129
130
131
132
133
134
135
136
137 private static void extendClasspath(final ClassLoader classLoader,
138 final List<URL> list) throws IOException
139 {
140 final Enumeration<URL> metaInfRootUrls =
141 UrlUtil.getResourceUrls(classLoader, "/META-INF");
142 while (metaInfRootUrls.hasMoreElements())
143 {
144 final URL rootUrl = metaInfRootUrls.nextElement();
145 if (!list.contains(rootUrl))
146 {
147 list.add(rootUrl);
148 }
149 }
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163 public ConfigurationPropertiesManagement load()
164 throws CompoundConfigurationException
165 {
166 final MultiSourceProperties properties = loadProperties();
167
168 final List<ConfigurationException> exceptions = properties.getExceptions();
169 if (!exceptions.isEmpty())
170 {
171 throw new CompoundConfigurationException(configuration.getKey(),
172 exceptions);
173 }
174
175 addProperties(properties);
176
177 return configuration;
178 }
179
180
181
182
183
184
185
186
187
188 public ConfigurationPropertiesManagement loadAndValidate()
189 throws ConfigurationValidationException
190 {
191 load();
192 configuration.validate(true);
193
194 return configuration;
195 }
196
197 private MultiSourceProperties loadProperties()
198 {
199 final MultiSourceProperties allProperties =
200 new MultiSourceProperties(configuration.getKey(),
201 new ArrayList<ConfigurationException>());
202
203 final PropertiesFilesLoader loader = new PropertiesFilesLoader();
204 final Set<String> propertiesFiles = loader.getBootPropertiesFiles(rootUrls);
205
206 final ClassLoader classLoader =
207 new URLClassLoader(rootUrls.toArray(new URL[rootUrls.size()]), Thread
208 .currentThread().getContextClassLoader());
209 for (final String propertiesFile : propertiesFiles)
210 {
211 final Properties properties = loadProperties(classLoader, propertiesFile);
212 final PropertyLocation location =
213 new PropertyLocationHelper().createPropertyLocation(classLoader,
214 propertiesFile);
215 allProperties.add(location, properties);
216 }
217
218 return allProperties;
219 }
220
221 private Properties loadProperties(final ClassLoader classLoader,
222 final String propertiesFile)
223 {
224
225 final Properties properties = new Properties();
226 InputStream in = classLoader.getResourceAsStream(propertiesFile);
227 try
228 {
229 if (in != null)
230 {
231 in = new BufferedInputStream(in);
232 properties.load(in);
233 }
234 else
235 {
236 LOG.warn("Cannot find properties '" + propertiesFile
237 + "' in class path.");
238 }
239 }
240 catch (final IOException e)
241 {
242 LOG.warn("Cannot load properties from '" + propertiesFile + "'.");
243 }
244 finally
245 {
246 IOUtils.closeQuietly(in);
247 }
248
249 return properties;
250 }
251
252 private void addProperties(final MultiSourceProperties compositeProperties)
253 {
254 final Properties properties = new Properties();
255 final Class<?> type = BootProperties.class;
256
257 final PropertiesContext context = configuration.getContext(type);
258 final PropertyMetaDataParser propertyDescriptorParser =
259 PropertyMetaDataParser.create(context);
260
261 final List<PropertyDescriptor> descriptors =
262 propertyDescriptorParser.readDescriptors(type);
263
264 for (final PropertyDescriptor descriptor : descriptors)
265 {
266 final String propertyKey = descriptor.getKey().toString();
267 final Property property = compositeProperties.getValue(propertyKey);
268 if (property != null && property.getValue() != null)
269 {
270 properties.put(propertyKey, property);
271 }
272 else
273 {
274 properties.remove(propertyKey);
275 }
276 }
277
278 configuration.addDescriptors(type);
279 final PropertyProvider provider =
280 new PropertiesPropertyProvider(configuration.getKey(),
281 new PropertyLocation("boot-various"), properties);
282 configuration.addDefinitions(provider);
283 }
284
285
286
287 }