public final void addJob(
        String jobName, String groupName, StorageType storageType, org.quartz.Trigger trigger) {

      JobKey jobKey = new JobKey(jobName, groupName);

      JobBuilder jobBuilder = JobBuilder.newJob(MessageSenderJob.class);

      jobBuilder = jobBuilder.withIdentity(jobKey);

      JobDetail jobDetail = jobBuilder.build();

      JobDataMap jobDataMap = jobDetail.getJobDataMap();

      jobDataMap.put(SchedulerEngine.MESSAGE, _jsonFactory.serialize(new Message()));
      jobDataMap.put(SchedulerEngine.DESTINATION_NAME, _TEST_DESTINATION_NAME);
      jobDataMap.put(SchedulerEngine.STORAGE_TYPE, storageType.toString());

      JobState jobState = new JobState(TriggerState.NORMAL);

      jobState.addException(new Exception(), new Date());

      jobDataMap.put(SchedulerEngine.JOB_STATE, JobStateSerializeUtil.serialize(jobState));

      _jobs.put(jobKey, new Tuple(jobDetail, trigger, TriggerState.NORMAL));
    }
  protected void updateJobState(
      Scheduler scheduler, JobKey jobKey, TriggerState triggerState, boolean suppressError)
      throws Exception {

    JobDetail jobDetail = scheduler.getJobDetail(jobKey);

    if (jobDetail == null) {
      return;
    }

    JobDataMap jobDataMap = jobDetail.getJobDataMap();

    JobState jobState = getJobState(jobDataMap);

    if (triggerState != null) {
      jobState.setTriggerState(triggerState);
    }

    if (suppressError) {
      jobState.clearExceptions();
    }

    jobDataMap.put(SchedulerEngine.JOB_STATE, JobStateSerializeUtil.serialize(jobState));

    scheduler.addJob(jobDetail, true);
  }
  protected void schedule(
      Scheduler scheduler,
      StorageType storageType,
      Trigger trigger,
      String description,
      String destinationName,
      Message message)
      throws Exception {

    if (_jsonFactory == null) {
      throw new IllegalStateException("JSON factory not initialized");
    }

    try {
      JobBuilder jobBuilder = JobBuilder.newJob(MessageSenderJob.class);

      jobBuilder.withIdentity(trigger.getJobKey());

      jobBuilder.storeDurably();

      JobDetail jobDetail = jobBuilder.build();

      JobDataMap jobDataMap = jobDetail.getJobDataMap();

      jobDataMap.put(SchedulerEngine.DESCRIPTION, description);
      jobDataMap.put(SchedulerEngine.DESTINATION_NAME, destinationName);
      jobDataMap.put(SchedulerEngine.MESSAGE, _jsonFactory.serialize(message));
      jobDataMap.put(SchedulerEngine.STORAGE_TYPE, storageType.toString());

      JobState jobState =
          new JobState(
              TriggerState.NORMAL, message.getInteger(SchedulerEngine.EXCEPTIONS_MAX_SIZE));

      jobDataMap.put(SchedulerEngine.JOB_STATE, JobStateSerializeUtil.serialize(jobState));

      unregisterMessageListener(scheduler, trigger.getJobKey());

      synchronized (this) {
        scheduler.deleteJob(trigger.getJobKey());
        scheduler.scheduleJob(jobDetail, trigger);
      }
    } catch (ObjectAlreadyExistsException oaee) {
      if (_log.isInfoEnabled()) {
        _log.info("Message is already scheduled");
      }
    }
  }
  protected void unschedule(Scheduler scheduler, JobKey jobKey) throws Exception {

    JobDetail jobDetail = scheduler.getJobDetail(jobKey);

    TriggerKey triggerKey = new TriggerKey(jobKey.getName(), jobKey.getGroup());

    if (jobDetail == null) {
      return;
    }

    unregisterMessageListener(scheduler, jobKey);

    JobDataMap jobDataMap = jobDetail.getJobDataMap();

    JobState jobState = getJobState(jobDataMap);

    Trigger trigger = scheduler.getTrigger(triggerKey);

    if (trigger == null) {
      return;
    }

    jobState.setTriggerDate(SchedulerEngine.END_TIME, new Date());
    jobState.setTriggerDate(SchedulerEngine.FINAL_FIRE_TIME, trigger.getPreviousFireTime());
    jobState.setTriggerDate(SchedulerEngine.NEXT_FIRE_TIME, null);
    jobState.setTriggerDate(SchedulerEngine.PREVIOUS_FIRE_TIME, trigger.getPreviousFireTime());
    jobState.setTriggerDate(SchedulerEngine.START_TIME, trigger.getStartTime());

    jobState.setTriggerState(TriggerState.UNSCHEDULED);

    jobState.clearExceptions();

    jobDataMap.put(SchedulerEngine.JOB_STATE, JobStateSerializeUtil.serialize(jobState));

    scheduler.unscheduleJob(triggerKey);

    scheduler.addJob(jobDetail, true);
  }
  protected JobState getJobState(JobDataMap jobDataMap) {
    Map<String, Object> jobStateMap =
        (Map<String, Object>) jobDataMap.get(SchedulerEngine.JOB_STATE);

    return JobStateSerializeUtil.deserialize(jobStateMap);
  }