001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.scheduler.quartz;
016    
017    import com.liferay.portal.kernel.annotation.BeanReference;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.messaging.Message;
021    import com.liferay.portal.kernel.scheduler.IntervalTrigger;
022    import com.liferay.portal.kernel.scheduler.SchedulerEngine;
023    import com.liferay.portal.kernel.scheduler.SchedulerException;
024    import com.liferay.portal.kernel.scheduler.TriggerType;
025    import com.liferay.portal.kernel.scheduler.messaging.SchedulerRequest;
026    import com.liferay.portal.kernel.util.ServerDetector;
027    import com.liferay.portal.kernel.util.StringPool;
028    import com.liferay.portal.kernel.util.Time;
029    import com.liferay.portal.scheduler.job.MessageSenderJob;
030    import com.liferay.portal.service.QuartzLocalService;
031    import com.liferay.portal.util.PropsUtil;
032    import com.liferay.portal.util.PropsValues;
033    
034    import java.text.ParseException;
035    
036    import java.util.ArrayList;
037    import java.util.Date;
038    import java.util.List;
039    
040    import org.quartz.CronTrigger;
041    import org.quartz.JobDataMap;
042    import org.quartz.JobDetail;
043    import org.quartz.ObjectAlreadyExistsException;
044    import org.quartz.Scheduler;
045    import org.quartz.SimpleTrigger;
046    import org.quartz.Trigger;
047    import org.quartz.impl.StdSchedulerFactory;
048    
049    /**
050     * @author Michael C. Han
051     * @author Bruno Farache
052     * @author Shuyang Zhou
053     * @author Wesley Gong
054     */
055    public class QuartzSchedulerEngineImpl implements SchedulerEngine {
056    
057            public void afterPropertiesSet() {
058                    try {
059                            if (!PropsValues.SCHEDULER_ENABLED) {
060                                    return;
061                            }
062    
063                            StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
064    
065                            schedulerFactory.initialize(
066                                    PropsUtil.getProperties("org.quartz.", false));
067    
068                            quartzLocalService.checkQuartzTables();
069    
070                            _scheduler = schedulerFactory.getScheduler();
071                    }
072                    catch (Exception e) {
073                            _log.error("Unable to initialize engine", e);
074                    }
075            }
076    
077            public List<SchedulerRequest> getScheduledJobs(String groupName)
078                    throws SchedulerException {
079    
080                    if (!PropsValues.SCHEDULER_ENABLED) {
081                            return new ArrayList<SchedulerRequest>();
082                    }
083    
084                    try {
085                            String[] jobNames = _scheduler.getJobNames(groupName);
086    
087                            List<SchedulerRequest> requests = new ArrayList<SchedulerRequest>();
088    
089                            for (String jobName : jobNames) {
090                                    JobDetail jobDetail = _scheduler.getJobDetail(
091                                            jobName, groupName);
092    
093                                    if (jobDetail == null) {
094                                            continue;
095                                    }
096    
097                                    JobDataMap jobDataMap = jobDetail.getJobDataMap();
098    
099                                    String description = jobDataMap.getString(DESCRIPTION);
100                                    Message message = (Message)jobDataMap.get(MESSAGE);
101    
102                                    SchedulerRequest schedulerRequest = null;
103    
104                                    Trigger trigger = _scheduler.getTrigger(jobName, groupName);
105    
106                                    if (CronTrigger.class.isAssignableFrom(trigger.getClass())) {
107                                            CronTrigger cronTrigger = CronTrigger.class.cast(trigger);
108    
109                                            schedulerRequest =
110                                                    SchedulerRequest.createRetrieveResponseRequest(
111                                                            new com.liferay.portal.kernel.scheduler.CronTrigger(
112                                                                    jobName, groupName, cronTrigger.getStartTime(),
113                                                                    cronTrigger.getEndTime(),
114                                                                    cronTrigger.getCronExpression()),
115                                                            description, message);
116                                    }
117                                    else if (SimpleTrigger.class.isAssignableFrom(
118                                                            trigger.getClass())) {
119    
120                                            SimpleTrigger simpleTrigger = SimpleTrigger.class.cast(
121                                                    trigger);
122    
123                                            schedulerRequest =
124                                                    SchedulerRequest.createRetrieveResponseRequest(
125                                                            new IntervalTrigger(
126                                                                    jobName, groupName,
127                                                                    simpleTrigger.getStartTime(),
128                                                                    simpleTrigger.getEndTime(),
129                                                                    simpleTrigger.getRepeatInterval()), description,
130                                                                    message);
131                                    }
132    
133                                    if (schedulerRequest != null) {
134                                            requests.add(schedulerRequest);
135                                    }
136                            }
137    
138                            return requests;
139                    }
140                    catch (org.quartz.SchedulerException se) {
141                            throw new SchedulerException("Unable to retrieve job", se);
142                    }
143            }
144    
145            public void schedule(
146                            com.liferay.portal.kernel.scheduler.Trigger trigger,
147                            String description, String destination, Message message)
148                    throws SchedulerException {
149    
150                    if (!PropsValues.SCHEDULER_ENABLED) {
151                            return;
152                    }
153    
154                    try {
155                            String jobName = trigger.getJobName();
156                            String groupName = trigger.getGroupName();
157    
158                            if (jobName.length() > JOB_NAME_MAX_LENGTH) {
159                                    jobName = jobName.substring(0, JOB_NAME_MAX_LENGTH);
160                            }
161    
162                            if (groupName.length() > GROUP_NAME_MAX_LENGTH) {
163                                    groupName = groupName.substring(0, GROUP_NAME_MAX_LENGTH);
164                            }
165    
166                            Trigger quartzTrigger = null;
167    
168                            if (trigger.getTriggerType() == TriggerType.CRON) {
169                                    try {
170                                            quartzTrigger = new CronTrigger(
171                                                    jobName, groupName,
172                                                    (String)trigger.getTriggerContent());
173                                    }
174                                    catch (ParseException pe) {
175                                            throw new SchedulerException(
176                                                    "Unable to parse cron text " +
177                                                            trigger.getTriggerContent());
178                                    }
179                            }
180                            else if (trigger.getTriggerType() == TriggerType.SIMPLE) {
181                                    long interval = (Long)trigger.getTriggerContent();
182    
183                                    if (interval <= 0) {
184                                            if (_log.isDebugEnabled()) {
185                                                    _log.debug(
186                                                            "Not scheduling " + trigger.getJobName() +
187                                                                    " because interval is less than or equal to 0");
188                                            }
189    
190                                            return;
191                                    }
192    
193                                    quartzTrigger = new SimpleTrigger(
194                                            jobName, groupName, SimpleTrigger.REPEAT_INDEFINITELY,
195                                            interval);
196                            }
197                            else {
198                                    throw new SchedulerException(
199                                            "Unknown trigger type " + trigger.getTriggerType());
200                            }
201    
202                            quartzTrigger.setJobName(jobName);
203                            quartzTrigger.setJobGroup(groupName);
204    
205                            Date startDate = trigger.getStartDate();
206    
207                            if (startDate == null) {
208                                    if (ServerDetector.getServerId().equals(
209                                                    ServerDetector.TOMCAT_ID)) {
210    
211                                            quartzTrigger.setStartTime(
212                                                    new Date(System.currentTimeMillis() + Time.MINUTE));
213                                    }
214                                    else {
215                                            quartzTrigger.setStartTime(
216                                                    new Date(
217                                                    System.currentTimeMillis() + Time.MINUTE * 3));
218                                    }
219                            }
220                            else {
221                                    quartzTrigger.setStartTime(startDate);
222                            }
223    
224                            Date endDate = trigger.getEndDate();
225    
226                            if (endDate != null) {
227                                    quartzTrigger.setEndTime(endDate);
228                            }
229    
230                            if ((description != null) &&
231                                    (description.length() > DESCRIPTION_MAX_LENGTH)) {
232    
233                                    description = description.substring(0, DESCRIPTION_MAX_LENGTH);
234                            }
235    
236                            if (message == null){
237                                    message = new Message();
238                            }
239    
240                            message.put(
241                                    RECEIVER_KEY,
242                                    jobName.concat(StringPool.COLON).concat(groupName));
243    
244                            schedule(quartzTrigger, description, destination, message);
245                    }
246                    catch (RuntimeException re) {
247    
248                            // ServerDetector will throw an exception when JobSchedulerImpl is
249                            // initialized in a test environment
250    
251                    }
252            }
253    
254            public void shutdown() throws SchedulerException {
255                    if (!PropsValues.SCHEDULER_ENABLED) {
256                            return;
257                    }
258    
259                    try {
260                            _scheduler.shutdown(false);
261                    }
262                    catch (org.quartz.SchedulerException se) {
263                            throw new SchedulerException("Unable to shutdown scheduler", se);
264                    }
265            }
266    
267            public void start() throws SchedulerException {
268                    if (!PropsValues.SCHEDULER_ENABLED) {
269                            return;
270                    }
271    
272                    try {
273                            _scheduler.start();
274                    }
275                    catch (org.quartz.SchedulerException se) {
276                            throw new SchedulerException("Unable to start scheduler", se);
277                    }
278            }
279    
280            public void unschedule(
281                            com.liferay.portal.kernel.scheduler.Trigger trigger)
282                    throws SchedulerException {
283    
284                    if (!PropsValues.SCHEDULER_ENABLED) {
285                            return;
286                    }
287    
288                    String jobName = trigger.getJobName();
289                    String groupName = trigger.getGroupName();
290    
291                    try {
292                            _scheduler.unscheduleJob(jobName, groupName);
293                    }
294                    catch (org.quartz.SchedulerException se) {
295                            throw new SchedulerException(
296                                    "Unable to unschedule job {jobName=" + jobName +
297                                            ", groupName=" + groupName + "}",
298                                    se);
299                    }
300            }
301    
302            protected void schedule(
303                            Trigger trigger, String description,
304                            String destination, Message message)
305                    throws SchedulerException {
306    
307                    try {
308                            String jobName = trigger.getName();
309                            String groupName = trigger.getGroup();
310    
311                            JobDetail jobDetail = new JobDetail(
312                                    jobName, groupName, MessageSenderJob.class);
313    
314                            JobDataMap jobDataMap = jobDetail.getJobDataMap();
315    
316                            jobDataMap.put(DESCRIPTION, description);
317                            jobDataMap.put(DESTINATION, destination);
318                            jobDataMap.put(MESSAGE, message);
319    
320                            synchronized (this) {
321                                    _scheduler.unscheduleJob(jobName, groupName);
322                                    _scheduler.scheduleJob(jobDetail, trigger);
323                            }
324                    }
325                    catch (ObjectAlreadyExistsException oare) {
326                            if (_log.isInfoEnabled()) {
327                                    _log.info("Message is already scheduled");
328                            }
329                    }
330                    catch (org.quartz.SchedulerException se) {
331                            throw new SchedulerException("Unable to scheduled job", se);
332                    }
333            }
334    
335            @BeanReference(name = "com.liferay.portal.service.QuartzLocalService")
336            protected QuartzLocalService quartzLocalService;
337    
338            private Log _log = LogFactoryUtil.getLog(QuartzSchedulerEngineImpl.class);
339    
340            private Scheduler _scheduler;
341    
342    }