package railo.runtime.tag; import java.util.Iterator; import railo.commons.io.res.Resource; import railo.commons.io.res.util.ResourceUtil; import railo.commons.lang.SerializableObject; import railo.commons.lang.StringUtil; import railo.runtime.exp.ApplicationException; import railo.runtime.exp.PageException; import railo.runtime.exp.SecurityException; import railo.runtime.ext.tag.BodyTagImpl; import railo.runtime.op.Caster; import railo.runtime.security.SecurityManager; /** * Enables CFML developers to execute a process on a server computer. * * * **/ public final class Execute extends BodyTagImpl { /** Command-line arguments passed to the application. */ private String arguments=null; /** Indicates how long, in seconds, the CFML executing thread waits for the spawned process. ** A timeout of 0 is equivalent to the non-blocking mode of executing. A very high timeout value is ** equivalent to a blocking mode of execution. The default is 0; therefore, the CFML thread spawns ** a process and returns without waiting for the process to terminate.If no output file is specified, ** and the timeout value is 0, the program output is discarded. */ private long timeout; /** The full pathname of the application to execute. ** Note: On Windows, you must specify the extension as part of the application's name. For example, ** myapp.exe, */ private String name=null; /** The file to which to direct the output of the program. If not specified, the output is ** displayed on the page from which it was called. */ private Resource outputfile; private Resource errorFile; private String variable; private String errorVariable; private String body; private boolean terminateOnTimeout=false; @Override public void release() { super.release(); arguments=null; timeout=0L; name=null; outputfile=null; errorFile=null; variable=null; errorVariable=null; body=null; terminateOnTimeout=false; } /** set the value arguments * Command-line arguments passed to the application. * @param args value to set **/ public void setArguments(Object args) { if(args instanceof railo.runtime.type.Collection) { StringBuffer sb=new StringBuffer(); railo.runtime.type.Collection coll=(railo.runtime.type.Collection)args; //railo.runtime.type.Collection.Key[] keys=coll.keys(); Iterator<Object> it = coll.valueIterator(); while(it.hasNext()) { sb.append(' '); sb.append(it.next()); } arguments=args.toString(); } else if(args instanceof String) { arguments=" "+args.toString(); } else this.arguments=""; } /** set the value timeout * Indicates how long, in seconds, the CFML executing thread waits for the spawned process. * A timeout of 0 is equivalent to the non-blocking mode of executing. A very high timeout value is * equivalent to a blocking mode of execution. The default is 0; therefore, the CFML thread spawns * a process and returns without waiting for the process to terminate.If no output file is specified, * and the timeout value is 0, the program output is discarded. * @param timeout value to set * @throws ApplicationException **/ public void setTimeout(double timeout) throws ApplicationException { if(timeout<0) throw new ApplicationException("value must be a positive number now ["+Caster.toString(timeout)+"]"); this.timeout=(long)(timeout*1000L); } public void setTerminateontimeout(boolean terminateontimeout) { this.terminateOnTimeout=terminateontimeout; } /** set the value name * The full pathname of the application to execute. * Note: On Windows, you must specify the extension as part of the application's name. For example, * myapp.exe, * @param name value to set **/ public void setName(String name) { this.name=name; } /** * define name of variable where output is written to * @param variable * @throws PageException */ public void setVariable(String variable) throws PageException { this.variable=variable; pageContext.setVariable(variable,""); } public void setErrorvariable(String errorVariable) throws PageException { this.errorVariable = errorVariable; pageContext.setVariable(errorVariable, ""); } /** set the value outputfile * The file to which to direct the output of the program. If not specified, the output is * displayed on the page from which it was called. * @param outputfile value to set * @throws SecurityException **/ public void setOutputfile(String outputfile) { try { this.outputfile=ResourceUtil.toResourceExistingParent(pageContext,outputfile); pageContext.getConfig().getSecurityManager().checkFileLocation(this.outputfile); } catch (PageException e) { this.outputfile=pageContext.getConfig().getTempDirectory().getRealResource(outputfile); if(!this.outputfile.getParentResource().exists()) this.outputfile=null; else if(!this.outputfile.isFile()) this.outputfile=null; else if(!this.outputfile.exists()) { ResourceUtil.createFileEL(this.outputfile, false); //try { //this.outputfile.createNewFile(); /*} catch (IOException e1) { this.outputfile=null; }*/ } } } public void setErrorfile(String errorfile) { try { this.errorFile = ResourceUtil.toResourceExistingParent(pageContext,errorfile); pageContext.getConfig().getSecurityManager().checkFileLocation(this.errorFile); } catch (PageException e) { this.errorFile = pageContext.getConfig().getTempDirectory().getRealResource(errorfile); if(!this.errorFile.getParentResource().exists()) this.errorFile=null; else if(!this.errorFile.isFile()) this.errorFile=null; else if(!this.errorFile.exists()) { ResourceUtil.createFileEL(this.errorFile, false); } } } @Override public int doStartTag() throws PageException { return EVAL_BODY_BUFFERED; } private void _execute() throws Exception { Object monitor=new SerializableObject(); String command=""; if(name==null) { if(StringUtil.isEmpty(body)) { required("execute", "name", name); required("execute", "arguments", arguments); } else command=body; } else { if(arguments==null)command=name; else command=name+arguments; } _Execute execute=new _Execute(pageContext, monitor, command, outputfile, variable, errorFile, errorVariable); //if(timeout<=0)execute._run(); //else { execute.start(); if(timeout>0){ try { synchronized(monitor) { monitor.wait(timeout); } } finally { execute.abort(terminateOnTimeout); } if(execute.hasException()) { throw execute.getException(); } if(!execute.hasFinished()) throw new ApplicationException("timeout ["+(timeout)+" ms] expired while executing ["+command+"]"); //} } } @Override public int doEndTag() throws PageException { if(pageContext.getConfig().getSecurityManager().getAccess(SecurityManager.TYPE_TAG_EXECUTE)==SecurityManager.VALUE_NO) throw new SecurityException("can't access tag [execute]","access is prohibited by security manager"); try { _execute(); } catch (PageException pe) { throw pe; } catch (Exception e) {e.printStackTrace(); throw new ApplicationException("Error invoking external process",e.getMessage()); } return EVAL_PAGE; } @Override public void doInitBody() { } @Override public int doAfterBody() { body=bodyContent.getString(); if(!StringUtil.isEmpty(body))body=body.trim(); return SKIP_BODY; } }