diff --git a/pom.xml b/pom.xml index eac06c7..2569f17 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.browserstack browserstack-local-java jar - 0.1.0 + 0.2.0 browserstack-local-java Java bindings for BrowserStack Local @@ -51,6 +51,11 @@ commons-io 1.3.2 + + org.json + json + 20160212 + diff --git a/src/main/java/com/browserstack/local/Local.java b/src/main/java/com/browserstack/local/Local.java index 81e5a99..e59d6c3 100644 --- a/src/main/java/com/browserstack/local/Local.java +++ b/src/main/java/com/browserstack/local/Local.java @@ -1,6 +1,7 @@ package com.browserstack.local; import java.io.BufferedReader; +import java.io.InputStreamReader; import java.io.FileReader; import java.io.FileWriter; import java.util.ArrayList; @@ -8,6 +9,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import org.json.*; /** * Creates and manages a secure tunnel connection to BrowserStack. @@ -15,6 +17,10 @@ public class Local { List command; + Map startOptions; + String binaryPath; + String logFilePath; + int pid = 0; private Process proc = null; @@ -44,22 +50,16 @@ public Local() { * @throws Exception */ public void start(Map options) throws Exception { - command = new ArrayList(); - + startOptions = options; if (options.get("binarypath") != null) { - command.add(options.get("binarypath")); + binaryPath = options.get("binarypath"); } else { LocalBinary lb = new LocalBinary(); - command.add(lb.getBinaryPath()); + binaryPath = lb.getBinaryPath(); } - String logFilePath = options.get("logfile") == null ? - (System.getProperty("user.dir") + "/local.log") : options.get("logfile"); - command.add("-logFile"); - command.add(logFilePath); - - command.add(options.get("key")); - makeCommand(options); + logFilePath = options.get("logfile") == null ? (System.getProperty("user.dir") + "/local.log") : options.get("logfile"); + makeCommand(options, "start"); if (options.get("onlyCommand") != null) return; @@ -71,26 +71,24 @@ public void start(Map options) throws Exception { fw.close(); proc = processBuilder.start(); - FileReader f = new FileReader(logFilePath); - BufferedReader reader = new BufferedReader(f); - String string; - - while (true) { - string = reader.readLine(); - if (string == null) continue; - - if (string.equalsIgnoreCase("Press Ctrl-C to exit")) { - f.close(); - break; - } - - if (string.contains("*** Error")) { - f.close(); - stop(); - throw new LocalException(string); - } + BufferedReader stdoutbr = new BufferedReader(new InputStreamReader(proc.getInputStream())); + BufferedReader stderrbr = new BufferedReader(new InputStreamReader(proc.getErrorStream())); + String stdout="", stderr="", line; + while ((line = stdoutbr.readLine()) != null) { + stdout += line; + } + while ((line = stderrbr.readLine()) != null) { + stderr += line; } + int r = proc.waitFor(); + JSONObject obj = new JSONObject(stdout != "" ? stdout : stderr); + if(!obj.getString("state").equals("connected")){ + throw new LocalException(obj.getString("message")); + } + else { + pid = obj.getInt("pid"); + } } } @@ -99,12 +97,13 @@ public void start(Map options) throws Exception { * * @throws InterruptedException */ - public void stop() throws InterruptedException { - if (proc != null) { - proc.destroy(); - while (isRunning()) { - Thread.sleep(1000); - } + public void stop() throws Exception { + if (pid != 0) { + makeCommand(startOptions, "stop"); + ProcessBuilder processBuilder = new ProcessBuilder(command); + proc = processBuilder.start(); + proc.waitFor(); + pid = 0; } } @@ -113,15 +112,9 @@ public void stop() throws InterruptedException { * * @return true if Local instance is running, else false */ - public boolean isRunning() { - if (proc == null) return false; - - try { - proc.exitValue(); - return false; - } catch (IllegalThreadStateException e) { - return true; - } + public boolean isRunning() throws Exception { + if (pid == 0) return false; + return isProcessRunning(pid); } /** @@ -129,7 +122,15 @@ public boolean isRunning() { * * @param options Options supplied for the Local instance */ - private void makeCommand(Map options) { + private void makeCommand(Map options, String opCode) { + command = new ArrayList(); + command.add(binaryPath); + command.add("-d"); + command.add(opCode); + command.add("-logFile"); + command.add(logFilePath); + command.add(options.get("key")); + for (Map.Entry opt : options.entrySet()) { List ignoreKeys = Arrays.asList("key", "logfile", "binarypath"); String parameter = opt.getKey().trim(); @@ -146,4 +147,34 @@ private void makeCommand(Map options) { } } } + + /** + * Checks if process with pid is running + * + * @param options Options supplied for the Local instance + * @link http://stackoverflow.com/a/26423642/941691 + */ + private boolean isProcessRunning(int pid) throws Exception { + ArrayList cmd = new ArrayList(); + if (System.getProperty("os.name").toLowerCase().contains("windows")) { + //tasklist exit code is always 0. Parse output + //findstr exit code 0 if found pid, 1 if it doesn't + cmd.add("cmd"); + cmd.add("/c"); + cmd.add("\"tasklist /FI \"PID eq " + pid + "\" | findstr " + pid + "\""); + } + else { + //ps exit code 0 if process exists, 1 if it doesn't + cmd.add("ps"); + cmd.add("-p"); + cmd.add(String.valueOf(pid)); + } + + ProcessBuilder processBuilder = new ProcessBuilder(cmd); + proc = processBuilder.start(); + int exitValue = proc.waitFor(); + + // 0 is the default exit code which means the process exists + return exitValue == 0; + } }