Java tutorial
/* * 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.remote; import static com.google.common.base.Charsets.UTF_8; import static com.google.common.net.HttpHeaders.CONTENT_LENGTH; import static com.google.common.net.HttpHeaders.CONTENT_TYPE; import static com.google.common.net.MediaType.JSON_UTF_8; import static java.util.Optional.ofNullable; import static org.openqa.selenium.remote.ErrorCodes.SESSION_NOT_CREATED; import static org.openqa.selenium.remote.ErrorCodes.SUCCESS; import com.google.common.base.Preconditions; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.openqa.selenium.Capabilities; import org.openqa.selenium.SessionNotCreatedException; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.remote.BeanToJsonConverter; import org.openqa.selenium.remote.Command; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.Dialect; import org.openqa.selenium.remote.ErrorHandler; import org.openqa.selenium.remote.JsonException; import org.openqa.selenium.remote.JsonToBeanConverter; import org.openqa.selenium.remote.Response; import org.openqa.selenium.remote.SessionId; import org.openqa.selenium.remote.http.HttpClient; import org.openqa.selenium.remote.http.HttpMethod; import org.openqa.selenium.remote.http.HttpRequest; import org.openqa.selenium.remote.http.HttpResponse; import java.io.IOException; import java.net.HttpURLConnection; import java.util.HashMap; import java.util.Map; import java.util.Optional; class AppiumProtocolHandShake { public Result createSession(HttpClient client, Command command) throws IOException, WebDriverException { Capabilities desired = ofNullable((Capabilities) command.getParameters().get("desiredCapabilities")) .orElseGet(DesiredCapabilities::new); Capabilities required = ofNullable((Capabilities) command.getParameters().get("requiredCapabilities")) .orElseGet(DesiredCapabilities::new); JsonParser parser = new JsonParser(); JsonElement des = parser.parse(new BeanToJsonConverter().convert(desired)); JsonElement req = parser.parse(new BeanToJsonConverter().convert(required)); JsonObject jsonObject = new JsonObject(); amendW3CParameters(jsonObject, des, req); amendOssParamters(jsonObject, des, req); Optional<Result> result = createSession(client, jsonObject); return ofNullable(result.orElseGet(() -> { JsonObject jsonObject1 = new JsonObject(); amendOssParamters(jsonObject1, des, req); try { return createSession(client, jsonObject1).orElseGet(() -> { JsonObject jsonObject2 = new JsonObject(); amendW3CParameters(jsonObject2, des, req); try { return createSession(client, jsonObject2).orElse(null); } catch (IOException e) { throw new WebDriverException(e); } }); } catch (IOException e) { throw new WebDriverException(e); } })).orElseThrow(() -> new SessionNotCreatedException(String.format( "Unable to create new remote session. " + "desired capabilities = %s, required capabilities = %s", desired, required))); } private Optional<Result> createSession(HttpClient client, JsonObject params) throws IOException { // Create the http request and send it HttpRequest request = new HttpRequest(HttpMethod.POST, "/session"); String content = params.toString(); byte[] data = content.getBytes(UTF_8); request.setHeader(CONTENT_LENGTH, String.valueOf(data.length)); request.setHeader(CONTENT_TYPE, JSON_UTF_8.toString()); request.setContent(data); HttpResponse response = client.execute(request, true); Map<?, ?> jsonBlob = new HashMap<>(); String resultString = response.getContentString(); try { jsonBlob = new JsonToBeanConverter().convert(Map.class, resultString); } catch (ClassCastException e) { return Optional.empty(); } catch (JsonException e) { // Fine. Handle that below } // If the result looks positive, return the result. Object sessionId = jsonBlob.get("sessionId"); Object value = jsonBlob.get("value"); Object w3cError = jsonBlob.get("error"); Object ossStatus = jsonBlob.get("status"); Map<String, ?> capabilities = null; if (value != null && value instanceof Map) { capabilities = (Map<String, ?>) value; } else if (value != null && value instanceof Capabilities) { capabilities = ((Capabilities) capabilities).asMap(); } if (response.getStatus() == HttpURLConnection.HTTP_OK && sessionId != null && capabilities != null) { Dialect dialect = ossStatus == null ? Dialect.W3C : Dialect.OSS; return Optional.of(new Result(dialect, String.valueOf(sessionId), capabilities)); } // If the result was an error that we believe has to do with the remote end failing to start the // session, create an exception and throw it. Response tempResponse = null; if ("session not created".equals(w3cError)) { tempResponse = new Response(null); tempResponse.setStatus(SESSION_NOT_CREATED); tempResponse.setValue(jsonBlob); } else if (ossStatus instanceof Number && ((Number) ossStatus).intValue() == SESSION_NOT_CREATED) { tempResponse = new Response(null); tempResponse.setStatus(SESSION_NOT_CREATED); tempResponse.setValue(jsonBlob); } if (tempResponse != null) { new ErrorHandler().throwIfResponseFailed(tempResponse, 0); } // Otherwise, just return empty. return Optional.empty(); } private void amendW3CParameters(JsonObject jsonObject, JsonElement desired, JsonElement required) { JsonArray result = new JsonArray(); JsonObject desiredJson = new JsonObject(); JsonObject requiredJson = new JsonObject(); desiredJson.add("desiredCapabilities", desired); requiredJson.add("requiredCapabilities", required); result.add(desiredJson); result.add(requiredJson); jsonObject.add("capabilities", result); } private void amendOssParamters(JsonObject jsonObject, JsonElement desired, JsonElement required) { jsonObject.add("desiredCapabilities", desired); jsonObject.add("requiredCapabilities", required); } public class Result { private final Dialect dialect; private final Map<String, ?> capabilities; private final SessionId sessionId; private Result(Dialect dialect, String sessionId, Map<String, ?> capabilities) { this.dialect = dialect; this.sessionId = new SessionId(Preconditions.checkNotNull(sessionId)); this.capabilities = capabilities; } public Dialect getDialect() { return dialect; } public Response createResponse() { Response response = new Response(sessionId); response.setValue(capabilities); response.setStatus(SUCCESS); return response; } @Override public String toString() { return String.format("%s: %s", dialect, capabilities); } } }