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

org.specrunner.webdriver.impl.HtmlUnitDriverLocal Maven / Gradle / Ivy

There is a newer version: 1.5.17
Show newest version
/*
    SpecRunner - Acceptance Test Driven Development Tool
    Copyright (C) 2011-2016  Thiago Santos

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see 
 */
package org.specrunner.webdriver.impl;

import java.lang.reflect.Constructor;

import org.openqa.selenium.Capabilities;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.specrunner.SRServices;
import org.specrunner.features.IFeatureManager;
import org.specrunner.parameters.IParameterDecorator;
import org.specrunner.parameters.core.ParameterDecoratorImpl;
import org.specrunner.util.UtilLog;
import org.specrunner.webdriver.IHtmlUnitDriver;
import org.specrunner.webdriver.impl.htmlunit.IWebConnection;
import org.specrunner.webdriver.impl.htmlunit.OptimizedCssErrorHandler;
import org.specrunner.webdriver.impl.htmlunit.OptimizedIncorrectnessListener;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.Cache;
import com.gargoylesoftware.htmlunit.DefaultCredentialsProvider;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.ProxyConfig;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebConnection;
import com.gargoylesoftware.htmlunit.WebResponse;

/**
 * Implementation for HtmlUnitDriver which enable recovering WebClient instance
 * and other customizations like setting the connection handler.
 * 
 * @author Thiago Santos
 * 
 */
@SuppressWarnings("serial")
public class HtmlUnitDriverLocal extends HtmlUnitDriver implements IHtmlUnitDriver {

    /**
     * Parameter decorator.
     */
    private IParameterDecorator parameters;

    /**
     * Browser name.
     */
    private String name;

    /**
     * Feature to set host (for proxies).
     */
    public static final String FEATURE_HOST = HtmlUnitDriverLocal.class.getName() + ".host";
    /**
     * The host.
     */
    private String host;

    /**
     * Feature to set port (for proxies).
     */
    public static final String FEATURE_PORT = HtmlUnitDriverLocal.class.getName() + ".port";
    /**
     * The port.
     */
    private Integer port;

    /**
     * Feature to set user name, if the browser requires authentication.
     */
    public static final String FEATURE_USERNAME = HtmlUnitDriverLocal.class.getName() + ".username";
    /**
     * The username.
     */
    private String username;

    /**
     * Feature to set password, if the browser requires authentication.
     */
    public static final String FEATURE_PASSWORD = HtmlUnitDriverLocal.class.getName() + ".password";
    /**
     * The password.
     */
    private String password;

    /**
     * Set default browser http timeout.
     */
    public static final String FEATURE_HTTPTIMEOUT = HtmlUnitDriverLocal.class.getName() + ".httptimeout";
    /**
     * The browser http timeout. Default is '0'.
     */
    private Integer httptimeout = 0;

    /**
     * Feature to set browser connection type.
     */
    public static final String FEATURE_CONNECTION = HtmlUnitDriverLocal.class.getName() + ".connection";
    /**
     * IWebConnection type to be used.
     */
    private String connection;
    /**
     * Connection instance.
     */
    private Class connectionType;

    /**
     * Default browser cache (class name) setting feature.
     */
    public static final String FEATURE_CACHE = HtmlUnitDriverLocal.class.getName() + ".cache";
    /**
     * Cache cache class to be used.
     */
    private String cache;
    /**
     * Cache instance.
     */
    private Cache cacheInstance;

    /**
     * Feature to set browser cached option (true/false).
     */
    public static final String FEATURE_CACHED = HtmlUnitDriverLocal.class.getName() + ".cached";
    /**
     * The cache status. Default is 'true'.
     */
    private Boolean cached = true;

    /**
     * Default constructor.
     */
    public HtmlUnitDriverLocal() {
        super();
    }

    /**
     * Creates the client with JS enabled or not.
     * 
     * @param enableJavascript
     *            true, to enable java script, false, otherwise.
     */
    public HtmlUnitDriverLocal(boolean enableJavascript) {
        super(enableJavascript);
    }

    /**
     * Creates a client with a given version.
     * 
     * @param version
     *            The browser version.
     */
    public HtmlUnitDriverLocal(BrowserVersion version) {
        super(version);
    }

    /**
     * Creates a driver with preset capabilities.
     * 
     * @param capabilities
     *            The capabilities.
     */
    public HtmlUnitDriverLocal(Capabilities capabilities) {
        super(capabilities);
    }

    @Override
    public IParameterDecorator getParameters() {
        return parameters;
    }

    @Override
    public void setParameters(IParameterDecorator parameters) {
        this.parameters = parameters;
    }

