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