Author: jvelociter
Date: 2007-10-26 18:01:52 +0200 (Fri, 26 Oct 2007)
New Revision: 5524

Added:
   
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/XWikiServletRequestStub.java
Modified:
   
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/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
Log:
XASCH-1 Scheduler now provide the job a custom XWiki context stub based on 
parameters stored in the Job XWiki object. This context is the guaranteed to be 
the same at each XWiki restart provided that the job o
bject fields have the same values.
Applied xwiki code style.



Modified: 
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-10-26 15:12:46 UTC (rev 5523)
+++ 
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/GroovyJob.java
    2007-10-26 16:01:52 UTC (rev 5524)
@@ -60,7 +60,7 @@
             // 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

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-10-26 15:12:46 UTC (rev 5523)
+++ 
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPlugin.java
      2007-10-26 16:01:52 UTC (rev 5524)
@@ -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,97 @@
     }
 
     /**
+     * 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());
+                jobHolder.setMinorEdit(true);
+                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 +275,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);
@@ -470,6 +562,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 {

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-10-26 15:12:46 UTC (rev 5523)
+++ 
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginApi.java
   2007-10-26 16:01:52 UTC (rev 5524)
@@ -87,7 +87,8 @@
      * 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, 
SchedulerPluginException
+    public JobState getJobStatus(BaseObject object)
+        throws SchedulerException, SchedulerPluginException
     {
         return plugin.getJobStatus(object);
     }
@@ -110,18 +111,17 @@
     {
         String docName = object.getName();
         int objNb = object.getNumber();
-        try
-        {
+        try {
 
-            XWikiDocument jobHolder = 
context.getWiki().getDocument(docName,context);
-            BaseObject jobObject = 
jobHolder.getObject(SchedulerPlugin.XWIKI_JOB_CLASS,objNb);
+            XWikiDocument jobHolder = context.getWiki().getDocument(docName, 
context);
+            BaseObject jobObject = 
jobHolder.getObject(SchedulerPlugin.XWIKI_JOB_CLASS, objNb);
             return jobObject;
         }
-        catch(XWikiException e)
-        {
+        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);
+                "Job in document [" + docName + "] with object number [" + 
objNb +
+                    "] could not be retrieved.", e);
         }
     }
 
@@ -136,10 +136,10 @@
      */
     public boolean scheduleJob(Object object)
     {
-        try{
+        try {
             return scheduleJob(retrieveBaseObject(object));
         }
-        catch(Exception e){
+        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;
@@ -167,17 +167,15 @@
     public boolean scheduleJobs(Document document)
     {
         boolean result = true;
-        try
-        {
-            XWikiDocument doc = 
context.getWiki().getDocument(document.getFullName(),context);
+        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)
-        {
+        catch (Exception e) {
             context.put("error", e.getMessage());
             return false;
         }
@@ -193,17 +191,14 @@
      */
     public boolean pauseJob(Object object)
     {
-        try
-        {
+        try {
             return pauseJob(retrieveBaseObject(object));
         }
-        catch(Exception e)
-        {
+        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)
@@ -227,10 +222,10 @@
      */
     public boolean resumeJob(Object object)
     {
-        try{
+        try {
             return resumeJob(retrieveBaseObject(object));
         }
-        catch(Exception e){
+        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;
@@ -258,10 +253,10 @@
      */
     public boolean unscheduleJob(Object object)
     {
-        try{
+        try {
             return unscheduleJob(retrieveBaseObject(object));
         }
-        catch(Exception e){
+        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;
@@ -293,10 +288,10 @@
      */
     public Date getNextFireTime(Object object)
     {
-        try{
+        try {
             return getNextFireTime(retrieveBaseObject(object));
         }
-        catch(Exception e){
+        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;

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-10-26 15:12:46 UTC (rev 5523)
+++ 
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/SchedulerPluginException.java
     2007-10-26 16:01:52 UTC (rev 5524)
@@ -47,6 +47,8 @@
 
     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);

Added: 
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/XWikiServletRequestStub.java
===================================================================
--- 
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/XWikiServletRequestStub.java
                              (rev 0)
+++ 
xwiki-platform/xwiki-plugins/trunk/scheduler/src/main/java/com/xpn/xwiki/plugin/scheduler/XWikiServletRequestStub.java
      2007-10-26 16:01:52 UTC (rev 5524)
@@ -0,0 +1,408 @@
+package com.xpn.xwiki.plugin.scheduler;
+
+import com.xpn.xwiki.web.XWikiRequest;
+
+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 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;
+
+/**
+ * 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.
+ */
+public class XWikiServletRequestStub implements XWikiRequest
+{
+    public XWikiServletRequestStub()
+    {
+        host = new String();
+    }
+
+    private String host;
+
+    public void setHost(String host)
+    {
+        this.host = host;
+    }
+
+    public String getHeader(String s)
+    {
+        if (s.equals("x-forwarded-host")) {
+            return host;
+        }
+        return new String();
+    }
+
+    public String get(String name)
+    {
+        return new String();
+    }
+
+    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 new String();
+    }
+
+    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
+     */
+    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 String getScheme()
+    {
+        return null;
+    }
+
+    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
+     */
+    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;
+    }
+}

_______________________________________________
notifications mailing list
[email protected]
http://lists.xwiki.org/mailman/listinfo/notifications

Reply via email to