package railo.runtime.tag;
import java.net.URL;
import railo.commons.io.res.Resource;
import railo.commons.io.res.util.ResourceUtil;
import railo.commons.lang.StringUtil;
import railo.commons.net.HTTPUtil;
import railo.commons.security.Credentials;
import railo.commons.security.CredentialsImpl;
import railo.runtime.exp.ApplicationException;
import railo.runtime.exp.DatabaseException;
import railo.runtime.exp.PageException;
import railo.runtime.ext.tag.TagImpl;
import railo.runtime.net.proxy.ProxyData;
import railo.runtime.net.proxy.ProxyDataImpl;
import railo.runtime.op.Caster;
import railo.runtime.op.date.DateCaster;
import railo.runtime.schedule.ScheduleTask;
import railo.runtime.schedule.ScheduleTaskImpl;
import railo.runtime.schedule.Scheduler;
import railo.runtime.schedule.SchedulerImpl;
import railo.runtime.type.QueryImpl;
import railo.runtime.type.dt.Date;
import railo.runtime.type.dt.DateImpl;
import railo.runtime.type.dt.Time;
import railo.runtime.type.util.KeyConstants;
/**
* Provides a programmatic interface to the Railo scheduling engine. You can run a specified
* page at scheduled intervals with the option to write out static HTML pages. This lets you offer users
* access to pages that publish data, such as reports, without forcing users to wait while a database transaction
* is performed in order to populate the data on the page.
**/
public final class Schedule extends TagImpl {
private static final short ACTION_RUN=1;
private static final short ACTION_UPDATE=2;
private static final short ACTION_DELETE=3;
private static final short ACTION_LIST=4;
private static final short ACTION_PAUSE=5;
private static final short ACTION_RESUME=6;
/** Password if URL is protected. */
private String password="";
/** Required when action ='update'. The date when scheduling of the task should start. */
private Date startdate;
/** Specifies whether to resolve links in the result page to absolute references. */
private boolean resolveurl;
/** */
private short action;
/** Host name or IP address of a proxy server. */
private String proxyserver;
/** The date when the scheduled task ends. */
private Date enddate;
/** Required with publish ='Yes' A valid filename for the published file. */
private String strFile;
/** Required when creating tasks with action = 'update'. Enter a value in seconds. The time when
** scheduling of the task starts. */
private Time starttime;
/** The port number on the proxy server from which the task is being requested. Default is 80. When
** used with resolveURL, the URLs of retrieved documents that specify a port number are automatically
** resolved to preserve links in the retrieved document. */
private int proxyport=80;
/** The port number on the server from which the task is being scheduled. Default is 80. When used
** with resolveURL, the URLs of retrieved documents that specify a port number are automatically resolved
** to preserve links in the retrieved document. */
private int port=-1;
/** The time when the scheduled task ends. Enter a value in seconds. */
private Time endtime;
/** Required when creating tasks with action = 'update'. Interval at which task should be scheduled.
** Can be set in seconds or as Once, Daily, Weekly, and Monthly. The default interval is one hour. The
** minimum interval is one minute. */
private String interval;
/** Specifies whether the result should be saved to a file. */
private boolean publish;
/** Customizes the requestTimeOut for the task operation. Can be used to extend the default timeout
** for operations that require more time to execute. */
private long requesttimeout=-1;
/** Username if URL is protected. */
private String username;
/** Required when action = 'update'. The URL to be executed. */
private String url;
/** Required with publish ='Yes' The path location for the published file. */
private String strPath;
/** The name of the task to delete, update, or run. */
private String task;
private Scheduler scheduler;
private String proxyuser;
private String proxypassword="";
private String returnvariable="cfschedule";
private boolean hidden;
private boolean readonly;
private String serverPassword=null;
private boolean paused;
private boolean autoDelete;
public void setAutodelete(boolean autoDelete) {
this.autoDelete=autoDelete;
}
/**
* @param readonly the readonly to set
*/
public void setReadonly(boolean readonly) {
this.readonly = readonly;
}
/**
* @param hidden the hidden to set
*/
public void setHidden(boolean hidden) {
this.hidden = hidden;
}
/**
* @param returnvariable The returnvariable to set.
*/
public void setReturnvariable(String returnvariable) {
this.returnvariable = returnvariable;
}
/**
* @param proxypassword The proxypassword to set.
*/
public void setProxypassword(String proxypassword) {
this.proxypassword = proxypassword;
}
/**
* @param proxyuser The proxyuser to set.
*/
public void setProxyuser(String proxyuser) {
this.proxyuser = proxyuser;
}
public void setPaused(boolean paused) {
this.paused = paused;
}
/** set the value password
* Password if URL is protected.
* @param password value to set
**/
public void setPassword(String password) {
this.password=password;
}
/** set the value startdate
* Required when action ='update'. The date when scheduling of the task should start.
* @param objStartDate value to set
* @throws PageException
**/
public void setStartdate(Object objStartDate) throws PageException {
if(StringUtil.isEmpty(objStartDate)) return;
this.startdate=new DateImpl(DateCaster.toDateAdvanced(objStartDate,pageContext.getTimeZone()));
}
/** set the value resolveurl
* Specifies whether to resolve links in the result page to absolute references.
* @param resolveurl value to set
**/
public void setResolveurl(boolean resolveurl) {
this.resolveurl=resolveurl;
}
public void setServerpassword(String serverPassword) {
this.serverPassword=serverPassword;
}
/** set the value action
*
* @param action value to set
* @throws ApplicationException
**/
public void setAction(String action) throws ApplicationException {
if(StringUtil.isEmpty(action)) return;
action=action.toLowerCase().trim();
if(action.equals("run"))this.action=ACTION_RUN;
else if(action.equals("delete"))this.action=ACTION_DELETE;
else if(action.equals("update"))this.action=ACTION_UPDATE;
else if(action.equals("list"))this.action=ACTION_LIST;
else if(action.equals("lists"))this.action=ACTION_LIST;
else if(action.equals("pause"))this.action=ACTION_PAUSE;
else if(action.equals("resume"))this.action=ACTION_RESUME;
else throw new ApplicationException("attribute action with value ["+action+"] of tag schedule is invalid","valid attributes are [delete,run,update,list,resume,pause]");
}
/** set the value proxyserver
* Host name or IP address of a proxy server.
* @param proxyserver value to set
**/
public void setProxyserver(String proxyserver) {
this.proxyserver=proxyserver;
}
/** set the value enddate
* The date when the scheduled task ends.
* @param enddate value to set
* @throws PageException
**/
public void setEnddate(Object enddate) throws PageException {
if(StringUtil.isEmpty(enddate)) return;
this.enddate=new DateImpl(DateCaster.toDateAdvanced(enddate,pageContext.getTimeZone()));
}
/** set the value file
* Required with publish ='Yes' A valid filename for the published file.
* @param file value to set
**/
public void setFile(String file) {
this.strFile=file;
}
/** set the value starttime
* Required when creating tasks with action = 'update'. Enter a value in seconds. The time when
* scheduling of the task starts.
* @param starttime value to set
* @throws PageException
**/
public void setStarttime(Object starttime) throws PageException {
if(StringUtil.isEmpty(starttime)) return;
this.starttime=DateCaster.toTime(pageContext.getTimeZone(),starttime);
}
/** set the value proxyport
* The port number on the proxy server from which the task is being requested. Default is 80. When
* used with resolveURL, the URLs of retrieved documents that specify a port number are automatically
* resolved to preserve links in the retrieved document.
* @param proxyport value to set
* @throws PageException
**/
public void setProxyport(Object oProxyport) throws PageException {
if(StringUtil.isEmpty(oProxyport)) return;
this.proxyport=Caster.toIntValue(oProxyport);
}
/** set the value port
* The port number on the server from which the task is being scheduled. Default is 80. When used
* with resolveURL, the URLs of retrieved documents that specify a port number are automatically resolved
* to preserve links in the retrieved document.
* @param port value to set
* @throws PageException
**/
public void setPort(Object oPort) throws PageException {
if(StringUtil.isEmpty(oPort)) return;
this.port=Caster.toIntValue(oPort);
}
/** set the value endtime
* The time when the scheduled task ends. Enter a value in seconds.
* @param endtime value to set
* @throws PageException
**/
public void setEndtime(Object endtime) throws PageException {
if(StringUtil.isEmpty(endtime)) return;
this.endtime=DateCaster.toTime(pageContext.getTimeZone(),endtime);
}
/** set the value operation
* The type of operation the scheduler performs when executing this task.
* @param operation value to set
* @throws ApplicationException
**/
public void setOperation(String operation) throws ApplicationException {
if(StringUtil.isEmpty(operation)) return;
operation=operation.toLowerCase().trim();
if(!operation.equals("httprequest"))
throw new ApplicationException("attribute operation must have the value [HTTPRequest]");
}
/** set the value interval
* Required when creating tasks with action = 'update'. Interval at which task should be scheduled.
* Can be set in seconds or as Once, Daily, Weekly, and Monthly. The default interval is one hour. The
* minimum interval is one minute.
* @param interval value to set
**/
public void setInterval(String interval) {
if(StringUtil.isEmpty(interval)) return;
interval=interval.trim().toLowerCase();
if(interval.equals("week")) this.interval="weekly";
else if(interval.equals("day")) this.interval="daily";
else if(interval.equals("month")) this.interval="monthly";
else if(interval.equals("year")) this.interval="yearly";
this.interval=interval;
}
/** set the value publish
* Specifies whether the result should be saved to a file.
* @param publish value to set
**/
public void setPublish(boolean publish) {
this.publish=publish;
}
/** set the value requesttimeout
* Customizes the requestTimeOut for the task operation. Can be used to extend the default timeout
* for operations that require more time to execute.
* @param requesttimeout value to set
**/
public void setRequesttimeout(Object oRequesttimeout) throws PageException {
if(StringUtil.isEmpty(oRequesttimeout)) return;
this.requesttimeout=Caster.toLongValue(oRequesttimeout)*1000L;
}
/** set the value username
* Username if URL is protected.
* @param username value to set
**/
public void setUsername(String username) {
this.username=username;
}
/** set the value url
* Required when action = 'update'. The URL to be executed.
* @param url value to set
**/
public void setUrl(String url) {
this.url=url;
}
/** set the value path
* Required with publish ='Yes' The path location for the published file.
* @param path value to set
**/
public void setPath(String path) {
this.strPath=path;
}
/** set the value task
* The name of the task to delete, update, or run.
* @param task value to set
**/
public void setTask(String task) {
this.task=task;
}
@Override
public int doStartTag() throws PageException {
scheduler=pageContext.getConfig().getScheduler();
if(action!=ACTION_LIST && task==null) {
throw new ApplicationException("attribute task is required for tag schedule when action is not list");
}
switch(action) {
case ACTION_DELETE: doDelete(); break;
case ACTION_RUN: doRun(); break;
case ACTION_UPDATE: doUpdate(); break;
case ACTION_LIST: doList(); break;
case ACTION_PAUSE: doPause(true); break;
case ACTION_RESUME: doPause(false); break;
}
return SKIP_BODY;
}
/**
* @throws PageException
*/
private void doUpdate() throws PageException {
String message="missing attribute for tag schedule with action update";
String detail="required attributes are [startDate, startTime, URL, interval, operation]";
Resource file=null;
//if(publish) {
if(!StringUtil.isEmpty(strFile) && !StringUtil.isEmpty(strPath)) {
file=ResourceUtil.toResourceNotExisting(pageContext, strPath);
file=file.getRealResource(strFile);
}
else if(!StringUtil.isEmpty(strFile)) {
file=ResourceUtil.toResourceNotExisting(pageContext, strFile);
}
else if(!StringUtil.isEmpty(strPath)) {
file=ResourceUtil.toResourceNotExisting(pageContext, strPath);
}
if(file!=null)pageContext.getConfig().getSecurityManager().checkFileLocation(pageContext.getConfig(),file,serverPassword);
// missing attributes
if(startdate==null || starttime==null || url==null || interval==null)
throw new ApplicationException(message,detail);
// timeout
if(requesttimeout<0)requesttimeout=pageContext.getRequestTimeout();
// username/password
Credentials cr=null;
if(username!=null) cr=CredentialsImpl.toCredentials(username,password);
try {
ScheduleTask st=new ScheduleTaskImpl(
task,
file,
startdate,
starttime,
enddate,
endtime,
url,
port,
interval,
requesttimeout,
cr,
ProxyDataImpl.getInstance(proxyserver,proxyport,proxyuser,proxypassword),
resolveurl,
publish,
hidden,
readonly,
paused,
autoDelete);
scheduler.addScheduleTask(st,true);
} catch (Exception e) {
throw Caster.toPageException(e);
}
//
}
/**
* @throws PageException
*/
private void doRun() throws PageException {
try {
scheduler.runScheduleTask(task,true);
} catch (Exception e) {
throw Caster.toPageException(e);
}
}
/**
* @throws PageException
*/
private void doDelete() throws PageException {
try {
scheduler.removeScheduleTask(task,false);
} catch (Exception e) {
throw Caster.toPageException(e);
}
}
/**
* @throws PageException
*
*/
private void doList() throws PageException {
//if(tr ue) throw new PageRuntimeException("qqq");
ScheduleTask[] tasks = scheduler.getAllScheduleTasks();
final String v="VARCHAR";
String[] cols = new String[]{"task","path","file","startdate","starttime","enddate","endtime",
"url","port","interval","timeout","username","password","proxyserver",
"proxyport","proxyuser","proxypassword","resolveurl","publish","valid","paused","autoDelete"};
String[] types = new String[]{v,v,v,"DATE","OTHER","DATE","OTHER",
v,v,v,v,v,v,v,
v,v,v,v,"BOOLEAN",v,"BOOLEAN","BOOLEAN"};
railo.runtime.type.Query query=new QueryImpl(cols,types,tasks.length,"query"
);
try {
for(int i=0;i<tasks.length;i++) {
int row=i+1;
ScheduleTask task=tasks[i];
query.setAt(KeyConstants._task,row,task.getTask());
if(task.getResource()!=null) {
query.setAt(KeyConstants._path,row,task.getResource().getParent());
query.setAt(KeyConstants._file,row,task.getResource().getName());
}
query.setAt("publish",row,Caster.toBoolean(task.isPublish()));
query.setAt("startdate",row,task.getStartDate());
query.setAt("starttime",row,task.getStartTime());
query.setAt("enddate",row,task.getEndDate());
query.setAt("endtime",row,task.getEndTime());
query.setAt(KeyConstants._url,row,printUrl(task.getUrl()));
query.setAt(KeyConstants._port,row,Caster.toString(HTTPUtil.getPort(task.getUrl())));
query.setAt("interval",row,task.getStringInterval());
query.setAt("timeout",row,Caster.toString(task.getTimeout()/1000));
query.setAt("valid",row,Caster.toString(task.isValid()));
if(task.hasCredentials()) {
query.setAt("username",row,task.getCredentials().getUsername());
query.setAt("password",row,task.getCredentials().getPassword());
}
ProxyData pd = task.getProxyData();
if(ProxyDataImpl.isValid(pd)){
query.setAt("proxyserver",row,pd.getServer());
if(pd.getPort()>0)query.setAt("proxyport",row,Caster.toString(pd.getPort()));
if(ProxyDataImpl.hasCredentials(pd)) {
query.setAt("proxyuser",row,pd.getUsername());
query.setAt("proxypassword",row,pd.getPassword());
}
}
query.setAt("resolveurl",row,Caster.toString(task.isResolveURL()));
query.setAt("paused",row,Caster.toBoolean(task.isPaused()));
query.setAt("autoDelete",row,Caster.toBoolean(((ScheduleTaskImpl)task).isAutoDelete()));
}
pageContext.setVariable(returnvariable,query);
}
catch (DatabaseException e) {}
}
private void doPause(boolean pause) throws PageException {
try {
((SchedulerImpl)scheduler).pauseScheduleTask(task,pause,true);
} catch (Exception e) {
throw Caster.toPageException(e);
}
}
private String printUrl(URL url) {
String qs=url.getQuery();
if(qs==null) qs="";
else if(qs.length()>0)qs="?"+qs;
String str=url.getProtocol()+"://"+url.getHost()+url.getPath()+qs;
return str;
}
@Override
public int doEndTag() {
return EVAL_PAGE;
}
@Override
public void release() {
super.release();
readonly=false;
strPath=null;
strFile=null;
starttime=null;
startdate=null;
endtime=null;
enddate=null;
url=null;
port=-1;
interval=null;
requesttimeout=-1;
username=null;
password="";
proxyserver=null;
proxyport=80;
proxyuser=null;
proxypassword="";
resolveurl=false;
publish=false;
returnvariable="cfschedule";
task=null;
hidden=false;
serverPassword=null;
paused=false;
autoDelete=false;
}
}