/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2016 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.rowgenerator; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.pentaho.di.core.CheckResult; import org.pentaho.di.core.CheckResultInterface; import org.pentaho.di.core.Const; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.RowMetaAndData; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.exception.KettlePluginException; import org.pentaho.di.core.exception.KettleValueException; import org.pentaho.di.core.row.RowDataUtil; import org.pentaho.di.core.row.RowMeta; import org.pentaho.di.core.row.RowMetaInterface; import org.pentaho.di.core.row.ValueMetaInterface; import org.pentaho.di.core.row.value.ValueMetaDate; import org.pentaho.di.core.row.value.ValueMetaFactory; import org.pentaho.di.core.util.StringUtil; 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; /** * Generates a number of (empty or the same) rows * * @author Matt * @since 4-apr-2003 */ public class RowGenerator extends BaseStep implements StepInterface { private static Class<?> PKG = RowGeneratorMeta.class; // for i18n purposes, needed by Translator2!! private RowGeneratorMeta meta; private RowGeneratorData data; public RowGenerator( StepMeta stepMeta, StepDataInterface stepDataInterface, int copyNr, TransMeta transMeta, Trans trans ) { super( stepMeta, stepDataInterface, copyNr, transMeta, trans ); meta = (RowGeneratorMeta) getStepMeta().getStepMetaInterface(); data = (RowGeneratorData) stepDataInterface; } public static final RowMetaAndData buildRow( RowGeneratorMeta meta, List<CheckResultInterface> remarks, String origin ) throws KettlePluginException { RowMetaInterface rowMeta = new RowMeta(); Object[] rowData = RowDataUtil.allocateRowData( meta.getFieldName().length + 2 ); int index = 0; if ( meta.isNeverEnding() ) { if ( !Utils.isEmpty( meta.getRowTimeField() ) ) { rowMeta.addValueMeta( new ValueMetaDate( meta.getRowTimeField() ) ); rowData[index++] = null; } if ( !Utils.isEmpty( meta.getLastTimeField() ) ) { rowMeta.addValueMeta( new ValueMetaDate( meta.getLastTimeField() ) ); rowData[index++] = null; } } for ( int i = 0; i < meta.getFieldName().length; i++ ) { int valtype = ValueMetaFactory.getIdForValueMeta( meta.getFieldType()[i] ); if ( meta.getFieldName()[i] != null ) { ValueMetaInterface valueMeta = ValueMetaFactory.createValueMeta( meta.getFieldName()[i], valtype ); // build a // value! valueMeta.setLength( meta.getFieldLength()[i] ); valueMeta.setPrecision( meta.getFieldPrecision()[i] ); valueMeta.setConversionMask( meta.getFieldFormat()[i] ); valueMeta.setCurrencySymbol( meta.getCurrency()[i] ); valueMeta.setGroupingSymbol( meta.getGroup()[i] ); valueMeta.setDecimalSymbol( meta.getDecimal()[i] ); valueMeta.setOrigin( origin ); ValueMetaInterface stringMeta = ValueMetaFactory.cloneValueMeta( valueMeta, ValueMetaInterface.TYPE_STRING ); if ( meta.isSetEmptyString() != null && meta.isSetEmptyString()[i] ) { // Set empty string rowData[index] = StringUtil.EMPTY_STRING; } else { String stringValue = meta.getValue()[i]; // If the value is empty: consider it to be NULL. if ( Utils.isEmpty( stringValue ) ) { rowData[index] = null; if ( valueMeta.getType() == ValueMetaInterface.TYPE_NONE ) { String message = BaseMessages.getString( PKG, "RowGenerator.CheckResult.SpecifyTypeError", valueMeta.getName(), stringValue ); remarks.add( new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, message, null ) ); } } else { // Convert the data from String to the specified type ... // try { rowData[index] = valueMeta.convertData( stringMeta, stringValue ); } catch ( KettleValueException e ) { switch ( valueMeta.getType() ) { case ValueMetaInterface.TYPE_NUMBER: String message = BaseMessages.getString( PKG, "RowGenerator.BuildRow.Error.Parsing.Number", valueMeta .getName(), stringValue, e.toString() ); remarks.add( new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, message, null ) ); break; case ValueMetaInterface.TYPE_DATE: message = BaseMessages.getString( PKG, "RowGenerator.BuildRow.Error.Parsing.Date", valueMeta.getName(), stringValue, e .toString() ); remarks.add( new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, message, null ) ); break; case ValueMetaInterface.TYPE_INTEGER: message = BaseMessages.getString( PKG, "RowGenerator.BuildRow.Error.Parsing.Integer", valueMeta .getName(), stringValue, e.toString() ); remarks.add( new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, message, null ) ); break; case ValueMetaInterface.TYPE_BIGNUMBER: message = BaseMessages.getString( PKG, "RowGenerator.BuildRow.Error.Parsing.BigNumber", valueMeta .getName(), stringValue, e.toString() ); remarks.add( new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, message, null ) ); break; case ValueMetaInterface.TYPE_TIMESTAMP: message = BaseMessages.getString( PKG, "RowGenerator.BuildRow.Error.Parsing.Timestamp", valueMeta .getName(), stringValue, e.toString() ); remarks.add( new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, message, null ) ); break; default: // Boolean and binary don't throw errors normally, so it's probably an unspecified error problem... message = BaseMessages.getString( PKG, "RowGenerator.CheckResult.SpecifyTypeError", valueMeta .getName(), stringValue ); remarks.add( new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, message, null ) ); break; } } } } // Now add value to the row! // This is in fact a copy from the fields row, but now with data. rowMeta.addValueMeta( valueMeta ); index++; } } return new RowMetaAndData( rowMeta, rowData ); } @Override public synchronized boolean processRow( StepMetaInterface smi, StepDataInterface sdi ) throws KettleException { meta = (RowGeneratorMeta) smi; data = (RowGeneratorData) sdi; Object[] r = null; boolean retval = true; if ( first ) { first = false; getRow(); } else { if ( meta.isNeverEnding() && data.delay > 0 ) { try { Thread.sleep( data.delay ); } catch ( InterruptedException e ) { throw new KettleException( e ); } } } if ( meta.isNeverEnding() || data.rowsWritten < data.rowLimit ) { r = data.outputRowMeta.cloneRow( data.outputRowData ); } else { setOutputDone(); // signal end to receiver(s) return false; } if ( meta.isNeverEnding() ) { data.prevDate = data.rowDate; data.rowDate = new Date(); int index = 0; if ( !Utils.isEmpty( meta.getRowTimeField() ) ) { r[index++] = data.rowDate; } if ( !Utils.isEmpty( meta.getLastTimeField() ) ) { r[index++] = data.prevDate; } } putRow( data.outputRowMeta, r ); data.rowsWritten++; if ( log.isRowLevel() ) { logRowlevel( BaseMessages.getString( PKG, "RowGenerator.Log.Wrote.Row", Long.toString( data.rowsWritten ), data.outputRowMeta.getString( r ) ) ); } if ( checkFeedback( data.rowsWritten ) ) { if ( log.isBasic() ) { logBasic( BaseMessages.getString( PKG, "RowGenerator.Log.LineNr", Long.toString( data.rowsWritten ) ) ); } } return retval; } @Override public boolean init( StepMetaInterface smi, StepDataInterface sdi ) { try { meta = (RowGeneratorMeta) smi; data = (RowGeneratorData) sdi; if ( super.init( smi, sdi ) ) { // Determine the number of rows to generate... data.rowLimit = Const.toLong( environmentSubstitute( meta.getRowLimit() ), -1L ); data.rowsWritten = 0L; data.delay = Const.toLong( environmentSubstitute( meta.getIntervalInMs() ), -1L ); if ( data.rowLimit < 0L ) { // Unable to parse logError( BaseMessages.getString( PKG, "RowGenerator.Wrong.RowLimit.Number" ) ); return false; // fail } // Create a row (constants) with all the values in it... List<CheckResultInterface> remarks = new ArrayList<CheckResultInterface>(); // stores the errors... RowMetaAndData outputRow = buildRow( meta, remarks, getStepname() ); if ( !remarks.isEmpty() ) { for ( int i = 0; i < remarks.size(); i++ ) { CheckResult cr = (CheckResult) remarks.get( i ); logError( cr.getText() ); } return false; } data.outputRowData = outputRow.getData(); data.outputRowMeta = outputRow.getRowMeta(); return true; } return false; } catch ( Exception e ) { setErrors( 1L ); logError( "Error initializing step", e ); return false; } } @Override public boolean canProcessOneRow() { return true; } }