@Override
  public void registerJob(final Report report, final Date startAt)
      throws SchedulerException, ParseException {
    ReportJob job = createSpringBean(ReportJob.class);
    job.setReportKey(report.getKey());

    Map<String, Object> jobMap = new HashMap<>();
    jobMap.put(JobInstanceLoader.DOMAIN, AuthContextUtils.getDomain());

    registerJob(JobNamer.getJobName(report), job, report.getCronExpression(), startAt, jobMap);
  }
  @Override
  public Map<String, Object> registerJob(
      final SchedTask task, final Date startAt, final long interruptMaxRetries)
      throws SchedulerException, ParseException {

    TaskJob job = createSpringBean(TaskJob.class);
    job.setTaskKey(task.getKey());

    String jobDelegateClassName =
        task instanceof SyncTask
            ? SyncJobDelegate.class.getName()
            : task instanceof PushTask
                ? PushJobDelegate.class.getName()
                : task.getJobDelegateClassName();

    Map<String, Object> jobMap = new HashMap<>();
    jobMap.put(JobInstanceLoader.DOMAIN, AuthContextUtils.getDomain());
    jobMap.put(TaskJob.DELEGATE_CLASS_KEY, jobDelegateClassName);
    jobMap.put(TaskJob.INTERRUPT_MAX_RETRIES_KEY, interruptMaxRetries);

    registerJob(JobNamer.getJobName(task), job, task.getCronExpression(), startAt, jobMap);
    return jobMap;
  }
  private void registerJob(
      final String jobName,
      final Job jobInstance,
      final String cronExpression,
      final Date startAt,
      final Map<String, Object> jobMap)
      throws SchedulerException, ParseException {

    synchronized (scheduler.getScheduler()) {
      boolean jobAlreadyRunning = false;
      for (JobExecutionContext jobCtx : scheduler.getScheduler().getCurrentlyExecutingJobs()) {
        if (jobName.equals(jobCtx.getJobDetail().getKey().getName())
            && Scheduler.DEFAULT_GROUP.equals(jobCtx.getJobDetail().getKey().getGroup())) {

          jobAlreadyRunning = true;

          LOG.debug("Job {} already running, cancel", jobCtx.getJobDetail().getKey());
        }
      }

      if (jobAlreadyRunning) {
        return;
      }
    }

    // 0. unregister job
    unregisterJob(jobName);

    // 1. Job bean
    ApplicationContextProvider.getBeanFactory().registerSingleton(jobName, jobInstance);

    // 2. JobDetail bean
    JobBuilder jobDetailBuilder =
        JobBuilder.newJob(jobInstance.getClass())
            .withIdentity(jobName)
            .usingJobData(new JobDataMap(jobMap));

    // 3. Trigger
    if (cronExpression == null && startAt == null) {
      // Jobs added with no trigger must be durable
      scheduler.getScheduler().addJob(jobDetailBuilder.storeDurably().build(), true);
    } else {
      TriggerBuilder<?> triggerBuilder;

      if (cronExpression == null) {
        triggerBuilder =
            TriggerBuilder.newTrigger()
                .withIdentity(JobNamer.getTriggerName(jobName))
                .startAt(startAt);
      } else {
        triggerBuilder =
            TriggerBuilder.newTrigger()
                .withIdentity(JobNamer.getTriggerName(jobName))
                .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression));

        if (startAt == null) {
          triggerBuilder = triggerBuilder.startNow();
        } else {
          triggerBuilder = triggerBuilder.startAt(startAt);
        }
      }

      scheduler.getScheduler().scheduleJob(jobDetailBuilder.build(), triggerBuilder.build());
    }
  }
 @Override
 public void unregisterJob(final Report report) {
   unregisterJob(JobNamer.getJobName(report));
 }
 @Override
 public void unregisterJob(final Task task) {
   unregisterJob(JobNamer.getJobName(task));
 }