Author: vmassol
Date: 2007-09-27 11:41:37 +0200 (Thu, 27 Sep 2007)
New Revision: 5104
Added:
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/GroovyJob.java
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/JobState.java
Removed:
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/GroovyTask.java
Modified:
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPlugin.java
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginApi.java
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginException.java
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/StatusListener.java
Log:
XASCH-2: Implement a Scheduler plugin
Patch submitted by Jerome Velociter
Modifed:
* Applied XWiki coding standards
* Reverted changed to LOG --> log and the removal of final in StatusListener
Added:
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/GroovyJob.java
===================================================================
---
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/GroovyJob.java
2007-09-26 21:31:28 UTC (rev 5103)
+++
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/GroovyJob.java
2007-09-27 09:41:37 UTC (rev 5104)
@@ -0,0 +1,88 @@
+/*
+ * 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.api.Context;
+import com.xpn.xwiki.objects.BaseObject;
+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;
+
+/**
+ * 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 implements Job
+{
+ /**
+ * Executes the Groovy script passed in the <code>script</code> property
of the [EMAIL PROTECTED]
+ * 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 context 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)
+ */
+ public void execute(JobExecutionContext context) throws
JobExecutionException
+ {
+ try {
+ JobDataMap data = context.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.
+ Context xcontext = (Context) data.get("context");
+
+ if (xcontext.hasProgrammingRights()) {
+
+ // Get the job XObject to be executed
+ BaseObject object = (BaseObject) data.get("xjob");
+
+ // 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 [" +
xcontext.getUser() + "] didn't have "
+ + "programming rights when the job [" +
context.getJobDetail().getName()
+ + "] was scheduled.");
+ }
+ } catch (CompilationFailedException e) {
+ throw new JobExecutionException("Failed to execute script for job
["
+ + context.getJobDetail().getName() + "]", e, true);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
Deleted:
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/GroovyTask.java
===================================================================
---
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/GroovyTask.java
2007-09-26 21:31:28 UTC (rev 5103)
+++
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/GroovyTask.java
2007-09-27 09:41:37 UTC (rev 5104)
@@ -1,99 +0,0 @@
-/*
- * 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.objects.BaseObject;
-import com.xpn.xwiki.api.Api;
-import com.xpn.xwiki.api.Context;
-
-/**
- * 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><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 GroovyTask implements Job
-{
- /**
- * Executes the Groovy script passed in the <code>script</code> property
of the
- * [EMAIL PROTECTED]
com.xpn.xwiki.plugin.scheduler.SchedulerPlugin#TASK_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 context the Quartz execution context containing the XWiki
context from which the
- * script to execute is retrieved
- * @exception 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)
- */
- public void execute(JobExecutionContext context) throws
JobExecutionException
- {
- try {
- JobDataMap data = context.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.
- Context xcontext = (Context) data.get("context");
-
- if (xcontext.hasProgrammingRights()) {
-
- // The current task id. This is needed to find the correct
XWiki Task object that
- // was stored in the current document as there can be several
tasks stored in that
- // document.
- int task = data.getInt("task");
-
- // Get the correct task object from the current doc set when
the Job was
- // scheduled.
- // TODO: I think it would be much cleaner to store the XWiki
Task object directly
- // in the Job execution context rather than having to assume
it's in the current
- // document that was set at that time... Fix this!
- BaseObject object =
xcontext.getDoc().getObject(SchedulerPlugin.TASK_CLASS, task);
-
- // 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 [" +
xcontext.getUser() + "] didn't have "
- + "programming rights when the job [" +
context.getJobDetail().getName()
- + "] was scheduled.");
- }
- } catch (CompilationFailedException e) {
- throw new JobExecutionException("Failed to execute script for job
["
- + context.getJobDetail().getName() + "]", e, true);
- }
- }
-}
Added:
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/JobState.java
===================================================================
---
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/JobState.java
2007-09-26 21:31:28 UTC (rev 5103)
+++
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/JobState.java
2007-09-27 09:41:37 UTC (rev 5104)
@@ -0,0 +1,77 @@
+/*
+ * 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
+ */
+public class JobState
+{
+ public static final String NORMAL = "Normal";
+
+ public static final String PAUSED = "Paused";
+
+ public static final String BLOCKED = "Blocked";
+
+ public static final String COMPLETE = "Complete";
+
+ public static final String ERROR = "Error";
+
+ public static final String NONE = "None";
+
+ private int state;
+
+ 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.NORMAL;
+ case Trigger.STATE_BLOCKED:
+ return JobState.BLOCKED;
+ case Trigger.STATE_COMPLETE:
+ return JobState.COMPLETE;
+ case Trigger.STATE_ERROR:
+ return JobState.ERROR;
+ case Trigger.STATE_PAUSED:
+ return JobState.PAUSED;
+ case Trigger.STATE_NONE:
+ default:
+ return JobState.NONE;
+ }
+ }
+}
Modified:
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPlugin.java
===================================================================
---
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPlugin.java
2007-09-26 21:31:28 UTC (rev 5103)
+++
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPlugin.java
2007-09-27 09:41:37 UTC (rev 5104)
@@ -19,18 +19,6 @@
*/
package com.xpn.xwiki.plugin.scheduler;
-import java.text.ParseException;
-import java.util.Date;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.quartz.CronTrigger;
-import org.quartz.JobDataMap;
-import org.quartz.JobDetail;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
-import org.quartz.Trigger;
-import org.quartz.impl.StdSchedulerFactory;
import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
@@ -39,16 +27,27 @@
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.classes.BaseClass;
-import com.xpn.xwiki.plugin.PluginException;
import com.xpn.xwiki.plugin.XWikiDefaultPlugin;
import com.xpn.xwiki.plugin.XWikiPluginInterface;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.quartz.CronTrigger;
+import org.quartz.JobDataMap;
+import org.quartz.JobDetail;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.impl.StdSchedulerFactory;
+import java.text.ParseException;
+import java.util.Date;
+
/**
* See [EMAIL PROTECTED] com.xpn.xwiki.plugin.scheduler.SchedulerPluginApi}
for documentation.
*
* @version $Id: $
*/
-public class SchedulerPlugin extends XWikiDefaultPlugin implements
XWikiPluginInterface
+public class SchedulerPlugin extends XWikiDefaultPlugin
{
/**
* Log object to log messages in this class.
@@ -56,21 +55,17 @@
private static final Log LOG = LogFactory.getLog(SchedulerPlugin.class);
/**
- * Fullname of the XWiki Task Class representing a task that can be
scheduled by this plugin.
+ * Fullname of the XWiki Scheduler Job Class representing a job that can
be scheduled by this
+ * plugin.
*/
- public static final String TASK_CLASS = "XWiki.Task";
-
+ public static final String XWIKI_JOB_CLASS = "XWiki.SchedulerJobClass";
+
/**
* Default Quartz scheduler instance.
*/
private Scheduler scheduler;
/**
- * Map that holds Job execution data.
- */
- private JobDataMap data = new JobDataMap();
-
- /**
* [EMAIL PROTECTED]
*
* @see
XWikiDefaultPlugin#XWikiDefaultPlugin(String,String,com.xpn.xwiki.XWikiContext)
@@ -79,17 +74,19 @@
{
super(name, className, context);
init(context);
+ //TODO: restaure existing jobs (according to their stored status)
}
/**
* [EMAIL PROTECTED]
+ *
* @see
com.xpn.xwiki.plugin.XWikiPluginInterface#init(com.xpn.xwiki.XWikiContext)
*/
public void init(XWikiContext context)
{
super.init(context);
try {
- updateTaskClass(context);
+ updateSchedulerJobClass(context);
setScheduler(getDefaultSchedulerInstance());
setStatusListener();
getScheduler().start();
@@ -102,6 +99,7 @@
/**
* [EMAIL PROTECTED]
+ *
* @see
com.xpn.xwiki.plugin.XWikiPluginInterface#virtualInit(com.xpn.xwiki.XWikiContext)
*/
public void virtualInit(XWikiContext context)
@@ -111,24 +109,38 @@
}
/**
- * Schedule the given task by creating a job and associating a cron
trigger with it
+ * Retrieve the job's status of a given [EMAIL PROTECTED]
com.xpn.xwiki.plugin.scheduler.SchedulerPlugin#XWIKI_JOB_CLASS}
+ * job XObject, by asking the actual job status to the quartz scheduler
instance. It's the
+ * actual status, as the one stored in the XObject may be changed manually
by users.
*
- * @param object the XWiki Task object
- * @param context the XWiki context
+ * @param object the XObject to give the status of
+ * @return the status of the Job inside the quartz scheduler, as [EMAIL
PROTECTED]
+ * com.xpn.xwiki.plugin.scheduler.JobState} instance
*/
- public boolean scheduleTask(BaseObject object, XWikiContext context)
+ public JobState getJobStatus(BaseObject object) throws SchedulerException
+ {
+ int state = getScheduler()
+ .getTriggerState(getObjectUniqueId(object),
Scheduler.DEFAULT_GROUP);
+ return new JobState(state);
+ }
+
+ public boolean scheduleJob(BaseObject object, XWikiContext context)
throws SchedulerPluginException
{
boolean scheduled = true;
try {
- String task = String.valueOf(object.getNumber());
+ JobDataMap data = new JobDataMap();
- JobDetail job = new JobDetail(task, Scheduler.DEFAULT_GROUP,
- Class.forName(object.getStringValue("taskClass")), true,
false, true);
- Trigger trigger = new CronTrigger(task, Scheduler.DEFAULT_GROUP,
task,
+ // compute the job unique Id
+ String xjob = getObjectUniqueId(object);
+
+ JobDetail job = new JobDetail(xjob, Scheduler.DEFAULT_GROUP,
+ Class.forName(object.getStringValue("jobClass")));
+
+ Trigger trigger = new CronTrigger(xjob, Scheduler.DEFAULT_GROUP,
xjob,
Scheduler.DEFAULT_GROUP, object.getStringValue("cron"));
- data.put("task", object.getNumber());
+ data.put("xjob", object);
// We offer the Job a wrapped copy of the request context and of
the XWiki API
Context copy = new Context((XWikiContext) context.clone());
@@ -138,135 +150,160 @@
job.setJobDataMap(data);
getScheduler().addJob(job, true);
- int state = getScheduler().getTriggerState(task,
Scheduler.DEFAULT_GROUP);
- switch (state) {
+
+ JobState status = getJobStatus(object);
+
+ switch (status.getState()) {
case Trigger.STATE_PAUSED:
- object.setStringValue("status", "Paused");
+ // a paused job must be resumed, not scheduled
break;
case Trigger.STATE_NORMAL:
- if (getTrigger(task).compareTo(trigger) != 0) {
- LOG.debug("Reschedule Task : " +
object.getStringValue("taskName"));
+ if (getTrigger(object).compareTo(trigger) != 0) {
+ LOG.debug("Reschedule Job : " +
object.getStringValue("jobName"));
}
getScheduler().rescheduleJob(trigger.getName(),
trigger.getGroup(), trigger);
- object.setStringValue("status", "Scheduled");
break;
case Trigger.STATE_NONE:
- LOG.debug("Schedule Task : " +
object.getStringValue("taskName"));
+ LOG.debug("Schedule Job : " +
object.getStringValue("jobName"));
getScheduler().scheduleJob(trigger);
- LOG.info("XWiki Task Status :" +
object.getStringValue("status"));
+ LOG.info("XWiki Job Status :" +
object.getStringValue("status"));
if (object.getStringValue("status").equals("Paused")) {
- getScheduler().pauseJob(task, Scheduler.DEFAULT_GROUP);
- object.setStringValue("status", "Paused");
+ getScheduler().pauseJob(xjob, Scheduler.DEFAULT_GROUP);
+ saveStatus("Paused", object, context);
} else {
- object.setStringValue("status", "Scheduled");
+ saveStatus("Normal", object, context);
}
break;
default:
- LOG.debug("Schedule Task : " +
object.getStringValue("taskName"));
+ LOG.debug("Schedule Job : " +
object.getStringValue("jobName"));
getScheduler().scheduleJob(trigger);
- object.setStringValue("status", "Scheduled");
+ saveStatus("Normal", object, context);
break;
}
} catch (SchedulerException e) {
throw new SchedulerPluginException(
- SchedulerPluginException.ERROR_SCHEDULERPLUGIN_SCHEDULE_TASK,
- "Error while scheduling task " +
object.getStringValue("taskName"), e);
+ SchedulerPluginException.ERROR_SCHEDULERPLUGIN_SCHEDULE_JOB,
+ "Error while scheduling job " +
object.getStringValue("jobName"), e);
} catch (ParseException e) {
throw new SchedulerPluginException(
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_BAD_CRON_EXPRESSION,
- "Error while parsing cron expression for task " +
object.getStringValue("taskName"),
+ "Error while parsing cron expression for job " +
object.getStringValue("jobName"),
e);
} catch (ClassNotFoundException e) {
throw new SchedulerPluginException(
-
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_TASK_CLASS_NOT_FOUND,
- "Error while loading task class for task : " +
object.getStringValue("taskName"),
+
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_JOB_XCLASS_NOT_FOUND,
+ "Error while loading job class for job : " +
object.getStringValue("jobName"),
e);
+ } catch (XWikiException e) {
+ throw new SchedulerPluginException(
+
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_JOB_XCLASS_NOT_FOUND,
+ "Error while saving job status for job : " +
object.getStringValue("jobName"),
+ e);
}
return scheduled;
}
/**
- * Pause the task with the given name by pausing all of its current
triggers.
+ * Pause the job with the given name by pausing all of its current
triggers.
*
- * @param taskName the name of the task to be paused
+ * @param object the non-wrapped XObject Job to be paused
*/
- public void pauseTask(String taskName) throws SchedulerPluginException
+ public void pauseJob(BaseObject object, XWikiContext context) throws
SchedulerPluginException
{
try {
- getScheduler().pauseJob(taskName, Scheduler.DEFAULT_GROUP);
+ getScheduler().pauseJob(getObjectUniqueId(object),
Scheduler.DEFAULT_GROUP);
+ saveStatus("Paused", object, context);
} catch (SchedulerException e) {
throw new SchedulerPluginException(
- SchedulerPluginException.ERROR_SCHEDULERPLUGIN_PAUSE_TASK,
- "Error occured while trying to pause task " + taskName, e);
+ SchedulerPluginException.ERROR_SCHEDULERPLUGIN_PAUSE_JOB,
+ "Error occured while trying to pause job " +
object.getStringValue("jobName"), e);
+ } catch (XWikiException e) {
+ throw new SchedulerPluginException(
+ SchedulerPluginException.ERROR_SCHEDULERPLUGIN_PAUSE_JOB,
+ "Error occured while trying to save status of job " +
+ object.getStringValue("jobName"), e);
}
}
/**
- * Resume the task with the given name (un-pause)
+ * Resume the job with the given name (un-pause)
*
- * @param taskName the name of the task to be paused
+ * @param object the non-wrapped XObject Job to be resumed
*/
- public void resumeTask(String taskName) throws PluginException
+ public void resumeJob(BaseObject object, XWikiContext context) throws
SchedulerPluginException
{
try {
- getScheduler().resumeJob(taskName, Scheduler.DEFAULT_GROUP);
+ getScheduler().resumeJob(getObjectUniqueId(object),
Scheduler.DEFAULT_GROUP);
+ saveStatus("Normal", object, context);
} catch (SchedulerException e) {
throw new SchedulerPluginException(
- SchedulerPluginException.ERROR_SCHEDULERPLUGIN_RESUME_TASK,
- "Error occured while trying to resume task " + taskName, e);
+ SchedulerPluginException.ERROR_SCHEDULERPLUGIN_RESUME_JOB,
+ "Error occured while trying to resume job " +
object.getStringValue("jobName"), e);
+ } catch (XWikiException e) {
+ throw new SchedulerPluginException(
+ SchedulerPluginException.ERROR_SCHEDULERPLUGIN_RESUME_JOB,
+ "Error occured while trying to save status of job " +
+ object.getStringValue("jobName"), e);
}
}
/**
- * Unschedule the given task
+ * Unschedule the given job
*
- * @param taskName the task name for the task to be unscheduled
+ * @param object the unwrapped XObject job to be unscheduled
*/
- public void unscheduleTask(String taskName) throws SchedulerPluginException
+ public void unscheduleJob(BaseObject object, XWikiContext context)
+ throws SchedulerPluginException
{
try {
- getScheduler().deleteJob(taskName, Scheduler.DEFAULT_GROUP);
+ getScheduler().deleteJob(getObjectUniqueId(object),
Scheduler.DEFAULT_GROUP);
+ saveStatus("None", object, context);
} catch (SchedulerException e) {
throw new SchedulerPluginException(
-
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_TASK_CLASS_NOT_FOUND,
- "Error while unscheduling task " + taskName, e);
+
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_JOB_XCLASS_NOT_FOUND,
+ "Error while unscheduling job " +
object.getStringValue("jobName"), e);
+ } catch (XWikiException e) {
+ throw new SchedulerPluginException(
+
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_JOB_XCLASS_NOT_FOUND,
+ "Error while saving status of job " +
object.getStringValue("jobName"), e);
}
}
/**
- * Get Trigger object of the given task
+ * Get Trigger object of the given job
*
- * @param task the task name for which the trigger will be given
- * @return the trigger object of the given task
+ * @param object the unwrapped XObject to be retrieve the trigger for
+ * @return the trigger object of the given job
*/
- private Trigger getTrigger(String task) throws SchedulerPluginException
+ private Trigger getTrigger(BaseObject object) throws
SchedulerPluginException
{
+ String job = getObjectUniqueId(object);
Trigger trigger;
try {
- trigger = getScheduler().getTrigger(task, Scheduler.DEFAULT_GROUP);
+ trigger = getScheduler().getTrigger(job, Scheduler.DEFAULT_GROUP);
} catch (SchedulerException e) {
throw new SchedulerPluginException(
-
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_TASK_CLASS_NOT_FOUND,
- "Error while getting trigger for task " + task, e);
+
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_JOB_XCLASS_NOT_FOUND,
+ "Error while getting trigger for job " + job, e);
}
if (trigger == null) {
throw new SchedulerPluginException(
-
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_TASK_DOES_NOT_EXITS,
- "Task does not exists");
+
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_JOB_DOES_NOT_EXITS,
+ "Job does not exists");
}
return trigger;
}
/**
- * Get the next fire time for the given task name Task
+ * Get the next fire time for the given job name SchedulerJob
*
- * @param task the task name for which the next fire time will be given
- * @return the next Date the task will be fired at
+ * @param object unwrapped XObject job for which the next fire time will
be given
+ * @return the next Date the job will be fired at
*/
- public Date getNextFireTime(String task) throws SchedulerPluginException
+ public Date getNextFireTime(BaseObject object) throws
SchedulerPluginException
{
- return getTrigger(task).getNextFireTime();
+ return getTrigger(object).getNextFireTime();
}
/**
@@ -303,9 +340,8 @@
/**
* @return the default Scheduler instance
- * @exception SchedulerPluginException if the default Scheduler instance
failed to be
- * retrieved for any reason. Note that on the first call the
default scheduler is
- * also initialized.
+ * @throws SchedulerPluginException if the default Scheduler instance
failed to be retrieved for
+ * any reason. Note that on the first call the default scheduler is also
initialized.
*/
private synchronized Scheduler getDefaultSchedulerInstance()
throws SchedulerPluginException
@@ -323,7 +359,8 @@
/**
* Associates the scheduler with a StatusListener
- * @exception SchedulerPluginException if the status listener failed to be
set properly
+ *
+ * @throws SchedulerPluginException if the status listener failed to be
set properly
*/
private void setStatusListener() throws SchedulerPluginException
{
@@ -338,43 +375,65 @@
}
}
+ private void saveStatus(String status, BaseObject object, XWikiContext
context)
+ throws XWikiException
+ {
+ XWikiDocument jobHolder =
context.getWiki().getDocument(object.getName(), context);
+ object.setStringValue("status", status);
+ context.getWiki().saveDocument(jobHolder, context);
+ }
+
/**
- * Creates the XWiki Task Class if it does not exist in the wiki. Update
it if it exists but
- * is missing some properties.
+ * Compute a cross-document unique [EMAIL PROTECTED]
com.xpn.xwiki.objects.BaseObject} id, by concatenating
+ * its name (it's document holder full name, such as "SomeSpace.SomeDoc")
and it's instance
+ * number inside this document. <p/> The scheduler uses this unique object
id to assure the
+ * unicity of jobs
*
+ * @return a unique String that can identify the object
+ */
+ private String getObjectUniqueId(BaseObject object)
+ {
+ return object.getName() + "_" + object.getNumber();
+ }
+
+ /**
+ * Creates the XWiki SchedulerJob XClass if it does not exist in the wiki.
Update it if it
+ * exists but is missing some properties.
+ *
* @param context the XWiki context
- * @exception SchedulerPluginException if the updated Task Class failed to
be saved
+ * @throws SchedulerPluginException if the updated SchedulerJob XClass
failed to be saved
*/
- private void updateTaskClass(XWikiContext context) throws
SchedulerPluginException
+ private void updateSchedulerJobClass(XWikiContext context) throws
SchedulerPluginException
{
XWiki xwiki = context.getWiki();
boolean needsUpdate = false;
XWikiDocument doc;
try {
- doc = xwiki.getDocument(SchedulerPlugin.TASK_CLASS, context);
+ doc = xwiki.getDocument(SchedulerPlugin.XWIKI_JOB_CLASS, context);
} catch (Exception e) {
doc = new XWikiDocument();
- doc.setFullName(SchedulerPlugin.TASK_CLASS);
+ doc.setFullName(SchedulerPlugin.XWIKI_JOB_CLASS);
needsUpdate = true;
}
BaseClass bclass = doc.getxWikiClass();
- bclass.setName(SchedulerPlugin.TASK_CLASS);
- needsUpdate |= bclass.addTextField("taskName", "Task Name", 30);
- needsUpdate |= bclass.addTextField("taskClass", "Task Class", 30);
+ bclass.setName(SchedulerPlugin.XWIKI_JOB_CLASS);
+ needsUpdate |= bclass.addTextField("jobName", "Job Name", 60);
+ needsUpdate |= bclass.addTextAreaField("jobDescription", "Job
Description", 45, 10);
+ needsUpdate |= bclass.addTextField("jobClass", "Job Class", 60);
needsUpdate |= bclass.addTextField("status", "Status", 30);
needsUpdate |= bclass.addTextField("cron", "Cron Expression", 30);
- needsUpdate |= bclass.addTextAreaField("script", "Groovy Script", 45,
10);
+ needsUpdate |= bclass.addTextAreaField("script", "Job Script", 45, 10);
if (needsUpdate) {
try {
xwiki.saveDocument(doc, context);
} catch (XWikiException ex) {
throw new SchedulerPluginException(
-
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_SAVE_TASK_CLASS,
- "Error while saving " + SchedulerPlugin.TASK_CLASS
- + " class document in XWiki", ex);
+
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_SAVE_JOB_CLASS,
+ "Error while saving " + SchedulerPlugin.XWIKI_JOB_CLASS
+ + " class document in XWiki", ex);
}
}
}
Modified:
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginApi.java
===================================================================
---
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginApi.java
2007-09-26 21:31:28 UTC (rev 5103)
+++
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginApi.java
2007-09-27 09:41:37 UTC (rev 5104)
@@ -19,21 +19,31 @@
*/
package com.xpn.xwiki.plugin.scheduler;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.Vector;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.api.Api;
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.XWikiPluginInterface;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.quartz.SchedulerException;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Vector;
+
/**
+ * 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 [EMAIL PROTECTED]
com.xpn.xwiki.api.Object}
+ * XObjects, instances of the [EMAIL PROTECTED]
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 [EMAIL PROTECTED] GroovyJob} Groovy Job wrapper to
execute groovy scripts (typically for
+ * use inside the Wiki), but can also be used with any Java class implementing
[EMAIL PROTECTED]
+ * org.quartz.Job}
+ *
* @version $Id: $
*/
public class SchedulerPluginApi extends Api
@@ -43,6 +53,9 @@
*/
private static final Log LOG = LogFactory.getLog(SchedulerPluginApi.class);
+ /**
+ * The instance of the actual implementation class of the plugin
+ */
private SchedulerPlugin plugin;
public SchedulerPluginApi(SchedulerPlugin plugin, XWikiContext context)
@@ -51,49 +64,56 @@
setPlugin(plugin);
}
- public boolean pauseTask(String number)
+ /**
+ * Return the trigger state of the given [EMAIL PROTECTED]
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)
{
- return pauseTask(context.getDoc().getObject(SchedulerPlugin.TASK_CLASS,
- Integer.valueOf(number).intValue()));
+ try {
+ return getJobStatus(object.getXWikiObject()).getValue();
+ } catch (SchedulerException e) {
+ context.put("error", e.getMessage());
+ return null;
+ }
}
- public boolean pauseTask(Object object)
+ /**
+ * Return the trigger state as a [EMAIL PROTECTED] 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
{
- return pauseTask(object.getXWikiObject());
+ return plugin.getJobStatus(object);
}
- public boolean pauseTask(BaseObject object)
+ public JobState getJobStatus(Object object) throws SchedulerException
{
- try {
- plugin.pauseTask(String.valueOf(object.getNumber()));
- saveStatus("Paused", object);
- LOG.debug("Pause Task : " + object.getStringValue("taskName"));
- return true;
- } catch (XWikiException e) {
- context.put("error", e.getMessage());
- return false;
- }
+ return plugin.getJobStatus(object.getXWikiObject());
}
/**
* 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.scheduleTask($task)!=true)
- * #error($context.get("error") #else #info("Task scheduled") #end </code>
Where $task is an
- * XObject, instance of the XWiki.Task XClass
+ * 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 [EMAIL PROTECTED]
SchedulerPlugin#XWIKI_JOB_CLASS} XClass
*
- * @param object the XObject to be scheduled, an instance of the XClass
XWiki.Task
+ * @param object the XObject to be scheduled, an instance of the XClass
XWiki.SchedulerJobClass
* @return true on success, false on failure
*/
- public boolean scheduleTask(Object object)
+ public boolean scheduleJob(Object object)
{
- return scheduleTask(object.getXWikiObject());
+ return scheduleJob(object.getXWikiObject());
}
- public boolean scheduleTask(BaseObject object)
+ public boolean scheduleJob(BaseObject object)
{
try {
- plugin.scheduleTask(object, context);
- saveStatus("Scheduled", object);
+ plugin.scheduleJob(object, context);
return true;
} catch (Exception e) {
context.put("error", e.getMessage());
@@ -102,17 +122,40 @@
}
/**
- * Schedule for execution all XWiki Tasks found in the passed Document
object.
+ * Schedule all [EMAIL PROTECTED]
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 scheduleTasks(Document document)
+ public boolean scheduleJobs(Document document)
{
+ boolean result = true;
+ Vector objects = document.getObjects(SchedulerPlugin.XWIKI_JOB_CLASS);
+ for (Iterator iterator = objects.iterator(); iterator.hasNext();) {
+ Object object = (Object) iterator.next();
+ result &= scheduleJob(object.getXWikiObject());
+ }
+ return result;
+ }
+
+ /**
+ * Pause the given XObject job by pausing all of its current triggers. Can
be called the same
+ * way as [EMAIL PROTECTED] #scheduleJob}
+ *
+ * @param object the wrapped XObject Job to be paused
+ * @return true on success, false on failure.
+ */
+ public boolean pauseJob(Object object)
+ {
+ return pauseJob(object.getXWikiObject());
+ }
+
+ public boolean pauseJob(BaseObject object)
+ {
try {
- Vector objects = document.getObjects(SchedulerPlugin.TASK_CLASS);
- for (Iterator iterator = objects.iterator(); iterator.hasNext();) {
- Object object = (Object) iterator.next();
- scheduleTask(object.getXWikiObject());
- }
- saveDocument(document.getDocument());
+ plugin.pauseJob(object, context);
+ LOG.debug("Pause Job : " + object.getStringValue("jobName"));
return true;
} catch (XWikiException e) {
context.put("error", e.getMessage());
@@ -120,23 +163,23 @@
}
}
- public boolean resumeTask(String number)
+ /**
+ * Resume a XObject job that is in a [EMAIL PROTECTED] JobState#PAUSED}
state. Can be called the same
+ * way as [EMAIL PROTECTED] #scheduleJob}
+ *
+ * @param object the wrapped XObject Job to be paused
+ * @return true on success, false on failure.
+ */
+ public boolean resumeJob(Object object)
{
- return
resumeTask(context.getDoc().getObject(SchedulerPlugin.TASK_CLASS,
- Integer.valueOf(number).intValue()));
+ return resumeJob(object.getXWikiObject());
}
- public boolean resumeTask(Object object)
+ public boolean resumeJob(BaseObject object)
{
- return resumeTask(object.getXWikiObject());
- }
-
- public boolean resumeTask(BaseObject object)
- {
try {
- plugin.resumeTask(String.valueOf(object.getNumber()));
- saveStatus("Scheduled", object);
- LOG.debug("Resume Task : " + object.getStringValue("taskName"));
+ plugin.resumeJob(object, context);
+ LOG.debug("Resume Job : " + object.getStringValue("jobName"));
return true;
} catch (XWikiException e) {
context.put("error", e.getMessage());
@@ -144,23 +187,23 @@
}
}
- public boolean unscheduleTask(String number)
+ /**
+ * Unschedule a XObject job by deleting it from the jobs table. Can be
called the same way as
+ * [EMAIL PROTECTED] #scheduleJob}
+ *
+ * @param object the wrapped XObject Job to be paused
+ * @return true on success, false on failure.
+ */
+ public boolean unscheduleJob(Object object)
{
- return
unscheduleTask(context.getDoc().getObject(SchedulerPlugin.TASK_CLASS,
- Integer.valueOf(number).intValue()));
+ return unscheduleJob(object.getXWikiObject());
}
- public boolean unscheduleTask(Object object)
+ public boolean unscheduleJob(BaseObject object)
{
- return unscheduleTask(object.getXWikiObject());
- }
-
- public boolean unscheduleTask(BaseObject object)
- {
try {
- saveStatus("Unscheduled", object);
- plugin.unscheduleTask(String.valueOf(object.getNumber()));
- LOG.debug("Delete Task : " + object.getStringValue("taskName"));
+ plugin.unscheduleJob(object, context);
+ LOG.debug("Delete Job : " + object.getStringValue("jobName"));
return true;
} catch (XWikiException e) {
context.put("error", e.getMessage());
@@ -168,36 +211,40 @@
}
}
+ /**
+ * Give, for a XObject job in a [EMAIL PROTECTED] 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
[EMAIL PROTECTED]
+ * 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)
{
+ return getNextFireTime(object.getXWikiObject());
+ }
+
+ public Date getNextFireTime(BaseObject object)
+ {
try {
- return
plugin.getNextFireTime(String.valueOf(object.getXWikiObject().getNumber()));
- } catch (SchedulerPluginException e) {
+ return plugin.getNextFireTime(object);
+ }
+ catch (SchedulerPluginException e) {
context.put("error", e.getMessage());
return null;
}
}
- public SchedulerPlugin getPlugin()
+ public void setPlugin(SchedulerPlugin plugin)
{
- return plugin;
+ this.plugin = plugin;
}
- private void saveStatus(String status, BaseObject object)
- throws XWikiException
+ public XWikiPluginInterface getPlugin()
{
- context.getDoc().getObject(SchedulerPlugin.TASK_CLASS,
- object.getNumber()).setStringValue("status", status);
- saveDocument(context.getDoc());
+ return plugin;
}
-
- private void saveDocument(XWikiDocument document) throws XWikiException
- {
- context.getWiki().saveDocument(document, context);
- }
-
- public void setPlugin(SchedulerPlugin plugin)
- {
- this.plugin = plugin;
- }
}
Modified:
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginException.java
===================================================================
---
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginException.java
2007-09-26 21:31:28 UTC (rev 5103)
+++
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginException.java
2007-09-27 09:41:37 UTC (rev 5104)
@@ -23,24 +23,26 @@
public class SchedulerPluginException extends PluginException
{
- protected static final int ERROR_SCHEDULERPLUGIN_SAVE_TASK_CLASS = 90000;
+ 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_TASK = 90002;
+ protected static final int ERROR_SCHEDULERPLUGIN_PAUSE_JOB = 90002;
- protected static final int ERROR_SCHEDULERPLUGIN_RESUME_TASK = 90003;
+ protected static final int ERROR_SCHEDULERPLUGIN_RESUME_JOB = 90003;
- protected static final int ERROR_SCHEDULERPLUGIN_SCHEDULE_TASK = 90004;
+ 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_TASK_CLASS_NOT_FOUND =
90006;
+ protected static final int ERROR_SCHEDULERPLUGIN_JOB_XCLASS_NOT_FOUND =
90006;
- protected static final int ERROR_SCHEDULERPLUGIN_TASK_DOES_NOT_EXITS =
90007;
+ 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_JOBS = 90008;
+
public SchedulerPluginException(int code, String message)
{
super(SchedulerPlugin.class, code, message);
Modified:
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/StatusListener.java
===================================================================
---
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/StatusListener.java
2007-09-26 21:31:28 UTC (rev 5103)
+++
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/StatusListener.java
2007-09-27 09:41:37 UTC (rev 5104)
@@ -34,9 +34,9 @@
public class StatusListener implements SchedulerListener, JobListener
{
/**
- * Log object to log messages in this class.
+ * Log4j logger that records events for this class
*/
- private static final Log LOG = LogFactory.getLog(SchedulerPlugin.class);
+ private static final Log LOG = LogFactory.getLog(StatusListener.class);
/**
* [EMAIL PROTECTED]
_______________________________________________
notifications mailing list
[email protected]
http://lists.xwiki.org/mailman/listinfo/notifications