/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2013 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.cubeoutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import org.pentaho.di.core.ResultFile;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleFileException;
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;
/**
* Outputs a stream/series of rows to a file, effectively building a sort of (compressed) microcube.
*
* @author Matt
* @since 4-apr-2003
*/
public class CubeOutput extends BaseStep implements StepInterface {
private static Class<?> PKG = CubeOutputMeta.class; // for i18n purposes, needed by Translator2!!
private CubeOutputMeta meta;
private CubeOutputData data;
public CubeOutput( StepMeta stepMeta, StepDataInterface stepDataInterface, int copyNr, TransMeta transMeta,
Trans trans ) {
super( stepMeta, stepDataInterface, copyNr, transMeta, trans );
}
public boolean processRow( StepMetaInterface smi, StepDataInterface sdi ) throws KettleException {
meta = (CubeOutputMeta) smi;
data = (CubeOutputData) sdi;
Object[] r;
boolean result = true;
r = getRow(); // This also waits for a row to be finished.
if ( first ) { // Always run this code once, even if stream is empty (r==null)
if ( getInputRowMeta() != null ) {
data.outputMeta = getInputRowMeta().clone();
} else {
// If the stream is empty, then row metadata probably hasn't been received. In this case, use
// the design-time algorithm to calculate the output metadata.
data.outputMeta = getTransMeta().getPrevStepFields( getStepMeta() );
}
// If input stream is empty, but file was already opened in init(), then
// write metadata so as to create a valid, empty cube file.
if ( r == null && data.oneFileOpened ) {
result = writeHeaderToFile();
if ( !result ) {
setErrors( 1 );
stopAll();
return false;
}
}
}
if ( r == null ) {
setOutputDone();
return false;
}
if ( first ) {
if ( meta.isDoNotOpenNewFileInit() ) {
try {
prepareFile();
data.oneFileOpened = true;
} catch ( KettleFileException ioe ) {
logError( BaseMessages.getString( PKG, "CubeOutput.Log.ErrorOpeningCubeOutputFile" ) + ioe.toString() );
setErrors( 1 );
return false;
}
}
result = writeHeaderToFile();
if ( !result ) {
setErrors( 1 );
stopAll();
return false;
}
first = false;
}
result = writeRowToFile( r );
if ( !result ) {
setErrors( 1 );
stopAll();
return false;
}
putRow( data.outputMeta, r ); // in case we want it to go further...
if ( checkFeedback( getLinesOutput() ) ) {
if ( log.isBasic() ) {
logBasic( BaseMessages.getString( PKG, "CubeOutput.Log.LineNumber" ) + getLinesOutput() );
}
}
return result;
}
private synchronized boolean writeHeaderToFile() {
try {
data.outputMeta.writeMeta( data.dos );
} catch ( Exception e ) {
logError( BaseMessages.getString( PKG, "CubeOutput.Log.ErrorWritingLine" ) + e.toString() );
return false;
}
return true;
}
private synchronized boolean writeRowToFile( Object[] r ) {
try {
// Write data to the cube file...
data.outputMeta.writeData( data.dos, r );
} catch ( Exception e ) {
logError( BaseMessages.getString( PKG, "CubeOutput.Log.ErrorWritingLine" ) + e.toString() );
return false;
}
incrementLinesOutput();
return true;
}
public boolean init( StepMetaInterface smi, StepDataInterface sdi ) {
meta = (CubeOutputMeta) smi;
data = (CubeOutputData) sdi;
if ( super.init( smi, sdi ) ) {
if ( !meta.isDoNotOpenNewFileInit() ) {
try {
prepareFile();
data.oneFileOpened = true;
return true;
} catch ( KettleFileException ioe ) {
logError( BaseMessages.getString( PKG, "CubeOutput.Log.ErrorOpeningCubeOutputFile" ) + ioe.toString() );
}
} else {
return true;
}
}
return false;
}
private void prepareFile() throws KettleFileException {
try {
String filename = environmentSubstitute( meta.getFilename() );
if ( meta.isAddToResultFiles() ) {
// Add this to the result file names...
ResultFile resultFile =
new ResultFile(
ResultFile.FILE_TYPE_GENERAL, KettleVFS.getFileObject( filename, getTransMeta() ), getTransMeta()
.getName(), getStepname() );
resultFile.setComment( "This file was created with a cube file output step" );
addResultFile( resultFile );
}
data.fos = KettleVFS.getOutputStream( filename, getTransMeta(), false );
data.zip = new GZIPOutputStream( data.fos );
data.dos = new DataOutputStream( data.zip );
} catch ( Exception e ) {
throw new KettleFileException( e );
}
}
public void dispose( StepMetaInterface smi, StepDataInterface sdi ) {
if ( data.oneFileOpened ) {
try {
if ( data.dos != null ) {
data.dos.close();
data.dos = null;
}
if ( data.zip != null ) {
data.zip.close();
data.zip = null;
}
if ( data.fos != null ) {
data.fos.close();
data.fos = null;
}
} catch ( IOException e ) {
logError( BaseMessages.getString( PKG, "CubeOutput.Log.ErrorClosingFile" ) + meta.getFilename() );
setErrors( 1 );
stopAll();
}
}
super.dispose( smi, sdi );
}
}