Java tutorial
/** * The MIT License * Copyright 2017 WebFolder O * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package io.webfolder.cdp.session; import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import static java.lang.String.format; import static java.lang.String.valueOf; import static java.util.Arrays.asList; import java.util.ArrayList; import java.util.List; import java.util.StringJoiner; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import io.webfolder.cdp.command.Runtime; import io.webfolder.cdp.exception.CdpException; import io.webfolder.cdp.type.constant.ObjectType; import io.webfolder.cdp.type.runtime.CallArgument; import io.webfolder.cdp.type.runtime.CallFunctionOnResult; import io.webfolder.cdp.type.runtime.EvaluateResult; import io.webfolder.cdp.type.runtime.RemoteObject; public interface JavaScript { /** * Evaluates JavaScript expression in global scope. * * @param expression JavaScript expression * * @return execution result */ default Object evaluate(String expression) { Runtime runtime = getThis().getCommand().getRuntime(); EvaluateResult result = runtime.evaluate(expression, null, null, null, null, null, null, null, null); if (result == null) { return null; } RemoteObject remoteObject = result.getResult(); if (remoteObject == null) { return null; } String objectId = result.getResult().getObjectId(); if (objectId != null) { getThis().releaseObject(objectId); } Object value = remoteObject.getValue(); getThis().logExit("evaluate", expression, value); return value; } /** * Calls JavaScript function. * * <p> * Function must be declared at the global {@literal (window object)} scope. * You can use <strong>dot notation</strong> for function name. * </p> * * @param name function name */ default void callFunction(String name) { callFunction(name, void.class, Constant.EMPTY_ARGS); } default <T> T callFunction(String name, Class<T> returnType) { return callFunction(name, returnType, Constant.EMPTY_ARGS); } /** * Calls JavaScript function. * * <p> * Function must be declared at the global {@literal (window object)} scope. * You can use <strong>dot notation</strong> for function name. * </p> * * @param name function name * @param returnType return type of function * @param arguments function arguments * * @return function result */ @SuppressWarnings("unchecked") default <T> T callFunction(String name, Class<T> returnType, Object... arguments) { EvaluateResult windowResult = getThis().getCommand().getRuntime().evaluate("window"); if (windowResult == null) { return null; } if (windowResult.getExceptionDetails() != null && windowResult.getExceptionDetails().getException() != null) { getThis().releaseObject(windowResult.getExceptionDetails().getException().getObjectId()); throw new CdpException(windowResult.getExceptionDetails().getException().getDescription()); } CallArgument objArgument = new CallArgument(); objArgument.setValue(name); CallFunctionOnResult funcObj = getThis().getCommand().getRuntime().callFunctionOn( windowResult.getResult().getObjectId(), "function(functionName) { return functionName.split('.').reduce((o, i) => o[i], this); }", asList(objArgument), FALSE, FALSE, FALSE, FALSE, FALSE); getThis().releaseObject(windowResult.getResult().getObjectId()); if (funcObj.getExceptionDetails() != null && funcObj.getExceptionDetails().getException() != null) { getThis().releaseObject(funcObj.getExceptionDetails().getException().getObjectId()); throw new CdpException(funcObj.getExceptionDetails().getException().getDescription()); } if (ObjectType.Undefined.equals(funcObj.getResult().getType())) { getThis().releaseObject(funcObj.getResult().getObjectId()); throw new CdpException(format("Function [%s] is not defined", name)); } StringJoiner argNames = new StringJoiner(","); List<CallArgument> argsFunc = new ArrayList<>(); int i = 0; if (arguments != null && arguments.length > 0) { for (Object argument : arguments) { CallArgument ca = new CallArgument(); argsFunc.add(ca); if (argument != null) { if (getThis().isPrimitive(argument.getClass())) { ca.setValue(argument); } else { ca.setValue(getThis().getGson().toJson(argument)); } } argNames.add("arg" + (i + 1)); } } CallFunctionOnResult func = getThis().getCommand().getRuntime().callFunctionOn( funcObj.getResult().getObjectId(), format("function(%s) { const result = this.apply(this, Array.prototype.slice.call(arguments)); " + "return typeof result === 'undefined' ? undefined : JSON.stringify({ result : result }); }", argNames.toString()), argsFunc, FALSE, TRUE, FALSE, FALSE, FALSE); getThis().releaseObject(funcObj.getResult().getObjectId()); getThis().releaseObject(func.getResult().getObjectId()); if (func.getExceptionDetails() != null && func.getExceptionDetails().getException() != null) { getThis().releaseObject(func.getExceptionDetails().getException().getObjectId()); throw new CdpException(func.getExceptionDetails().getException().getDescription()); } Object value = null; if (ObjectType.String.equals(func.getResult().getType()) && !returnType.equals(void.class)) { String json = valueOf(func.getResult().getValue()); JsonObject object = getThis().getGson().fromJson(json, JsonObject.class); JsonElement result = object.get("result"); if (getThis().isPrimitive(returnType)) { value = getThis().getGson().fromJson(result, returnType); } else { if (result.isJsonPrimitive()) { value = getThis().getGson().fromJson(result.getAsString(), returnType); } } } else if (ObjectType.Undefined.equals(func.getResult().getType())) { value = void.class; } StringJoiner joiner = new StringJoiner("\", \""); for (Object o : arguments) { joiner.add(valueOf(o)); } getThis().logExit("callFunction", name + (arguments == null || arguments.length == 0 ? "" : "\", " + joiner.toString()), valueOf(value).replace("\n", "").replace("\r", "")); return !void.class.equals(value) ? (T) value : null; } /** * Gets JavaScript variable. * * <p> * Variable must be declared at the global {@literal (window object)} scope. * You can use <strong>dot notation</strong> for variable name. * </p> * * @param name variable name * @param returnType variable type * * @return variable value */ @SuppressWarnings("unchecked") public default <T> T getVariable(String name, Class<T> returnType) { EvaluateResult windowResult = getThis().getCommand().getRuntime().evaluate("window"); if (windowResult == null) { return null; } if (windowResult.getExceptionDetails() != null && windowResult.getExceptionDetails().getException() != null) { getThis().releaseObject(windowResult.getExceptionDetails().getException().getObjectId()); throw new CdpException(windowResult.getExceptionDetails().getException().getDescription()); } CallArgument objArgument = new CallArgument(); objArgument.setValue(name); CallFunctionOnResult obj = getThis().getCommand().getRuntime().callFunctionOn( windowResult.getResult().getObjectId(), "function(functionName) { const result = functionName.split('.').reduce((o, i) => o[i], this); " + "return typeof result === 'undefined' ? undefined : JSON.stringify({ result : result }); }", asList(objArgument), FALSE, FALSE, FALSE, FALSE, FALSE); getThis().releaseObject(windowResult.getResult().getObjectId()); if (obj.getExceptionDetails() != null && obj.getExceptionDetails().getException() != null) { getThis().releaseObject(obj.getExceptionDetails().getException().getObjectId()); throw new CdpException(obj.getExceptionDetails().getException().getDescription()); } if (ObjectType.Undefined.equals(obj.getResult().getType())) { getThis().releaseObject(obj.getResult().getObjectId()); throw new CdpException(format("Variable [%s] is not defined", name)); } Object value = null; if (ObjectType.String.equals(obj.getResult().getType()) && !returnType.equals(void.class)) { String json = valueOf(obj.getResult().getValue()); JsonObject object = getThis().getGson().fromJson(json, JsonObject.class); JsonElement result = object.get("result"); if (getThis().isPrimitive(returnType)) { value = getThis().getGson().fromJson(result, returnType); } else { if (result.isJsonPrimitive()) { value = getThis().getGson().fromJson(result.getAsString(), returnType); } } } else if (ObjectType.Undefined.equals(obj.getResult().getType())) { value = void.class; } getThis().releaseObject(obj.getResult().getObjectId()); return (T) value; } /** * Sets JavaScript variable. * * <p> * Variable must be declared at the global {@literal (window object)} scope. * You can use <strong>dot notation</strong> for variable name. * </p> * * @param name variable name * @param newValue value */ public default void setVariable(String name, Object newValue) { EvaluateResult windowResult = getThis().getCommand().getRuntime().evaluate("window"); if (windowResult == null) { return; } if (windowResult.getExceptionDetails() != null && windowResult.getExceptionDetails().getException() != null) { getThis().releaseObject(windowResult.getExceptionDetails().getException().getObjectId()); throw new CdpException(windowResult.getExceptionDetails().getException().getDescription()); } CallArgument argVariableName = new CallArgument(); argVariableName.setValue(name); CallArgument argVariableValue = new CallArgument(); if (newValue != null) { if (getThis().isPrimitive(newValue.getClass())) { argVariableValue.setValue(newValue); } else { argVariableValue.setValue(getThis().getGson().toJson(newValue)); } } CallFunctionOnResult obj = getThis().getCommand().getRuntime().callFunctionOn( windowResult.getResult().getObjectId(), "function(is, value) { console.info(Object.prototype.toString.call(value)); function index(obj, is, value) { if (typeof is == 'string') return index(obj, is.split('.'), value); " + "else if (is.length === 1 && value !== undefined) return obj[is[0]] = value; else if (is.length === 0) " + "return obj; else return index(obj[is[0]], is.slice(1), value); } index(window, is, value); }", asList(argVariableName, argVariableValue), FALSE, FALSE, FALSE, FALSE, FALSE); getThis().releaseObject(windowResult.getResult().getObjectId()); if (obj.getExceptionDetails() != null && obj.getExceptionDetails().getException() != null) { getThis().releaseObject(obj.getExceptionDetails().getException().getObjectId()); throw new CdpException(obj.getExceptionDetails().getException().getDescription()); } getThis().releaseObject(obj.getResult().getObjectId()); } public Session getThis(); }