001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.scheduler.quartz;
016    
017    import com.liferay.portal.kernel.bean.BeanReference;
018    import com.liferay.portal.kernel.dao.db.DB;
019    import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
020    import com.liferay.portal.kernel.json.JSONFactoryUtil;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.messaging.Message;
024    import com.liferay.portal.kernel.scheduler.IntervalTrigger;
025    import com.liferay.portal.kernel.scheduler.JobState;
026    import com.liferay.portal.kernel.scheduler.JobStateSerializeUtil;
027    import com.liferay.portal.kernel.scheduler.SchedulerEngine;
028    import com.liferay.portal.kernel.scheduler.SchedulerException;
029    import com.liferay.portal.kernel.scheduler.StorageType;
030    import com.liferay.portal.kernel.scheduler.TriggerFactoryUtil;
031    import com.liferay.portal.kernel.scheduler.TriggerState;
032    import com.liferay.portal.kernel.scheduler.TriggerType;
033    import com.liferay.portal.kernel.scheduler.messaging.SchedulerResponse;
034    import com.liferay.portal.kernel.util.CharPool;
035    import com.liferay.portal.kernel.util.ServerDetector;
036    import com.liferay.portal.kernel.util.StringPool;
037    import com.liferay.portal.kernel.util.Time;
038    import com.liferay.portal.scheduler.job.MessageSenderJob;
039    import com.liferay.portal.service.QuartzLocalService;
040    import com.liferay.portal.util.PropsUtil;
041    import com.liferay.portal.util.PropsValues;
042    
043    import java.text.ParseException;
044    
045    import java.util.ArrayList;
046    import java.util.Date;
047    import java.util.List;
048    import java.util.Map;
049    import java.util.Properties;
050    
051    import org.quartz.CronTrigger;
052    import org.quartz.JobDataMap;
053    import org.quartz.JobDetail;
054    import org.quartz.ObjectAlreadyExistsException;
055    import org.quartz.Scheduler;
056    import org.quartz.SimpleTrigger;
057    import org.quartz.Trigger;
058    import org.quartz.impl.StdSchedulerFactory;
059    
060    /**
061     * @author Michael C. Han
062     * @author Bruno Farache
063     * @author Shuyang Zhou
064     * @author Wesley Gong
065     * @author Tina Tian
066     */
067    public class QuartzSchedulerEngine implements SchedulerEngine {
068    
069            public void afterPropertiesSet() {
070                    if (!PropsValues.SCHEDULER_ENABLED) {
071                            return;
072                    }
073    
074                    try {
075                            quartzLocalService.checkQuartzTables();
076    
077                            _persistedScheduler = initializeScheduler(
078                                    "persisted.scheduler.", true);
079    
080                            _memoryScheduler = initializeScheduler("memory.scheduler.", false);
081                    }
082                    catch (Exception e) {
083                            _log.error("Unable to initialize engine", e);
084                    }
085            }
086    
087            public void delete(String groupName) throws SchedulerException {
088                    if (!PropsValues.SCHEDULER_ENABLED) {
089                            return;
090                    }
091    
092                    try {
093                            Scheduler scheduler = getScheduler(groupName);
094    
095                            delete(scheduler, groupName);
096                    }
097                    catch (Exception e) {
098                            throw new SchedulerException(
099                                    "Unable to delete jobs in group " + groupName, e);
100                    }
101            }
102    
103            public void delete(String jobName, String groupName)
104                    throws SchedulerException {
105    
106                    if (!PropsValues.SCHEDULER_ENABLED) {
107                            return;
108                    }
109    
110                    try {
111                            Scheduler scheduler = getScheduler(groupName);
112    
113                            delete(scheduler, jobName, groupName);
114                    }
115                    catch (Exception e) {
116                            throw new SchedulerException(
117                                    "Unable to delete job {jobName=" + jobName + ", groupName=" +
118                                            groupName + "}",
119                                    e);
120                    }
121            }
122    
123            public void destroy() {
124                    try {
125                            shutdown();
126                    }
127                    catch (SchedulerException se) {
128                            if (_log.isWarnEnabled()) {
129                                    _log.warn("Unable to shutdown", se);
130                            }
131                    }
132            }
133    
134            public SchedulerResponse getScheduledJob(String jobName, String groupName)
135                    throws SchedulerException {
136    
137                    if (!PropsValues.SCHEDULER_ENABLED) {
138                            return null;
139                    }
140    
141                    try {
142                            Scheduler scheduler = getScheduler(groupName);
143    
144                            return getScheduledJob(scheduler, jobName, groupName);
145                    }
146                    catch (Exception e) {
147                            throw new SchedulerException(
148                                    "Unable to get job {jobName=" + jobName + ", groupName=" +
149                                            groupName + "}",
150                                    e);
151                    }
152            }
153    
154            public List<SchedulerResponse> getScheduledJobs()
155                    throws SchedulerException {
156    
157                    if (!PropsValues.SCHEDULER_ENABLED) {
158                            return null;
159                    }
160    
161                    try {
162                            String[] groupNames = _persistedScheduler.getJobGroupNames();
163    
164                            List<SchedulerResponse> schedulerResponses =
165                                    new ArrayList<SchedulerResponse>();
166    
167                            for (String groupName : groupNames) {
168                                    schedulerResponses.addAll(
169                                            getScheduledJobs(_persistedScheduler, groupName));
170                            }
171    
172                            groupNames = _memoryScheduler.getJobGroupNames();
173    
174                            for (String groupName : groupNames) {
175                                    schedulerResponses.addAll(
176                                            getScheduledJobs(_memoryScheduler, groupName));
177                            }
178    
179                            return schedulerResponses;
180                    }
181                    catch (Exception e) {
182                            throw new SchedulerException("Unable to get jobs", e);
183                    }
184            }
185    
186            public List<SchedulerResponse> getScheduledJobs(String groupName)
187                    throws SchedulerException {
188    
189                    if (!PropsValues.SCHEDULER_ENABLED) {
190                            return null;
191                    }
192    
193                    try {
194                            Scheduler scheduler = getScheduler(groupName);
195    
196                            return getScheduledJobs(scheduler, groupName);
197                    }
198                    catch (Exception e) {
199                            throw new SchedulerException(
200                                    "Unable to get jobs in group " + groupName, e);
201                    }
202            }
203    
204            public void pause(String groupName) throws SchedulerException {
205                    if (!PropsValues.SCHEDULER_ENABLED) {
206                            return;
207                    }
208    
209                    try {
210                            Scheduler scheduler = getScheduler(groupName);
211    
212                            pause(scheduler, groupName);
213                    }
214                    catch (Exception e) {
215                            throw new SchedulerException(
216                                    "Unable to pause jobs in group " + groupName, e);
217                    }
218            }
219    
220            public void pause(String jobName, String groupName)
221                    throws SchedulerException {
222    
223                    if (!PropsValues.SCHEDULER_ENABLED) {
224                            return;
225                    }
226    
227                    try {
228                            Scheduler scheduler = getScheduler(groupName);
229    
230                            pause(scheduler, jobName, groupName);
231                    }
232                    catch (Exception e) {
233                            throw new SchedulerException(
234                                    "Unable to pause job {jobName=" + jobName + ", groupName=" +
235                                            groupName + "}",
236                                    e);
237                    }
238            }
239    
240            public void resume(String groupName) throws SchedulerException {
241                    if (!PropsValues.SCHEDULER_ENABLED) {
242                            return;
243                    }
244    
245                    try {
246                            Scheduler scheduler = getScheduler(groupName);
247    
248                            resume(scheduler, groupName);
249                    }
250                    catch (Exception e) {
251                            throw new SchedulerException(
252                                    "Unable to resume jobs in group " + groupName, e);
253                    }
254            }
255    
256            public void resume(String jobName, String groupName)
257                    throws SchedulerException {
258    
259                    if (!PropsValues.SCHEDULER_ENABLED) {
260                            return;
261                    }
262    
263                    try {
264                            Scheduler scheduler = getScheduler(groupName);
265    
266                            resume(scheduler, jobName, groupName);
267                    }
268                    catch (Exception e) {
269                            throw new SchedulerException(
270                                    "Unable to resume job {jobName=" + jobName + ", groupName=" +
271                                            groupName + "}",
272                                    e);
273                    }
274            }
275    
276            public void schedule(
277                            com.liferay.portal.kernel.scheduler.Trigger trigger,
278                            String description, String destination, Message message)
279                    throws SchedulerException {
280    
281                    if (!PropsValues.SCHEDULER_ENABLED) {
282                            return;
283                    }
284    
285                    try {
286                            Scheduler scheduler = getScheduler(trigger.getGroupName());
287    
288                            StorageType storageType = getStorageType(trigger.getGroupName());
289    
290                            trigger = TriggerFactoryUtil.buildTrigger(
291                                    trigger.getTriggerType(), trigger.getJobName(),
292                                    getOriginalGroupName(trigger.getGroupName()),
293                                    trigger.getStartDate(), trigger.getEndDate(),
294                                    trigger.getTriggerContent());
295    
296                            Trigger quartzTrigger = getQuartzTrigger(trigger);
297    
298                            if (quartzTrigger == null) {
299                                    return;
300                            }
301    
302                            description = fixMaxLength(description, DESCRIPTION_MAX_LENGTH);
303    
304                            if (message == null) {
305                                    message = new Message();
306                            }
307                            else {
308                                    message = message.clone();
309                            }
310    
311                            message.put(RECEIVER_KEY, quartzTrigger.getFullJobName());
312    
313                            schedule(
314                                    scheduler, storageType, quartzTrigger, description, destination,
315                                    message);
316                    }
317                    catch (RuntimeException re) {
318    
319                            // ServerDetector will throw an exception when JobSchedulerImpl is
320                            // initialized in a test environment
321    
322                    }
323                    catch (Exception e) {
324                            throw new SchedulerException("Unable to schedule job", e);
325                    }
326            }
327    
328            public void shutdown() throws SchedulerException {
329                    if (!PropsValues.SCHEDULER_ENABLED) {
330                            return;
331                    }
332    
333                    try {
334                            if (!_persistedScheduler.isShutdown()) {
335                                    _persistedScheduler.shutdown(false);
336                            }
337    
338                            if (!_memoryScheduler.isShutdown()) {
339                                    _memoryScheduler.shutdown(false);
340                            }
341                    }
342                    catch (Exception e) {
343                            throw new SchedulerException("Unable to shutdown scheduler", e);
344                    }
345            }
346    
347            public void start() throws SchedulerException {
348                    if (!PropsValues.SCHEDULER_ENABLED) {
349                            return;
350                    }
351    
352                    try {
353                            _persistedScheduler.start();
354    
355                            initJobState();
356    
357                            _memoryScheduler.start();
358                    }
359                    catch (Exception e) {
360                            throw new SchedulerException("Unable to start scheduler", e);
361                    }
362            }
363    
364            public void suppressError(String jobName, String groupName)
365                    throws SchedulerException {
366    
367                    if (!PropsValues.SCHEDULER_ENABLED) {
368                            return;
369                    }
370    
371                    try {
372                            Scheduler scheduler = getScheduler(groupName);
373    
374                            suppressError(jobName, groupName, scheduler);
375                    }
376                    catch (Exception e) {
377                            throw new SchedulerException(
378                                    "Unable to suppress error for job {jobName=" + jobName +
379                                            ", groupName=" + groupName + "}",
380                                    e);
381                    }
382            }
383    
384            public void unschedule(String groupName) throws SchedulerException {
385                    if (!PropsValues.SCHEDULER_ENABLED) {
386                            return;
387                    }
388    
389                    try {
390                            Scheduler scheduler = getScheduler(groupName);
391    
392                            unschedule(groupName, scheduler);
393                    }
394                    catch (Exception e) {
395                            throw new SchedulerException(
396                                    "Unable to unschedule jobs in group " + groupName, e);
397                    }
398            }
399    
400            public void unschedule(String jobName, String groupName)
401                    throws SchedulerException {
402    
403                    if (!PropsValues.SCHEDULER_ENABLED) {
404                            return;
405                    }
406    
407                    try {
408                            Scheduler scheduler = getScheduler(groupName);
409    
410                            unschedule(jobName, groupName, scheduler);
411                    }
412                    catch (Exception e) {
413                            throw new SchedulerException(
414                                    "Unable to unschedule job {jobName=" + jobName +
415                                            ", groupName=" + groupName + "}",
416                                    e);
417                    }
418            }
419    
420            public void update(com.liferay.portal.kernel.scheduler.Trigger trigger)
421                    throws SchedulerException {
422    
423                    if (!PropsValues.SCHEDULER_ENABLED) {
424                            return;
425                    }
426    
427                    try {
428                            Scheduler scheduler = getScheduler(trigger.getGroupName());
429    
430                            trigger = TriggerFactoryUtil.buildTrigger(
431                                    trigger.getTriggerType(), trigger.getJobName(),
432                                    getOriginalGroupName(trigger.getGroupName()),
433                                    trigger.getStartDate(), trigger.getEndDate(),
434                                    trigger.getTriggerContent());
435    
436                            update(scheduler, trigger);
437                    }
438                    catch (Exception e) {
439                            throw new SchedulerException("Unable to update trigger", e);
440                    }
441            }
442    
443            protected void delete(Scheduler scheduler, String groupName)
444                    throws Exception {
445    
446                    groupName = fixMaxLength(
447                            getOriginalGroupName(groupName), GROUP_NAME_MAX_LENGTH);
448    
449                    String[] jobNames = scheduler.getJobNames(groupName);
450    
451                    for (String jobName : jobNames) {
452                            delete(scheduler, jobName, groupName);
453                    }
454            }
455    
456            protected void delete(Scheduler scheduler, String jobName, String groupName)
457                    throws Exception {
458    
459                    jobName = fixMaxLength(jobName, JOB_NAME_MAX_LENGTH);
460                    groupName = fixMaxLength(
461                            getOriginalGroupName(groupName), GROUP_NAME_MAX_LENGTH);
462    
463                    scheduler.deleteJob(jobName, groupName);
464            }
465    
466            protected String fixMaxLength(String argument, int maxLength) {
467                    if (argument == null) {
468                            return null;
469                    }
470    
471                    if (argument.length() > maxLength) {
472                            argument = argument.substring(0, maxLength);
473                    }
474    
475                    return argument;
476            }
477    
478            protected String getFullName(String jobName, String groupName) {
479                    return groupName.concat(StringPool.PERIOD).concat(jobName);
480            }
481    
482            protected JobState getJobState(JobDataMap jobDataMap) {
483                    Map<String, Object> jobStateMap = (Map<String, Object>)jobDataMap.get(
484                            JOB_STATE);
485    
486                    return JobStateSerializeUtil.deserialize(jobStateMap);
487            }
488    
489            protected Message getMessage(JobDataMap jobDataMap) {
490                    String messageJSON = (String)jobDataMap.get(MESSAGE);
491    
492                    return (Message)JSONFactoryUtil.deserialize(messageJSON);
493            }
494    
495            protected String getOriginalGroupName(String groupName) {
496                    int pos = groupName.indexOf(CharPool.POUND);
497    
498                    return groupName.substring(pos + 1);
499            }
500    
501            protected Trigger getQuartzTrigger(
502                            com.liferay.portal.kernel.scheduler.Trigger trigger)
503                    throws SchedulerException {
504    
505                    if (trigger == null) {
506                            return null;
507                    }
508    
509                    String jobName = fixMaxLength(
510                            trigger.getJobName(), JOB_NAME_MAX_LENGTH);
511                    String groupName = fixMaxLength(
512                            trigger.getGroupName(), GROUP_NAME_MAX_LENGTH);
513    
514                    Trigger quartzTrigger = null;
515    
516                    TriggerType triggerType = trigger.getTriggerType();
517    
518                    if (triggerType.equals(TriggerType.CRON)) {
519                            try {
520                                    quartzTrigger = new CronTrigger(
521                                            jobName, groupName, (String)trigger.getTriggerContent());
522                            }
523                            catch (ParseException pe) {
524                                    throw new SchedulerException(
525                                            "Unable to parse cron text " + trigger.getTriggerContent());
526                            }
527                    }
528                    else if (triggerType.equals(TriggerType.SIMPLE)) {
529                            long interval = (Long)trigger.getTriggerContent();
530    
531                            if (interval <= 0) {
532                                    if (_log.isDebugEnabled()) {
533                                            _log.debug(
534                                                    "Not scheduling " + trigger.getJobName() +
535                                                            " because interval is less than or equal to 0");
536                                    }
537    
538                                    return null;
539                            }
540    
541                            quartzTrigger = new SimpleTrigger(
542                                    jobName, groupName, SimpleTrigger.REPEAT_INDEFINITELY,
543                                    interval);
544                    }
545                    else {
546                            throw new SchedulerException(
547                                    "Unknown trigger type " + trigger.getTriggerType());
548                    }
549    
550                    quartzTrigger.setJobName(jobName);
551                    quartzTrigger.setJobGroup(groupName);
552    
553                    Date startDate = trigger.getStartDate();
554    
555                    if (startDate == null) {
556                            if (ServerDetector.getServerId().equals(ServerDetector.TOMCAT_ID)) {
557                                    quartzTrigger.setStartTime(
558                                            new Date(System.currentTimeMillis() + Time.MINUTE));
559                            }
560                            else {
561                                    quartzTrigger.setStartTime(
562                                            new Date(System.currentTimeMillis() + Time.MINUTE * 3));
563                            }
564                    }
565                    else {
566                            quartzTrigger.setStartTime(startDate);
567                    }
568    
569                    Date endDate = trigger.getEndDate();
570    
571                    if (endDate != null) {
572                            quartzTrigger.setEndTime(endDate);
573                    }
574    
575                    return quartzTrigger;
576            }
577    
578            protected SchedulerResponse getScheduledJob(
579                            Scheduler scheduler, String jobName, String groupName)
580                    throws Exception {
581    
582                    jobName = fixMaxLength(jobName, JOB_NAME_MAX_LENGTH);
583                    groupName = fixMaxLength(
584                            getOriginalGroupName(groupName), GROUP_NAME_MAX_LENGTH);
585    
586                    JobDetail jobDetail = scheduler.getJobDetail(
587                            jobName, groupName);
588    
589                    if (jobDetail == null) {
590                            return null;
591                    }
592    
593                    JobDataMap jobDataMap = jobDetail.getJobDataMap();
594    
595                    String description = jobDataMap.getString(DESCRIPTION);
596                    String destinationName = jobDataMap.getString(DESTINATION_NAME);
597                    Message message = getMessage(jobDataMap);
598                    StorageType storageType = StorageType.valueOf(
599                            jobDataMap.getString(STORAGE_TYPE));
600    
601                    SchedulerResponse schedulerResponse = null;
602    
603                    Trigger trigger = scheduler.getTrigger(jobName, groupName);
604    
605                    JobState jobState = getJobState(jobDataMap);
606    
607                    message.put(JOB_STATE, jobState);
608    
609                    if (trigger == null) {
610                            schedulerResponse = new SchedulerResponse();
611    
612                            schedulerResponse.setDescription(description);
613                            schedulerResponse.setDestinationName(destinationName);
614                            schedulerResponse.setGroupName(groupName);
615                            schedulerResponse.setJobName(jobName);
616                            schedulerResponse.setMessage(message);
617                            schedulerResponse.setStorageType(storageType);
618                    }
619                    else {
620                            message.put(END_TIME, trigger.getEndTime());
621                            message.put(FINAL_FIRE_TIME, trigger.getFinalFireTime());
622                            message.put(NEXT_FIRE_TIME, trigger.getNextFireTime());
623                            message.put(PREVIOUS_FIRE_TIME, trigger.getPreviousFireTime());
624                            message.put(START_TIME, trigger.getStartTime());
625    
626                            if (CronTrigger.class.isAssignableFrom(trigger.getClass())) {
627    
628                                    CronTrigger cronTrigger = CronTrigger.class.cast(trigger);
629    
630                                    schedulerResponse = new SchedulerResponse();
631    
632                                    schedulerResponse.setDescription(description);
633                                    schedulerResponse.setDestinationName(destinationName);
634                                    schedulerResponse.setMessage(message);
635                                    schedulerResponse.setStorageType(storageType);
636                                    schedulerResponse.setTrigger(
637                                            new com.liferay.portal.kernel.scheduler.CronTrigger(
638                                                    jobName, groupName, cronTrigger.getStartTime(),
639                                                    cronTrigger.getEndTime(),
640                                                    cronTrigger.getCronExpression()));
641                            }
642                            else if (SimpleTrigger.class.isAssignableFrom(
643                                                    trigger.getClass())) {
644    
645                                    SimpleTrigger simpleTrigger = SimpleTrigger.class.cast(
646                                            trigger);
647    
648                                    schedulerResponse = new SchedulerResponse();
649    
650                                    schedulerResponse.setDescription(description);
651                                    schedulerResponse.setDestinationName(destinationName);
652                                    schedulerResponse.setMessage(message);
653                                    schedulerResponse.setStorageType(storageType);
654                                    schedulerResponse.setTrigger(
655                                            new IntervalTrigger(
656                                                    jobName, groupName, simpleTrigger.getStartTime(),
657                                                    simpleTrigger.getEndTime(),
658                                                    simpleTrigger.getRepeatInterval()));
659                            }
660                    }
661    
662                    return schedulerResponse;
663            }
664    
665            protected List<SchedulerResponse> getScheduledJobs(
666                            Scheduler scheduler, String groupName)
667                    throws Exception {
668    
669                    groupName = fixMaxLength(
670                            getOriginalGroupName(groupName), GROUP_NAME_MAX_LENGTH);
671    
672                    List<SchedulerResponse> schedulerResponses =
673                            new ArrayList<SchedulerResponse>();
674    
675                    String[] jobNames = scheduler.getJobNames(groupName);
676    
677                    for (String jobName : jobNames) {
678                            SchedulerResponse schedulerResponse = getScheduledJob(
679                                    scheduler, jobName, groupName);
680    
681                            if (schedulerResponse != null) {
682                                    schedulerResponses.add(schedulerResponse);
683                            }
684                    }
685    
686                    return schedulerResponses;
687            }
688    
689            protected Scheduler getScheduler(String groupName) throws Exception {
690                    if (groupName.startsWith(StorageType.PERSISTED.toString())) {
691                            return _persistedScheduler;
692                    }
693                    else {
694                            return _memoryScheduler;
695                    }
696            }
697    
698            protected StorageType getStorageType(String groupName) {
699                    int pos = groupName.indexOf(CharPool.POUND);
700    
701                    String storageTypeString = groupName.substring(0, pos);
702    
703                    return StorageType.valueOf(storageTypeString);
704            }
705    
706            protected Scheduler initializeScheduler(
707                            String propertiesPrefix, boolean useQuartzCluster)
708                    throws Exception {
709    
710                    StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
711    
712                    Properties properties = PropsUtil.getProperties(propertiesPrefix, true);
713    
714                    if (useQuartzCluster && PropsValues.CLUSTER_LINK_ENABLED) {
715                            DB db = DBFactoryUtil.getDB();
716    
717                            String dbType = db.getType();
718    
719                            if (dbType.equals(DB.TYPE_HYPERSONIC)) {
720                                    _log.error("Unable to cluster scheduler on Hypersonic");
721                            }
722                            else {
723                                    properties.put(
724                                            "org.quartz.jobStore.isClustered", Boolean.TRUE.toString());
725                            }
726                    }
727    
728                    schedulerFactory.initialize(properties);
729    
730                    return schedulerFactory.getScheduler();
731            }
732    
733            protected void initJobState() throws Exception {
734                    String [] groupNames = _persistedScheduler.getJobGroupNames();
735    
736                    for (String groupName : groupNames) {
737                            String[] jobNames = _persistedScheduler.getJobNames(groupName);
738    
739                            for (String jobName : jobNames) {
740                                    Trigger trigger = _persistedScheduler.getTrigger(
741                                            jobName, groupName);
742    
743                                    if (trigger != null) {
744                                            continue;
745                                    }
746    
747                                    JobDetail jobDetail = _persistedScheduler.getJobDetail(
748                                            jobName, groupName);
749    
750                                    JobDataMap jobDataMap = jobDetail.getJobDataMap();
751    
752                                    JobState jobState = getJobState(jobDataMap);
753    
754                                    jobState.setTriggerState(TriggerState.COMPLETE);
755    
756                                    jobDataMap.put(
757                                            JOB_STATE, JobStateSerializeUtil.serialize(jobState));
758    
759                                    _persistedScheduler.addJob(jobDetail, true);
760                            }
761                    }
762            }
763    
764            protected void pause(Scheduler scheduler, String groupName)
765                    throws Exception {
766    
767                    groupName = fixMaxLength(
768                            getOriginalGroupName(groupName), GROUP_NAME_MAX_LENGTH);
769    
770                    String[] jobNames = scheduler.getJobNames(groupName);
771    
772                    for (String jobName : jobNames) {
773                            updateJobState(
774                                    scheduler, jobName, groupName, TriggerState.PAUSED, false);
775                    }
776    
777                    scheduler.pauseJobGroup(groupName);
778            }
779    
780            protected void pause(Scheduler scheduler, String jobName, String groupName)
781                    throws Exception {
782    
783                    jobName = fixMaxLength(jobName, JOB_NAME_MAX_LENGTH);
784                    groupName = fixMaxLength(
785                            getOriginalGroupName(groupName), GROUP_NAME_MAX_LENGTH);
786    
787                    updateJobState(
788                            scheduler, jobName, groupName, TriggerState.PAUSED, false);
789    
790                    scheduler.pauseJob(jobName, groupName);
791            }
792    
793            protected void resume(Scheduler scheduler, String groupName)
794                    throws Exception {
795    
796                    groupName = fixMaxLength(
797                            getOriginalGroupName(groupName), GROUP_NAME_MAX_LENGTH);
798    
799                    String[] jobNames = scheduler.getJobNames(groupName);
800    
801                    for (String jobName : jobNames) {
802                            updateJobState(
803                                    scheduler, jobName, groupName, TriggerState.NORMAL, false);
804                    }
805    
806                    scheduler.resumeJobGroup(groupName);
807            }
808    
809            protected void resume(Scheduler scheduler, String jobName, String groupName)
810                    throws Exception {
811    
812                    jobName = fixMaxLength(jobName, JOB_NAME_MAX_LENGTH);
813                    groupName = fixMaxLength(
814                            getOriginalGroupName(groupName), GROUP_NAME_MAX_LENGTH);
815    
816                    updateJobState(
817                            scheduler, jobName, groupName, TriggerState.NORMAL, false);
818    
819                    scheduler.resumeJob(jobName, groupName);
820            }
821    
822            protected void schedule(
823                            Scheduler scheduler, StorageType storageType, Trigger trigger,
824                            String description, String destinationName, Message message)
825                    throws Exception {
826    
827                    try {
828                            String jobName = trigger.getName();
829                            String groupName = trigger.getGroup();
830    
831                            JobDetail jobDetail = new JobDetail(
832                                    jobName, groupName, MessageSenderJob.class);
833    
834                            JobDataMap jobDataMap = jobDetail.getJobDataMap();
835    
836                            jobDataMap.put(DESCRIPTION, description);
837                            jobDataMap.put(DESTINATION_NAME, destinationName);
838                            jobDataMap.put(MESSAGE, JSONFactoryUtil.serialize(message));
839                            jobDataMap.put(STORAGE_TYPE, storageType.toString());
840    
841                            JobState jobState = new JobState(
842                                    TriggerState.NORMAL, message.getInteger(EXCEPTIONS_MAX_SIZE));
843    
844                            jobDataMap.put(
845                                    JOB_STATE, JobStateSerializeUtil.serialize(jobState));
846    
847                            if (scheduler == _persistedScheduler) {
848                                    jobDetail.setDurability(true);
849                            }
850    
851                            synchronized (this) {
852                                    scheduler.deleteJob(jobName, groupName);
853                                    scheduler.scheduleJob(jobDetail, trigger);
854                            }
855                    }
856                    catch (ObjectAlreadyExistsException oare) {
857                            if (_log.isInfoEnabled()) {
858                                    _log.info("Message is already scheduled");
859                            }
860                    }
861            }
862    
863            protected void suppressError(
864                            String jobName, String groupName, Scheduler scheduler)
865                    throws Exception {
866    
867                    jobName = fixMaxLength(jobName, JOB_NAME_MAX_LENGTH);
868                    groupName = fixMaxLength(
869                            getOriginalGroupName(groupName), GROUP_NAME_MAX_LENGTH);
870    
871                    updateJobState(scheduler, jobName, groupName, null, true);
872            }
873    
874            protected void unschedule(String groupName, Scheduler scheduler)
875                    throws Exception {
876    
877                    groupName = fixMaxLength(
878                            getOriginalGroupName(groupName), GROUP_NAME_MAX_LENGTH);
879    
880                    String[] jobNames = scheduler.getJobNames(groupName);
881    
882                    for (String jobName : jobNames) {
883                            unschedule(jobName, groupName, scheduler);
884                    }
885            }
886    
887            protected void unschedule(
888                            String jobName, String groupName, Scheduler scheduler)
889                    throws Exception {
890    
891                    jobName = fixMaxLength(jobName, JOB_NAME_MAX_LENGTH);
892                    groupName = fixMaxLength(
893                            getOriginalGroupName(groupName), GROUP_NAME_MAX_LENGTH);
894    
895                    JobDetail jobDetail = scheduler.getJobDetail(jobName, groupName);
896    
897                    if (jobDetail == null) {
898                            return;
899                    }
900    
901                    if (scheduler == _memoryScheduler) {
902                            scheduler.unscheduleJob(jobName, groupName);
903    
904                            return;
905                    }
906    
907                    JobDataMap jobDataMap = jobDetail.getJobDataMap();
908    
909                    JobState jobState = getJobState(jobDataMap);
910    
911                    Trigger trigger = scheduler.getTrigger(jobName, groupName);
912    
913                    jobState.setTriggerDate(END_TIME, new Date());
914                    jobState.setTriggerDate(FINAL_FIRE_TIME, trigger.getPreviousFireTime());
915                    jobState.setTriggerDate(NEXT_FIRE_TIME, null);
916                    jobState.setTriggerDate(
917                            PREVIOUS_FIRE_TIME, trigger.getPreviousFireTime());
918                    jobState.setTriggerDate(START_TIME, trigger.getStartTime());
919    
920                    jobState.setTriggerState(TriggerState.UNSCHEDULED);
921    
922                    jobState.clearExceptions();
923    
924                    jobDataMap.put(JOB_STATE, JobStateSerializeUtil.serialize(jobState));
925    
926                    scheduler.unscheduleJob(jobName, groupName);
927    
928                    scheduler.addJob(jobDetail, true);
929            }
930    
931            protected void update(
932                            Scheduler scheduler,
933                            com.liferay.portal.kernel.scheduler.Trigger trigger)
934                    throws Exception {
935    
936                    Trigger quartzTrigger = getQuartzTrigger(trigger);
937    
938                    if (quartzTrigger == null) {
939                            return;
940                    }
941    
942                    String jobName = quartzTrigger.getJobName();
943                    String groupName = quartzTrigger.getGroup();
944    
945                    if (scheduler.getTrigger(jobName, groupName) != null) {
946                            scheduler.rescheduleJob(jobName, groupName, quartzTrigger);
947                    }
948                    else {
949                            JobDetail jobDetail = scheduler.getJobDetail(jobName, groupName);
950    
951                            if (jobDetail == null) {
952                                    return;
953                            }
954    
955                            updateJobState(
956                                    scheduler, jobName, groupName, TriggerState.NORMAL, true);
957    
958                            synchronized (this) {
959                                    scheduler.deleteJob(jobName, groupName);
960                                    scheduler.scheduleJob(jobDetail, quartzTrigger);
961                            }
962                    }
963            }
964    
965            protected void updateJobState(
966                            Scheduler scheduler, String jobName, String groupName,
967                            TriggerState triggerState, boolean suppressError)
968                    throws Exception {
969    
970                    JobDetail jobDetail = scheduler.getJobDetail(jobName, groupName);
971    
972                    JobDataMap jobDataMap = jobDetail.getJobDataMap();
973    
974                    JobState jobState = getJobState(jobDataMap);
975    
976                    if (triggerState != null) {
977                            jobState.setTriggerState(triggerState);
978                    }
979    
980                    if (suppressError) {
981                            jobState.clearExceptions();
982                    }
983    
984                    jobDataMap.put(JOB_STATE, JobStateSerializeUtil.serialize(jobState));
985    
986                    scheduler.addJob(jobDetail, true);
987            }
988    
989            @BeanReference(name = "com.liferay.portal.service.QuartzLocalService")
990            protected QuartzLocalService quartzLocalService;
991    
992            private static Log _log = LogFactoryUtil.getLog(
993                    QuartzSchedulerEngine.class);
994    
995            private Scheduler _memoryScheduler;
996            private Scheduler _persistedScheduler;
997    
998    }