com.eclipsesource.v8.V8 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of j2v8_android_armv7l Show documentation
Show all versions of j2v8_android_armv7l Show documentation
J2V8 is a set of Java bindings for V8
/*******************************************************************************
* Copyright (c) 2014 EclipseSource and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* EclipseSource - initial API and implementation
******************************************************************************/
package com.eclipsesource.v8;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class V8 extends V8Object {
private static int v8InstanceCounter;
private static Thread thread = null;
private static List runtimes = new ArrayList<>();
private static Runnable debugHandler = null;
private int methodReferenceCounter = 0;
private int v8RuntimeHandle;
private boolean debugEnabled = false;
long objectReferences = 0;
private static boolean nativeLibraryLoaded = false;
private static Error nativeLoadError = null;
private static Exception nativeLoadException = null;
private static V8Value undefined = new V8Object.Undefined();
private static Object invalid = new Object();
class MethodDescriptor {
Object object;
Method method;
JavaCallback callback;
JavaVoidCallback voidCallback;
}
Map functions = new HashMap<>();
private static void load(final String tmpDirectory) {
try {
LibraryLoader.loadLibrary(tmpDirectory);
nativeLibraryLoaded = true;
} catch (Error e) {
nativeLoadError = e;
} catch (Exception e) {
nativeLoadException = e;
}
}
public static boolean isEnabled() {
return nativeLibraryLoaded;
}
public synchronized static V8 createV8Runtime() {
return createV8Runtime(null, null);
}
public synchronized static V8 createV8Runtime(final String globalAlias) {
return createV8Runtime(globalAlias, null);
}
public synchronized static V8 createV8Runtime(final String globalAlias, final String tempDirectory) {
if (!nativeLibraryLoaded) {
load(tempDirectory);
}
checkNativeLibraryLoaded();
if (thread == null) {
thread = Thread.currentThread();
}
V8 runtime = new V8(globalAlias);
runtimes.add(runtime);
return runtime;
}
private static void checkNativeLibraryLoaded() {
if (!nativeLibraryLoaded) {
if (nativeLoadError != null) {
throw new IllegalStateException("J2V8 native library not loaded.", nativeLoadError);
} else if (nativeLoadException != null) {
throw new IllegalStateException("J2V8 native library not loaded.", nativeLoadException);
} else {
throw new IllegalStateException("J2V8 native library not loaded.");
}
}
}
protected V8() {
this(null);
}
protected V8(final String globalAlias) {
super(null, 0);
checkThread();
v8RuntimeHandle = v8InstanceCounter++;
_createIsolate(v8RuntimeHandle, globalAlias);
}
public static V8Value getUndefined() {
return undefined;
}
public boolean enableDebugSupport(final int port, final boolean waitForConnection) {
checkThread();
debugEnabled = _enableDebugSupport(getHandle(), port, waitForConnection);
return debugEnabled;
}
public boolean enableDebugSupport(final int port) {
checkThread();
debugEnabled = _enableDebugSupport(getV8RuntimeHandle(), port, false);
return debugEnabled;
}
public void disableDebugSupport() {
checkThread();
_disableDebugSupport(getV8RuntimeHandle());
debugEnabled = false;
}
public static void processDebugMessages() {
checkThread();
for (V8 v8 : runtimes) {
v8._processDebugMessages(v8.getV8RuntimeHandle());
}
}
public static int getActiveRuntimes() {
return runtimes.size();
}
public static void registerDebugHandler(final Runnable handler) {
debugHandler = handler;
}
public int getV8RuntimeHandle() {
return v8RuntimeHandle;
}
@Override
public void release() {
release(true);
}
public void release(final boolean reportMemoryLeaks) {
checkThread();
if (debugEnabled) {
disableDebugSupport();
}
runtimes.remove(this);
_releaseRuntime(v8RuntimeHandle);
if (reportMemoryLeaks && (objectReferences > 0)) {
throw new IllegalStateException(objectReferences + " Object(s) still exist in runtime");
}
}
public int executeIntScript(final String script) {
return executeIntScript(script, null, 0);
}
public int executeIntScript(final String script, final String scriptName, final int lineNumber) {
checkThread();
return _executeIntScript(v8RuntimeHandle, script, scriptName, lineNumber);
}
public double executeDoubleScript(final String script) {
return executeDoubleScript(script, null, 0);
}
public double executeDoubleScript(final String script, final String scriptName, final int lineNumber) {
checkThread();
return _executeDoubleScript(v8RuntimeHandle, script, scriptName, lineNumber);
}
public String executeStringScript(final String script) {
return executeStringScript(script, null, 0);
}
public String executeStringScript(final String script, final String scriptName, final int lineNumber) {
checkThread();
return _executeStringScript(v8RuntimeHandle, script, scriptName, lineNumber);
}
public boolean executeBooleanScript(final String script) {
return executeBooleanScript(script, null, 0);
}
public boolean executeBooleanScript(final String script, final String scriptName, final int lineNumber) {
checkThread();
return _executeBooleanScript(v8RuntimeHandle, script, scriptName, lineNumber);
}
public V8Array executeArrayScript(final String script) {
return this.executeArrayScript(script, null, 0);
}
public V8Array executeArrayScript(final String script, final String scriptName, final int lineNumber) {
checkThread();
Object result = this.executeScript(script, null, 0);
if (result instanceof V8Array) {
return (V8Array) result;
}
throw new V8ResultUndefined();
}
public Object executeScript(final String script) {
return this.executeScript(script, null, 0);
}
public Object executeScript(final String script, final String scriptName, final int lineNumber) {
checkThread();
return _executeScript(getV8RuntimeHandle(), UNKNOWN, script, scriptName, lineNumber);
}
public V8Object executeObjectScript(final String script) {
return this.executeObjectScript(script, null, 0);
}
public V8Object executeObjectScript(final String script, final String scriptName, final int lineNumber) {
checkThread();
Object result = this.executeScript(script, null, 0);
if (result instanceof V8Object) {
return (V8Object) result;
}
throw new V8ResultUndefined();
}
public void executeVoidScript(final String script) {
this.executeVoidScript(script, null, 0);
}
public void executeVoidScript(final String script, final String scriptName, final int lineNumber) {
checkThread();
_executeVoidScript(v8RuntimeHandle, script, scriptName, lineNumber);
}
static void checkThread() {
if ((thread != null) && (thread != Thread.currentThread())) {
throw new Error("Invalid V8 thread access.");
}
}
void registerCallback(final Object object, final Method method, final int objectHandle, final String jsFunctionName) {
MethodDescriptor methodDescriptor = new MethodDescriptor();
methodDescriptor.object = object;
methodDescriptor.method = method;
int methodID = methodReferenceCounter++;
getFunctionRegistry().put(methodID, methodDescriptor);
_registerJavaMethod(getV8RuntimeHandle(), objectHandle, jsFunctionName, methodID, isVoidMethod(method));
}
void registerVoidCallback(final JavaVoidCallback callback, final int objectHandle, final String jsFunctionName) {
MethodDescriptor methodDescriptor = new MethodDescriptor();
methodDescriptor.voidCallback = callback;
int methodID = methodReferenceCounter++;
getFunctionRegistry().put(methodID, methodDescriptor);
_registerJavaMethod(getV8RuntimeHandle(), objectHandle, jsFunctionName, methodID, true);
}
void registerCallback(final JavaCallback callback, final int objectHandle, final String jsFunctionName) {
MethodDescriptor methodDescriptor = new MethodDescriptor();
methodDescriptor.callback = callback;
int methodID = methodReferenceCounter++;
getFunctionRegistry().put(methodID, methodDescriptor);
_registerJavaMethod(getV8RuntimeHandle(), objectHandle, jsFunctionName, methodID, false);
}
private boolean isVoidMethod(final Method method) {
Class> returnType = method.getReturnType();
if (returnType.equals(Void.TYPE)) {
return true;
}
return false;
}
private Object getDefaultValue(final Class> type) {
if (type.equals(V8Object.class)) {
return new V8Object.Undefined();
} else if (type.equals(V8Array.class)) {
return new V8Array.Undefined();
}
return invalid;
}
protected Object callObjectJavaMethod(final int methodID, final V8Array parameters) throws Throwable {
MethodDescriptor methodDescriptor = getFunctionRegistry().get(methodID);
if (methodDescriptor.callback != null) {
return checkResult(methodDescriptor.callback.invoke(parameters));
}
boolean hasVarArgs = methodDescriptor.method.isVarArgs();
Object[] args = getArgs(methodDescriptor, parameters, hasVarArgs);
checkArgs(args);
try {
Object result = methodDescriptor.method.invoke(methodDescriptor.object, args);
return checkResult(result);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (IllegalAccessException | IllegalArgumentException e) {
throw e;
} finally {
releaseArguments(args, hasVarArgs);
}
}
private Object checkResult(final Object result) {
if (result == null) {
return result;
}
if (result instanceof Float) {
return ((Float) result).doubleValue();
}
if ((result instanceof Integer) || (result instanceof Double) || (result instanceof Boolean)
|| (result instanceof String) || (result instanceof V8Object) || (result instanceof V8Array)) {
return result;
}
throw new V8RuntimeException("Unknown return type: " + result.getClass());
}
protected void callVoidJavaMethod(final int methodID, final V8Array parameters) throws Throwable {
MethodDescriptor methodDescriptor = getFunctionRegistry().get(methodID);
if (methodDescriptor.voidCallback != null) {
methodDescriptor.voidCallback.invoke(parameters);
return;
}
boolean hasVarArgs = methodDescriptor.method.isVarArgs();
Object[] args = getArgs(methodDescriptor, parameters, hasVarArgs);
checkArgs(args);
try {
methodDescriptor.method.invoke(methodDescriptor.object, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (IllegalAccessException | IllegalArgumentException e) {
throw e;
} finally {
releaseArguments(args, hasVarArgs);
}
}
private void checkArgs(final Object[] args) {
for (Object argument : args) {
if (argument == invalid) {
throw new IllegalArgumentException("argument type mismatch");
}
}
}
private void releaseArguments(final Object[] args, final boolean hasVarArgs) {
if (hasVarArgs && ((args.length > 0) && (args[args.length - 1] instanceof Object[]))) {
Object[] varArgs = (Object[]) args[args.length - 1];
for (Object object : varArgs) {
if (object instanceof V8Object) {
((V8Value) object).release();
}
}
}
for (Object arg : args) {
if (arg instanceof V8Object) {
((V8Value) arg).release();
}
}
}
private Object[] getArgs(final MethodDescriptor methodDescriptor, final V8Array parameters, final boolean hasVarArgs) {
int numberOfParameters = methodDescriptor.method.getParameterTypes().length;
int varArgIndex = hasVarArgs ? numberOfParameters - 1 : numberOfParameters;
Object[] args = setDefaultValues(new Object[numberOfParameters], methodDescriptor.method.getParameterTypes());
List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy