[R-Console] Improve implementation of RTermController

  - Make use of current APIs by Java and JCommons
diff --git a/r/org.eclipse.statet.r.console.core/META-INF/MANIFEST.MF b/r/org.eclipse.statet.r.console.core/META-INF/MANIFEST.MF
index f069ff7..2aacac6 100644
--- a/r/org.eclipse.statet.r.console.core/META-INF/MANIFEST.MF
+++ b/r/org.eclipse.statet.r.console.core/META-INF/MANIFEST.MF
@@ -24,6 +24,7 @@
  org.eclipse.statet.jcommons.collections;version="4.3.0",
  org.eclipse.statet.jcommons.lang;version="4.3.0",
  org.eclipse.statet.jcommons.rmi;version="4.3.0",
+ org.eclipse.statet.jcommons.runtime;version="4.3.0",
  org.eclipse.statet.jcommons.status;version="4.3.0",
  org.eclipse.statet.jcommons.status.eplatform;version="4.3.0",
  org.eclipse.statet.jcommons.text.core;version="4.3.0",
diff --git a/r/org.eclipse.statet.r.console.core/src/org/eclipse/statet/r/nico/impl/RTermCancelRunnable.java b/r/org.eclipse.statet.r.console.core/src/org/eclipse/statet/r/nico/impl/RTermCancelRunnable.java
index 950949a..b1ebb8c 100644
--- a/r/org.eclipse.statet.r.console.core/src/org/eclipse/statet/r/nico/impl/RTermCancelRunnable.java
+++ b/r/org.eclipse.statet.r.console.core/src/org/eclipse/statet/r/nico/impl/RTermCancelRunnable.java
@@ -18,8 +18,8 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.ProcessBuilder.Redirect;
 import java.net.URL;
-import java.util.Arrays;
 
 import org.eclipse.core.runtime.FileLocator;
 import org.eclipse.core.runtime.IStatus;
@@ -27,6 +27,8 @@
 import org.eclipse.core.runtime.Status;
 
 import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.ObjectUtils.ToStringBuilder;
+import org.eclipse.statet.jcommons.runtime.ProcessUtils;
 import org.eclipse.statet.jcommons.status.ProgressMonitor;
 import org.eclipse.statet.jcommons.status.StatusException;
 import org.eclipse.statet.jcommons.status.WarningStatus;
@@ -95,35 +97,34 @@
 			}
 			m.addWorked(1);
 			final RTermController controller= (RTermController) r.getController();
