1 jls.loader.provide('jls.lang.ProcessBuilder'); 2 3 jls.loader.require('jls.lang.Process'); 4 5 jls.lang.ProcessBuilder = jls.lang.Class.create( /** @lends jls.lang.ProcessBuilder.prototype */ 6 { 7 /** 8 * Creates a process builder with the specified command and arguments with the specified environment and working directory. 9 * 10 * @param {Array} cmdArray Array of strings specifying the command-line arguments. The first argument is the name of the executable file. 11 * @param {Array} [envp] Array of key-values specifying the environment strings. If undefined, the new process inherits the environment of the parent process. 12 * @constructs 13 * @class This class is used to create OS processes. 14 */ 15 initialize : function(cmdArray, envp) { 16 this._no = undefined; 17 this._cmdArray = cmdArray; 18 this._envp = envp; 19 this._process = null; 20 this._stdoutHandler = null; 21 }, 22 /** 23 * Sets this process builder's working directory. 24 * 25 * @param {jls.io.File} dir The working directory of the subprocess, or undefined if the subprocess should inherit the working directory of the current process. 26 */ 27 setCurrentDirectory : function(dir) { 28 if (! this._no) { 29 this._no = new _native.core.ProcessAttr(); 30 } 31 this._no.setCurrentDirectory(dir.getAbsolutePath()); 32 }, 33 /** 34 * Sets this process builder's working directory. 35 * 36 * @param {jls.io.FileDescriptor} fd The file descriptor to use for redirection. 37 * @param {Number} stdio The standard IO to redirect. 38 */ 39 setStdioRedirect : function(fd, stdio) { 40 if (! this._no) { 41 this._no = new _native.core.ProcessAttr(); 42 } 43 fd.setInheritable(true); 44 this._no.setStdioRedirect(fd.getFD(), stdio || jls.io.Pipe.StandardOutput); 45 }, 46 setReadHandler : function(fn, stdio, bufferSize) { 47 bufferSize = bufferSize || 1024; 48 var handler = this._stdoutHandler = {}; 49 handler.ended = false; 50 handler.pipe = new jls.io.Pipe(); 51 handler.thread = new jls.lang.Thread(); 52 this.setStdioRedirect(handler.pipe.source(), jls.lang.ProcessBuilder.StandardOutput); 53 handler.thread.run = function() { 54 var buffer = jls.lang.ByteBuffer.allocate(bufferSize); 55 for (;;) { 56 buffer.clear(); 57 this.pipe.sink().read(buffer); 58 buffer.flip(); 59 if (this.ended) { 60 if (buffer.remaining() > 1) { 61 jls.logger.warn('unreaded data in the pipe: ' + (buffer.remaining() - 1)); 62 } 63 break; 64 } 65 while (buffer.remaining() > 0) { 66 fn(buffer); 67 } 68 } 69 }; 70 }, 71 /** 72 * Starts a new process using the attributes of this process builder. 73 * 74 * @returns {jls.lang.Process} A new Process for managing the subprocess. 75 */ 76 start : function() { 77 this._process = new jls.lang.Process(this._cmdArray, this._envp, this._no); 78 this._process._processBuilder = this; 79 if (this._stdoutHandler != null) { 80 jls.logger.debug('Start reading thread'); 81 this._stdoutHandler.thread.start(this._stdoutHandler); 82 this._process.registerExitCallback(function(exitValue) { 83 jls.logger.debug('Stop reading thread (' + exitValue + ')'); 84 // say that its over 85 this._processBuilder._stdoutHandler.ended = true; 86 // unlock pipe reader 87 this._processBuilder._stdoutHandler.pipe.source().writeByte(0); 88 }); 89 } 90 return this._process; 91 } 92 }); 93 94 Object.extend(jls.lang.ProcessBuilder, /** @lends jls.lang.ProcessBuilder */ 95 { 96 /** 97 * Represents the standard output. 98 * 99 * @type Number 100 */ 101 StandardOutput : _native.core.ProcessAttr.StandardOutput, 102 /** 103 * Represents the standard error. 104 * 105 * @type Number 106 */ 107 StandardError : _native.core.ProcessAttr.StandardError, 108 /** 109 * Represents the standard input. 110 * 111 * @type Number 112 */ 113 StandardInput : _native.core.ProcessAttr.StandardInput 114 }); 115 116