/* * JBoss, Home of Professional Open Source * Copyright 2010, Red Hat Middleware LLC, and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * 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 org.jboss.arquillian.drone.webdriver.factory.remote.reusable; import java.lang.reflect.Field; import java.net.URL; import org.openqa.selenium.Capabilities; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.remote.CommandExecutor; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.Dialect; import org.openqa.selenium.remote.HttpCommandExecutor; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.remote.SessionId; /** * Reusable remote driver provides same functionality like {@link RemoteWebDriver}, but it additionally allows to reuse * browser * session. * <p> * Provides reusing of {@link RemoteWebDriver} session by allowing to setup {@link DesiredCapabilities} and {@link * SessionId} * from previous session. * * @author <a href="mailto:lryc@redhat.com">Lukas Fryc</a> */ public class ReusableRemoteWebDriver extends RemoteWebDriver { ReusableRemoteWebDriver() { super(); } protected ReusableRemoteWebDriver(CommandExecutor executor, Capabilities capabilities, SessionId sessionId) { super(); setCommandExecutor(executor); setReusedCapabilities(capabilities); setSessionId(sessionId.toString()); } protected ReusableRemoteWebDriver(URL remoteAddress, Capabilities capabilities, SessionId sessionId) { super(); HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(remoteAddress); setCommandExecutor(httpCommandExecutor); setReusedCapabilities(capabilities); setValueToFieldInHttpCommandExecutor(httpCommandExecutor, "commandCodec", Dialect.OSS.getCommandCodec()); setValueToFieldInHttpCommandExecutor(httpCommandExecutor, "responseCodec", Dialect.OSS.getResponseCodec()); setSessionId(sessionId.toString()); } /** * Creates the {@link ReusableRemoteWebDriver} from valid {@link RemoteWebDriver} instance. * * @param remoteWebDriver * valid {@link RemoteWebDriver} instance. * * @return the {@link RemoteWebDriver} wrapped as {@link ReusableRemoteWebDriver} */ public static RemoteWebDriver fromRemoteWebDriver(RemoteWebDriver remoteWebDriver) { RemoteWebDriver driver = new ReusableRemoteWebDriver(remoteWebDriver.getCommandExecutor(), remoteWebDriver.getCapabilities(), remoteWebDriver.getSessionId()); try { checkReusability(remoteWebDriver.getSessionId(), driver); return driver; } catch (UnableReuseSessionException e) { throw new IllegalStateException("Reusing RemoteWebDriver session unexpectedly failed", e); } } /** * Reuses browser session using sessionId and desiredCapabilities as fully-initialized {@link Capabilities} object * from the * previous {@link RemoteWebDriver} session. * * @param remoteAddress * address of the remote Selenium Server hub * @param desiredCapabilities * fully-initialized capabilities returned from previous {@link RemoteWebDriver} session * @param sessionId * sessionId from previous {@link RemoteWebDriver} session */ public static RemoteWebDriver fromReusedSession(URL remoteAddress, Capabilities desiredCapabilities, SessionId sessionId) throws UnableReuseSessionException { RemoteWebDriver driver = new ReusableRemoteWebDriver(remoteAddress, desiredCapabilities, sessionId); checkReusability(sessionId, driver); return driver; } /** * Check that reused session can be controlled. * <p> * If it cannot be controlled (API calls throw exception), throw {@link UnableReuseSessionException}. * * @throws UnableReuseSessionException */ private static void checkReusability(SessionId oldSessionId, RemoteWebDriver driver) throws UnableReuseSessionException { if (!oldSessionId.equals(driver.getSessionId())) { throw new UnableReuseSessionException("The created session has another id then session we tried to reuse"); } try { driver.getCurrentUrl(); } catch (WebDriverException e) { throw new UnableReuseSessionException(e); } } private static Field getFieldSafely(Object object, Class<?> clazz, String fieldName) { try { return clazz.getDeclaredField(fieldName); } catch (Exception e) { throw new IllegalStateException(e); } } private static void writeValueToField(Object object, Field field, Object value) { boolean wasAccessible = field.isAccessible(); if (!wasAccessible) { field.setAccessible(true); } try { field.set(object, value); } catch (Exception e) { throw new IllegalStateException(e); } if (!wasAccessible) { field.setAccessible(false); } } void setReusedCapabilities(Capabilities capabilities) { Field capabilitiesField = getFieldSafely(this, RemoteWebDriver.class, "capabilities"); writeValueToField(this, capabilitiesField, capabilities); } void setValueToFieldInHttpCommandExecutor(Object instance, String fieldName, Object value) { Field field = getFieldSafely(instance, HttpCommandExecutor.class, fieldName); writeValueToField(instance, field, value); } }