001 package railo.runtime.schedule; 002 003 import java.io.IOException; 004 import java.util.ArrayList; 005 006 import org.w3c.dom.Attr; 007 import org.w3c.dom.Document; 008 import org.w3c.dom.Element; 009 import org.w3c.dom.NamedNodeMap; 010 import org.w3c.dom.Node; 011 import org.w3c.dom.NodeList; 012 import org.xml.sax.SAXException; 013 014 import railo.commons.io.log.LogAndSource; 015 import railo.commons.io.res.Resource; 016 import railo.loader.engine.CFMLEngine; 017 import railo.runtime.config.Config; 018 import railo.runtime.engine.CFMLEngineImpl; 019 import railo.runtime.exp.PageException; 020 import railo.runtime.op.Caster; 021 022 /** 023 * scheduler class to execute the scheduled tasks 024 */ 025 public final class SchedulerImpl implements Scheduler { 026 027 private ScheduleTaskImpl[] tasks; 028 private Resource schedulerFile; 029 private Document doc; 030 private LogAndSource log; 031 private StorageUtil su=new StorageUtil(); 032 private String charset; 033 private Config config; 034 //private String md5; 035 036 private CFMLEngineImpl engine; 037 038 /** 039 * constructor of the sheduler 040 * @param config 041 * @param schedulerDir schedule file 042 * @param log 043 * @throws IOException 044 * @throws SAXException 045 * @throws PageException 046 */ 047 public SchedulerImpl(CFMLEngine engine,Config config, Resource schedulerDir, LogAndSource log, String charset) throws SAXException, IOException, PageException { 048 this.engine=(CFMLEngineImpl) engine; 049 this.charset=charset; 050 this.config=config; 051 052 initFile(schedulerDir,log); 053 doc=su.loadDocument(schedulerFile); 054 tasks=readInAllTasks(); 055 init(); 056 } 057 058 059 /** 060 * creates a empty Scheduler, used for event gateway context 061 * @param engine 062 * @param config 063 * @param log 064 * @throws SAXException 065 * @throws IOException 066 * @throws PageException 067 */ 068 public SchedulerImpl(CFMLEngine engine,String xml,Config config, LogAndSource log) { 069 this.engine=(CFMLEngineImpl) engine; 070 this.config=config; 071 try { 072 doc=su.loadDocument(xml); 073 } catch (Exception e) {} 074 tasks=new ScheduleTaskImpl[0]; 075 init(); 076 } 077 078 079 080 081 private void initFile(Resource schedulerDir, LogAndSource log) throws IOException { 082 this.schedulerFile=schedulerDir.getRealResource("scheduler.xml"); 083 if(!schedulerFile.exists()) su.loadFile(schedulerFile,"/resource/schedule/default.xml"); 084 this.log=log; 085 } 086 087 /** 088 * initialize all tasks 089 */ 090 private void init() { 091 for(int i=0;i<tasks.length;i++) { 092 init(tasks[i]); 093 } 094 } 095 096 private void init(ScheduleTask task) { 097 new ScheduledTaskThread(engine,this,config,log,task,charset).start(); 098 } 099 100 /** 101 * read in all schedule tasks 102 * @return all schedule tasks 103 * @throws PageException 104 */ 105 private ScheduleTaskImpl[] readInAllTasks() throws PageException { 106 Element root = doc.getDocumentElement(); 107 NodeList children = root.getChildNodes(); 108 ArrayList<ScheduleTaskImpl> list=new ArrayList<ScheduleTaskImpl>(); 109 110 int len=children.getLength(); 111 for(int i=0;i<len;i++) { 112 Node n=children.item(i); 113 if(n instanceof Element && n.getNodeName().equals("task")) { 114 list.add(readInTask((Element)n)); 115 } 116 } 117 return (ScheduleTaskImpl[]) list.toArray(new ScheduleTaskImpl[list.size()]); 118 } 119 120 121 122 /** 123 * read in a single task element 124 * @param el 125 * @return matching task to Element 126 * @throws PageException 127 */ 128 private ScheduleTaskImpl readInTask(Element el) throws PageException { 129 long timeout=su.toLong(el,"timeout"); 130 if(timeout>0 && timeout<1000)timeout*=1000; 131 if(timeout<0)timeout=600000; 132 try { 133 ScheduleTaskImpl st = new ScheduleTaskImpl( 134 su.toString(el,"name").trim(), 135 su.toResource(config,el,"file"), 136 su.toDate(config,el,"startDate"), 137 su.toTime(config,el,"startTime"), 138 su.toDate(config,el,"endDate"), 139 su.toTime(config,el,"endTime"), 140 su.toString(el,"url"), 141 su.toInt(el,"port",-1), 142 su.toString(el,"interval"), 143 timeout, 144 su.toCredentials(el,"username","password"), 145 su.toString(el,"proxyHost"), 146 su.toInt(el,"proxyPort",80), 147 su.toCredentials(el,"proxyUser","proxyPassword"), 148 su.toBoolean(el,"resolveUrl"), 149 su.toBoolean(el,"publish"), 150 su.toBoolean(el,"hidden",false), 151 su.toBoolean(el,"readonly",false), 152 su.toBoolean(el,"paused",false), 153 su.toBoolean(el,"autoDelete",false)); 154 return st; 155 } catch (Exception e) {e.printStackTrace(); 156 throw Caster.toPageException(e); 157 } 158 } 159 160 161 private void addTask(ScheduleTaskImpl task) { 162 for(int i=0;i<tasks.length;i++){ 163 if(!tasks[i].getTask().equals(task.getTask())) continue; 164 if(!tasks[i].md5().equals(task.md5())) { 165 tasks[i].setValid(false); 166 tasks[i]=task; 167 init(task); 168 } 169 return; 170 } 171 172 ScheduleTaskImpl[] tmp = new ScheduleTaskImpl[tasks.length+1]; 173 for(int i=0;i<tasks.length;i++){ 174 tmp[i]=tasks[i]; 175 } 176 tmp[tasks.length]=task; 177 tasks=tmp; 178 init(task); 179 } 180 181 /** 182 * sets all attributes in XML Element from Schedule Task 183 * @param el 184 * @param task 185 */ 186 private void setAttributes(Element el,ScheduleTask task) { 187 if(el==null) return; 188 NamedNodeMap atts = el.getAttributes(); 189 190 for(int i=atts.getLength()-1;i>=0;i--) { 191 Attr att=(Attr) atts.item(i); 192 el.removeAttribute(att.getName()); 193 } 194 195 su.setString(el,"name",task.getTask()); 196 su.setFile(el,"file",task.getResource()); 197 su.setDateTime(el,"startDate",task.getStartDate()); 198 su.setDateTime(el,"startTime",task.getStartTime()); 199 su.setDateTime(el,"endDate",task.getEndDate()); 200 su.setDateTime(el,"endTime",task.getEndTime()); 201 su.setString(el,"url",task.getUrl().toExternalForm()); 202 su.setInt(el,"port",task.getUrl().getPort()); 203 su.setString(el,"interval",task.getIntervalAsString()); 204 su.setInt(el,"timeout",(int)task.getTimeout()); 205 su.setCredentials(el,"username","password",task.getCredentials()); 206 su.setString(el,"proxyHost",task.getProxyHost()); 207 su.setInt(el,"proxyPort",task.getProxyPort()); 208 su.setCredentials(el,"proxyUser","proxyPassword",task.getProxyCredentials()); 209 su.setBoolean(el,"resolveUrl",task.isResolveURL()); 210 su.setBoolean(el,"publish",task.isPublish()); 211 su.setBoolean(el,"hidden",((ScheduleTaskImpl)task).isHidden()); 212 su.setBoolean(el,"readonly",((ScheduleTaskImpl)task).isReadonly()); 213 su.setBoolean(el,"autoDelete",((ScheduleTaskImpl)task).isAutoDelete()); 214 } 215 216 /** 217 * translate a schedule task object to a XML Element 218 * @param task schedule task to translate 219 * @return XML Element 220 */ 221 private Element toElement(ScheduleTask task) { 222 Element el = doc.createElement("task"); 223 setAttributes(el,task); 224 return el; 225 } 226 227 /** 228 * @see railo.runtime.schedule.Scheduler#getScheduleTask(java.lang.String) 229 */ 230 public ScheduleTask getScheduleTask(String name) throws ScheduleException { 231 for(int i=0;i<tasks.length;i++) { 232 if(tasks[i].getTask().equalsIgnoreCase(name)) return tasks[i]; 233 } 234 throw new ScheduleException("schedule task with name "+name+" doesn't exist"); 235 } 236 237 /** 238 * @see railo.runtime.schedule.Scheduler#getScheduleTask(java.lang.String, railo.runtime.schedule.ScheduleTask) 239 */ 240 public ScheduleTask getScheduleTask(String name, ScheduleTask defaultValue) { 241 for(int i=0;i<tasks.length;i++) { 242 if(tasks[i]!=null && tasks[i].getTask().equalsIgnoreCase(name)) return tasks[i]; 243 } 244 return defaultValue; 245 } 246 247 /** 248 * @see railo.runtime.schedule.Scheduler#getAllScheduleTasks() 249 */ 250 public ScheduleTask[] getAllScheduleTasks() { 251 ArrayList<ScheduleTask> list=new ArrayList<ScheduleTask>(); 252 for(int i=0;i<tasks.length;i++) { 253 if(!tasks[i].isHidden()) list.add(tasks[i]); 254 } 255 return (ScheduleTask[]) list.toArray(new ScheduleTask[list.size()]); 256 } 257 258 /** 259 * @see railo.runtime.schedule.Scheduler#addScheduleTask(railo.runtime.schedule.ScheduleTask, boolean) 260 */ 261 public void addScheduleTask(ScheduleTask task, boolean allowOverwrite) throws ScheduleException, IOException { 262 //ScheduleTask exTask = getScheduleTask(task.getTask(),null); 263 NodeList list = doc.getDocumentElement().getChildNodes(); 264 Element el=su.getElement(list,"name", task.getTask()); 265 266 if(!allowOverwrite && el!=null) 267 throw new ScheduleException("there is already a schedule task with name "+task.getTask()); 268 269 addTask((ScheduleTaskImpl)task); 270 271 // Element update 272 if(el!=null) { 273 setAttributes(el,task); 274 } 275 // Element insert 276 else { 277 doc.getDocumentElement().appendChild(toElement(task)); 278 } 279 280 su.store(doc,schedulerFile); 281 } 282 283 284 // FUTURE add to interface 285 public void pauseScheduleTask(String name, boolean pause, boolean throwWhenNotExist) throws ScheduleException, IOException { 286 287 for(int i=0;i<tasks.length;i++) { 288 if(tasks[i].getTask().equalsIgnoreCase(name)) { 289 tasks[i].setPaused(pause); 290 291 } 292 } 293 294 NodeList list = doc.getDocumentElement().getChildNodes(); 295 Element el=su.getElement(list,"name", name); 296 if(el!=null) { 297 el.setAttribute("paused", Caster.toString(pause)); 298 //el.getParentNode().removeChild(el); 299 } 300 else if(throwWhenNotExist) throw new ScheduleException("can't "+(pause?"pause":"resume")+" schedule task ["+name+"], task doesn't exist"); 301 302 //init(); 303 su.store(doc,schedulerFile); 304 } 305 306 /** 307 * @see railo.runtime.schedule.Scheduler#removeScheduleTask(java.lang.String, boolean) 308 */ 309 public synchronized void removeScheduleTask(String name, boolean throwWhenNotExist) throws IOException, ScheduleException { 310 311 int pos=-1; 312 for(int i=0;i<tasks.length;i++) { 313 if(tasks[i].getTask().equalsIgnoreCase(name)) { 314 tasks[i].setValid(false); 315 pos=i; 316 } 317 } 318 if(pos!=-1) { 319 ScheduleTaskImpl[] newTasks=new ScheduleTaskImpl[tasks.length-1]; 320 int count=0; 321 for(int i=0;i<tasks.length;i++) { 322 if(i!=pos)newTasks[count++]=tasks[i]; 323 324 } 325 tasks=newTasks; 326 } 327 328 329 NodeList list = doc.getDocumentElement().getChildNodes(); 330 Element el=su.getElement(list,"name", name); 331 if(el!=null) { 332 el.getParentNode().removeChild(el); 333 } 334 else if(throwWhenNotExist) throw new ScheduleException("can't delete schedule task ["+name+"], task doesn't exist"); 335 336 //init(); 337 su.store(doc,schedulerFile); 338 } 339 340 public synchronized void removeIfNoLonerValid(ScheduleTask task) throws IOException { 341 ScheduleTaskImpl sti=(ScheduleTaskImpl) task; 342 if(sti.isValid() || !sti.isAutoDelete()) return; 343 344 345 try { 346 removeScheduleTask(task.getTask(), false); 347 } catch (ScheduleException e) {} 348 } 349 350 351 /** 352 * @see railo.runtime.schedule.Scheduler#runScheduleTask(java.lang.String, boolean) 353 */ 354 public synchronized void runScheduleTask(String name, boolean throwWhenNotExist) throws IOException, ScheduleException { 355 ScheduleTask task = getScheduleTask(name); 356 357 if(task!=null) { 358 execute(task); 359 } 360 else if(throwWhenNotExist) throw new ScheduleException("can't run schedule task ["+name+"], task doesn't exist"); 361 362 363 su.store(doc,schedulerFile); 364 } 365 366 /** 367 * @param task 368 * @see railo.runtime.schedule.Scheduler#execute() 369 */ 370 public void execute(ScheduleTask task) { 371 new ExecutionThread(config,log,task,charset).start(); 372 } 373 374 375 /** 376 * @see railo.runtime.schedule.Scheduler#getNextExecutionTime() 377 */ 378 public long getNextExecutionTime() { 379 // no longer called and used 380 return -1; 381 } 382 383 /** 384 * @see railo.runtime.schedule.Scheduler#getLogger() 385 */ 386 public LogAndSource getLogger() { 387 return log; 388 } 389 390 /* 391 * FUTURE remove 392 * */ 393 public void execute() { 394 395 } 396 }