/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, version 2 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.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 General Public License for more details.
*
* Copyright 2009 Pentaho Corporation. All rights reserved.
*
* Created Feb 4, 2009
* @author jdixon
*/
package org.pentaho.platform.engine.core.system.boot;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.pentaho.platform.api.engine.IApplicationContext;
import org.pentaho.platform.api.engine.IPentahoDefinableObjectFactory;
import org.pentaho.platform.api.engine.IPentahoObjectFactory;
import org.pentaho.platform.api.engine.IPentahoPublisher;
import org.pentaho.platform.api.engine.IPentahoSystemListener;
import org.pentaho.platform.api.engine.ISessionStartupAction;
import org.pentaho.platform.api.engine.ISystemSettings;
import org.pentaho.platform.api.engine.IPentahoDefinableObjectFactory.Scope;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.engine.core.system.StandaloneApplicationContext;
import org.pentaho.platform.engine.core.system.objfac.StandaloneObjectFactory;
import org.pentaho.platform.engine.core.messages.Messages;
/**
* This class is designed to help embedded deployments start the Pentaho system.
* {@link PentahoSystemBoot} is a self-contained and very easy to configure platform initializer
* which does not impose the use of configuration files on your filesystem. A booter instance
* gives you the flexibility to configure and run the platform entirely in memory.
* <p>
* In general you will want to
* <ol>
* <li> Construct a {@link PentahoSystemBoot}
* <li> define the system objects that your system requires, by using one of the {@link #define(Class, Class)} variants
* <li> (optionally) initialize the Pentaho system for processing requests by calling {@link #start()}
* </ol>
* An extremely minimal platform might be configured like this:
* <pre>
* @Before
* public void init() {
* PentahoSystemBoot booter = new PentahoSystemBoot();
* //setup your required object definitions
* booter.define(ISolutionRepository.class, FileBasedSolutionRepository.class);
*
* //initialize the minimal platform
* booter.init();
* }
* </pre>
* @author jamesdixon and aphillips
*
*/
public class PentahoSystemBoot {
private IPentahoObjectFactory factory;
private String filePath;
private String baseUrl;
// list of the system listeners to hook up
private List<IPentahoSystemListener> lifecycleListeners = new ArrayList<IPentahoSystemListener>();
// list of startup actions to execute
private List<ISessionStartupAction> startupActions = new ArrayList<ISessionStartupAction>();
// list of admin plugins (aka publishers)
private List<IPentahoPublisher> adminActions = new ArrayList<IPentahoPublisher>();
private ISystemSettings settingsProvider = null;
private boolean initialized = false;
/**
* Creates a minimal ready-to-run platform. Use this constructor if you want to accept
* all the defaults for your in-memory platform.
*/
public PentahoSystemBoot() {
configure(null, null, null);
}
/**
* Creates a minimal ready-to-run platform with a specified solution path. Use this constructor if
* your system needs to access system or other solution files from a particular directory.
* @param solutionPath full path to the pentaho_solutions folder
*/
public PentahoSystemBoot(String solutionPath) {
configure(solutionPath, null, null);
}
public PentahoSystemBoot(String solutionPath, String baseUrl) {
configure(solutionPath, baseUrl, null);
}
public PentahoSystemBoot(String solutionPath, IPentahoDefinableObjectFactory factory) {
configure(solutionPath, null, factory);
}
public PentahoSystemBoot(String solutionPath, String baseUrl, IPentahoDefinableObjectFactory factory) {
configure(solutionPath, baseUrl, factory);
}
/**
* Configures this booter to run. Any parameters that are <code>null</code> will be set
* with default values. The default values are as follows:
* <ul>
* <li> solutionPath = "." (current working directory)
* <li> baseUrl = "http://localhost:8080/pentaho/"
* <li> factory = a new StandaloneObjectFactory instance
* </ul>
* Override this method to create a different set of defaults or
* use the 'setter' methods to override defaults in a more fine-grained manner
*/
protected void configure(String userFilePath, String userBaseUrl, IPentahoDefinableObjectFactory userFactory) {
setFilePath(userFilePath != null?userFilePath:new File(".").getAbsolutePath()); //$NON-NLS-1$
setBaseUrl(userBaseUrl != null?userBaseUrl:"http://localhost:8080/pentaho/"); //$NON-NLS-1$
setFactory(userFactory != null?userFactory:new StandaloneObjectFactory());
PentahoSystem.setSystemListeners(lifecycleListeners);
PentahoSystem.setSessionStartupActions(startupActions);
PentahoSystem.setAdministrationPlugins(adminActions);
}
/**
* Sets the file path that will be used to get to file-based
* resources
* @return
*/
public String getFilePath() {
return filePath;
}
/**
* Sets the file path to be used to find configuration and content files
* If this is not set the current directory (.) is used.
* @param filePath
*/
public void setFilePath(final String filePath) {
this.filePath = filePath;
}
/**
* Sets the URL that the platform uses to generate paths to its own resources
* @param baseUrl
*/
public void setBaseUrl(final String baseUrl) {
this.baseUrl = baseUrl;
}
/**
* Override this method if you want to change the type and state of the application
* context used to initialize the system.
* @return an application context for system initialization
*/
protected IApplicationContext createApplicationContext() {
StandaloneApplicationContext appCtxt = new StandaloneApplicationContext(getFilePath(), ""); //$NON-NLS-1$
appCtxt.setBaseUrl(baseUrl);
return appCtxt;
}
/**
* @deprecated use {@link #start()}. This method is hanging around for backward compatibility
* with MicroPlatform
*/
public void init() {
try {
start();
} catch (PlatformInitializationException e) {
throw new RuntimeException(e);
}
}
/**
* Starts the Pentaho platform, making it ready to process requests.
* @throws PlatformInitializationException if there was a problem initializing the platform
*/
public boolean start() throws PlatformInitializationException {
initialized = false;
try {
initialized = PentahoSystem.init(createApplicationContext());
//we want to wrap any exception that causes initialization to fail, so we will
//catch throwable
} catch (Throwable t) {
throw new PlatformInitializationException(Messages.getInstance().getErrorString("PentahoSystemBoot.ERROR_0001_PLATFORM_INIT_FAILED"), t); //$NON-NLS-1$
}
if (!initialized) {
throw new PlatformInitializationException(Messages.getInstance().getErrorString("PentahoSystemBoot.ERROR_0001_PLATFORM_INIT_FAILED")); //$NON-NLS-1$
}
return initialized;
}
/**
* Stops the Pentaho platform
* @return
*/
public boolean stop() {
initialized = false;
PentahoSystem.shutdown();
return true;
}
/**
* Gets the object factory for the Pentaho platform
* @return
*/
public IPentahoObjectFactory getFactory() {
return factory;
}
/**
* Sets the object factory for the Pentaho platform, This defaults to the
* StandaloneObjectFactory
* @return
*/
public void setFactory(IPentahoObjectFactory factory) {
this.factory = factory;
//object factory needs to also be early here so clients that do not need to
//run the platform can have an object factory available
PentahoSystem.setObjectFactory(factory);
}
/**
* Adds an administrative action to the system.
* @param adminAction
*/
public void addAdminAction(final IPentahoPublisher adminAction) {
adminActions.add(adminAction);
}
public void setAdminActions(final List<IPentahoPublisher> adminActions) {
this.adminActions = adminActions;
}
/**
* Adds a lifecycle listener. This object will be notified when the Pentaho platform
* starts and stops.
* @param lifecycleListener
*/
public void addLifecycleListener(final IPentahoSystemListener lifecycleListener) {
lifecycleListeners.add(lifecycleListener);
}
/**
* Returns the list of lifecycle listeners that will be used.
* These objects will be notified when the Pentaho platform
* starts and stops.
* @return
*/
public List<IPentahoSystemListener> getLifecycleListeners() {
return lifecycleListeners;
}
/**
* Returns the list of lifecycle listeners that will be used.
* These objects will be notified when the Pentaho platform
* starts and stops.
* @return
*/
public void setLifecycleListeners(final List<IPentahoSystemListener> lifecycleListeners) {
this.lifecycleListeners = lifecycleListeners;
}
/**
* Gets the system settings object that will be used by the Pentaho platform
* @return
*/
public ISystemSettings getSettingsProvider() {
return settingsProvider;
}
/**
* Sets the system settings object that will be used by the Pentaho platform
* @return
*/
public void setSettingsProvider(final ISystemSettings settingsProvider) {
PentahoSystem.setSystemSettingsService(settingsProvider);
this.settingsProvider = settingsProvider;
}
/**
* Returns true if the Pentaho platform has initialized successfully.
* @return
*/
public boolean isInitialized() {
return initialized;
}
/**
* Returns the list of startup actions.
* These actions will be executed on system startup or on session creation.
* @return
*/
public List<ISessionStartupAction> getStartupActions() {
return startupActions;
}
/**
* Sets the list of startup actions
* These actions will be executed on system startup or on session creation.
* @param startupActions
*/
public void setStartupActions(final List<ISessionStartupAction> startupActions) {
this.startupActions = startupActions;
}
/**
* Adds a strtup action to the system.
* These actions will be executed on system startup or on session creation.
* @param startupAction
*/
public void addStartupAction(final ISessionStartupAction startupAction) {
startupActions.add(startupAction);
}
/**
* Define an arbitrarily scoped object
* @param key the key to retrieval of this object
* @param implClassName the actual type that is served back to you when requested.
* @param scope the scope of the object
* @return the current {@link PentahoSystemBoot} instance, for chaining
* @throws NoSuchMethodError if the object factory does not support runtime object definition
*/
public PentahoSystemBoot define(String key, String implClassName, Scope scope) {
if (factory instanceof IPentahoDefinableObjectFactory) {
IPentahoDefinableObjectFactory definableFactory = (IPentahoDefinableObjectFactory) getFactory();
definableFactory.defineObject(key, implClassName, scope);
} else {
throw new NoSuchMethodError("define is only supported by IPentahoDefinableObjectFactory"); //$NON-NLS-1$
}
return this;
}
/**
* Define an arbitrarily scoped object
* @param interfaceClass the key to retrieval of this object
* @param implClass the actual type that is served back to you when requested.
* @param scope the scope of the object
* @return the current {@link PentahoSystemBoot} instance, for chaining
* @throws NoSuchMethodError if the object factory does not support runtime object definition
*/
public PentahoSystemBoot define(Class<?> interfaceClass, Class<?> implClass, Scope scope) {
return define(interfaceClass.getSimpleName(), implClass.getName(), scope);
}
/**
* Define an arbitrarily scoped object
* @param key the key to retrieval of this object
* @param implClass the actual type that is served back to you when requested.
* @param scope the scope of the object
* @return the current {@link PentahoSystemBoot} instance, for chaining
* @throws NoSuchMethodError if the object factory does not support runtime object definition
*/
public PentahoSystemBoot define(String key, Class<?> implClass, Scope scope) {
return define(key, implClass.getName(), scope);
}
/**
* Define a locally scoped object (aka prototype scope -- unique instance for each request for the class)
* @param interfaceClass the key to retrieval of this object
* @param implClass the actual type that is served back to you when requested.
* @return the current {@link MicroPlatform} instance, for chaining
*/
public PentahoSystemBoot define(Class<?> interfaceClass, Class<?> implClass) {
return define(interfaceClass.getSimpleName(), implClass.getName(), Scope.LOCAL);
}
/**
* Define a locally scoped object (aka prototype scope -- unique instance for each request for the class)
* @param key the key to retrieval of this object
* @param implClass the actual type that is served back to you when requested.
* @return the current {@link MicroPlatform} instance, for chaining
*/
public PentahoSystemBoot define(String key, Class<?> implClass) {
return define(key, implClass.getName(), Scope.LOCAL);
}
}