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