1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.scheduler.quartz;
24  
25  import com.liferay.portal.kernel.annotation.BeanReference;
26  import com.liferay.portal.kernel.log.Log;
27  import com.liferay.portal.kernel.log.LogFactoryUtil;
28  import com.liferay.portal.kernel.scheduler.SchedulerEngine;
29  import com.liferay.portal.kernel.scheduler.SchedulerException;
30  import com.liferay.portal.kernel.scheduler.messaging.SchedulerRequest;
31  import com.liferay.portal.kernel.util.ServerDetector;
32  import com.liferay.portal.kernel.util.Time;
33  import com.liferay.portal.kernel.util.Validator;
34  import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
35  import com.liferay.portal.scheduler.job.MessageSenderJob;
36  import com.liferay.portal.service.QuartzLocalService;
37  import com.liferay.portal.util.PropsUtil;
38  import com.liferay.portal.util.PropsValues;
39  
40  import java.text.ParseException;
41  
42  import java.util.ArrayList;
43  import java.util.Date;
44  import java.util.List;
45  
46  import org.quartz.CronTrigger;
47  import org.quartz.JobDataMap;
48  import org.quartz.JobDetail;
49  import org.quartz.ObjectAlreadyExistsException;
50  import org.quartz.Scheduler;
51  import org.quartz.SimpleTrigger;
52  import org.quartz.Trigger;
53  import org.quartz.impl.StdSchedulerFactory;
54  
55  /**
56   * <a href="QuartzSchedulerEngineImpl.java.html"><b><i>View Source</i></b></a>
57   *
58   * @author Michael C. Han
59   * @author Bruno Farache
60   * @author Wesley Gong
61   */
62  public class QuartzSchedulerEngineImpl implements SchedulerEngine {
63  
64      public void afterPropertiesSet() {
65          try {
66              if (!PropsValues.SCHEDULER_ENABLED) {
67                  return;
68              }
69  
70              StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
71  
72              schedulerFactory.initialize(
73                  PropsUtil.getProperties("org.quartz.", false));
74  
75              quartzLocalService.checkQuartzTables();
76  
77              _scheduler = schedulerFactory.getScheduler();
78          }
79          catch (Exception e) {
80              _log.error("Unable to initialize engine", e);
81          }
82      }
83  
84      public List<SchedulerRequest> getScheduledJobs(String groupName)
85          throws SchedulerException {
86  
87          if (!PropsValues.SCHEDULER_ENABLED) {
88              return new ArrayList<SchedulerRequest>();
89          }
90  
91          try {
92              String[] jobNames = _scheduler.getJobNames(groupName);
93  
94              List<SchedulerRequest> requests = new ArrayList<SchedulerRequest>();
95  
96              for (String jobName : jobNames) {
97                  JobDetail jobDetail = _scheduler.getJobDetail(
98                      jobName, groupName);
99  
100                 if (jobDetail == null) {
101                     continue;
102                 }
103 
104                 JobDataMap jobDataMap = jobDetail.getJobDataMap();
105 
106                 String description = jobDataMap.getString(DESCRIPTION);
107                 String messageBody = jobDataMap.getString(MESSAGE_BODY);
108 
109                 SchedulerRequest schedulerRequest = null;
110 
111                 Trigger trigger = _scheduler.getTrigger(jobName, groupName);
112 
113                 if (CronTrigger.class.isAssignableFrom(trigger.getClass())) {
114                     CronTrigger cronTrigger = CronTrigger.class.cast(trigger);
115 
116                     schedulerRequest =
117                         SchedulerRequest.createRetrieveResponseRequest(
118                             jobName, groupName, cronTrigger.getCronExpression(),
119                             cronTrigger.getStartTime(),
120                             cronTrigger.getEndTime(), description, messageBody);
121                 }
122                 else if (SimpleTrigger.class.isAssignableFrom(
123                             trigger.getClass())) {
124 
125                     SimpleTrigger simpleTrigger = SimpleTrigger.class.cast(
126                         trigger);
127 
128                     schedulerRequest =
129                         SchedulerRequest.createRetrieveResponseRequest(
130                             jobName, groupName,
131                             simpleTrigger.getRepeatInterval(),
132                             simpleTrigger.getStartTime(),
133                             simpleTrigger.getEndTime(), description,
134                             messageBody);
135                 }
136 
137                 if (schedulerRequest != null) {
138                     requests.add(schedulerRequest);
139                 }
140             }
141 
142             return requests;
143         }
144         catch (org.quartz.SchedulerException se) {
145             throw new SchedulerException("Unable to retrieve job", se);
146         }
147     }
148 
149     public void schedule(
150             String groupName, long interval, Date startDate, Date endDate,
151             String description, String destination, String messageBody)
152         throws SchedulerException {
153 
154         schedule(
155             null, groupName, interval, startDate, endDate, description,
156             destination, messageBody);
157     }
158 
159     public void schedule(
160             String groupName, String cronText, Date startDate, Date endDate,
161             String description, String destination, String messageBody)
162         throws SchedulerException {
163 
164         schedule(
165             null, groupName, cronText, startDate, endDate, description,
166             destination, messageBody);
167     }
168 
169     public void schedule(
170             String jobName, String groupName, long interval, Date startDate,
171             Date endDate, String description, String destinationName,
172             String messageBody)
173         throws SchedulerException {
174 
175         if (!PropsValues.SCHEDULER_ENABLED) {
176             return;
177         }
178 
179         if (Validator.isNull(jobName)) {
180             jobName = PortalUUIDUtil.generate();
181         }
182 
183         try {
184             SimpleTrigger simpleTrigger = new SimpleTrigger(
185                 jobName, groupName, SimpleTrigger.REPEAT_INDEFINITELY,
186                 interval);
187 
188             simpleTrigger.setJobName(jobName);
189             simpleTrigger.setJobGroup(groupName);
190 
191             if (startDate == null) {
192                 if (ServerDetector.getServerId().equals(
193                         ServerDetector.TOMCAT_ID)) {
194 
195                     simpleTrigger.setStartTime(
196                         new Date(System.currentTimeMillis() + Time.MINUTE));
197                 }
198                 else {
199                     simpleTrigger.setStartTime(
200                         new Date(
201                         System.currentTimeMillis() + Time.MINUTE * 3));
202                 }
203             }
204             else {
205                 simpleTrigger.setStartTime(startDate);
206             }
207 
208             if (endDate != null) {
209                 simpleTrigger.setEndTime(endDate);
210             }
211 
212             schedule(
213                 groupName, simpleTrigger, description, destinationName,
214                 messageBody);
215         }
216         catch (RuntimeException re) {
217 
218             // ServerDetector will throw an exception when JobSchedulerImpl is
219             // initialized in a test environment
220 
221         }
222     }
223 
224     public void schedule(
225             String jobName, String groupName, String cronText, Date startDate,
226             Date endDate, String description, String destinationName,
227             String messageBody)
228         throws SchedulerException {
229 
230         if (!PropsValues.SCHEDULER_ENABLED) {
231             return;
232         }
233 
234         if (Validator.isNull(jobName)) {
235             jobName = PortalUUIDUtil.generate();
236         }
237 
238         try {
239             CronTrigger cronTrigger = new CronTrigger(
240                 jobName, groupName, jobName, groupName, cronText);
241 
242             if (startDate == null) {
243                 if (ServerDetector.getServerId().equals(
244                         ServerDetector.TOMCAT_ID)) {
245 
246                     cronTrigger.setStartTime(
247                         new Date(System.currentTimeMillis() + Time.MINUTE));
248                 }
249                 else {
250                     cronTrigger.setStartTime(
251                         new Date(System.currentTimeMillis() + Time.MINUTE * 3));
252                 }
253             }
254             else {
255                 cronTrigger.setStartTime(startDate);
256             }
257 
258             if (endDate != null) {
259                 cronTrigger.setEndTime(endDate);
260             }
261 
262             schedule(
263                 groupName, cronTrigger, description, destinationName,
264                 messageBody);
265         }
266         catch(ParseException pe) {
267             throw new SchedulerException("Unable to parse cron text", pe);
268         }
269         catch (RuntimeException re) {
270 
271             // ServerDetector will throw an exception when JobSchedulerImpl is
272             // initialized in a test environment
273 
274         }
275     }
276 
277     public void shutdown() throws SchedulerException {
278         if (!PropsValues.SCHEDULER_ENABLED) {
279             return;
280         }
281 
282         try {
283             _scheduler.shutdown(false);
284         }
285         catch (org.quartz.SchedulerException se) {
286             throw new SchedulerException("Unable to shutdown scheduler", se);
287         }
288     }
289 
290     public void start() throws SchedulerException {
291         if (!PropsValues.SCHEDULER_ENABLED) {
292             return;
293         }
294 
295         try {
296             _scheduler.start();
297         }
298         catch (org.quartz.SchedulerException se) {
299             throw new SchedulerException("Unable to start scheduler", se);
300         }
301     }
302 
303     public void unschedule(String jobName, String groupName)
304         throws SchedulerException {
305 
306         if (!PropsValues.SCHEDULER_ENABLED) {
307             return;
308         }
309 
310         try {
311             _scheduler.unscheduleJob(jobName, groupName);
312         }
313         catch (org.quartz.SchedulerException se) {
314             throw new SchedulerException(
315                 "Unable to unschedule job {jobName=" + jobName +
316                     ", groupName=" + groupName + "}",
317                 se);
318         }
319     }
320 
321     protected void schedule(
322             String groupName, Trigger trigger, String description,
323             String destination, String messageBody)
324         throws SchedulerException {
325 
326         try {
327             JobDetail jobDetail = new JobDetail(
328                 trigger.getJobName(), groupName, MessageSenderJob.class);
329 
330             JobDataMap jobDataMap = jobDetail.getJobDataMap();
331 
332             jobDataMap.put(DESCRIPTION, description);
333             jobDataMap.put(DESTINATION, destination);
334             jobDataMap.put(MESSAGE_BODY, messageBody);
335 
336             synchronized (this) {
337                 _scheduler.unscheduleJob(trigger.getJobName(), groupName);
338                 _scheduler.scheduleJob(jobDetail, trigger);
339             }
340         }
341         catch (ObjectAlreadyExistsException oare) {
342             if (_log.isInfoEnabled()) {
343                 _log.info("Message is already scheduled");
344             }
345         }
346         catch (org.quartz.SchedulerException se) {
347             throw new SchedulerException("Unable to scheduled job", se);
348         }
349     }
350 
351     @BeanReference(name = "com.liferay.portal.service.QuartzLocalService")
352     protected QuartzLocalService quartzLocalService;
353 
354     private Log _log = LogFactoryUtil.getLog(QuartzSchedulerEngineImpl.class);
355 
356     private Scheduler _scheduler;
357 
358 }