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