    /**
     * Get browser name.
     * 
     * @return The name.
     */
    public String getName() {
        return name;
    }

    /**
     * Set browser name.
     * 
     * @param name
     *            A name.
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Gets the host for proxy settings. Default is null, to use a proxy set
     * 'host' an 'port' attributes.
     * 
     * @return The proxy host.
     */
    public String getHost() {
        return host;
    }

    /**
     * Sets the host.
     * 
     * @param host
     *            The host.
     */
    public void setHost(String host) {
        this.host = host;
    }

    /**
     * Gets the port for proxy settings. Default is null, to use a proxy set
     * 'host' and 'port' attributes.
     * 
     * @return The proxy port.
     */
    public Integer getPort() {
        return port;
    }

    /**
     * Sets the port.
     * 
     * @param port
     *            The port.
     */
    public void setPort(Integer port) {
        this.port = port;
    }

    /**
     * Gets username for authentication. Default is null, to use authentication
     * set 'username' and 'password' attributes.
     * 
     * @return The username.
     */
    public String getUsername() {
        return username;
    }

    /**
     * Sets the username.
     * 
     * @param username
     *            The username.
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * Gets the password for authentication. Default is null, to use
     * authentication set 'username' and 'password' attributes.
     * 
     * @return The password.
     */
    public String getPassword() {
        return password;
    }

    /**
     * Sets the password.
     * 
     * @param password
     *            The password.
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * Gets the default browser Http timeout. This timeout is passed to HtmlUnit
     * and it uses it as Socket connection time limitation. Default is '0',
     * which is infinite.
     * 
     * @return The timeout.
     */
    public Integer getHttptimeout() {
        return httptimeout;
    }

    /**
     * Sets the HTTP timeout.
     * 
     * @param httptimeout
     *            The timeout.
     */
    public void setHttptimeout(Integer httptimeout) {
        this.httptimeout = httptimeout;
    }

    /**
     * Gets the web connection type, valid values are classes which implements
     * com.gargoylesoftware.htmlunit.WebConnection. Default is
     * null.
     * 
     * @return The connection instance class.
     */
    public String getConnection() {
        return connection;
    }

    /**
     * Sets the connection class.
     * 
     * @param connection
     *            The connection.
     */
    public void setConnection(String connection) {
        this.connection = connection;
    }

    /**
     * Gets the cache type, valid values are classes which extend
     * com.gargoylesoftware.htmlunit.Cache. Default is null.
     * 
     * @return The cache class.
     */
    public String getCache() {
        return cache;
    }

    /**
     * Sets the cache class name.
     * 
     * @param cache
     *            The cache class name.
     */
    public void setCache(String cache) {
        this.cache = cache;
    }

    /**
     * Gets if the browser uses a cache strategy. Default is false, to enable
     * cache set 'cache' attribute to true.
     * 
     * @return The cache status.
     */
    public Boolean getCached() {
        return cached;
    }

    /**
     * Set cached version.
     * 
     * @param cached
     *            The cached status.
     */
    public void setCached(Boolean cached) {
        this.cached = cached;
    }

    @Override
    public WebClient getWebClient() {
        return super.getWebClient();
    }

    @Override
    protected WebClient modifyWebClient(WebClient client) {
        parameters = new ParameterDecoratorImpl();
        parameters.setDecorated(this);
        return client;
    }

    /**
     * Adds a header to the client.
     * 
     * @param name
     *            The header name.
     * @param value
     *            The header value.
     */
    public void setHeader(String name, String value) {
        getWebClient().addRequestHeader(name, value);
    }

    @Override
    public void initialize() {
        setFeatures();
        WebClient client = getWebClient();
        setBasic(client);
        setConnection(client);
        setProxy(client);
        setCredentials(client);
        setCache(client);
        setTime(client);
    }

    /**
     * Prepare features from attribute information.
     */
    protected void setFeatures() {
        IFeatureManager fm = SRServices.getFeatureManager();
        if (host == null) {
            fm.set(FEATURE_HOST, this);
        }
        if (port == null) {
            fm.set(FEATURE_PORT, this);
        }
        if (username == null) {
            fm.set(FEATURE_USERNAME, this);
        }
        if (password == null) {
            fm.set(FEATURE_PASSWORD, this);
        }
        fm.set(FEATURE_HTTPTIMEOUT, this);
        if (connection == null) {
            fm.set(FEATURE_CONNECTION, this);
        }
        if (cache == null) {
            fm.set(FEATURE_CACHE, this);
        }
        if (cached == null) {
            fm.set(FEATURE_CACHED, this);
        }
    }

