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.ModuleManagementException;
39 import info.magnolia.module.ModuleManager;
40 import info.magnolia.module.model.ModuleDefinition;
41 import info.magnolia.module.model.PropertyDefinition;
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 info.magnolia.objectfactory.Components;
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 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 public static PropertiesInitializer getInstance() {
102 return Components.getSingleton(PropertiesInitializer.class);
103 }
104
105
106
107
108 public static final String DEFAULT_INITIALIZATION_PARAMETER =
109 "WEB-INF/config/${servername}/${webapp}/magnolia.properties,"
110 + "WEB-INF/config/${servername}/magnolia.properties,"
111 + "WEB-INF/config/${webapp}/magnolia.properties,"
112 + "WEB-INF/config/default/magnolia.properties,"
113 + "WEB-INF/config/magnolia.properties";
114
115 public void loadAllProperties(String propertiesFilesString, String rootPath) {
116
117 loadBeanProperties();
118
119 loadAllModuleProperties();
120
121
122 loadPropertiesFiles(propertiesFilesString, rootPath);
123
124
125 overloadWithSystemProperties();
126
127
128 resolveNestedProperties();
129 }
130
131 private void resolveNestedProperties() {
132
133 Properties sysProps = SystemProperty.getProperties();
134
135 for (Iterator it = sysProps.keySet().iterator(); it.hasNext();) {
136 String key = (String) it.next();
137 String oldValue = (String) sysProps.get(key);
138 String value = parseStringValue(oldValue, new HashSet<String>());
139 SystemProperty.getProperties().put(key, value);
140 }
141
142 }
143
144 public void loadAllModuleProperties() {
145
146 final ModuleManager moduleManager = ModuleManager.Factory.getInstance();
147 try {
148 final List<ModuleDefinition> moduleDefinitions = moduleManager.loadDefinitions();
149 loadModuleProperties(moduleDefinitions);
150 }
151 catch (ModuleManagementException e) {
152 log.error(e.getMessage());
153 throw new RuntimeException(e);
154 }
155 }
156
157
158
159
160
161 protected void loadModuleProperties(List<ModuleDefinition> moduleDefinitions) {
162 for (ModuleDefinition module : moduleDefinitions) {
163 for (PropertyDefinition property : module.getProperties()) {
164 SystemProperty.setProperty(property.getName(), property.getValue());
165 }
166 }
167 }
168
169 public void loadPropertiesFiles(String propertiesLocationString, String rootPath) {
170
171 String[] propertiesLocation = StringUtils.split(propertiesLocationString, ',');
172
173 boolean found = false;
174
175
176 for (int j = propertiesLocation.length - 1; j >= 0; j--) {
177 String location = StringUtils.trim(propertiesLocation[j]);
178
179 if (loadPropertiesFile(rootPath, location)) {
180 found = true;
181 }
182 }
183
184 if (!found) {
185 final String msg = MessageFormat.format("No configuration found using location list {0}. Base path is [{1}]", ArrayUtils.toString(propertiesLocation), rootPath);
186 log.error(msg);
187 throw new ConfigurationException(msg);
188 }
189 }
190
191 public void loadBeanProperties() {
192 InputStream mgnlbeansStream = getClass().getResourceAsStream(MGNL_BEANS_PROPERTIES);
193
194 if (mgnlbeansStream != null) {
195 Properties mgnlbeans = new Properties();
196 try {
197 mgnlbeans.load(mgnlbeansStream);
198 }
199 catch (IOException e) {
200 log.error("Unable to load {} due to an IOException: {}", MGNL_BEANS_PROPERTIES, e.getMessage());
201 }
202 finally {
203 IOUtils.closeQuietly(mgnlbeansStream);
204 }
205
206 for (Iterator iter = mgnlbeans.keySet().iterator(); iter.hasNext();) {
207 String key = (String) iter.next();
208 SystemProperty.setProperty(key, mgnlbeans.getProperty(key));
209 }
210
211 }
212 else {
213 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);
214 }
215 }
216
217
218
219
220
221
222
223 public boolean loadPropertiesFile(String rootPath, String location) {
224 final File initFile;
225 if (Path.isAbsolute(location)) {
226 initFile = new File(location);
227 }
228 else {
229 initFile = new File(rootPath, location);
230 }
231
232 if (!initFile.exists() || initFile.isDirectory()) {
233 log.debug("Configuration file not found with path [{}]", initFile.getAbsolutePath());
234 return false;
235 }
236
237 InputStream fileStream = null;
238 try {
239 fileStream = new FileInputStream(initFile);
240 }
241 catch (FileNotFoundException e1) {
242 log.debug("Configuration file not found with path [{}]", initFile.getAbsolutePath());
243 return false;
244 }
245
246 try {
247 SystemProperty.getProperties().load(fileStream);
248 log.info("Loading configuration at {}", initFile.getAbsolutePath());
249 }
250 catch (Exception e) {
251 log.error(e.getMessage(), e);
252 return false;
253 }
254 finally {
255 IOUtils.closeQuietly(fileStream);
256 }
257 return true;
258 }
259
260
261
262
263 public void overloadWithSystemProperties() {
264 Iterator it = SystemProperty.getProperties().keySet().iterator();
265 while (it.hasNext()) {
266 String key = (String) it.next();
267 if (System.getProperties().containsKey(key)) {
268 log.info("system property found: {}", key);
269 String value = System.getProperty(key);
270 SystemProperty.setProperty(key, value);
271 }
272 }
273 }
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288 public static String processPropertyFilesString(ServletContext context, String servername, String webapp,
289 String propertiesFilesString) {
290
291 propertiesFilesString = StringUtils.replace(propertiesFilesString, "${servername}", servername);
292 propertiesFilesString = StringUtils.replace(propertiesFilesString, "${webapp}", webapp);
293
294
295 String[] contextAttributeNames = getNamesBetweenPlaceholders(propertiesFilesString, CONTEXT_ATTRIBUTE_PLACEHOLDER_PREFIX);
296 if (contextAttributeNames != null) {
297 for (String ctxAttrName : contextAttributeNames) {
298 if (ctxAttrName != null) {
299
300
301 final String originalPlaceHolder = PLACEHOLDER_PREFIX + CONTEXT_ATTRIBUTE_PLACEHOLDER_PREFIX + ctxAttrName + PLACEHOLDER_SUFFIX;
302 final Object attrValue = context.getAttribute(ctxAttrName);
303 if (attrValue != null) {
304 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, attrValue.toString());
305 }
306 }
307 }
308 }
309
310
311 String[] contextParamNames = getNamesBetweenPlaceholders(propertiesFilesString, CONTEXT_PARAM_PLACEHOLDER_PREFIX);
312 if (contextParamNames != null) {
313 for (String ctxParamName : contextParamNames) {
314 if (ctxParamName != null) {
315
316 final String originalPlaceHolder = PLACEHOLDER_PREFIX + CONTEXT_PARAM_PLACEHOLDER_PREFIX + ctxParamName + PLACEHOLDER_SUFFIX;
317 final String paramValue = context.getInitParameter(ctxParamName);
318 if (paramValue != null) {
319 propertiesFilesString = propertiesFilesString.replace(originalPlaceHolder, paramValue);
320 }
321 }
322 }
323 }
324
325 return propertiesFilesString;
326 }
327
328 private static String[] getNamesBetweenPlaceholders(String propertiesFilesString, String contextNamePlaceHolder) {
329 final String[] names = StringUtils.substringsBetween(
330 propertiesFilesString,
331 PLACEHOLDER_PREFIX + contextNamePlaceHolder,
332 PLACEHOLDER_SUFFIX);
333 return StringUtils.stripAll(names);
334 }
335
336
337
338
339
340 protected String parseStringValue(String strVal, Set<String> visitedPlaceholders) {
341
342 StringBuffer buf = new StringBuffer(strVal);
343
344 int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
345 while (startIndex != -1) {
346 int endIndex = -1;
347
348 int index = startIndex + PLACEHOLDER_PREFIX.length();
349 int withinNestedPlaceholder = 0;
350 while (index < buf.length()) {
351 if (PLACEHOLDER_SUFFIX.equals(buf.subSequence(index, index + PLACEHOLDER_SUFFIX.length()))) {
352 if (withinNestedPlaceholder > 0) {
353 withinNestedPlaceholder--;
354 index = index + PLACEHOLDER_SUFFIX.length();
355 }
356 else {
357 endIndex = index;
358 break;
359 }
360 }
361 else if (PLACEHOLDER_PREFIX.equals(buf.subSequence(index, index + PLACEHOLDER_PREFIX.length()))) {
362 withinNestedPlaceholder++;
363 index = index + PLACEHOLDER_PREFIX.length();
364 }
365 else {
366 index++;
367 }
368 }
369
370 if (endIndex != -1) {
371 String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
372 if (!visitedPlaceholders.add(placeholder)) {
373
374 log.warn("Circular reference detected in properties, \"{}\" is not resolvable", strVal);
375 return strVal;
376 }
377
378 placeholder = parseStringValue(placeholder, visitedPlaceholders);
379
380 String propVal = SystemProperty.getProperty(placeholder);
381 if (propVal != null) {
382
383
384 propVal = parseStringValue(propVal, visitedPlaceholders);
385 buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal);
386 startIndex = buf.indexOf(PLACEHOLDER_PREFIX, startIndex + propVal.length());
387 }
388 else {
389
390 startIndex = buf.indexOf(PLACEHOLDER_PREFIX, endIndex + PLACEHOLDER_SUFFIX.length());
391 }
392 visitedPlaceholders.remove(placeholder);
393 }
394 else {
395 startIndex = -1;
396 }
397 }
398
399 return buf.toString();
400 }
401
402 }