package railo.runtime.schedule; import java.io.IOException; import java.util.ArrayList; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import railo.commons.io.log.LogAndSource; import railo.commons.io.res.Resource; import railo.commons.lang.StringUtil; import railo.loader.engine.CFMLEngine; import railo.runtime.config.Config; import railo.runtime.engine.CFMLEngineImpl; import railo.runtime.exp.PageException; import railo.runtime.net.proxy.ProxyData; import railo.runtime.net.proxy.ProxyDataImpl; import railo.runtime.op.Caster; /** * scheduler class to execute the scheduled tasks */ public final class SchedulerImpl implements Scheduler { private ScheduleTaskImpl[] tasks; private Resource schedulerFile; private Document doc; private LogAndSource log; private StorageUtil su=new StorageUtil(); private String charset; private Config config; //private String md5; private CFMLEngineImpl engine; /** * constructor of the sheduler * @param config * @param schedulerDir schedule file * @param log * @throws IOException * @throws SAXException * @throws PageException */ public SchedulerImpl(CFMLEngine engine,Config config, Resource schedulerDir, LogAndSource log, String charset) throws SAXException, IOException, PageException { this.engine=(CFMLEngineImpl) engine; this.charset=charset; this.config=config; initFile(schedulerDir,log); doc=su.loadDocument(schedulerFile); tasks=readInAllTasks(); init(); } /** * creates a empty Scheduler, used for event gateway context * @param engine * @param config * @param log * @throws SAXException * @throws IOException * @throws PageException */ public SchedulerImpl(CFMLEngine engine,String xml,Config config, LogAndSource log) { this.engine=(CFMLEngineImpl) engine; this.config=config; try { doc=su.loadDocument(xml); } catch (Exception e) {} tasks=new ScheduleTaskImpl[0]; init(); } private void initFile(Resource schedulerDir, LogAndSource log) throws IOException { this.schedulerFile=schedulerDir.getRealResource("scheduler.xml"); if(!schedulerFile.exists()) su.loadFile(schedulerFile,"/resource/schedule/default.xml"); this.log=log; } /** * initialize all tasks */ private void init() { for(int i=0;i<tasks.length;i++) { init(tasks[i]); } } private void init(ScheduleTask task) { new ScheduledTaskThread(engine,this,config,log,task,charset).start(); } /** * read in all schedule tasks * @return all schedule tasks * @throws PageException */ private ScheduleTaskImpl[] readInAllTasks() throws PageException { Element root = doc.getDocumentElement(); NodeList children = root.getChildNodes(); ArrayList<ScheduleTaskImpl> list=new ArrayList<ScheduleTaskImpl>(); int len=children.getLength(); for(int i=0;i<len;i++) { Node n=children.item(i); if(n instanceof Element && n.getNodeName().equals("task")) { list.add(readInTask((Element)n)); } } return list.toArray(new ScheduleTaskImpl[list.size()]); } /** * read in a single task element * @param el * @return matching task to Element * @throws PageException */ private ScheduleTaskImpl readInTask(Element el) throws PageException { long timeout=su.toLong(el,"timeout"); if(timeout>0 && timeout<1000)timeout*=1000; if(timeout<0)timeout=600000; try { ScheduleTaskImpl st = new ScheduleTaskImpl( su.toString(el,"name").trim(), su.toResource(config,el,"file"), su.toDate(config,el,"startDate"), su.toTime(config,el,"startTime"), su.toDate(config,el,"endDate"), su.toTime(config,el,"endTime"), su.toString(el,"url"), su.toInt(el,"port",-1), su.toString(el,"interval"), timeout, su.toCredentials(el,"username","password"), ProxyDataImpl.getInstance( su.toString(el,"proxyHost"), su.toInt(el,"proxyPort",80), su.toString(el,"proxyUser"), su.toString(el,"proxyPassword")), su.toBoolean(el,"resolveUrl"), su.toBoolean(el,"publish"), su.toBoolean(el,"hidden",false), su.toBoolean(el,"readonly",false), su.toBoolean(el,"paused",false), su.toBoolean(el,"autoDelete",false)); return st; } catch (Exception e) {e.printStackTrace(); throw Caster.toPageException(e); } } private void addTask(ScheduleTaskImpl task) { for(int i=0;i<tasks.length;i++){ if(!tasks[i].getTask().equals(task.getTask())) continue; if(!tasks[i].md5().equals(task.md5())) { tasks[i].setValid(false); tasks[i]=task; init(task); } return; } ScheduleTaskImpl[] tmp = new ScheduleTaskImpl[tasks.length+1]; for(int i=0;i<tasks.length;i++){ tmp[i]=tasks[i]; } tmp[tasks.length]=task; tasks=tmp; init(task); } /** * sets all attributes in XML Element from Schedule Task * @param el * @param task */ private void setAttributes(Element el,ScheduleTask task) { if(el==null) return; NamedNodeMap atts = el.getAttributes(); for(int i=atts.getLength()-1;i>=0;i--) { Attr att=(Attr) atts.item(i); el.removeAttribute(att.getName()); } su.setString(el,"name",task.getTask()); su.setFile(el,"file",task.getResource()); su.setDateTime(el,"startDate",task.getStartDate()); su.setDateTime(el,"startTime",task.getStartTime()); su.setDateTime(el,"endDate",task.getEndDate()); su.setDateTime(el,"endTime",task.getEndTime()); su.setString(el,"url",task.getUrl().toExternalForm()); su.setInt(el,"port",task.getUrl().getPort()); su.setString(el,"interval",task.getIntervalAsString()); su.setInt(el,"timeout",(int)task.getTimeout()); su.setCredentials(el,"username","password",task.getCredentials()); ProxyData pd = task.getProxyData(); su.setString(el,"proxyHost",StringUtil.emptyIfNull(pd==null?"":pd.getServer())); su.setString(el,"proxyUser",StringUtil.emptyIfNull(pd==null?"":pd.getUsername())); su.setString(el,"proxyPassword",StringUtil.emptyIfNull(pd==null?"":pd.getPassword())); su.setInt(el,"proxyPort",pd==null?0:pd.getPort()); su.setBoolean(el,"resolveUrl",task.isResolveURL()); su.setBoolean(el,"publish",task.isPublish()); su.setBoolean(el,"hidden",((ScheduleTaskImpl)task).isHidden()); su.setBoolean(el,"readonly",((ScheduleTaskImpl)task).isReadonly()); su.setBoolean(el,"autoDelete",((ScheduleTaskImpl)task).isAutoDelete()); } /** * translate a schedule task object to a XML Element * @param task schedule task to translate * @return XML Element */ private Element toElement(ScheduleTask task) { Element el = doc.createElement("task"); setAttributes(el,task); return el; } @Override public ScheduleTask getScheduleTask(String name) throws ScheduleException { for(int i=0;i<tasks.length;i++) { if(tasks[i].getTask().equalsIgnoreCase(name)) return tasks[i]; } throw new ScheduleException("schedule task with name "+name+" doesn't exist"); } @Override public ScheduleTask getScheduleTask(String name, ScheduleTask defaultValue) { for(int i=0;i<tasks.length;i++) { if(tasks[i]!=null && tasks[i].getTask().equalsIgnoreCase(name)) return tasks[i]; } return defaultValue; } @Override public ScheduleTask[] getAllScheduleTasks() { ArrayList<ScheduleTask> list=new ArrayList<ScheduleTask>(); for(int i=0;i<tasks.length;i++) { if(!tasks[i].isHidden()) list.add(tasks[i]); } return list.toArray(new ScheduleTask[list.size()]); } @Override public void addScheduleTask(ScheduleTask task, boolean allowOverwrite) throws ScheduleException, IOException { //ScheduleTask exTask = getScheduleTask(task.getTask(),null); NodeList list = doc.getDocumentElement().getChildNodes(); Element el=su.getElement(list,"name", task.getTask()); if(!allowOverwrite && el!=null) throw new ScheduleException("there is already a schedule task with name "+task.getTask()); addTask((ScheduleTaskImpl)task); // Element update if(el!=null) { setAttributes(el,task); } // Element insert else { doc.getDocumentElement().appendChild(toElement(task)); } su.store(doc,schedulerFile); } @Override public void pauseScheduleTask(String name, boolean pause, boolean throwWhenNotExist) throws ScheduleException, IOException { for(int i=0;i<tasks.length;i++) { if(tasks[i].getTask().equalsIgnoreCase(name)) { tasks[i].setPaused(pause); } } NodeList list = doc.getDocumentElement().getChildNodes(); Element el=su.getElement(list,"name", name); if(el!=null) { el.setAttribute("paused", Caster.toString(pause)); //el.getParentNode().removeChild(el); } else if(throwWhenNotExist) throw new ScheduleException("can't "+(pause?"pause":"resume")+" schedule task ["+name+"], task doesn't exist"); //init(); su.store(doc,schedulerFile); } @Override public synchronized void removeScheduleTask(String name, boolean throwWhenNotExist) throws IOException, ScheduleException { int pos=-1; for(int i=0;i<tasks.length;i++) { if(tasks[i].getTask().equalsIgnoreCase(name)) { tasks[i].setValid(false); pos=i; } } if(pos!=-1) { ScheduleTaskImpl[] newTasks=new ScheduleTaskImpl[tasks.length-1]; int count=0; for(int i=0;i<tasks.length;i++) { if(i!=pos)newTasks[count++]=tasks[i]; } tasks=newTasks; } NodeList list = doc.getDocumentElement().getChildNodes(); Element el=su.getElement(list,"name", name); if(el!=null) { el.getParentNode().removeChild(el); } else if(throwWhenNotExist) throw new ScheduleException("can't delete schedule task ["+name+"], task doesn't exist"); //init(); su.store(doc,schedulerFile); } public synchronized void removeIfNoLonerValid(ScheduleTask task) throws IOException { ScheduleTaskImpl sti=(ScheduleTaskImpl) task; if(sti.isValid() || !sti.isAutoDelete()) return; try { removeScheduleTask(task.getTask(), false); } catch (ScheduleException e) {} } @Override public synchronized void runScheduleTask(String name, boolean throwWhenNotExist) throws IOException, ScheduleException { ScheduleTask task = getScheduleTask(name); if(task!=null) { execute(task); } else if(throwWhenNotExist) throw new ScheduleException("can't run schedule task ["+name+"], task doesn't exist"); su.store(doc,schedulerFile); } public void execute(ScheduleTask task) { new ExecutionThread(config,log,task,charset).start(); } @Override public LogAndSource getLogger() { return log; } }