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 } catch (IOException e) {
217 log.error("Unable to load {} due to an IOException: {}", MGNL_BEANS_PROPERTIES, e.getMessage());
218 } finally {
219 IOUtils.closeQuietly(mgnlbeansStream);
220 }
221
222 for (Iterator<Object> iter = mgnlbeans.keySet().iterator(); iter.hasNext(); ) {
223 String key = (String) iter.next();
224 SystemProperty.setProperty(key, mgnlbeans.getProperty(key));
225 }
226
227 } else {
228 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);
229 }
230 }
231
232
233
234
235 public boolean loadPropertiesFile(String rootPath, String location) {
236 final File initFile;
237 if (Path.isAbsolute(location)) {
238 initFile = new File(location);
239 } else {
240 initFile = new File(rootPath, location);
241 }
242
243 if (!initFile.exists() || initFile.isDirectory()) {
244 log.debug("Configuration file not found with path [{}]", initFile.getAbsolutePath());
245 return false;
246 }
247
248 InputStream fileStream = null;
249 try {
250 fileStream = new FileInputStream(initFile);
251 } catch (FileNotFoundException e1) {
252 log.debug("Configuration file not found with path [{}]", initFile.getAbsolutePath());
253 return false;
254 }
255
256 try {
257 SystemProperty.getProperties().load(fileStream);
258 log.info("Loading configuration at {}", initFile.getAbsolutePath());
259 } catch (Exception e) {
260 log.error(e.getMessage(), e);
261 return false;
262 } finally {
263 IOUtils.closeQuietly(fileStream);
264 }
265 return true;
266 }
267
268
269
270
271 public void overloadWithSystemProperties() {
272 Iterator<Object> it = SystemProperty.getProperties().keySet().iterator();
273 while (it.hasNext()) {
274 String key = (String) it.next();
275 if (System.getProperties().containsKey(key)) {
276 log.info("system property found: {}", key);
277 String value = System.getProperty(key);
278 SystemProperty.setProperty(key, value);
279 }
280 }
281 }
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301 public static String processPropertyFilesString(ServletContext context, String servername, String webapp, String propertiesFilesString, String contextPath) {
302
303 propertiesFilesString = StringUtils.replace(propertiesFilesString, "${servername}", servername);
304 propertiesFilesString = StringUtils.replace(propertiesFilesString, "${webapp}", webapp);
305 propertiesFilesString = StringUtils.replace(propertiesFilesString, "${contextPath}", contextPath);
306
307
308 String[] contextAttributeNames = getNamesBetweenPlaceholders(propertiesFilesString, CONTEXT_ATTRIBUTE_PLACEHOLDER_PREFIX);
309 if (contextAttributeNames != null) {
310 for (String ctxAttrName : contextAttributeNames) {
311 if (ctxAttrName != null) {
312
313
314 final String originalPlaceHolder = PLACEHOLDER_PREFIX + CONTEXT_ATTRIBUTE_PLACEHOLDER_PREFIX + ctxAttrName + PLACEHOLDER_SUFFIX;
315 final Object attrValue = context.getAttribute(ctxAttrName);
316 if (attrValue != null) {
317 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, attrValue.toString());
318 }
319 }
320 }
321 }
322
323
324 String[] contextParamNames = getNamesBetweenPlaceholders(propertiesFilesString, CONTEXT_PARAM_PLACEHOLDER_PREFIX);
325 if (contextParamNames != null) {
326 for (String ctxParamName : contextParamNames) {
327 if (ctxParamName != null) {
328
329 final String originalPlaceHolder = PLACEHOLDER_PREFIX + CONTEXT_PARAM_PLACEHOLDER_PREFIX + ctxParamName + PLACEHOLDER_SUFFIX;
330 final String paramValue = context.getInitParameter(ctxParamName);
331 if (paramValue != null) {
332 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
333 }
334 }
335 }
336 }
337
338
339 String[] systemPropertiesNames = getNamesBetweenPlaceholders(propertiesFilesString, SYSTEM_PROPERTY_PLACEHOLDER_PREFIX);
340 if (systemPropertiesNames != null) {
341 for (String sysPropName : systemPropertiesNames) {
342 if (StringUtils.isNotBlank(sysPropName)) {
343 final String originalPlaceHolder = PLACEHOLDER_PREFIX + SYSTEM_PROPERTY_PLACEHOLDER_PREFIX + sysPropName + PLACEHOLDER_SUFFIX;
344 final String paramValue = System.getProperty(sysPropName);
345 if (paramValue != null) {
346 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
347 }
348 }
349 }
350 }
351
352
353 String[] envPropertiesNames = getNamesBetweenPlaceholders(propertiesFilesString, ENV_PROPERTY_PLACEHOLDER_PREFIX);
354 if (envPropertiesNames != null) {
355 for (String envPropName : envPropertiesNames) {
356 if (StringUtils.isNotBlank(envPropName)) {
357 final String originalPlaceHolder = PLACEHOLDER_PREFIX + ENV_PROPERTY_PLACEHOLDER_PREFIX + envPropName + PLACEHOLDER_SUFFIX;
358 final String paramValue = System.getenv(envPropName);
359 if (paramValue != null) {
360 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
361 }
362 }
363 }
364 }
365
366 return propertiesFilesString;
367 }
368
369 private static String[] getNamesBetweenPlaceholders(String propertiesFilesString, String contextNamePlaceHolder) {
370 final String[] names = StringUtils.substringsBetween(
371 propertiesFilesString,
372 PLACEHOLDER_PREFIX + contextNamePlaceHolder,
373 PLACEHOLDER_SUFFIX);
374 return StringUtils.stripAll(names);
375 }
376
377
378
379
380
381
382
383 protected String parseStringValue(String strVal, Set<String> visitedPlaceholders) {
384
385 StringBuffer buf = new StringBuffer(strVal);
386
387 int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
388 while (startIndex != -1) {
389 int endIndex = -1;
390
391 int index = startIndex + PLACEHOLDER_PREFIX.length();
392 int withinNestedPlaceholder = 0;
393 while (index < buf.length()) {
394 if (PLACEHOLDER_SUFFIX.equals(buf.subSequence(index, index + PLACEHOLDER_SUFFIX.length()))) {
395 if (withinNestedPlaceholder > 0) {
396 withinNestedPlaceholder--;
397 index = index + PLACEHOLDER_SUFFIX.length();
398 } else {
399 endIndex = index;
400 break;
401 }
402 } else if (PLACEHOLDER_PREFIX.equals(buf.subSequence(index, index + PLACEHOLDER_PREFIX.length()))) {
403 withinNestedPlaceholder++;
404 index = index + PLACEHOLDER_PREFIX.length();
405 } else {
406 index++;
407 }
408 }
409
410 if (endIndex != -1) {
411 String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
412 if (!visitedPlaceholders.add(placeholder)) {
413
414 log.warn("Circular reference detected in properties, \"{}\" is not resolvable", strVal);
415 return strVal;
416 }
417
418 placeholder = parseStringValue(placeholder, visitedPlaceholders);
419
420 String propVal = SystemProperty.getProperty(placeholder);
421 if (propVal != null) {
422
423
424 propVal = parseStringValue(propVal, visitedPlaceholders);
425 buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal);
426 startIndex = buf.indexOf(PLACEHOLDER_PREFIX, startIndex + propVal.length());
427 } else {
428
429 startIndex = buf.indexOf(PLACEHOLDER_PREFIX, endIndex + PLACEHOLDER_SUFFIX.length());
430 }
431 visitedPlaceholders.remove(placeholder);
432 } else {
433 startIndex = -1;
434 }
435 }
436
437 return buf.toString();
438 }
439
440 }