Skip to content

Commit e4d0b5d

Browse files
committed
Removed old files
2 parents 8a28381 + fb5c777 commit e4d0b5d

File tree

8 files changed

+1102
-0
lines changed

8 files changed

+1102
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ dependency-reduced-pom.xml
88
buildNumber.properties
99
.mvn/timing.properties
1010
.DS_Store
11+
*.class
12+
*.swp
13+
.project

browserstack-api/pom.xml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>com.browserstack.local</groupId>
5+
<artifactId>browserstack-api</artifactId>
6+
<packaging>jar</packaging>
7+
<version>1.0-SNAPSHOT</version>
8+
<name>browserstack-api</name>
9+
<url>http://maven.apache.org</url>
10+
<properties>
11+
<powermock.version>1.6.4</powermock.version>
12+
</properties>
13+
<dependencies>
14+
<dependency>
15+
<groupId>junit</groupId>
16+
<artifactId>junit</artifactId>
17+
<version>4.12</version>
18+
<scope>test</scope>
19+
</dependency>
20+
<dependency>
21+
<groupId>org.mockito</groupId>
22+
<artifactId>mockito-core</artifactId>
23+
<version>1.10.19</version>
24+
<scope>test</scope>
25+
</dependency>
26+
<dependency>
27+
<groupId>org.powermock</groupId>
28+
<artifactId>powermock-module-junit4</artifactId>
29+
<version>${powermock.version}</version>
30+
<scope>test</scope>
31+
</dependency>
32+
<dependency>
33+
<groupId>org.powermock</groupId>
34+
<artifactId>powermock-api-mockito</artifactId>
35+
<version>${powermock.version}</version>
36+
<scope>test</scope>
37+
</dependency>
38+
</dependencies>
39+
</project>
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
package com.browserstack.local;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.io.BufferedReader;
6+
import java.io.InputStreamReader;
7+
import java.util.Map;
8+
import java.util.HashMap;
9+
import java.util.regex.Matcher;
10+
import java.util.regex.Pattern;
11+
import java.util.logging.Level;
12+
import java.util.logging.Logger;
13+
14+
import com.browserstack.local.BrowserStackTunnel.TunnelState;
15+
import com.browserstack.local.BrowserStackTunnel.BrowserStackLocalListener;
16+
17+
public class BrowserStackLocal {
18+
private static Logger logger;
19+
private static final int MAX_CONNECT_WAIT = 30000; // 30s x 2 = 60s
20+
private static final int MAX_CONNECT_ATTEMPTS = 2;
21+
22+
private final File binaryFile;
23+
private final String argumentString;
24+
25+
private Process process;
26+
private Thread processThread;
27+
28+
private StringBuffer output;
29+
private String lastError;
30+
private TunnelState tunnelState;
31+
32+
private BrowserStackLocalListener listener;
33+
34+
private static final Object monitor = new Object();
35+
private static final Map<Pattern, TunnelState> stateMatchers = new HashMap<Pattern, TunnelState>();
36+
37+
static {
38+
stateMatchers.put(Pattern.compile("Press Ctrl-C to exit.*", Pattern.MULTILINE), TunnelState.CONNECTED);
39+
stateMatchers.put(Pattern.compile("\\s*\\*\\*\\* Error:\\s+(.*)$", Pattern.MULTILINE), TunnelState.ERROR);
40+
}
41+
42+
protected BrowserStackLocal(File binaryFile, String argumentString) {
43+
if (binaryFile == null || argumentString == null || !binaryFile.exists()) {
44+
throw new IllegalArgumentException("Invalid arguments");
45+
}
46+
47+
this.binaryFile = binaryFile;
48+
this.argumentString = argumentString;
49+
this.output = new StringBuffer();
50+
this.tunnelState = TunnelState.IDLE;
51+
this.logger = BrowserStackTunnel.logger;
52+
53+
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
54+
@Override
55+
public void run() {
56+
BrowserStackLocal.this.kill();
57+
}
58+
}));
59+
}
60+
61+
protected void run() {
62+
if (process != null) {
63+
kill();
64+
}
65+
66+
processThread = new Thread(new Runnable() {
67+
@Override
68+
public void run() {
69+
notifyTunnelStateChanged(TunnelState.CONNECTING);
70+
71+
try {
72+
logger.fine("Arguments -- " + argumentString);
73+
process = new ProcessBuilder((binaryFile.getAbsolutePath() + " " + argumentString)
74+
.split(" ")).start();
75+
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
76+
77+
String line;
78+
while ((line = br.readLine()) != null) {
79+
output.append(line).append("\n");
80+
81+
if (processOutput(output.toString())) {
82+
logger.fine(output.toString());
83+
output.setLength(0);
84+
}
85+
}
86+
} catch (IOException e) {
87+
if (listener != null) {
88+
listener.onError(e.getMessage());
89+
}
90+
} finally {
91+
logger.fine(output.toString());
92+
output.setLength(0);
93+
notifyTunnelStateChanged(TunnelState.DISCONNECTED);
94+
}
95+
}
96+
});
97+
98+
processThread.start();
99+
}
100+
101+
protected void run(BrowserStackLocalListener listener) {
102+
setListener(listener);
103+
run();
104+
}
105+
106+
protected void runSync(BrowserStackLocalListener listener) {
107+
setListener(listener);
108+
109+
if (process != null) {
110+
kill();
111+
}
112+
113+
notifyTunnelStateChanged(TunnelState.CONNECTING);
114+
run();
115+
116+
int connAttempts = 0;
117+
boolean connFailed = false;
118+
119+
synchronized (monitor) {
120+
while (tunnelState == TunnelState.CONNECTING) {
121+
logger.info("Waiting: " + connAttempts);
122+
try {
123+
monitor.wait(MAX_CONNECT_WAIT);
124+
} catch (InterruptedException e) {
125+
logger.info("Exc: " + e.getMessage() + " " + isConnected());
126+
}
127+
128+
if (MAX_CONNECT_ATTEMPTS > 0 && ++connAttempts >= MAX_CONNECT_ATTEMPTS) {
129+
connFailed = true;
130+
break;
131+
}
132+
}
133+
}
134+
135+
if (connFailed) {
136+
killWithError("Failed to connect to BrowserStack");
137+
}
138+
}
139+
140+
protected void kill() {
141+
if (process != null) {
142+
process.destroy();
143+
process = null;
144+
}
145+
146+
if (processThread != null && processThread.isAlive()) {
147+
processThread.interrupt();
148+
processThread = null;
149+
}
150+
151+
logger.fine(output.toString());
152+
output.setLength(0);
153+
tunnelState = TunnelState.DISCONNECTED;
154+
}
155+
156+
protected void setListener(BrowserStackLocalListener listener) {
157+
this.listener = listener;
158+
}
159+
160+
protected boolean isConnected() {
161+
return (tunnelState == TunnelState.CONNECTED);
162+
}
163+
164+
protected String getLastError() {
165+
return lastError;
166+
}
167+
168+
protected TunnelState getTunnelState() {
169+
return tunnelState;
170+
}
171+
172+
private void killWithError(String message) {
173+
setError(message);
174+
notifyTunnelStateChanged(TunnelState.ERROR);
175+
kill();
176+
}
177+
178+
private boolean processOutput(final String output) {
179+
if (output != null && !output.trim().isEmpty()) {
180+
String error;
181+
182+
for (Map.Entry<Pattern, TunnelState> entry : stateMatchers.entrySet()) {
183+
Matcher m = entry.getKey().matcher(output);
184+
185+
if (m.find()) {
186+
if (entry.getValue() == TunnelState.ERROR) {
187+
error = (m.groupCount() > 0) ? m.group(1) : output;
188+
} else {
189+
error = null;
190+
}
191+
192+
setError(error);
193+
notifyTunnelStateChanged(entry.getValue());
194+
return true;
195+
}
196+
}
197+
}
198+
199+
return false;
200+
}
201+
202+
private void notifyTunnelStateChanged(TunnelState state) {
203+
if (tunnelState != state) {
204+
if (listener != null) {
205+
listener.onTunnelStateChange(state);
206+
}
207+
208+
synchronized (monitor) {
209+
monitor.notifyAll();
210+
}
211+
}
212+
213+
tunnelState = state;
214+
}
215+
216+
private void setError(String message) {
217+
lastError = message;
218+
219+
if (listener != null) {
220+
listener.lastError = lastError;
221+
}
222+
}
223+
224+
}

0 commit comments

Comments
 (0)