// Save the attributes of this job entry
  //
  public void saveRep(Repository rep, IMetaStore metaStore, ObjectId id_job)
      throws KettleException {
    try {
      rep.saveJobEntryAttribute(id_job, getObjectId(), "file_name", filename);
      rep.saveJobEntryAttribute(id_job, getObjectId(), "work_directory", workDirectory);
      rep.saveJobEntryAttribute(id_job, getObjectId(), "arg_from_previous", argFromPrevious);
      rep.saveJobEntryAttribute(id_job, getObjectId(), "exec_per_row", execPerRow);
      rep.saveJobEntryAttribute(id_job, getObjectId(), "set_logfile", setLogfile);
      rep.saveJobEntryAttribute(id_job, getObjectId(), "set_append_logfile", setAppendLogfile);
      rep.saveJobEntryAttribute(id_job, getObjectId(), "add_date", addDate);
      rep.saveJobEntryAttribute(id_job, getObjectId(), "add_time", addTime);
      rep.saveJobEntryAttribute(id_job, getObjectId(), "logfile", logfile);
      rep.saveJobEntryAttribute(id_job, getObjectId(), "logext", logext);
      rep.saveJobEntryAttribute(
          id_job,
          getObjectId(),
          "loglevel",
          logFileLevel == null ? LogLevel.NOTHING.getCode() : logFileLevel.getCode());
      rep.saveJobEntryAttribute(id_job, getObjectId(), "insertScript", insertScript);
      rep.saveJobEntryAttribute(id_job, getObjectId(), "script", script);

      // save the arguments...
      if (arguments != null) {
        for (int i = 0; i < arguments.length; i++) {
          rep.saveJobEntryAttribute(id_job, getObjectId(), i, "argument", arguments[i]);
        }
      }
    } catch (KettleDatabaseException dbe) {
      throw new KettleException("Unable to save job entry of type 'shell' to the repository", dbe);
    }
  }
  public String getXML() {
    StringBuffer retval = new StringBuffer(300);

    retval.append(super.getXML());

    retval.append("      ").append(XMLHandler.addTagValue("filename", filename));
    retval.append("      ").append(XMLHandler.addTagValue("work_directory", workDirectory));
    retval.append("      ").append(XMLHandler.addTagValue("arg_from_previous", argFromPrevious));
    retval.append("      ").append(XMLHandler.addTagValue("exec_per_row", execPerRow));
    retval.append("      ").append(XMLHandler.addTagValue("set_logfile", setLogfile));
    retval.append("      ").append(XMLHandler.addTagValue("logfile", logfile));
    retval.append("      ").append(XMLHandler.addTagValue("set_append_logfile", setAppendLogfile));
    retval.append("      ").append(XMLHandler.addTagValue("logext", logext));
    retval.append("      ").append(XMLHandler.addTagValue("add_date", addDate));
    retval.append("      ").append(XMLHandler.addTagValue("add_time", addTime));
    retval.append("      ").append(XMLHandler.addTagValue("insertScript", insertScript));
    retval.append("      ").append(XMLHandler.addTagValue("script", script));

    retval
        .append("      ")
        .append(
            XMLHandler.addTagValue(
                "loglevel", (logFileLevel == null) ? null : logFileLevel.getCode()));

    if (arguments != null) {
      for (int i = 0; i < arguments.length; i++) {
        // THIS IS A VERY BAD WAY OF READING/SAVING AS IT MAKES
        // THE XML "DUBIOUS". DON'T REUSE IT. (Sven B)
        retval.append("      ").append(XMLHandler.addTagValue("argument" + i, arguments[i]));
      }
    }

    return retval.toString();
  }
  public void getInfo() {
    try {
      configuration.setExecutingLocally(wExecLocal.getSelection());
      configuration.setExecutingRemotely(wExecRemote.getSelection());

      // Remote data
      //
      if (wExecRemote.getSelection()) {
        String serverName = wRemoteHost.getText();
        configuration.setRemoteServer(abstractMeta.findSlaveServer(serverName));
      }
      configuration.setPassingExport(wPassExport.getSelection());
      getConfiguration().setExpandingRemoteJob(wExpandRemote.getSelection());

      // various settings
      //
      configuration.setReplayDate(null);
      configuration.setSafeModeEnabled(wSafeMode.getSelection());
      configuration.setClearingLog(wClearLog.getSelection());
      configuration.setLogLevel(LogLevel.values()[wLogLevel.getSelectionIndex()]);

      String startCopyName = null;
      int startCopyNr = 0;
      if (!Const.isEmpty(wStartCopy.getText())) {
        if (wStartCopy.getSelectionIndex() >= 0) {
          JobEntryCopy copy =
              ((JobMeta) abstractMeta).getJobCopies().get(wStartCopy.getSelectionIndex());
          startCopyName = copy.getName();
          startCopyNr = copy.getNr();
        }
      }
      getConfiguration().setStartCopyName(startCopyName);
      getConfiguration().setStartCopyNr(startCopyNr);

      // The lower part of the dialog...
      getInfoParameters();
      getInfoVariables();

      // Metrics
      configuration.setGatheringMetrics(wGatherMetrics.getSelection());
    } catch (Exception e) {
      new ErrorDialog(shell, "Error in settings", "There is an error in the dialog settings", e);
    }
  }
  public void loadXML(
      Node entrynode,
      List<DatabaseMeta> databases,
      List<SlaveServer> slaveServers,
      Repository rep,
      IMetaStore metaStore)
      throws KettleXMLException {
    try {
      super.loadXML(entrynode, databases, slaveServers);
      setFileName(XMLHandler.getTagValue(entrynode, "filename"));
      setWorkDirectory(XMLHandler.getTagValue(entrynode, "work_directory"));
      argFromPrevious =
          "Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "arg_from_previous"));
      execPerRow = "Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "exec_per_row"));
      setLogfile = "Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "set_logfile"));
      setAppendLogfile =
          "Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "set_append_logfile"));
      addDate = "Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "add_date"));
      addTime = "Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "add_time"));
      logfile = XMLHandler.getTagValue(entrynode, "logfile");
      logext = XMLHandler.getTagValue(entrynode, "logext");
      logFileLevel = LogLevel.getLogLevelForCode(XMLHandler.getTagValue(entrynode, "loglevel"));
      insertScript = "Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "insertScript"));

      script = XMLHandler.getTagValue(entrynode, "script");

      // How many arguments?
      int argnr = 0;
      while (XMLHandler.getTagValue(entrynode, "argument" + argnr) != null) {
        argnr++;
      }
      arguments = new String[argnr];

      // Read them all...
      // THIS IS A VERY BAD WAY OF READING/SAVING AS IT MAKES
      // THE XML "DUBIOUS". DON'T REUSE IT.
      for (int a = 0; a < argnr; a++) {
        arguments[a] = XMLHandler.getTagValue(entrynode, "argument" + a);
      }
    } catch (KettleException e) {
      throw new KettleXMLException("Unable to load job entry of type 'shell' from XML node", e);
    }
  }
  // Load the jobentry from repository
  public void loadRep(
      Repository rep,
      IMetaStore metaStore,
      ObjectId id_jobentry,
      List<DatabaseMeta> databases,
      List<SlaveServer> slaveServers)
      throws KettleException {
    try {
      setFileName(rep.getJobEntryAttributeString(id_jobentry, "file_name"));
      setWorkDirectory(rep.getJobEntryAttributeString(id_jobentry, "work_directory"));
      argFromPrevious = rep.getJobEntryAttributeBoolean(id_jobentry, "arg_from_previous");
      execPerRow = rep.getJobEntryAttributeBoolean(id_jobentry, "exec_per_row");

      setLogfile = rep.getJobEntryAttributeBoolean(id_jobentry, "set_logfile");
      setAppendLogfile = rep.getJobEntryAttributeBoolean(id_jobentry, "set_append_logfile");
      addDate = rep.getJobEntryAttributeBoolean(id_jobentry, "add_date");
      addTime = rep.getJobEntryAttributeBoolean(id_jobentry, "add_time");
      logfile = rep.getJobEntryAttributeString(id_jobentry, "logfile");
      logext = rep.getJobEntryAttributeString(id_jobentry, "logext");
      logFileLevel =
          LogLevel.getLogLevelForCode(rep.getJobEntryAttributeString(id_jobentry, "loglevel"));
      insertScript = rep.getJobEntryAttributeBoolean(id_jobentry, "insertScript");

      script = rep.getJobEntryAttributeString(id_jobentry, "script");
      // How many arguments?
      int argnr = rep.countNrJobEntryAttributes(id_jobentry, "argument");
      arguments = new String[argnr];

      // Read them all...
      for (int a = 0; a < argnr; a++) {
        arguments[a] = rep.getJobEntryAttributeString(id_jobentry, a, "argument");
      }
    } catch (KettleDatabaseException dbe) {
      throw new KettleException(
          "Unable to load job entry of type 'shell' from the repository with id_jobentry="
              + id_jobentry,
          dbe);
    }
  }
  private void getInfo(JobEntryTrans jet) throws KettleException {
    jet.setName(wName.getText());
    if (rep != null) {
      specificationMethod = ObjectLocationSpecificationMethod.REPOSITORY_BY_NAME;
    } else {
      specificationMethod = ObjectLocationSpecificationMethod.FILENAME;
    }
    jet.setSpecificationMethod(specificationMethod);
    switch (specificationMethod) {
      case FILENAME:
        jet.setFileName(wPath.getText());
        if (jet.getFilename().isEmpty()) {
          throw new KettleException(
              BaseMessages.getString(PKG, "JobTrans.Dialog.Exception.NoValidMappingDetailsFound"));
        }

        jet.setDirectory(null);
        jet.setTransname(null);
        jet.setTransObjectId(null);
        break;
      case REPOSITORY_BY_NAME:
        String transPath = wPath.getText();
        String transName = transPath;
        String directory = "";
        int index = transPath.lastIndexOf("/");
        if (index != -1) {
          transName = transPath.substring(index + 1);
          directory = transPath.substring(0, index);
        }
        jet.setDirectory(directory);
        if (jet.getDirectory().isEmpty()) {
          throw new KettleException(
              BaseMessages.getString(
                  PKG, "JobTrans.Dialog.Exception.UnableToFindRepositoryDirectory"));
        }

        jet.setTransname(transName);
        jet.setFileName(null);
        jet.setTransObjectId(null);
        break;
      default:
        break;
    }

    int nritems = wFields.nrNonEmpty();
    int nr = 0;
    for (int i = 0; i < nritems; i++) {
      String arg = wFields.getNonEmpty(i).getText(1);
      if (arg != null && arg.length() != 0) {
        nr++;
      }
    }
    jet.arguments = new String[nr];
    nr = 0;
    for (int i = 0; i < nritems; i++) {
      String arg = wFields.getNonEmpty(i).getText(1);
      if (arg != null && arg.length() != 0) {
        jet.arguments[nr] = arg;
        nr++;
      }
    }

    // Do the parameters
    nritems = wParameters.nrNonEmpty();
    nr = 0;
    for (int i = 0; i < nritems; i++) {
      String param = wParameters.getNonEmpty(i).getText(1);
      if (param != null && param.length() != 0) {
        nr++;
      }
    }
    jet.parameters = new String[nr];
    jet.parameterFieldNames = new String[nr];
    jet.parameterValues = new String[nr];
    nr = 0;
    for (int i = 0; i < nritems; i++) {
      String param = wParameters.getNonEmpty(i).getText(1);
      String fieldName = wParameters.getNonEmpty(i).getText(2);
      String value = wParameters.getNonEmpty(i).getText(3);

      jet.parameters[nr] = param;

      if (!Utils.isEmpty(Const.trim(fieldName))) {
        jet.parameterFieldNames[nr] = fieldName;
      } else {
        jet.parameterFieldNames[nr] = "";
      }

      if (!Utils.isEmpty(Const.trim(value))) {
        jet.parameterValues[nr] = value;
      } else {
        jet.parameterValues[nr] = "";
      }

      nr++;
    }

    jet.setPassingAllParameters(wPassParams.getSelection());

    jet.logfile = wLogfile.getText();
    jet.logext = wLogext.getText();

    if (wLoglevel.getSelectionIndex() >= 0) {
      jet.logFileLevel = LogLevel.values()[wLoglevel.getSelectionIndex()];
    } else {
      jet.logFileLevel = LogLevel.BASIC;
    }

    jet.argFromPrevious = wPrevious.getSelection();
    jet.paramsFromPrevious = wPrevToParams.getSelection();
    jet.execPerRow = wEveryRow.getSelection();
    jet.setLogfile = wSetLogfile.getSelection();
    jet.addDate = wAddDate.getSelection();
    jet.addTime = wAddTime.getSelection();
    jet.clearResultRows = wClearRows.getSelection();
    jet.clearResultFiles = wClearFiles.getSelection();
    jet.setClustering(wCluster.getSelection());
    jet.setLoggingRemoteWork(wLogRemoteWork.getSelection());
    jet.createParentFolder = wCreateParentFolder.getSelection();

    jet.setRemoteSlaveServerName(wSlaveServer.getText());
    jet.setAppendLogfile = wAppendLogfile.getSelection();
    jet.setWaitingToFinish(wWaitingToFinish.getSelection());
    jet.setFollowingAbortRemotely(wFollowingAbortRemotely.getSelection());
  }
  protected void optionsSectionControls() {

    wSafeMode = new Button(gDetails, SWT.CHECK);
    wSafeMode.setText(
        BaseMessages.getString(PKG, "JobExecutionConfigurationDialog.SafeMode.Label"));
    wSafeMode.setToolTipText(
        BaseMessages.getString(PKG, "JobExecutionConfigurationDialog.SafeMode.Tooltip"));
    props.setLook(wSafeMode);
    FormData fdSafeMode = new FormData();
    fdSafeMode.right = new FormAttachment(0, 186);
    fdSafeMode.top = new FormAttachment(0, 30);
    fdSafeMode.left = new FormAttachment(0, 10);
    wSafeMode.setLayoutData(fdSafeMode);

    wGatherMetrics = new Button(gDetails, SWT.CHECK);
    wGatherMetrics.setText(
        BaseMessages.getString(PKG, "JobExecutionConfigurationDialog.GatherMetrics.Label"));
    wGatherMetrics.setToolTipText(
        BaseMessages.getString(PKG, "JobExecutionConfigurationDialog.GatherMetrics.Tooltip"));
    props.setLook(wGatherMetrics);
    FormData fdGatherMetrics = new FormData();
    fdGatherMetrics.right = new FormAttachment(0, 230);
    fdGatherMetrics.top = new FormAttachment(0, 55);
    fdGatherMetrics.left = new FormAttachment(0, 10);
    wGatherMetrics.setLayoutData(fdGatherMetrics);

    wClearLog = new Button(gDetails, SWT.CHECK);
    wClearLog.setText(
        BaseMessages.getString(PKG, "JobExecutionConfigurationDialog.ClearLog.Label"));
    wClearLog.setToolTipText(
        BaseMessages.getString(PKG, "JobExecutionConfigurationDialog.ClearLog.Tooltip"));
    props.setLook(wClearLog);
    FormData fdClearLog = new FormData();
    fdClearLog.right = new FormAttachment(0, 200);
    fdClearLog.top = new FormAttachment(0, 5);
    fdClearLog.left = new FormAttachment(0, 10);
    wClearLog.setLayoutData(fdClearLog);

    wlLogLevel = new Label(gDetails, SWT.RIGHT);
    props.setLook(wlLogLevel);
    wlLogLevel.setText(
        BaseMessages.getString(PKG, "JobExecutionConfigurationDialog.LogLevel.Label"));
    wlLogLevel.setToolTipText(
        BaseMessages.getString(PKG, "JobExecutionConfigurationDialog.LogLevel.Tooltip"));
    FormData fdlLogLevel = new FormData();
    fdlLogLevel.right = new FormAttachment(0, 333);
    fdlLogLevel.top = new FormAttachment(0, 7);
    fdlLogLevel.left = new FormAttachment(0, 260);
    wlLogLevel.setLayoutData(fdlLogLevel);

    wLogLevel = new CCombo(gDetails, SWT.READ_ONLY | SWT.BORDER);
    wLogLevel.setToolTipText(
        BaseMessages.getString(PKG, "JobExecutionConfigurationDialog.LogLevel.Tooltip"));
    props.setLook(wLogLevel);
    FormData fdLogLevel = new FormData();
    fdLogLevel.left = new FormAttachment(wlLogLevel, 6);
    fdLogLevel.width = 200;
    if (Const.isOSX()) {
      fdLogLevel.top = new FormAttachment(wClearLog, 2, SWT.TOP);
    } else {
      fdLogLevel.top = new FormAttachment(wClearLog, -2, SWT.TOP);
    }
    fdLogLevel.right = new FormAttachment(0, 500);
    wLogLevel.setLayoutData(fdLogLevel);
    wLogLevel.setItems(LogLevel.getLogLevelDescriptions());

    wStartCopy = new CCombo(gDetails, SWT.READ_ONLY | SWT.BORDER);
    props.setLook(wStartCopy);
    wStartCopy.setToolTipText(
        BaseMessages.getString(PKG, "JobExecutionConfigurationDialog.StartCopy.Tooltip"));
    FormData fd_startJobCombo = new FormData();
    fd_startJobCombo.right = new FormAttachment(wLogLevel, 0, SWT.RIGHT);
    if (Const.isOSX()) {
      fd_startJobCombo.top = new FormAttachment(wLogLevel, 8);
    } else {
      fd_startJobCombo.top = new FormAttachment(wLogLevel, 10);
    }
    wStartCopy.setLayoutData(fd_startJobCombo);

    JobMeta jobMeta = (JobMeta) super.abstractMeta;

    String[] names = new String[jobMeta.getJobCopies().size()];
    for (int i = 0; i < names.length; i++) {
      JobEntryCopy copy = jobMeta.getJobCopies().get(i);
      names[i] = getJobEntryCopyName(copy);
    }
    wStartCopy.setItems(names);

    Label lblStartJob = new Label(gDetails, SWT.NONE);
    props.setLook(lblStartJob);
    fd_startJobCombo.left = new FormAttachment(lblStartJob, 6);
    FormData fd_lblStartJob = new FormData();
    if (Const.isOSX()) {
      fd_lblStartJob.top = new FormAttachment(wlLogLevel, 8);
    } else {
      fd_lblStartJob.top = new FormAttachment(wlLogLevel, 18);
    }
    fd_lblStartJob.right = new FormAttachment(wlLogLevel, 0, SWT.RIGHT);
    lblStartJob.setLayoutData(fd_lblStartJob);
    lblStartJob.setText(
        BaseMessages.getString(PKG, "JobExecutionConfigurationDialog.StartCopy.Label"));
    lblStartJob.setToolTipText(
        BaseMessages.getString(PKG, "JobExecutionConfigurationDialog.StartCopy.Tooltip"));
  }
  public JobExecutionConfiguration(Node trecNode) throws KettleException {
    this();

    executingLocally = "Y".equalsIgnoreCase(XMLHandler.getTagValue(trecNode, "exec_local"));

    executingRemotely = "Y".equalsIgnoreCase(XMLHandler.getTagValue(trecNode, "exec_remote"));
    Node remoteHostNode = XMLHandler.getSubNode(trecNode, SlaveServer.XML_TAG);
    if (remoteHostNode != null) {
      remoteServer = new SlaveServer(remoteHostNode);
    }
    passingExport = "Y".equalsIgnoreCase(XMLHandler.getTagValue(trecNode, "pass_export"));
    expandingRemoteJob =
        "Y".equalsIgnoreCase(XMLHandler.getTagValue(trecNode, "expand_remote_job"));

    // Read the variables...
    //
    Node varsNode = XMLHandler.getSubNode(trecNode, "variables");
    int nrVariables = XMLHandler.countNodes(varsNode, "variable");
    for (int i = 0; i < nrVariables; i++) {
      Node argNode = XMLHandler.getSubNodeByNr(varsNode, "variable", i);
      String name = XMLHandler.getTagValue(argNode, "name");
      String value = XMLHandler.getTagValue(argNode, "value");
      if (!Utils.isEmpty(name) && !Utils.isEmpty(value)) {
        variables.put(name, value);
      }
    }

    // Read the arguments...
    //
    Node argsNode = XMLHandler.getSubNode(trecNode, "arguments");
    int nrArguments = XMLHandler.countNodes(argsNode, "argument");
    for (int i = 0; i < nrArguments; i++) {
      Node argNode = XMLHandler.getSubNodeByNr(argsNode, "argument", i);
      String name = XMLHandler.getTagValue(argNode, "name");
      String value = XMLHandler.getTagValue(argNode, "value");
      if (!Utils.isEmpty(name) && !Utils.isEmpty(value)) {
        arguments.put(name, value);
      }
    }

    // Read the parameters...
    //
    Node parmsNode = XMLHandler.getSubNode(trecNode, "parameters");
    int nrParams = XMLHandler.countNodes(parmsNode, "parameter");
    for (int i = 0; i < nrParams; i++) {
      Node parmNode = XMLHandler.getSubNodeByNr(parmsNode, "parameter", i);
      String name = XMLHandler.getTagValue(parmNode, "name");
      String value = XMLHandler.getTagValue(parmNode, "value");
      if (!Utils.isEmpty(name)) {
        params.put(name, value);
      }
    }

    replayDate = XMLHandler.stringToDate(XMLHandler.getTagValue(trecNode, "replay_date"));
    safeModeEnabled = "Y".equalsIgnoreCase(XMLHandler.getTagValue(trecNode, "safe_mode"));
    logLevel = LogLevel.getLogLevelForCode(XMLHandler.getTagValue(trecNode, "log_level"));
    clearingLog = "Y".equalsIgnoreCase(XMLHandler.getTagValue(trecNode, "clear_log"));

    startCopyName = XMLHandler.getTagValue(trecNode, "start_copy_name");
    startCopyNr = Const.toInt(XMLHandler.getTagValue(trecNode, "start_copy_nr"), 0);

    gatheringMetrics = "Y".equalsIgnoreCase(XMLHandler.getTagValue(trecNode, "gather_metrics"));

    String sPassedBatchId = XMLHandler.getTagValue(trecNode, "passedBatchId");
    if (!StringUtils.isEmpty(sPassedBatchId)) {
      passedBatchId = Long.parseLong(sPassedBatchId);
    }

    Node resultNode = XMLHandler.getSubNode(trecNode, Result.XML_TAG);
    if (resultNode != null) {
      try {
        previousResult = new Result(resultNode);
      } catch (KettleException e) {
        throw new KettleException("Unable to hydrate previous result", e);
      }
    }

    // Try to get a handle to the repository from here...
    //
    Node repNode = XMLHandler.getSubNode(trecNode, "repository");
    if (repNode != null) {
      String repositoryName = XMLHandler.getTagValue(repNode, "name");
      String username = XMLHandler.getTagValue(repNode, "login");
      String password = Encr.decryptPassword(XMLHandler.getTagValue(repNode, "password"));
      connectRepository(repositoryName, username, password);
    }
  }
  public String getXML() throws IOException {
    StringBuilder xml = new StringBuilder(160);

    xml.append("  <" + XML_TAG + ">").append(Const.CR);

    xml.append("    ").append(XMLHandler.addTagValue("exec_local", executingLocally));

    xml.append("    ").append(XMLHandler.addTagValue("exec_remote", executingRemotely));
    if (remoteServer != null) {
      xml.append("    ").append(remoteServer.getXML()).append(Const.CR);
    }
    xml.append("    ").append(XMLHandler.addTagValue("pass_export", passingExport));

    // Serialize the parameters...
    //
    xml.append("    <parameters>").append(Const.CR);
    List<String> paramNames = new ArrayList<String>(params.keySet());
    Collections.sort(paramNames);
    for (String name : paramNames) {
      String value = params.get(name);
      xml.append("    <parameter>");
      xml.append(XMLHandler.addTagValue("name", name, false));
      xml.append(XMLHandler.addTagValue("value", value, false));
      xml.append("</parameter>").append(Const.CR);
    }
    xml.append("    </parameters>").append(Const.CR);

    // Serialize the variables...
    //
    xml.append("    <variables>").append(Const.CR);
    List<String> variableNames = new ArrayList<String>(variables.keySet());
    Collections.sort(variableNames);
    for (String name : variableNames) {
      String value = variables.get(name);
      xml.append("    <variable>");
      xml.append(XMLHandler.addTagValue("name", name, false));
      xml.append(XMLHandler.addTagValue("value", value, false));
      xml.append("</variable>").append(Const.CR);
    }
    xml.append("    </variables>").append(Const.CR);

    // Serialize the variables...
    //
    xml.append("    <arguments>").append(Const.CR);
    List<String> argumentNames = new ArrayList<String>(arguments.keySet());
    Collections.sort(argumentNames);
    for (String name : argumentNames) {
      String value = arguments.get(name);
      xml.append("    <argument>");
      xml.append(XMLHandler.addTagValue("name", name, false));
      xml.append(XMLHandler.addTagValue("value", value, false));
      xml.append("</argument>").append(Const.CR);
    }
    xml.append("    </arguments>").append(Const.CR);

    xml.append("    ").append(XMLHandler.addTagValue("replay_date", replayDate));
    xml.append("    ").append(XMLHandler.addTagValue("safe_mode", safeModeEnabled));
    xml.append("    ").append(XMLHandler.addTagValue("log_level", logLevel.getCode()));
    xml.append("    ").append(XMLHandler.addTagValue("clear_log", clearingLog));

    xml.append("    ").append(XMLHandler.addTagValue("start_copy_name", startCopyName));
    xml.append("    ").append(XMLHandler.addTagValue("start_copy_nr", startCopyNr));

    xml.append("    ").append(XMLHandler.addTagValue("gather_metrics", gatheringMetrics));
    xml.append("    ").append(XMLHandler.addTagValue("expand_remote_job", expandingRemoteJob));
    if (passedBatchId != null) {
      xml.append("    ").append(XMLHandler.addTagValue("passedBatchId", passedBatchId));
    }

    // The source rows...
    //
    if (previousResult != null) {
      xml.append(previousResult.getXML());
    }

    // Send the repository name and user to the remote site...
    //
    if (repository != null) {
      xml.append(XMLHandler.openTag("repository"));
      xml.append(XMLHandler.addTagValue("name", repository.getName()));
      // File base repositories doesn't have user info
      if (repository.getUserInfo() != null) {
        xml.append(XMLHandler.addTagValue("login", repository.getUserInfo().getLogin()));
        xml.append(
            XMLHandler.addTagValue(
                "password", Encr.encryptPassword(repository.getUserInfo().getPassword())));
      }
      xml.append(XMLHandler.closeTag("repository"));
    }

    xml.append("</" + XML_TAG + ">").append(Const.CR);
    return xml.toString();
  }