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.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlTableCell; 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 getSuggestions(HtmlElement suggestion, int column) { final Map suggestions = new HashMap(); final HtmlElement suggestElement = suggestion.getElementById(suggestion.getId() + ":suggest"); @SuppressWarnings("unchecked") final DomNodeList suggestionRows = suggestElement.getElementsByTagName("tr"); for (HtmlElement row : suggestionRows) { @SuppressWarnings("unchecked") final DomNodeList 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 scripts = page.getElementsByTagName("script"); /** * We cannot iterate over html DomNodeList cause it depends on sibling relationship which we will modify. */ final List scriptsList = new ArrayList(); 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); } } } } }