public void dispose(StepMetaInterface smi, StepDataInterface sdi) {
   if (data.outputBuffer != null) {
     data.outputBuffer = null;
   }
   if (data.sfBuffer != null) {
     data.sfBuffer = null;
   }
   super.dispose(smi, sdi);
 }
  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.sfBuffer = new SObject[meta.getBatchSizeInt()];
      data.outputBuffer = new Object[meta.getBatchSizeInt()][];

      // get total fields in the grid
      data.nrfields = meta.getUpdateLookup().length;

      // Check if field list is filled
      if (data.nrfields == 0) {
        throw new KettleException(
            BaseMessages.getString(PKG, "SalesforceUpdateDialog.FieldsMissing.DialogMessage"));
      }

      // Create the output row meta-data
      data.inputRowMeta = getInputRowMeta().clone();
      data.outputRowMeta = data.inputRowMeta.clone();
      meta.getFields(data.outputRowMeta, getStepname(), null, null, this, repository, metaStore);

      // Build the mapping of input position to field name
      data.fieldnrs = new int[meta.getUpdateStream().length];
      for (int i = 0; i < meta.getUpdateStream().length; i++) {
        data.fieldnrs[i] = getInputRowMeta().indexOfValue(meta.getUpdateStream()[i]);
        if (data.fieldnrs[i] < 0) {
          throw new KettleException(
              "Field [" + meta.getUpdateStream()[i] + "] couldn't be found in the input stream!");
        }
      }
    }

    try {
      writeToSalesForce(outputRowData);

    } catch (Exception e) {
      throw new KettleStepException(
          BaseMessages.getString(PKG, "SalesforceUpdate.log.Exception"), e);
    }
    return true;
  }
  private void flushBuffers() throws KettleException {

    try {
      // create the object(s) by sending the array to the web service
      data.saveResult = data.connection.update(data.sfBuffer);
      int nr = data.saveResult.length;
      for (int j = 0; j < nr; j++) {
        if (data.saveResult[j].isSuccess()) {
          // Row was updated
          String id = data.saveResult[j].getId();
          if (log.isDetailed()) {
            logDetailed("Row updated with id: " + id);
          }

          // write out the row with the SalesForce ID
          Object[] newRow =
              RowDataUtil.resizeArray(data.outputBuffer[j], data.outputRowMeta.size());

          if (log.isDetailed()) {
            logDetailed("The new row has an id value of : " + newRow[0]);
          }

          putRow(data.outputRowMeta, newRow); // copy row to output rowset(s);
          incrementLinesUpdated();

          if (checkFeedback(getLinesInput())) {
            if (log.isDetailed()) {
              logDetailed(
                  BaseMessages.getString(
                      PKG, "SalesforceUpdate.log.LineRow", "" + 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("Found error from SalesForce and raising the exception");
            }

            // Only send the first error
            //
            com.sforce.soap.partner.Error err = data.saveResult[j].getErrors()[0];
            throw new KettleException(
                BaseMessages.getString(
                    PKG,
                    "SalesforceUpdate.Error.FlushBuffer",
                    new Integer(j),
                    err.getStatusCode(),
                    err.getMessage()));
          }

          String errorMessage = "";
          for (int i = 0; i < data.saveResult[j].getErrors().length; i++) {
            // get the next error
            com.sforce.soap.partner.Error err = data.saveResult[j].getErrors()[i];
            errorMessage +=
                BaseMessages.getString(
                    PKG,
                    "SalesforceUpdate.Error.FlushBuffer",
                    new Integer(j),
                    err.getStatusCode(),
                    err.getMessage());
          }

          // Simply add this row to the error row
          if (log.isDebug()) {
            logDebug("Passing row to error step");
          }

          putError(
              getInputRowMeta(),
              data.outputBuffer[j],
              1,
              errorMessage,
              null,
              "SalesforceUpdate001");
        }
      }

      // reset the buffers
      data.sfBuffer = new SObject[meta.getBatchSizeInt()];
      data.outputBuffer = new Object[meta.getBatchSizeInt()][];
      data.iBufferPos = 0;

    } catch (Exception e) {
      if (!getStepMeta().isDoingErrorHandling()) {
        throw new KettleException(
            "\nFailed to update object, error message was: \n" + 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,
            "SalesforceUpdate002");
      }

    } finally {
      if (data.saveResult != null) {
        data.saveResult = null;
      }
    }
  }