/**
   * Validates one import job in case there is a notification for that.
   *
   * <p>Note: Only one job at a time will be processed. It is not clear what the consequences will
   * be in a clustered environment running different import jobs. All submitted import jobs are
   * executed in sequence ordered by the date of submission.
   */
  public void launchImportJob() {
    final long startTime = System.currentTimeMillis();
    LOG.info("Start import job quartz job at: " + new Date(startTime));

    if (hasRunningImportJob()) {
      LOG.info("Import Job. Another processor is running at the moment. Quiting operation.");
      return;
    }
    List<ImportNotification> notifications =
        importNotificationDao.findByActionAndState(
            ImportAction.LAUNCH_IMPORT, ImportNotificationState.NEW, 1);

    if (CollectionUtils.isEmpty(notifications)) {
      LOG.info("Import Job. No notifications found. Quiting operation.");
      return;
    }

    // grab the first notification. there should be only one.
    ImportNotification notification = notifications.iterator().next();

    if (!lock(notification)) {
      LOG.info(
          "Import Job. Could not lock notification. Likely locked by another processor. "
              + notification);
      return;
    }

    try {
      if (isCancelled(notification.getProcessId())) {
        LOG.info("Import Job cancelled. Process ID: " + notification.getProcessId());
        return;
      }

      if (validateImportJob(notification)) {
        if (isCancelled(notification.getProcessId())) {
          LOG.info("Import Job cancelled. Process ID: " + notification.getProcessId());
          return;
        }
        ImportJobStatus importStatus = null;
        try {
          importStatus = executeImport(notification);
        } catch (Exception exc) {
          LOG.error("Import job failure.", exc);
          importJobStatusHandler.reportImportJobState(
              notification.getProcessId(), ImportJobState.FAILED);
          return;
        }
        sendEmail(importStatus, notification.getInitiator(), notification.getReportingLocale());
        LOG.info(
            "Import job quartz job completed in (ms): " + (System.currentTimeMillis() - startTime));
      }
    } finally {
      unlock(notification);
    }
  }
  /**
   * Process the validation by using the import job runner.
   *
   * @param notification the notification
   * @return a list of bad rows
   */
  protected List<ImportBadRow> processValidation(final ImportNotification notification) {
    ImportJob importJob = notification.getImportJob();

    // update the CSV file path with the local file path
    notification.setImportSource(getRemoteCsvFileName(notification.getImportSource()));

    // Validate again
    final ImportDataType importDataType =
        importService.findImportDataType(importJob.getImportDataTypeName());
    if (importDataType == null) {
      throw new EpSystemException(
          "ImportJob specifies unknown importDataType " + importJob.getImportDataTypeName());
    }

    ImportJobRunner importJobRunner =
        getImportJobRunner(importDataType.getImportJobRunnerBeanName());
    importJobRunner.init(notification, notification.getProcessId());

    return importJobRunner.validate(notification.getReportingLocale());
  }