1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.module.scheduler;
35
36 import info.magnolia.module.ModuleLifecycle;
37 import info.magnolia.module.ModuleLifecycleContext;
38
39 import java.text.ParseException;
40 import java.util.ArrayList;
41 import java.util.Iterator;
42 import java.util.List;
43
44 import org.apache.commons.lang.StringUtils;
45 import org.quartz.CronTrigger;
46 import org.quartz.JobDetail;
47 import org.quartz.Scheduler;
48 import org.quartz.SchedulerException;
49 import org.quartz.SchedulerFactory;
50 import org.quartz.Trigger;
51 import org.quartz.impl.StdSchedulerFactory;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55
56
57
58
59
60
61
62
63
64 public class SchedulerModule implements ModuleLifecycle {
65 private static final Logger log = LoggerFactory.getLogger(JobDefinition.class);
66
67 private static SchedulerModule instance;
68
69 private List<JobDefinition> jobs = new ArrayList<JobDefinition>();
70
71 private boolean running = false;
72
73
74
75
76 protected Scheduler scheduler;
77
78 public SchedulerModule() {
79 instance = this;
80 }
81
82
83 public List<JobDefinition> getJobs() {
84 return this.jobs;
85 }
86
87
88 public void setJobs(List<JobDefinition> jobs) throws SchedulerException {
89 this.jobs = jobs;
90 for (JobDefinition job : jobs) {
91 if (running) {
92 initJob(job);
93 }
94 }
95 }
96
97 public void addJob(JobDefinition job) throws SchedulerException{
98 jobs.add(job);
99 if(running){
100 initJob(job);
101 }
102 }
103
104
105
106
107 @Override
108 public void stop(ModuleLifecycleContext moduleLifecycleContext) {
109 try {
110 scheduler.shutdown(true);
111 log.info("Waiting up to 30 seconds for scheduled jobs to stop...");
112 int count = 0;
113 while (count < 30) {
114 try {
115 Thread.sleep(1000);
116 } catch (InterruptedException e) {
117 Thread.interrupted();
118 }
119 if (scheduler.isShutdown()) {
120 break;
121 } else {
122 count++;
123 }
124 }
125 if (!scheduler.isShutdown()) {
126 log.info("Scheduled jobs failed to finish in 30 seconds interval, forcing shutdown now...");
127 scheduler.shutdown(false);
128 }
129 running = false;
130 }
131 catch (SchedulerException e) {
132 log.error("Can't stop scheduler properly", e);
133 }
134 }
135
136
137
138
139 @Override
140 public void start(ModuleLifecycleContext moduleLifecycleContext) {
141 try {
142 initScheduler();
143 running = true;
144 }
145 catch (SchedulerException e) {
146 log.error("Can't start scheduler", e);
147 return;
148 }
149
150 initJobs();
151 }
152
153
154
155
156 protected void initJobs() {
157 for (Iterator iter = jobs.iterator(); iter.hasNext();) {
158 JobDefinition job = (JobDefinition) iter.next();
159 try {
160 initJob(job);
161 }
162 catch (SchedulerException e) {
163 log.error("Can't initialize job [" + job.getName() + "]", e);
164 }
165 }
166 }
167
168
169
170
171 protected void initJob(JobDefinition job) throws SchedulerException {
172 if (job.isActive()) {
173 try {
174 stopJob(job.getName());
175 startJob(job);
176 }
177 catch (SchedulerException e) {
178 throw new SchedulerException("Can't schedule job" + job.getName(), e);
179 }
180 }
181 else {
182 try {
183 stopJob(job.getName());
184 } catch (SchedulerException e) {
185 throw new SchedulerException("Can't delete inactive job " + job.getName(), e);
186 }
187 }
188 }
189
190 protected void startJob(JobDefinition job) throws SchedulerException {
191 Trigger trigger;
192 try {
193 String cron = cronToQuarzCron(job.getCron());
194 trigger = new CronTrigger(job.getName(), SchedulerConsts.SCHEDULER_GROUP_NAME, cron);
195 }
196 catch (ParseException e) {
197 log.error("Can't parse the job's cron expression [" + job.getCron() + "]", e);
198 return;
199 }
200
201 final Class jobClass = job.isConcurrent() ? CommandJob.class : StatefulCommandJob.class;
202 final JobDetail jd = new JobDetail(job.getName(), SchedulerConsts.SCHEDULER_GROUP_NAME, jobClass);
203 jd.getJobDataMap().put(SchedulerConsts.CONFIG_JOB_COMMAND, job.getCommand());
204 jd.getJobDataMap().put(SchedulerConsts.CONFIG_JOB_COMMAND_CATALOG, job.getCatalog());
205 jd.getJobDataMap().put(SchedulerConsts.CONFIG_JOB_PARAMS, job.getParams());
206 scheduler.scheduleJob(jd, trigger);
207 log.info("Job " + job.getName() + " added [" + job.getCron() + "]. Will fire first time at " + trigger.getNextFireTime());
208 }
209
210
211 protected String cronToQuarzCron(String cron) {
212
213 String[] tokens = StringUtils.split(cron);
214 if (tokens.length >= 6) {
215 if (!tokens[3].equals("?") && !tokens[5].equals("?")) {
216 if(tokens[5].equals("*")){
217 tokens[5] = "?";
218 }
219 else if(tokens[3].equals("*")){
220 tokens[3] = "?";
221 }
222 }
223 }
224 cron = StringUtils.join(tokens, " ");
225 return cron;
226 }
227
228
229
230
231 public void stopJob(String name) throws SchedulerException {
232 scheduler.deleteJob(name, SchedulerConsts.SCHEDULER_GROUP_NAME);
233 }
234
235
236
237
238
239 protected void initScheduler() throws SchedulerException {
240 SchedulerFactory sf = new StdSchedulerFactory();
241 scheduler = sf.getScheduler();
242 scheduler.start();
243 }
244
245
246
247
248 public Scheduler getScheduler() {
249 return scheduler;
250 }
251
252
253
254
255 public static SchedulerModule getInstance() {
256 return instance;
257 }
258
259 }