Wiki source code of Create Scheduler jobs in Java
Last modified by Lavinia Vitel on 2020/08/24 16:54
Show last authors
| author | version | line-number | content |
|---|---|---|---|
| 1 | XWiki provides a [[Scheduler Application>>extensions:Extension.Scheduler Application]] that offers the possiblity of creating jobs and perform actions on these jobs (Schedule, Trigger, Cancel ...). | ||
| 2 | |||
| 3 | Jobs created by the scheduler application executes a Groovy script periodicaly following a predifined period that is using a Cron expression. | ||
| 4 | |||
| 5 | A Scheduler Job is an **XWiki.SchedulerJobClass** object attached to a wiki page. | ||
| 6 | |||
| 7 | The script to excute is set in the Job Script property of the **XWiki.SchedulerJobClass** object, it is a groovy script. | ||
| 8 | |||
| 9 | In this post we will provide a solution to use Java code instead of Groovy in the Job Script. | ||
| 10 | |||
| 11 | == Use Java in the job script == | ||
| 12 | |||
| 13 | To use java in the Job script you will need 2 steps: | ||
| 14 | 1) Create a java class that extends **com.xpn.xwiki.plugin.scheduler.AbstractJob** class and implements the **org.quartz.Job** interface. | ||
| 15 | 2) Set the Job **class** property with the full java class name and let the Job script property empty. | ||
| 16 | |||
| 17 | === Create the java class === | ||
| 18 | |||
| 19 | The class will need a Cron expression to be used to execute the job periodically. The Cron expression will be provided by the Scheduler Job object. | ||
| 20 | |||
| 21 | In the java class we will need to override the **executeJob** method that will be called periodically from the scheduler. | ||
| 22 | |||
| 23 | We will take the **watchlist scheduler jobs**. as an example, the Scheduler job page is **Scheduler.WatchListDailyNotifier** in your Wiki and the java class is [[here>>https://github.com/xwiki/xwiki-platform/blob/master/xwiki-platform-core/xwiki-platform-watchlist/xwiki-platform-watchlist-api/src/main/java/org/xwiki/watchlist/internal/job/WatchListJob.java]] | ||
| 24 | |||
| 25 | ==== Methods that need to be defined in the class ==== | ||
| 26 | |||
| 27 | **init** method: Sets objects required by the Job : XWiki, XWikiContext, Components ... etc. | ||
| 28 | |||
| 29 | {{code}} | ||
| 30 | ... | ||
| 31 | public void init(JobExecutionContext jobContext) throws Exception | ||
| 32 | { | ||
| 33 | JobDataMap data = jobContext.getJobDetail().getJobDataMap(); | ||
| 34 | |||
| 35 | this.watchlist = Utils.getComponent(WatchList.class); | ||
| 36 | this.schedulerJobObject = (BaseObject) data.get("xjob"); | ||
| 37 | this.watchListJobObject = | ||
| 38 | getXWikiContext().getWiki().getDocument(this.schedulerJobObject.getDocumentReference(), getXWikiContext()) | ||
| 39 | .getXObject(WatchListJobClassDocumentInitializer.DOCUMENT_REFERENCE); | ||
| 40 | } | ||
| 41 | ... | ||
| 42 | {{/code}} | ||
| 43 | |||
| 44 | **executeJob** method: Method called from the scheduler. | ||
| 45 | |||
| 46 | {{code}} | ||
| 47 | ... | ||
| 48 | @Override | ||
| 49 | public void executeJob(JobExecutionContext jobContext) throws JobExecutionException | ||
| 50 | { | ||
| 51 | try { | ||
| 52 | init(jobContext); | ||
| 53 | |||
| 54 | if (this.watchListJobObject == null) { | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | |||
| 58 | Collection<String> subscribers = getSubscribers(); | ||
| 59 | |||
| 60 | // Stop here if nobody is interested. | ||
| 61 | if (!hasSubscribers()) { | ||
| 62 | return; | ||
| 63 | } | ||
| 64 | |||
| 65 | // Determine what happened since the last execution for everybody. | ||
| 66 | Date previousFireTime = getPreviousFireTime(); | ||
| 67 | WatchListEventMatcher eventMatcher = Utils.getComponent(WatchListEventMatcher.class); | ||
| 68 | List<WatchListEvent> events = eventMatcher.getEventsSince(previousFireTime); | ||
| 69 | setPreviousFireTime(); | ||
| 70 | |||
| 71 | // Stop here if nothing happened in the meantime. | ||
| 72 | if (events.size() == 0) { | ||
| 73 | return; | ||
| 74 | } | ||
| 75 | |||
| 76 | // Notify all the interested subscribers of the events that occurred. | ||
| 77 | // When processing the events, a subscriber will only be notified of events that interest him. | ||
| 78 | Map<String, Object> notificationData = new HashMap<>(); | ||
| 79 | notificationData.put(DefaultWatchListNotifier.PREVIOUS_FIRE_TIME_VARIABLE, previousFireTime); | ||
| 80 | |||
| 81 | String mailTemplate = | ||
| 82 | this.watchListJobObject.getStringValue(WatchListJobClassDocumentInitializer.TEMPLATE_FIELD); | ||
| 83 | notificationData.put(WatchListEventMimeMessageFactory.TEMPLATE_PARAMETER, mailTemplate); | ||
| 84 | |||
| 85 | // Send the notification for processing. | ||
| 86 | this.watchlist.getNotifier().sendNotification(subscribers, events, notificationData); | ||
| 87 | } catch (Exception e) { | ||
| 88 | // We're in a job, we don't throw exceptions | ||
| 89 | LOGGER.error("Exception while running job", e); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | ... | ||
| 93 | {{/code}} | ||
| 94 | |||
| 95 | Find a complete example here: https://github.com/xwiki/xwiki-platform/blob/master/xwiki-platform-core/xwiki-platform-watchlist/xwiki-platform-watchlist-api/src/main/java/org/xwiki/watchlist/internal/job/WatchListJob.java | ||
| 96 | |||
| 97 | === Set the Job class property with the java full class name === | ||
| 98 | |||
| 99 | Edit the **Scheduler.WatchListDailyNotifier** in Object mode and update the **Job class** property of the **XWiki.SchedulerJobClass** object with the full java class name and let the **Job script** property empty. | ||
| 100 | |||
| 101 | {{image reference="edit-job.png"/}} | ||
| 102 | //Scheduler job object// | ||
| 103 | |||
| 104 | == Conclusion == | ||
| 105 | |||
| 106 | This approach will allow you to take advantage of all power that Java provides in scheduler jobs. |