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