001 package railo.runtime.tag; 002 003 import java.net.URL; 004 005 import railo.commons.io.res.Resource; 006 import railo.commons.io.res.util.ResourceUtil; 007 import railo.commons.lang.StringUtil; 008 import railo.commons.net.HTTPUtil; 009 import railo.commons.security.Credentials; 010 import railo.commons.security.CredentialsImpl; 011 import railo.runtime.exp.ApplicationException; 012 import railo.runtime.exp.DatabaseException; 013 import railo.runtime.exp.PageException; 014 import railo.runtime.ext.tag.TagImpl; 015 import railo.runtime.net.proxy.ProxyData; 016 import railo.runtime.net.proxy.ProxyDataImpl; 017 import railo.runtime.op.Caster; 018 import railo.runtime.op.date.DateCaster; 019 import railo.runtime.schedule.ScheduleTask; 020 import railo.runtime.schedule.ScheduleTaskImpl; 021 import railo.runtime.schedule.Scheduler; 022 import railo.runtime.schedule.SchedulerImpl; 023 import railo.runtime.type.QueryImpl; 024 import railo.runtime.type.dt.Date; 025 import railo.runtime.type.dt.DateImpl; 026 import railo.runtime.type.dt.Time; 027 import railo.runtime.type.util.KeyConstants; 028 /** 029 * Provides a programmatic interface to the Railo scheduling engine. You can run a specified 030 * page at scheduled intervals with the option to write out static HTML pages. This lets you offer users 031 * access to pages that publish data, such as reports, without forcing users to wait while a database transaction 032 * is performed in order to populate the data on the page. 033 **/ 034 public final class Schedule extends TagImpl { 035 036 private static final short ACTION_RUN=1; 037 private static final short ACTION_UPDATE=2; 038 private static final short ACTION_DELETE=3; 039 private static final short ACTION_LIST=4; 040 private static final short ACTION_PAUSE=5; 041 private static final short ACTION_RESUME=6; 042 043 044 /** Password if URL is protected. */ 045 private String password=""; 046 047 /** Required when action ='update'. The date when scheduling of the task should start. */ 048 private Date startdate; 049 050 /** Specifies whether to resolve links in the result page to absolute references. */ 051 private boolean resolveurl; 052 053 /** */ 054 private short action; 055 056 /** Host name or IP address of a proxy server. */ 057 private String proxyserver; 058 059 /** The date when the scheduled task ends. */ 060 private Date enddate; 061 062 /** Required with publish ='Yes' A valid filename for the published file. */ 063 private String strFile; 064 065 /** Required when creating tasks with action = 'update'. Enter a value in seconds. The time when 066 ** scheduling of the task starts. */ 067 private Time starttime; 068 069 /** The port number on the proxy server from which the task is being requested. Default is 80. When 070 ** used with resolveURL, the URLs of retrieved documents that specify a port number are automatically 071 ** resolved to preserve links in the retrieved document. */ 072 private int proxyport=80; 073 074 /** The port number on the server from which the task is being scheduled. Default is 80. When used 075 ** with resolveURL, the URLs of retrieved documents that specify a port number are automatically resolved 076 ** to preserve links in the retrieved document. */ 077 private int port=-1; 078 079 /** The time when the scheduled task ends. Enter a value in seconds. */ 080 private Time endtime; 081 082 083 /** Required when creating tasks with action = 'update'. Interval at which task should be scheduled. 084 ** Can be set in seconds or as Once, Daily, Weekly, and Monthly. The default interval is one hour. The 085 ** minimum interval is one minute. */ 086 private String interval; 087 088 /** Specifies whether the result should be saved to a file. */ 089 private boolean publish; 090 091 /** Customizes the requestTimeOut for the task operation. Can be used to extend the default timeout 092 ** for operations that require more time to execute. */ 093 private long requesttimeout=-1; 094 095 /** Username if URL is protected. */ 096 private String username; 097 098 /** Required when action = 'update'. The URL to be executed. */ 099 private String url; 100 101 /** Required with publish ='Yes' The path location for the published file. */ 102 private String strPath; 103 104 /** The name of the task to delete, update, or run. */ 105 private String task; 106 private Scheduler scheduler; 107 108 private String proxyuser; 109 private String proxypassword=""; 110 111 private String returnvariable="cfschedule"; 112 private boolean hidden; 113 private boolean readonly; 114 private String serverPassword=null; 115 private boolean paused; 116 private boolean autoDelete; 117 118 public void setAutodelete(boolean autoDelete) { 119 this.autoDelete=autoDelete; 120 } 121 122 /** 123 * @param readonly the readonly to set 124 */ 125 public void setReadonly(boolean readonly) { 126 this.readonly = readonly; 127 } 128 129 /** 130 * @param hidden the hidden to set 131 */ 132 public void setHidden(boolean hidden) { 133 this.hidden = hidden; 134 } 135 136 /** 137 * @param returnvariable The returnvariable to set. 138 */ 139 public void setReturnvariable(String returnvariable) { 140 this.returnvariable = returnvariable; 141 } 142 143 /** 144 * @param proxypassword The proxypassword to set. 145 */ 146 public void setProxypassword(String proxypassword) { 147 this.proxypassword = proxypassword; 148 } 149 /** 150 * @param proxyuser The proxyuser to set. 151 */ 152 public void setProxyuser(String proxyuser) { 153 this.proxyuser = proxyuser; 154 } 155 156 public void setPaused(boolean paused) { 157 this.paused = paused; 158 } 159 160 /** set the value password 161 * Password if URL is protected. 162 * @param password value to set 163 **/ 164 public void setPassword(String password) { 165 this.password=password; 166 } 167 168 /** set the value startdate 169 * Required when action ='update'. The date when scheduling of the task should start. 170 * @param objStartDate value to set 171 * @throws PageException 172 **/ 173 public void setStartdate(Object objStartDate) throws PageException { 174 if(StringUtil.isEmpty(objStartDate)) return; 175 this.startdate=new DateImpl(DateCaster.toDateAdvanced(objStartDate,pageContext.getTimeZone())); 176 } 177 178 /** set the value resolveurl 179 * Specifies whether to resolve links in the result page to absolute references. 180 * @param resolveurl value to set 181 **/ 182 public void setResolveurl(boolean resolveurl) { 183 this.resolveurl=resolveurl; 184 } 185 186 public void setServerpassword(String serverPassword) { 187 this.serverPassword=serverPassword; 188 } 189 190 /** set the value action 191 * 192 * @param action value to set 193 * @throws ApplicationException 194 **/ 195 public void setAction(String action) throws ApplicationException { 196 if(StringUtil.isEmpty(action)) return; 197 action=action.toLowerCase().trim(); 198 if(action.equals("run"))this.action=ACTION_RUN; 199 else if(action.equals("delete"))this.action=ACTION_DELETE; 200 else if(action.equals("update"))this.action=ACTION_UPDATE; 201 else if(action.equals("list"))this.action=ACTION_LIST; 202 else if(action.equals("lists"))this.action=ACTION_LIST; 203 else if(action.equals("pause"))this.action=ACTION_PAUSE; 204 else if(action.equals("resume"))this.action=ACTION_RESUME; 205 else throw new ApplicationException("attribute action with value ["+action+"] of tag schedule is invalid","valid attributes are [delete,run,update,list,resume,pause]"); 206 } 207 208 /** set the value proxyserver 209 * Host name or IP address of a proxy server. 210 * @param proxyserver value to set 211 **/ 212 public void setProxyserver(String proxyserver) { 213 this.proxyserver=proxyserver; 214 } 215 216 /** set the value enddate 217 * The date when the scheduled task ends. 218 * @param enddate value to set 219 * @throws PageException 220 **/ 221 public void setEnddate(Object enddate) throws PageException { 222 if(StringUtil.isEmpty(enddate)) return; 223 this.enddate=new DateImpl(DateCaster.toDateAdvanced(enddate,pageContext.getTimeZone())); 224 } 225 226 /** set the value file 227 * Required with publish ='Yes' A valid filename for the published file. 228 * @param file value to set 229 **/ 230 public void setFile(String file) { 231 this.strFile=file; 232 } 233 234 /** set the value starttime 235 * Required when creating tasks with action = 'update'. Enter a value in seconds. The time when 236 * scheduling of the task starts. 237 * @param starttime value to set 238 * @throws PageException 239 **/ 240 public void setStarttime(Object starttime) throws PageException { 241 if(StringUtil.isEmpty(starttime)) return; 242 this.starttime=DateCaster.toTime(pageContext.getTimeZone(),starttime); 243 } 244 245 /** set the value proxyport 246 * The port number on the proxy server from which the task is being requested. Default is 80. When 247 * used with resolveURL, the URLs of retrieved documents that specify a port number are automatically 248 * resolved to preserve links in the retrieved document. 249 * @param proxyport value to set 250 * @throws PageException 251 **/ 252 public void setProxyport(Object oProxyport) throws PageException { 253 if(StringUtil.isEmpty(oProxyport)) return; 254 this.proxyport=Caster.toIntValue(oProxyport); 255 } 256 257 /** set the value port 258 * The port number on the server from which the task is being scheduled. Default is 80. When used 259 * with resolveURL, the URLs of retrieved documents that specify a port number are automatically resolved 260 * to preserve links in the retrieved document. 261 * @param port value to set 262 * @throws PageException 263 **/ 264 public void setPort(Object oPort) throws PageException { 265 if(StringUtil.isEmpty(oPort)) return; 266 this.port=Caster.toIntValue(oPort); 267 } 268 269 /** set the value endtime 270 * The time when the scheduled task ends. Enter a value in seconds. 271 * @param endtime value to set 272 * @throws PageException 273 **/ 274 public void setEndtime(Object endtime) throws PageException { 275 if(StringUtil.isEmpty(endtime)) return; 276 this.endtime=DateCaster.toTime(pageContext.getTimeZone(),endtime); 277 } 278 279 /** set the value operation 280 * The type of operation the scheduler performs when executing this task. 281 * @param operation value to set 282 * @throws ApplicationException 283 **/ 284 public void setOperation(String operation) throws ApplicationException { 285 if(StringUtil.isEmpty(operation)) return; 286 operation=operation.toLowerCase().trim(); 287 if(!operation.equals("httprequest")) 288 throw new ApplicationException("attribute operation must have the value [HTTPRequest]"); 289 } 290 291 /** set the value interval 292 * Required when creating tasks with action = 'update'. Interval at which task should be scheduled. 293 * Can be set in seconds or as Once, Daily, Weekly, and Monthly. The default interval is one hour. The 294 * minimum interval is one minute. 295 * @param interval value to set 296 **/ 297 public void setInterval(String interval) { 298 if(StringUtil.isEmpty(interval)) return; 299 interval=interval.trim().toLowerCase(); 300 if(interval.equals("week")) this.interval="weekly"; 301 else if(interval.equals("day")) this.interval="daily"; 302 else if(interval.equals("month")) this.interval="monthly"; 303 else if(interval.equals("year")) this.interval="yearly"; 304 this.interval=interval; 305 } 306 307 /** set the value publish 308 * Specifies whether the result should be saved to a file. 309 * @param publish value to set 310 **/ 311 public void setPublish(boolean publish) { 312 this.publish=publish; 313 } 314 315 /** set the value requesttimeout 316 * Customizes the requestTimeOut for the task operation. Can be used to extend the default timeout 317 * for operations that require more time to execute. 318 * @param requesttimeout value to set 319 **/ 320 public void setRequesttimeout(Object oRequesttimeout) throws PageException { 321 if(StringUtil.isEmpty(oRequesttimeout)) return; 322 this.requesttimeout=Caster.toLongValue(oRequesttimeout)*1000L; 323 } 324 325 /** set the value username 326 * Username if URL is protected. 327 * @param username value to set 328 **/ 329 public void setUsername(String username) { 330 this.username=username; 331 } 332 333 /** set the value url 334 * Required when action = 'update'. The URL to be executed. 335 * @param url value to set 336 **/ 337 public void setUrl(String url) { 338 this.url=url; 339 } 340 341 /** set the value path 342 * Required with publish ='Yes' The path location for the published file. 343 * @param path value to set 344 **/ 345 public void setPath(String path) { 346 this.strPath=path; 347 } 348 349 /** set the value task 350 * The name of the task to delete, update, or run. 351 * @param task value to set 352 **/ 353 public void setTask(String task) { 354 this.task=task; 355 } 356 357 358 @Override 359 public int doStartTag() throws PageException { 360 scheduler=pageContext.getConfig().getScheduler(); 361 362 if(action!=ACTION_LIST && task==null) { 363 throw new ApplicationException("attribute task is required for tag schedule when action is not list"); 364 } 365 366 367 switch(action) { 368 case ACTION_DELETE: doDelete(); break; 369 case ACTION_RUN: doRun(); break; 370 case ACTION_UPDATE: doUpdate(); break; 371 case ACTION_LIST: doList(); break; 372 case ACTION_PAUSE: doPause(true); break; 373 case ACTION_RESUME: doPause(false); break; 374 } 375 return SKIP_BODY; 376 } 377 378 /** 379 * @throws PageException 380 */ 381 private void doUpdate() throws PageException { 382 String message="missing attribute for tag schedule with action update"; 383 String detail="required attributes are [startDate, startTime, URL, interval, operation]"; 384 385 Resource file=null; 386 //if(publish) { 387 if(!StringUtil.isEmpty(strFile) && !StringUtil.isEmpty(strPath)) { 388 file=ResourceUtil.toResourceNotExisting(pageContext, strPath); 389 file=file.getRealResource(strFile); 390 } 391 else if(!StringUtil.isEmpty(strFile)) { 392 file=ResourceUtil.toResourceNotExisting(pageContext, strFile); 393 } 394 else if(!StringUtil.isEmpty(strPath)) { 395 file=ResourceUtil.toResourceNotExisting(pageContext, strPath); 396 } 397 if(file!=null)pageContext.getConfig().getSecurityManager().checkFileLocation(pageContext.getConfig(),file,serverPassword); 398 399 // missing attributes 400 if(startdate==null || starttime==null || url==null || interval==null) 401 throw new ApplicationException(message,detail); 402 403 // timeout 404 if(requesttimeout<0)requesttimeout=pageContext.getRequestTimeout(); 405 406 // username/password 407 Credentials cr=null; 408 if(username!=null) cr=CredentialsImpl.toCredentials(username,password); 409 410 try { 411 412 ScheduleTask st=new ScheduleTaskImpl( 413 task, 414 file, 415 startdate, 416 starttime, 417 enddate, 418 endtime, 419 url, 420 port, 421 interval, 422 requesttimeout, 423 cr, 424 ProxyDataImpl.getInstance(proxyserver,proxyport,proxyuser,proxypassword), 425 resolveurl, 426 publish, 427 hidden, 428 readonly, 429 paused, 430 autoDelete); 431 scheduler.addScheduleTask(st,true); 432 } catch (Exception e) { 433 throw Caster.toPageException(e); 434 } 435 436 437 438 439 440 // 441 } 442 443 /** 444 * @throws PageException 445 */ 446 private void doRun() throws PageException { 447 try { 448 scheduler.runScheduleTask(task,true); 449 } catch (Exception e) { 450 throw Caster.toPageException(e); 451 } 452 } 453 454 /** 455 * @throws PageException 456 */ 457 private void doDelete() throws PageException { 458 try { 459 scheduler.removeScheduleTask(task,false); 460 } catch (Exception e) { 461 throw Caster.toPageException(e); 462 } 463 } 464 465 /** 466 * @throws PageException 467 * 468 */ 469 private void doList() throws PageException { 470 //if(tr ue) throw new PageRuntimeException("qqq"); 471 ScheduleTask[] tasks = scheduler.getAllScheduleTasks(); 472 final String v="VARCHAR"; 473 String[] cols = new String[]{"task","path","file","startdate","starttime","enddate","endtime", 474 "url","port","interval","timeout","username","password","proxyserver", 475 "proxyport","proxyuser","proxypassword","resolveurl","publish","valid","paused","autoDelete"}; 476 String[] types = new String[]{v,v,v,"DATE","OTHER","DATE","OTHER", 477 v,v,v,v,v,v,v, 478 v,v,v,v,"BOOLEAN",v,"BOOLEAN","BOOLEAN"}; 479 railo.runtime.type.Query query=new QueryImpl(cols,types,tasks.length,"query" 480 ); 481 try { 482 for(int i=0;i<tasks.length;i++) { 483 int row=i+1; 484 ScheduleTask task=tasks[i]; 485 query.setAt(KeyConstants._task,row,task.getTask()); 486 if(task.getResource()!=null) { 487 query.setAt(KeyConstants._path,row,task.getResource().getParent()); 488 query.setAt(KeyConstants._file,row,task.getResource().getName()); 489 } 490 query.setAt("publish",row,Caster.toBoolean(task.isPublish())); 491 query.setAt("startdate",row,task.getStartDate()); 492 query.setAt("starttime",row,task.getStartTime()); 493 query.setAt("enddate",row,task.getEndDate()); 494 query.setAt("endtime",row,task.getEndTime()); 495 query.setAt(KeyConstants._url,row,printUrl(task.getUrl())); 496 query.setAt(KeyConstants._port,row,Caster.toString(HTTPUtil.getPort(task.getUrl()))); 497 query.setAt("interval",row,task.getStringInterval()); 498 query.setAt("timeout",row,Caster.toString(task.getTimeout()/1000)); 499 query.setAt("valid",row,Caster.toString(task.isValid())); 500 if(task.hasCredentials()) { 501 query.setAt("username",row,task.getCredentials().getUsername()); 502 query.setAt("password",row,task.getCredentials().getPassword()); 503 } 504 ProxyData pd = task.getProxyData(); 505 if(ProxyDataImpl.isValid(pd)){ 506 query.setAt("proxyserver",row,pd.getServer()); 507 if(pd.getPort()>0)query.setAt("proxyport",row,Caster.toString(pd.getPort())); 508 if(ProxyDataImpl.hasCredentials(pd)) { 509 query.setAt("proxyuser",row,pd.getUsername()); 510 query.setAt("proxypassword",row,pd.getPassword()); 511 } 512 } 513 query.setAt("resolveurl",row,Caster.toString(task.isResolveURL())); 514 515 query.setAt("paused",row,Caster.toBoolean(task.isPaused())); 516 query.setAt("autoDelete",row,Caster.toBoolean(((ScheduleTaskImpl)task).isAutoDelete())); 517 518 519 520 } 521 pageContext.setVariable(returnvariable,query); 522 } 523 catch (DatabaseException e) {} 524 525 526 } 527 528 private void doPause(boolean pause) throws PageException { 529 try { 530 ((SchedulerImpl)scheduler).pauseScheduleTask(task,pause,true); 531 } catch (Exception e) { 532 throw Caster.toPageException(e); 533 } 534 535 } 536 537 private String printUrl(URL url) { 538 539 String qs=url.getQuery(); 540 if(qs==null) qs=""; 541 else if(qs.length()>0)qs="?"+qs; 542 543 String str=url.getProtocol()+"://"+url.getHost()+url.getPath()+qs; 544 return str; 545 } 546 @Override 547 public int doEndTag() { 548 return EVAL_PAGE; 549 } 550 551 @Override 552 public void release() { 553 super.release(); 554 readonly=false; 555 strPath=null; 556 strFile=null; 557 starttime=null; 558 startdate=null; 559 endtime=null; 560 enddate=null; 561 url=null; 562 port=-1; 563 interval=null; 564 requesttimeout=-1; 565 username=null; 566 password=""; 567 proxyserver=null; 568 proxyport=80; 569 proxyuser=null; 570 proxypassword=""; 571 resolveurl=false; 572 publish=false; 573 returnvariable="cfschedule"; 574 task=null; 575 hidden=false; 576 serverPassword=null; 577 paused=false; 578 autoDelete=false; 579 } 580 581 }