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.lang3.ArrayUtils;
60 import org.apache.commons.lang3.StringUtils;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64
65
66
67
68
69
70 public class PropertiesInitializer {
71 private static final Logger log = LoggerFactory.getLogger(PropertiesInitializer.class);
72
73
74
75
76 private static final String MGNL_BEANS_PROPERTIES = "/mgnl-beans.properties";
77
78
79
80
81 public static final String PLACEHOLDER_PREFIX = "${";
82
83
84
85
86 public static final String PLACEHOLDER_SUFFIX = "}";
87
88
89
90
91
92 public static final String CONTEXT_ATTRIBUTE_PLACEHOLDER_PREFIX = "contextAttribute/";
93
94
95
96
97
98 public static final String CONTEXT_PARAM_PLACEHOLDER_PREFIX = "contextParam/";
99
100
101
102
103
104 public static final String SYSTEM_PROPERTY_PLACEHOLDER_PREFIX = "systemProperty/";
105
106
107
108
109
110 public static final String ENV_PROPERTY_PLACEHOLDER_PREFIX = "env/";
111
112
113
114
115 public static PropertiesInitializer getInstance() {
116 return Components.getSingleton(PropertiesInitializer.class);
117 }
118
119
120
121
122 public static final String DEFAULT_INITIALIZATION_PARAMETER =
123 "WEB-INF/config/${servername}/${webapp}/magnolia.properties,"
124 + "WEB-INF/config/${servername}/magnolia.properties,"
125 + "WEB-INF/config/${webapp}/magnolia.properties,"
126 + "WEB-INF/config/default/magnolia.properties,"
127 + "WEB-INF/config/magnolia.properties";
128
129 private final ModuleRegistry moduleRegistry;
130
131 @Inject
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 public boolean loadPropertiesFile(String rootPath, String location) {
239 final File initFile;
240 if (Path.isAbsolute(location)) {
241 initFile = new File(location);
242 }
243 else {
244 initFile = new File(rootPath, location);
245 }
246
247 if (!initFile.exists() || initFile.isDirectory()) {
248 log.debug("Configuration file not found with path [{}]", initFile.getAbsolutePath());
249 return false;
250 }
251
252 InputStream fileStream = null;
253 try {
254 fileStream = new FileInputStream(initFile);
255 }
256 catch (FileNotFoundException e1) {
257 log.debug("Configuration file not found with path [{}]", initFile.getAbsolutePath());
258 return false;
259 }
260
261 try {
262 SystemProperty.getProperties().load(fileStream);
263 log.info("Loading configuration at {}", initFile.getAbsolutePath());
264 }
265 catch (Exception e) {
266 log.error(e.getMessage(), e);
267 return false;
268 }
269 finally {
270 IOUtils.closeQuietly(fileStream);
271 }
272 return true;
273 }
274
275
276
277
278 public void overloadWithSystemProperties() {
279 Iterator<Object> it = SystemProperty.getProperties().keySet().iterator();
280 while (it.hasNext()) {
281 String key = (String) it.next();
282 if (System.getProperties().containsKey(key)) {
283 log.info("system property found: {}", key);
284 String value = System.getProperty(key);
285 SystemProperty.setProperty(key, value);
286 }
287 }
288 }
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309 public static String processPropertyFilesString(ServletContext context, String servername, String webapp, String propertiesFilesString, String contextPath) {
310
311 propertiesFilesString = StringUtils.replace(propertiesFilesString, "${servername}", servername);
312 propertiesFilesString = StringUtils.replace(propertiesFilesString, "${webapp}", webapp);
313 propertiesFilesString = StringUtils.replace(propertiesFilesString, "${contextPath}", contextPath);
314
315
316 String[] contextAttributeNames = getNamesBetweenPlaceholders(propertiesFilesString, CONTEXT_ATTRIBUTE_PLACEHOLDER_PREFIX);
317 if (contextAttributeNames != null) {
318 for (String ctxAttrName : contextAttributeNames) {
319 if (ctxAttrName != null) {
320
321
322 final String originalPlaceHolder = PLACEHOLDER_PREFIX + CONTEXT_ATTRIBUTE_PLACEHOLDER_PREFIX + ctxAttrName + PLACEHOLDER_SUFFIX;
323 final Object attrValue = context.getAttribute(ctxAttrName);
324 if (attrValue != null) {
325 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, attrValue.toString());
326 }
327 }
328 }
329 }
330
331
332 String[] contextParamNames = getNamesBetweenPlaceholders(propertiesFilesString, CONTEXT_PARAM_PLACEHOLDER_PREFIX);
333 if (contextParamNames != null) {
334 for (String ctxParamName : contextParamNames) {
335 if (ctxParamName != null) {
336
337 final String originalPlaceHolder = PLACEHOLDER_PREFIX + CONTEXT_PARAM_PLACEHOLDER_PREFIX + ctxParamName + PLACEHOLDER_SUFFIX;
338 final String paramValue = context.getInitParameter(ctxParamName);
339 if (paramValue != null) {
340 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
341 }
342 }
343 }
344 }
345
346
347 String[] systemPropertiesNames = getNamesBetweenPlaceholders(propertiesFilesString, SYSTEM_PROPERTY_PLACEHOLDER_PREFIX);
348 if (systemPropertiesNames != null) {
349 for (String sysPropName : systemPropertiesNames) {
350 if (StringUtils.isNotBlank(sysPropName)) {
351 final String originalPlaceHolder = PLACEHOLDER_PREFIX + SYSTEM_PROPERTY_PLACEHOLDER_PREFIX + sysPropName + PLACEHOLDER_SUFFIX;
352 final String paramValue = System.getProperty(sysPropName);
353 if (paramValue != null) {
354 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
355 }
356 }
357 }
358 }
359
360
361 String[] envPropertiesNames = getNamesBetweenPlaceholders(propertiesFilesString, ENV_PROPERTY_PLACEHOLDER_PREFIX);
362 if (envPropertiesNames != null) {
363 for (String envPropName : envPropertiesNames) {
364 if (StringUtils.isNotBlank(envPropName)) {
365 final String originalPlaceHolder = PLACEHOLDER_PREFIX + ENV_PROPERTY_PLACEHOLDER_PREFIX + envPropName + PLACEHOLDER_SUFFIX;
366 final String paramValue = System.getenv(envPropName);
367 if (paramValue != null) {
368 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
369 }
370 }
371 }
372 }
373
374 return propertiesFilesString;
375 }
376
377 private static String[] getNamesBetweenPlaceholders(String propertiesFilesString, String contextNamePlaceHolder) {
378 final String[] names = StringUtils.substringsBetween(
379 propertiesFilesString,
380 PLACEHOLDER_PREFIX + contextNamePlaceHolder,
381 PLACEHOLDER_SUFFIX);
382 return StringUtils.stripAll(names);
383 }
384
385
386
387
388
389
390
391 protected String parseStringValue(String strVal, Set<String> visitedPlaceholders) {
392
393 StringBuffer buf = new StringBuffer(strVal);
394
395 int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
396 while (startIndex != -1) {
397 int endIndex = -1;
398
399 int index = startIndex + PLACEHOLDER_PREFIX.length();
400 int withinNestedPlaceholder = 0;
401 while (index < buf.length()) {
402 if (PLACEHOLDER_SUFFIX.equals(buf.subSequence(index, index + PLACEHOLDER_SUFFIX.length()))) {
403 if (withinNestedPlaceholder > 0) {
404 withinNestedPlaceholder--;
405 index = index + PLACEHOLDER_SUFFIX.length();
406 }
407 else {
408 endIndex = index;
409 break;
410 }
411 }
412 else if (PLACEHOLDER_PREFIX.equals(buf.subSequence(index, index + PLACEHOLDER_PREFIX.length()))) {
413 withinNestedPlaceholder++;
414 index = index + PLACEHOLDER_PREFIX.length();
415 }
416 else {
417 index++;
418 }
419 }
420
421 if (endIndex != -1) {
422 String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
423 if (!visitedPlaceholders.add(placeholder)) {
424
425 log.warn("Circular reference detected in properties, \"{}\" is not resolvable", strVal);
426 return strVal;
427 }
428
429 placeholder = parseStringValue(placeholder, visitedPlaceholders);
430
431 String propVal = SystemProperty.getProperty(placeholder);
432 if (propVal != null) {
433
434
435 propVal = parseStringValue(propVal, visitedPlaceholders);
436 buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal);
437 startIndex = buf.indexOf(PLACEHOLDER_PREFIX, startIndex + propVal.length());
438 }
439 else {
440
441 startIndex = buf.indexOf(PLACEHOLDER_PREFIX, endIndex + PLACEHOLDER_SUFFIX.length());
442 }
443 visitedPlaceholders.remove(placeholder);
444 }
445 else {
446 startIndex = -1;
447 }
448 }
449
450 return buf.toString();
451 }
452
453 }