Skip to content
Snippets Groups Projects
Commit 8456efc4 authored by Sergiu Dumitriu's avatar Sergiu Dumitriu
Browse files

Merge branch 'master-A'

parents a4d2f71e e78b7502
No related branches found
No related tags found
No related merge requests found
Showing
with 3050 additions and 0 deletions
<?xml version="1.0" encoding="UTF-8"?>
<!--
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.xwiki.platform.applications</groupId>
<artifactId>xwiki-applications</artifactId>
<version>37-SNAPSHOT</version>
</parent>
<artifactId>xwiki-application-scheduler</artifactId>
<name>XWiki Platform - Applications - Scheduler</name>
<version>1.26-SNAPSHOT</version>
<packaging>xar</packaging>
<description>Manages Scheduler Jobs</description>
<dependencies>
<dependency>
<groupId>com.xpn.xwiki.platform.plugins</groupId>
<artifactId>xwiki-plugin-scheduler</artifactId>
<!-- We want to release the Scheduler plugin and application together. Hence they should have the same version -->
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.xwiki.platform</groupId>
<artifactId>xwiki-core-parent</artifactId>
<version>[2.5,)</version>
<type>pom</type>
<scope>runtime</scope>
</dependency>
</dependencies>
<!-- We must configure SCM in each module. For more information see:
http://svn.xwiki.org/svnroot/xwiki/platform/pom/trunk/pom.xml -->
<scm>
<connection>scm:svn:http://svn.xwiki.org/svnroot/xwiki/platform/xwiki-applications/trunk/scheduler</connection>
<developerConnection>scm:svn:https://svn.xwiki.org/svnroot/xwiki/platform/xwiki-applications/trunk/scheduler</developerConnection>
<url>http://svn.xwiki.org/svnroot/xwiki/platform/xwiki-applications/trunk/scheduler</url>
</scm>
<issueManagement>
<system>jira</system>
<url>http://jira.xwiki.org/jira/browse/XASCH</url>
</issueManagement>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<xwikidoc>
<web>Scheduler</web>
<name>WebHome</name>
<language></language>
<defaultLanguage>en</defaultLanguage>
<translation>0</translation>
<parent>Main.WebHome</parent>
<creator>XWiki.Admin</creator>
<author>XWiki.Admin</author>
<customClass></customClass>
<contentAuthor>XWiki.Admin</contentAuthor>
<creationDate>1252454400000</creationDate>
<date>1288213047000</date>
<contentUpdateDate>1288213047000</contentUpdateDate>
<version>1.1</version>
<title>$msg.get("xe.scheduler")</title>
<template></template>
<defaultTemplate></defaultTemplate>
<validationScript></validationScript>
<comment></comment>
<minorEdit>false</minorEdit>
<syntaxId>xwiki/2.0</syntaxId>
<hidden>false</hidden>
<content>{{velocity}}
## First, set a shortcut to our Scheduler plugin
##
#set($scheduler=$xwiki.scheduler)
##
## If the sheet is called with an action ($request.do), let us first process this action
## Possible values are : "schedule", "pause", "resume", "unschedule", "delete"
##
#if($request.do &amp;&amp; $request.do!="")
##
## Obtain the Job document and object for which the action has been called
##
#set($tJobHolder=$request.which)
#set($jobDoc=$xwiki.getDocument($tJobHolder))
#set($jobObj=$jobDoc.getObject('XWiki.SchedulerJobClass'))
#if($request.do=="schedule")
##
## Schedule a job
##
#set($ok=$scheduler.scheduleJob($jobObj))
#if($ok==false)
{{error}}$xcontext.get('error'){{/error}}
#else
#set($jobName = "$jobObj.get('jobName')")
{{info}}$msg.get('xe.scheduler.jobscheduled', [$jobName, $scheduler.getNextFireTime($jobObj)]){{/info}}
#end
#elseif($request.do=="pause")
##
## Pause a scheduled job
##
#set($ok=$scheduler.pauseJob($jobObj))
#if($ok==false)
{{error}}$xcontext.get('error'){{/error}}
#else
{{info}}$msg.get('xe.scheduler.paused', [$jobObj.get('jobName')]){{/info}}
#end
#elseif($request.do=="resume")
##
## Resume a paused job
##
#set($ok=$scheduler.resumeJob($jobObj))
#if($ok==false)
{{error}}$xcontext.get('error'){{/error}}
#else
{{info}}$msg.get('xe.scheduler.resumed', [$jobObj.get('jobName'), $scheduler.getNextFireTime($jobObj)]){{/info}}
#end
#elseif($request.do=="unschedule")
##
## Unschedule a scheduled job (paused or not)
##
#set($ok=$scheduler.unscheduleJob($jobObj))
#if($ok==false)
{{error}}$xcontext.get('error'){{/error}}
#else
{{info}}$msg.get('xe.scheduler.unscheduled', [$jobObj.get('jobName')]){{/info}}
#end
#elseif($request.do=="delete")
##
## Delete a job
## First unschedule it (if needed), then delete its document holder
##
#set($jobName=$jobObj.get('jobName'))
#if($jobObj.get("status")=="Normal"||$jobObj.get('status')=="Paused")
#set($ok=$scheduler.unscheduleJob($jobObj))
#if($ok==true)
#set($deleteRedirect = $xwiki.getURL($jobObj.getName(),"delete"))
$response.sendRedirect($deleteRedirect)
#else
{{error}}$xcontext.get('error'){{/error}}
#end
#else
#set($deleteRedirect = $xwiki.getURL($jobObj.getName(),"delete"))
$response.sendRedirect($deleteRedirect))
#end
#elseif($request.do=="trigger")
##
## Trigger a job (execute it now)
##
#set($ok=$scheduler.triggerJob($jobObj))
#if($ok==false)
{{error}}$xcontext.get('error'){{/error}}
#else
{{info}}$msg.get('xe.scheduler.triggered', [$jobObj.get('jobName')]){{/info}}
#end
#end
#end
$msg.get('xe.scheduler.welcome')
= $msg.get('xe.scheduler.jobs.list') =
##
## Retrieve all scheduler jobs
## Display their name, status, possible next fire time, and available actions
##
|=(%scope="col"%) $msg.get('xe.scheduler.jobs.name')|=(%scope="col"%) $msg.get('xe.scheduler.jobs.status')|=(%scope="col"%) $msg.get('xe.scheduler.jobs.next')|=(%scope="col"%) $msg.get('xe.scheduler.jobs.actions')
#foreach($docName in $services.query.xwql("from doc.object(XWiki.SchedulerJobClass) as jobs where doc.fullName &lt;&gt; 'XWiki.SchedulerJobTemplate'").execute())
#set($actions = $util.hashMap)## get a hash to store action urls
#set($jobHolder = $xwiki.getDocument($docName))
#set($job = $jobHolder.getObject('XWiki.SchedulerJobClass'))
#set($status = $scheduler.getJobStatus($job).value)
#if($status == "")
#set($status="None")
#end
#set($firetime = "")
#if($status != "None")
#set($firetime = $scheduler.getNextFireTime($job))
#else
#set($firetime="N/A")
#end
#if($status == "None")
#set($ok = $!actions.put("schedule",$doc.getExternalURL("view","do=schedule&amp;which=${jobHolder.fullName}")))
#elseif($status == "Normal")
#set($ok = $!actions.put("pause",$doc.getExternalURL("view","do=pause&amp;which=${jobHolder.fullName}")))
#set($ok = $!actions.put("unschedule",$doc.getExternalURL("view","do=unschedule&amp;which=${jobHolder.fullName}")))
#elseif($status == "Paused")
#set($ok = $!actions.put("resume",$doc.getExternalURL("view","do=resume&amp;which=${jobHolder.fullName}")))
#set($ok = $!actions.put("unschedule",$doc.getExternalURL("view","do=unschedule&amp;which=${jobHolder.fullName}")))
#end
#set($ok = $!actions.put("delete",$doc.getExternalURL("view","do=delete&amp;which=${jobHolder.fullName}")))
#set($ok = $!actions.put("trigger",$doc.getExternalURL("view","do=trigger&amp;which=${jobHolder.fullName}")))
|$job.get("jobName")|$status|$firetime|**$msg.get('xe.scheduler.jobs.infos')**: [[view&gt;&gt;$jobHolder.fullName]]#if($jobHolder.hasAccessLevel("programming")) [[$msg.get("edit")&gt;&gt;${jobHolder.getExternalURL('inline')}]]#end **$msg.get('job')**:#foreach($action in $actions.keySet()) [[$action&gt;&gt;${actions.get($action)}]]#end
#end
#if($doc.hasAccessLevel("programming"))
##
## Job creation is offered only for programmers, because the job page needs to be saved
## with programming right for groovy jobs to be executed.
## However, this page should stay accessibles to admins, that can manipulate existing jobs :
## scheduler, pause, etc.
##
= $msg.get('xe.scheduler.jobs.create') =
##
## Form to create a new Job
##
{{info}}$msg.get('xe.scheduler.jobs.explaincreate'){{/info}}
{{html}}
&lt;form action="" id="newdoc"&gt;
&lt;div&gt;
&lt;input type="hidden" name="form_token" value="$!{services.csrf.getToken()}" /&gt;
&lt;input type="hidden" name="parent" value="Scheduler.WebHome" /&gt;
&lt;input type="hidden" name="template" value="XWiki.SchedulerJobTemplate" /&gt;
&lt;input type="hidden" name="sheet" value="1" /&gt;
&lt;input type="hidden" name="webname" value="Scheduler"/&gt;
&lt;input type="hidden" name="name" value=""/&gt;
&lt;input type="hidden" name="parent" value="${doc.fullName}"/&gt;
&lt;label class="hidden" for="title"&gt;Job page name&lt;/label&gt;
&lt;input id="title" name="title" size="30" type="text" value="Job page name"&gt;&lt;/input&gt;
&lt;span class="buttonwrapper"&gt;&lt;input type="button" class="button" value="$msg.get('xe.scheduler.jobs.add')" onclick='if (updateName(this.form.title,this.form.name)) { action="../../inline/" + this.form.webname.value + "/" + this.form.name.value; this.form.submit(); }' /&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;/form&gt;
{{/html}}
#else
{{warning}}$msg.get('xe.scheduler.jobs.warning')){{/warning}}
#end
{{/velocity}}</content></xwikidoc>
<?xml version="1.0" encoding="UTF-8"?>
<xwikidoc>
<web>Scheduler</web>
<name>WebPreferences</name>
<language></language>
<defaultLanguage>en</defaultLanguage>
<translation>0</translation>
<parent>Scheduler.WebHome</parent>
<creator>XWiki.Admin</creator>
<author>XWiki.Admin</author>
<customClass></customClass>
<contentAuthor>XWiki.Admin</contentAuthor>
<creationDate>1252454400000</creationDate>
<date>1252454400000</date>
<contentUpdateDate>1252454400000</contentUpdateDate>
<version>1.1</version>
<title>Scheduler Space Preferences</title>
<template></template>
<defaultTemplate></defaultTemplate>
<validationScript></validationScript>
<comment></comment>
<minorEdit>false</minorEdit>
<syntaxId>xwiki/2.0</syntaxId>
<hidden>false</hidden>
<object>
<class>
<name>XWiki.XWikiGlobalRights</name>
<customClass></customClass>
<customMapping></customMapping>
<defaultViewSheet></defaultViewSheet>
<defaultEditSheet></defaultEditSheet>
<defaultWeb></defaultWeb>
<nameField></nameField>
<validationScript></validationScript>
<allow>
<defaultValue>1</defaultValue>
<displayFormType>select</displayFormType>
<displayType>allow</displayType>
<name>allow</name>
<number>4</number>
<prettyName>Allow/Deny</prettyName>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.BooleanClass</classType>
</allow>
<groups>
<cache>0</cache>
<displayType>select</displayType>
<multiSelect>1</multiSelect>
<name>groups</name>
<number>1</number>
<prettyName>Groups</prettyName>
<relationalStorage>0</relationalStorage>
<separator> </separator>
<size>5</size>
<unmodifiable>0</unmodifiable>
<usesList>1</usesList>
<classType>com.xpn.xwiki.objects.classes.GroupsClass</classType>
</groups>
<levels>
<cache>0</cache>
<displayType>select</displayType>
<multiSelect>1</multiSelect>
<name>levels</name>
<number>2</number>
<prettyName>Levels</prettyName>
<relationalStorage>0</relationalStorage>
<separator> </separator>
<size>3</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.LevelsClass</classType>
</levels>
<users>
<cache>0</cache>
<displayType>select</displayType>
<multiSelect>1</multiSelect>
<name>users</name>
<number>3</number>
<prettyName>Users</prettyName>
<relationalStorage>0</relationalStorage>
<separator> </separator>
<size>5</size>
<unmodifiable>0</unmodifiable>
<usesList>1</usesList>
<classType>com.xpn.xwiki.objects.classes.UsersClass</classType>
</users>
</class>
<name>Scheduler.WebPreferences</name>
<number>0</number>
<className>XWiki.XWikiGlobalRights</className>
<guid>fcff4443-6524-4b92-adcd-bc97d1f63d58</guid>
<property>
<allow>1</allow>
</property>
<property>
<groups>XWiki.XWikiAdminGroup,</groups>
</property>
<property>
<levels>admin,edit</levels>
</property>
<property>
<users></users>
</property>
</object>
<object>
<class>
<name>XWiki.XWikiGlobalRights</name>
<customClass></customClass>
<customMapping></customMapping>
<defaultViewSheet></defaultViewSheet>
<defaultEditSheet></defaultEditSheet>
<defaultWeb></defaultWeb>
<nameField></nameField>
<validationScript></validationScript>
<allow>
<defaultValue>1</defaultValue>
<displayFormType>select</displayFormType>
<displayType>allow</displayType>
<name>allow</name>
<number>4</number>
<prettyName>Allow/Deny</prettyName>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.BooleanClass</classType>
</allow>
<groups>
<cache>0</cache>
<displayType>select</displayType>
<multiSelect>1</multiSelect>
<name>groups</name>
<number>1</number>
<prettyName>Groups</prettyName>
<relationalStorage>0</relationalStorage>
<separator> </separator>
<size>5</size>
<unmodifiable>0</unmodifiable>
<usesList>1</usesList>
<classType>com.xpn.xwiki.objects.classes.GroupsClass</classType>
</groups>
<levels>
<cache>0</cache>
<displayType>select</displayType>
<multiSelect>1</multiSelect>
<name>levels</name>
<number>2</number>
<prettyName>Levels</prettyName>
<relationalStorage>0</relationalStorage>
<separator> </separator>
<size>3</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.LevelsClass</classType>
</levels>
<users>
<cache>0</cache>
<displayType>select</displayType>
<multiSelect>1</multiSelect>
<name>users</name>
<number>3</number>
<prettyName>Users</prettyName>
<relationalStorage>0</relationalStorage>
<separator> </separator>
<size>5</size>
<unmodifiable>0</unmodifiable>
<usesList>1</usesList>
<classType>com.xpn.xwiki.objects.classes.UsersClass</classType>
</users>
</class>
<name>Scheduler.WebPreferences</name>
<number>1</number>
<className>XWiki.XWikiGlobalRights</className>
<guid>0b2c7da3-315a-4a6d-b782-5de0b20b6497</guid>
<property>
<allow>0</allow>
</property>
<property>
<groups>XWiki.XWikiAllGroup,</groups>
</property>
<property>
<levels>view</levels>
</property>
<property>
<users></users>
</property>
</object>
<object>
<class>
<name>XWiki.XWikiGlobalRights</name>
<customClass></customClass>
<customMapping></customMapping>
<defaultViewSheet></defaultViewSheet>
<defaultEditSheet></defaultEditSheet>
<defaultWeb></defaultWeb>
<nameField></nameField>
<validationScript></validationScript>
<allow>
<defaultValue>1</defaultValue>
<displayFormType>select</displayFormType>
<displayType>allow</displayType>
<name>allow</name>
<number>4</number>
<prettyName>Allow/Deny</prettyName>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.BooleanClass</classType>
</allow>
<groups>
<cache>0</cache>
<displayType>select</displayType>
<multiSelect>1</multiSelect>
<name>groups</name>
<number>1</number>
<prettyName>Groups</prettyName>
<relationalStorage>0</relationalStorage>
<separator> </separator>
<size>5</size>
<unmodifiable>0</unmodifiable>
<usesList>1</usesList>
<classType>com.xpn.xwiki.objects.classes.GroupsClass</classType>
</groups>
<levels>
<cache>0</cache>
<displayType>select</displayType>
<multiSelect>1</multiSelect>
<name>levels</name>
<number>2</number>
<prettyName>Levels</prettyName>
<relationalStorage>0</relationalStorage>
<separator> </separator>
<size>3</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.LevelsClass</classType>
</levels>
<users>
<cache>0</cache>
<displayType>select</displayType>
<multiSelect>1</multiSelect>
<name>users</name>
<number>3</number>
<prettyName>Users</prettyName>
<relationalStorage>0</relationalStorage>
<separator> </separator>
<size>5</size>
<unmodifiable>0</unmodifiable>
<usesList>1</usesList>
<classType>com.xpn.xwiki.objects.classes.UsersClass</classType>
</users>
</class>
<name>Scheduler.WebPreferences</name>
<number>2</number>
<className>XWiki.XWikiGlobalRights</className>
<guid>fef3f075-e0ed-46d1-991f-680326129a9d</guid>
<property>
<allow>0</allow>
</property>
<property>
<groups></groups>
</property>
<property>
<levels>view</levels>
</property>
<property>
<users>XWiki.XWikiGuest</users>
</property>
</object>
<content>{{include document="XWiki.AdminSheet" /}}</content></xwikidoc>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<xwikidoc>
<web>XWiki</web>
<name>SchedulerJobSheet</name>
<language></language>
<defaultLanguage>en</defaultLanguage>
<translation>0</translation>
<parent>XWiki.SchedulerJobClass</parent>
<creator>XWiki.Admin</creator>
<author>XWiki.Admin</author>
<customClass></customClass>
<contentAuthor>XWiki.Admin</contentAuthor>
<creationDate>1252454400000</creationDate>
<date>1274533105000</date>
<contentUpdateDate>1274533105000</contentUpdateDate>
<version>1.1</version>
<title>Scheduler Job Sheet</title>
<template></template>
<defaultTemplate></defaultTemplate>
<validationScript></validationScript>
<comment></comment>
<minorEdit>false</minorEdit>
<syntaxId>xwiki/2.0</syntaxId>
<hidden>false</hidden>
<object>
<class>
<name>XWiki.SheetClass</name>
<customClass></customClass>
<customMapping></customMapping>
<defaultViewSheet></defaultViewSheet>
<defaultEditSheet></defaultEditSheet>
<defaultWeb></defaultWeb>
<nameField></nameField>
<validationScript></validationScript>
<defaultEditMode>
<name>defaultEditMode</name>
<number>1</number>
<prettyName>Default Edit Mode</prettyName>
<size>15</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.StringClass</classType>
</defaultEditMode>
</class>
<name>XWiki.SchedulerJobSheet</name>
<number>0</number>
<className>XWiki.SheetClass</className>
<guid>fc835417-d3d3-4d13-b519-57d2ec39df52</guid>
<property>
<defaultEditMode>inline</defaultEditMode>
</property>
</object>
<content>{{velocity}}
#if($doc.getObject('XWiki.SchedulerJobClass'))
#set($job = $doc.getObject("XWiki.SchedulerJobClass"))
**$msg.get("xe.scheduler.job.name")**
$!doc.display('jobName')
**$msg.get("xe.scheduler.job.description")**
$!doc.display('jobDescription')
**$msg.get("xe.scheduler.job.expression")**
$!doc.display('cron')
**$msg.get("xe.scheduler.job.script")**
#if($xcontext.action=="inline")
$!doc.display("script")
#elseif($xcontext.action=="view" &amp;&amp; "$!job.getProperty('script').value" !="")
{{code language="java"}}
$job.getProperty('script').value
{{/code}}
#end
#if($xcontext.action=="inline")
{{info}}$msg.get('xe.scheduler.job.scriptexplanation')){{/info}}
{{info}}"Below some example of valid cron expression, from the [[official quartz scheduler documentation&gt;&gt;http://www.opensymphony.com/quartz/api/org/quartz/CronExpression.html&gt;_blank]]:
|= Cron expression |= Meaning
| **0 15 10 * * ?** | Fire at 10:15am every day
| **0 15 10 ? * MON-FRI** | Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday
| ** 0 0/5 14 * * ?** | Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day
| ** 0 15 10 ? * 6L** | Fire at 10:15am on the last Friday of every month
{{/info}}
#elseif($xcontext.action=="view")
[[$msg.get("xe.scheduler.job.backtolist")&gt;&gt;Scheduler.WebHome]]
#end
#else
{{warning}}$msg.get('xe.scheduler.job.object'){{/warning}}
#end
{{/velocity}}</content></xwikidoc>
<?xml version="1.0" encoding="UTF-8"?>
<xwikidoc>
<web>XWiki</web>
<name>SchedulerJobTemplate</name>
<language></language>
<defaultLanguage>en</defaultLanguage>
<translation>0</translation>
<parent>XWiki.SchedulerJobClass</parent>
<creator>XWiki.Admin</creator>
<author>XWiki.Admin</author>
<customClass></customClass>
<contentAuthor>XWiki.Admin</contentAuthor>
<creationDate>1252454400000</creationDate>
<date>1252454400000</date>
<contentUpdateDate>1252454400000</contentUpdateDate>
<version>1.1</version>
<title>Scheduler Job Template</title>
<template></template>
<defaultTemplate></defaultTemplate>
<validationScript></validationScript>
<comment></comment>
<minorEdit>false</minorEdit>
<syntaxId>xwiki/2.0</syntaxId>
<hidden>false</hidden>
<object>
<class>
<name>XWiki.SchedulerJobClass</name>
<customClass></customClass>
<customMapping></customMapping>
<defaultViewSheet></defaultViewSheet>
<defaultEditSheet></defaultEditSheet>
<defaultWeb></defaultWeb>
<nameField></nameField>
<validationScript></validationScript>
<contextDatabase>
<name>contextDatabase</name>
<number>9</number>
<prettyName>Job execution context database</prettyName>
<size>30</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.StringClass</classType>
</contextDatabase>
<contextLang>
<name>contextLang</name>
<number>8</number>
<prettyName>Job execution context lang</prettyName>
<size>30</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.StringClass</classType>
</contextLang>
<contextUser>
<name>contextUser</name>
<number>7</number>
<prettyName>Job execution context user</prettyName>
<size>30</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.StringClass</classType>
</contextUser>
<cron>
<name>cron</name>
<number>5</number>
<prettyName>Cron Expression</prettyName>
<size>30</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.StringClass</classType>
</cron>
<jobClass>
<name>jobClass</name>
<number>3</number>
<prettyName>Job Class</prettyName>
<size>60</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.StringClass</classType>
</jobClass>
<jobDescription>
<name>jobDescription</name>
<number>2</number>
<prettyName>Job Description</prettyName>
<rows>10</rows>
<size>45</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.TextAreaClass</classType>
</jobDescription>
<jobName>
<name>jobName</name>
<number>1</number>
<prettyName>Job Name</prettyName>
<size>60</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.StringClass</classType>
</jobName>
<script>
<name>script</name>
<number>6</number>
<prettyName>Job Script</prettyName>
<rows>10</rows>
<size>45</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.TextAreaClass</classType>
</script>
<status>
<name>status</name>
<number>4</number>
<prettyName>Status</prettyName>
<size>30</size>
<unmodifiable>0</unmodifiable>
<classType>com.xpn.xwiki.objects.classes.StringClass</classType>
</status>
</class>
<name>XWiki.SchedulerJobTemplate</name>
<number>0</number>
<className>XWiki.SchedulerJobClass</className>
<guid>8d588ee0-c34d-4616-a74e-822491343730</guid>
<property>
<cron>0 0 12 * * ?</cron>
</property>
<property>
<jobClass>com.xpn.xwiki.plugin.scheduler.GroovyJob</jobClass>
</property>
<property>
<jobDescription></jobDescription>
</property>
<property>
<jobName></jobName>
</property>
<property>
<script></script>
</property>
<property>
<status></status>
</property>
</object>
<content>{{include document="XWiki.SchedulerJobSheet"/}}</content></xwikidoc>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xpn.xwiki.platform.plugins</groupId>
<artifactId>xwiki-plugins</artifactId>
<version>31-SNAPSHOT</version>
</parent>
<artifactId>xwiki-plugin-scheduler</artifactId>
<version>1.26-SNAPSHOT</version>
<name>XWiki Platform - Plugins - Scheduler</name>
<packaging>jar</packaging>
<description>XWiki Platform - Plugins - Scheduler</description>
<dependencies>
<dependency>
<groupId>com.xpn.xwiki.platform</groupId>
<artifactId>xwiki-core</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.opensymphony.quartz</groupId>
<artifactId>quartz</artifactId>
<version>1.6.5</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Needed at run time. Some versions of Maven don't inherit provided dependencies. -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
<!-- The last versions of quartz (> 1.6.3) are not present on the default maven repositories -->
<repositories>
<repository>
<id>JBOSS</id>
<name>JBoss Repository</name>
<url>http://repository.jboss.org/maven2/</url>
</repository>
</repositories>
<!-- We must configure SCM in each module. For more information see:
http://svn.xwiki.org/svnroot/xwiki/platform/pom/trunk/pom.xml -->
<scm>
<connection>scm:svn:http://svn.xwiki.org/svnroot/xwiki/platform/xwiki-plugins/trunk/scheduler</connection>
<developerConnection>scm:svn:https://svn.xwiki.org/svnroot/xwiki/platform/xwiki-plugins/trunk/scheduler</developerConnection>
<url>http://svn.xwiki.org/svnroot/xwiki/platform/xwiki-plugins/trunk/scheduler</url>
</scm>
<issueManagement>
<system>jira</system>
<url>http://jira.xwiki.org/jira/browse/XASCH</url>
</issueManagement>
</project>
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.xpn.xwiki.plugin.scheduler;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.xwiki.context.Execution;
import org.xwiki.context.ExecutionContext;
import org.xwiki.context.ExecutionContextException;
import org.xwiki.context.ExecutionContextManager;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.web.Utils;
/**
* Base class for any XWiki Quartz Job. This class take care of initializing ExecutionContext properly.
* <p>
* A class extending {@link AbstractJob} should implements {@link #executeJob(JobExecutionContext)}.
*
* @since 1.8
* @version $Id$
*/
public abstract class AbstractJob implements Job
{
/**
* {@inheritDoc}
*
* @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
*/
public final void execute(JobExecutionContext jobContext) throws JobExecutionException
{
JobDataMap data = jobContext.getJobDetail().getJobDataMap();
// The XWiki context was saved in the Job execution data map. Get it as we'll retrieve
// the script to execute from it.
XWikiContext xwikiContext = (XWikiContext) data.get("context");
// Init execution context
Execution execution;
try {
ExecutionContextManager ecim = (ExecutionContextManager) Utils.getComponent(ExecutionContextManager.class);
execution = (Execution) Utils.getComponent(Execution.class);
ExecutionContext ec = new ExecutionContext();
// Bridge with old XWiki Context, required for old code.
ec.setProperty("xwikicontext", xwikiContext);
ecim.initialize(ec);
execution.setContext(ec);
} catch (ExecutionContextException e) {
throw new JobExecutionException("Fail to initialize execution context", e);
}
try {
// Execute the job
executeJob(jobContext);
} finally {
// We must ensure we clean the ThreadLocal variables located in the Execution
// component as otherwise we will have a potential memory leak.
execution.removeContext();
}
}
protected abstract void executeJob(JobExecutionContext jobContext) throws JobExecutionException;
}
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.xpn.xwiki.plugin.scheduler;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import org.codehaus.groovy.control.CompilationFailedException;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
/**
* The task that will get executed by the Scheduler when the Job is triggered. This task in turn calls a Groovy script
* to perform the execution.
* <p/>
* <p>
* <b>Important:</b>: Note that the script will execute in the XWiki Context that was set at the time the Job was
* scheduled for execution. For example calling <code>context.getDoc()</code> will return the current document that was
* set at that time and not the current document that is set when the Groovy script executes...
*
* @version $Id$
*/
public class GroovyJob extends AbstractJob
{
/**
* Executes the Groovy script passed in the <code>script</code> property of the
* {@link com.xpn.xwiki.plugin.scheduler.SchedulerPlugin#XWIKI_JOB_CLASS} object extracted from the XWiki context
* passed in the Quartz's Job execution context. The XWiki Task object is looked for in the current document that
* was set in the context at the time the Job was scheduled.
*
* @param jobContext the Quartz execution context containing the XWiki context from which the script to execute is
* retrieved
* @throws JobExecutionException if the script fails to execute or if the user didn't have programming rights when
* the Job was scheduled
* @see Job#execute(org.quartz.JobExecutionContext)
*/
@Override
protected void executeJob(JobExecutionContext jobContext) throws JobExecutionException
{
try {
JobDataMap data = jobContext.getJobDetail().getJobDataMap();
// The XWiki context was saved in the Job execution data map. Get it as we'll retrieve
// the script to execute from it.
XWikiContext context = (XWikiContext) data.get("context");
// Get the job XObject to be executed
BaseObject object = (BaseObject) data.get("xjob");
// Force context document
XWikiDocument jobDocument = context.getWiki().getDocument(object.getName(), context);
context.setDoc(jobDocument);
context.put("sdoc", jobDocument);
if (context.getWiki().getRightService().hasProgrammingRights(context)) {
// Make the Job execution data available to the Groovy script
Binding binding = new Binding(data.getWrappedMap());
// Execute the Groovy script
GroovyShell shell = new GroovyShell(binding);
shell.evaluate(object.getLargeStringValue("script"));
} else {
throw new JobExecutionException("The user [" + context.getUser() + "] didn't have "
+ "programming rights when the job [" + jobContext.getJobDetail().getName() + "] was scheduled.");
}
} catch (CompilationFailedException e) {
throw new JobExecutionException("Failed to execute script for job [" + jobContext.getJobDetail().getName()
+ "]", e, true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.xpn.xwiki.plugin.scheduler;
import org.quartz.Trigger;
/**
* Wrapper around the Quartz trigger's inner state of a Scheduler Job. This class allows to query the actual status of a
* Job as a String, typically to be displayed inside the Wiki
*
* @version $Id$
*/
public class JobState
{
private int state;
public static final String STATE_NORMAL = "Normal";
public static final String STATE_PAUSED = "Paused";
public static final String STATE_BLOCKED = "Blocked";
public static final String STATE_COMPLETE = "Complete";
public static final String STATE_ERROR = "Error";
public static final String STATE_NONE = "None";
public JobState(int state)
{
setState(state);
}
public void setState(int state)
{
this.state = state;
}
public int getState()
{
return this.state;
}
public String getValue()
{
switch (this.state) {
case Trigger.STATE_NORMAL:
return JobState.STATE_NORMAL;
case Trigger.STATE_BLOCKED:
return JobState.STATE_BLOCKED;
case Trigger.STATE_COMPLETE:
return JobState.STATE_COMPLETE;
case Trigger.STATE_ERROR:
return JobState.STATE_ERROR;
case Trigger.STATE_PAUSED:
return JobState.STATE_PAUSED;
case Trigger.STATE_NONE:
default:
return JobState.STATE_NONE;
}
}
}
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.xpn.xwiki.plugin.scheduler;
import java.util.Date;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.SchedulerException;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.api.Document;
import com.xpn.xwiki.api.Object;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.plugin.PluginApi;
/**
* A Scheduler plugin to plan execution of Jobs from XWiki with cron expressions. The plugin uses Quartz's scheduling
* library. <p/> Jobs are represented by {@link com.xpn.xwiki.api.Object} XObjects, instances of the
* {@link SchedulerPlugin#XWIKI_JOB_CLASS} XClass. These XObjects do store a job name, the implementation class name of
* the job to be executed, the cron expression to precise when the job should be fired, and possibly a groovy script
* with the job's program. <p/> The plugin offers a {@link GroovyJob} Groovy Job wrapper to execute groovy scripts
* (typically for use inside the Wiki), but can also be used with any Java class implementing {@link org.quartz.Job}
*
* @version $Id$
*/
public class SchedulerPluginApi extends PluginApi<SchedulerPlugin>
{
/**
* Log object to log messages in this class.
*/
private static final Log LOG = LogFactory.getLog(SchedulerPluginApi.class);
public SchedulerPluginApi(SchedulerPlugin plugin, XWikiContext context)
{
super(plugin, context);
}
/**
* Return the trigger state of the given {@link com.xpn.xwiki.plugin.scheduler.SchedulerPlugin#XWIKI_JOB_CLASS}
* XObject job. Possible values are : None (the trigger does not exists yet, or has been deleted), Normal, Blocked,
* Complete, Error and Paused
*
* @param object the XObject job to give the state of
* @return a String representing this state
*/
public String getStatus(Object object)
{
try {
return getJobStatus(object.getXWikiObject()).getValue();
} catch (Exception e) {
this.context.put("error", e.getMessage());
return null;
}
}
/**
* Return the trigger state as a ${@link JobState}, that holds both the integer trigger's inner value of the state
* and a String as a human readable representation of that state
*/
public JobState getJobStatus(BaseObject object) throws SchedulerException, SchedulerPluginException
{
return getProtectedPlugin().getJobStatus(object, this.context);
}
public JobState getJobStatus(Object object) throws SchedulerException, SchedulerPluginException
{
return getProtectedPlugin().getJobStatus(retrieveBaseObject(object), this.context);
}
/**
* This function allow to retrieve a com.xpn.xwiki.objects.BaseObject from a com.xpn.xwiki.api.Object without that
* the current user needs programming rights (as in com.xpn.xwiki.api.Object#getXWikiObject(). The function is used
* internally by this api class and allows wiki users to call methods from the scheduler without having programming
* right. The programming right is only needed at script execution time.
*
* @return object the unwrapped version of the passed api object
*/
private BaseObject retrieveBaseObject(Object object) throws SchedulerPluginException
{
String docName = object.getName();
int objNb = object.getNumber();
try {
XWikiDocument jobHolder = this.context.getWiki().getDocument(docName, this.context);
BaseObject jobObject = jobHolder.getObject(SchedulerPlugin.XWIKI_JOB_CLASS, objNb);
return jobObject;
} catch (XWikiException e) {
throw new SchedulerPluginException(SchedulerPluginException.ERROR_SCHEDULERPLUGIN_UNABLE_TO_RETRIEVE_JOB,
"Job in document [" + docName + "] with object number [" + objNb + "] could not be retrieved.", e);
}
}
/**
* Schedule the given XObject to be executed according to its parameters. Errors are returned in the context map.
* Scheduling can be called for example: <code> #if($xwiki.scheduler.scheduleJob($job)!=true)
* #error($context.get("error") #else #info("Job scheduled") #end </code>
* Where $job is an XObject, instance of the {@link SchedulerPlugin#XWIKI_JOB_CLASS} XClass
*
* @param object the XObject to be scheduled, an instance of the XClass XWiki.SchedulerJobClass
* @return true on success, false on failure
*/
public boolean scheduleJob(Object object)
{
try {
return scheduleJob(retrieveBaseObject(object));
} catch (Exception e) {
// we don't need to push the exception message in the context here
// as it should already have been pushed by the throwing exception
return false;
}
}
public boolean scheduleJob(BaseObject object)
{
try {
getProtectedPlugin().scheduleJob(object, this.context);
return true;
} catch (Exception e) {
this.context.put("error", e.getMessage());
return false;
}
}
/**
* Schedule all {@link com.xpn.xwiki.plugin.scheduler.SchedulerPlugin#XWIKI_JOB_CLASS} XObjects stored inside the
* given Wiki document, according to each XObject own parameters.
*
* @param document the document holding the XObjects Jobs to be scheduled
* @return true on success, false on failure.
*/
public boolean scheduleJobs(Document document)
{
boolean result = true;
try {
XWikiDocument doc = this.context.getWiki().getDocument(document.getFullName(), this.context);
List<BaseObject> objects = doc.getObjects(SchedulerPlugin.XWIKI_JOB_CLASS);
for (BaseObject object : objects) {
result &= scheduleJob(object);
}
} catch (Exception e) {
this.context.put("error", e.getMessage());
return false;
}
return result;
}
/**
* Pause the given XObject job by pausing all of its current triggers. Can be called the same way as
* {@link #scheduleJob(Object)}
*
* @param object the wrapped XObject Job to be paused
* @return true on success, false on failure.
*/
public boolean pauseJob(Object object)
{
try {
return pauseJob(retrieveBaseObject(object));
} catch (Exception e) {
// we don't need to push the exception message in the context here
// as it should already have been pushed by the throwing exception
return false;
}
}
public boolean pauseJob(BaseObject object)
{
try {
getProtectedPlugin().pauseJob(object, this.context);
LOG.debug("Pause Job : " + object.getStringValue("jobName"));
return true;
} catch (XWikiException e) {
this.context.put("error", e.getMessage());
return false;
}
}
/**
* Resume a XObject job that is in a {@link JobState#STATE_PAUSED} state. Can be called the same way as
* {@link #scheduleJob(Object)}
*
* @param object the wrapped XObject Job to be paused
* @return true on success, false on failure.
*/
public boolean resumeJob(Object object)
{
try {
return resumeJob(retrieveBaseObject(object));
} catch (Exception e) {
// we don't need to push the exception message in the context here
// as it should already have been pushed by the throwing exception
return false;
}
}
public boolean resumeJob(BaseObject object)
{
try {
getProtectedPlugin().resumeJob(object, this.context);
LOG.debug("Resume Job : " + object.getStringValue("jobName"));
return true;
} catch (XWikiException e) {
this.context.put("error", e.getMessage());
return false;
}
}
/**
* Unschedule a XObject job by deleting it from the jobs table. Can be called the same way as
* {@link #scheduleJob(Object)}
*
* @param object the wrapped XObject Job to be paused
* @return true on success, false on failure.
*/
public boolean unscheduleJob(Object object)
{
try {
return unscheduleJob(retrieveBaseObject(object));
} catch (Exception e) {
// we don't need to push the exception message in the context here
// as it should already have been pushed by the throwing exception
return false;
}
}
public boolean unscheduleJob(BaseObject object)
{
try {
getProtectedPlugin().unscheduleJob(object, this.context);
LOG.debug("Delete Job : " + object.getStringValue("jobName"));
return true;
} catch (XWikiException e) {
this.context.put("error", e.getMessage());
return false;
}
}
/**
* Trigger a XObject job (execute it now).
*
* @param object the wrapped XObject Job to be triggered
* @return true on success, false on failure.
*/
public boolean triggerJob(Object object)
{
try {
return triggerJob(retrieveBaseObject(object));
} catch (Exception e) {
// we don't need to push the exception message in the context here
// as it should already have been pushed by the throwing exception
return false;
}
}
/**
* Trigger a BaseObject job (execute it now).
*
* @param object the BaseObject Job to be triggered
* @return true on success, false on failure.
*/
public boolean triggerJob(BaseObject object)
{
try {
getProtectedPlugin().triggerJob(object, this.context);
LOG.debug("Trigger Job : " + object.getStringValue("jobName"));
return true;
} catch (XWikiException e) {
this.context.put("error", e.getMessage());
return false;
}
}
/**
* Give, for a XObject job in a {@link JobState#STATE_NORMAL} state, the previous date at which the job has been
* executed, the fire time is not computed from the CRON expression, this method will return null if the .
*
* @param object the wrapped XObject for which to give the fire time
* @return the date the job has been executed
*/
public Date getPreviousFireTime(Object object)
{
try {
return getPreviousFireTime(retrieveBaseObject(object));
} catch (Exception e) {
// we don't need to push the exception message in the context here
// as it should already have been pushed by the throwing exception
return null;
}
}
/**
* Give, for a BaseObject job in a {@link JobState#STATE_NORMAL} state, the previous date at which the job has been
* executed. Note that this method does not compute a date from the CRON expression, it only returns a date value
* which is set each time the job is executed. If the job has never been fired this method will return null.
*
* @param object the BaseObject for which to give the fire time
* @return the date the job has been executed
*/
public Date getPreviousFireTime(BaseObject object)
{
try {
return getProtectedPlugin().getPreviousFireTime(object, this.context);
} catch (SchedulerPluginException e) {
this.context.put("error", e.getMessage());
return null;
}
}
/**
* Give, for a XObject job in a {@link JobState#STATE_NORMAL} state, the next date at which the job will be
* executed, according to its cron expression. Errors are returned in the context map. Can be called for example:
* <code> #set($firetime = $xwiki.scheduler.getNextFireTime($job))
* #if (!$firetime || $firetime=="") #error($context.get("error") #else #info("Fire time :
* $firetime") #end </code>
* Where $job is an XObject, instance of the {@link SchedulerPlugin#XWIKI_JOB_CLASS} XClass
*
* @param object the wrapped XObject for which to give the fire date
* @return the date the job will be executed
*/
public Date getNextFireTime(Object object)
{
try {
return getNextFireTime(retrieveBaseObject(object));
} catch (Exception e) {
// we don't need to push the exception message in the context here
// as it should already have been pushed by the throwing exception
return null;
}
}
public Date getNextFireTime(BaseObject object)
{
try {
return getProtectedPlugin().getNextFireTime(object, this.context);
} catch (SchedulerPluginException e) {
this.context.put("error", e.getMessage());
return null;
}
}
}
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.xpn.xwiki.plugin.scheduler;
import com.xpn.xwiki.plugin.PluginException;
/**
* An exception that might be thrown when doing various tasks in the scheduler plugin.
*
* @version $Id$
*/
public class SchedulerPluginException extends PluginException
{
protected static final int ERROR_SCHEDULERPLUGIN_SAVE_JOB_CLASS = 90000;
protected static final int ERROR_SCHEDULERPLUGIN_INITIALIZE_STATUS_LISTENER = 90001;
protected static final int ERROR_SCHEDULERPLUGIN_PAUSE_JOB = 90002;
protected static final int ERROR_SCHEDULERPLUGIN_RESUME_JOB = 90003;
protected static final int ERROR_SCHEDULERPLUGIN_SCHEDULE_JOB = 90004;
protected static final int ERROR_SCHEDULERPLUGIN_BAD_CRON_EXPRESSION = 90005;
protected static final int ERROR_SCHEDULERPLUGIN_JOB_XCLASS_NOT_FOUND = 90006;
protected static final int ERROR_SCHEDULERPLUGIN_JOB_DOES_NOT_EXITS = 90007;
protected static final int ERROR_SCHEDULERPLUGIN_GET_SCHEDULER = 90007;
protected static final int ERROR_SCHEDULERPLUGIN_RESTORE_JOB = 90008;
protected static final int ERROR_SCHEDULERPLUGIN_RESTORE_EXISTING_JOBS = 90009;
protected static final int ERROR_SCHEDULERPLUGIN_UNABLE_TO_RETRIEVE_JOB = 90010;
protected static final int ERROR_SCHEDULERPLUGIN_UNABLE_TO_PREPARE_JOB_CONTEXT = 90011;
protected static final int ERROR_SCHEDULERPLUGIN_TRIGGER_JOB = 90012;
public SchedulerPluginException(int code, String message)
{
super(SchedulerPlugin.class, code, message);
}
public SchedulerPluginException(int code, String message, Throwable e, Object[] args)
{
super(SchedulerPlugin.class, code, message, e, args);
}
public SchedulerPluginException(int code, String message, Throwable e)
{
super(SchedulerPlugin.class, code, message, e);
}
}
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.xpn.xwiki.plugin.scheduler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
import org.quartz.SchedulerException;
import org.quartz.SchedulerListener;
import org.quartz.Trigger;
/**
* @version $Id$
*/
public class StatusListener implements SchedulerListener, JobListener
{
/**
* Log4j logger that records events for this class
*/
private static final Log LOG = LogFactory.getLog(StatusListener.class);
/**
* {@inheritDoc}
*/
public void jobScheduled(Trigger trigger)
{
LOG.info("Task '" + trigger.getJobName() + "' scheduled");
}
/**
* {@inheritDoc}
*/
public void jobUnscheduled(String name, String group)
{
LOG.info("Task '" + name + "' unscheduled");
}
/**
* {@inheritDoc}
*/
public void triggerFinalized(Trigger trigger)
{
}
/**
* {@inheritDoc}
*/
public void triggersPaused(String trigger, String group)
{
}
/**
* {@inheritDoc}
*/
public void triggersResumed(String trigger, String group)
{
}
/**
* {@inheritDoc}
*/
public void jobsPaused(String name, String group)
{
LOG.info("Task '" + name + "' paused");
}
/**
* {@inheritDoc}
*/
public void jobsResumed(String name, String group)
{
LOG.info("Task '" + name + "' resumed");
}
/**
* {@inheritDoc}
*/
public void schedulerError(String message, SchedulerException error)
{
LOG.error(message, error);
}
/**
* {@inheritDoc}
*/
public void schedulerShutdown()
{
LOG.warn("Scheduler is shutting down");
}
/**
* {@inheritDoc}
*/
public String getName()
{
return "StatusListener";
}
/**
* {@inheritDoc}
*/
public void jobToBeExecuted(JobExecutionContext context)
{
LOG.info("Task '" + context.getJobDetail().getName() + "' is about to be executed");
}
/**
* {@inheritDoc}
*/
public void jobExecutionVetoed(JobExecutionContext context)
{
}
/**
* {@inheritDoc}
*/
public void jobWasExecuted(JobExecutionContext context, JobExecutionException e)
{
LOG.info("Task '" + context.getJobDetail().getName() + "' executed : " + e);
}
}
package com.xpn.xwiki.plugin.scheduler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
import javax.portlet.PortalContext;
import javax.portlet.PortletMode;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletSession;
import javax.portlet.WindowState;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import com.xpn.xwiki.web.XWikiRequest;
/**
* This stub is intended to simulate a servlet request in a daemon context, in order to be able to create a custom XWiki
* context. This trick is used in the Scheduler plugin to give the job execution thread access to the XWiki api.
*
* @version $Id$
*/
public class XWikiServletRequestStub implements XWikiRequest
{
/** The scheme used by the runtime instance. This is required for creating URLs from scheduled jobs. */
private String scheme;
public XWikiServletRequestStub()
{
this.host = "";
}
private String host;
public void setHost(String host)
{
this.host = host;
}
public String getHeader(String s)
{
if (s.equals("x-forwarded-host")) {
return this.host;
}
return "";
}
public String get(String name)
{
return "";
}
public HttpServletRequest getHttpServletRequest()
{
return null;
}
public Cookie getCookie(String cookieName)
{
return null;
}
public boolean isWindowStateAllowed(WindowState windowState)
{
return false;
}
public boolean isPortletModeAllowed(PortletMode portletMode)
{
return false;
}
public PortletMode getPortletMode()
{
return null;
}
public WindowState getWindowState()
{
return null;
}
public PortletPreferences getPreferences()
{
return null;
}
public PortletSession getPortletSession()
{
return null;
}
public PortletSession getPortletSession(boolean b)
{
return null;
}
public String getProperty(String s)
{
return null;
}
public Enumeration getProperties(String s)
{
return null;
}
public Enumeration getPropertyNames()
{
return null;
}
public PortalContext getPortalContext()
{
return null;
}
public String getAuthType()
{
return "";
}
public Cookie[] getCookies()
{
return new Cookie[0];
}
public long getDateHeader(String s)
{
return 0;
}
public Enumeration getHeaders(String s)
{
return null;
}
public Enumeration getHeaderNames()
{
return null;
}
public int getIntHeader(String s)
{
return 0;
}
public String getMethod()
{
return null;
}
public String getPathInfo()
{
return null;
}
public String getPathTranslated()
{
return null;
}
public String getContextPath()
{
return null;
}
public String getQueryString()
{
return "";
}
public String getRemoteUser()
{
return null;
}
public boolean isUserInRole(String s)
{
return false;
}
public Principal getUserPrincipal()
{
return null;
}
public String getRequestedSessionId()
{
return null;
}
public String getRequestURI()
{
return null;
}
public StringBuffer getRequestURL()
{
return new StringBuffer();
}
public String getServletPath()
{
return null;
}
public HttpSession getSession(boolean b)
{
return null;
}
public HttpSession getSession()
{
return null;
}
public boolean isRequestedSessionIdValid()
{
return false;
}
public String getResponseContentType()
{
return null;
}
public Enumeration getResponseContentTypes()
{
return null;
}
public boolean isRequestedSessionIdFromCookie()
{
return false;
}
public boolean isRequestedSessionIdFromURL()
{
return false;
}
/**
* @deprecated
*/
@Deprecated
public boolean isRequestedSessionIdFromUrl()
{
return false;
}
public Object getAttribute(String s)
{
return null;
}
public Enumeration getAttributeNames()
{
return null;
}
public String getCharacterEncoding()
{
return null;
}
public InputStream getPortletInputStream() throws IOException
{
return null;
}
public void setCharacterEncoding(String s) throws UnsupportedEncodingException
{
}
public int getContentLength()
{
return 0;
}
public String getContentType()
{
return null;
}
public ServletInputStream getInputStream() throws IOException
{
return null;
}
public String getParameter(String s)
{
return null;
}
public Enumeration getParameterNames()
{
return null;
}
public String[] getParameterValues(String s)
{
return new String[0];
}
public Map getParameterMap()
{
return null;
}
public String getProtocol()
{
return null;
}
public void setScheme(String scheme)
{
this.scheme = scheme;
}
public String getScheme()
{
return scheme;
}
public String getServerName()
{
return null;
}
public int getServerPort()
{
return 0;
}
public BufferedReader getReader() throws IOException
{
return null;
}
public String getRemoteAddr()
{
return null;
}
public String getRemoteHost()
{
return null;
}
public void setAttribute(String s, Object o)
{
}
public void removeAttribute(String s)
{
}
public Locale getLocale()
{
return null;
}
public Enumeration getLocales()
{
return null;
}
public boolean isSecure()
{
return false;
}
public RequestDispatcher getRequestDispatcher(String s)
{
return null;
}
/**
* @deprecated
*/
@Deprecated
public String getRealPath(String s)
{
return null;
}
public int getRemotePort()
{
return 0;
}
public String getLocalName()
{
return null;
}
public String getLocalAddr()
{
return null;
}
public int getLocalPort()
{
return 0;
}
}
package com.xpn.xwiki.plugin.scheduler;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Locale;
import java.util.Map;
import javax.portlet.PortletMode;
import javax.portlet.PortletModeException;
import javax.portlet.PortletURL;
import javax.portlet.WindowState;
import javax.portlet.WindowStateException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import com.xpn.xwiki.web.XWikiRequest;
import com.xpn.xwiki.web.XWikiResponse;
/**
* This stub is intended to emulate a servlet response in the daemon context of the scheduler.
*
* @version $Id$
*/
public class XWikiServletResponseStub implements XWikiResponse
{
public HttpServletResponse getHttpServletResponse()
{
return null;
}
public void removeCookie(String arg0, XWikiRequest arg1)
{
}
public void setCharacterEncoding(String arg0)
{
}
public void addCookie(Cookie arg0)
{
}
public void addDateHeader(String arg0, long arg1)
{
}
public void addHeader(String arg0, String arg1)
{
}
public void addIntHeader(String arg0, int arg1)
{
}
public boolean containsHeader(String arg0)
{
return false;
}
public String encodeRedirectURL(String arg0)
{
return null;
}
public String encodeRedirectUrl(String arg0)
{
return null;
}
public String encodeURL(String arg0)
{
// TODO Auto-generated method stub
return null;
}
public String encodeUrl(String arg0)
{
return null;
}
public void sendError(int arg0) throws IOException
{
}
public void sendError(int arg0, String arg1) throws IOException
{
}
public void sendRedirect(String arg0) throws IOException
{
}
public void setDateHeader(String arg0, long arg1)
{
}
public void setHeader(String arg0, String arg1)
{
}
public void setIntHeader(String arg0, int arg1)
{
}
public void setStatus(int arg0)
{
}
public void setStatus(int arg0, String arg1)
{
}
public void flushBuffer() throws IOException
{
}
public int getBufferSize()
{
return 0;
}
public String getCharacterEncoding()
{
return null;
}
public String getContentType()
{
return null;
}
public Locale getLocale()
{
return null;
}
public ServletOutputStream getOutputStream() throws IOException
{
return null;
}
public PrintWriter getWriter() throws IOException
{
return null;
}
public boolean isCommitted()
{
return false;
}
public void reset()
{
}
public void resetBuffer()
{
}
public void setBufferSize(int arg0)
{
}
public void setContentLength(int arg0)
{
}
public void setContentType(String arg0)
{
}
public void setLocale(Locale arg0)
{
}
public PortletURL createActionURL()
{
return null;
}
public PortletURL createRenderURL()
{
return null;
}
public String getNamespace()
{
return null;
}
public OutputStream getPortletOutputStream() throws IOException
{
return null;
}
public void setTitle(String arg0)
{
}
public void addProperty(String arg0, String arg1)
{
}
public void setProperty(String arg0, String arg1)
{
}
public void setPortletMode(PortletMode arg0) throws PortletModeException
{
}
public void setRenderParameter(String arg0, String arg1)
{
}
public void setRenderParameter(String arg0, String[] arg1)
{
}
public void setRenderParameters(Map arg0)
{
}
public void setWindowState(WindowState arg0) throws WindowStateException
{
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment