Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.machinepublishers.jbrowserdriver.ElementServer Maven / Gradle / Ivy
/*
* jBrowserDriver (TM)
* Copyright (C) 2014-2016 Machine Publishers, LLC
*
* Sales and support: [email protected]
* Updates: https://github.com/MachinePublishers/jBrowserDriver
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.machinepublishers.jbrowserdriver;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.ElementNotVisibleException;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.internal.FindsByClassName;
import org.openqa.selenium.internal.FindsByCssSelector;
import org.openqa.selenium.internal.FindsById;
import org.openqa.selenium.internal.FindsByLinkText;
import org.openqa.selenium.internal.FindsByName;
import org.openqa.selenium.internal.FindsByTagName;
import org.openqa.selenium.internal.FindsByXPath;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.html.HTMLFormElement;
import org.w3c.dom.html.HTMLInputElement;
import org.w3c.dom.html.HTMLOptionElement;
import com.machinepublishers.jbrowserdriver.AppThread.Sync;
import com.machinepublishers.jbrowserdriver.Robot.MouseButton;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
class ElementServer extends RemoteObject implements ElementRemote, WebElement,
JavascriptExecutor, FindsById, FindsByClassName, FindsByLinkText, FindsByName,
FindsByCssSelector, FindsByTagName, FindsByXPath {
private static final String IS_VISIBLE;
static {
StringBuilder builder = new StringBuilder();
builder.append("var me = this;");
builder.append("(function(){");
//The following JavaScript is Copyright 2011-2015 Software Freedom Conservancy and Copyright 2004-2011 Selenium committers.
//Adapted and modified from https://github.com/SeleniumHQ/selenium/blob/master/javascript/selenium-core/scripts/selenium-api.js
builder.append("var findEffectiveStyle = function(element) {");
builder.append(" if (element.style == undefined) {");
builder.append(" return undefined;");
builder.append(" }");
builder.append(" if (window.getComputedStyle) {");
builder.append(" return window.getComputedStyle(element, null);");
builder.append(" }");
builder.append(" if (element.currentStyle) {");
builder.append(" return element.currentStyle;");
builder.append(" }");
builder.append(" if (window.document.defaultView && window.document.defaultView.getComputedStyle) {");
builder.append(" return window.document.defaultView.getComputedStyle(element, null);");
builder.append(" }");
builder.append(" return undefined;");
builder.append("};");
builder.append("var findEffectiveStyleProperty = function(element, property) {");
builder.append(" var effectiveStyle = findEffectiveStyle(element);");
builder.append(" var propertyValue = effectiveStyle[property];");
builder.append(" if (propertyValue == 'inherit' && element.parentNode.style) {");
builder.append(" return findEffectiveStyleProperty(element.parentNode, property);");
builder.append(" }");
builder.append(" return propertyValue;");
builder.append("};");
builder.append("var isDisplayed = function(element) {");
builder.append(" var display = findEffectiveStyleProperty(element, \"display\");");
builder.append(" if (display == \"none\") return false;");
builder.append(" if (element.parentNode.style) {");
builder.append(" return isDisplayed(element.parentNode);");
builder.append(" }");
builder.append(" return true;");
builder.append("};");
builder.append("var isVisible = function(element) {");
builder.append(" if (element.tagName) {");
builder.append(" var tagName = new String(element.tagName).toLowerCase();");
builder.append(" if (tagName == \"input\") {");
builder.append(" if (element.type) {");
builder.append(" var elementType = new String(element.type).toLowerCase();");
builder.append(" if (elementType == \"hidden\") {");
builder.append(" return false;");
builder.append(" }");
builder.append(" }");
builder.append(" }");
builder.append(" }");
builder.append(" var visibility = findEffectiveStyleProperty(element, \"visibility\");");
builder.append(" return (visibility != \"hidden\" && isDisplayed(element));");
builder.append("};");
builder.append("return isVisible(me);");
builder.append("})();");
IS_VISIBLE = builder.toString();
}
private static final Pattern rgb = Pattern.compile(
"rgb\\(([0-9]{1,3}), ([0-9]{1,3}), ([0-9]{1,3})\\)");
private static final Map map = new HashMap();
private final JSObject node;
private final Context context;
private final AtomicLong frameId = new AtomicLong();
ElementServer(final JSObject node, final Context context) throws RemoteException {
AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Object perform() {
validate(node, context.item());
node.getMember("");
return null;
}
});
this.node = node;
this.context = context;
}
JSObject node() {
return node;
}
void setFrameId(long frameId) {
this.frameId.set(frameId);
}
long frameId() {
return frameId.get();
}
static ElementServer create(final Context context) {
final JSObject doc = AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public JSObject perform() {
JSObject node;
ElementServer selectedFrame = context.item().selectedFrame();
if (selectedFrame == null) {
node = (JSObject) context.item().engine.get().getDocument();
} else {
node = selectedFrame.node;
}
return node;
}
});
try {
return new ElementServer(doc, context);
} catch (RemoteException e) {
Util.handleException(e);
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public void activate() {
context.item().selectFrame(this);
}
/**
* {@inheritDoc}
*/
@Override
public void scriptParam(ElementId id) {
synchronized (map) {
map.put(id, this);
}
}
private static void validate(JSObject node, ContextItem contextItem) {
if (node == null) {
throw new NoSuchElementException("Element not found or does not exist.");
}
JSObject doc = node instanceof Document ? node : (JSObject) ((Node) node).getOwnerDocument();
if (!contextItem.containsFrame(doc)) {
throw new StaleElementReferenceException("The page containing the element no longer exists.");
}
if (!(Boolean) doc.call("contains", node)) {
throw new StaleElementReferenceException("The element no longer exists within the page.");
}
}
private void validate(boolean mustBeVisible) {
validate(node, context.item());
if (mustBeVisible && !isDisplayed()) {
throw new ElementNotVisibleException("Element is not visible.");
}
}
/**
* {@inheritDoc}
*/
@Override
public void click() {
AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Object perform() {
validate(false);
node.call("scrollIntoView");
if (context.keyboard.get().isShiftPressed()) {
node.eval(
new StringBuilder()
.append("this.origOnclick = this.onclick;")
.append("this.onclick=function(event){")
.append(" this.target='_blank';")
.append(" if(event){")
.append(" if(event.stopPropagation){")
.append(" event.stopPropagation();")
.append(" }")
.append(" }")
.append(" if(this.origOnclick){")
.append(" this.origOnclick(event? event: null);")
.append(" }")
.append(" this.onclick = this.origOnclick;")
.append("};").toString());
}
return null;
}
});
if (node instanceof HTMLOptionElement) {
AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Object perform() {
validate(false);
try {
new ElementServer((JSObject) ((HTMLOptionElement) node).getParentNode(), context).click();
} catch (RemoteException e) {
Util.handleException(e);
}
int index = ((HTMLOptionElement) node).getIndex();
for (int i = 0; i <= index; i++) {
context.robot.get().keysType(Keys.DOWN);
}
context.robot.get().keysType(Keys.SPACE);
return null;
}
});
} else {
AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Object perform() {
validate(true);
final JSObject obj = (JSObject) node.call("getBoundingClientRect");
final double top = Double.parseDouble(obj.getMember("top").toString());
final double left = Double.parseDouble(obj.getMember("left").toString());
final double bottom = Double.parseDouble(obj.getMember("bottom").toString());
final double right = Double.parseDouble(obj.getMember("right").toString());
double clickX = (left + right) / 2d;
double clickY = (top + bottom) / 2d;
ElementServer doc = ElementServer.create(context);
if (!node.equals(doc.node.eval(
"(function(){return document.elementFromPoint(" + clickX + "," + clickY + ");})();"))) {
final Stage stage = context.item().stage.get();
final int minX = Math.max(0, (int) Math.floor(left));
final int maxX = Math.min((int) Math.ceil(stage.getScene().getWidth()), (int) Math.ceil(right));
final int minY = Math.max(0, (int) Math.floor(top));
final int maxY = Math.min((int) Math.ceil(stage.getScene().getHeight()), (int) Math.ceil(bottom));
final int incX = (int) Math.max(1, .05d * (double) (maxX - minX));
final int incY = (int) Math.max(1, .05d * (double) (maxY - minY));
for (int x = minX; x <= maxX; x += incX) {
boolean found = false;
for (int y = minY; y <= maxY; y += incY) {
if (node.equals(doc.node.eval(
"(function(){return document.elementFromPoint(" + x + "," + y + ");})();"))) {
clickX = x;
clickY = y;
found = true;
break;
}
}
if (found) {
break;
}
}
}
final org.openqa.selenium.Point frameLocation = context.item().selectedFrameLocation();
context.robot.get().mouseMove(clickX + frameLocation.getX(), clickY + frameLocation.getY());
context.robot.get().mouseClick(MouseButton.LEFT);
return null;
}
});
}
}
/**
* {@inheritDoc}
*/
@Override
public void submit() {
AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Object perform() {
validate(false);
context.item().httpListener.get().resetStatusCode();
if (node instanceof HTMLInputElement) {
((HTMLInputElement) node).getForm().submit();
} else if (node instanceof HTMLFormElement) {
((HTMLFormElement) node).submit();
}
return null;
}
});
}
/**
* {@inheritDoc}
*/
@Override
public void sendKeys(final CharSequence... keys) {
AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Object perform() {
validate(true);
node.call("scrollIntoView");
node.call("focus");
return null;
}
});
final boolean fileChooser = node instanceof HTMLInputElement && "file".equalsIgnoreCase(getAttribute("type"));
if (fileChooser) {
click();
}
context.robot.get().keysType(keys);
if (fileChooser) {
context.robot.get().typeEnter();
}
}
/**
* {@inheritDoc}
*/
@Override
public void clear() {
AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Object perform() {
validate(false);
context.item().httpListener.get().resetStatusCode();
node.call("scrollIntoView");
node.call("focus");
node.eval("this.value='';");
return null;
}
});
}
/**
* {@inheritDoc}
*/
@Override
public String getAttribute(final String attrName) {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public String perform() {
validate(false);
Object obj = node.getMember(attrName);
if (obj != null) {
String str = obj.toString();
if (!StringUtils.isEmpty(str) && !"undefined".equals(str)) {
return str;
}
}
obj = executeScript(new StringBuilder()
.append("return this.getAttribute('").append(attrName).append("');").toString());
if (obj != null) {
String str = obj.toString();
if (!StringUtils.isEmpty(str)) {
return str;
}
}
return null;
}
});
}
/**
* {@inheritDoc}
*/
@Override
public String getCssValue(final String name) {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public String perform() {
validate(false);
return cleanUpCssVal((String) (node.eval(new StringBuilder()
.append("var me = this;")
.append("(function(){")
.append(" return window.getComputedStyle(me).getPropertyValue('")
.append(name)
.append("');")
.append("})();").toString())));
}
});
}
private static String cleanUpCssVal(String rgbStr) {
if (rgbStr != null) {
Matcher matcher = rgb.matcher(rgbStr);
if (matcher.matches()) {
return new StringBuilder().append("rgba(").append(matcher.group(1)).append(", ")
.append(matcher.group(2)).append(", ").append(matcher.group(3)).append(", 1)").toString();
}
}
return rgbStr == null ? "" : rgbStr;
}
/**
* {@inheritDoc}
*/
@Override
public Point remoteGetLocation() {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Point perform() {
validate(true);
JSObject obj = (JSObject) node.call("getBoundingClientRect");
int y = (int) Math.rint(Double.parseDouble(obj.getMember("top").toString()));
int x = (int) Math.rint(Double.parseDouble(obj.getMember("left").toString()));
return new Point(x + 1, y + 1);
}
});
}
/**
* {@inheritDoc}
*/
@Override
public org.openqa.selenium.Point getLocation() {
return remoteGetLocation().toSelenium();
}
/**
* {@inheritDoc}
*/
@Override
public Dimension remoteGetSize() {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Dimension perform() {
validate(true);
JSObject obj = (JSObject) node.call("getBoundingClientRect");
int y = (int) Math.rint(Double.parseDouble(obj.getMember("top").toString()));
int y2 = (int) Math.rint(Double.parseDouble(obj.getMember("bottom").toString()));
int x = (int) Math.rint(Double.parseDouble(obj.getMember("left").toString()));
int x2 = (int) Math.rint(Double.parseDouble(obj.getMember("right").toString()));
return new Dimension(x2 - x, y2 - y);
}
});
}
/**
* {@inheritDoc}
*/
@Override
public org.openqa.selenium.Dimension getSize() {
return remoteGetSize().toSelenium();
}
/**
* {@inheritDoc}
*/
@Override
public Rectangle remoteGetRect() {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Rectangle perform() {
validate(true);
JSObject obj = (JSObject) node.call("getBoundingClientRect");
int y = (int) Math.rint(Double.parseDouble(obj.getMember("top").toString()));
int y2 = (int) Math.rint(Double.parseDouble(obj.getMember("bottom").toString()));
int x = (int) Math.rint(Double.parseDouble(obj.getMember("left").toString()));
int x2 = (int) Math.rint(Double.parseDouble(obj.getMember("right").toString()));
return new Rectangle(x + 1, y + 1, y2 - y, x2 - x);
}
});
}
/**
* {@inheritDoc}
*/
@Override
public org.openqa.selenium.Rectangle getRect() {
return remoteGetRect().toSelenium();
}
/**
* {@inheritDoc}
*/
@Override
public String getTagName() {
return getAttribute("tagName").toLowerCase();
}
/**
* {@inheritDoc}
*/
@Override
public String getText() {
return AppThread.exec(context.statusCode,
new Sync() {
@Override
public String perform() {
validate(false);
if ((Boolean) node.eval(IS_VISIBLE)) {
Object text = node.getMember("innerText");
return text instanceof String ? ((String) text).trim() : "";
}
return "";
}
});
}
/**
* {@inheritDoc}
*/
@Override
public boolean isDisplayed() {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Boolean perform() {
validate(false);
return (Boolean) node.eval(IS_VISIBLE);
}
});
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEnabled() {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Boolean perform() {
validate(false);
String val = node.getMember("disabled").toString();
return val == null || "undefined".equals(val) || val.isEmpty() || "false".equals(val);
}
});
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSelected() {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Boolean perform() {
validate(false);
String selected = node.getMember("selected").toString();
String checked = node.getMember("checked").toString();
return (selected != null && !"undefined".equals(selected) && !"false".equals(selected) && !selected.isEmpty())
|| (checked != null && !"undefined".equals(checked) && !"false".equals(checked) && !checked.isEmpty());
}
});
}
/**
* {@inheritDoc}
*/
@Override
public ElementServer findElement(By by) {
return (ElementServer) by.findElement(this);
}
/**
* {@inheritDoc}
*/
@Override
public List findElements(By by) {
return by.findElements(this);
}
/**
* {@inheritDoc}
*/
@Override
public ElementServer findElementByXPath(final String expr) {
List list = findElementsByXPath(expr);
return list.isEmpty() ? null : (ElementServer) list.get(0);
}
/**
* {@inheritDoc}
*/
@Override
public List findElementsByXPath(final String expr) {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync>() {
@Override
public List perform() {
validate(false);
return asList(executeScript(new StringBuilder()
.append("var iter = ")
.append(" document.evaluate(arguments[0], arguments[1], null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);")
.append("var items = [];")
.append("var cur = null;")
.append("while(cur = iter.iterateNext()){")
.append(" items.push(cur);")
.append("}")
.append("return items;").toString(), expr, node));
}
});
}
/**
* {@inheritDoc}
*/
@Override
public ElementServer findElementByTagName(String tagName) {
List list = byTagName(tagName);
return list == null || list.isEmpty() ? null : list.get(0);
}
/**
* {@inheritDoc}
*/
@Override
public List findElementsByTagName(String tagName) {
return byTagName(tagName);
}
private List byTagName(final String tagName) {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync>() {
@Override
public List perform() {
validate(false);
if (node != null) {
return asList(parseScriptResult(
node.call("getElementsByTagName", new Object[] { tagName })));
}
return new ArrayList();
}
});
}
/**
* {@inheritDoc}
*/
@Override
public ElementServer findElementByCssSelector(final String expr) {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public ElementServer perform() {
validate(false);
JSObject result = (JSObject) node.call("querySelector", new Object[] { expr });
if (result == null) {
return null;
}
try {
return new ElementServer(result, context);
} catch (RemoteException e) {
Util.handleException(e);
return null;
}
}
});
}
/**
* {@inheritDoc}
*/
@Override
public List findElementsByCssSelector(final String expr) {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync>() {
@Override
public List perform() {
validate(false);
List elements = new ArrayList();
JSObject result = (JSObject) node.call("querySelectorAll", new Object[] { expr });
for (int i = 0;; i++) {
Object cur = result.getSlot(i);
if (cur instanceof Node) {
try {
elements.add(new ElementServer((JSObject) cur, context));
} catch (RemoteException e) {
Util.handleException(e);
}
} else {
break;
}
}
return elements;
}
});
}
/**
* {@inheritDoc}
*/
@Override
public ElementServer findElementByName(String name) {
return findElementByCssSelector(new StringBuilder().append("*[name='").append(name).append("']").toString());
}
/**
* {@inheritDoc}
*/
@Override
public List findElementsByName(String name) {
return findElementsByCssSelector(new StringBuilder().append("*[name='").append(name).append("']").toString());
}
/**
* {@inheritDoc}
*/
@Override
public ElementServer findElementByLinkText(final String text) {
List list = byLinkText(text, false, false);
return list.isEmpty() ? null : list.get(0);
}
/**
* {@inheritDoc}
*/
@Override
public ElementServer findElementByPartialLinkText(String text) {
List list = byLinkText(text, false, true);
return list.isEmpty() ? null : list.get(0);
}
/**
* {@inheritDoc}
*/
@Override
public List findElementsByLinkText(String text) {
return byLinkText(text, true, false);
}
/**
* {@inheritDoc}
*/
@Override
public List findElementsByPartialLinkText(String text) {
return byLinkText(text, true, true);
}
private List byLinkText(final String text,
final boolean multiple, final boolean partial) {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync>() {
@Override
public List perform() {
validate(false);
List elements = new ArrayList();
List nodes = (List) findElementsByTagName("a");
for (ElementServer cur : nodes) {
String curText = cur.getText();
if (curText == null) {
continue;
}
if ((partial && curText.contains(text))
|| (!partial && curText.equals(text))) {
elements.add(cur);
if (!multiple) {
break;
}
}
}
return elements;
}
});
}
/**
* {@inheritDoc}
*/
@Override
public ElementServer findElementByClassName(String cssClass) {
List list = byCssClass(cssClass);
return list.isEmpty() ? null : list.get(0);
}
/**
* {@inheritDoc}
*/
@Override
public List findElementsByClassName(String cssClass) {
return byCssClass(cssClass);
}
private List byCssClass(String cssClass) {
return asList(executeScript(
new StringBuilder().append("return this.getElementsByClassName('").append(cssClass).append("');").toString()));
}
/**
* {@inheritDoc}
*/
@Override
public ElementServer findElementById(final String id) {
return findElementByCssSelector(new StringBuilder("*[id='").append(id).append("']").toString());
}
/**
* {@inheritDoc}
*/
@Override
public List findElementsById(String id) {
return findElementsByCssSelector(new StringBuilder().append("*[id='").append(id).append("']").toString());
}
/**
* {@inheritDoc}
*/
@Override
public Object executeAsyncScript(final String script, final Object... args) {
final JavascriptNames jsNames = new JavascriptNames();
script(true, script, args, jsNames);
int sleep = 1;
final int sleepBackoff = 2;
final int sleepMax = 500;
while (true) {
sleep = sleep < sleepMax ? sleep * sleepBackoff : sleep;
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {}
Object result = AppThread.exec(
context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Object perform() {
validate(false);
try {
return node.eval(new StringBuilder()
.append("(function(){return this.")
.append(jsNames.callbackVal)
.append(";})();").toString());
} finally {
node.eval(new StringBuilder()
.append("delete ")
.append(jsNames.callbackVal)
.append(";").toString());
}
}
});
if (!(result instanceof String) || !"undefined".equals(result.toString())) {
Object parsed = parseScriptResult(result);
if (parsed instanceof List) {
if (((List) parsed).size() == 0) {
return null;
}
if (((List) parsed).size() == 1) {
return ((List) parsed).get(0);
}
}
return parsed;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public Object executeScript(final String script, final Object... args) {
return script(false, script, args, new JavascriptNames());
}
private static List asList(Object objToCast) {
try {
return (List) objToCast;
} catch (ClassCastException e) {
return new ArrayList();
}
}
private static class JavascriptNames {
private final String callbackVal = Util.randomPropertyName();
private final String callback = Util.randomPropertyName();
private final String exec = Util.randomPropertyName();
}
private Object script(boolean callback, String script, Object[] args, final JavascriptNames jsNames) {
for (int i = 0; args != null && i < args.length; i++) {
if (args[i] instanceof ElementId) {
synchronized (map) {
args[i] = ((ElementServer) map.remove(args[i])).node;
}
}
}
return parseScriptResult(AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Object perform() {
validate(false);
List argList = new ArrayList();
if (args != null) {
argList.addAll(Arrays.asList(args));
}
try {
if (callback) {
argList.add(null);
node.eval(new StringBuilder().append("(function(){")
.append("this.").append(jsNames.callback).append(" = function(){")
.append(jsNames.callbackVal).append(" = arguments && arguments.length > 0? arguments[0] : null;")
.append("}")
.append("}).apply(this);")
.append("this.").append(jsNames.exec).append(" = function(){")
.append("arguments[arguments.length-1] = this.").append(jsNames.callback).append(";")
.append("return (function(){").append(script).append("}).apply(this, arguments);")
.append("};").toString());
} else {
node.eval(new StringBuilder().append("this.").append(jsNames.exec).append(" = function(){")
.append("return (function(){").append(script).append("}).apply(this, arguments);")
.append("};").toString());
}
return node.call(jsNames.exec, argList.toArray(new Object[0]));
} catch (Throwable t) {
return t;
} finally {
node.eval(new StringBuilder().append("delete ").append("this.").append(jsNames.exec).append(";").toString());
if (callback) {
node.eval(new StringBuilder().append("delete ").append("this.").append(jsNames.callback).append(";").toString());
}
}
}
}));
}
private Object parseScriptResult(final Object obj) {
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Object perform() {
validate(false);
AppThread.handleExecutionException(obj);
if (obj == null || (obj instanceof String && "undefined".equals(obj.toString()))) {
return null;
}
if (obj instanceof Node) {
try {
return new ElementServer((JSObject) obj, context);
} catch (RemoteException e) {
Util.handleException(e);
return null;
}
}
if (obj instanceof JSObject) {
List list = new ArrayList();
boolean isList = false;
for (int i = 0;; i++) {
Object cur = ((JSObject) obj).getSlot(i);
if (cur instanceof String && "undefined".equals(cur.toString())) {
break;
}
isList = true;
list.add(parseScriptResult(cur));
}
if (isList) {
return list;
}
if ("function".equals(executeScript("return typeof arguments[0];", obj))) {
return obj.toString();
}
if (Boolean.TRUE.equals(executeScript("return Array.isArray(arguments[0]);", obj))) {
return new ArrayList();
}
List mapAsList = (List) executeScript(new StringBuilder()
.append("var list = [];")
.append("for(var propertyName in arguments[0]){")
.append("list.push(propertyName);")
.append("var val = arguments[0][propertyName];")
.append("list.push(val === undefined? null : val);")
.append("}")
.append("return list.length > 0? list : undefined;").toString(),
obj);
//TODO ES6 will support Symbol keys
Map map = new LinkedHashMap();
for (int i = 0; mapAsList != null && i < mapAsList.size(); i += 2) {
map.put(mapAsList.get(i).toString(), mapAsList.get(i + 1));
}
return map;
}
if (obj instanceof Boolean || obj instanceof Long || obj instanceof Double) {
return obj;
}
if (obj instanceof Integer) {
return new Long((Integer) obj);
}
if (obj instanceof Float) {
return new Double((Float) obj);
}
return obj.toString();
}
});
}
/**
* {@inheritDoc}
*/
@Override
public Point locate() {
AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Point perform() {
validate(false);
node.call("scrollIntoView");
return null;
}
});
return AppThread.exec(context.statusCode, context.timeouts.get().getScriptTimeoutMS(),
new Sync() {
@Override
public Point perform() {
validate(true);
JSObject obj = (JSObject) node.call("getBoundingClientRect");
double y = Double.parseDouble(obj.getMember("top").toString());
double x = Double.parseDouble(obj.getMember("left").toString());
y = y < 0d ? 0d : y;
x = x < 0d ? 0d : x;
final org.openqa.selenium.Point frameLocation = context.item().selectedFrameLocation();
return new Point((int) Math.rint(x) + 1 + frameLocation.getX(),
(int) Math.rint(y) + 1 + frameLocation.getY());
}
});
}
/**
* {@inheritDoc}
*/
@Override
public X getScreenshotAs(OutputType arg0) throws WebDriverException {
LogsServer.instance().warn("Screenshot not supported on jBrowserDriver WebElements");
return null;
}
/**
* {@inheritDoc}
*/
@Override
public byte[] getScreenshot() throws WebDriverException {
LogsServer.instance().warn("Screenshot not supported on jBrowserDriver WebElements");
return null;
}
/**
* {@inheritDoc}
*/
@Override
public int remoteHashCode() {
return AppThread.exec(
context.statusCode,
new Sync() {
@Override
public Integer perform() {
validate(false);
return node.hashCode();
}
});
}
/**
* {@inheritDoc}
*/
@Override
public boolean remoteEquals(ElementId id) {
return AppThread.exec(
context.statusCode,
new Sync() {
@Override
public Boolean perform() {
validate(false);
ElementServer other;
synchronized (map) {
other = map.remove(id);
}
other.validate(false);
return node.equals(other.node);
}
});
}
}