Author: jvelociter
Date: 2007-10-29 19:19:35 +0100 (Mon, 29 Oct 2007)
New Revision: 5560
Modified:
xwiki-platform/xwiki-plugins/branches/xwiki-plugin-scheduler-1.0/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPlugin.java
xwiki-platform/xwiki-plugins/branches/xwiki-plugin-scheduler-1.0/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginApi.java
xwiki-platform/xwiki-plugins/branches/xwiki-plugin-scheduler-1.0/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginException.java
Log:
Scheduler plugin. Merged from trunk
Modified:
xwiki-platform/xwiki-plugins/branches/xwiki-plugin-scheduler-1.0/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPlugin.java
===================================================================
---
xwiki-platform/xwiki-plugins/branches/xwiki-plugin-scheduler-1.0/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPlugin.java
2007-10-29 18:06:41 UTC (rev 5559)
+++
xwiki-platform/xwiki-plugins/branches/xwiki-plugin-scheduler-1.0/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPlugin.java
2007-10-29 18:19:35 UTC (rev 5560)
@@ -29,6 +29,7 @@
import com.xpn.xwiki.objects.classes.BaseClass;
import com.xpn.xwiki.plugin.XWikiDefaultPlugin;
import com.xpn.xwiki.plugin.XWikiPluginInterface;
+import com.xpn.xwiki.web.XWikiServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.CronTrigger;
@@ -110,6 +111,96 @@
}
/**
+ * Create and feed a stub context for the job execution thread. Stub
context data are retrieved
+ * from job object fields "contextUser", "contextLang", "contextDatabase".
If one of this field
+ * is empty (this would typically happen on the first schedule operation),
it is instead
+ * retrieved from the passed context, and the job object is updated with
this value. This mean
+ * that this method may modify the passed object.
+ *
+ * @param job the job for which the context will be prepared
+ * @param context the XWikiContext at preparation time. This is a real
context associated with a
+ * servlet request
+ * @return the stub context prepared with job datas.
+ */
+ private XWikiContext prepareJobStubContext(BaseObject job, XWikiContext
context)
+ throws SchedulerPluginException
+ {
+ boolean jobNeedsUpdate = true;
+ String cUser = job.getStringValue("contextUser");
+ if (cUser.equals("")) {
+ // The context user has not been filled yet.
+ // We can suppose it's the first scheduling. Let's assume it's the
context user
+ cUser = context.getUser();
+ job.setStringValue("contextUser", cUser);
+ jobNeedsUpdate = true;
+ }
+ String cLang = job.getStringValue("contextLang");
+ if (cLang.equals("")) {
+ cLang = context.getLanguage();
+ job.setStringValue("contextLang", cLang);
+ jobNeedsUpdate = true;
+ }
+ String cDb = job.getStringValue("contextDatabase");
+ if (cDb.equals("")) {
+ cDb = context.getDatabase();
+ job.setStringValue("contextDatabase", cDb);
+ jobNeedsUpdate = true;
+ }
+
+ if (jobNeedsUpdate) {
+ try {
+ XWikiDocument jobHolder =
context.getWiki().getDocument(job.getName(), context);
+ BaseObject jObj =
+ jobHolder.getObject(SchedulerPlugin.XWIKI_JOB_CLASS,
job.getNumber());
+ context.getWiki().saveDocument(jobHolder, context);
+ }
+ catch (XWikiException e) {
+ throw new SchedulerPluginException(
+
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_UNABLE_TO_PREPARE_JOB_CONTEXT,
+ "Failed to prepare context for job with job name " +
+ job.getStringValue("jobName"), e);
+ }
+ }
+
+ //lets now build the stub context
+ XWikiContext scontext = new XWikiContext();
+ scontext.setWiki(context.getWiki());
+
+ // We are sure the context request is a real servlet request
+ // So we force the dummy request with the current host
+ XWikiServletRequestStub dummy = new XWikiServletRequestStub();
+ dummy.setHost(context.getRequest().getHeader("x-forwarded-host"));
+ XWikiServletRequest request = new XWikiServletRequest(dummy);
+ scontext.setRequest(request);
+
+ // feed the dummy context
+ scontext.setUser(cUser);
+ scontext.setLanguage(cLang);
+ scontext.setDatabase(cDb);
+ scontext.setVirtual(context.isVirtual());
+
+ com.xpn.xwiki.web.XWikiURLFactory xurf = context.getURLFactory();
+ if (xurf == null) {
+ xurf = context.getWiki().getURLFactoryService()
+ .createURLFactory(context.getMode(), context);
+ }
+ scontext.setURLFactory(xurf);
+
+ try {
+ XWikiDocument cDoc = context.getWiki().getDocument(job.getName(),
context);
+ scontext.setDoc(cDoc);
+ }
+ catch (Exception e) {
+ throw new SchedulerPluginException(
+
SchedulerPluginException.ERROR_SCHEDULERPLUGIN_UNABLE_TO_PREPARE_JOB_CONTEXT,
+ "Failed to prepare context for job with job name " +
job.getStringValue("jobName"),
+ e);
+ }
+
+ return scontext;
+ }
+
+ /**
* Restore the existing job, by looking up for such job in the database
and re-scheduling those
* according to their stored status. If a Job is stored with the status
"Normal", it is just
* scheduled If a Job is stored with the status "Paused", then it is both
scheduled and paused
@@ -183,14 +274,14 @@
Trigger trigger = new CronTrigger(xjob, Scheduler.DEFAULT_GROUP,
xjob,
Scheduler.DEFAULT_GROUP, object.getStringValue("cron"));
+ // Let's prepare an execution context...
+ XWikiContext stubContext = prepareJobStubContext(object, context);
+ Context stub = new Context(stubContext);
+
+ data.put("context", stub);
+ data.put("xwiki", new com.xpn.xwiki.api.XWiki(context.getWiki(),
stubContext));
data.put("xjob", object);
- // We offer the Job a wrapped copy of the request context and of
the XWiki API
- XWikiContext cloneContext = (XWikiContext) context.clone();
- Context copy = new Context(cloneContext);
- data.put("context", copy);
- data.put("xwiki", new
com.xpn.xwiki.api.XWiki(cloneContext.getWiki(), cloneContext));
-
job.setJobDataMap(data);
getScheduler().addJob(job, true);
@@ -469,6 +560,9 @@
needsUpdate |= bclass.addTextField("status", "Status", 30);
needsUpdate |= bclass.addTextField("cron", "Cron Expression", 30);
needsUpdate |= bclass.addTextAreaField("script", "Job Script", 45, 10);
+ needsUpdate |= bclass.addTextField("contextUser", "Job execution
context user", 30);
+ needsUpdate |= bclass.addTextField("contextLang", "Job execution
context lang", 30);
+ needsUpdate |= bclass.addTextField("contextDatabase", "Job execution
context database", 30);
if (needsUpdate) {
try {
@@ -482,3 +576,4 @@
}
}
}
+
Modified:
xwiki-platform/xwiki-plugins/branches/xwiki-plugin-scheduler-1.0/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginApi.java
===================================================================
---
xwiki-platform/xwiki-plugins/branches/xwiki-plugin-scheduler-1.0/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginApi.java
2007-10-29 18:06:41 UTC (rev 5559)
+++
xwiki-platform/xwiki-plugins/branches/xwiki-plugin-scheduler-1.0/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginApi.java
2007-10-29 18:19:35 UTC (rev 5560)
@@ -24,6 +24,7 @@
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;
@@ -32,7 +33,7 @@
import java.util.Date;
import java.util.Iterator;
-import java.util.Vector;
+import java.util.List;
/**
* A Scheduler plugin to plan execution of Jobs from XWiki with cron
expressions. The plugin uses
@@ -76,7 +77,7 @@
{
try {
return getJobStatus(object.getXWikiObject()).getValue();
- } catch (SchedulerException e) {
+ } catch (Exception e) {
context.put("error", e.getMessage());
return null;
}
@@ -86,17 +87,45 @@
* 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
+ public JobState getJobStatus(BaseObject object) throws SchedulerException,
SchedulerPluginException
{
return plugin.getJobStatus(object);
}
- public JobState getJobStatus(Object object) throws SchedulerException
+ public JobState getJobStatus(Object object) throws SchedulerException,
SchedulerPluginException
{
- return plugin.getJobStatus(object.getXWikiObject());
+ return plugin.getJobStatus(retrieveBaseObject(object));
}
/**
+ * Tnis 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 =
context.getWiki().getDocument(docName,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
@@ -107,12 +136,20 @@
*/
public boolean scheduleJob(Object object)
{
- return scheduleJob(object.getXWikiObject());
+ 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 {
+
plugin.scheduleJob(object, context);
return true;
} catch (Exception e) {
@@ -131,11 +168,20 @@
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());
+ try
+ {
+ XWikiDocument doc =
context.getWiki().getDocument(document.getFullName(),context);
+ List objects = doc.getObjects(SchedulerPlugin.XWIKI_JOB_CLASS);
+ for (Iterator iterator = objects.iterator(); iterator.hasNext();) {
+ Object object = (Object) iterator.next();
+ result &= scheduleJob(object);
+ }
}
+ catch(Exception e)
+ {
+ context.put("error", e.getMessage());
+ return false;
+ }
return result;
}
@@ -148,7 +194,17 @@
*/
public boolean pauseJob(Object object)
{
- return pauseJob(object.getXWikiObject());
+ 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)
@@ -164,7 +220,7 @@
}
/**
- * Resume a XObject job that is in a [EMAIL PROTECTED] JobState#PAUSED}
state. Can be called the same
+ * Resume a XObject job that is in a [EMAIL PROTECTED]
JobState#STATE_PAUSED} state. Can be called the same
* way as [EMAIL PROTECTED] #scheduleJob}
*
* @param object the wrapped XObject Job to be paused
@@ -172,7 +228,14 @@
*/
public boolean resumeJob(Object object)
{
- return resumeJob(object.getXWikiObject());
+ 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)
@@ -196,7 +259,14 @@
*/
public boolean unscheduleJob(Object object)
{
- return unscheduleJob(object.getXWikiObject());
+ 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)
@@ -224,7 +294,14 @@
*/
public Date getNextFireTime(Object object)
{
- return getNextFireTime(object.getXWikiObject());
+ 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)
Modified:
xwiki-platform/xwiki-plugins/branches/xwiki-plugin-scheduler-1.0/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginException.java
===================================================================
---
xwiki-platform/xwiki-plugins/branches/xwiki-plugin-scheduler-1.0/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginException.java
2007-10-29 18:06:41 UTC (rev 5559)
+++
xwiki-platform/xwiki-plugins/branches/xwiki-plugin-scheduler-1.0/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginException.java
2007-10-29 18:19:35 UTC (rev 5560)
@@ -45,6 +45,10 @@
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;
+
public SchedulerPluginException(int code, String message)
{
super(SchedulerPlugin.class, code, message);
_______________________________________________
notifications mailing list
[email protected]
http://lists.xwiki.org/mailman/listinfo/notifications