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