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