/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2017 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ package org.pentaho.di.trans.steps.pentahoreporting; import java.math.BigDecimal; import java.net.URL; import java.util.Date; import org.apache.commons.vfs2.FileObject; import org.pentaho.di.core.ResultFile; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.exception.KettleStepException; import org.pentaho.di.core.logging.LogChannelInterface; import org.pentaho.di.core.vfs.KettleVFS; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.trans.Trans; import org.pentaho.di.trans.TransMeta; import org.pentaho.di.trans.step.BaseStep; import org.pentaho.di.trans.step.StepDataInterface; import org.pentaho.di.trans.step.StepInterface; import org.pentaho.di.trans.step.StepMeta; import org.pentaho.di.trans.step.StepMetaInterface; import org.pentaho.di.trans.steps.pentahoreporting.PentahoReportingOutputMeta.ProcessorType; import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot; import org.pentaho.reporting.engine.classic.core.MasterReport; import org.pentaho.reporting.engine.classic.core.modules.gui.common.StatusType; import org.pentaho.reporting.engine.classic.core.modules.gui.csv.CSVTableExportTask; import org.pentaho.reporting.engine.classic.core.modules.gui.html.HtmlStreamExportTask; import org.pentaho.reporting.engine.classic.core.modules.gui.pdf.PdfExportTask; import org.pentaho.reporting.engine.classic.core.modules.gui.rtf.RTFExportTask; import org.pentaho.reporting.engine.classic.core.modules.gui.xls.ExcelExportTask; import org.pentaho.reporting.engine.classic.core.modules.gui.xls.XSSFExcelExportTask; import org.pentaho.reporting.engine.classic.core.modules.output.table.html.HtmlReportUtil; import org.pentaho.reporting.engine.classic.core.parameters.ParameterDefinitionEntry; import org.pentaho.reporting.engine.classic.core.parameters.ReportParameterDefinition; import org.pentaho.reporting.engine.classic.core.util.ReportParameterValues; import org.pentaho.reporting.libraries.base.config.ModifiableConfiguration; import org.pentaho.reporting.libraries.base.util.ObjectUtilities; import org.pentaho.reporting.libraries.fonts.LibFontBoot; import org.pentaho.reporting.libraries.resourceloader.LibLoaderBoot; import org.pentaho.reporting.libraries.resourceloader.Resource; import org.pentaho.reporting.libraries.resourceloader.ResourceManager; /** * Outputs a stream/series of rows to a file, effectively building a sort of (compressed) microcube. * * @author Matt * @since 4-apr-2003 */ public class PentahoReportingOutput extends BaseStep implements StepInterface { private static Class<?> PKG = PentahoReportingOutput.class; // for i18n purposes, needed by Translator2!! private PentahoReportingOutputMeta meta; private PentahoReportingOutputData data; public PentahoReportingOutput( StepMeta stepMeta, StepDataInterface stepDataInterface, int copyNr, TransMeta transMeta, Trans trans ) { super( stepMeta, stepDataInterface, copyNr, transMeta, trans ); } @Override public boolean processRow( StepMetaInterface smi, StepDataInterface sdi ) throws KettleException { meta = (PentahoReportingOutputMeta) smi; data = (PentahoReportingOutputData) sdi; boolean result = true; // For every row we read, we execute a report // Object[] r = getRow(); // All done, signal this to the next steps... // if ( r == null ) { setOutputDone(); return false; } if ( first ) { first = false; data.inputFieldIndex = getInputRowMeta().indexOfValue( meta.getInputFileField() ); if ( data.inputFieldIndex < 0 ) { throw new KettleException( BaseMessages.getString( PKG, "PentahoReportingOutput.Exception.CanNotFindField", meta.getInputFileField() ) ); } data.outputFieldIndex = getInputRowMeta().indexOfValue( meta.getOutputFileField() ); if ( data.inputFieldIndex < 0 ) { throw new KettleException( BaseMessages.getString( PKG, "PentahoReportingOutput.Exception.CanNotFindField", meta.getOutputFileField() ) ); } performPentahoReportingBoot( log, getClass() ); } String sourceFilename = getInputRowMeta().getString( r, data.inputFieldIndex ); String targetFilename = getInputRowMeta().getString( r, data.outputFieldIndex ); processReport( r, sourceFilename, targetFilename, meta.getOutputProcessorType(), meta.getCreateParentfolder() ); // in case we want the input data to go to more steps. // putRow( getInputRowMeta(), r ); if ( checkFeedback( getLinesOutput() ) ) { logBasic( BaseMessages.getString( PKG, "PentahoReportingOutput.Log.LineNumber" ) + getLinesOutput() ); } return result; } public static void performPentahoReportingBoot( LogChannelInterface log, Class<?> referenceClass ) { // Boot the Pentaho reporting engine! // if ( ClassicEngineBoot.getInstance().isBootDone() == false ) { ObjectUtilities.setClassLoader( referenceClass.getClassLoader() ); ObjectUtilities.setClassLoaderSource( ObjectUtilities.CLASS_CONTEXT ); LibLoaderBoot.getInstance().start(); LibFontBoot.getInstance().start(); ClassicEngineBoot.getInstance().start(); Exception exception = ClassicEngineBoot.getInstance().getBootFailureReason(); if ( exception != null ) { log.logError( "Error booting the Pentaho reporting engine", exception ); } } } public static MasterReport loadMasterReport( String sourceFilename ) throws Exception { ResourceManager manager = new ResourceManager(); manager.registerDefaults(); FileObject fileObject = KettleVFS.getFileObject( sourceFilename ); URL url = new URL( fileObject.getName().getURI() ); Resource resource = manager.createDirectly( url, MasterReport.class ); MasterReport report = (MasterReport) resource.getResource(); return report; } private void processReport( Object[] r, String sourceFilename, String targetFilename, ProcessorType outputProcessorType, Boolean createParentFolder ) throws KettleException { try { // Load the master report from the PRPT // MasterReport report = loadMasterReport( sourceFilename ); // Set the parameters values that are present in the various fields... // ReportParameterValues values = report.getParameterValues(); ReportParameterDefinition definition = report.getParameterDefinition(); for ( String parameterName : meta.getParameterFieldMap().keySet() ) { String fieldName = meta.getParameterFieldMap().get( parameterName ); if ( fieldName != null ) { int index = getInputRowMeta().indexOfValue( fieldName ); if ( index < 0 ) { throw new KettleException( BaseMessages.getString( PKG, "PentahoReportingOutput.Exception.CanNotFindField", fieldName ) ); } Class<?> clazz = findParameterClass( definition, parameterName ); Object value = null; if ( clazz != null ) { if ( clazz.equals( String.class ) ) { value = getInputRowMeta().getString( r, index ); } else if ( clazz.equals( ( new String[0] ).getClass() ) ) { value = getInputRowMeta().getString( r, index ).split( "\t" ); } else if ( clazz.equals( Date.class ) ) { value = getInputRowMeta().getDate( r, index ); } else if ( clazz.equals( byte.class ) || clazz.equals( Byte.class ) ) { value = getInputRowMeta().getInteger( r, index ).byteValue(); } else if ( clazz.equals( Short.class ) || clazz.equals( short.class ) ) { value = getInputRowMeta().getInteger( r, index ).shortValue(); } else if ( clazz.equals( Integer.class ) || clazz.equals( int.class ) ) { value = getInputRowMeta().getInteger( r, index ).intValue(); } else if ( clazz.equals( Long.class ) || clazz.equals( long.class ) ) { value = getInputRowMeta().getInteger( r, index ); } else if ( clazz.equals( Double.class ) || clazz.equals( double.class ) ) { value = getInputRowMeta().getNumber( r, index ); } else if ( clazz.equals( Float.class ) || clazz.equals( float.class ) ) { value = getInputRowMeta().getNumber( r, index ).floatValue(); } else if ( clazz.equals( Number.class ) ) { value = getInputRowMeta().getBigNumber( r, index ).floatValue(); } else if ( clazz.equals( Boolean.class ) || clazz.equals( boolean.class ) ) { value = getInputRowMeta().getBoolean( r, index ); } else if ( clazz.equals( BigDecimal.class ) ) { value = getInputRowMeta().getBigNumber( r, index ); } else if ( clazz.equals( ( new byte[0] ).getClass() ) ) { value = getInputRowMeta().getBinary( r, index ); } else { value = getInputRowMeta().getValueMeta( index ).convertToNormalStorageType( r[index] ); } values.put( parameterName, value ); } else { // This parameter was not found, log this as a warning... // logBasic( BaseMessages.getString( PKG, "PentahoReportingOutput.Log.ParameterNotFoundInReport", parameterName, sourceFilename ) ); } } } ModifiableConfiguration modifiableConfiguration = (ModifiableConfiguration) report.getConfiguration(); String property; Runnable exportTask; PentahoReportingSwingGuiContext context = new PentahoReportingSwingGuiContext(); switch ( outputProcessorType ) { case PDF: property = "org.pentaho.reporting.engine.classic.core.modules.gui.pdf.TargetFileName"; modifiableConfiguration.setConfigProperty( property, targetFilename ); property = "org.pentaho.reporting.engine.classic.core.modules.gui.pdf.CreateParentFolder"; modifiableConfiguration.setConfigProperty( property, createParentFolder.toString() ); exportTask = new PdfExportTask( report, null, context ); break; case CSV: property = "org.pentaho.reporting.engine.classic.core.modules.gui.csv.FileName"; modifiableConfiguration.setConfigProperty( property, targetFilename ); property = "org.pentaho.reporting.engine.classic.core.modules.gui.csv.CreateParentFolder"; modifiableConfiguration.setConfigProperty( property, createParentFolder.toString() ); exportTask = new CSVTableExportTask( report, null, context ); break; case Excel: property = "org.pentaho.reporting.engine.classic.core.modules.gui.xls.FileName"; modifiableConfiguration.setConfigProperty( property, targetFilename ); property = "org.pentaho.reporting.engine.classic.core.modules.gui.xls.CreateParentFolder"; modifiableConfiguration.setConfigProperty( property, createParentFolder.toString() ); exportTask = new ExcelExportTask( report, null, context ); break; case Excel_2007: property = "org.pentaho.reporting.engine.classic.core.modules.gui.xls.FileName"; modifiableConfiguration.setConfigProperty( property, targetFilename ); property = "org.pentaho.reporting.engine.classic.core.modules.gui.xls.CreateParentFolder"; modifiableConfiguration.setConfigProperty( property, createParentFolder.toString() ); exportTask = new XSSFExcelExportTask( report, null, context ); break; case StreamingHTML: property = "org.pentaho.reporting.engine.classic.core.modules.gui.html.stream.TargetFileName"; modifiableConfiguration.setConfigProperty( property, targetFilename ); property = "org.pentaho.reporting.engine.classic.core.modules.gui.html.stream.CreateParentFolder"; modifiableConfiguration.setConfigProperty( property, createParentFolder.toString() ); exportTask = new HtmlStreamExportTask( report, null, context ); break; case PagedHTML: property = "org.pentaho.reporting.engine.classic.core.modules.gui.html.paged.CreateParentFolder"; modifiableConfiguration.setConfigProperty( property, createParentFolder.toString() ); HtmlReportUtil.createDirectoryHTML( report, targetFilename ); exportTask = null; break; case RTF: property = "org.pentaho.reporting.engine.classic.core.modules.gui.rtf.FileName"; modifiableConfiguration.setConfigProperty( property, targetFilename ); property = "org.pentaho.reporting.engine.classic.core.modules.gui.rtf.CreateParentFolder"; modifiableConfiguration.setConfigProperty( property, createParentFolder.toString() ); exportTask = new RTFExportTask( report, null, context ); break; default: exportTask = null; break; } if ( exportTask != null ) { exportTask.run(); } if ( context.getStatusType() == StatusType.ERROR ) { KettleVFS.getFileObject( targetFilename, getTransMeta() ).delete(); if ( context.getCause() != null ) { throw context.getCause(); } throw new KettleStepException( context.getMessage() ); } ResultFile resultFile = new ResultFile( ResultFile.FILE_TYPE_GENERAL, KettleVFS.getFileObject( targetFilename, getTransMeta() ), getTransMeta().getName(), getStepname() ); resultFile.setComment( "This file was created with a Pentaho Reporting Output step" ); addResultFile( resultFile ); } catch ( Throwable e ) { throw new KettleException( BaseMessages.getString( PKG, "PentahoReportingOutput.Exception.UnexpectedErrorRenderingReport", sourceFilename, targetFilename, outputProcessorType.getDescription() ), e ); } } private Class<?> findParameterClass( ReportParameterDefinition definition, String parameterName ) { for ( int i = 0; i < definition.getParameterCount(); i++ ) { ParameterDefinitionEntry entry = definition.getParameterDefinition( i ); if ( parameterName.equals( entry.getName() ) ) { return entry.getValueType(); } } return null; } }