-			final Long processId= controller.processId;
-			if (processId == null) {
-				RConsoleCorePlugin.log(new Status(IStatus.WARNING, RConsoleCorePlugin.BUNDLE_ID,
-						"Cannot run cancel command: process-id of Rterm process is missing." )); //$NON-NLS-1$
+			final Process rProcess= controller.getProcess();
+			if (rProcess == null) {
 				return;
 			}
-			final String[] cmd= new String[] {
-					file.getAbsolutePath(), processId.toString()
-					// the tool usually does not print output
-			};
-			final Process process= Runtime.getRuntime().exec(cmd);
+			
+			final ProcessBuilder processBuilder= new ProcessBuilder(
+					file.getAbsolutePath(), Long.toString(rProcess.pid()) );
+			processBuilder.redirectOutput(Redirect.DISCARD);
+			processBuilder.redirectErrorStream(true);
+			final Process process= processBuilder.start();
 			m.addWorked(1);
 			while (true) {
 				try {
 					final int code= process.exitValue();
 					if (code != 0) {
-						final StringBuilder detail= new StringBuilder("Command failed:"); //$NON-NLS-1$
-						detail.append("\n command= "); //$NON-NLS-1$
-						detail.append(Arrays.toString(cmd));
-						detail.append("\n os.name= "); //$NON-NLS-1$
-						detail.append(System.getProperty("os.name")); //$NON-NLS-1$
-						detail.append("\n os.version= "); //$NON-NLS-1$
-						detail.append(System.getProperty("os.version")); //$NON-NLS-1$
-						detail.append("\n os.arch= "); //$NON-NLS-1$
-						detail.append(System.getProperty("os.arch")); //$NON-NLS-1$
-						detail.append("\n r.arch= "); //$NON-NLS-1$
-						detail.append(arch); 
-						detail.append("\n exit.code= 0x"); //$NON-NLS-1$
-						detail.append(Integer.toHexString(code));
+						final ToStringBuilder detail= new ToStringBuilder("Command failed:");
+						detail.addProp("command", //$NON-NLS-1$
+								ProcessUtils.generateCommandLine(processBuilder.command()) );
+						detail.addProp("os.name", //$NON-NLS-1$
+								System.getProperty("os.name") ); //$NON-NLS-1$
+						detail.addProp("os.version", //$NON-NLS-1$
+								System.getProperty("os.version") ); //$NON-NLS-1$
+						detail.addProp("os.arch", //$NON-NLS-1$
+								System.getProperty("os.arch") ); //$NON-NLS-1$
+						detail.addProp("r.arch", //$NON-NLS-1$
+								arch ); 
+						detail.addProp("exit.code", //$NON-NLS-1$
+								"0x" + Integer.toHexString(code) );
 						throw new IOException(detail.toString());
 					}
 					break;
@@ -133,7 +134,7 @@
 				if (m.isCanceled()) {
 					process.destroy();
 					RConsoleCorePlugin.log(new Status(IStatus.WARNING, RConsoleCorePlugin.BUNDLE_ID, -1,
-							"Sending CTRL+C to R process canceled, command: " + Arrays.toString(cmd), null )); //$NON-NLS-1$
+							"Sending CTRL+C to R process canceled.", null )); //$NON-NLS-1$
 					break;
 				}
 				try {
diff --git a/r/org.eclipse.statet.r.console.core/src/org/eclipse/statet/r/nico/impl/RTermController.java b/r/org.eclipse.statet.r.console.core/src/org/eclipse/statet/r/nico/impl/RTermController.java
index fd6f2e2..4b447c4 100644
--- a/r/org.eclipse.statet.r.console.core/src/org/eclipse/statet/r/nico/impl/RTermController.java
+++ b/r/org.eclipse.statet.r.console.core/src/org/eclipse/statet/r/nico/impl/RTermController.java
@@ -17,7 +17,6 @@
 import static org.eclipse.statet.nico.core.runtime.IToolEventHandler.RUN_BLOCKING_EVENT_ID;
 import static org.eclipse.statet.nico.core.runtime.IToolEventHandler.RUN_RUNNABLE_DATA_KEY;
 
-import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -46,7 +45,6 @@
 import org.eclipse.statet.jcommons.status.ProgressMonitor;
 import org.eclipse.statet.jcommons.status.Status;
 import org.eclipse.statet.jcommons.status.StatusException;
-import org.eclipse.statet.jcommons.ts.core.SystemRunnable;
 import org.eclipse.statet.jcommons.ts.core.ToolCommandHandler;
 import org.eclipse.statet.jcommons.ts.core.ToolRunnable;
 import org.eclipse.statet.jcommons.ts.core.ToolService;
@@ -79,14 +77,18 @@
 	
 	private class ReadThread extends Thread {
 		
+		
+		private final InputStreamReader reader;
+		
 		volatile int hasNoOutput;
 		private final int SYNC_COUNT= 2;
 		private final int SYNC_MS= 33;
 		
 		final Lock streamLock= new ReentrantLock();
 		
-		public ReadThread() {
+		public ReadThread(final InputStream output) {
 			super("Rterm-Output Monitor"); //$NON-NLS-1$
+			this.reader= new InputStreamReader(output, RTermController.this.charset);
 		}
 		
 		@Override
@@ -96,14 +98,13 @@
 			try {
 				boolean canRead= false;
 				final char[] b= new char[1024];
-				while (RTermController.this.process != null | (canRead= RTermController.this.processOutputReader.ready())) {
-					RTermController.this.processOutputBuffer.available();
+				while (RTermController.this.process != null | (canRead= this.reader.ready())) {
 					if (canRead || this.hasNoOutput > this.SYNC_COUNT) {
 						if (!canRead && locked) {
 							this.streamLock.unlock();
 							locked= false;
 						}
-						int n= RTermController.this.processOutputReader.read(b);
+						int n= this.reader.read(b);
 						if (n > 0) {
 							this.hasNoOutput= 0;
 							if (!locked) {
@@ -146,7 +147,7 @@
 					locked= false;
 				}
 				try {
-					RTermController.this.processOutputReader.close();
+					this.reader.close();
 				} catch (final IOException e1) {
 				}
 			}
@@ -160,47 +161,12 @@
 		}
 	}
 	
-	private class UpdateProcessIdTask extends ControllerSystemRunnable implements SystemRunnable {
-		
-		
-		public UpdateProcessIdTask() {
-			super("r/rterm/fetch-process-id", "Fetch Process Id"); //$NON-NLS-1$
-		}
-		
-		
-		@Override
-		public void run(final ToolService service, final ProgressMonitor m) throws StatusException {
-			final StringBuilder output= readOutputLine("Sys.getpid()", m); //$NON-NLS-1$
-			if (output != null) {
-				final Matcher matcher= INT_OUTPUT_PATTERN.matcher(output);
-				if (matcher.find()) {
-					final String idString= matcher.group(1);
-					if (idString != null) {
-						try {
-							RTermController.this.processId= Long.valueOf(idString);
-						}
-						catch (final NumberFormatException e) {
-							RTermController.this.processId= null;
-						}
-					}
-					else {
-						RTermController.this.processId= null;
-					}
-				}
-			}
-		}
-		
-	}
-	
 	
 	private final ProcessBuilder processConfig;
 	private final Charset charset;
 	private @Nullable Process process;
 	private OutputStreamWriter processInputWriter;
-	private BufferedInputStream processOutputBuffer;
-	private InputStreamReader processOutputReader;
 	private ReadThread processOutputThread;
-	@Nullable Long processId;
 	
 	
 	public RTermController(final RProcess process, final ProcessBuilder config, final Charset charset) {
@@ -242,19 +208,13 @@
 	@Override
 	protected void startToolL(final ProgressMonitor m) throws StatusException {
 		OutputStream processInput= null;
-		InputStream processOutput;
 		try {
 			final List<Status> warnings= new ArrayList<>();
 			
 			this.processConfig.redirectErrorStream(true);
 			final Process process= this.processConfig.start();
 			this.process= process;
-			processOutput= process.getInputStream();
-			if (processOutput instanceof BufferedInputStream) {
-				this.processOutputBuffer= (BufferedInputStream) processOutput;
-			}
-			this.processOutputReader= new InputStreamReader(processOutput, this.charset);
-			this.processOutputThread= new ReadThread();
+			this.processOutputThread= new ReadThread(process.getInputStream());
 			this.processOutputThread.start();
 			processInput= process.getOutputStream();
 			this.processInputWriter= new OutputStreamWriter(processInput, this.charset);
@@ -262,7 +222,6 @@
 			
 			initTracks(m, warnings);
 			
-			getQueue().add(new UpdateProcessIdTask());
 			if (!this.startupsRunnables.isEmpty()) {
 				getQueue().add(this.startupsRunnables);
 				this.startupsRunnables.clear();
@@ -285,8 +244,7 @@
 			if (processInput != null) {
 				try {
 					processInput.close();
-				} catch (final IOException e1) {
-				}
+				} catch (final IOException e1) {}
 			}
 			throw new StatusException(new ErrorStatus(RConsoleCorePlugin.BUNDLE_ID,
 					RNicoMessages.RTerm_error_Starting_message,
@@ -294,6 +252,10 @@
 		}
 	}
 	
+	@Nullable Process getProcess() {
+		return this.process;
+	}
+	
 	@Override
 	protected void interruptTool() {
 		runSendCtrlC();