/**
   * @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;
  }