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 jobs = new ArrayList();
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 getJobs() {
84 return this.jobs;
85 }
86
87
88 public void setJobs(List jobs) {
89 this.jobs = jobs;
90 }
91
92 public void addJob(JobDefinition job) throws SchedulerException{
93 jobs.add(job);
94 if(running){
95 initJob(job);
96 }
97 }
98
99
100
101
102 public void stop(ModuleLifecycleContext moduleLifecycleContext) {
103 try {
104 scheduler.shutdown(true);
105 log.info("Waiting up to 30 seconds for scheduled jobs to stop");
106 int count = 0;
107 while (count < 30) {
108 try {
109 Thread.sleep(1000);
110 } catch (InterruptedException e) {
111 Thread.interrupted();
112 }
113 if (scheduler.isShutdown()) {
114 break;
115 } else {
116 count++;
117 }
118 }
119 if (!scheduler.isShutdown()) {
120 log.info("Scheduled jobs failed to finish in 30 seconds interval, forcing shutdown now.");
121 scheduler.shutdown(false);
122 }
123 running = false;
124 }
125 catch (SchedulerException e) {
126 log.error("Can't stop scheduler properly", e);
127 }
128 }
129
130
131
132
133 public void start(ModuleLifecycleContext moduleLifecycleContext) {
134 try {
135 initScheduler();
136 running = true;
137 }
138 catch (SchedulerException e) {
139 log.error("Can't start scheduler", e);
140 return;
141 }
142
143 initJobs();
144 }
145
146
147
148
149 protected void initJobs() {
150 for (Iterator iter = jobs.iterator(); iter.hasNext();) {
151 JobDefinition job = (JobDefinition) iter.next();
152 try {
153 initJob(job);
154 }
155 catch (SchedulerException e) {
156 log.error("Can't initialize job [" + job.getName() + "]", e);
157 }
158 }
159 }
160
161
162
163
164 protected void initJob(JobDefinition job) throws SchedulerException {
165 if (job.isActive()) {
166 try {
167 stopJob(job.getName());
168 startJob(job);
169 }
170 catch (SchedulerException e) {
171 throw new SchedulerException("Can't schedule job" + job.getName(), e);
172 }
173 }
174 else {
175 try {
176 stopJob(job.getName());
177 } catch (SchedulerException e) {
178 throw new SchedulerException("Can't delete inactive job " + job.getName(), e);
179 }
180 }
181 }
182
183 protected void startJob(JobDefinition job) throws SchedulerException {
184 Trigger trigger;
185 try {
186 String cron = cronToQuarzCron(job.getCron());
187 trigger = new CronTrigger(job.getName(), SchedulerConsts.SCHEDULER_GROUP_NAME, cron);
188 }
189 catch (ParseException e) {
190 log.error("Can't parse the job's cron expression [" + job.getCron() + "]", e);
191 return;
192 }
193
194 final Class jobClass = job.isConcurrent() ? CommandJob.class : StatefulCommandJob.class;
195 final JobDetail jd = new JobDetail(job.getName(), SchedulerConsts.SCHEDULER_GROUP_NAME, jobClass);
196 jd.getJobDataMap().put(SchedulerConsts.CONFIG_JOB_COMMAND, job.getCommand());
197 jd.getJobDataMap().put(SchedulerConsts.CONFIG_JOB_COMMAND_CATALOG, job.getCatalog());
198 jd.getJobDataMap().put(SchedulerConsts.CONFIG_JOB_PARAMS, job.getParams());
199 scheduler.scheduleJob(jd, trigger);
200 log.info("Job " + job.getName() + " added [" + job.getCron() + "]. Will fire first time at " + trigger.getNextFireTime());
201 }
202
203
204 protected String cronToQuarzCron(String cron) {
205
206 String[] tokens = StringUtils.split(cron);
207 if (tokens.length >= 6) {
208 if (!tokens[3].equals("?") && !tokens[5].equals("?")) {
209 if(tokens[5].equals("*")){
210 tokens[5] = "?";
211 }
212 else if(tokens[3].equals("*")){
213 tokens[3] = "?";
214 }
215 }
216 }
217 cron = StringUtils.join(tokens, " ");
218 return cron;
219 }
220
221
222
223
224 public void stopJob(String name) throws SchedulerException {
225 scheduler.deleteJob(name, SchedulerConsts.SCHEDULER_GROUP_NAME);
226 }
227
228
229
230
231
232 protected void initScheduler() throws SchedulerException {
233 SchedulerFactory sf = new StdSchedulerFactory();
234 scheduler = sf.getScheduler();
235 scheduler.start();
236 }
237
238
239
240
241 public Scheduler getScheduler() {
242 return scheduler;
243 }
244
245
246
247
248 public static SchedulerModule getInstance() {
249 return instance;
250 }
251
252 }