Skip to content

fix: Deprecate AppiumProtocolHandshake class #2173

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

Merged
merged 5 commits into from
May 16, 2024
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
41 changes: 22 additions & 19 deletions src/main/java/io/appium/java_client/AppiumDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import io.appium.java_client.internal.ReflectionHelpers;
import io.appium.java_client.internal.SessionHelpers;
import io.appium.java_client.remote.AppiumCommandExecutor;
import io.appium.java_client.remote.AppiumNewSessionCommandPayload;
import io.appium.java_client.remote.AppiumW3CHttpCommandCodec;
import io.appium.java_client.remote.options.BaseOptions;
import io.appium.java_client.service.local.AppiumDriverLocalService;
Expand Down Expand Up @@ -50,11 +49,13 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import static com.google.common.base.Strings.isNullOrEmpty;
import static io.appium.java_client.internal.CapabilityHelpers.APPIUM_PREFIX;
import static io.appium.java_client.remote.options.SupportsAutomationNameOption.AUTOMATION_NAME_OPTION;
import static java.util.Collections.singleton;
import static org.openqa.selenium.remote.CapabilityType.PLATFORM_NAME;

/**
Expand Down Expand Up @@ -265,25 +266,27 @@ public void addCommand(HttpMethod httpMethod, String url, String methodName) {

@Override
protected void startSession(Capabilities capabilities) {
Response response = execute(new AppiumNewSessionCommandPayload(capabilities));
if (response == null) {
throw new SessionNotCreatedException(
"The underlying command executor returned a null response.");
}

Object responseValue = response.getValue();
if (responseValue == null) {
throw new SessionNotCreatedException(
"The underlying command executor returned a response without payload: "
+ response);
}
if (!(responseValue instanceof Map)) {
throw new SessionNotCreatedException(
"The underlying command executor returned a response with a non well formed payload: "
+ response);
}
var response = Optional.ofNullable(
execute(DriverCommand.NEW_SESSION(singleton(capabilities)))
).orElseThrow(() -> new SessionNotCreatedException(
"The underlying command executor returned a null response."
));

var rawCapabilities = Optional.ofNullable(response.getValue())
.map(value -> {
if (!(value instanceof Map)) {
throw new SessionNotCreatedException(String.format(
"The underlying command executor returned a response "
+ "with a non well formed payload: %s", response)
);
}
//noinspection unchecked
return (Map<String, Object>) value;
})
.orElseThrow(() -> new SessionNotCreatedException(
"The underlying command executor returned a response without payload: " + response)
);

@SuppressWarnings("unchecked") Map<String, Object> rawCapabilities = (Map<String, Object>) responseValue;
// TODO: remove this workaround for Selenium API enforcing some legacy capability values in major version
rawCapabilities.remove("platform");
if (rawCapabilities.containsKey(CapabilityType.BROWSER_NAME)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ private Response createSession(Command command) throws IOException {
throw new SessionNotCreatedException("Session already exists");
}

ProtocolHandshake.Result result = new AppiumProtocolHandshake().createSession(getClient(), command);
var result = new ProtocolHandshake().createSession(getClient(), command);
Dialect dialect = result.getDialect();
if (!(dialect.getCommandCodec() instanceof W3CHttpCommandCodec)) {
throw new SessionNotCreatedException("Only W3C sessions are supported. "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@

import static org.openqa.selenium.remote.DriverCommand.NEW_SESSION;

/**
* This class is deprecated and will be removed.
*
* @deprecated Use CommandPayload instead.
*/
@Deprecated
public class AppiumNewSessionCommandPayload extends CommandPayload {
/**
* Appends "appium:" prefix to all non-prefixed non-standard capabilities.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,108 +16,13 @@

package io.appium.java_client.remote;

import org.openqa.selenium.Capabilities;
import org.openqa.selenium.ImmutableCapabilities;
import org.openqa.selenium.SessionNotCreatedException;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.internal.Either;
import org.openqa.selenium.json.Json;
import org.openqa.selenium.json.JsonOutput;
import org.openqa.selenium.remote.Command;
import org.openqa.selenium.remote.NewSessionPayload;
import org.openqa.selenium.remote.ProtocolHandshake;
import org.openqa.selenium.remote.http.Contents;
import org.openqa.selenium.remote.http.HttpHandler;

import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;

@SuppressWarnings("UnstableApiUsage")
/**
* This class is deprecated and should be removed.
*
* @deprecated Use ProtocolHandshake instead.
*/
@Deprecated
public class AppiumProtocolHandshake extends ProtocolHandshake {
private static void writeJsonPayload(NewSessionPayload srcPayload, Appendable destination) {
try (JsonOutput json = new Json().newOutput(destination)) {
json.beginObject();

json.name("capabilities");
json.beginObject();

json.name("firstMatch");
json.beginArray();
json.beginObject();
json.endObject();
json.endArray();

json.name("alwaysMatch");
try {
Method getW3CMethod = NewSessionPayload.class.getDeclaredMethod("getW3C");
getW3CMethod.setAccessible(true);
//noinspection unchecked,resource
((Stream<Map<String, Object>>) getW3CMethod.invoke(srcPayload))
.findFirst()
.map(json::write)
.orElseGet(() -> {
json.beginObject();
json.endObject();
return null;
});
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new WebDriverException(e);
}

json.endObject(); // Close "capabilities" object

try {
Method writeMetaDataMethod = NewSessionPayload.class.getDeclaredMethod(
"writeMetaData", JsonOutput.class);
writeMetaDataMethod.setAccessible(true);
writeMetaDataMethod.invoke(srcPayload, json);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new WebDriverException(e);
}

json.endObject();
}
}

@Override
public Result createSession(HttpHandler client, Command command) throws IOException {
//noinspection unchecked
Capabilities desired = ((Set<Map<String, Object>>) command.getParameters().get("capabilities"))
.stream()
.findAny()
.map(ImmutableCapabilities::new)
.orElseGet(ImmutableCapabilities::new);
try (NewSessionPayload payload = NewSessionPayload.create(desired)) {
Either<SessionNotCreatedException, Result> result = createSession(client, payload);
if (result.isRight()) {
return result.right();
}
throw result.left();
}
}

@Override
public Either<SessionNotCreatedException, Result> createSession(HttpHandler client, NewSessionPayload payload) {

StringWriter stringWriter = new StringWriter();
writeJsonPayload(payload, stringWriter);

try {
Method createSessionMethod = ProtocolHandshake.class.getDeclaredMethod(
"createSession", HttpHandler.class, Contents.Supplier.class
);
createSessionMethod.setAccessible(true);
//noinspection unchecked
return (Either<SessionNotCreatedException, Result>) createSessionMethod.invoke(
this, client, Contents.utf8String(stringWriter.toString())
);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new WebDriverException(e);
}
}
}