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

Reply via email to