public boolean init(StepMetaInterface smi, StepDataInterface sdi) {
    meta = (RandomValueMeta) smi;
    data = (RandomValueData) sdi;

    if (super.init(smi, sdi)) {
      data.readsRows = getStepMeta().getRemoteInputSteps().size() > 0;
      List<StepMeta> previous = getTransMeta().findPreviousSteps(getStepMeta());
      if (previous != null && previous.size() > 0) {
        data.readsRows = true;
      }
      boolean genHmacMD5 = false;
      boolean genHmacSHA1 = false;
      boolean uuid4 = false;

      for (int i = 0; i < meta.getFieldName().length; i++) {
        switch (meta.getFieldType()[i]) {
          case RandomValueMeta.TYPE_RANDOM_MAC_HMACMD5:
            genHmacMD5 = true;
            break;
          case RandomValueMeta.TYPE_RANDOM_MAC_HMACSHA1:
            genHmacSHA1 = true;
            break;
          case RandomValueMeta.TYPE_RANDOM_UUID4:
            uuid4 = true;
            break;
          default:
            break;
        }
      }
      if (genHmacMD5) {
        try {
          data.keyGenHmacMD5 = KeyGenerator.getInstance("HmacMD5");
        } catch (NoSuchAlgorithmException s) {
          logError(
              BaseMessages.getString(
                  PKG, "RandomValue.Log.HmacMD5AlgorithmException", s.getMessage()));
          return false;
        }
      }
      if (genHmacSHA1) {
        try {
          data.keyGenHmacSHA1 = KeyGenerator.getInstance("HmacSHA1");
        } catch (NoSuchAlgorithmException s) {
          logError(
              BaseMessages.getString(
                  PKG, "RandomValue.Log.HmacSHA1AlgorithmException", s.getMessage()));
          return false;
        }
      }
      if (uuid4) {
        data.u4 = new UUID4Util();
      }
      return true;
    }
    return false;
  }
  private Object[] getRandomValue(RowMetaInterface inputRowMeta, Object[] inputRowData) {
    Object[] row = new Object[data.outputRowMeta.size()];
    for (int i = 0; i < inputRowMeta.size(); i++) {
      row[i] = inputRowData[i]; // no data is changed, clone is not
      // needed here.
    }

    for (int i = 0, index = inputRowMeta.size(); i < meta.getFieldName().length; i++, index++) {
      switch (meta.getFieldType()[i]) {
        case RandomValueMeta.TYPE_RANDOM_NUMBER:
          row[index] = data.randomgen.nextDouble();
          break;
        case RandomValueMeta.TYPE_RANDOM_INTEGER:
          row[index] =
              new Long(data.randomgen.nextInt()); // nextInt() already returns all 2^32 numbers.
          break;
        case RandomValueMeta.TYPE_RANDOM_STRING:
          row[index] = Long.toString(Math.abs(data.randomgen.nextLong()), 32);
          break;
        case RandomValueMeta.TYPE_RANDOM_UUID:
          row[index] = UUIDUtil.getUUIDAsString();
          break;
        case RandomValueMeta.TYPE_RANDOM_UUID4:
          row[index] = data.u4.getUUID4AsString();
          break;
        case RandomValueMeta.TYPE_RANDOM_MAC_HMACMD5:
          try {
            row[index] = generateRandomMACHash(RandomValueMeta.TYPE_RANDOM_MAC_HMACMD5);
          } catch (Exception e) {
            logError(
                BaseMessages.getString(
                    PKG, "RandomValue.Log.ErrorGettingRandomHMACMD5", e.getMessage()));
            setErrors(1);
            stopAll();
          }
          break;
        case RandomValueMeta.TYPE_RANDOM_MAC_HMACSHA1:
          try {
            row[index] = generateRandomMACHash(RandomValueMeta.TYPE_RANDOM_MAC_HMACSHA1);
          } catch (Exception e) {
            logError(
                BaseMessages.getString(
                    PKG, "RandomValue.Log.ErrorGettingRandomHMACSHA1", e.getMessage()));
            setErrors(1);
            stopAll();
          }
          break;
        default:
          break;
      }
    }

    return row;
  }
  public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException {
    Object[] row;
    if (data.readsRows) {
      row = getRow();
      if (row == null) {
        setOutputDone();
        return false;
      }

      if (first) {
        first = false;
        data.outputRowMeta = getInputRowMeta().clone();
        meta.getFields(data.outputRowMeta, getStepname(), null, null, this, repository, metaStore);
      }
    } else {
      row = new Object[] {}; // empty row
      incrementLinesRead();

      if (first) {
        first = false;
        data.outputRowMeta = new RowMeta();
        meta.getFields(data.outputRowMeta, getStepname(), null, null, this, repository, metaStore);
      }
    }

    RowMetaInterface imeta = getInputRowMeta();
    if (imeta == null) {
      imeta = new RowMeta();
      this.setInputRowMeta(imeta);
    }

    row = getRandomValue(imeta, row);

    if (log.isRowLevel()) {
      logRowlevel(
          BaseMessages.getString(
              PKG, "RandomValue.Log.ValueReturned", data.outputRowMeta.getString(row)));
    }

    putRow(data.outputRowMeta, row);

    if (!data.readsRows) { // Just one row and then stop!

      setOutputDone();
      return false;
    }

    return true;
  }