Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#594 FIX #597

Merged
merged 8 commits into from
Mar 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ compileJava {
}

dependencies {
compile('org.seleniumhq.selenium:selenium-java:3.2.0'){
compile('org.seleniumhq.selenium:selenium-java:3.3.1'){
exclude module: 'cglib'
exclude group: 'com.google.code.gson'
}
Expand Down
45 changes: 45 additions & 0 deletions src/main/java/io/appium/java_client/AppiumCommandInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.appium.java_client;

import org.openqa.selenium.remote.CommandInfo;
import org.openqa.selenium.remote.http.HttpMethod;

public class AppiumCommandInfo extends CommandInfo {
private final String url;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't it be more useful to keep url as an URL object instead of just a string?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private final HttpMethod method;

/**
* It conntains method and URL of the command.
*
* @param url command URL
* @param method is http-method
*/
public AppiumCommandInfo(String url, HttpMethod method) {
super(url, method);
this.url = url;
this.method = method;
}

public String getUrl() {
return url;
}

public HttpMethod getMethod() {
return method;
}
}
3 changes: 1 addition & 2 deletions src/main/java/io/appium/java_client/AppiumDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import org.openqa.selenium.remote.DriverCommand;
import org.openqa.selenium.remote.ErrorHandler;
import org.openqa.selenium.remote.ExecuteMethod;
import org.openqa.selenium.remote.HttpCommandExecutor;
import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.html5.RemoteLocationContext;
import org.openqa.selenium.remote.http.HttpClient;
Expand Down Expand Up @@ -85,7 +84,7 @@ public class AppiumDriver<T extends WebElement>
* @param capabilities take a look
* at {@link org.openqa.selenium.Capabilities}
*/
public AppiumDriver(HttpCommandExecutor executor, Capabilities capabilities) {
public AppiumDriver(AppiumCommandExecutor executor, Capabilities capabilities) {
super(executor, capabilities);
this.executeMethod = new AppiumExecutionMethod(this);
locationContext = new RemoteLocationContext(executeMethod);
Expand Down
15 changes: 7 additions & 8 deletions src/main/java/io/appium/java_client/MobileCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import com.google.common.collect.ImmutableMap;

import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.remote.CommandInfo;
import org.openqa.selenium.remote.http.HttpMethod;

import java.util.AbstractMap;
Expand Down Expand Up @@ -77,7 +76,7 @@ public class MobileCommand {
protected static final String GET_SETTINGS;
protected static final String SET_SETTINGS;

public static final Map<String, CommandInfo> commandRepository;
public static final Map<String, AppiumCommandInfo> commandRepository;

static {
RESET = "reset";
Expand Down Expand Up @@ -184,8 +183,8 @@ public class MobileCommand {
* @param url is the command URL
* @return an instance of {@link org.openqa.selenium.remote.CommandInfo}
*/
public static CommandInfo getC(String url) {
return new CommandInfo(url, HttpMethod.GET);
public static AppiumCommandInfo getC(String url) {
return new AppiumCommandInfo(url, HttpMethod.GET);
}

/**
Expand All @@ -194,8 +193,8 @@ public static CommandInfo getC(String url) {
* @param url is the command URL
* @return an instance of {@link org.openqa.selenium.remote.CommandInfo}
*/
public static CommandInfo postC(String url) {
return new CommandInfo(url, HttpMethod.POST);
public static AppiumCommandInfo postC(String url) {
return new AppiumCommandInfo(url, HttpMethod.POST);
}

/**
Expand All @@ -204,8 +203,8 @@ public static CommandInfo postC(String url) {
* @param url is the command URL
* @return an instance of {@link org.openqa.selenium.remote.CommandInfo}
*/
public static CommandInfo deleteC(String url) {
return new CommandInfo(url, HttpMethod.DELETE);
public static AppiumCommandInfo deleteC(String url) {
return new AppiumCommandInfo(url, HttpMethod.DELETE);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
import io.appium.java_client.FindsByAndroidUIAutomator;
import io.appium.java_client.PressesKeyCode;
import io.appium.java_client.TouchAction;
import io.appium.java_client.remote.AppiumCommandExecutor;
import io.appium.java_client.remote.MobilePlatform;
import io.appium.java_client.service.local.AppiumDriverLocalService;
import io.appium.java_client.service.local.AppiumServiceBuilder;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.HttpCommandExecutor;
import org.openqa.selenium.remote.http.HttpClient;

import java.net.URL;
Expand Down Expand Up @@ -59,7 +59,7 @@ public class AndroidDriver<T extends WebElement>
* @param capabilities take a look
* at {@link org.openqa.selenium.Capabilities}
*/
public AndroidDriver(HttpCommandExecutor executor, Capabilities capabilities) {
public AndroidDriver(AppiumCommandExecutor executor, Capabilities capabilities) {
super(executor, substituteMobilePlatform(capabilities, ANDROID_PLATFORM));
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/io/appium/java_client/ios/IOSDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@
import io.appium.java_client.FindsByIosUIAutomation;
import io.appium.java_client.HidesKeyboardWithKeyName;
import io.appium.java_client.TouchAction;
import io.appium.java_client.remote.AppiumCommandExecutor;
import io.appium.java_client.remote.MobilePlatform;
import io.appium.java_client.service.local.AppiumDriverLocalService;
import io.appium.java_client.service.local.AppiumServiceBuilder;
import org.openqa.selenium.Alert;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DriverCommand;
import org.openqa.selenium.remote.HttpCommandExecutor;
import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.security.Credentials;
Expand Down Expand Up @@ -61,7 +61,7 @@ public class IOSDriver<T extends WebElement>
* @param capabilities take a look
* at {@link org.openqa.selenium.Capabilities}
*/
public IOSDriver(HttpCommandExecutor executor, Capabilities capabilities) {
public IOSDriver(AppiumCommandExecutor executor, Capabilities capabilities) {
super(executor, substituteMobilePlatform(capabilities, IOS_PLATFORM));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ public interface AndroidMobileCapabilityType extends CapabilityType {
String SELENDROID_PORT = "selendroidPort";

/**
* The port number, which being used by UIAutomator2
* The port number, which being used by UIAutomator2.
*/
String SYSTEM_PORT = "systemPort";
}
125 changes: 109 additions & 16 deletions src/main/java/io/appium/java_client/remote/AppiumCommandExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,29 @@

package io.appium.java_client.remote;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.getRootCause;
import static com.google.common.base.Throwables.throwIfUnchecked;
import static org.openqa.selenium.remote.DriverCommand.GET_ALL_SESSIONS;
import static org.openqa.selenium.remote.DriverCommand.NEW_SESSION;
import static org.openqa.selenium.remote.DriverCommand.QUIT;

import com.google.common.base.Throwables;

import io.appium.java_client.AppiumCommandInfo;
import org.openqa.selenium.NoSuchSessionException;
import org.openqa.selenium.SessionNotCreatedException;
import org.openqa.selenium.UnsupportedCommandException;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.Command;
import org.openqa.selenium.remote.CommandInfo;
import org.openqa.selenium.remote.CommandCodec;
import org.openqa.selenium.remote.CommandExecutor;
import org.openqa.selenium.remote.Dialect;
import org.openqa.selenium.remote.DriverCommand;
import org.openqa.selenium.remote.HttpCommandExecutor;
import org.openqa.selenium.remote.HttpSessionId;
import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.ResponseCodec;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.internal.ApacheHttpClient;
import org.openqa.selenium.remote.service.DriverService;

Expand All @@ -34,41 +47,121 @@
import java.net.URL;
import java.util.Map;

public class AppiumCommandExecutor extends HttpCommandExecutor {
public class AppiumCommandExecutor implements CommandExecutor {

private final DriverService service;
private final URL remoteServer;
private final HttpClient client;
private final Map<String, AppiumCommandInfo> additionalCommands;
private CommandCodec<HttpRequest> commandCodec;
private ResponseCodec<HttpResponse> responseCodec;
private DriverService service;

public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands,
/**
* Cretes an instance that sends requests and receives responses.
*
* @param additionalCommands is the mapped command repository
* @param addressOfRemoteServer is the url to connect to the Appium remote/local server
* @param httpClientFactory is the http client factory
*/
public AppiumCommandExecutor(Map<String, AppiumCommandInfo> additionalCommands,
URL addressOfRemoteServer, HttpClient.Factory httpClientFactory) {
super(additionalCommands, addressOfRemoteServer, httpClientFactory);
service = null;
checkNotNull(addressOfRemoteServer);
remoteServer = addressOfRemoteServer;
this.additionalCommands = additionalCommands;
this.client = httpClientFactory.createClient(remoteServer);
}

public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands, DriverService service,
public AppiumCommandExecutor(Map<String, AppiumCommandInfo> additionalCommands, DriverService service,
HttpClient.Factory httpClientFactory) {
super(additionalCommands, service.getUrl(), httpClientFactory);
this(additionalCommands, service.getUrl(), httpClientFactory);
this.service = service;
}

public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands,
public AppiumCommandExecutor(Map<String, AppiumCommandInfo> additionalCommands,
URL addressOfRemoteServer) {
this(additionalCommands, addressOfRemoteServer, new ApacheHttpClient.Factory());
}

public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands,
public AppiumCommandExecutor(Map<String, AppiumCommandInfo> additionalCommands,
DriverService service) {
this(additionalCommands, service, new ApacheHttpClient.Factory());
}

public URL getAddressOfRemoteServer() {
return remoteServer;
}

private Response doExecute(Command command) throws IOException, WebDriverException {
if (command.getSessionId() == null) {
if (QUIT.equals(command.getName())) {
return new Response();
}
if (!GET_ALL_SESSIONS.equals(command.getName())
&& !NEW_SESSION.equals(command.getName())) {
throw new NoSuchSessionException(
"Session ID is null. Using WebDriver after calling quit()?");
}
}

if (NEW_SESSION.equals(command.getName())) {
if (commandCodec != null) {
throw new SessionNotCreatedException("Session already exists");
}
AppiumProtocolHandShake handshake = new AppiumProtocolHandShake();
AppiumProtocolHandShake.Result result = handshake.createSession(client, command);
Dialect dialect = result.getDialect();
commandCodec = dialect.getCommandCodec();

additionalCommands.forEach((key, value) -> {
checkNotNull(key);
checkNotNull(value);
commandCodec.defineCommand(key, value.getMethod(), value.getUrl());
} );

responseCodec = dialect.getResponseCodec();
return result.createResponse();
}

if (commandCodec == null || responseCodec == null) {
throw new WebDriverException(
"No command or response codec has been defined. Unable to proceed");
}

HttpRequest httpRequest = commandCodec.encode(command);
try {
HttpResponse httpResponse = client.execute(httpRequest, true);

Response response = responseCodec.decode(httpResponse);
if (response.getSessionId() == null) {
if (httpResponse.getTargetHost() != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we assume, that httpResponse and response can never be equal to null?

response.setSessionId(HttpSessionId.getSessionId(httpResponse.getTargetHost()));
} else {
response.setSessionId(command.getSessionId().toString());
}
}
if (QUIT.equals(command.getName())) {
client.close();
}
return response;
} catch (UnsupportedCommandException e) {
if (e.getMessage() == null || "".equals(e.getMessage())) {
throw new UnsupportedOperationException(
"No information from server. Command name was: " + command.getName(),
e.getCause());
}
throw e;
}
}

@Override public Response execute(Command command) throws IOException, WebDriverException {
if (DriverCommand.NEW_SESSION.equals(command.getName()) && service != null) {
service.start();
}

try {
return super.execute(command);
return doExecute(command);
} catch (Throwable t) {
Throwable rootCause = Throwables.getRootCause(t);
Throwable rootCause = getRootCause(t);
if (rootCause instanceof ConnectException
&& rootCause.getMessage().contains("Connection refused")
&& service != null) {
Expand All @@ -80,7 +173,7 @@ public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands,
throw new WebDriverException("The appium server has accidentally died!", t);
}
}
Throwables.propagateIfPossible(t);
throwIfUnchecked(t);
throw new WebDriverException(t);
} finally {
if (DriverCommand.QUIT.equals(command.getName()) && service != null) {
Expand Down
Loading