1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.cms.beans.config;
35
36 import info.magnolia.cms.core.Path;
37 import info.magnolia.cms.core.SystemProperty;
38 import info.magnolia.module.ModuleRegistry;
39 import info.magnolia.module.model.ModuleDefinition;
40 import info.magnolia.module.model.PropertyDefinition;
41 import info.magnolia.objectfactory.Components;
42
43 import java.io.File;
44 import java.io.FileInputStream;
45 import java.io.FileNotFoundException;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.text.MessageFormat;
49 import java.util.HashSet;
50 import java.util.Iterator;
51 import java.util.List;
52 import java.util.Properties;
53 import java.util.Set;
54
55 import javax.servlet.ServletContext;
56
57 import org.apache.commons.io.IOUtils;
58 import org.apache.commons.lang.ArrayUtils;
59 import org.apache.commons.lang.StringUtils;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63
64
65
66
67
68
69
70
71 public class PropertiesInitializer {
72 private static final Logger log = LoggerFactory.getLogger(PropertiesInitializer.class);
73
74
75
76
77 private static final String MGNL_BEANS_PROPERTIES = "/mgnl-beans.properties";
78
79
80
81
82 public static final String PLACEHOLDER_PREFIX = "${";
83
84
85
86
87 public static final String PLACEHOLDER_SUFFIX = "}";
88
89
90
91
92
93 public static final String CONTEXT_ATTRIBUTE_PLACEHOLDER_PREFIX = "contextAttribute/";
94
95
96
97
98
99 public static final String CONTEXT_PARAM_PLACEHOLDER_PREFIX = "contextParam/";
100
101
102
103
104
105 public static final String SYSTEM_PROPERTY_PLACEHOLDER_PREFIX = "systemProperty/";
106
107
108
109
110
111 public static final String ENV_PROPERTY_PLACEHOLDER_PREFIX = "env/";
112
113
114
115
116 public static PropertiesInitializer getInstance() {
117 return Components.getSingleton(PropertiesInitializer.class);
118 }
119
120
121
122
123 public static final String DEFAULT_INITIALIZATION_PARAMETER =
124 "WEB-INF/config/${servername}/${webapp}/magnolia.properties,"
125 + "WEB-INF/config/${servername}/magnolia.properties,"
126 + "WEB-INF/config/${webapp}/magnolia.properties,"
127 + "WEB-INF/config/default/magnolia.properties,"
128 + "WEB-INF/config/magnolia.properties";
129
130 private final ModuleRegistry moduleRegistry;
131
132 public PropertiesInitializer(ModuleRegistry moduleRegistry) {
133 this.moduleRegistry = moduleRegistry;
134 }
135
136 public void loadAllProperties(String propertiesFilesString, String rootPath) {
137
138 loadBeanProperties();
139
140 loadAllModuleProperties();
141
142
143 loadPropertiesFiles(propertiesFilesString, rootPath);
144
145
146 overloadWithSystemProperties();
147
148
149 resolveNestedProperties();
150 }
151
152 private void resolveNestedProperties() {
153
154 Properties sysProps = SystemProperty.getProperties();
155
156 for (Iterator<Object> it = sysProps.keySet().iterator(); it.hasNext();) {
157 String key = (String) it.next();
158 String oldValue = (String) sysProps.get(key);
159 String value = parseStringValue(oldValue, new HashSet<String>());
160 SystemProperty.getProperties().put(key, value.trim());
161 }
162
163 }
164
165 public void loadAllModuleProperties() {
166
167 final List<ModuleDefinition> moduleDefinitions = moduleRegistry.getModuleDefinitions();
168 loadModuleProperties(moduleDefinitions);
169 }
170
171
172
173
174
175 protected void loadModuleProperties(List<ModuleDefinition> moduleDefinitions) {
176 for (ModuleDefinition module : moduleDefinitions) {
177 for (PropertyDefinition property : module.getProperties()) {
178 SystemProperty.setProperty(property.getName(), property.getValue());
179 }
180 }
181 }
182
183 public void loadPropertiesFiles(String propertiesLocationString, String rootPath) {
184
185 String[] propertiesLocation = StringUtils.split(propertiesLocationString, ',');
186
187 boolean found = false;
188
189
190 for (int j = propertiesLocation.length - 1; j >= 0; j--) {
191 String location = StringUtils.trim(propertiesLocation[j]);
192
193 if (loadPropertiesFile(rootPath, location)) {
194 found = true;
195 }
196 }
197
198 if (!found) {
199 final String msg = MessageFormat.format("No configuration found using location list {0}. Base path is [{1}]", ArrayUtils.toString(propertiesLocation), rootPath);
200 log.error(msg);
201 throw new ConfigurationException(msg);
202 }
203 }
204
205
206
207
208
209 public void loadBeanProperties() {
210 InputStream mgnlbeansStream = getClass().getResourceAsStream(MGNL_BEANS_PROPERTIES);
211
212 if (mgnlbeansStream != null) {
213 Properties mgnlbeans = new Properties();
214 try {
215 mgnlbeans.load(mgnlbeansStream);
216 }
217 catch (IOException e) {
218 log.error("Unable to load {} due to an IOException: {}", MGNL_BEANS_PROPERTIES, e.getMessage());
219 }
220 finally {
221 IOUtils.closeQuietly(mgnlbeansStream);
222 }
223
224 for (Iterator<Object> iter = mgnlbeans.keySet().iterator(); iter.hasNext();) {
225 String key = (String) iter.next();
226 SystemProperty.setProperty(key, mgnlbeans.getProperty(key));
227 }
228
229 }
230 else {
231 log.warn("{} not found in the classpath. Check that all the needed implementation classes are defined in your custom magnolia.properties file.", MGNL_BEANS_PROPERTIES);
232 }
233 }
234
235
236
237
238
239
240
241 public boolean loadPropertiesFile(String rootPath, String location) {
242 final File initFile;
243 if (Path.isAbsolute(location)) {
244 initFile = new File(location);
245 }
246 else {
247 initFile = new File(rootPath, location);
248 }
249
250 if (!initFile.exists() || initFile.isDirectory()) {
251 log.debug("Configuration file not found with path [{}]", initFile.getAbsolutePath());
252 return false;
253 }
254
255 InputStream fileStream = null;
256 try {
257 fileStream = new FileInputStream(initFile);
258 }
259 catch (FileNotFoundException e1) {
260 log.debug("Configuration file not found with path [{}]", initFile.getAbsolutePath());
261 return false;
262 }
263
264 try {
265 SystemProperty.getProperties().load(fileStream);
266 log.info("Loading configuration at {}", initFile.getAbsolutePath());
267 }
268 catch (Exception e) {
269 log.error(e.getMessage(), e);
270 return false;
271 }
272 finally {
273 IOUtils.closeQuietly(fileStream);
274 }
275 return true;
276 }
277
278
279
280
281 public void overloadWithSystemProperties() {
282 Iterator<Object> it = SystemProperty.getProperties().keySet().iterator();
283 while (it.hasNext()) {
284 String key = (String) it.next();
285 if (System.getProperties().containsKey(key)) {
286 log.info("system property found: {}", key);
287 String value = System.getProperty(key);
288 SystemProperty.setProperty(key, value);
289 }
290 }
291 }
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312 public static String processPropertyFilesString(ServletContext context, String servername, String webapp,
313 String propertiesFilesString) {
314
315 propertiesFilesString = StringUtils.replace(propertiesFilesString, "${servername}", servername);
316 propertiesFilesString = StringUtils.replace(propertiesFilesString, "${webapp}", webapp);
317
318
319 String[] contextAttributeNames = getNamesBetweenPlaceholders(propertiesFilesString, CONTEXT_ATTRIBUTE_PLACEHOLDER_PREFIX);
320 if (contextAttributeNames != null) {
321 for (String ctxAttrName : contextAttributeNames) {
322 if (ctxAttrName != null) {
323
324
325 final String originalPlaceHolder = PLACEHOLDER_PREFIX + CONTEXT_ATTRIBUTE_PLACEHOLDER_PREFIX + ctxAttrName + PLACEHOLDER_SUFFIX;
326 final Object attrValue = context.getAttribute(ctxAttrName);
327 if (attrValue != null) {
328 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, attrValue.toString());
329 }
330 }
331 }
332 }
333
334
335 String[] contextParamNames = getNamesBetweenPlaceholders(propertiesFilesString, CONTEXT_PARAM_PLACEHOLDER_PREFIX);
336 if (contextParamNames != null) {
337 for (String ctxParamName : contextParamNames) {
338 if (ctxParamName != null) {
339
340 final String originalPlaceHolder = PLACEHOLDER_PREFIX + CONTEXT_PARAM_PLACEHOLDER_PREFIX + ctxParamName + PLACEHOLDER_SUFFIX;
341 final String paramValue = context.getInitParameter(ctxParamName);
342 if (paramValue != null) {
343 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
344 }
345 }
346 }
347 }
348
349
350 String[] systemPropertiesNames = getNamesBetweenPlaceholders(propertiesFilesString, SYSTEM_PROPERTY_PLACEHOLDER_PREFIX);
351 if (systemPropertiesNames != null) {
352 for (String sysPropName : systemPropertiesNames) {
353 if (StringUtils.isNotBlank(sysPropName)) {
354 final String originalPlaceHolder = PLACEHOLDER_PREFIX + SYSTEM_PROPERTY_PLACEHOLDER_PREFIX + sysPropName + PLACEHOLDER_SUFFIX;
355 final String paramValue = System.getProperty(sysPropName);
356 if (paramValue != null) {
357 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
358 }
359 }
360 }
361 }
362
363
364 String[] envPropertiesNames = getNamesBetweenPlaceholders(propertiesFilesString, ENV_PROPERTY_PLACEHOLDER_PREFIX);
365 if (envPropertiesNames != null) {
366 for (String envPropName : envPropertiesNames) {
367 if (StringUtils.isNotBlank(envPropName)) {
368 final String originalPlaceHolder = PLACEHOLDER_PREFIX + ENV_PROPERTY_PLACEHOLDER_PREFIX + envPropName + PLACEHOLDER_SUFFIX;
369 final String paramValue = System.getenv(envPropName);
370 if (paramValue != null) {
371 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
372 }
373 }
374 }
375 }
376
377 return propertiesFilesString;
378 }
379
380 private static String[] getNamesBetweenPlaceholders(String propertiesFilesString, String contextNamePlaceHolder) {
381 final String[] names = StringUtils.substringsBetween(
382 propertiesFilesString,
383 PLACEHOLDER_PREFIX + contextNamePlaceHolder,
384 PLACEHOLDER_SUFFIX);
385 return StringUtils.stripAll(names);
386 }
387
388
389
390
391
392
393
394 protected String parseStringValue(String strVal, Set<String> visitedPlaceholders) {
395
396 StringBuffer buf = new StringBuffer(strVal);
397
398 int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
399 while (startIndex != -1) {
400 int endIndex = -1;
401
402 int index = startIndex + PLACEHOLDER_PREFIX.length();
403 int withinNestedPlaceholder = 0;
404 while (index < buf.length()) {
405 if (PLACEHOLDER_SUFFIX.equals(buf.subSequence(index, index + PLACEHOLDER_SUFFIX.length()))) {
406 if (withinNestedPlaceholder > 0) {
407 withinNestedPlaceholder--;
408 index = index + PLACEHOLDER_SUFFIX.length();
409 }
410 else {
411 endIndex = index;
412 break;
413 }
414 }
415 else if (PLACEHOLDER_PREFIX.equals(buf.subSequence(index, index + PLACEHOLDER_PREFIX.length()))) {
416 withinNestedPlaceholder++;
417 index = index + PLACEHOLDER_PREFIX.length();
418 }
419 else {
420 index++;
421 }
422 }
423
424 if (endIndex != -1) {
425 String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
426 if (!visitedPlaceholders.add(placeholder)) {
427
428 log.warn("Circular reference detected in properties, \"{}\" is not resolvable", strVal);
429 return strVal;
430 }
431
432 placeholder = parseStringValue(placeholder, visitedPlaceholders);
433
434 String propVal = SystemProperty.getProperty(placeholder);
435 if (propVal != null) {
436
437
438 propVal = parseStringValue(propVal, visitedPlaceholders);
439 buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal);
440 startIndex = buf.indexOf(PLACEHOLDER_PREFIX, startIndex + propVal.length());
441 }
442 else {
443
444 startIndex = buf.indexOf(PLACEHOLDER_PREFIX, endIndex + PLACEHOLDER_SUFFIX.length());
445 }
446 visitedPlaceholders.remove(placeholder);
447 }
448 else {
449 startIndex = -1;
450 }
451 }
452
453 return buf.toString();
454 }
455
456 }