/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package fedora.server.utilities;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.log4j.LogManager;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.helpers.FileWatchdog;
import org.apache.log4j.xml.DOMConfigurator;
/**
* Log4j Configuration Listener.
*
* <p>An implementation of ServletContextListener. To use, add a listener
* element to web.xml that specifies this class.</p>
*
* <p>Two configuration parameters are supported via context-param entries.
* {@value #CONFIG_LOCATION_PARAM} defines the location of the log4j
* configuration file. {@value #REFRESH_INTERVAL_PARAM} defines the interval,
* in milliseconds, between config file refresh checks.</p>
*
* <p>Limited variable substitutions are supported in the log4j configuration
* file. System properties or environment variables enclosed with curly braces
* and prefixed with a dollar sign (e.g. <code>${fedora.home}</code>) will be
* automatically replaced.</p>
*
* @author Edwin Shin
* @version $Id$
*/
public class Log4jConfigListener
implements ServletContextListener {
/**
* Parameter name for the location of the log4j configuration file.
*/
public static final String CONFIG_LOCATION_PARAM = "log4j-configLocation";
/**
* Parameter name for the interval between config file refresh checks,
* in milliseconds.
*/
public static final String REFRESH_INTERVAL_PARAM = "log4j-refreshInterval";
public static final String FEDORA_HOME_PARAM = "fedora.home";
/**
* {@inheritDoc}
*/
public void contextInitialized(ServletContextEvent event) {
ServletContext servletContext = event.getServletContext();
String fedoraHome = servletContext.getInitParameter(FEDORA_HOME_PARAM);
if (fedoraHome == null) {
servletContext.log("init-param, " + FEDORA_HOME_PARAM + " was not set.");
} else {
System.setProperty(FEDORA_HOME_PARAM, fedoraHome);
}
initLogging(servletContext);
}
/**
* {@inheritDoc}
*/
public void contextDestroyed(ServletContextEvent event) {
shutdownLogging(event.getServletContext());
}
public static void initLogging(ServletContext servletContext) {
String location = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
if (location == null || location.length() == 0) {
servletContext.log("init-param ," + CONFIG_LOCATION_PARAM +
" not set, skipping log4j configuration.");
return;
}
String intervalString = servletContext.getInitParameter(REFRESH_INTERVAL_PARAM);
long refreshInterval = FileWatchdog.DEFAULT_DELAY;
if (intervalString != null) {
refreshInterval = Long.parseLong(intervalString);
}
try {
initLogging(location, refreshInterval);
} catch (FileNotFoundException e) {
throw new IllegalArgumentException("Invalid Log4jConfigListener parameter: " + location);
}
}
public static void shutdownLogging(ServletContext servletContext) {
servletContext.log("Shutting down log4j...");
LogManager.shutdown();
}
private static void initLogging(String location, long refreshInterval) throws FileNotFoundException {
assert (location != null && location.length() > 0);
String resolvedLocation = dereferenceSystemProperties(location);
File file = new File(resolvedLocation);
if (!file.exists()) {
throw new FileNotFoundException(file.getAbsolutePath() + " does not exist.");
}
if (location.toLowerCase().endsWith(".xml")) {
DOMConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval);
} else {
PropertyConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval);
}
}
/**
* Replaces System Properties or environment variables surrounded by curly
* braces and prefixed by a dollar sign {e.g. <code>${fedora.home}</code>}
* with their values.
*
* @param s the input string to perform substitutions on.
* @return the string with the variables replaced.
*/
public static String dereferenceSystemProperties(String s) {
if (s == null || s.length() == 0) {
return s;
}
String prefix = "${";
String suffix = "}";
// e.g., match ${fedora.home}
Pattern pattern = Pattern.compile("(\\$\\{.*?\\})");
Matcher matcher = pattern.matcher(s);
while(matcher.find()) {
String match = matcher.group();
String propertyName = match.substring(prefix.length(), match.length() - suffix.length());
String propertyValue = System.getProperty(propertyName);
if (propertyValue == null) {
propertyValue = System.getenv(propertyName);
}
if (propertyValue != null) {
s = s.replace(match, propertyValue);
} else {
System.out.println("Could not match: " + propertyName +
" to a System Property or environment variable.");
}
}
return s;
}
}