001    package railo.runtime.tag;
002    
003    import railo.commons.io.res.Resource;
004    import railo.commons.io.res.util.ResourceUtil;
005    import railo.commons.lang.SerializableObject;
006    import railo.commons.lang.StringUtil;
007    import railo.runtime.exp.ApplicationException;
008    import railo.runtime.exp.PageException;
009    import railo.runtime.exp.SecurityException;
010    import railo.runtime.ext.tag.BodyTagImpl;
011    import railo.runtime.op.Caster;
012    import railo.runtime.security.SecurityManager;
013    
014    /**
015    * Enables CFML developers to execute a process on a server computer.
016    *
017    *
018    *
019    **/
020    public final class Execute extends BodyTagImpl {
021    
022            /** Command-line arguments passed to the application. */
023            private String arguments=null;
024    
025            /** Indicates how long, in seconds, the CFML executing thread waits for the spawned process. 
026            **              A timeout of 0 is equivalent to the non-blocking mode of executing. A very high timeout value is 
027            **              equivalent to a blocking mode of execution. The default is 0; therefore, the CFML thread spawns 
028            **              a process and returns without waiting for the process to terminate.If no output file is specified, 
029            **              and the timeout value is 0, the program output is discarded. */
030            private long timeout;
031    
032            /** The full pathname of the application to execute.
033            **              Note: On Windows, you must specify the extension as part of the application's name. For example, 
034            **              myapp.exe, */
035            private String name=null;
036    
037            /** The file to which to direct the output of the program. If not specified, the output is 
038            **              displayed on the page from which it was called. */
039            private Resource outputfile;
040    
041        private String variable;
042    
043            private String body;
044    
045            private boolean terminateOnTimeout=false;
046    
047            /**
048            * @see javax.servlet.jsp.tagext.Tag#release()
049            */
050            public void release()   {
051                    super.release();
052                    arguments=null;
053                    timeout=0L;
054                    name=null;
055                    outputfile=null;
056                    variable=null;
057                    body=null;
058                    terminateOnTimeout=false;
059            }
060    
061            /** set the value arguments
062            *  Command-line arguments passed to the application.
063            * @param args value to set
064            **/
065            public void setArguments(Object args)   {
066                    
067                if(args instanceof railo.runtime.type.Collection) {
068                        StringBuffer sb=new StringBuffer();
069                        railo.runtime.type.Collection coll=(railo.runtime.type.Collection)args;
070                        railo.runtime.type.Collection.Key[] keys=coll.keys();
071                        for(int i=0;i<keys.length;i++) {
072                            sb.append(' ');
073                            sb.append(coll.get(keys[i],null));
074                        }
075                        arguments=args.toString();
076                    }
077                else if(args instanceof String) {
078                    arguments=" "+args.toString();
079                }
080                else this.arguments="";
081            }
082    
083            /** set the value timeout
084            *  Indicates how long, in seconds, the CFML executing thread waits for the spawned process. 
085            *               A timeout of 0 is equivalent to the non-blocking mode of executing. A very high timeout value is 
086            *               equivalent to a blocking mode of execution. The default is 0; therefore, the CFML thread spawns 
087            *               a process and returns without waiting for the process to terminate.If no output file is specified, 
088            *               and the timeout value is 0, the program output is discarded.
089            * @param timeout value to set
090             * @throws ApplicationException 
091            **/
092            public void setTimeout(double timeout) throws ApplicationException      {
093                    if(timeout<0) 
094                            throw new ApplicationException("value must be a positive number now ["+Caster.toString(timeout)+"]");
095                    this.timeout=(long)(timeout*1000L);
096            }
097    
098            public void setTerminateontimeout(boolean terminateontimeout)   {
099                    this.terminateOnTimeout=terminateontimeout;
100            }
101            
102            /** set the value name
103            *  The full pathname of the application to execute.
104            *               Note: On Windows, you must specify the extension as part of the application's name. For example, 
105            *               myapp.exe,
106            * @param name value to set
107            **/
108            public void setName(String name)        {
109                    this.name=name;
110            }
111            
112            /**
113             * define name of variable where output is written to
114             * @param variable
115             * @throws PageException
116             */
117            public void setVariable(String variable) throws PageException   {
118                    this.variable=variable;
119                    pageContext.setVariable(variable,"");
120            }       
121    
122            /** set the value outputfile
123            *  The file to which to direct the output of the program. If not specified, the output is 
124            *               displayed on the page from which it was called.
125            * @param outputfile value to set
126             * @throws SecurityException
127            **/
128            public void setOutputfile(String outputfile)    {
129                try {
130                this.outputfile=ResourceUtil.toResourceExistingParent(pageContext,outputfile);
131                pageContext.getConfig().getSecurityManager().checkFileLocation(this.outputfile);
132                    
133            } 
134                catch (PageException e) {
135                this.outputfile=pageContext.getConfig().getTempDirectory().getRealResource(outputfile);
136                if(!this.outputfile.getParentResource().exists())
137                    this.outputfile=null;
138                else if(!this.outputfile.isFile())
139                    this.outputfile=null;
140                else if(!this.outputfile.exists()) {
141                    ResourceUtil.createFileEL(this.outputfile, false);
142                    //try {
143                        //this.outputfile.createNewFile();
144                    /*} catch (IOException e1) {
145                        this.outputfile=null;
146                    }*/
147                }
148            }
149            }
150    
151    
152            /**
153            * @throws ApplicationException
154             * @see javax.servlet.jsp.tagext.Tag#doStartTag()
155            */
156            public int doStartTag() throws PageException    {
157                    return EVAL_BODY_BUFFERED;
158            }
159            
160            private void _execute() throws Exception        {
161                Object monitor=new SerializableObject();
162                
163                String command="";
164                if(name==null) {
165                    if(StringUtil.isEmpty(body)) {
166                            required("execute", "name", name);
167                            required("execute", "arguments", arguments);
168                    }
169                    else command=body;
170                }
171                else {
172                    if(arguments==null)command=name;
173                    else command=name+arguments;
174                }
175                
176                
177                
178                _Execute execute=new _Execute(pageContext,monitor,command,outputfile,variable,body);
179                
180                //if(timeout<=0)execute._run();
181                //else {
182            execute.start();
183            if(timeout>0){
184                    try {
185                        synchronized(monitor) {
186                            monitor.wait(timeout);
187                        }
188                    } 
189                        finally {
190                            execute.abort(terminateOnTimeout);
191                    }
192                        if(execute.hasException()) {
193                            throw execute.getException();
194                        }
195                        if(!execute.hasFinished())
196                            throw new ApplicationException("timeout ["+(timeout)+" ms] expired while executing ["+command+"]");
197                        //}
198            }
199                
200            }
201    
202            /**
203            * @throws PageException 
204             * @see javax.servlet.jsp.tagext.Tag#doEndTag()
205            */
206            public int doEndTag() throws PageException      {
207                    if(pageContext.getConfig().getSecurityManager().getAccess(SecurityManager.TYPE_TAG_EXECUTE)==SecurityManager.VALUE_NO) 
208                            throw new SecurityException("can't access tag [execute]","access is prohibited by security manager");
209                try {
210                _execute();
211            } 
212                catch (PageException pe) {
213               throw pe;
214            }
215            catch (Exception e) {e.printStackTrace();
216               throw new ApplicationException("Error invoking external process",e.getMessage());
217            }
218                return EVAL_PAGE;
219            }
220    
221            /**
222            * @see javax.servlet.jsp.tagext.BodyTag#doInitBody()
223            */
224            public void doInitBody()        {
225                    
226            }
227    
228            /**
229            * @see javax.servlet.jsp.tagext.BodyTag#doAfterBody()
230            */
231            public int doAfterBody()        {
232                    body=bodyContent.getString();
233                    if(!StringUtil.isEmpty(body))body=body.trim();
234                    return SKIP_BODY;
235            }
236    }