/*! ****************************************************************************** * * 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.salesforcedelete; import org.pentaho.di.core.Const; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.exception.KettleStepException; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.trans.Trans; import org.pentaho.di.trans.TransMeta; import org.pentaho.di.trans.step.StepDataInterface; import org.pentaho.di.trans.step.StepMeta; import org.pentaho.di.trans.step.StepMetaInterface; import org.pentaho.di.trans.steps.salesforce.SalesforceStep; /** * Read data from Salesforce module, convert them to rows and writes these to one or more output streams. * * @author jstairs,Samatar * @since 10-06-2007 */ public class SalesforceDelete extends SalesforceStep { private static Class<?> PKG = SalesforceDeleteMeta.class; // for i18n purposes, needed by Translator2!! private SalesforceDeleteMeta meta; private SalesforceDeleteData data; public SalesforceDelete( 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 { // get one row ... This does some basic initialization of the objects, including loading the info coming in Object[] outputRowData = getRow(); if ( outputRowData == null ) { if ( data.iBufferPos > 0 ) { flushBuffers(); } setOutputDone(); return false; } // If we haven't looked at a row before then do some basic setup. if ( first ) { first = false; data.deleteId = new String[meta.getBatchSizeInt()]; data.outputBuffer = new Object[meta.getBatchSizeInt()][]; // Create the output row meta-data data.outputRowMeta = getInputRowMeta().clone(); meta.getFields( data.outputRowMeta, getStepname(), null, null, this, repository, metaStore ); // Check deleteKeyField String realFieldName = environmentSubstitute( meta.getDeleteField() ); if ( Utils.isEmpty( realFieldName ) ) { throw new KettleException( BaseMessages.getString( PKG, "SalesforceDelete.Error.DeleteKeyFieldMissing" ) ); } // return the index of the field in the input stream data.indexOfKeyField = getInputRowMeta().indexOfValue( realFieldName ); if ( data.indexOfKeyField < 0 ) { // the field is unreachable! throw new KettleException( BaseMessages.getString( PKG, "SalesforceDelete.Error.CanNotFindFDeleteKeyField", realFieldName ) ); } } try { writeToSalesForce( outputRowData ); } catch ( Exception e ) { throw new KettleStepException( BaseMessages.getString( PKG, "SalesforceDelete.log.Exception" ), e ); } return true; } private void writeToSalesForce( Object[] rowData ) throws KettleException { try { if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "SalesforceDelete.Log.WriteToSalesforce", data.iBufferPos, meta .getBatchSizeInt() ) ); } // if there is room in the buffer if ( data.iBufferPos < meta.getBatchSizeInt() ) { // Load the buffer array data.deleteId[data.iBufferPos] = getInputRowMeta().getString( rowData, data.indexOfKeyField ); data.outputBuffer[data.iBufferPos] = rowData; data.iBufferPos++; } if ( data.iBufferPos >= meta.getBatchSizeInt() ) { if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "SalesforceDelete.Log.CallingFlush" ) ); } flushBuffers(); } } catch ( Exception e ) { throw new KettleException( BaseMessages.getString( PKG, "SalesforceDelete.Error.WriteToSalesforce", e .getMessage() ) ); } } private void flushBuffers() throws KettleException { try { if ( data.deleteId.length > data.iBufferPos ) { String[] smallBuffer = new String[data.iBufferPos]; System.arraycopy( data.deleteId, 0, smallBuffer, 0, data.iBufferPos ); data.deleteId = smallBuffer; } // delete the object(s) by sending the array to the web service data.deleteResult = data.connection.delete( data.deleteId ); int nr = data.deleteResult.length; for ( int j = 0; j < nr; j++ ) { if ( data.deleteResult[j].isSuccess() ) { putRow( data.outputRowMeta, data.outputBuffer[j] ); // copy row to output rowset(s); incrementLinesOutput(); if ( checkFeedback( getLinesInput() ) ) { if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "SalesforceDelete.log.LineRow", String .valueOf( getLinesInput() ) ) ); } } } else { // there were errors during the create call, go through the // errors // array and write them to the screen if ( !getStepMeta().isDoingErrorHandling() ) { if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "SalesforceDelete.Found.Error" ) ); } com.sforce.soap.partner.Error err = data.deleteResult[j].getErrors()[0]; throw new KettleException( BaseMessages .getString( PKG, "SalesforceDelete.Error.FlushBuffer", new Integer( j ), err.getStatusCode(), err .getMessage() ) ); } String errorMessage = ""; int nrErrors = data.deleteResult[j].getErrors().length; for ( int i = 0; i < nrErrors; i++ ) { // get the next error com.sforce.soap.partner.Error err = data.deleteResult[j].getErrors()[i]; errorMessage += BaseMessages.getString( PKG, "SalesforceDelete.Error.FlushBuffer", new Integer( j ), err .getStatusCode(), err.getMessage() ); } // Simply add this row to the error row if ( log.isDebug() ) { logDebug( BaseMessages.getString( PKG, "SalesforceDelete.PassingRowToErrorStep" ) ); } putError( getInputRowMeta(), data.outputBuffer[j], 1, errorMessage, null, "SalesforceDelete001" ); } } // reset the buffers data.deleteId = new String[meta.getBatchSizeInt()]; data.outputBuffer = new Object[meta.getBatchSizeInt()][]; data.iBufferPos = 0; } catch ( Exception e ) { if ( !getStepMeta().isDoingErrorHandling() ) { throw new KettleException( BaseMessages .getString( PKG, "SalesforceDelete.FailedToDeleted", e.getMessage() ) ); } // Simply add this row to the error row if ( log.isDebug() ) { logDebug( "Passing row to error step" ); } for ( int i = 0; i < data.iBufferPos; i++ ) { putError( data.inputRowMeta, data.outputBuffer[i], 1, e.getMessage(), null, "SalesforceDelete002" ); } } finally { if ( data.deleteResult != null ) { data.deleteResult = null; } } } @Override public boolean init( StepMetaInterface smi, StepDataInterface sdi ) { meta = (SalesforceDeleteMeta) smi; data = (SalesforceDeleteData) sdi; if ( super.init( smi, sdi ) ) { try { // set timeout data.connection.setTimeOut( Const.toInt( environmentSubstitute( meta.getTimeout() ), 0 ) ); // Do we use compression? data.connection.setUsingCompression( meta.isCompression() ); // Do we rollback all changes on error data.connection.setRollbackAllChangesOnError( meta.isRollbackAllChangesOnError() ); // Now connect ... data.connection.connect(); return true; } catch ( KettleException ke ) { logError( BaseMessages.getString( PKG, "SalesforceDelete.Log.ErrorOccurredDuringStepInitialize" ) + ke.getMessage() ); return false; } } return false; } @Override public void dispose( StepMetaInterface smi, StepDataInterface sdi ) { if ( data.outputBuffer != null ) { data.outputBuffer = null; } if ( data.deleteId != null ) { data.deleteId = null; } super.dispose( smi, sdi ); } }