Skip to content

Commit 065d1a9

Browse files
Merge pull request appium#597 from TikhomirovSergey/master
appium#594 FIX
2 parents b8bd6a3 + b8bc1f0 commit 065d1a9

15 files changed

Lines changed: 397 additions & 43 deletions

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ compileJava {
5454
}
5555

5656
dependencies {
57-
compile('org.seleniumhq.selenium:selenium-java:3.2.0'){
57+
compile('org.seleniumhq.selenium:selenium-java:3.3.1'){
5858
exclude module: 'cglib'
5959
exclude group: 'com.google.code.gson'
6060
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* See the NOTICE file distributed with this work for additional
5+
* information regarding copyright ownership.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.appium.java_client;
18+
19+
import org.openqa.selenium.remote.CommandInfo;
20+
import org.openqa.selenium.remote.http.HttpMethod;
21+
22+
public class AppiumCommandInfo extends CommandInfo {
23+
private final String url;
24+
private final HttpMethod method;
25+
26+
/**
27+
* It conntains method and URL of the command.
28+
*
29+
* @param url command URL
30+
* @param method is http-method
31+
*/
32+
public AppiumCommandInfo(String url, HttpMethod method) {
33+
super(url, method);
34+
this.url = url;
35+
this.method = method;
36+
}
37+
38+
public String getUrl() {
39+
return url;
40+
}
41+
42+
public HttpMethod getMethod() {
43+
return method;
44+
}
45+
}

src/main/java/io/appium/java_client/AppiumDriver.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import org.openqa.selenium.remote.DriverCommand;
4545
import org.openqa.selenium.remote.ErrorHandler;
4646
import org.openqa.selenium.remote.ExecuteMethod;
47-
import org.openqa.selenium.remote.HttpCommandExecutor;
4847
import org.openqa.selenium.remote.Response;
4948
import org.openqa.selenium.remote.html5.RemoteLocationContext;
5049
import org.openqa.selenium.remote.http.HttpClient;
@@ -85,7 +84,7 @@ public class AppiumDriver<T extends WebElement>
8584
* @param capabilities take a look
8685
* at {@link org.openqa.selenium.Capabilities}
8786
*/
88-
public AppiumDriver(HttpCommandExecutor executor, Capabilities capabilities) {
87+
public AppiumDriver(AppiumCommandExecutor executor, Capabilities capabilities) {
8988
super(executor, capabilities);
9089
this.executeMethod = new AppiumExecutionMethod(this);
9190
locationContext = new RemoteLocationContext(executeMethod);

src/main/java/io/appium/java_client/MobileCommand.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import com.google.common.collect.ImmutableMap;
2020

2121
import org.apache.commons.lang3.StringUtils;
22-
import org.openqa.selenium.remote.CommandInfo;
2322
import org.openqa.selenium.remote.http.HttpMethod;
2423

2524
import java.util.AbstractMap;
@@ -77,7 +76,7 @@ public class MobileCommand {
7776
protected static final String GET_SETTINGS;
7877
protected static final String SET_SETTINGS;
7978

80-
public static final Map<String, CommandInfo> commandRepository;
79+
public static final Map<String, AppiumCommandInfo> commandRepository;
8180

8281
static {
8382
RESET = "reset";
@@ -184,8 +183,8 @@ public class MobileCommand {
184183
* @param url is the command URL
185184
* @return an instance of {@link org.openqa.selenium.remote.CommandInfo}
186185
*/
187-
public static CommandInfo getC(String url) {
188-
return new CommandInfo(url, HttpMethod.GET);
186+
public static AppiumCommandInfo getC(String url) {
187+
return new AppiumCommandInfo(url, HttpMethod.GET);
189188
}
190189

191190
/**
@@ -194,8 +193,8 @@ public static CommandInfo getC(String url) {
194193
* @param url is the command URL
195194
* @return an instance of {@link org.openqa.selenium.remote.CommandInfo}
196195
*/
197-
public static CommandInfo postC(String url) {
198-
return new CommandInfo(url, HttpMethod.POST);
196+
public static AppiumCommandInfo postC(String url) {
197+
return new AppiumCommandInfo(url, HttpMethod.POST);
199198
}
200199

201200
/**
@@ -204,8 +203,8 @@ public static CommandInfo postC(String url) {
204203
* @param url is the command URL
205204
* @return an instance of {@link org.openqa.selenium.remote.CommandInfo}
206205
*/
207-
public static CommandInfo deleteC(String url) {
208-
return new CommandInfo(url, HttpMethod.DELETE);
206+
public static AppiumCommandInfo deleteC(String url) {
207+
return new AppiumCommandInfo(url, HttpMethod.DELETE);
209208
}
210209

211210
/**

src/main/java/io/appium/java_client/android/AndroidDriver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
import io.appium.java_client.FindsByAndroidUIAutomator;
2626
import io.appium.java_client.PressesKeyCode;
2727
import io.appium.java_client.TouchAction;
28+
import io.appium.java_client.remote.AppiumCommandExecutor;
2829
import io.appium.java_client.remote.MobilePlatform;
2930
import io.appium.java_client.service.local.AppiumDriverLocalService;
3031
import io.appium.java_client.service.local.AppiumServiceBuilder;
3132
import org.openqa.selenium.Capabilities;
3233
import org.openqa.selenium.WebElement;
33-
import org.openqa.selenium.remote.HttpCommandExecutor;
3434
import org.openqa.selenium.remote.http.HttpClient;
3535

3636
import java.net.URL;
@@ -59,7 +59,7 @@ public class AndroidDriver<T extends WebElement>
5959
* @param capabilities take a look
6060
* at {@link org.openqa.selenium.Capabilities}
6161
*/
62-
public AndroidDriver(HttpCommandExecutor executor, Capabilities capabilities) {
62+
public AndroidDriver(AppiumCommandExecutor executor, Capabilities capabilities) {
6363
super(executor, substituteMobilePlatform(capabilities, ANDROID_PLATFORM));
6464
}
6565

src/main/java/io/appium/java_client/ios/IOSDriver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@
2424
import io.appium.java_client.FindsByIosUIAutomation;
2525
import io.appium.java_client.HidesKeyboardWithKeyName;
2626
import io.appium.java_client.TouchAction;
27+
import io.appium.java_client.remote.AppiumCommandExecutor;
2728
import io.appium.java_client.remote.MobilePlatform;
2829
import io.appium.java_client.service.local.AppiumDriverLocalService;
2930
import io.appium.java_client.service.local.AppiumServiceBuilder;
3031
import org.openqa.selenium.Alert;
3132
import org.openqa.selenium.Capabilities;
3233
import org.openqa.selenium.WebElement;
3334
import org.openqa.selenium.remote.DriverCommand;
34-
import org.openqa.selenium.remote.HttpCommandExecutor;
3535
import org.openqa.selenium.remote.Response;
3636
import org.openqa.selenium.remote.http.HttpClient;
3737
import org.openqa.selenium.security.Credentials;
@@ -62,7 +62,7 @@ public class IOSDriver<T extends WebElement>
6262
* @param capabilities take a look
6363
* at {@link org.openqa.selenium.Capabilities}
6464
*/
65-
public IOSDriver(HttpCommandExecutor executor, Capabilities capabilities) {
65+
public IOSDriver(AppiumCommandExecutor executor, Capabilities capabilities) {
6666
super(executor, substituteMobilePlatform(capabilities, IOS_PLATFORM));
6767
}
6868

src/main/java/io/appium/java_client/remote/AndroidMobileCapabilityType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public interface AndroidMobileCapabilityType extends CapabilityType {
241241
String SELENDROID_PORT = "selendroidPort";
242242

243243
/**
244-
* The port number, which being used by UIAutomator2
244+
* The port number, which being used by UIAutomator2.
245245
*/
246246
String SYSTEM_PORT = "systemPort";
247247
}

src/main/java/io/appium/java_client/remote/AppiumCommandExecutor.java

Lines changed: 109 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,29 @@
1616

1717
package io.appium.java_client.remote;
1818

19+
import static com.google.common.base.Preconditions.checkNotNull;
20+
import static com.google.common.base.Throwables.getRootCause;
21+
import static com.google.common.base.Throwables.throwIfUnchecked;
22+
import static org.openqa.selenium.remote.DriverCommand.GET_ALL_SESSIONS;
23+
import static org.openqa.selenium.remote.DriverCommand.NEW_SESSION;
24+
import static org.openqa.selenium.remote.DriverCommand.QUIT;
1925

20-
import com.google.common.base.Throwables;
21-
26+
import io.appium.java_client.AppiumCommandInfo;
27+
import org.openqa.selenium.NoSuchSessionException;
28+
import org.openqa.selenium.SessionNotCreatedException;
29+
import org.openqa.selenium.UnsupportedCommandException;
2230
import org.openqa.selenium.WebDriverException;
2331
import org.openqa.selenium.remote.Command;
24-
import org.openqa.selenium.remote.CommandInfo;
32+
import org.openqa.selenium.remote.CommandCodec;
33+
import org.openqa.selenium.remote.CommandExecutor;
34+
import org.openqa.selenium.remote.Dialect;
2535
import org.openqa.selenium.remote.DriverCommand;
26-
import org.openqa.selenium.remote.HttpCommandExecutor;
36+
import org.openqa.selenium.remote.HttpSessionId;
2737
import org.openqa.selenium.remote.Response;
38+
import org.openqa.selenium.remote.ResponseCodec;
2839
import org.openqa.selenium.remote.http.HttpClient;
40+
import org.openqa.selenium.remote.http.HttpRequest;
41+
import org.openqa.selenium.remote.http.HttpResponse;
2942
import org.openqa.selenium.remote.internal.ApacheHttpClient;
3043
import org.openqa.selenium.remote.service.DriverService;
3144

@@ -34,41 +47,121 @@
3447
import java.net.URL;
3548
import java.util.Map;
3649

37-
public class AppiumCommandExecutor extends HttpCommandExecutor {
50+
public class AppiumCommandExecutor implements CommandExecutor {
3851

39-
private final DriverService service;
52+
private final URL remoteServer;
53+
private final HttpClient client;
54+
private final Map<String, AppiumCommandInfo> additionalCommands;
55+
private CommandCodec<HttpRequest> commandCodec;
56+
private ResponseCodec<HttpResponse> responseCodec;
57+
private DriverService service;
4058

41-
public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands,
59+
/**
60+
* Cretes an instance that sends requests and receives responses.
61+
*
62+
* @param additionalCommands is the mapped command repository
63+
* @param addressOfRemoteServer is the url to connect to the Appium remote/local server
64+
* @param httpClientFactory is the http client factory
65+
*/
66+
public AppiumCommandExecutor(Map<String, AppiumCommandInfo> additionalCommands,
4267
URL addressOfRemoteServer, HttpClient.Factory httpClientFactory) {
43-
super(additionalCommands, addressOfRemoteServer, httpClientFactory);
44-
service = null;
68+
checkNotNull(addressOfRemoteServer);
69+
remoteServer = addressOfRemoteServer;
70+
this.additionalCommands = additionalCommands;
71+
this.client = httpClientFactory.createClient(remoteServer);
4572
}
4673

47-
public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands, DriverService service,
74+
public AppiumCommandExecutor(Map<String, AppiumCommandInfo> additionalCommands, DriverService service,
4875
HttpClient.Factory httpClientFactory) {
49-
super(additionalCommands, service.getUrl(), httpClientFactory);
76+
this(additionalCommands, service.getUrl(), httpClientFactory);
5077
this.service = service;
5178
}
5279

53-
public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands,
80+
public AppiumCommandExecutor(Map<String, AppiumCommandInfo> additionalCommands,
5481
URL addressOfRemoteServer) {
5582
this(additionalCommands, addressOfRemoteServer, new ApacheHttpClient.Factory());
5683
}
5784

58-
public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands,
85+
public AppiumCommandExecutor(Map<String, AppiumCommandInfo> additionalCommands,
5986
DriverService service) {
6087
this(additionalCommands, service, new ApacheHttpClient.Factory());
6188
}
6289

90+
public URL getAddressOfRemoteServer() {
91+
return remoteServer;
92+
}
93+
94+
private Response doExecute(Command command) throws IOException, WebDriverException {
95+
if (command.getSessionId() == null) {
96+
if (QUIT.equals(command.getName())) {
97+
return new Response();
98+
}
99+
if (!GET_ALL_SESSIONS.equals(command.getName())
100+
&& !NEW_SESSION.equals(command.getName())) {
101+
throw new NoSuchSessionException(
102+
"Session ID is null. Using WebDriver after calling quit()?");
103+
}
104+
}
105+
106+
if (NEW_SESSION.equals(command.getName())) {
107+
if (commandCodec != null) {
108+
throw new SessionNotCreatedException("Session already exists");
109+
}
110+
AppiumProtocolHandShake handshake = new AppiumProtocolHandShake();
111+
AppiumProtocolHandShake.Result result = handshake.createSession(client, command);
112+
Dialect dialect = result.getDialect();
113+
commandCodec = dialect.getCommandCodec();
114+
115+
additionalCommands.forEach((key, value) -> {
116+
checkNotNull(key);
117+
checkNotNull(value);
118+
commandCodec.defineCommand(key, value.getMethod(), value.getUrl());
119+
} );
120+
121+
responseCodec = dialect.getResponseCodec();
122+
return result.createResponse();
123+
}
124+
125+
if (commandCodec == null || responseCodec == null) {
126+
throw new WebDriverException(
127+
"No command or response codec has been defined. Unable to proceed");
128+
}
129+
130+
HttpRequest httpRequest = commandCodec.encode(command);
131+
try {
132+
HttpResponse httpResponse = client.execute(httpRequest, true);
133+
134+
Response response = responseCodec.decode(httpResponse);
135+
if (response.getSessionId() == null) {
136+
if (httpResponse.getTargetHost() != null) {
137+
response.setSessionId(HttpSessionId.getSessionId(httpResponse.getTargetHost()));
138+
} else {
139+
response.setSessionId(command.getSessionId().toString());
140+
}
141+
}
142+
if (QUIT.equals(command.getName())) {
143+
client.close();
144+
}
145+
return response;
146+
} catch (UnsupportedCommandException e) {
147+
if (e.getMessage() == null || "".equals(e.getMessage())) {
148+
throw new UnsupportedOperationException(
149+
"No information from server. Command name was: " + command.getName(),
150+
e.getCause());
151+
}
152+
throw e;
153+
}
154+
}
155+
63156
@Override public Response execute(Command command) throws IOException, WebDriverException {
64157
if (DriverCommand.NEW_SESSION.equals(command.getName()) && service != null) {
65158
service.start();
66159
}
67160

68161
try {
69-
return super.execute(command);
162+
return doExecute(command);
70163
} catch (Throwable t) {
71-
Throwable rootCause = Throwables.getRootCause(t);
164+
Throwable rootCause = getRootCause(t);
72165
if (rootCause instanceof ConnectException
73166
&& rootCause.getMessage().contains("Connection refused")
74167
&& service != null) {
@@ -80,7 +173,7 @@ public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands,
80173
throw new WebDriverException("The appium server has accidentally died!", t);
81174
}
82175
}
83-
Throwables.propagateIfPossible(t);
176+
throwIfUnchecked(t);
84177
throw new WebDriverException(t);
85178
} finally {
86179
if (DriverCommand.QUIT.equals(command.getName()) && service != null) {

0 commit comments

Comments
 (0)