1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.scheduler.quartz;
16  
17  import com.liferay.portal.kernel.annotation.BeanReference;
18  import com.liferay.portal.kernel.log.Log;
19  import com.liferay.portal.kernel.log.LogFactoryUtil;
20  import com.liferay.portal.kernel.messaging.Message;
21  import com.liferay.portal.kernel.scheduler.IntervalTrigger;
22  import com.liferay.portal.kernel.scheduler.SchedulerEngine;
23  import com.liferay.portal.kernel.scheduler.SchedulerException;
24  import com.liferay.portal.kernel.scheduler.TriggerType;
25  import com.liferay.portal.kernel.scheduler.messaging.SchedulerRequest;
26  import com.liferay.portal.kernel.util.ServerDetector;
27  import com.liferay.portal.kernel.util.StringPool;
28  import com.liferay.portal.kernel.util.Time;
29  import com.liferay.portal.scheduler.job.MessageSenderJob;
30  import com.liferay.portal.service.QuartzLocalService;
31  import com.liferay.portal.util.PropsUtil;
32  import com.liferay.portal.util.PropsValues;
33  
34  import java.text.ParseException;
35  
36  import java.util.ArrayList;
37  import java.util.Date;
38  import java.util.List;
39  
40  import org.quartz.CronTrigger;
41  import org.quartz.JobDataMap;
42  import org.quartz.JobDetail;
43  import org.quartz.ObjectAlreadyExistsException;
44  import org.quartz.Scheduler;
45  import org.quartz.SimpleTrigger;
46  import org.quartz.Trigger;
47  import org.quartz.impl.StdSchedulerFactory;
48  
49  /**
50   * <a href="QuartzSchedulerEngineImpl.java.html"><b><i>View Source</i></b></a>
51   *
52   * @author Michael C. Han
53   * @author Bruno Farache
54   * @author Shuyang Zhou
55   * @author Wesley Gong
56   */
57  public class QuartzSchedulerEngineImpl implements SchedulerEngine {
58  
59      public void afterPropertiesSet() {
60          try {
61              if (!PropsValues.SCHEDULER_ENABLED) {
62                  return;
63              }
64  
65              StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
66  
67              schedulerFactory.initialize(
68                  PropsUtil.getProperties("org.quartz.", false));
69  
70              quartzLocalService.checkQuartzTables();
71  
72              _scheduler = schedulerFactory.getScheduler();
73          }
74          catch (Exception e) {
75              _log.error("Unable to initialize engine", e);
76          }
77      }
78  
79      public List<SchedulerRequest> getScheduledJobs(String groupName)
80          throws SchedulerException {
81  
82          if (!PropsValues.SCHEDULER_ENABLED) {
83              return new ArrayList<SchedulerRequest>();
84          }
85  
86          try {
87              String[] jobNames = _scheduler.getJobNames(groupName);
88  
89              List<SchedulerRequest> requests = new ArrayList<SchedulerRequest>();
90  
91              for (String jobName : jobNames) {
92                  JobDetail jobDetail = _scheduler.getJobDetail(
93                      jobName, groupName);
94  
95                  if (jobDetail == null) {
96                      continue;
97                  }
98  
99                  JobDataMap jobDataMap = jobDetail.getJobDataMap();
100 
101                 String description = jobDataMap.getString(DESCRIPTION);
102                 Message message = (Message)jobDataMap.get(MESSAGE);
103 
104                 SchedulerRequest schedulerRequest = null;
105 
106                 Trigger trigger = _scheduler.getTrigger(jobName, groupName);
107 
108                 if (CronTrigger.class.isAssignableFrom(trigger.getClass())) {
109                     CronTrigger cronTrigger = CronTrigger.class.cast(trigger);
110 
111                     schedulerRequest =
112                         SchedulerRequest.createRetrieveResponseRequest(
113                             new com.liferay.portal.kernel.scheduler.CronTrigger(
114                                 jobName, groupName, cronTrigger.getStartTime(),
115                                 cronTrigger.getEndTime(),
116                                 cronTrigger.getCronExpression()),
117                             description, message);
118                 }
119                 else if (SimpleTrigger.class.isAssignableFrom(
120                             trigger.getClass())) {
121 
122                     SimpleTrigger simpleTrigger = SimpleTrigger.class.cast(
123                         trigger);
124 
125                     schedulerRequest =
126                         SchedulerRequest.createRetrieveResponseRequest(
127                             new IntervalTrigger(
128                                 jobName, groupName,
129                                 simpleTrigger.getStartTime(),
130                                 simpleTrigger.getEndTime(),
131                                 simpleTrigger.getRepeatInterval()), description,
132                                 message);
133                 }
134 
135                 if (schedulerRequest != null) {
136                     requests.add(schedulerRequest);
137                 }
138             }
139 
140             return requests;
141         }
142         catch (org.quartz.SchedulerException se) {
143             throw new SchedulerException("Unable to retrieve job", se);
144         }
145     }
146 
147     public void schedule(
148             com.liferay.portal.kernel.scheduler.Trigger trigger,
149             String description, String destination, Message message)
150         throws SchedulerException {
151 
152         if (!PropsValues.SCHEDULER_ENABLED) {
153             return;
154         }
155 
156         try {
157             String jobName = trigger.getJobName();
158             String groupName = trigger.getGroupName();
159 
160             if (jobName.length() > JOB_NAME_MAX_LENGTH) {
161                 jobName = jobName.substring(0, JOB_NAME_MAX_LENGTH);
162             }
163 
164             if (groupName.length() > GROUP_NAME_MAX_LENGTH) {
165                 groupName = groupName.substring(0, GROUP_NAME_MAX_LENGTH);
166             }
167 
168             Trigger quartzTrigger = null;
169 
170             if (trigger.getTriggerType() == TriggerType.CRON) {
171                 try {
172                     quartzTrigger = new CronTrigger(
173                         jobName, groupName,
174                         (String)trigger.getTriggerContent());
175                 }
176                 catch (ParseException pe) {
177                     throw new SchedulerException(
178                         "Unable to parse cron text " +
179                             trigger.getTriggerContent());
180                 }
181             }
182             else if (trigger.getTriggerType() == TriggerType.SIMPLE) {
183                 long interval = (Long)trigger.getTriggerContent();
184 
185                 if (interval <= 0) {
186                     if (_log.isDebugEnabled()) {
187                         _log.debug(
188                             "Not scheduling " + trigger.getJobName() +
189                                 " because interval is less than or equal to 0");
190                     }
191 
192                     return;
193                 }
194 
195                 quartzTrigger = new SimpleTrigger(
196                     jobName, groupName, SimpleTrigger.REPEAT_INDEFINITELY,
197                     interval);
198             }
199             else {
200                 throw new SchedulerException(
201                     "Unknown trigger type " + trigger.getTriggerType());
202             }
203 
204             quartzTrigger.setJobName(jobName);
205             quartzTrigger.setJobGroup(groupName);
206 
207             Date startDate = trigger.getStartDate();
208 
209             if (startDate == null) {
210                 if (ServerDetector.getServerId().equals(
211                         ServerDetector.TOMCAT_ID)) {
212 
213                     quartzTrigger.setStartTime(
214                         new Date(System.currentTimeMillis() + Time.MINUTE));
215                 }
216                 else {
217                     quartzTrigger.setStartTime(
218                         new Date(
219                         System.currentTimeMillis() + Time.MINUTE * 3));
220                 }
221             }
222             else {
223                 quartzTrigger.setStartTime(startDate);
224             }
225 
226             Date endDate = trigger.getEndDate();
227 
228             if (endDate != null) {
229                 quartzTrigger.setEndTime(endDate);
230             }
231 
232             if ((description != null) &&
233                 (description.length() > DESCRIPTION_MAX_LENGTH)) {
234 
235                 description = description.substring(0, DESCRIPTION_MAX_LENGTH);
236             }
237 
238             if (message == null){
239                 message = new Message();
240             }
241 
242             message.put(
243                 RECEIVER_KEY,
244                 jobName.concat(StringPool.COLON).concat(groupName));
245 
246             schedule(quartzTrigger, description, destination, message);
247         }
248         catch (RuntimeException re) {
249 
250             // ServerDetector will throw an exception when JobSchedulerImpl is
251             // initialized in a test environment
252 
253         }
254     }
255 
256     public void shutdown() throws SchedulerException {
257         if (!PropsValues.SCHEDULER_ENABLED) {
258             return;
259         }
260 
261         try {
262             _scheduler.shutdown(false);
263         }
264         catch (org.quartz.SchedulerException se) {
265             throw new SchedulerException("Unable to shutdown scheduler", se);
266         }
267     }
268 
269     public void start() throws SchedulerException {
270         if (!PropsValues.SCHEDULER_ENABLED) {
271             return;
272         }
273 
274         try {
275             _scheduler.start();
276         }
277         catch (org.quartz.SchedulerException se) {
278             throw new SchedulerException("Unable to start scheduler", se);
279         }
280     }
281 
282     public void unschedule(
283             com.liferay.portal.kernel.scheduler.Trigger trigger)
284         throws SchedulerException {
285 
286         if (!PropsValues.SCHEDULER_ENABLED) {
287             return;
288         }
289 
290         String jobName = trigger.getJobName();
291         String groupName = trigger.getGroupName();
292 
293         try {
294             _scheduler.unscheduleJob(jobName, groupName);
295         }
296         catch (org.quartz.SchedulerException se) {
297             throw new SchedulerException(
298                 "Unable to unschedule job {jobName=" + jobName +
299                     ", groupName=" + groupName + "}",
300                 se);
301         }
302     }
303 
304     protected void schedule(
305             Trigger trigger, String description,
306             String destination, Message message)
307         throws SchedulerException {
308 
309         try {
310             String jobName = trigger.getName();
311             String groupName = trigger.getGroup();
312 
313             JobDetail jobDetail = new JobDetail(
314                 jobName, groupName, MessageSenderJob.class);
315 
316             JobDataMap jobDataMap = jobDetail.getJobDataMap();
317 
318             jobDataMap.put(DESCRIPTION, description);
319             jobDataMap.put(DESTINATION, destination);
320             jobDataMap.put(MESSAGE, message);
321 
322             synchronized (this) {
323                 _scheduler.unscheduleJob(jobName, groupName);
324                 _scheduler.scheduleJob(jobDetail, trigger);
325             }
326         }
327         catch (ObjectAlreadyExistsException oare) {
328             if (_log.isInfoEnabled()) {
329                 _log.info("Message is already scheduled");
330             }
331         }
332         catch (org.quartz.SchedulerException se) {
333             throw new SchedulerException("Unable to scheduled job", se);
334         }
335     }
336 
337     @BeanReference(name = "com.liferay.portal.service.QuartzLocalService")
338     protected QuartzLocalService quartzLocalService;
339 
340     private Log _log = LogFactoryUtil.getLog(QuartzSchedulerEngineImpl.class);
341 
342     private Scheduler _scheduler;
343 
344 }