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