WebClientUtils.java 7.57 KB
package pl.labno.bernard.htmlunified;

import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomNode;
import com.gargoylesoftware.htmlunit.html.DomNodeList;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSpan;
import com.gargoylesoftware.htmlunit.html.HtmlTable;
import com.gargoylesoftware.htmlunit.html.HtmlTableCell;
import com.gargoylesoftware.htmlunit.html.HtmlTableRow;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class WebClientUtils {

    private static long defaultCheckInterval = 500;
    private static long defaultTimeout = 10000;

    public static long getDefaultCheckInterval() {
        return defaultCheckInterval;
    }

    public static void setDefaultCheckInterval(long defaultCheckInterval) {
        WebClientUtils.defaultCheckInterval = defaultCheckInterval;
    }

    public static long getDefaultTimeout() {
        return defaultTimeout;
    }

    public static void setDefaultTimeout(long defaultTimeout) {
        WebClientUtils.defaultTimeout = defaultTimeout;
    }

    public static int waitForJSJob(String message, WebClient webClient) {
        return waitForJSJob(message, webClient, webClient.waitForBackgroundJavaScript(10) - 1);
    }

    public static int waitForJSJob(String message, WebClient webClient, int initialJobCount) {
        return waitForJSJob(message, webClient, initialJobCount, defaultTimeout);
    }

    public static int waitForJSJob(WebClient webClient, int initialJobCount, int timeout) {
        return waitForJSJob(null, webClient, initialJobCount, timeout);
    }

    public static int waitForJSJob(String message, WebClient webClient, int initialJobCount, long timeout) {
        return waitForJSJob(message, webClient, initialJobCount, timeout, defaultCheckInterval);
    }

    public static int waitForJSJob(String message, WebClient webClient, int initialJobCount, int timeout) {
        return waitForJSJob(message, webClient, initialJobCount, timeout, defaultCheckInterval);
    }

    public static int waitForJSJob(String message, WebClient webClient, int initialJobCount, long timeout, long checkInterval) {
        int jobs;
        long startTime = System.currentTimeMillis();
        do {
            jobs = webClient.waitForBackgroundJavaScript(checkInterval);
            if (startTime + timeout < System.currentTimeMillis()) {
                throw new RuntimeException("Number of JavaScript jobs doesn't drop to initial level for " + timeout + " seconds. It's memory leak in your JavaScript rather then request taking so long!");
            }
        } while (jobs > initialJobCount);
        System.out.println("Waiting" + (message == null ? "" : " for " + message) + " took: " + (System.currentTimeMillis() - startTime) + "ms");
        return jobs;
    }

    /**
     * Returns list of suggestions from rich:suggestionBox
     *
     * @param suggestion suggestionBox element
     * @param column     column of suggestionBox to extract text from
     * @return list of suggestions
     */
    public static Map<String, HtmlTableCell> getSuggestions(HtmlElement suggestion, int column) {
        final Map<String, HtmlTableCell> suggestions = new HashMap<String, HtmlTableCell>();
        final HtmlElement suggestElement = suggestion.getElementById(suggestion.getId() + ":suggest");
        @SuppressWarnings("unchecked")
        final DomNodeList<HtmlElement> suggestionRows = suggestElement.getElementsByTagName("tr");
        for (HtmlElement row : suggestionRows) {
            if (!row.getId().endsWith("NothingLabel")) {
                @SuppressWarnings("unchecked")
                final DomNodeList<HtmlElement> cells = row.getElementsByTagName("td");
                final HtmlTableCell cell = (HtmlTableCell) cells.get(column + 1);
                suggestions.put(cell.asText(), cell);
            }
        }
        return suggestions;
    }

    public static void forceWait(int timeout) {
        final long startTime = System.currentTimeMillis();
        do {
            try {
                final long millis = startTime + timeout - System.currentTimeMillis();
                if (millis > 0) {
                    Thread.sleep(millis);
                }
            } catch (InterruptedException ignore) {
            } catch (IllegalArgumentException ignore) {
            }
        } while (startTime + timeout > System.currentTimeMillis());
    }

    public static void executeAjaxReRenderedScripts(HtmlPage page) {
        final DomNodeList<HtmlElement> scripts = page.getElementsByTagName("script");
        /**
         * We cannot iterate over html DomNodeList cause it depends on sibling relationship which we will modify.
         */
        final List<HtmlElement> scriptsList = new ArrayList<HtmlElement>();
        for (HtmlElement element : scripts) {
            scriptsList.add(element);
        }
        for (HtmlElement element : scriptsList) {
            if (element.getChildNodes().size() > 1) {
                element.removeChild(element.getFirstChild());
                final DomNode sibling = element.getNextSibling();
                final DomNode parentNode = element.getParentNode();
                /**
                 * Script will be executed upon inserting into DOM tree, so we removed and add it again.
                 */
                if (sibling != null) {
                    parentNode.removeChild(element);
                    sibling.insertBefore(element);
                } else {
                    parentNode.removeChild(element);
                    parentNode.appendChild(element);
                }
            }
        }
    }

    public static void setColorPickerValue(WebClient webClient, HtmlElement colorPicker, String hex) throws IOException {
        HtmlPage page = (HtmlPage) webClient.getCurrentWindow().getEnclosedPage();
        colorPicker.click();
        ((HtmlInput) page.getElementById(colorPicker.getId() + "-colorPicker-hex")).setValueAttribute(hex);
        page.getElementById(colorPicker.getId() + "-colorPicker-popup").getHtmlElementsByTagName("button").get(0).click();
    }

    public static void setColorPickerValue(WebClient webClient, HtmlElement colorPicker, int red, int green, int blue) throws IOException {
        HtmlPage page = (HtmlPage) webClient.getCurrentWindow().getEnclosedPage();
        colorPicker.click();
        ((HtmlInput) page.getElementById(colorPicker.getId() + "-colorPicker-rgb-r")).setValueAttribute(Integer.toString(red));
        ((HtmlInput) page.getElementById(colorPicker.getId() + "-colorPicker-rgb-g")).setValueAttribute(Integer.toString(green));
        ((HtmlInput) page.getElementById(colorPicker.getId() + "-colorPicker-rgb-b")).setValueAttribute(Integer.toString(blue));
        page.getElementById(colorPicker.getId() + "-colorPicker-popup").getHtmlElementsByTagName("button").get(0).click();
    }

    @SuppressWarnings("unchecked")
    public static List<HtmlTableRow> getTableRows(HtmlTable table) {
        return (List<HtmlTableRow>) table.getByXPath(".//*[contains(@class,'rich-table-row')]");
    }

    @SuppressWarnings("unchecked")
    public static List<String> getScheduleEventTitles(HtmlElement schedule) {
        final List<HtmlSpan> titleElements = (List<HtmlSpan>) schedule.getByXPath(".//*[@class='fc-event-title']");
        List<String> titles = new ArrayList<String>(titleElements.size());
        for (HtmlSpan o : titleElements) {
            titles.add(o.asText());
        }
        return titles;
    }
}