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