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

jp.vmi.selenium.webdriver.WebDriverManager Maven / Gradle / Ivy

package jp.vmi.selenium.webdriver;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.NoSuchWindowException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.remote.UnreachableBrowserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.thoughtworks.selenium.SeleniumException;

/**
 * Manager of {@link WebDriver} instances.
 */
public class WebDriverManager implements WebDriverPreparator {

    private static final Logger log = LoggerFactory.getLogger(WebDriverManager.class);

    /**
     * Firefox.
     */
    public static final String FIREFOX = "firefox";

    /**
     * Chrome.
     */
    public static final String CHROME = "chrome";

    /**
     * Internet Explorer.
     */
    public static final String IE = "ie";

    /**
     * Html Unit.
     */
    public static final String HTMLUNIT = "htmlunit";

    /**
     * Safari.
     */
    public static final String SAFARI = "safari";

    /**
     *  RemoteWebDriver
     */
    public static final String REMOTE = "remote";

    /**
     *  AppiumWebDriver
     */
    public static final String APPIUM = "appium";

    /**
     * PhantomJS
     */
    public static final String PHANTOMJS = "phantomjs";

    /**
     * AndroidDriver
     */
    @Deprecated
    public static final String ANDROID = "android";

    private static class Builder {
        private final WebDriverFactory factory;
        private final DriverOptions driverOptions;
        public WebDriver driver;

        public Builder(WebDriverFactory factory, DriverOptions driverOptions) {
            this.factory = factory;
            this.driverOptions = driverOptions;
        }

        public String getKey() {
            return factory.getClass().getCanonicalName() + driverOptions.toString();
        }

        public Builder build() {
            driver = factory.newInstance(driverOptions);
            return this;
        }
    }

    /**
     * System property name for user defined {@link WebDriverFactory}.
     */
    public static final String WEBDRIVER_FACTORY = "jp.vmi.selenium.webdriver.factory";

    private static final WebDriverManager manager = new WebDriverManager();

    private boolean isSingleInstance = true;

    private WebDriverFactory factory;

    private DriverOptions driverOptions = new DriverOptions();

    private final Map driverMap = new HashMap();

    @Deprecated
    private final Map environmentVariables = new HashMap();

    /**
     * Get WebDriverManager instance. (singleton)
     *
     * @return WebDriverMangaer.
     */
    public static WebDriverManager getInstance() {
        return manager;
    }

    /**
     * Constructor.
     */
    private WebDriverManager() {
        String factoryName = System.getProperty(WEBDRIVER_FACTORY, FIREFOX);
        setWebDriverFactory(factoryName);
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                quitAllDrivers();
            }
        });
    }

    /**
     * Is single instance of WebDriver?
     *
     * @return true if
     */
    public boolean isSingleInstance() {
        return isSingleInstance;
    }

    /**
     * Set single instance of WebDriver.
     *
     * @param isSingleInstance if true, the number of WebDriver instance is only 1.
     */
    public void setSingleInstance(boolean isSingleInstance) {
        this.isSingleInstance = isSingleInstance;
    }

    /**
     * Set current WebDriverFactory.
     *
     * @param factory WebDriverFactory instance.
     */
    public void setWebDriverFactory(WebDriverFactory factory) {
        this.factory = factory;
    }

    /**
     * Set current WebDriverFactory name.
     *
     * @param factoryName WebDriverFactory name.
     */
    public void setWebDriverFactory(String factoryName) {
        WebDriverFactory factory = lookupWebDriverFactory(factoryName);
        setWebDriverFactory(factory);
    }

    /**
     * Lookup WebDriverFactory by name.
     *
     * @param factoryName WebDriverFactory name.
     *
     * @return WebDriverFactory instance.
     */
    public WebDriverFactory lookupWebDriverFactory(String factoryName) {
        if (StringUtils.isBlank(factoryName))
            factoryName = FIREFOX;
        else
            factoryName = factoryName.toLowerCase();
        WebDriverFactory factory;
        if (FIREFOX.equals(factoryName))
            factory = new FirefoxDriverFactory();
        else if (CHROME.equals(factoryName))
            factory = new ChromeDriverFactory();
        else if (IE.equals(factoryName))
            factory = new IEDriverFactory();
        else if (SAFARI.equals(factoryName))
            factory = new SafariDriverFactory();
        else if (HTMLUNIT.equals(factoryName))
            factory = new HtmlUnitDriverFactory();
        else if (REMOTE.equals(factoryName)) {
            factory = new RemoteWebDriverFactory();
        } else if (APPIUM.equals(factoryName)) {
            factory = new AppiumWebDriverFactory();
        } else if (PHANTOMJS.equals(factoryName)) {
            factory = new PhantomJSDriverFactory();
        } else {
            try {
                factory = (WebDriverFactory) Class.forName(factoryName).newInstance();
            } catch (Exception e) {
                throw new IllegalArgumentException("Invalid WebDriverFactory class name: " + factoryName, e);
            }
        }
        return factory;
    }

    /**
     * Get current driver options.
     *
     * @return DriverOptions instance.
     */
    public DriverOptions getDriverOptions() {
        return driverOptions;
    }

    /**
     * Set current driver options.
     *
     * @param driverOptions DriverOptions instance.
     */
    public void setDriverOptions(DriverOptions driverOptions) {
        this.driverOptions = driverOptions;
    }

    private String getDriverName(WebDriver driver) {
        String name = driver.getClass().getSimpleName();
        if (StringUtils.isNotBlank(name))
            return name;
        else
            return driver.getClass().getName();
    }

    /**
     * Get environment variable map.
     *
     * @return environment variable map.
     *
     * @deprecated use {@link DriverOptions#getEnvVars()}.
     */
    @Deprecated
    public Map getEnvironmentVariables() {
        return environmentVariables;
    }

    private boolean isBrowserUnreachable(Throwable t) {
        if (t instanceof UnreachableBrowserException)
            return true;
        while (t instanceof SeleniumException)
            t = t.getCause();
        if (t instanceof WebDriverException && StringUtils.contains(t.getMessage(), "not reachable"))
            return true;
        return false;
    }

    private boolean reprepare(WebDriver driver, String message) {
        try {
            driver.getWindowHandle();
            // ChromeDriver does not send UnreachableBrowserException.
            // TODO fix me when ChromeDriver is fixed.
            if (driver instanceof ChromeDriver)
                driver.getTitle();
            if (message != null)
                log.info(message);
            return true;
        } catch (NoSuchWindowException e) {
            log.info("No focused window.");
            Set handles = driver.getWindowHandles();
            if (!handles.isEmpty()) {
                log.info("Activate a window.");
                driver.switchTo().window(handles.iterator().next());
                return true;
            }
            log.warn("No window exists.");
        } catch (RuntimeException e) {
            if (!isBrowserUnreachable(e))
                throw e;
            log.warn("Browser might crash.");
        }
        try {
            driver.quit();
        } catch (Throwable e) {
            // no operation
        }
        return false;
    }

    private synchronized WebDriver get(Builder builder) throws IllegalArgumentException {
        String key = builder.getKey();
        Builder prevBuilder = driverMap.get(key);
        if (prevBuilder != null) {
            WebDriver driver = prevBuilder.driver;
            if (reprepare(driver, "Existing driver found."))
                return driver;
        }
        if (isSingleInstance)
            quitAllDrivers();
        driverMap.put(builder.getKey(), builder.build());
        log.info("Initialized: {}", getDriverName(builder.driver));
        return builder.driver;
    }

    @Override
    public WebDriver get() throws IllegalArgumentException {
        DriverOptions dopts = new DriverOptions(driverOptions);
        dopts.getEnvVars().putAll(environmentVariables); // for backward compaitibility.
        return get(new Builder(factory, dopts));
    }

    @Override
    public WebDriver reprepare(WebDriver driver) {
        if (reprepare(driver, null))
            return driver;
        for (Entry entry : driverMap.entrySet()) {
            Builder builder = entry.getValue();
            if (driver == builder.driver) {
                log.info("Restart driver.");
                return builder.build().driver;
            }
        }
        throw new IllegalArgumentException("The driver is not managed by WebDriverManager: " + driver);
    }

    /**
     * Quit all WebDriver instances.
     */
    public synchronized void quitAllDrivers() {
        for (Builder builder : driverMap.values()) {
            try {
                builder.driver.quit();
            } catch (Exception e) {
                log.warn(e.getMessage());
            } finally {
                log.info("Quit: {}", getDriverName(builder.driver));
            }
        }
        driverMap.clear();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy