/**
* This file Copyright (c) 2011-2012 Magnolia International
* Ltd. (http://www.magnolia-cms.com). All rights reserved.
*
*
* This file is dual-licensed under both the Magnolia
* Network Agreement and the GNU General Public License.
* You may elect to use one or the other of these licenses.
*
* This file is distributed in the hope that it will be
* useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
* Redistribution, except as permitted by whichever of the GPL
* or MNA you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or
* modify this file under the terms of the GNU General
* Public License, Version 3, as published by the Free Software
* Foundation. You should have received a copy of the GNU
* General Public License, Version 3 along with this program;
* if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 2. For the Magnolia Network Agreement (MNA), this file
* and the accompanying materials are made available under the
* terms of the MNA which accompanies this distribution, and
* is available at http://www.magnolia-cms.com/mna.html
*
* Any modifications to this file must keep this entire header
* intact.
*
*/
package info.magnolia.init;
import info.magnolia.cms.core.Path;
import info.magnolia.init.properties.FileSystemPropertySource;
import info.magnolia.init.properties.ServletContextPropertySource;
import org.apache.commons.lang.StringUtils;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.ServletContext;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static info.magnolia.cms.beans.config.PropertiesInitializer.processPropertyFilesString;
/**
* Resolves the paths of the properties files to load. The name of the file can be defined as a context parameter in
* web.xml. Multiple paths, comma separated, are supported (the first existing file in the list will be used), and the
* following variables will be used:
*
* <ul>
* <li><b><code>${servername}</code></b>: name of the server where the webapp is running, lowercase</li>
* <li><b><code>${webapp}</code></b>: the last token in the webapp path (e.g. <code>magnoliaPublic</code> for a webapp
* deployed at <code>tomcat/webapps/magnoliaPublic</code>)</li>
* </ul>
* <p>
* If no <code>magnolia.initialization.file</code> context parameter is set, the following default is assumed:
* </p>
*
* <pre>
* <context-param>
* <param-name>magnolia.initialization.file</param-name>
* <param-value>
* WEB-INF/config/${servername}/${webapp}/magnolia.properties,
* WEB-INF/config/${servername}/magnolia.properties,
* WEB-INF/config/${webapp}/magnolia.properties,
* WEB-INF/config/default/magnolia.properties,
* WEB-INF/config/magnolia.properties
* </param-value>
* </context-param>
* </pre>
*
* <h3>Advanced usage: deployment service</h3>
*
* <p>
* Using the <code>${servername}</code> and <code>${webapp}</code> properties you can easily bundle in the same webapp
* different set of configurations which are automatically applied dependending on the server name (useful for switching
* between development, test and production instances where the repository configuration need to be different) or the
* webapp name (useful to bundle both the public and admin log4j/jndi/bootstrap configuration in the same war). By
* default the initializer will try to search for the file in different location with different combination of
* <code>servername</code> and <code>webapp</code>: the <code>default</code> fallback directory will be used if no other
* environment-specific directory has been added.
* </p>
*
* <p>The variables are provided by {@link MagnoliaInitPaths}.</p>
*
* @version $Id$
*/
@Singleton
public class DefaultMagnoliaPropertiesResolver implements MagnoliaPropertiesResolver {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultMagnoliaPropertiesResolver.class);
/**
* Context parameter name. Value should be a comma-separated list of paths to look for properties files.
* Defaults to {@value #DEFAULT_INITIALIZATION_PARAMETER}
*/
protected static final String MAGNOLIA_INITIALIZATION_FILE = "magnolia.initialization.file";
/**
* Default value for the MAGNOLIA_INITIALIZATION_FILE parameter.
*/
protected static final String DEFAULT_INITIALIZATION_PARAMETER =
"WEB-INF/config/${servername}/${contextPath}/magnolia.properties,"
+ "WEB-INF/config/${servername}/${webapp}/magnolia.properties,"
+ "WEB-INF/config/${servername}/magnolia.properties,"
+ "WEB-INF/config/${contextPath}/magnolia.properties,"
+ "WEB-INF/config/${webapp}/magnolia.properties,"
+ "WEB-INF/config/default/magnolia.properties,"
+ "WEB-INF/config/magnolia.properties";
private final ServletContext context;
private final List<String> locations;
@Inject
public DefaultMagnoliaPropertiesResolver(ServletContext context, MagnoliaInitPaths initPaths) {
this.context = context;
String propertiesFilesString = getInitParameter(context, MAGNOLIA_INITIALIZATION_FILE, DEFAULT_INITIALIZATION_PARAMETER);
// Use ROOT for the default (root) context, otherwise trim the leading slash to prevent double slashes
String contextPath = initPaths.getContextPath();
if (contextPath.length() == 0) {
contextPath = "ROOT";
} else {
contextPath = contextPath.substring(1);
}
final String propertiesLocationString = processPropertyFilesString(context, initPaths.getServerName(), initPaths.getWebappFolderName(), propertiesFilesString, contextPath);
final String[] propertiesLocation = propertiesLocationString.trim().split("[,]+",0);
this.locations = new ArrayList<String>(propertiesLocation.length);
// TODO - order ?
// trim all:
for (String loc : propertiesLocation) {
locations.add(loc.trim());
}
}
protected String getInitParameter(ServletContext ctx, String name, String defaultValue) {
final String propertiesFilesString = ctx.getInitParameter(name);
if (StringUtils.isEmpty(propertiesFilesString)) {
log.debug("{} value in web.xml is undefined, falling back to default: {}", name, defaultValue);
return defaultValue;
}
log.debug("{} value in web.xml is :'{}'", name, propertiesFilesString);
return propertiesFilesString;
}
/**
* Used in tests, potentially in subclasses.
*/
protected List<String> getLocations() {
return locations;
}
@Override
public List<PropertySource> getSources() {
final List<PropertySource> sources = new ArrayList<PropertySource>();
boolean foundFiles = false;
for (String location : getLocations()) {
try {
if (Path.isAbsolute(location)) {
sources.add(new FileSystemPropertySource(location));
} else {
sources.add(new ServletContextPropertySource(context, location));
}
foundFiles = true;
} catch (FileNotFoundException e) {
log.debug("Configuration file not found with path [{}]", location);
} catch (IOException e) {
throw new RuntimeException(e); // TODO
}
}
if (!foundFiles) {
log.warn("No configuration files found using location list {}.", getLocations());
}
return sources;
}
}