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    }