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);

      // Check deleteKeyField
      String realFieldName = environmentSubstitute(meta.getDeleteField());
      if (Const.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;
  }