11package com .browserstack .local ;
22
33import java .io .BufferedReader ;
4+ import java .io .InputStreamReader ;
45import java .io .FileReader ;
56import java .io .FileWriter ;
67import java .util .ArrayList ;
78import java .util .HashMap ;
89import java .util .Arrays ;
910import java .util .List ;
1011import java .util .Map ;
12+ import org .json .*;
1113
1214/**
1315 * Creates and manages a secure tunnel connection to BrowserStack.
1416 */
1517public class Local {
1618
1719 List <String > command ;
20+ Map <String , String > startOptions ;
21+ String binaryPath ;
22+ String logFilePath ;
23+ int pid = 0 ;
1824
1925 private Process proc = null ;
2026
@@ -44,22 +50,16 @@ public Local() {
4450 * @throws Exception
4551 */
4652 public void start (Map <String , String > options ) throws Exception {
47- command = new ArrayList <String >();
48-
53+ startOptions = options ;
4954 if (options .get ("binarypath" ) != null ) {
50- command . add ( options .get ("binarypath" ) );
55+ binaryPath = options .get ("binarypath" );
5156 } else {
5257 LocalBinary lb = new LocalBinary ();
53- command . add ( lb .getBinaryPath () );
58+ binaryPath = lb .getBinaryPath ();
5459 }
5560
56- String logFilePath = options .get ("logfile" ) == null ?
57- (System .getProperty ("user.dir" ) + "/local.log" ) : options .get ("logfile" );
58- command .add ("-logFile" );
59- command .add (logFilePath );
60-
61- command .add (options .get ("key" ));
62- makeCommand (options );
61+ logFilePath = options .get ("logfile" ) == null ? (System .getProperty ("user.dir" ) + "/local.log" ) : options .get ("logfile" );
62+ makeCommand (options , "start" );
6363
6464 if (options .get ("onlyCommand" ) != null ) return ;
6565
@@ -71,26 +71,24 @@ public void start(Map<String, String> options) throws Exception {
7171 fw .close ();
7272
7373 proc = processBuilder .start ();
74- FileReader f = new FileReader (logFilePath );
75- BufferedReader reader = new BufferedReader (f );
76- String string ;
77-
78- while (true ) {
79- string = reader .readLine ();
80- if (string == null ) continue ;
81-
82- if (string .equalsIgnoreCase ("Press Ctrl-C to exit" )) {
83- f .close ();
84- break ;
85- }
86-
87- if (string .contains ("*** Error" )) {
88- f .close ();
89- stop ();
90- throw new LocalException (string );
91- }
74+ BufferedReader stdoutbr = new BufferedReader (new InputStreamReader (proc .getInputStream ()));
75+ BufferedReader stderrbr = new BufferedReader (new InputStreamReader (proc .getErrorStream ()));
76+ String stdout ="" , stderr ="" , line ;
77+ while ((line = stdoutbr .readLine ()) != null ) {
78+ stdout += line ;
79+ }
80+ while ((line = stderrbr .readLine ()) != null ) {
81+ stderr += line ;
9282 }
83+ int r = proc .waitFor ();
9384
85+ JSONObject obj = new JSONObject (stdout != "" ? stdout : stderr );
86+ if (!obj .getString ("state" ).equals ("connected" )){
87+ throw new LocalException (obj .getString ("message" ));
88+ }
89+ else {
90+ pid = obj .getInt ("pid" );
91+ }
9492 }
9593 }
9694
@@ -99,12 +97,13 @@ public void start(Map<String, String> options) throws Exception {
9997 *
10098 * @throws InterruptedException
10199 */
102- public void stop () throws InterruptedException {
103- if (proc != null ) {
104- proc .destroy ();
105- while (isRunning ()) {
106- Thread .sleep (1000 );
107- }
100+ public void stop () throws Exception {
101+ if (pid != 0 ) {
102+ makeCommand (startOptions , "stop" );
103+ ProcessBuilder processBuilder = new ProcessBuilder (command );
104+ proc = processBuilder .start ();
105+ proc .waitFor ();
106+ pid = 0 ;
108107 }
109108 }
110109
@@ -113,23 +112,25 @@ public void stop() throws InterruptedException {
113112 *
114113 * @return true if Local instance is running, else false
115114 */
116- public boolean isRunning () {
117- if (proc == null ) return false ;
118-
119- try {
120- proc .exitValue ();
121- return false ;
122- } catch (IllegalThreadStateException e ) {
123- return true ;
124- }
115+ public boolean isRunning () throws Exception {
116+ if (pid == 0 ) return false ;
117+ return isProcessRunning (pid );
125118 }
126119
127120 /**
128121 * Creates a list of command-line arguments for the Local instance
129122 *
130123 * @param options Options supplied for the Local instance
131124 */
132- private void makeCommand (Map <String , String > options ) {
125+ private void makeCommand (Map <String , String > options , String opCode ) {
126+ command = new ArrayList <String >();
127+ command .add (binaryPath );
128+ command .add ("-d" );
129+ command .add (opCode );
130+ command .add ("-logFile" );
131+ command .add (logFilePath );
132+ command .add (options .get ("key" ));
133+
133134 for (Map .Entry <String , String > opt : options .entrySet ()) {
134135 List <String > ignoreKeys = Arrays .asList ("key" , "logfile" , "binarypath" );
135136 String parameter = opt .getKey ().trim ();
@@ -146,4 +147,34 @@ private void makeCommand(Map<String, String> options) {
146147 }
147148 }
148149 }
150+
151+ /**
152+ * Checks if process with pid is running
153+ *
154+ * @param options Options supplied for the Local instance
155+ * @link http://stackoverflow.com/a/26423642/941691
156+ */
157+ private boolean isProcessRunning (int pid ) throws Exception {
158+ ArrayList <String > cmd = new ArrayList <String >();
159+ if (System .getProperty ("os.name" ).toLowerCase ().contains ("windows" )) {
160+ //tasklist exit code is always 0. Parse output
161+ //findstr exit code 0 if found pid, 1 if it doesn't
162+ cmd .add ("cmd" );
163+ cmd .add ("/c" );
164+ cmd .add ("\" tasklist /FI \" PID eq " + pid + "\" | findstr " + pid + "\" " );
165+ }
166+ else {
167+ //ps exit code 0 if process exists, 1 if it doesn't
168+ cmd .add ("ps" );
169+ cmd .add ("-p" );
170+ cmd .add (String .valueOf (pid ));
171+ }
172+
173+ ProcessBuilder processBuilder = new ProcessBuilder (cmd );
174+ proc = processBuilder .start ();
175+ int exitValue = proc .waitFor ();
176+
177+ // 0 is the default exit code which means the process exists
178+ return exitValue == 0 ;
179+ }
149180}
0 commit comments