/*! * 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 (c) 2002-2016 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.plugin.action.kettle; import com.google.common.annotations.VisibleForTesting; import org.apache.commons.lang.StringUtils; import org.pentaho.di.cluster.SlaveServer; import org.pentaho.di.core.KettleEnvironment; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.logging.KettleLogStore; import org.pentaho.di.core.logging.LogChannel; import org.pentaho.di.core.xml.XMLHandler; import org.pentaho.di.www.CarteSingleton; import org.pentaho.di.www.SlaveServerConfig; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.engine.IPentahoSystemListener; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.plugin.action.messages.Messages; import org.pentaho.platform.util.logging.Logger; import org.pentaho.platform.util.xml.XMLParserFactoryProducer; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.Map; import java.util.Properties; public class KettleSystemListener implements IPentahoSystemListener { /** * If {@code true}, send Kettle output to the platform log file (e.g. pentaho.log) in addition to its normal * destinations. */ private boolean usePlatformLogFile = true; private org.slf4j.Logger logger = LoggerFactory.getLogger( getClass() ); public boolean startup( final IPentahoSession session ) { if ( usePlatformLogFile ) { KettleLogStore.init( false, false ); initLogging(); } hookInDataSourceProvider(); // Default DI_HOME System Property if not set if ( StringUtils.isEmpty( System.getProperty( "DI_HOME" ) ) ) { String defaultKettleHomePath = PentahoSystem.getApplicationContext().getSolutionPath( "system" + File.separator + "kettle" ); logger.error( "DI_HOME System Property not properly set. The default location of " + defaultKettleHomePath + " will be used." ); System.setProperty( "DI_HOME", defaultKettleHomePath ); } try { KettleSystemListener.environmentInit( session ); } catch ( Throwable t ) { t.printStackTrace(); Logger.error( KettleSystemListener.class.getName(), Messages.getInstance().getErrorString( "KettleSystemListener.ERROR_0001_PLUGIN_LOAD_FAILED" ) ); //$NON-NLS-1$ } try { String slaveServerConfigFilename = "system" + File.separator + "kettle" + File.separator + "slave-server-config.xml"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ File slaveServerConfigFile = new File( PentahoSystem.getApplicationContext().getSolutionPath( slaveServerConfigFilename ) ); if ( slaveServerConfigFile.exists() ) { InputStream is = new FileInputStream( slaveServerConfigFile ); Node configNode = getSlaveServerConfigNode( is ); SlaveServerConfig config = new DIServerConfig( new LogChannel( "Slave server config" ), configNode ); config.setFilename( slaveServerConfigFile.getAbsolutePath() ); SlaveServer slaveServer = new SlaveServer(); config.setSlaveServer( slaveServer ); CarteSingleton.setSlaveServerConfig( config ); } } catch ( Throwable t ) { t.printStackTrace(); Logger.error( KettleSystemListener.class.getName(), t.getMessage() ); } return true; } /** * Sends Kettle's logs to the platform log as well. */ @SuppressWarnings( "unchecked" ) protected void initLogging() { // Find the platform file listener (if any) and make sure it gets data from Kettle. // We listen to the log records from Kettle and pass logging along // Enumeration<org.apache.log4j.Appender> appenders = org.apache.log4j.Logger.getRootLogger().getAllAppenders(); while ( appenders.hasMoreElements() ) { org.apache.log4j.Appender appender = appenders.nextElement(); if ( appender instanceof org.apache.log4j.FileAppender ) { Log4jForwardingKettleLoggingEventListener listener = new Log4jForwardingKettleLoggingEventListener( appender ); KettleLogStore.getAppender().addLoggingEventListener( listener ); } } } private void hookInDataSourceProvider() { try { @SuppressWarnings( "unused" ) Class<?> clazz = Class.forName( "org.pentaho.di.core.database.DataSourceProviderInterface" ); //$NON-NLS-1$ PlatformKettleDataSourceProvider.hookupProvider(); } catch ( Exception ignored ) { // if here, then it's because we're running with an older // kettle. } } public static Map readProperties( final IPentahoSession session ) { Properties props = new Properties(); String kettlePropsFilename = "system" + File.separator + "kettle" + File.separator + "kettle.properties"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ InputStream is = null; try { File f = new File( PentahoSystem.getApplicationContext().getSolutionPath( kettlePropsFilename ) ); if ( !f.exists() ) { return props; } is = new FileInputStream( f ); props.load( is ); } catch ( IOException ioe ) { Logger.error( KettleSystemListener.class.getName(), Messages.getInstance().getString( "KettleSystemListener.ERROR_0003_PROPERTY_FILE_READ_FAILED" ) + ioe.getMessage(), ioe ); //$NON-NLS-1$ } finally { if ( is != null ) { try { is.close(); } catch ( IOException e ) { // ignore } } } props.put( "pentaho.solutionpath", "solution:" ); //$NON-NLS-1$ //$NON-NLS-2$ return props; } public static void environmentInit( final IPentahoSession session ) throws KettleException { // init kettle without simplejndi KettleEnvironment.init( false ); } public void shutdown() { // Nothing required } public void setUsePlatformLogFile( final boolean usePlatformLogFile ) { this.usePlatformLogFile = usePlatformLogFile; } @VisibleForTesting Node getSlaveServerConfigNode( InputStream is ) throws SAXException, IOException, ParserConfigurationException { Document document = XMLParserFactoryProducer.createSecureDocBuilderFactory().newDocumentBuilder().parse( is ); return XMLHandler.getSubNode( document, SlaveServerConfig.XML_TAG ); } }