/**
   * @param xmlSpecification
   * @param userGroup
   * @return
   */
  public ValidationReport Validate(String xmlSpecification, String userGroup) {
    final String methodName = "Validate";
    Logfile.WriteCalled(logLevel, STR_ClassName, methodName);

    ValidationReport validationReport = null;

    try {
      if (this.labExperimentEngines == null) {
        throw new NullPointerException(STRERR_LabExperimentEngines);
      }

      /*
       * Pass to the each experiment engine in turn to validate until validation is successful.
       * It may be possible that the LabEquipment for a particular LabExperimentEngine may be offline.
       */
      for (int i = 0; i < this.labExperimentEngines.length; i++) {
        LabExperimentEngine labExperimentEngine = this.labExperimentEngines[i];
        if (labExperimentEngine == null) {
          throw new NullPointerException(String.format(STRERR_LabExperimentEngineUnitId_arg, 0));
        }

        /*
         * Check if the LabExperimentEngine is online before trying to use it to validate
         */
        LabStatus labStatus = labExperimentEngine.GetLabStatus();
        if (labStatus.isOnline() == false) {
          continue;
        }

        /*
         * Validate the specification
         */
        validationReport = labExperimentEngine.Validate(xmlSpecification);
        if (validationReport.isAccepted() == true) {
          break;
        }
      }
    } catch (Exception ex) {
      Logfile.WriteError(ex.toString());
      validationReport = new ValidationReport(ex.toString());
    }

    Logfile.WriteCompleted(
        logLevel,
        STR_ClassName,
        methodName,
        String.format(
            STRLOG_Accepted_arg,
            (validationReport != null) ? validationReport.isAccepted() : false));

    return validationReport;
  }
  /**
   * @param experimentId
   * @param sbName
   * @param xmlSpecification
   * @param userGroup
   * @param priorityHint
   * @return
   */
  public synchronized SubmissionReport Submit(
      int experimentId,
      String sbName,
      String xmlSpecification,
      String userGroup,
      int priorityHint) {
    final String methodName = "Submit";
    Logfile.WriteCalled(
        logLevel,
        STR_ClassName,
        methodName,
        String.format(STRLOG_ExperimentIdSbName_arg2, experimentId, sbName));

    SubmissionReport submissionReport = new SubmissionReport(experimentId);

    /*
     * Validate the experiment specification before submitting
     */
    ValidationReport validationReport = this.Validate(xmlSpecification, userGroup);
    if (validationReport.isAccepted() == true) {
      /*
       * Specification is valid, create an instance of the experiment
       */
      LabExperimentInfo labExperimentInfo = new LabExperimentInfo(experimentId, sbName);
      labExperimentInfo.setXmlSpecification(xmlSpecification);
      labExperimentInfo.setUserGroup(userGroup);
      labExperimentInfo.setPriorityHint(priorityHint);
      labExperimentInfo.setEstimatedExecTime((int) validationReport.getEstRuntime());

      /*
       * Add the experiment to the queue
       */
      try {
        QueuedExperimentInfo queuedExperimentInfo =
            this.labManagement.getExperimentQueueDB().Enqueue(labExperimentInfo);
        if (queuedExperimentInfo == null) {
          throw new RuntimeException(STRERR_FailedToEnqueueExperiment);
        }

        /*
         * Update submission report current queue length and wait time
         */
        WaitEstimate waitEstimate = new WaitEstimate();
        waitEstimate.setEffectiveQueueLength(queuedExperimentInfo.getQueueLength());
        waitEstimate.setEstWait(queuedExperimentInfo.getWaitTime() + this.GetMinRemainingRuntime());
        submissionReport.setWaitEstimate(waitEstimate);

        /*
         * Update the statistics with revised wait estimate
         */
        queuedExperimentInfo.setWaitTime((int) waitEstimate.getEstWait());
        this.labManagement.getExperimentStatisticsDB().Submitted(queuedExperimentInfo);

        /*
         * Tell lab experiment manager thread that an experiment has been submitted
         */
        this.labManagement.getSignalSubmitted().Notify();
      } catch (Exception ex) {
        validationReport = new ValidationReport(ex.getMessage());
      }
    }

    submissionReport.setValidationReport(validationReport);

    Logfile.WriteCompleted(
        logLevel,
        STR_ClassName,
        methodName,
        String.format(STRLOG_Accepted_arg, submissionReport.getValidationReport().isAccepted()));

    return submissionReport;
  }