    /**
     * Basic adjusts.
     * 
     * @param client
     *            A client.
     */
    protected void setBasic(WebClient client) {
        // ignore SSL.
        client.getOptions().setUseInsecureSSL(true);

        // synchronize Ajax calls
        client.setAjaxController(new NicelyResynchronizingAjaxController());

        // replace error handlers
        client.setCssErrorHandler(new OptimizedCssErrorHandler());
        client.setIncorrectnessListener(new OptimizedIncorrectnessListener());
    }

    /**
     * Set connection information.
     * 
     * @param client
     *            A client.
     */
    @SuppressWarnings("unchecked")
    protected void setConnection(WebClient client) {
        if (connection != null) {
            try {
                connectionType = (Class) Class.forName(connection);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("Connection class '" + connection + "' not found, or is not a subtype of " + WebConnection.class.getName() + ".", e);
            }
        }
        // change web connection
        if (connectionType != null) {
            WebConnection connectionInstance = null;
            try {
                Constructor constr = connectionType.getConstructor(WebClient.class);
                connectionInstance = constr.newInstance(client);
            } catch (Exception e) {
                try {
                    connectionInstance = connectionType.newInstance();
                } catch (Exception e1) {
                    throw new RuntimeException("Constructor with WebClient argument or empty not found for '" + connectionType + "'.", e);
                }
            }
            client.setWebConnection(connectionInstance);
        }
    }

    /**
     * Set proxy setup.
     * 
     * @param client
     *            A client.
     */
    protected void setProxy(WebClient client) {
        if (host != null && port != null) {
            ProxyConfig config = new ProxyConfig(host, port);
            if (UtilLog.LOG.isInfoEnabled()) {
                UtilLog.LOG.info("Browser named '" + getName() + "' proxy '" + host + ":" + port + "'.");
            }
            client.getOptions().setProxyConfig(config);
        }
    }

    /**
     * Set user credentials.
     * 
     * @param client
     *            A client.
     */
    protected void setCredentials(WebClient client) {
        if (username != null && password != null) {
            DefaultCredentialsProvider provider = new DefaultCredentialsProvider();
            provider.addCredentials(username, password);
            client.setCredentialsProvider(provider);
            if (UtilLog.LOG.isInfoEnabled()) {
                UtilLog.LOG.info("Browser named '" + getName() + "' credentials '" + username + "|" + password + "'.");
            }
        }
    }

    /**
     * Set cache handler.
     * 
     * @param client
     *            A client.
     */
    @SuppressWarnings("unchecked")
    protected void setCache(WebClient client) {
        if (cache != null) {
            try {
                Class cacheType = (Class) Class.forName(cache);
                cacheInstance = cacheType.newInstance();
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("Cache class '" + cache + "' not found, or is not a subtype of " + Cache.class.getName() + ".", e);
            } catch (Exception e) {
                throw new RuntimeException("Cache class '" + cache + "' instance could not be created.", e);
            }
        }
        if (cached || cacheInstance != null) {
            if (UtilLog.LOG.isInfoEnabled()) {
                UtilLog.LOG.info("Browser named '" + getName() + "' cached.");
            }
            Cache cacheLocal = null;
            if (cacheInstance == null) {
                if (UtilLog.LOG.isInfoEnabled()) {
                    UtilLog.LOG.info("Using default cache.");
                }
                cacheLocal = new Cache() {
                    @Override
                    protected boolean isCacheableContent(WebResponse response) {
                        String type = response.getContentType();
                        boolean dynamic = ("".equals(type) || "text/html".equals(type)) && !super.isCacheableContent(response);
                        if (UtilLog.LOG.isInfoEnabled()) {
                            String url = response.getWebRequest().getUrl().toString();
                            UtilLog.LOG.info("Dynamic '" + type + "' = " + dynamic + ", loaded in " + response.getLoadTime() + "mls, URL: " + url + ".");
                        }
                        return !dynamic;
                    }
                };
            } else {
                if (UtilLog.LOG.isInfoEnabled()) {
                    UtilLog.LOG.info("Using customized cache '" + cacheInstance.getClass() + "'.");
                }
                cacheLocal = cacheInstance;
            }
            client.setCache(cacheLocal);
        } else {
            if (UtilLog.LOG.isInfoEnabled()) {
                UtilLog.LOG.info("Browser named '" + getName() + "' not cached.");
            }
        }
    }

    /**
     * Set timeout information.
     * 
     * @param client
     *            A client.
     */
    protected void setTime(WebClient client) {
        client.getOptions().setTimeout(httptimeout);
        if (UtilLog.LOG.isInfoEnabled()) {
            UtilLog.LOG.info("Browser named '" + getName() + "' bound to '" + client + "'.");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy