All Downloads are FREE. Search and download functionalities are using the official Maven repository.

uk.sponte.automation.seleniumpom.proxies.handlers.PageElementListHandler Maven / Gradle / Ivy

There is a newer version: 3.0.14
Show newest version
package uk.sponte.automation.seleniumpom.proxies.handlers;

import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.internal.Locatable;
import org.openqa.selenium.internal.WrapsElement;
import uk.sponte.automation.seleniumpom.PageElementImpl;
import uk.sponte.automation.seleniumpom.configuration.Constants;
import uk.sponte.automation.seleniumpom.dependencies.DependencyInjector;
import uk.sponte.automation.seleniumpom.helpers.FrameWrapper;
import uk.sponte.automation.seleniumpom.helpers.ReflectionHelper;
import uk.sponte.automation.seleniumpom.orchestration.WebDriverFrameSwitchingOrchestrator;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import static java.util.logging.Logger.getLogger;

/**
 * Invocation handler for page element lists
 * Created by swozniak on 03/04/15.
 */
public class PageElementListHandler implements InvocationHandler, Refreshable {

    private final static Logger LOG = getLogger(
            PageElementListHandler.class.getName());

    private DependencyInjector driver;

    private SearchContext searchContext;

    private By by;

    private final FrameWrapper frame;

    private WebDriverFrameSwitchingOrchestrator webDriverFrameSwitchingOrchestrator;

    private ArrayList webElements;

    private Refreshable parent;
    private boolean needsRefresh;

    public PageElementListHandler(DependencyInjector driver,
            SearchContext searchContext, By by, FrameWrapper frame,
            WebDriverFrameSwitchingOrchestrator webDriverFrameSwitchingOrchestrator) {
        this.driver = driver;
        this.searchContext = searchContext;
        this.by = by;
        this.frame = frame;
        this.webDriverFrameSwitchingOrchestrator = webDriverFrameSwitchingOrchestrator;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        if (webElements == null) {
            List elements = this.searchContext.findElements(this.by);
            webElements = new ArrayList();

            for (WebElement webElement : elements) {
                webElements.add(getPageElementProxy(webElement));
            }
        }

        if(needsRefresh) {
            this.refresh();
        }

        try {
            LOG.fine(String.format("Calling %s on %s", method.getName(), this));
            return method.invoke(webElements, args);
        } catch (InvocationTargetException ex) {
            if(ex.getCause() instanceof IndexOutOfBoundsException) {
                refresh();
                return method.invoke(webElements, args);
            }
            LOG.warning(String.format("Error calling %s on %s", method.getName(), this));
            throw ex.getCause();
        }
    }

    private WebElement getPageElementProxy(WebElement webElement) {
        WebElementHandler handler = new WebElementHandler(driver,
                searchContext,
                By.id(Constants.DUMMY_PAGE_LOCATOR_FOR_LISTS),
                frame,
                webDriverFrameSwitchingOrchestrator,
                webElement
        );
        handler.setParent(this);

        WebElement webElementProxy = (WebElement) Proxy
                .newProxyInstance(
                        WebElement.class.getClassLoader(),
                        new Class[] {
                                WebElement.class,
                                Locatable.class,
                                SearchContext.class,
                                WrapsElement.class
                        },
                        handler
                );

        return new PageElementImpl(webElementProxy);
    }

    @Override
    public void invalidate() {
        if(webElements == null) return;
        for (WebElement webElement : this.webElements) {
            if(webElement instanceof PageElementImpl) {
                WebElement wrappedElement = ((PageElementImpl) webElement)
                        .getWrappedElement();
                if(wrappedElement instanceof Proxy) {
                    InvocationHandler invocationHandler = Proxy
                            .getInvocationHandler(wrappedElement);
                    if(invocationHandler instanceof Refreshable) {
                        ((Refreshable) invocationHandler).invalidate();
                    }
                }
            }
        }

        needsRefresh = true;
    }

    public void refresh() {
        needsRefresh = false;
        if(webElements == null) return;

        List elements = this.searchContext.findElements(by);
        Field elementField = ReflectionHelper
                .getField(PageElementImpl.class,
                        Constants.PAGE_ELEMENT_CONTAINER_FIELD_NAME);

        Field webElementInvocationHandlerWebElementField = ReflectionHelper
                .getField(WebElementHandler.class,
                        Constants.PAGE_ELEMENT_CONTAINER_FIELD_NAME);
        webElementInvocationHandlerWebElementField.setAccessible(true);


        assert elementField != null;
        elementField.setAccessible(true);

        while(webElements.size() > elements.size()) {
            webElements.remove(webElements.size() - 1);
        }

        for (int i = 0; i < elements.size(); i++) {
            WebElement e = elements.get(i);

            if (webElements.size() == i) {
                // this adds new element to the list
                webElements.add(getPageElementProxy(e));
            } else {
                // This resets web element handler in the existing list item so that references are still valid
                Object s = webElements.get(i);
                try {
                    Object webElementProxy = elementField.get(s);
                    if(webElementProxy instanceof Proxy) {
                        InvocationHandler invocationHandler = Proxy
                                .getInvocationHandler(webElementProxy);
                        if(invocationHandler instanceof WebElementHandler) {
                            webElementInvocationHandlerWebElementField.set(invocationHandler, e);
                        }
                    }
                } catch (IllegalAccessException e1) {
                    e1.printStackTrace();
                } catch (IllegalArgumentException e2) {
                    e2.printStackTrace();
                }
            }
        }
    }

    @Override
    public void setParent(Refreshable refreshable) {
        this.parent = refreshable;
    }

    @Override
    public void pageRefreshed(WebDriver driver) {
        invalidate();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy