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.events; import static io.appium.java_client.events.DefaultBeanConfiguration.COMPONENT_BEAN; import com.google.common.collect.ImmutableList; import io.appium.java_client.events.api.Listener; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.openqa.selenium.Alert; import org.openqa.selenium.ContextAware; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.springframework.context.support.AbstractApplicationContext; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.List; @SuppressWarnings("unused") @Aspect class DefaultAspect { private static final List<Class<?>> listenable = ImmutableList.of(WebDriver.class, WebElement.class, WebDriver.Navigation.class, WebDriver.TargetLocator.class, ContextAware.class, Alert.class, WebDriver.Options.class, WebDriver.Window.class); private static final String EXECUTION_NAVIGATION_TO = "execution(* org.openqa.selenium.WebDriver." + "Navigation.get(..)) || " + "execution(* org.openqa.selenium.WebDriver.Navigation.to(..)) || " + "execution(* org.openqa.selenium.WebDriver.get(..))"; private static final String EXECUTION_NAVIGATION_BACK = "execution(* org.openqa.selenium.WebDriver." + "Navigation.back(..))"; private static final String EXECUTION_NAVIGATION_FORWARD = "execution(* org.openqa.selenium.WebDriver." + "Navigation.forward(..))"; private static final String EXECUTION_NAVIGATION_REFRESH = "execution(* org.openqa.selenium.WebDriver." + "Navigation.refresh(..))"; private static final String EXECUTION_SEARCH = "execution(* org.openqa.selenium.SearchContext." + "findElement(..)) || " + "execution(* org.openqa.selenium.SearchContext.findElements(..))"; private static final String EXECUTION_CLICK = "execution(* org.openqa.selenium.WebElement.click(..))"; private static final String EXECUTION_CHANGE_VALUE = "execution(* org.openqa.selenium.WebElement." + "sendKeys(..)) || " + "execution(* org.openqa.selenium.WebElement.clear(..)) || " + "execution(* io.appium.java_client.android.AndroidElement.replaceValue(..)) || " + "execution(* io.appium.java_client.MobileElement.setValue(..))"; private static final String EXECUTION_SCRIPT = "execution(* org.openqa.selenium.JavascriptExecutor." + "executeScript(..)) || " + "execution(* org.openqa.selenium.JavascriptExecutor.executeAsyncScript(..))"; private static final String EXECUTION_ALERT_ACCEPT = "execution(* org.openqa.selenium.Alert." + "accept(..))"; private static final String EXECUTION_ALERT_DISMISS = "execution(* org.openqa.selenium.Alert." + "dismiss(..))"; private static final String EXECUTION_ALERT_SEND_KEYS = "execution(* org.openqa.selenium.Alert." + "sendKeys(..))"; private static final String EXECUTION_WINDOW_SET_SIZE = "execution(* org.openqa.selenium." + "WebDriver.Window.setSize(..))"; private static final String EXECUTION_WINDOW_SET_POSITION = "execution(* org.openqa.selenium.WebDriver." + "Window.setPosition(..))"; private static final String EXECUTION_WINDOW_MAXIMIZE = "execution(* org.openqa.selenium.WebDriver." + "Window.maximize(..))"; private static final String EXECUTION_ROTATE = "execution(* org.openqa.selenium.Rotatable" + ".rotate(..))"; private static final String EXECUTION_CONTEXT = "execution(* org.openqa.selenium.ContextAware." + "context(..))"; private static final String EXECUTION_SWITCH_TO_WINDOW = "execution(* org.openqa.selenium.WebDriver.TargetLocator" + ".window(..))"; private static final String EXECUTION_TAKE_SCREENSHOT_AS = "execution(* org.openqa.selenium.TakesScreenshot" + ".getScreenshotAs(..))"; private static final String AROUND = "execution(* org.openqa.selenium.WebDriver.*(..)) || " + "execution(* org.openqa.selenium.WebElement.*(..)) || " + "execution(* org.openqa.selenium.WebDriver.Navigation.*(..)) || " + "execution(* org.openqa.selenium.WebDriver.Options.*(..)) || " + "execution(* org.openqa.selenium.WebDriver.TargetLocator.*(..)) || " + "execution(* org.openqa.selenium.WebDriver.TargetLocator.*(..)) || " + "execution(* org.openqa.selenium.JavascriptExecutor.*(..)) || " + "execution(* org.openqa.selenium.ContextAware.*(..)) || " + "execution(* io.appium.java_client.FindsByAccessibilityId.*(..)) || " + "execution(* io.appium.java_client.FindsByAndroidUIAutomator.*(..)) || " + "execution(* io.appium.java_client.FindsByIosUIAutomation.*(..)) || " + "execution(* io.appium.java_client.FindsByWindowsAutomation.*(..)) || " + "execution(* io.appium.java_client.FindsByIosNSPredicate.*(..)) || " + "execution(* org.openqa.selenium.internal.FindsByClassName.*(..)) || " + "execution(* org.openqa.selenium.internal.FindsByCssSelector.*(..)) || " + "execution(* org.openqa.selenium.internal.FindsById.*(..)) || " + "execution(* org.openqa.selenium.internal.FindsByLinkText.*(..)) || " + "execution(* org.openqa.selenium.internal.FindsByName.*(..)) || " + "execution(* org.openqa.selenium.internal.FindsByTagName.*(..)) || " + "execution(* org.openqa.selenium.internal.FindsByXPath.*(..)) || " + "execution(* org.openqa.selenium.WebDriver.Window.*(..)) || " + "execution(* io.appium.java_client.android.AndroidElement.*(..)) || " + "execution(* io.appium.java_client.ios.IOSElement.*(..)) || " + "execution(* io.appium.java_client.android.AndroidDriver.*(..)) || " + "execution(* io.appium.java_client.ios.IOSDriver.*(..)) || " + "execution(* io.appium.java_client.AppiumDriver.*(..)) || " + "execution(* io.appium.java_client.MobileElement.*(..)) || " + "execution(* org.openqa.selenium.remote.RemoteWebDriver.*(..)) || " + "execution(* org.openqa.selenium.remote.RemoteWebElement.*(..)) || " + "execution(* org.openqa.selenium.Alert.*(..)) || " + "execution(* org.openqa.selenium.TakesScreenshot.*(..))"; private final AbstractApplicationContext context; private final WebDriver driver; private final DefaultListener listener = new DefaultListener(); private static Throwable getRootCause(Throwable thrown) { Class<? extends Throwable> throwableClass = thrown.getClass(); if (!InvocationTargetException.class.equals(throwableClass) && !RuntimeException.class.equals(throwableClass)) { return thrown; } if (thrown.getCause() != null) { return getRootCause(thrown.getCause()); } return thrown; } private static Class<?> getClassForProxy(Class<?> classOfObject) { Class<?> returnStatement = null; for (Class<?> c : listenable) { if (!c.isAssignableFrom(classOfObject)) { continue; } returnStatement = c; } return returnStatement; } DefaultAspect(AbstractApplicationContext context, WebDriver driver) { this.context = context; this.driver = driver; } private Object transformToListenable(Object toBeTransformed) { if (toBeTransformed == null) { return null; } Object result = toBeTransformed; if (getClassForProxy(toBeTransformed.getClass()) != null) { result = context.getBean(COMPONENT_BEAN, toBeTransformed); } return result; } private List<Object> returnProxyList(List<Object> originalList) throws Exception { try { List<Object> proxyList = new ArrayList<>(); for (Object o : originalList) { if (getClassForProxy(o.getClass()) == null) { proxyList.add(o); } else { proxyList.add(context.getBean(COMPONENT_BEAN, o)); } } return proxyList; } catch (Exception e) { throw e; } } public void add(Collection<Listener> listeners) { listener.add(listeners); } @Before(EXECUTION_NAVIGATION_TO) public void beforeNavigateTo(JoinPoint joinPoint) throws Throwable { try { listener.beforeNavigateTo(String.valueOf(joinPoint.getArgs()[0]), driver); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_NAVIGATION_TO) public void afterNavigateTo(JoinPoint joinPoint) throws Throwable { try { listener.afterNavigateTo(String.valueOf(joinPoint.getArgs()[0]), driver); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_NAVIGATION_BACK) public void beforeNavigateBack(JoinPoint joinPoint) throws Throwable { try { listener.beforeNavigateBack(driver); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_NAVIGATION_BACK) public void afterNavigateBack(JoinPoint joinPoint) throws Throwable { try { listener.afterNavigateBack(driver); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_NAVIGATION_FORWARD) public void beforeNavigateForward(JoinPoint joinPoint) throws Throwable { try { listener.beforeNavigateForward(driver); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_NAVIGATION_FORWARD) public void afterNavigateForward(JoinPoint joinPoint) throws Throwable { try { listener.afterNavigateForward(driver); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_NAVIGATION_REFRESH) public void beforeNavigateRefresh(JoinPoint joinPoint) throws Throwable { try { listener.beforeNavigateRefresh(driver); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_NAVIGATION_REFRESH) public void afterNavigateRefresh(JoinPoint joinPoint) throws Throwable { try { listener.afterNavigateRefresh(driver); } catch (Throwable t) { throw getRootCause(t); } } @SuppressWarnings("unchecked") private <T> T castArgument(JoinPoint joinPoint, int argIndex) { return (T) joinPoint.getArgs()[argIndex]; } @SuppressWarnings("unchecked") private <T> T castTarget(JoinPoint joinPoint) { return (T) joinPoint.getTarget(); } @Before(EXECUTION_SEARCH) public void beforeFindBy(JoinPoint joinPoint) throws Throwable { try { Object target = joinPoint.getTarget(); if (!WebElement.class.isAssignableFrom(target.getClass())) { listener.beforeFindBy(castArgument(joinPoint, 0), null, driver); } else { listener.beforeFindBy(castArgument(joinPoint, 0), castTarget(joinPoint), driver); } } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_SEARCH) public void afterFindBy(JoinPoint joinPoint) throws Throwable { try { Object target = joinPoint.getTarget(); if (!WebElement.class.isAssignableFrom(target.getClass())) { listener.afterFindBy(castArgument(joinPoint, 0), null, driver); } else { listener.afterFindBy(castArgument(joinPoint, 0), castTarget(joinPoint), driver); } } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_CLICK) public void beforeClickOn(JoinPoint joinPoint) throws Throwable { try { listener.beforeClickOn(castTarget(joinPoint), driver); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_CLICK) public void afterClickOn(JoinPoint joinPoint) throws Throwable { try { listener.afterClickOn(castTarget(joinPoint), driver); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_CHANGE_VALUE) public void beforeChangeValueOf(JoinPoint joinPoint) throws Throwable { try { listener.beforeChangeValueOf(castTarget(joinPoint), driver); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_CHANGE_VALUE) public void afterChangeValueOf(JoinPoint joinPoint) throws Throwable { try { listener.afterChangeValueOf(castTarget(joinPoint), driver); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_SCRIPT) public void beforeScript(JoinPoint joinPoint) throws Throwable { try { listener.beforeScript(String.valueOf(joinPoint.getArgs()[0]), driver); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_SCRIPT) public void afterScript(JoinPoint joinPoint) throws Throwable { try { listener.afterScript(String.valueOf(joinPoint.getArgs()[0]), driver); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_ALERT_ACCEPT) public void beforeAlertAccept(JoinPoint joinPoint) throws Throwable { try { listener.beforeAlertAccept(driver, castTarget(joinPoint)); listener.beforeAlertAccept(driver); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_ALERT_ACCEPT) public void afterAlertAccept(JoinPoint joinPoint) throws Throwable { try { listener.afterAlertAccept(driver, castTarget(joinPoint)); listener.afterAlertAccept(driver); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_ALERT_DISMISS) public void beforeAlertDismiss(JoinPoint joinPoint) throws Throwable { try { listener.beforeAlertDismiss(driver, castTarget(joinPoint)); listener.beforeAlertDismiss(driver); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_ALERT_DISMISS) public void afterAlertDismiss(JoinPoint joinPoint) throws Throwable { try { listener.afterAlertDismiss(driver, castTarget(joinPoint)); listener.afterAlertDismiss(driver); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_ALERT_SEND_KEYS) public void beforeAlertSendKeys(JoinPoint joinPoint) throws Throwable { try { listener.beforeAlertSendKeys(driver, castTarget(joinPoint), String.valueOf(joinPoint.getArgs()[0])); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_ALERT_SEND_KEYS) public void afterAlertSendKeys(JoinPoint joinPoint) throws Throwable { try { listener.afterAlertSendKeys(driver, castTarget(joinPoint), String.valueOf(joinPoint.getArgs()[0])); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_WINDOW_SET_SIZE) public void beforeWindowIsResized(JoinPoint joinPoint) throws Throwable { try { listener.beforeWindowChangeSize(driver, castTarget(joinPoint), castArgument(joinPoint, 0)); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_WINDOW_SET_SIZE) public void afterWindowIsResized(JoinPoint joinPoint) throws Throwable { try { listener.afterWindowChangeSize(driver, castTarget(joinPoint), castArgument(joinPoint, 0)); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_WINDOW_SET_POSITION) public void beforeWindowIsMoved(JoinPoint joinPoint) throws Throwable { try { listener.beforeWindowIsMoved(driver, castTarget(joinPoint), castArgument(joinPoint, 0)); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_WINDOW_SET_POSITION) public void afterWindowIsMoved(JoinPoint joinPoint) throws Throwable { try { listener.afterWindowIsMoved(driver, castTarget(joinPoint), castArgument(joinPoint, 0)); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_WINDOW_MAXIMIZE) public void beforeMaximization(JoinPoint joinPoint) throws Throwable { try { listener.beforeWindowIsMaximized(driver, castTarget(joinPoint)); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_WINDOW_MAXIMIZE) public void afterMaximization(JoinPoint joinPoint) throws Throwable { try { listener.afterWindowIsMaximized(driver, castTarget(joinPoint)); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_SWITCH_TO_WINDOW) public void beforeSwitchToWindow(JoinPoint joinPoint) throws Throwable { try { listener.beforeSwitchToWindow(castArgument(joinPoint, 0), driver); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_SWITCH_TO_WINDOW) public void afterSwitchToWindow(JoinPoint joinPoint) throws Throwable { try { listener.afterSwitchToWindow(castArgument(joinPoint, 0), driver); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_TAKE_SCREENSHOT_AS) public void beforeTakeScreenShot(JoinPoint joinPoint) throws Throwable { try { listener.beforeGetScreenshotAs(castArgument(joinPoint, 0)); } catch (Throwable t) { throw getRootCause(t); } } @AfterReturning(value = EXECUTION_TAKE_SCREENSHOT_AS, returning = "result") public void afterTakeScreenShot(JoinPoint joinPoint, Object result) throws Throwable { try { listener.afterGetScreenshotAs(castArgument(joinPoint, 0), result); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_ROTATE) public void beforeRotation(JoinPoint joinPoint) throws Throwable { try { listener.beforeRotation(driver, castArgument(joinPoint, 0)); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_ROTATE) public void afterRotation(JoinPoint joinPoint) throws Throwable { try { listener.afterRotation(driver, castArgument(joinPoint, 0)); } catch (Throwable t) { throw getRootCause(t); } } @Before(EXECUTION_CONTEXT) public void beforeSwitchingToContext(JoinPoint joinPoint) throws Throwable { try { listener.beforeSwitchingToContext(driver, String.valueOf(joinPoint.getArgs()[0])); } catch (Throwable t) { throw getRootCause(t); } } @After(EXECUTION_CONTEXT) public void afterSwitchingToContextn(JoinPoint joinPoint) throws Throwable { try { listener.afterSwitchingToContext(driver, String.valueOf(joinPoint.getArgs()[0])); } catch (Throwable t) { throw getRootCause(t); } } @Around(AROUND) public Object doAround(ProceedingJoinPoint point) throws Throwable { Throwable t = null; Object result = null; try { result = point.proceed(); } catch (Throwable e) { t = e; } if (t != null) { Throwable rootCause = getRootCause(t); listener.onException(rootCause, driver); throw rootCause; } if (result == null) { // maybe it was "void" return null; } if (List.class.isAssignableFrom(result.getClass())) { return returnProxyList((List<Object>) (result)); } return transformToListenable(result); } }