/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright 2005 - 2009 Pentaho Corporation. All rights reserved.
*
*
* @created Apr 12, 2005
* @author James Dixon
*
*/
package org.pentaho.platform.web.http.context;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Properties;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.lang.StringUtils;
import org.pentaho.platform.api.engine.IApplicationContext;
import org.pentaho.platform.api.engine.IPentahoObjectFactory;
import org.pentaho.platform.api.util.IVersionHelper;
import org.pentaho.platform.engine.core.system.PathBasedSystemSettings;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.util.logging.Logger;
import org.pentaho.platform.util.messages.LocaleHelper;
import org.pentaho.platform.web.http.PentahoHttpSessionHelper;
import org.pentaho.platform.web.http.messages.Messages;
public class SolutionContextListener implements ServletContextListener {
protected static String solutionPath;
protected static String contextPath;
private static final String DEFAULT_SPRING_CONFIG_FILE_NAME = "pentahoObjects.spring.xml"; //$NON-NLS-1$
public void contextInitialized(final ServletContextEvent event) {
ServletContext context = event.getServletContext();
String encoding = context.getInitParameter("encoding"); //$NON-NLS-1$
if (encoding != null) {
LocaleHelper.setSystemEncoding(encoding);
}
String textDirection = context.getInitParameter("text-direction"); //$NON-NLS-1$
if (textDirection != null) {
LocaleHelper.setTextDirection(textDirection);
}
String localeLanguage = context.getInitParameter("locale-language"); //$NON-NLS-1$
String localeCountry = context.getInitParameter("locale-country"); //$NON-NLS-1$
boolean localeSet = false;
if ((localeLanguage != null) && !"".equals(localeLanguage) && (localeCountry != null) && !"".equals(localeCountry)) { //$NON-NLS-1$ //$NON-NLS-2$
Locale locales[] = Locale.getAvailableLocales();
if (locales != null) {
for (Locale element : locales) {
if (element.getLanguage().equals(localeLanguage) && element.getCountry().equals(localeCountry)) {
LocaleHelper.setLocale(element);
localeSet = true;
break;
}
}
}
}
if (!localeSet) {
// do this thread in the default locale
LocaleHelper.setLocale(Locale.getDefault());
}
LocaleHelper.setDefaultLocale(LocaleHelper.getLocale());
// log everything that goes on here
Logger.info(SolutionContextListener.class.getName(), Messages.getInstance()
.getString("SolutionContextListener.INFO_INITIALIZING")); //$NON-NLS-1$
Logger.info(SolutionContextListener.class.getName(), Messages.getInstance()
.getString("SolutionContextListener.INFO_SERVLET_CONTEXT") + context); //$NON-NLS-1$
SolutionContextListener.contextPath = context.getRealPath(""); //$NON-NLS-1$
Logger.info(SolutionContextListener.class.getName(), Messages.getInstance()
.getString("SolutionContextListener.INFO_CONTEXT_PATH") + SolutionContextListener.contextPath); //$NON-NLS-1$
SolutionContextListener.solutionPath = PentahoHttpSessionHelper.getSolutionPath(context);
if (StringUtils.isEmpty(SolutionContextListener.solutionPath)) {
String errorMsg = Messages.getInstance().getErrorString("SolutionContextListener.ERROR_0001_NO_ROOT_PATH"); //$NON-NLS-1$
Logger.error(getClass().getName(), errorMsg);
/*
* Since we couldn't find solution repository path there is no point in going
* forward and the user should know that a major config setting was not found.
* So we are throwing in a RunTimeException with the requisite message.
*/
throw new RuntimeException(errorMsg);
}
Logger.info(getClass().getName(),
Messages.getInstance().getString("SolutionContextListener.INFO_ROOT_PATH") + SolutionContextListener.solutionPath); //$NON-NLS-1$
// TODO: derive the base URL from somewhere
String baseUrl = context.getInitParameter("base-url"); //$NON-NLS-1$
if (baseUrl == null) {
// assume this is a demo installation
// TODO: Create a servlet that's loaded on startup to set this value
baseUrl = "http://localhost:8080/pentaho/"; //$NON-NLS-1$
}
IApplicationContext applicationContext = createWebApplicationContext(baseUrl, context);
/*
* Copy out all the initParameter values from the servlet context and
* put them in the application context.
*/
Properties props = new Properties();
Enumeration<?> initParmNames = context.getInitParameterNames();
String initParmName;
while (initParmNames.hasMoreElements()) {
initParmName = (String) initParmNames.nextElement();
props.setProperty(initParmName, context.getInitParameter(initParmName));
}
((WebApplicationContext) applicationContext).setProperties(props);
setSystemCfgFile(context);
setObjectFactory(context);
boolean initOk = PentahoSystem.init(applicationContext);
this.showInitializationMessage(initOk, baseUrl);
}
/**
* Provide a simple extension point for someone to be able to override the behavior
* of the WebApplicationContext. To extend or change behavior, you will need to
* extend WebApplicationContext, and extend SolutionContextListener to override
* the createWebApplicationContext method. The subclassing is currently required
* because the initialization code above makes a specific setProperties call on the
* returned ApplicationContext method by casting it to a WebApplicationContext.
*
* Tangible example where this would be needed - context.getRealPath("") doesn't
* work the same way on all platforms. In some cases, you need to pass in a null,
* not an empty string. For other servers that don't unpack the war, the
* realPath call may need to be replaced with a parameter defined in the web.xml
*
* @param bUrl
* @param context
* @return
*/
protected WebApplicationContext createWebApplicationContext(String bUrl, ServletContext context) {
return new WebApplicationContext(SolutionContextListener.solutionPath, bUrl,
context.getRealPath(""), context); //$NON-NLS-1$
}
private void setObjectFactory(final ServletContext context) {
final String SYSTEM_FOLDER = "/system"; //$NON-NLS-1$
String pentahoObjectFactoryClassName = context.getInitParameter("pentahoObjectFactory"); //$NON-NLS-1$
String pentahoObjectFactoryConfigFile = context.getInitParameter("pentahoObjectFactoryCfgFile"); //$NON-NLS-1$
// if web.xml doesnt specify a config file, use the default path.
if (StringUtils.isEmpty(pentahoObjectFactoryConfigFile)) {
pentahoObjectFactoryConfigFile = solutionPath + SYSTEM_FOLDER + "/" + DEFAULT_SPRING_CONFIG_FILE_NAME; //$NON-NLS-1$
} else if (-1 == pentahoObjectFactoryConfigFile.indexOf("/")) { //$NON-NLS-1$
pentahoObjectFactoryConfigFile = solutionPath + SYSTEM_FOLDER + "/" + pentahoObjectFactoryConfigFile; //$NON-NLS-1$
}
// else objectFactoryCreatorCfgFile contains the full path.
IPentahoObjectFactory pentahoObjectFactory;
try {
Class<?> classObject = Class.forName(pentahoObjectFactoryClassName);
pentahoObjectFactory = (IPentahoObjectFactory) classObject.newInstance();
} catch (Exception e) {
String msg = Messages.getInstance().getErrorString("SolutionContextListener.ERROR_0002_BAD_OBJECT_FACTORY", pentahoObjectFactoryClassName); //$NON-NLS-1$
//Cannot proceed without an object factory, so we'll put some context around what
//we were trying to do throw a runtime exception
throw new RuntimeException(msg, e);
}
pentahoObjectFactory.init(pentahoObjectFactoryConfigFile, context);
PentahoSystem.setObjectFactory(pentahoObjectFactory);
}
/**
* Look for a parameter called "pentaho-system-cfg". If found, use its value to set the
* the value of the System property "SYSTEM_CFG_PATH_KEY". This value is used by a
* LiberatedSystemSettings class to determine the location of the system configuration file.
* This is typically pentaho.xml.
*
* @param context ServletContext
*/
private void setSystemCfgFile(final ServletContext context) {
String jvmSpecifiedSysCfgPath = System.getProperty(PathBasedSystemSettings.SYSTEM_CFG_PATH_KEY);
if (StringUtils.isBlank(jvmSpecifiedSysCfgPath)) {
String webSpecifiedSysCfgPath = context.getInitParameter("pentaho-system-cfg"); //$NON-NLS-1$
if (StringUtils.isNotBlank(webSpecifiedSysCfgPath)) {
System.setProperty(PathBasedSystemSettings.SYSTEM_CFG_PATH_KEY, webSpecifiedSysCfgPath);
}
}
// if it is blank, no big deal, we'll simply fall back on defaults
}
public void showInitializationMessage(final boolean initOk, final String baseUrl) {
if( PentahoSystem.getObjectFactory().objectDefined( IVersionHelper.class.getSimpleName() ) ) {
IVersionHelper helper = PentahoSystem.get(IVersionHelper.class, null); // No session yet
if (initOk) {
System.out
.println(Messages.getInstance()
.getString(
"SolutionContextListener.INFO_SYSTEM_READY", "(" + helper.getVersionInformation(PentahoSystem.class) + ")", baseUrl, SolutionContextListener.solutionPath)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} else {
System.err
.println(Messages.getInstance()
.getString(
"SolutionContextListener.INFO_SYSTEM_NOT_READY", "(" + helper.getVersionInformation(PentahoSystem.class) + ")", baseUrl, SolutionContextListener.solutionPath)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
}
protected String getContextPath() {
return SolutionContextListener.contextPath;
}
protected String getRootPath() {
return SolutionContextListener.solutionPath;
}
public void contextDestroyed(final ServletContextEvent event) {
PentahoSystem.shutdown();
if (LocaleHelper.getLocale() == null) {
LocaleHelper.setLocale(Locale.getDefault());
}
// log everything that goes on here
Logger.info(SolutionContextListener.class.getName(), Messages.getInstance()
.getString("SolutionContextListener.INFO_SYSTEM_EXITING")); //$NON-NLS-1$
}
}