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