Skip to content

Commit 84b5dbd

Browse files
shs96cTikhomirovSergey
authored andcommitted
AppiumProtocolHandShake was added. As it 99.9% repeats the old working version so the real authorship is used for this commit.
1 parent 48f3a96 commit 84b5dbd

1 file changed

Lines changed: 201 additions & 0 deletions

File tree

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
package io.appium.java_client.remote;
2+
3+
import static com.google.common.base.Charsets.UTF_8;
4+
import static com.google.common.net.HttpHeaders.CONTENT_LENGTH;
5+
import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
6+
import static com.google.common.net.MediaType.JSON_UTF_8;
7+
import static org.openqa.selenium.remote.ErrorCodes.SESSION_NOT_CREATED;
8+
import static org.openqa.selenium.remote.ErrorCodes.SUCCESS;
9+
10+
import com.google.common.base.Preconditions;
11+
12+
import org.openqa.selenium.Capabilities;
13+
import org.openqa.selenium.SessionNotCreatedException;
14+
import org.openqa.selenium.remote.BeanToJsonConverter;
15+
import org.openqa.selenium.remote.Command;
16+
import org.openqa.selenium.remote.DesiredCapabilities;
17+
import org.openqa.selenium.remote.Dialect;
18+
import org.openqa.selenium.remote.ErrorHandler;
19+
import org.openqa.selenium.remote.JsonException;
20+
import org.openqa.selenium.remote.JsonToBeanConverter;
21+
import org.openqa.selenium.remote.Response;
22+
import org.openqa.selenium.remote.SessionId;
23+
import org.openqa.selenium.remote.http.HttpClient;
24+
import org.openqa.selenium.remote.http.HttpMethod;
25+
import org.openqa.selenium.remote.http.HttpRequest;
26+
import org.openqa.selenium.remote.http.HttpResponse;
27+
28+
import java.io.IOException;
29+
import java.net.HttpURLConnection;
30+
import java.util.HashMap;
31+
import java.util.Map;
32+
import java.util.Optional;
33+
34+
class AppiumProtocolHandShake {
35+
36+
public Result createSession(HttpClient client, Command command)
37+
throws IOException {
38+
39+
Capabilities desired = (Capabilities) command.getParameters().get("desiredCapabilities");
40+
desired = desired == null ? new DesiredCapabilities() : desired;
41+
Capabilities required = (Capabilities) command.getParameters().get("requiredCapabilities");
42+
required = required == null ? new DesiredCapabilities() : required;
43+
44+
String des = new BeanToJsonConverter().convert(desired);
45+
String req = new BeanToJsonConverter().convert(required);
46+
47+
// Assume the remote end obeys the robustness principle.
48+
StringBuilder parameters = new StringBuilder("{");
49+
amendW3CParameters(parameters, des, req);
50+
parameters.append(",");
51+
amendOssParamters(parameters, des, req);
52+
parameters.append("}");
53+
Optional<Result> result = createSession(client, parameters);
54+
55+
// Assume a fragile OSS webdriver implementation
56+
if (!result.isPresent()) {
57+
parameters = new StringBuilder("{");
58+
amendOssParamters(parameters, des, req);
59+
parameters.append("}");
60+
result = createSession(client, parameters);
61+
}
62+
63+
// Assume a fragile w3c implementation
64+
if (!result.isPresent()) {
65+
parameters = new StringBuilder("{");
66+
amendW3CParameters(parameters, des, req);
67+
parameters.append("}");
68+
result = createSession(client, parameters);
69+
}
70+
71+
if (result.isPresent()) {
72+
Result toReturn = result.get();
73+
return toReturn;
74+
}
75+
76+
throw new SessionNotCreatedException(
77+
String.format(
78+
"Unable to create new remote session. "
79+
+ "desired capabilities = %s, required capabilities = %s",
80+
desired,
81+
required));
82+
}
83+
84+
private Optional<Result> createSession(HttpClient client, StringBuilder params)
85+
throws IOException {
86+
// Create the http request and send it
87+
HttpRequest request = new HttpRequest(HttpMethod.POST, "/session");
88+
String content = params.toString();
89+
byte[] data = content.getBytes(UTF_8);
90+
91+
request.setHeader(CONTENT_LENGTH, String.valueOf(data.length));
92+
request.setHeader(CONTENT_TYPE, JSON_UTF_8.toString());
93+
request.setContent(data);
94+
HttpResponse response = client.execute(request, true);
95+
96+
Map<?, ?> jsonBlob = null;
97+
String resultString = response.getContentString();
98+
try {
99+
jsonBlob = new JsonToBeanConverter().convert(Map.class, resultString);
100+
} catch (ClassCastException e) {
101+
return Optional.empty();
102+
} catch (JsonException e) {
103+
// Fine. Handle that below
104+
}
105+
106+
if (jsonBlob == null) {
107+
jsonBlob = new HashMap<>();
108+
}
109+
110+
// If the result looks positive, return the result.
111+
Object sessionId = jsonBlob.get("sessionId");
112+
Object value = jsonBlob.get("value");
113+
Object w3cError = jsonBlob.get("error");
114+
Object ossStatus = jsonBlob.get("status");
115+
Map<String, ?> capabilities = null;
116+
if (value != null && value instanceof Map) {
117+
capabilities = (Map<String, ?>) value;
118+
} else if (value != null && value instanceof Capabilities) {
119+
capabilities = ((Capabilities) capabilities).asMap();
120+
}
121+
122+
if (response.getStatus() == HttpURLConnection.HTTP_OK) {
123+
if (sessionId != null && capabilities != null) {
124+
Dialect dialect = ossStatus == null ? Dialect.W3C : Dialect.OSS;
125+
return Optional.of(
126+
new Result(dialect, String.valueOf(sessionId), capabilities));
127+
}
128+
}
129+
130+
// If the result was an error that we believe has to do with the remote end failing to start the
131+
// session, create an exception and throw it.
132+
Response tempResponse = null;
133+
if ("session not created".equals(w3cError)) {
134+
tempResponse = new Response(null);
135+
tempResponse.setStatus(SESSION_NOT_CREATED);
136+
tempResponse.setValue(jsonBlob);
137+
} else if (
138+
ossStatus instanceof Number
139+
&& ((Number) ossStatus).intValue() == SESSION_NOT_CREATED) {
140+
tempResponse = new Response(null);
141+
tempResponse.setStatus(SESSION_NOT_CREATED);
142+
tempResponse.setValue(jsonBlob);
143+
}
144+
145+
if (tempResponse != null) {
146+
new ErrorHandler().throwIfResponseFailed(tempResponse, 0);
147+
}
148+
149+
// Otherwise, just return empty.
150+
return Optional.empty();
151+
}
152+
153+
private void amendW3CParameters(
154+
StringBuilder params,
155+
String desired,
156+
String required) {
157+
params.append("\"capabilities\": {");
158+
params.append("\"desiredCapabilities\": ").append(desired);
159+
params.append(",");
160+
params.append("\"requiredCapabilities\": ").append(required);
161+
params.append("}");
162+
}
163+
164+
private void amendOssParamters(
165+
StringBuilder params,
166+
String desired,
167+
String required) {
168+
params.append("\"desiredCapabilities\": ").append(desired);
169+
params.append(",");
170+
params.append("\"requiredCapabilities\": ").append(required);
171+
}
172+
173+
174+
public class Result {
175+
private final Dialect dialect;
176+
private final Map<String, ?> capabilities;
177+
private final SessionId sessionId;
178+
179+
private Result(Dialect dialect, String sessionId, Map<String, ?> capabilities) {
180+
this.dialect = dialect;
181+
this.sessionId = new SessionId(Preconditions.checkNotNull(sessionId));
182+
this.capabilities = capabilities;
183+
}
184+
185+
public Dialect getDialect() {
186+
return dialect;
187+
}
188+
189+
public Response createResponse() {
190+
Response response = new Response(sessionId);
191+
response.setValue(capabilities);
192+
response.setStatus(SUCCESS);
193+
return response;
194+
}
195+
196+
@Override
197+
public String toString() {
198+
return String.format("%s: %s", dialect, capabilities);
199+
}
200+
}
201+
}

0 commit comments

Comments
 (0)