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 public static String processPropertyFilesString(ServletContext context, String servername, String webapp,
312 String propertiesFilesString) {
313
314 propertiesFilesString = StringUtils.replace(propertiesFilesString, "${servername}", servername);
315 propertiesFilesString = StringUtils.replace(propertiesFilesString, "${webapp}", webapp);
316
317
318 String[] contextAttributeNames = getNamesBetweenPlaceholders(propertiesFilesString, CONTEXT_ATTRIBUTE_PLACEHOLDER_PREFIX);
319 if (contextAttributeNames != null) {
320 for (String ctxAttrName : contextAttributeNames) {
321 if (ctxAttrName != null) {
322
323
324 final String originalPlaceHolder = PLACEHOLDER_PREFIX + CONTEXT_ATTRIBUTE_PLACEHOLDER_PREFIX + ctxAttrName + PLACEHOLDER_SUFFIX;
325 final Object attrValue = context.getAttribute(ctxAttrName);
326 if (attrValue != null) {
327 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, attrValue.toString());
328 }
329 }
330 }
331 }
332
333
334 String[] contextParamNames = getNamesBetweenPlaceholders(propertiesFilesString, CONTEXT_PARAM_PLACEHOLDER_PREFIX);
335 if (contextParamNames != null) {
336 for (String ctxParamName : contextParamNames) {
337 if (ctxParamName != null) {
338
339 final String originalPlaceHolder = PLACEHOLDER_PREFIX + CONTEXT_PARAM_PLACEHOLDER_PREFIX + ctxParamName + PLACEHOLDER_SUFFIX;
340 final String paramValue = context.getInitParameter(ctxParamName);
341 if (paramValue != null) {
342 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
343 }
344 }
345 }
346 }
347
348
349 String[] systemPropertiesNames = getNamesBetweenPlaceholders(propertiesFilesString, SYSTEM_PROPERTY_PLACEHOLDER_PREFIX);
350 if (systemPropertiesNames != null) {
351 for (String sysPropName : systemPropertiesNames) {
352 if (StringUtils.isNotBlank(sysPropName)) {
353 final String originalPlaceHolder = PLACEHOLDER_PREFIX + SYSTEM_PROPERTY_PLACEHOLDER_PREFIX + sysPropName + PLACEHOLDER_SUFFIX;
354 final String paramValue = System.getProperty(sysPropName);
355 if (paramValue != null) {
356 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
357 }
358 }
359 }
360 }
361
362
363 String[] envPropertiesNames = getNamesBetweenPlaceholders(propertiesFilesString, ENV_PROPERTY_PLACEHOLDER_PREFIX);
364 if (envPropertiesNames != null) {
365 for (String envPropName : envPropertiesNames) {
366 if (StringUtils.isNotBlank(envPropName)) {
367 final String originalPlaceHolder = PLACEHOLDER_PREFIX + ENV_PROPERTY_PLACEHOLDER_PREFIX + envPropName + PLACEHOLDER_SUFFIX;
368 final String paramValue = System.getenv(envPropName);
369 if (paramValue != null) {
370 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
371 }
372 }
373 }
374 }
375
376 return propertiesFilesString;
377 }
378
379 private static String[] getNamesBetweenPlaceholders(String propertiesFilesString, String contextNamePlaceHolder) {
380 final String[] names = StringUtils.substringsBetween(
381 propertiesFilesString,
382 PLACEHOLDER_PREFIX + contextNamePlaceHolder,
383 PLACEHOLDER_SUFFIX);
384 return StringUtils.stripAll(names);
385 }
386
387
388
389
390
391
392
393 protected String parseStringValue(String strVal, Set<String> visitedPlaceholders) {
394
395 StringBuffer buf = new StringBuffer(strVal);
396
397 int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
398 while (startIndex != -1) {
399 int endIndex = -1;
400
401 int index = startIndex + PLACEHOLDER_PREFIX.length();
402 int withinNestedPlaceholder = 0;
403 while (index < buf.length()) {
404 if (PLACEHOLDER_SUFFIX.equals(buf.subSequence(index, index + PLACEHOLDER_SUFFIX.length()))) {
405 if (withinNestedPlaceholder > 0) {
406 withinNestedPlaceholder--;
407 index = index + PLACEHOLDER_SUFFIX.length();
408 }
409 else {
410 endIndex = index;
411 break;
412 }
413 }
414 else if (PLACEHOLDER_PREFIX.equals(buf.subSequence(index, index + PLACEHOLDER_PREFIX.length()))) {
415 withinNestedPlaceholder++;
416 index = index + PLACEHOLDER_PREFIX.length();
417 }
418 else {
419 index++;
420 }
421 }
422
423 if (endIndex != -1) {
424 String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
425 if (!visitedPlaceholders.add(placeholder)) {
426
427 log.warn("Circular reference detected in properties, \"{}\" is not resolvable", strVal);
428 return strVal;
429 }
430
431 placeholder = parseStringValue(placeholder, visitedPlaceholders);
432
433 String propVal = SystemProperty.getProperty(placeholder);
434 if (propVal != null) {
435
436
437 propVal = parseStringValue(propVal, visitedPlaceholders);
438 buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal);
439 startIndex = buf.indexOf(PLACEHOLDER_PREFIX, startIndex + propVal.length());
440 }
441 else {
442
443 startIndex = buf.indexOf(PLACEHOLDER_PREFIX, endIndex + PLACEHOLDER_SUFFIX.length());
444 }
445 visitedPlaceholders.remove(placeholder);
446 }
447 else {
448 startIndex = -1;
449 }
450 }
451
452 return buf.toString();
453 }
454
455 }