/*! ******************************************************************************
*
* 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.closure;
import java.util.HashMap;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.row.RowDataUtil;
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;
/**
* Reads information from a database table by using freehand SQL
*
* @author Matt
* @since 8-apr-2003
*/
public class ClosureGenerator extends BaseStep implements StepInterface {
private static Class<?> PKG = ClosureGeneratorMeta.class; // for i18n purposes, needed by Translator2!!
private ClosureGeneratorMeta meta;
private ClosureGeneratorData data;
public ClosureGenerator( 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 {
if ( data.reading ) {
Object[] rowData = getRow();
if ( rowData == null ) {
data.reading = false;
} else {
if ( first ) {
first = false;
// Create the output row metadata
//
data.outputRowMeta = getInputRowMeta().clone();
meta.getFields( data.outputRowMeta, getStepname(), null, null, this, repository, metaStore );
// Get indexes of parent and child field
//
data.parentIndex = getInputRowMeta().indexOfValue( meta.getParentIdFieldName() );
if ( data.parentIndex < 0 ) {
throw new KettleException( BaseMessages.getString(
PKG, "ClosureGenerator.Exception.ParentFieldNotFound" ) );
}
data.childIndex = getInputRowMeta().indexOfValue( meta.getChildIdFieldName() );
if ( data.childIndex < 0 ) {
throw new KettleException( BaseMessages.getString(
PKG, "ClosureGenerator.Exception.ChildFieldNotFound" ) );
}
data.parentValueMeta = getInputRowMeta().getValueMeta( data.parentIndex );
data.childValueMeta = getInputRowMeta().getValueMeta( data.childIndex );
}
// add values to the buffer...
//
Object parentId = rowData[data.parentIndex];
Object childId = rowData[data.childIndex];
data.map.put( childId, parentId );
}
} else {
// Writing the rows back...
//
for ( Object current : data.map.keySet() ) {
data.parents = new HashMap<Object, Long>();
// add self as distance 0
//
data.parents.put( current, 0L );
recurseParents( current, 1 );
for ( Object parent : data.parents.keySet() ) {
Object[] outputRow = RowDataUtil.allocateRowData( data.outputRowMeta.size() );
outputRow[0] = parent;
outputRow[1] = current;
outputRow[2] = data.parents.get( parent );
putRow( data.outputRowMeta, outputRow );
}
}
setOutputDone();
return false;
}
return true;
}
private void recurseParents( Object key, long distance ) {
// catch infinite loop - change at will
if ( distance > 50 ) {
throw new RuntimeException( "infinite loop detected:" + key );
}
Object parent = data.map.get( key );
if ( parent == null || parent == data.topLevel || parent.equals( data.topLevel ) ) {
return;
} else {
data.parents.put( parent, distance );
recurseParents( parent, distance + 1 );
return;
}
}
public boolean init( StepMetaInterface smi, StepDataInterface sdi ) {
meta = (ClosureGeneratorMeta) smi;
data = (ClosureGeneratorData) sdi;
if ( super.init( smi, sdi ) ) {
data.reading = true;
data.map = new HashMap<Object, Object>();
data.topLevel = null;
if ( meta.isRootIdZero() ) {
data.topLevel = new Long( 0 );
}
return true;
}
return false;
}
}