View Javadoc
1   package com.atlassian.sal.core.scheduling;
2   
3   import com.atlassian.sal.api.scheduling.PluginJob;
4   import com.atlassian.sal.api.scheduling.PluginScheduler;
5   
6   import java.util.Date;
7   import java.util.Map;
8   import java.util.concurrent.ConcurrentHashMap;
9   import java.util.concurrent.Executors;
10  import java.util.concurrent.Future;
11  import java.util.concurrent.ScheduledExecutorService;
12  import java.util.concurrent.TimeUnit;
13  
14  /**
15   * Plugin scheduler that uses java.util.concurrent.Executor.
16   */
17  public class ExecutorPluginScheduler implements PluginScheduler {
18  
19      public static final int DEFAULT_POOL_SIZE = 5;
20      private final ScheduledExecutorService jobExecutor;
21      private final Map<String, Future<?>> jobs;
22  
23      public ExecutorPluginScheduler() {
24          this(Executors.newScheduledThreadPool(DEFAULT_POOL_SIZE));
25      }
26  
27      public ExecutorPluginScheduler(ScheduledExecutorService executor) {
28          this.jobExecutor = executor;
29          this.jobs = new ConcurrentHashMap<>();
30      }
31  
32      @Override
33      public synchronized void scheduleJob(String jobKey, Class<? extends PluginJob> jobClass, Map<String, Object> jobDataMap, Date startTime, long repeatInterval) {
34          final Future<?> job = jobs.get(jobKey);
35          if (job != null) {
36              cancelJob(job);
37          }
38  
39          jobs.put(jobKey, jobExecutor.scheduleAtFixedRate(new Job(jobClass, jobDataMap), getDelay(startTime), repeatInterval, TimeUnit.MILLISECONDS));
40      }
41  
42      @Override
43      public synchronized void unscheduleJob(String jobKey) {
44          final Future<?> job = jobs.remove(jobKey);
45          if (job != null) {
46              cancelJob(job);
47          } else {
48              throw new IllegalArgumentException("Attempted to unschedule unknown job: " + jobKey);
49          }
50      }
51  
52      protected void cancelJob(Future<?> job) {
53          job.cancel(false);
54      }
55  
56      private long getDelay(Date startTime) {
57          final long time = startTime.getTime() - System.currentTimeMillis();
58          return time > 0 ? time : 0;
59      }
60  
61      private static class Job implements Runnable {
62  
63          private final Class<? extends PluginJob> jobClass;
64          private final Map<String, Object> jobDataMap;
65  
66          private Job(Class<? extends PluginJob> jobClass, Map<String, Object> jobDataMap) {
67              this.jobClass = jobClass;
68              this.jobDataMap = jobDataMap;
69          }
70  
71          @Override
72          public void run() {
73              PluginJob job;
74              try {
75                  job = jobClass.newInstance();
76              } catch (final InstantiationException ie) {
77                  throw new IllegalStateException("Error instantiating job", ie);
78              } catch (final IllegalAccessException iae) {
79                  throw new IllegalStateException("Cannot access job class", iae);
80              }
81              job.execute(jobDataMap);
82          }
83      }
84  
85  }