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 = classLoader.getResources("");
111 while (rootUrls.hasMoreElements())
112 {
113 final URL rootUrl = rootUrls.nextElement();
114 list.add(rootUrl);
115 }
116 }
117 catch (final IOException e)
118 {
119 LOG.warn("Cannot determine class path roots for the given class loader.",
120 e);
121 }
122
123 return list;
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137 public ConfigurationPropertiesManagement load()
138 throws CompoundConfigurationException
139 {
140 final MultiSourceProperties properties = loadProperties();
141
142 final List<ConfigurationException> exceptions = properties.getExceptions();
143 if (!exceptions.isEmpty())
144 {
145 throw new CompoundConfigurationException(configuration.getKey(),
146 exceptions);
147 }
148
149 addProperties(properties);
150
151 return configuration;
152 }
153
154
155
156
157
158
159
160
161
162 public ConfigurationPropertiesManagement loadAndValidate()
163 throws ConfigurationValidationException
164 {
165 load();
166 configuration.validate(true);
167
168 return configuration;
169 }
170
171 private MultiSourceProperties loadProperties()
172 {
173 final MultiSourceProperties allProperties =
174 new MultiSourceProperties(configuration.getKey(),
175 new ArrayList<ConfigurationException>());
176
177 final PropertiesFilesLoader loader = new PropertiesFilesLoader();
178 final Set<String> propertiesFiles = loader.getBootPropertiesFiles(rootUrls);
179
180 final ClassLoader classLoader =
181 new URLClassLoader(rootUrls.toArray(new URL[rootUrls.size()]), Thread
182 .currentThread().getContextClassLoader());
183 for (final String propertiesFile : propertiesFiles)
184 {
185 final Properties properties = loadProperties(classLoader, propertiesFile);
186 final PropertyLocation location =
187 new PropertyLocationHelper().createPropertyLocation(classLoader,
188 propertiesFile);
189 allProperties.add(location, properties);
190 }
191
192 return allProperties;
193 }
194
195 private Properties loadProperties(final ClassLoader classLoader,
196 final String propertiesFile)
197 {
198
199 final Properties properties = new Properties();
200 InputStream in = classLoader.getResourceAsStream(propertiesFile);
201 try
202 {
203 if (in != null)
204 {
205 in = new BufferedInputStream(in);
206 properties.load(in);
207 }
208 else
209 {
210 LOG.warn("Cannot find properties '" + propertiesFile
211 + "' in class path.");
212 }
213 }
214 catch (final IOException e)
215 {
216 LOG.warn("Cannot load properties from '" + propertiesFile + "'.");
217 }
218 finally
219 {
220 IOUtils.closeQuietly(in);
221 }
222
223 return properties;
224 }
225
226 private void addProperties(final MultiSourceProperties compositeProperties)
227 {
228 final Properties properties = new Properties();
229 final Class<?> type = BootProperties.class;
230
231 final PropertiesContext context = configuration.getContext(type);
232 final PropertyMetaDataParser propertyDescriptorParser =
233 PropertyMetaDataParser.create(context);
234
235 final List<PropertyDescriptor> descriptors =
236 propertyDescriptorParser.readDescriptors(type);
237
238 for (final PropertyDescriptor descriptor : descriptors)
239 {
240 final String propertyKey = descriptor.getKey().toString();
241 final Property property = compositeProperties.getValue(propertyKey);
242 if (property != null && property.getValue() != null)
243 {
244 properties.put(propertyKey, property);
245 }
246 else
247 {
248 properties.remove(propertyKey);
249 }
250 }
251
252 configuration.addDescriptors(type);
253 final PropertyProvider provider =
254 new PropertiesPropertyProvider(configuration.getKey(),
255 new PropertyLocation("boot-various"), properties);
256 configuration.addDefinitions(provider);
257 }
258
259
260
261 }