private boolean validateImportJob(final ImportNotification notification) {
    importJobStatusHandler.reportImportJobState(
        notification.getProcessId(), ImportJobState.VALIDATING);

    List<ImportBadRow> importBadRows = Collections.emptyList();
    try {
      importBadRows = processValidation(notification);
    } catch (Exception exc) {
      LOG.error("Validation failed.", exc);
      importJobStatusHandler.reportImportJobState(
          notification.getProcessId(), ImportJobState.VALIDATION_FAILED);
      return false;
    }

    if (CollectionUtils.isNotEmpty(importBadRows)) {
      importJobStatusHandler.reportBadRows(
          notification.getProcessId(),
          importBadRows.toArray(new ImportBadRow[importBadRows.size()]));
      importJobStatusHandler.reportImportJobState(
          notification.getProcessId(), ImportJobState.VALIDATION_FAILED);
      return false;
    }

    importJobStatusHandler.reportImportJobState(
        notification.getProcessId(), ImportJobState.QUEUED_FOR_IMPORT);
    return true;
  }
 /**
  * Sets the notification in processed state.
  *
  * @param notification the notification
  */
 protected void unlock(final ImportNotification notification) {
   notification.setState(ImportNotificationState.PROCESSED);
   importNotificationDao.update(notification);
   if (LOG.isDebugEnabled()) {
     LOG.debug(
         "Import notification has been processed. Process ID: " + notification.getProcessId());
   }
 }
  /**
   * 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);
    }
  }
  /**
   * Executes an import by getting the parameters from the notification.
   *
   * @param notification the notification
   * @return the status of the import
   */
  protected ImportJobStatus executeImport(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());

    updateTotalRowsNumber(importJobRunner.getTotalRows(), notification.getProcessId());

    importJobStatusHandler.reportImportJobState(
        notification.getProcessId(), ImportJobState.RUNNING);
    // Start the runner.
    LOG.info("Launch import job runner: " + importJobRunner);
    importJobRunner.run();

    return importJobStatusHandler.getImportJobStatus(notification.getProcessId());
  }
 /**
  * Tries to lock the notification by setting it into in_process state.
  *
  * @param notification the notification to lock
  * @return true if the lock has been gained successfully
  */
 protected boolean lock(final ImportNotification notification) {
   if (ObjectUtils.equals(ImportNotificationState.IN_PROCESS, notification.getState())) {
     return false;
   }
   // set in process on notification so that no other parties should take it over
   notification.setState(ImportNotificationState.IN_PROCESS);
   try {
     // update the notification which makes sure that no other participants will take it for
     // processing
     // could throw OptimisticLockException wrapped in EpPersistenceException when some other party
     // has updated the same object which means that it was already locked
     importNotificationDao.update(notification);
   } catch (EpPersistenceException exc) {
     LOG.debug("Cannot gain lock over notification: " + notification, exc);
     return false;
   }
   return true;
 }
  /**
   * 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());
  }