/**
  * Loop over all currently started tasks and cycle them. This should be done after the classloader
  * has been changed (e.g. during module start/stop)
  */
 public void rescheduleAllTasks() throws SchedulerException {
   for (TaskDefinition task : getScheduledTasks()) {
     try {
       rescheduleTask(task);
     } catch (SchedulerException e) {
       log.error("Failed to restart task: " + task.getName(), e);
     }
   }
 }
  /**
   * Delete the task with the given identifier.
   *
   * @param id the identifier of the task
   */
  public void deleteTask(Integer id) {

    TaskDefinition task = getTask(id);
    if (task.getStarted()) {
      throw new APIException(
          "Started tasks should not be deleted. They should be stopped first, and then deleted.");
    }

    // delete the task
    getSchedulerDAO().deleteTask(id);
  }
 /**
  * Get all scheduled tasks.
  *
  * @return all scheduled tasks
  */
 public Collection<TaskDefinition> getScheduledTasks() {
   // The real list of scheduled tasks is kept up-to-date in the scheduledTasks map
   // TODO change the index for the scheduledTasks map to be the TaskDefinition rather than the ID
   List<TaskDefinition> list = new ArrayList<TaskDefinition>();
   Set<Integer> taskIds = scheduledTasks.keySet();
   for (Integer id : taskIds) {
     TaskDefinition task = getTask(id);
     log.debug("Adding scheduled task " + id + " to list (" + task.getRepeatInterval() + ")");
     list.add(task);
   }
   return list;
 }
  /**
   * Stops a running task.
   *
   * @param taskDefinition the task to be stopped
   * @see org.openmrs.scheduler.SchedulerService#shutdownTask(TaskDefinition)
   */
  public void shutdownTask(TaskDefinition taskDefinition) throws SchedulerException {
    if (taskDefinition != null) {

      // Remove the task from the scheduled tasks and shutdown the timer
      TimerSchedulerTask schedulerTask = scheduledTasks.remove(taskDefinition.getId());
      if (schedulerTask != null) {
        schedulerTask
            .shutdown(); // Stops the timer and tells the timer task to release its resources
      }

      // Update task that has been started
      taskDefinition.setStarted(false);
      saveTask(taskDefinition);
    }
  }
  /** Shutdown all running tasks. */
  public void shutdownAllTasks() {

    // iterate over this (copied) list of tasks and stop them all
    for (TaskDefinition task : getScheduledTasks()) {
      try {

        shutdownTask(task);

      } catch (SchedulerException e) {
        log.error("Failed to stop task " + task.getTaskClass() + " due to Scheduler exception", e);
      } catch (APIException e) {
        log.error("Failed to stop task " + task.getTaskClass() + " due to API exception", e);
      }
    }
  }
 /**
  * Save a task in the database.
  *
  * @param task the <code>TaskDefinition</code> to save
  */
 public void saveTaskDefinition(TaskDefinition task) {
   if (task.getId() != null) {
     getSchedulerDAO().updateTask(task);
   } else {
     getSchedulerDAO().createTask(task);
   }
 }
  /**
   * Saves and stops all active tasks
   *
   * @return OpenmrsMemento
   */
  public OpenmrsMemento saveToMemento() {

    Set<Integer> tasks = new HashSet<Integer>();

    for (TaskDefinition task : getScheduledTasks()) {
      tasks.add(task.getId());
      try {
        shutdownTask(task);
      } catch (SchedulerException e) {
        // just swallow exceptions
        log.debug("Failed to stop task while saving memento " + task.getName(), e);
      }
    }

    TimerSchedulerMemento memento = new TimerSchedulerMemento(tasks);
    memento.saveErrorTasks();

    return memento;
  }
  /** Start up hook for the scheduler and all of its scheduled tasks. */
  public void onStartup() {
    log.debug("Starting scheduler service ...");

    // Get all of the tasks in the database
    Collection<TaskDefinition> taskDefinitions = getSchedulerDAO().getTasks();

    // Iterate through the tasks and start them if their startOnStartup flag is true
    if (taskDefinitions != null) {
      for (TaskDefinition taskDefinition : taskDefinitions) {
        try {
          // If the task is configured to start on startup, we schedule it to run
          // Otherwise it needs to be started manually.
          if (taskDefinition.getStartOnStartup()) {
            scheduleTask(taskDefinition);
          }

        } catch (Exception e) {
          log.error("Failed to schedule task for class " + taskDefinition.getTaskClass(), e);
        }
      }
    }
  }
 @Override
 public void scheduleIfNotRunning(TaskDefinition taskDef) {
   Task task = taskDef.getTaskInstance();
   if (task == null) {
     try {
       scheduleTask(taskDef);
     } catch (SchedulerException e) {
       log.error("Failed to schedule task, because:", e);
     }
   } else if (!task.isExecuting()) {
     try {
       rescheduleTask(taskDef);
     } catch (SchedulerException e) {
       log.error("Failed to re-schedule task, because:", e);
     }
   }
 }
  /**
   * Tests whether the TimerScheduler schedules tasks even if the repeatInterval is zero.
   *
   * @see {@link TimerSchedulerServiceImpl#scheduleTask(TaskDefinition)}
   */
  @Test
  @Verifies(value = "should handle zero repeat interval", method = "scheduleTask(TaskDefinition)")
  public void scheduleTask_shouldHandleZeroRepeatInterval() throws Exception {

    // Represents the start time of the task (right now)
    Calendar startTime = Calendar.getInstance();

    // Define repeatInterval as zero
    Long repeatInterval = new Long(0);

    String taskName = "TestTask";
    String className = "org.openmrs.scheduler.tasks.TestTask";

    Boolean startOnStartup = false;

    // Create the new task
    TaskDefinition taskDefinition = new TaskDefinition();
    taskDefinition.setName(taskName);
    taskDefinition.setTaskClass(className);
    taskDefinition.setStartTime(startTime.getTime());
    taskDefinition.setRepeatInterval(repeatInterval);
    taskDefinition.setStartOnStartup(startOnStartup);

    Task clientTask = null;

    TimerSchedulerServiceImpl t = new TimerSchedulerServiceImpl();
    clientTask = t.scheduleTask(taskDefinition);

    // without this commit there seems to be a table lock left on the SCHEDULER_TASK_CONFIG table,
    // see TRUNK-4212
    Context.flushSession();
    getConnection().commit();

    // Assert that the clientTask is not null, i.e. the sheduleTask was able to successfully
    // schedule in case of zero repeatInterval.
    assertNotNull(
        "The clientTask variable is null, so either the TimerSchedulerServiceImpl.scheduleTask method hasn't finished or didn't get run",
        clientTask);
  }
  /**
   * Schedule the given task according to the given schedule.
   *
   * @param taskDefinition the task to be scheduled
   * @should should handle zero repeat interval
   */
  public Task scheduleTask(TaskDefinition taskDefinition) throws SchedulerException {
    Task clientTask = null;
    if (taskDefinition != null) {

      // Cancel any existing timer tasks for the same task definition
      // TODO Make sure this is the desired behavior
      // TODO Do we ever want the same task definition to run more than once?
      TimerSchedulerTask schedulerTask = scheduledTasks.get(taskDefinition.getId());
      if (schedulerTask != null) {
        // schedulerTask.cancel();
        log.info("Shutting down the existing instance of this task to avoid conflicts!!");
        schedulerTask.shutdown();
      }

      try {

        // Create new task from task definition
        clientTask = TaskFactory.getInstance().createInstance(taskDefinition);

        // if we were unable to get a class, just quit
        if (clientTask != null) {

          schedulerTask = new TimerSchedulerTask(clientTask);
          taskDefinition.setTaskInstance(clientTask);

          // Once this method is called, the timer is set to start at the given start time.
          // NOTE:  We need to adjust the repeat interval as the JDK Timer expects time in
          // milliseconds and
          // we record by seconds.

          long repeatInterval = 0;
          if (taskDefinition.getRepeatInterval() != null)
            repeatInterval =
                taskDefinition.getRepeatInterval() * SchedulerConstants.SCHEDULER_MILLIS_PER_SECOND;

          if (taskDefinition.getStartTime() != null) {
            // Need to calculate the "next execution time" because the scheduled time is most likely
            // in the past
            // and the JDK timer will run the task X number of times from the start time until now
            // to catch up.
            Date nextTime = SchedulerUtil.getNextExecution(taskDefinition);

            // Start task at fixed rate at given future date and repeat as directed
            log.info("Starting task ... the task will execute for the first time at " + nextTime);

            if (repeatInterval > 0) {
              // Schedule the task to run at a fixed rate
              getTimer(taskDefinition).scheduleAtFixedRate(schedulerTask, nextTime, repeatInterval);
            } else {
              // Schedule the task to be non-repeating
              getTimer(taskDefinition).schedule(schedulerTask, nextTime);
            }

          } else if (repeatInterval > 0) {
            // Start task on repeating schedule, delay for SCHEDULER_DEFAULT_DELAY seconds
            log.info(
                "Delaying start time by "
                    + SchedulerConstants.SCHEDULER_DEFAULT_DELAY
                    + " seconds");
            getTimer(taskDefinition)
                .scheduleAtFixedRate(
                    schedulerTask, SchedulerConstants.SCHEDULER_DEFAULT_DELAY, repeatInterval);
          } else {
            // schedule for single execution, starting now
            log.info("Starting one-shot task");
            getTimer(taskDefinition).schedule(schedulerTask, new Date());
          }

          // Update task that has been started
          log.debug("Registering timer for task " + taskDefinition.getId());

          //  Add the new timer to the scheduler running task list
          scheduledTasks.put(taskDefinition.getId(), schedulerTask);

          // Update the timer status in the database
          taskDefinition.setStarted(true);
          saveTask(taskDefinition);
        }
      } catch (Exception e) {
        log.error("Failed to schedule task " + taskDefinition.getName(), e);
        throw new SchedulerException("Failed to schedule task", e);
      }
    }
    return clientTask;
  }