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 }