Browse Source

REPORT-83322 j2v8引擎升级之后,内置到third中

feature/x
pengda 2 years ago
parent
commit
6afe04c671
  1. 1
      base-third-project/base-third-step1/pom.xml
  2. 3
      build.third_step1-jdk11.gradle
  3. 3
      build.third_step1.gradle
  4. 18
      fine-j2v8/pom.xml
  5. 37
      fine-j2v8/src/main/java/com/eclipsesource/v8/JavaCallback.java
  6. 33
      fine-j2v8/src/main/java/com/eclipsesource/v8/JavaVoidCallback.java
  7. 194
      fine-j2v8/src/main/java/com/eclipsesource/v8/LibraryLoader.java
  8. 12
      fine-j2v8/src/main/java/com/eclipsesource/v8/Platform.java
  9. 316
      fine-j2v8/src/main/java/com/eclipsesource/v8/PlatformDetector.java
  10. 34
      fine-j2v8/src/main/java/com/eclipsesource/v8/ReferenceHandler.java
  11. 30
      fine-j2v8/src/main/java/com/eclipsesource/v8/Releasable.java
  12. 5
      fine-j2v8/src/main/java/com/eclipsesource/v8/SignatureProvider.java
  13. 1666
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8.java
  14. 1189
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8Array.java
  15. 472
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8ArrayBuffer.java
  16. 98
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8Function.java
  17. 113
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8Locker.java
  18. 1005
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8Object.java
  19. 32
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8ResultUndefined.java
  20. 27
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8RuntimeException.java
  21. 24
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8ScriptCompilationException.java
  22. 165
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8ScriptException.java
  23. 40
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8ScriptExecutionException.java
  24. 183
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8TypedArray.java
  25. 393
      fine-j2v8/src/main/java/com/eclipsesource/v8/V8Value.java
  26. 69
      fine-j2v8/src/main/java/com/eclipsesource/v8/utils/ArrayBuffer.java
  27. 94
      fine-j2v8/src/main/java/com/eclipsesource/v8/utils/ConcurrentV8.java
  28. 138
      fine-j2v8/src/main/java/com/eclipsesource/v8/utils/MemoryManager.java
  29. 55
      fine-j2v8/src/main/java/com/eclipsesource/v8/utils/SingleTypeAdapter.java
  30. 39
      fine-j2v8/src/main/java/com/eclipsesource/v8/utils/TypeAdapter.java
  31. 73
      fine-j2v8/src/main/java/com/eclipsesource/v8/utils/TypedArray.java
  32. 253
      fine-j2v8/src/main/java/com/eclipsesource/v8/utils/V8Executor.java
  33. 185
      fine-j2v8/src/main/java/com/eclipsesource/v8/utils/V8Map.java
  34. 690
      fine-j2v8/src/main/java/com/eclipsesource/v8/utils/V8ObjectUtils.java
  35. 176
      fine-j2v8/src/main/java/com/eclipsesource/v8/utils/V8PropertyMap.java
  36. 29
      fine-j2v8/src/main/java/com/eclipsesource/v8/utils/V8Runnable.java
  37. 57
      fine-j2v8/src/main/java/com/eclipsesource/v8/utils/V8Thread.java
  38. BIN
      fine-j2v8/src/main/resources/libj2v8-linux-x86_64.so
  39. BIN
      fine-j2v8/src/main/resources/libj2v8-macosx-aarch_64.dylib
  40. BIN
      fine-j2v8/src/main/resources/libj2v8-macosx-x86_64.dylib
  41. BIN
      fine-j2v8/src/main/resources/libj2v8-windows-x86_64.dll

1
base-third-project/base-third-step1/pom.xml

@ -26,6 +26,7 @@
<module>../../fine-iconloader</module>
<module>../../fine-icu4j</module>
<module>../../fine-imageJ</module>
<module>../../fine-j2v8</module>
<!-- <module>../../fine-jai</module>-->
<module>../../fine-jboss-transaction-api</module>
<module>../../fine-jgit</module>

3
build.third_step1-jdk11.gradle

@ -43,6 +43,7 @@ sourceSets{
"${srcDir}/fine-hsqldb/src/main/java",
"${srcDir}/fine-iconloader/src/main/java",
"${srcDir}/fine-icu4j/src/main/java",
"${srcDir}/fine-j2v8/src/main/java",
// "${srcDir}/fine-jai/src/main/java",
"${srcDir}/fine-jboss-transaction-api/src/main/java",
"${srcDir}/fine-jgit/src/main/java",
@ -95,6 +96,8 @@ def resourceDirs = [
"${srcDir}/fine-iconloader/src/main/resources",
"${srcDir}/fine-icu4j/src/main/java",
"${srcDir}/fine-icu4j/src/main/resources",
"${srcDir}/fine-j2v8/src/main/java",
"${srcDir}/fine-j2v8/src/main/resources",
// "${srcDir}/fine-jai/src/main/java",
"${srcDir}/fine-jboss-transaction-api/src/main/java",
"${srcDir}/fine-jboss-transaction-api/src/main/resources",

3
build.third_step1.gradle

@ -44,6 +44,7 @@ sourceSets{
"${srcDir}/fine-hsqldb/src/main/java",
"${srcDir}/fine-iconloader/src/main/java",
"${srcDir}/fine-icu4j/src/main/java",
"${srcDir}/fine-j2v8/src/main/java",
// "${srcDir}/fine-jai/src/main/java",
"${srcDir}/fine-jboss-transaction-api/src/main/java",
"${srcDir}/fine-jgit/src/main/java",
@ -144,6 +145,8 @@ task copyFiles(type:Copy,dependsOn:'compileJava'){
with dataContent.call("${srcDir}/fine-hsqldb/src/main/resources")
with dataContent.call("${srcDir}/fine-icu4j/src/main/java")
with dataContent.call("${srcDir}/fine-icu4j/src/main/resources")
with dataContent.call("${srcDir}/fine-j2v8/src/main/java")
with dataContent.call("${srcDir}/fine-j2v8/src/main/resources")
// with dataContent.call("${srcDir}/fine-jai/src/main/java")
with dataContent.call("${srcDir}/fine-jboss-transaction-api/src/main/java")
with dataContent.call("${srcDir}/fine-jboss-transaction-api/src/main/resources")

18
fine-j2v8/pom.xml

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.fr.third</groupId>
<artifactId>step1</artifactId>
<version>${revision}</version>
<relativePath>../base-third-project/base-third-step1</relativePath>
</parent>
<artifactId>fine-j2v8</artifactId>
<version>${revision}</version>
</project>

37
fine-j2v8/src/main/java/com/eclipsesource/v8/JavaCallback.java

@ -0,0 +1,37 @@
/*******************************************************************************
* 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;
/**
* Classes that implement this interface provide a method
* which can be invoked from JavaScript. The method can return
* a result.
*
* After creating an instance of a class that implements this
* interface it can be registered as a Callback on a V8Object.
*/
public interface JavaCallback {
/**
* Called when a JS Function invokes a the registered Java
* method.
*
* @param receiver The V8Object that the function was called on.
* @param parameters The parameters passed to the JS Function. The
* parameter array does not need to be released, by any objects accessed
* from the array must be.
*
* @return A result that should be passed back to JavaScript. The
* result must be either an Integer, Double, Boolean, String or V8Value.
*/
public Object invoke(V8Object receiver, V8Array parameters);
}

33
fine-j2v8/src/main/java/com/eclipsesource/v8/JavaVoidCallback.java

@ -0,0 +1,33 @@
/*******************************************************************************
* 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;
/**
* Classes that implement this interface provide a method
* which can be invoked from JavaScript.
*
* After creating an instance of a class that implements this
* interface it can be registered as a Callback on a V8Object.
*/
public interface JavaVoidCallback {
/**
* Called when a JS Function invokes a the registered Java
* method.
*
* @param receiver The V8Object that the function was called on.
* @param parameters The parameters passed to the JS Function. The
* parameter array does not need to be released, by any objects accessed
* from the array must be.
*/
public void invoke(V8Object receiver, V8Array parameters);
}

194
fine-j2v8/src/main/java/com/eclipsesource/v8/LibraryLoader.java

@ -0,0 +1,194 @@
/*******************************************************************************
* Copyright (c) 2015 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
* Wolfgang Steiner - code separation PlatformDetector/LibraryLoader
******************************************************************************/
package com.eclipsesource.v8;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class LibraryLoader {
static final String SEPARATOR;
static final String DELIMITER;
static final String SWT_LIB_DIR = ".j2v8";
static {
DELIMITER = System.getProperty("line.separator"); //$NON-NLS-1$
SEPARATOR = System.getProperty("file.separator"); //$NON-NLS-1$
}
/**
* Returns the base-name for the native J2V8 library file.
* @param withLinuxVendor include/exclude the {vendor} part from the returned filename
* <p>NOTE: Vendors are only included for linux systems</p>
* @return The filename string has the following structure:
* <pre><code>{arch}-[vendor]-{operating_system}</pre></code>
*/
public static String computeLibraryShortName(boolean withLinuxVendor) {
String prefix = "j2v8";
String vendor = withLinuxVendor && PlatformDetector.OS.isLinux() ? PlatformDetector.Vendor.getName() : null;
String os = PlatformDetector.OS.getName();
String arch = PlatformDetector.Arch.getName();
final String separator = "-";
return
prefix +
(vendor != null ? separator + vendor : "") +
separator + os +
separator + arch;
}
public static String computeLibraryFullName(boolean withLinuxVendor) {
return "lib" + computeLibraryShortName(withLinuxVendor) + "." + PlatformDetector.OS.getLibFileExtension();
}
static boolean tryLoad(boolean withLinuxVendor, StringBuffer message) {
String libShortName = computeLibraryShortName(withLinuxVendor);
String libFullName = computeLibraryFullName(withLinuxVendor);
String ideLocation = System.getProperty("user.dir") + SEPARATOR + "jni" + SEPARATOR + libFullName;
/* Try loading library from java library path */
if (load(libFullName, message)) {
return true;
}
if (load(libShortName, message)) {
return true;
}
/* Try loading library from the IDE location */
if (new File(ideLocation).exists()) {
if (load(ideLocation, message)) {
return true;
}
}
return false;
}
static void loadLibrary(final String tempDirectory) {
if (PlatformDetector.OS.isAndroid()) {
System.loadLibrary("j2v8");
return;
}
StringBuffer message = new StringBuffer();
// try loading a vendor-specific library first
if (tryLoad(true, message))
return;
// if there is no vendor-specific library, just try to load the default OS library
if (tryLoad(false, message))
return;
String path = null;
if (tempDirectory != null) {
path = tempDirectory;
} else {
path = System.getProperty("java.io.tmpdir"); //$NON-NLS-1$
}
// try extracting a vendor-specific library first
if (extract(path, true, message))
return;
// if there is no vendor-specific library, just try to extract the default OS library
if (extract(path, false, message))
return;
/* Failed to find the library */
throw new UnsatisfiedLinkError("Could not load J2V8 library. Reasons: " + message.toString()); //$NON-NLS-1$
}
static boolean load(final String libName, final StringBuffer message) {
try {
if (libName.indexOf(SEPARATOR) != -1) {
System.load(libName);
} else {
System.loadLibrary(libName);
}
return true;
} catch (UnsatisfiedLinkError e) {
if (message.length() == 0) {
message.append(DELIMITER);
}
message.append('\t');
message.append(e.getMessage());
message.append(DELIMITER);
}
return false;
}
static boolean extract(String libPath, boolean withLinuxVendor, StringBuffer message) {
String libFullName = computeLibraryFullName(withLinuxVendor);
return extract(libPath + SEPARATOR + libFullName, libFullName, message);
}
static boolean extract(final String fileName, final String mappedName, final StringBuffer message) {
FileOutputStream os = null;
InputStream is = null;
File file = new File(fileName);
boolean extracted = false;
try {
if (file.exists()) {
file.delete();
}
is = LibraryLoader.class.getResourceAsStream("/" + mappedName); //$NON-NLS-1$
if (is != null) {
extracted = true;
int read;
byte[] buffer = new byte[4096];
os = new FileOutputStream(fileName);
while ((read = is.read(buffer)) != -1) {
os.write(buffer, 0, read);
}
os.close();
is.close();
chmod("755", fileName);
if (load(fileName, message)) {
return true;
}
}
} catch (Throwable e) {
try {
if (os != null) {
os.close();
}
} catch (IOException e1) {
}
try {
if (is != null) {
is.close();
}
} catch (IOException e1) {
}
if (extracted && file.exists()) {
file.delete();
}
}
return false;
}
static void chmod(final String permision, final String path) {
if (PlatformDetector.OS.isWindows()) {
return;
}
try {
Runtime.getRuntime().exec(new String[] { "chmod", permision, path }).waitFor(); //$NON-NLS-1$
} catch (Throwable e) {
}
}
}

12
fine-j2v8/src/main/java/com/eclipsesource/v8/Platform.java

@ -0,0 +1,12 @@
package com.eclipsesource.v8;
public class Platform {
public static final String ANDROID = "android";
public static final String LINUX = "linux";
public static final String MACOSX = "macosx";
public static final String WINDOWS = "windows";
public static final String NATIVE_CLIENT = "nacl";
public static final String UNKNOWN = "unknown";
}

316
fine-j2v8/src/main/java/com/eclipsesource/v8/PlatformDetector.java

@ -0,0 +1,316 @@
/*******************************************************************************
* Copyright (c) 2017 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:
* Trustin Lee - original OS/Arch/Vendor detection code (see: https://github.com/trustin/os-maven-plugin)
* Wolfgang Steiner - initial API and implementation
*
* Copyright 2014 Trustin Heuiseung Lee.
*
* 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.eclipsesource.v8;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Locale;
public class PlatformDetector {
public static class Arch {
public static String getName() {
final String archProperty = System.getProperty("os.arch");
final String archName = normalizeArch(archProperty);
if (archName.equals(Platform.UNKNOWN)) {
throw new UnsatisfiedLinkError("Unsupported arch: " + archProperty);
}
return archName;
}
}
public static class OS {
public static String getName() {
final String osProperty = System.getProperty("os.name");
final String osName = normalizeOs(osProperty);
final String vendorProperty = System.getProperty("java.specification.vendor");
final String vendorName = normalize(vendorProperty);
// special handling for android
if (vendorName.contains("android") || osName.contains("android")) {
return Platform.ANDROID;
}
if (osName.equals(Platform.UNKNOWN)) {
throw new UnsatisfiedLinkError("Unsupported platform/vendor: " + osProperty + " / " + vendorProperty);
}
return osName;
}
public static boolean isWindows() {
return getName().equals(Platform.WINDOWS);
}
public static boolean isMac() {
return getName().equals(Platform.MACOSX);
}
public static boolean isLinux() {
return getName().equals(Platform.LINUX);
}
public static boolean isNativeClient() {
return getName().equals(Platform.NATIVE_CLIENT);
}
public static boolean isAndroid() {
return getName().equals(Platform.ANDROID);
}
public static String getLibFileExtension() {
if (isWindows()) {
return "dll";
}
if (isMac()) {
return "dylib";
}
if (isLinux()
|| isAndroid()
|| isNativeClient()) {
return "so";
}
throw new UnsatisfiedLinkError("Unsupported platform library-extension for: " + getName());
}
}
public static class Vendor {
private static final String[] LINUX_OS_RELEASE_FILES = {"/etc/os-release", "/usr/lib/os-release"};
private static final String REDHAT_RELEASE_FILE = "/etc/redhat-release";
private static final String LINUX_ID_PREFIX = "ID=";
public static String getName() {
if (OS.isWindows()) {
return "microsoft";
}
if (OS.isMac()) {
return "apple";
}
if (OS.isLinux()) {
return getLinuxOsReleaseId();
}
if (OS.isAndroid()) {
return "google";
}
throw new UnsatisfiedLinkError("Unsupported vendor: " + getName());
}
private static String getLinuxOsReleaseId() {
// First, look for the os-release file.
for (String osReleaseFileName : LINUX_OS_RELEASE_FILES) {
File file = new File(osReleaseFileName);
if (file.exists()) {
return parseLinuxOsReleaseFile(file);
}
}
// Older versions of redhat don't have /etc/os-release. In this case, try
// parsing this file.
File file = new File(REDHAT_RELEASE_FILE);
if (file.exists()) {
return parseLinuxRedhatReleaseFile(file);
}
throw new UnsatisfiedLinkError("Unsupported linux vendor: " + getName());
}
private static String parseLinuxOsReleaseFile(final File file) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
String id = null;
String line;
while((line = reader.readLine()) != null) {
// Parse the ID line.
if (line.startsWith(LINUX_ID_PREFIX)) {
// Set the ID for this version.
id = normalizeOsReleaseValue(line.substring(LINUX_ID_PREFIX.length()));
break;
}
}
return id;
} catch (IOException ignored) {
// Just absorb. Don't treat failure to read /etc/os-release as an error.
} finally {
closeQuietly(reader);
}
return null;
}
private static String parseLinuxRedhatReleaseFile(final File file) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
// There is only a single line in this file.
String line = reader.readLine();
if (line != null) {
line = line.toLowerCase(Locale.US);
String id;
if (line.contains("centos")) {
id = "centos";
} else if (line.contains("fedora")) {
id = "fedora";
} else if (line.contains("red hat enterprise linux")) {
id = "rhel";
} else {
// Other variants are not currently supported.
return null;
}
return id;
}
} catch (IOException ignored) {
// Just absorb. Don't treat failure to read /etc/os-release as an error.
} finally {
closeQuietly(reader);
}
return null;
}
private static void closeQuietly(final Closeable obj) {
try {
if (obj != null) {
obj.close();
}
} catch (IOException ignored) {
// Ignore.
}
}
}
private static String normalizeOsReleaseValue(final String value) {
// Remove any quotes from the string.
return value.trim().replace("\"", "");
}
private static String normalizeOs(String value) {
value = normalize(value);
if (value.startsWith("aix")) {
return "aix";
}
if (value.startsWith("hpux")) {
return "hpux";
}
if (value.startsWith("os400")) {
// Avoid the names such as os4000
if ((value.length() <= 5) || !Character.isDigit(value.charAt(5))) {
return "os400";
}
}
if (value.startsWith("android")) {
return Platform.ANDROID;
}
if (value.startsWith("linux")) {
return Platform.LINUX;
}
if (value.startsWith("nacl")) {
return Platform.NATIVE_CLIENT;
}
if (value.startsWith("macosx") || value.startsWith("osx")) {
return Platform.MACOSX;
}
if (value.startsWith("freebsd")) {
return "freebsd";
}
if (value.startsWith("openbsd")) {
return "openbsd";
}
if (value.startsWith("netbsd")) {
return "netbsd";
}
if (value.startsWith("solaris") || value.startsWith("sunos")) {
return "sunos";
}
if (value.startsWith("windows")) {
return Platform.WINDOWS;
}
return Platform.UNKNOWN;
}
private static String normalizeArch(String value) {
value = normalize(value);
if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$")) {
return "x86_64";
}
if (value.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) {
return "x86_32";
}
if (value.matches("^(ia64|itanium64)$")) {
return "itanium_64";
}
if (value.matches("^(sparc|sparc32)$")) {
return "sparc_32";
}
if (value.matches("^(sparcv9|sparc64)$")) {
return "sparc_64";
}
if (value.matches("^(arm|arm32)$") || value.startsWith("armv7")) {
return "arm_32";
}
if ("aarch64".equals(value) || value.startsWith("armv8")) {
return "aarch_64";
}
if (value.matches("^(ppc|ppc32)$")) {
return "ppc_32";
}
if ("ppc64".equals(value)) {
return "ppc_64";
}
if ("ppc64le".equals(value)) {
return "ppcle_64";
}
if ("s390".equals(value)) {
return "s390_32";
}
if ("s390x".equals(value)) {
return "s390_64";
}
return Platform.UNKNOWN;
}
private static String normalize(final String value) {
if (value == null) {
return "";
}
return value.toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", "");
}
}

34
fine-j2v8/src/main/java/com/eclipsesource/v8/ReferenceHandler.java

@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright (c) 2016 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;
/**
* Callback used to track when native handles are created and released.
*/
public interface ReferenceHandler {
/**
* Called when a native handle is first created. The V8Value
* referenced by that handle is passed as a parameter.
*
* @param object The V8Value referenced by the handle
*/
public void v8HandleCreated(V8Value object);
/**
* Called when a native handle is released. The V8Value
* referenced by that handle is passed as a parameter.
*
* @param object The V8Value referenced by the handle
*/
public void v8HandleDisposed(V8Value object);
}

30
fine-j2v8/src/main/java/com/eclipsesource/v8/Releasable.java

@ -0,0 +1,30 @@
/*******************************************************************************
* Copyright (c) 2015 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.io.Closeable;
/**
* An interface used to denote all V8 Classes which can be released.
*/
public interface Releasable extends Closeable {
/**
* Release the underlying resources. Once an object is released
* it typically cannot be used again.
*/
void close();
/**
* Synonym for {@link #close()}.
*/
void release();
}

5
fine-j2v8/src/main/java/com/eclipsesource/v8/SignatureProvider.java

@ -0,0 +1,5 @@
package com.eclipsesource.v8;
public interface SignatureProvider {
public byte[] getSignature(String uri);
}

1666
fine-j2v8/src/main/java/com/eclipsesource/v8/V8.java

File diff suppressed because it is too large Load Diff

1189
fine-j2v8/src/main/java/com/eclipsesource/v8/V8Array.java

File diff suppressed because it is too large Load Diff

472
fine-j2v8/src/main/java/com/eclipsesource/v8/V8ArrayBuffer.java

@ -0,0 +1,472 @@
/*******************************************************************************
* Copyright (c) 2016 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.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* V8ArrayBuffers represent ArrayBuffers from V8, but are backed by a
* java.nio.ByteBuffer. This means that any data stored in a TypedArray
* can be accessed by the java.nio.ByteBuffer. This significantly improves
* performance of data access from Java to JavaScript.
*
* V8ArrayBuffers can either be constructed in Java, or returned from
* JavaScript.
*
*/
public class V8ArrayBuffer extends V8Value {
public ByteBuffer byteBuffer;
/**
* Creates a new V8ArrayBuffer on a given V8Runtime with a
* given capacity.
*
* @param v8 The runtime on which to create the ArrayBuffer
* @param capacity The capacity of the buffer
*/
public V8ArrayBuffer(final V8 v8, final int capacity) {
super(v8);
initialize(v8.getV8RuntimePtr(), capacity);
byteBuffer = v8.createV8ArrayBufferBackingStore(v8.getV8RuntimePtr(), objectHandle, capacity);
byteBuffer.order(ByteOrder.nativeOrder());
}
public V8ArrayBuffer(final V8 v8, ByteBuffer byteBuffer) {
super(v8);
if (byteBuffer == null) {
byteBuffer = ByteBuffer.allocateDirect(0);
}
if (!byteBuffer.isDirect()) {
throw new IllegalArgumentException("ByteBuffer must be a allocated as a direct ByteBuffer");
}
initialize(v8.getV8RuntimePtr(), byteBuffer);
this.byteBuffer = byteBuffer;
byteBuffer.order(ByteOrder.nativeOrder());
}
@Override
protected void initialize(final long runtimePtr, final Object data) {
v8.checkThread();
if (data instanceof ByteBuffer) {
ByteBuffer buffer = (ByteBuffer) data;
int capacity = buffer.limit();
objectHandle = v8.initNewV8ArrayBuffer(v8.getV8RuntimePtr(), buffer, capacity);
} else {
int capacity = (Integer) data;
objectHandle = v8.initNewV8ArrayBuffer(v8.getV8RuntimePtr(), capacity);
}
released = false;
addObjectReference(objectHandle);
}
@Override
protected V8Value createTwin() {
return new V8ArrayBuffer(v8, byteBuffer);
}
/*
* (non-Javadoc)
* @see com.eclipsesource.v8.V8Object#twin()
*/
@Override
public V8ArrayBuffer twin() {
v8.checkThread();
checkReleased();
return (V8ArrayBuffer) super.twin();
}
/**
* Returns the buffers limit
*
* @return the buffers limit
*/
public int limit() {
v8.checkThread();
checkReleased();
return byteBuffer.limit();
}
/**
* Returns the buffers capacity
*
* @return the buffers capacity
*/
public final int capacity() {
v8.checkThread();
checkReleased();
return byteBuffer.capacity();
}
/**
*
* @return
*/
public final int position() {
v8.checkThread();
checkReleased();
return byteBuffer.position();
}
public final V8ArrayBuffer position(final int newPosition) {
v8.checkThread();
checkReleased();
byteBuffer.position(newPosition);
return this;
}
public final V8ArrayBuffer limit(final int newLimit) {
v8.checkThread();
checkReleased();
byteBuffer.limit(newLimit);
return this;
}
public final V8ArrayBuffer mark() {
v8.checkThread();
checkReleased();
byteBuffer.mark();
return this;
}
public final V8ArrayBuffer reset() {
v8.checkThread();
checkReleased();
byteBuffer.reset();
return this;
}
public final V8ArrayBuffer clear() {
v8.checkThread();
checkReleased();
byteBuffer.clear();
return this;
}
public final V8ArrayBuffer flip() {
v8.checkThread();
checkReleased();
byteBuffer.flip();
return this;
}
public final V8ArrayBuffer rewind() {
v8.checkThread();
checkReleased();
byteBuffer.rewind();
return this;
}
public final int remaining() {
v8.checkThread();
checkReleased();
return byteBuffer.remaining();
}
public final boolean hasRemaining() {
v8.checkThread();
checkReleased();
return byteBuffer.hasRemaining();
}
public boolean isReadOnly() {
v8.checkThread();
checkReleased();
return byteBuffer.isReadOnly();
}
public byte get() {
v8.checkThread();
checkReleased();
return byteBuffer.get();
}
public V8ArrayBuffer put(final byte b) {
v8.checkThread();
checkReleased();
byteBuffer.put(b);
return this;
}
public byte get(final int index) {
v8.checkThread();
checkReleased();
return byteBuffer.get(index);
}
public V8ArrayBuffer put(final int index, final byte b) {
v8.checkThread();
checkReleased();
byteBuffer.put(index, b);
return this;
}
public V8ArrayBuffer get(final byte[] dst, final int offset, final int length) {
v8.checkThread();
checkReleased();
byteBuffer.get(dst, offset, length);
return this;
}
public V8ArrayBuffer get(final byte[] dst) {
v8.checkThread();
checkReleased();
byteBuffer.get(dst);
return this;
}
public V8ArrayBuffer put(final ByteBuffer src) {
v8.checkThread();
checkReleased();
byteBuffer.put(src);
return this;
}
public V8ArrayBuffer put(final byte[] src, final int offset, final int length) {
v8.checkThread();
checkReleased();
byteBuffer.put(src, offset, length);
return this;
}
public final V8ArrayBuffer put(final byte[] src) {
v8.checkThread();
checkReleased();
byteBuffer.put(src);
return this;
}
public final boolean hasArray() {
v8.checkThread();
checkReleased();
return byteBuffer.hasArray();
}
public final byte[] array() {
v8.checkThread();
checkReleased();
return byteBuffer.array();
}
public final int arrayOffset() {
v8.checkThread();
checkReleased();
return byteBuffer.arrayOffset();
}
public V8ArrayBuffer compact() {
v8.checkThread();
checkReleased();
byteBuffer.compact();
return this;
}
public boolean isDirect() {
v8.checkThread();
checkReleased();
return byteBuffer.isDirect();
}
public final ByteOrder order() {
v8.checkThread();
checkReleased();
return byteBuffer.order();
}
public final V8ArrayBuffer order(final ByteOrder bo) {
v8.checkThread();
checkReleased();
byteBuffer.order(bo);
return this;
}
public char getChar() {
v8.checkThread();
checkReleased();
return byteBuffer.getChar();
}
public V8ArrayBuffer putChar(final char value) {
v8.checkThread();
checkReleased();
byteBuffer.putChar(value);
return this;
}
public char getChar(final int index) {
v8.checkThread();
checkReleased();
return byteBuffer.getChar(index);
}
public V8ArrayBuffer putChar(final int index, final char value) {
v8.checkThread();
checkReleased();
byteBuffer.putChar(index, value);
return this;
}
public short getShort() {
v8.checkThread();
checkReleased();
return byteBuffer.getShort();
}
public V8ArrayBuffer putShort(final short value) {
v8.checkThread();
checkReleased();
byteBuffer.putShort(value);
return this;
}
public short getShort(final int index) {
v8.checkThread();
checkReleased();
return byteBuffer.getShort(index);
}
public V8ArrayBuffer putShort(final int index, final short value) {
v8.checkThread();
checkReleased();
byteBuffer.putShort(index, value);
return this;
}
public int getInt() {
v8.checkThread();
checkReleased();
return byteBuffer.getInt();
}
public V8ArrayBuffer putInt(final int value) {
v8.checkThread();
checkReleased();
byteBuffer.putInt(value);
return this;
}
public int getInt(final int index) {
v8.checkThread();
checkReleased();
return byteBuffer.getInt(index);
}
public V8ArrayBuffer putInt(final int index, final int value) {
v8.checkThread();
checkReleased();
byteBuffer.asIntBuffer().put(index, value);
return this;
}
public long getLong() {
v8.checkThread();
checkReleased();
return byteBuffer.getLong();
}
public V8ArrayBuffer putLong(final long value) {
v8.checkThread();
checkReleased();
byteBuffer.putLong(value);
return this;
}
public long getLong(final int index) {
v8.checkThread();
checkReleased();
return byteBuffer.getLong(index);
}
public V8ArrayBuffer putLong(final int index, final long value) {
v8.checkThread();
checkReleased();
byteBuffer.putLong(index, value);
return this;
}
public float getFloat() {
v8.checkThread();
checkReleased();
return byteBuffer.getFloat();
}
public V8ArrayBuffer putFloat(final float value) {
v8.checkThread();
checkReleased();
byteBuffer.putFloat(value);
return this;
}
public float getFloat(final int index) {
v8.checkThread();
checkReleased();
return byteBuffer.getFloat(index);
}
public V8ArrayBuffer putFloat(final int index, final float value) {
v8.checkThread();
checkReleased();
byteBuffer.putFloat(index, value);
return this;
}
public double getDouble() {
v8.checkThread();
checkReleased();
return byteBuffer.getDouble();
}
public V8ArrayBuffer putDouble(final double value) {
v8.checkThread();
checkReleased();
byteBuffer.putDouble(value);
return this;
}
public double getDouble(final int index) {
v8.checkThread();
checkReleased();
return byteBuffer.getDouble(index);
}
public V8ArrayBuffer putDouble(final int index, final double value) {
v8.checkThread();
checkReleased();
byteBuffer.putDouble(index, value);
return this;
}
public int floatLimit() {
v8.checkThread();
checkReleased();
return byteBuffer.asFloatBuffer().limit();
}
public int intLimit() {
v8.checkThread();
checkReleased();
return byteBuffer.asIntBuffer().limit();
}
public int shortLimit() {
v8.checkThread();
checkReleased();
return byteBuffer.asShortBuffer().limit();
}
public int doubleLimit() {
v8.checkThread();
checkReleased();
return byteBuffer.asDoubleBuffer().limit();
}
}

98
fine-j2v8/src/main/java/com/eclipsesource/v8/V8Function.java

@ -0,0 +1,98 @@
/*******************************************************************************
* Copyright (c) 2015 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;
/**
* A V8Value that represents a JavaScript function.
* JavaScript functions cannot be created in Java, but
* can be returned as the result of invoking a JS script
* or JS Function.
*/
public class V8Function extends V8Object {
/**
* Create a JavaScript function, that when invoked will call
* the javaCallback passed to the receiver.
*
* @param v8 The v8 runtime on which to create this function
* @param javaCallback The callback to invoke
*/
public V8Function(final V8 v8, final JavaCallback javaCallback) {
super(v8, javaCallback);
}
public V8Function(final V8 v8) {
this(v8, null);
}
@Override
protected V8Value createTwin() {
return new V8Function(v8);
}
/*
* (non-Javadoc)
* @see com.eclipsesource.v8.V8Object#toString()
*/
@Override
public String toString() {
if (released || v8.isReleased()) {
return "[Function released]";
}
return super.toString();
}
@Override
protected void initialize(final long runtimePtr, final Object data) {
if (data == null) {
super.initialize(runtimePtr, null);
return;
}
JavaCallback javaCallback = (JavaCallback) data;
long[] pointers = v8.initNewV8Function(runtimePtr);
// position 0 is the object reference, position 1 is the function reference
v8.createAndRegisterMethodDescriptor(javaCallback, pointers[1]);
released = false;
addObjectReference(pointers[0]);
}
/*
* (non-Javadoc)
* @see com.eclipsesource.v8.V8Object#twin()
*/
@Override
public V8Function twin() {
return (V8Function) super.twin();
}
/**
* Invoke the JavaScript function on the current runtime.
*
* @param receiver The object on which to call the function on. The
* receiver will be mapped to 'this' in JavaScript. If receiver is null
* or undefined, then the V8 runtime will be used instead.
* @param parameters The parameters passed to the JS Function.
*
* @return The result of JavaScript function.
*/
@SuppressWarnings("resource")
public Object call(V8Object receiver, final V8Array parameters) {
v8.checkThread();
checkReleased();
v8.checkRuntime(receiver);
v8.checkRuntime(parameters);
receiver = receiver != null ? receiver : v8;
long parametersHandle = parameters == null ? 0 : parameters.getHandle();
long receiverHandle = receiver.isUndefined() ? v8.getHandle() : receiver.getHandle();
return v8.executeFunction(v8.getV8RuntimePtr(), receiverHandle, objectHandle, parametersHandle);
}
}

113
fine-j2v8/src/main/java/com/eclipsesource/v8/V8Locker.java

@ -0,0 +1,113 @@
/*******************************************************************************
* Copyright (c) 2015 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;
/**
* Represents a lock for a V8Runtime that can be moved between
* threads. When instantiated, the lock is automatically assigned
* to the current thread. If another thread wishes to acquire the
* lock, it must first be released.
*/
public class V8Locker {
private Thread thread = null;
private boolean released = false;
private V8 runtime;
public V8Locker(final V8 runtime) {
this.runtime = runtime;
acquire();
}
/**
* Returns the current thread associated with locker.
*
* @return The currently locked thread.
*/
public Thread getThread() {
return thread;
}
/**
* Acquire the lock if it's currently not acquired by another
* thread. If it's currently held by another thread, an
* Error will be thrown.
*/
public synchronized void acquire() {
if ((thread != null) && (thread != Thread.currentThread())) {
throw new Error("Invalid V8 thread access: current thread is " + Thread.currentThread() + " while the locker has thread " + thread);
} else if ((thread == Thread.currentThread())) {
return;
}
runtime.acquireLock(runtime.getV8RuntimePtr());
thread = Thread.currentThread();
released = false;
}
/**
* Acquire the lock if it's currently not acquired by another
* thread. If it's currently held by another thread, tryAcquire
* will return false, otherwise true is returned.
*
* @return Returns true if the lock was acquired, false otherwise.
*/
public synchronized boolean tryAcquire() {
if ((thread != null) && (thread != Thread.currentThread())) {
return false;
} else if (thread == Thread.currentThread()) {
return true;
}
runtime.acquireLock(runtime.getV8RuntimePtr());
thread = Thread.currentThread();
released = false;
return true;
}
/**
* Release the lock if it's currently held by the calling thread.
* If the current thread does not hold the lock, and error will be
* thrown. If no thread holds the lock then nothing will happen.
*/
public synchronized void release() {
if ((released && (thread == null)) || runtime.isReleased()) {
return;
}
checkThread();
runtime.releaseLock(runtime.getV8RuntimePtr());
thread = null;
released = true;
}
/**
* Checks if the locker has access to the current thread.
* If the locker holds a different thread, than an Error
* is thrown.
*/
public void checkThread() {
if(released && (thread == null)){
throw new Error("Invalid V8 thread access: the locker has been released!");
}
if ((thread != Thread.currentThread())) {
throw new Error("Invalid V8 thread access: current thread is " + Thread.currentThread() + " while the locker has thread " + thread);
}
}
/**
* Check if the current thread holds this lock.
*
* @return Returns true if the current thread holds the lock,
* false otherwise.
*/
public boolean hasLock() {
return thread == Thread.currentThread();
}
}

1005
fine-j2v8/src/main/java/com/eclipsesource/v8/V8Object.java

File diff suppressed because it is too large Load Diff

32
fine-j2v8/src/main/java/com/eclipsesource/v8/V8ResultUndefined.java

@ -0,0 +1,32 @@
/*******************************************************************************
* 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;
/**
* An exception that's used to indicate that method that should have returned a
* primitive, returned an Undefined instead.
*
* In Java, Undefined cannot be returned for all methods, especially if
* the method returns a primitive (int, double, boolean) or a String.
* In this case, if an Undefined should be returned from JS, then an instance
* of this exception is thrown.
*/
@SuppressWarnings("serial")
public class V8ResultUndefined extends V8RuntimeException {
V8ResultUndefined(final String message) {
super(message);
}
V8ResultUndefined() {
super();
}
}

27
fine-j2v8/src/main/java/com/eclipsesource/v8/V8RuntimeException.java

@ -0,0 +1,27 @@
/*******************************************************************************
* 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;
/**
* A top-level exception used to indicate that a script failed. In most cases
* a more specific exception will be thrown.
*/
@SuppressWarnings("serial")
public class V8RuntimeException extends RuntimeException {
V8RuntimeException() {
}
V8RuntimeException(final String message) {
super(message);
}
}

24
fine-j2v8/src/main/java/com/eclipsesource/v8/V8ScriptCompilationException.java

@ -0,0 +1,24 @@
/*******************************************************************************
* 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;
/**
* An exception used to indicate that a script failed to compile.
*/
@SuppressWarnings("serial")
public class V8ScriptCompilationException extends V8ScriptException {
public V8ScriptCompilationException(final String fileName, final int lineNumber,
final String message, final String sourceLine, final int startColumn, final int endColumn) {
super(fileName, lineNumber, message, sourceLine, startColumn, endColumn, null, null);
}
}

165
fine-j2v8/src/main/java/com/eclipsesource/v8/V8ScriptException.java

@ -0,0 +1,165 @@
/*******************************************************************************
* 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;
/**
* An exception that indicates that the execution of a script failed.
* Details about the exception, such as the line number, stack trace, and
* message can retrieved using the accessors.
*/
@SuppressWarnings("serial")
public abstract class V8ScriptException extends V8RuntimeException {
private final String fileName;
private final int lineNumber;
private final String jsMessage;
private final String sourceLine;
private final int startColumn;
private final int endColumn;
private final String jsStackTrace;
V8ScriptException(final String fileName,
final int lineNumber,
final String jsMessage,
final String sourceLine,
final int startColumn,
final int endColumn,
final String jsStackTrace,
final Throwable cause) {
this.fileName = fileName;
this.lineNumber = lineNumber;
this.jsMessage = jsMessage;
this.sourceLine = sourceLine;
this.startColumn = startColumn;
this.endColumn = endColumn;
this.jsStackTrace = jsStackTrace;
if (cause != null) {
initCause(cause);
}
}
/**
* Get the JavaScript Stack as a String.
*
* @return The JavaScript stack.
*/
public String getJSStackTrace() {
return jsStackTrace;
}
/**
* Get the file name contains the script that was currently executing.
*
* @return The file name that contains the script.
*/
public String getFileName() {
return fileName;
}
/**
* Get the line number that the failure occurred on.
*
* @return The line number the failure occurred on.
*/
public int getLineNumber() {
return lineNumber;
}
/**
* Get the JavaScript column where the error begins.
*
* @return The JavaScript column where the error begins.
*/
public int getStartColumn() {
return startColumn;
}
/**
* Get the JavaScript column where the error ends.
*
* @return The JavaScript column where the error ends.
*/
public int getEndColumn() {
return endColumn;
}
/**
* Get the JavaScript line of source that caused the error.
*
* @return The JavaScript line of source that caused the error.
*/
public String getSourceLine() {
return sourceLine;
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(createMessageLine());
result.append(createMessageDetails());
result.append(createJSStackDetails());
result.append("\n");
result.append(this.getClass().getName());
return result.toString();
}
/*
* (non-Javadoc)
* @see java.lang.Throwable#getMessage()
*/
@Override
public String getMessage() {
return createMessageLine();
}
/**
* Get the message set by the JavaScript exception.
*
* @return The message set by the JavaScript exception.
*/
public String getJSMessage() {
return jsMessage;
}
private String createMessageLine() {
return fileName + ":" + lineNumber + ": " + jsMessage;
}
private String createJSStackDetails() {
if (jsStackTrace != null) {
return "\n" + jsStackTrace;
}
return "";
}
private String createMessageDetails() {
StringBuilder result = new StringBuilder();
if ((sourceLine != null) && !sourceLine.isEmpty()) {
result.append('\n');
result.append(sourceLine);
result.append('\n');
if (startColumn >= 0) {
result.append(createCharSequence(startColumn, ' '));
result.append(createCharSequence(endColumn - startColumn, '^'));
}
}
return result.toString();
}
private char[] createCharSequence(final int length, final char c) {
char[] result = new char[length];
for (int i = 0; i < length; i++) {
result[i] = c;
}
return result;
}
}

40
fine-j2v8/src/main/java/com/eclipsesource/v8/V8ScriptExecutionException.java

@ -0,0 +1,40 @@
/*******************************************************************************
* 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;
/**
* An exception used to indicate that a script failed to execute.
*/
@SuppressWarnings("serial")
public class V8ScriptExecutionException extends V8ScriptException {
V8ScriptExecutionException(final String fileName,
final int lineNumber,
final String message,
final String sourceLine,
final int startColumn,
final int endColumn,
final String jsStackTrace) {
this(fileName, lineNumber, message, sourceLine, startColumn, endColumn, jsStackTrace, null);
}
public V8ScriptExecutionException(final String fileName,
final int lineNumber,
final String message,
final String sourceLine,
final int startColumn,
final int endColumn,
final String jsStackTrace,
final Throwable cause) {
super(fileName, lineNumber, message, sourceLine, startColumn, endColumn, jsStackTrace, cause);
}
}

183
fine-j2v8/src/main/java/com/eclipsesource/v8/V8TypedArray.java

@ -0,0 +1,183 @@
/*******************************************************************************
* Copyright (c) 2016 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;
/**
* A representation of a JS TypedArray in Java. The typed array is simply a 'view' onto
* a back buffer.
*/
public class V8TypedArray extends V8Array {
/**
* Create a new TypedArray from a specified ArrayBuffer, type, offset and size. For
* example, a V8Int32Array is a typed array where each value is a 32-bit integer. The
* typed array is backed by the V8ArrayBuffer.
*
* @param v8 The V8Runtime on which to create this Int32Array
* @param type The type of Array to create. Currently Integer and Byte are supported.
* @param buffer The buffer used to back the typed array
* @param offset The offset into the buffer at which to start the the array
* @param size The size of the typed array
*/
public V8TypedArray(final V8 v8, final V8ArrayBuffer buffer, final int type, final int offset, final int size) {
super(v8, new V8ArrayData(buffer, offset, size, type));
}
private V8TypedArray(final V8 v8) {
super(v8);
}
@Override
protected V8Value createTwin() {
v8.checkThread();
checkReleased();
return new V8TypedArray(v8);
}
@Override
public Object get(final int index) {
v8.checkThread();
checkReleased();
int type = getType();
switch (type) {
case FLOAT_32_ARRAY:
return ((Number) super.get(index)).floatValue();
case FLOAT_64_ARRAY:
return super.get(index);
case INT_32_ARRAY:
return super.get(index);
case INT_16_ARRAY:
return ((Number) super.get(index)).shortValue();
case INT_8_ARRAY:
return ((Number) super.get(index)).byteValue();
case UNSIGNED_INT_16_ARRAY:
return 0xFFFF & (Integer) super.get(index);
case UNSIGNED_INT_32_ARRAY:
return 0x00000000FFFFFFFF & ((Number) super.get(index)).longValue();
case UNSIGNED_INT_8_CLAMPED_ARRAY:
return (short) (0x00FF & ((Number) super.get(index)).byteValue());
case UNSIGNED_INT_8_ARRAY:
return (short) (0x00FF & ((Number) super.get(index)).shortValue());
}
return null;
}
/**
* Provide access to the underlying ByteBuffer used for this TypedArray.
* The V8ArrayBuffer must be released.
*
* @return The V8ArrayBuffer used to back this TypedArray.
*/
public V8ArrayBuffer getBuffer() {
return (V8ArrayBuffer) get("buffer");
}
@Override
protected void initialize(final long runtimePtr, final Object data) {
v8.checkThread();
if (data == null) {
super.initialize(runtimePtr, data);
return;
}
V8ArrayData arrayData = (V8ArrayData) data;
checkArrayProperties(arrayData);
long handle = createTypedArray(runtimePtr, arrayData);
released = false;
addObjectReference(handle);
}
private long createTypedArray(final long runtimePtr, final V8ArrayData arrayData) {
switch (arrayData.type) {
case V8Value.FLOAT_32_ARRAY:
return v8.initNewV8Float32Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size);
case V8Value.FLOAT_64_ARRAY:
return v8.initNewV8Float64Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size);
case V8Value.UNSIGNED_INT_32_ARRAY:
return v8.initNewV8UInt32Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size);
case V8Value.INT_16_ARRAY:
return v8.initNewV8Int16Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size);
case V8Value.UNSIGNED_INT_16_ARRAY:
return v8.initNewV8UInt16Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size);
case V8Value.INTEGER:
return v8.initNewV8Int32Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size);
case V8Value.UNSIGNED_INT_8_ARRAY:
return v8.initNewV8UInt8Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size);
case V8Value.INT_8_ARRAY:
return v8.initNewV8Int8Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size);
case V8Value.UNSIGNED_INT_8_CLAMPED_ARRAY:
return v8.initNewV8UInt8ClampedArray(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size);
default:
throw new IllegalArgumentException("Cannot create a typed array of type " + V8Value.getStringRepresentation(arrayData.type));
}
}
/**
* Computes the size of the structures required for each TypedArray variation.
*
* @param type The type of the TypeArray
* @return The size of the structures required
*/
public static int getStructureSize(final int type) {
switch (type) {
case V8Value.FLOAT_64_ARRAY:
return 8;
case V8Value.INT_32_ARRAY:
case V8Value.UNSIGNED_INT_32_ARRAY:
case V8Value.FLOAT_32_ARRAY:
return 4;
case V8Value.UNSIGNED_INT_16_ARRAY:
case V8Value.INT_16_ARRAY:
return 2;
case V8Value.INT_8_ARRAY:
case V8Value.UNSIGNED_INT_8_ARRAY:
case V8Value.UNSIGNED_INT_8_CLAMPED_ARRAY:
return 1;
default:
throw new IllegalArgumentException("Cannot create a typed array of type " + V8Value.getStringRepresentation(type));
}
}
private void checkArrayProperties(final V8ArrayData arrayData) {
checkOffset(arrayData);
checkSize(arrayData);
}
private void checkSize(final V8ArrayData arrayData) {
if (arrayData.size < 0) {
throw new IllegalStateException("RangeError: Invalid typed array length");
}
int limit = (arrayData.size * getStructureSize(arrayData.type)) + arrayData.offset;
if (limit > arrayData.buffer.limit()) {
throw new IllegalStateException("RangeError: Invalid typed array length");
}
}
private void checkOffset(final V8ArrayData arrayData) {
if ((arrayData.offset % getStructureSize(arrayData.type)) != 0) {
throw new IllegalStateException("RangeError: Start offset of Int32Array must be a multiple of " + getStructureSize(arrayData.type));
}
}
private static class V8ArrayData {
private V8ArrayBuffer buffer;
private int offset;
private int size;
private int type;
public V8ArrayData(final V8ArrayBuffer buffer, final int offset, final int size, final int type) {
this.buffer = buffer;
this.offset = offset;
this.size = size;
this.type = type;
}
}
}

393
fine-j2v8/src/main/java/com/eclipsesource/v8/V8Value.java

@ -0,0 +1,393 @@
/*******************************************************************************
* 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;
/**
* A base class for all V8 resources. V8 resources must
* be closed/released. The rules for releasing resources is as
* follows:
* <p>
* 1. If you created it, you must close it, with one exception;
* if the object is being passed pack via a return statement,
* the system will release it for you.
* <p>
* 2. If the system created it, you dont need to worry about it,
* with one caveat; if the object was returned to you as a
* result of a method call, you must close it.
*/
abstract public class V8Value implements Releasable {
public static final int NULL = 0;
public static final int UNKNOWN = 0;
public static final int INTEGER = 1;
public static final int INT_32_ARRAY = 1;
public static final int DOUBLE = 2;
public static final int FLOAT_64_ARRAY = 2;
public static final int BOOLEAN = 3;
public static final int STRING = 4;
public static final int V8_ARRAY = 5;
public static final int V8_OBJECT = 6;
public static final int V8_FUNCTION = 7;
public static final int V8_TYPED_ARRAY = 8;
public static final int BYTE = 9;
public static final int INT_8_ARRAY = 9;
public static final int V8_ARRAY_BUFFER = 10;
public static final int UNSIGNED_INT_8_ARRAY = 11;
public static final int UNSIGNED_INT_8_CLAMPED_ARRAY = 12;
public static final int INT_16_ARRAY = 13;
public static final int UNSIGNED_INT_16_ARRAY = 14;
public static final int UNSIGNED_INT_32_ARRAY = 15;
public static final int FLOAT_32_ARRAY = 16;
public static final int UNDEFINED = 99;
protected V8 v8;
protected long objectHandle;
protected boolean released = true;
protected V8Value() {
super();
}
protected V8Value(final V8 v8) {
if (v8 == null) {
this.v8 = (V8) this;
} else {
this.v8 = v8;
}
}
protected void initialize(final long runtimePtr, final Object data) {
long objectHandle = v8.initNewV8Object(runtimePtr);
released = false;
addObjectReference(objectHandle);
}
protected void addObjectReference(final long objectHandle) throws Error {
this.objectHandle = objectHandle;
try {
v8.addObjRef(this);
} catch (Error e) {
release();
throw e;
} catch (RuntimeException e) {
release();
throw e;
}
}
/**
* Returns a string representation of the V8 Type.
*
* @param type Type to return as a string. See constants in V8Value.
* @return The V8Value type as a string.
* @deprecated Use
*/
@Deprecated
public static String getStringRepresentaion(final int type) {
return getStringRepresentation(type);
}
/**
* Returns a string representation of the V8 Type.
*
* @param type Type to return as a string. See constants in V8Value.
* @return The V8Value type as a string.
*/
public static String getStringRepresentation(final int type) {
switch (type) {
case NULL:
return "Null";
case INTEGER:
return "Integer";
case DOUBLE:
return "Double";
case BOOLEAN:
return "Boolean";
case STRING:
return "String";
case V8_ARRAY:
return "V8Array";
case V8_OBJECT:
return "V8Object";
case V8_FUNCTION:
return "V8Function";
case V8_TYPED_ARRAY:
return "V8TypedArray";
case BYTE:
return "Byte";
case V8_ARRAY_BUFFER:
return "V8ArrayBuffer";
case UNSIGNED_INT_8_ARRAY:
return "UInt8Array";
case UNSIGNED_INT_8_CLAMPED_ARRAY:
return "UInt8ClampedArray";
case INT_16_ARRAY:
return "Int16Array";
case UNSIGNED_INT_16_ARRAY:
return "UInt16Array";
case UNSIGNED_INT_32_ARRAY:
return "UInt32Array";
case FLOAT_32_ARRAY:
return "Float32Array";
case UNDEFINED:
return "Undefined";
default:
throw new IllegalArgumentException("Invalid V8 type: " + type);
}
}
/**
* Returns a constructor name of the V8 Value.
*
* @return The V8Value constructor name as a string.
*/
public String getConstructorName() {
v8.checkThread();
v8.checkReleased();
return v8.getConstructorName(v8.getV8RuntimePtr(), objectHandle);
}
/**
* Determines if this value is undefined.
*
* @return Returns true if the value is undefined, false otherwise
*/
public boolean isUndefined() {
return false;
}
/**
* Gets the runtime this Value was created on.
*
* @return Returns the V8 runtime this value is associated with.
*/
public V8 getRuntime() {
return v8;
}
/**
* Returns the 'type' of this V8Value. The available types are defined
* as constants in {@link V8Value}. Only types that inherit from
* {@link V8Value} can be returned here.
*
* @return The 'type of this V8Value.
*/
public int getV8Type() {
if (isUndefined()) {
return UNDEFINED;
}
v8.checkThread();
v8.checkReleased();
return v8.getType(v8.getV8RuntimePtr(), objectHandle);
}
/**
* Creates a new Java object pointing at the same V8 Value
* as this. If the value is mutated (by adding new members or
* changing existing ones) then both the original and twin
* will be updated. Twins are .equal and .strict equals, but
* not == in Java.
* <p>
* Twins must be closed separately since they have their own
* native resources.
*
* @return A new Java object pointing at the same V8 Value
* as this.
*/
public V8Value twin() {
if (isUndefined()) {
return this;
}
v8.checkThread();
v8.checkReleased();
V8Value twin = createTwin();
v8.createTwin(this, twin);
return twin;
}
/**
* Sets the V8Value as weak reference. A weak reference will eventually
* be closed when no more references exist to this object. Once setWeak
* is called, you should check if {@link V8Value#isReleased()} is true
* before invoking any methods on this object.
* <p>
* If any other references exist to this object, the object will not be
* reclaimed. Even if no reference exist, V8 does not give any guarantee
* the object will be closed, so this should only be used if there is no
* other way to track object usage.
*
* @return The receiver.
*/
public V8Value setWeak() {
v8.checkThread();
v8.checkReleased();
v8.v8WeakReferences.put(getHandle(), this);
v8.setWeak(v8.getV8RuntimePtr(), getHandle());
return this;
}
/**
* Clears any weak reference set on this V8Value and makes this a strong
* reference. Strong references will not be garbage collected and this
* Object must be explicitly released.
* <p>
* Calling clearWeak does nothing if the object is not currently set
* to weak.
*
* @return The receiver.
*/
public V8Value clearWeak() {
v8.checkThread();
v8.checkReleased();
v8.v8WeakReferences.remove(getHandle());
v8.clearWeak(v8.getV8RuntimePtr(), getHandle());
return this;
}
/**
* If {@link V8Value#setWeak()} has been called on this Object, this method
* will return true. Otherwise it will return false.
*
* @return Returns true if this object has been set 'Weak', return false otherwise.
*/
public boolean isWeak() {
v8.checkThread();
v8.checkReleased();
return v8.isWeak(v8.getV8RuntimePtr(), getHandle());
}
/*
* (non-Javadoc)
* @see java.io.Closeable#close()
*/
@Override
public void close() {
v8.checkThread();
if (!released) {
try {
v8.releaseObjRef(this);
} finally {
released = true;
v8.release(v8.getV8RuntimePtr(), objectHandle);
}
}
}
/**
* Releases the native resources associated with this V8Value.
*
* @deprecated use close() instead.
*/
@Override
@Deprecated
public void release() {
close();
}
/**
* Determine if the native resources have been released. Once released
* a V8 Value can no longer be used.
*
* @return Returns true if this object has been released, false otherwise.
*/
public boolean isReleased() {
return released;
}
/**
* Performs a JS === on the parameter and the receiver.
*
* @param that The Object to compare this object against.
* @return Returns true iff this === that
*/
public boolean strictEquals(final Object that) {
v8.checkThread();
checkReleased();
if (that == this) {
return true;
}
if (that == null) {
return false;
}
if (!(that instanceof V8Value)) {
return false;
}
if (isUndefined() && ((V8Value) that).isUndefined()) {
return true;
}
if (((V8Value) that).isUndefined()) {
return false;
}
return v8.strictEquals(v8.getV8RuntimePtr(), getHandle(), ((V8Value) that).getHandle());
}
protected long getHandle() {
checkReleased();
return objectHandle;
}
protected abstract V8Value createTwin();
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object that) {
return strictEquals(that);
}
/**
* Performs a JS == on the parameter and the receiver.
*
* @param that The Object to compare this object against.
* @return Returns true iff this == that
*/
public boolean jsEquals(final Object that) {
v8.checkThread();
checkReleased();
if (that == this) {
return true;
}
if (that == null) {
return false;
}
if (!(that instanceof V8Value)) {
return false;
}
if (isUndefined() && ((V8Value) that).isUndefined()) {
return true;
}
if (((V8Value) that).isUndefined()) {
return false;
}
return v8.equals(v8.getV8RuntimePtr(), getHandle(), ((V8Value) that).getHandle());
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
v8.checkThread();
checkReleased();
return v8.identityHash(v8.getV8RuntimePtr(), getHandle());
}
protected void checkReleased() {
if (released) {
throw new IllegalStateException("Object released");
}
}
}

69
fine-j2v8/src/main/java/com/eclipsesource/v8/utils/ArrayBuffer.java

@ -0,0 +1,69 @@
package com.eclipsesource.v8.utils;
/*******************************************************************************
* Copyright (c) 2019 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
******************************************************************************/
import java.nio.ByteBuffer;
import com.eclipsesource.v8.V8;
import com.eclipsesource.v8.V8ArrayBuffer;
/**
* A lightweight handle to a V8TypedArray. This handle provides
* access to a V8TypedArray. This handle does not need to be
* closed, but if the type array is accessed using getV8TypedArray
* then the result must be closed.
*
* The underlying V8TypedArray may be reclaimed by the JavaScript
* garbage collector. To check if it's still available, use
* isAvailable.
*/
public class ArrayBuffer {
private V8ArrayBuffer arrayBuffer;
ArrayBuffer(final V8ArrayBuffer arrayBuffer) {
this.arrayBuffer = (V8ArrayBuffer) arrayBuffer.twin().setWeak();
}
/**
* Create a new ArrayBuffer from a java.nio.ByteBuffer
*
* @param v8 the Runtime on which to create the ArrayBuffer
* @param byteBuffer the ByteBuffer to use to back the ArrayBuffer
*/
public ArrayBuffer(final V8 v8, final ByteBuffer byteBuffer) {
V8ArrayBuffer v8ArrayBuffer = new V8ArrayBuffer(v8, byteBuffer);
try {
arrayBuffer = (V8ArrayBuffer) v8ArrayBuffer.twin().setWeak();
} finally {
v8ArrayBuffer.close();
}
}
/**
* Determine if the underlying V8ArrayBuffer is still available, or if it's been cleaned up by the JavaScript
* garbage collector.
*
* @return true if the underlying V8ArrayBuffer is still available, false otherwise.
*/
public boolean isAvailable() {
return !arrayBuffer.isReleased();
}
/**
* Returns the underlying V8ArrayBuffer.
* @return the underlying V8ArrayBuffer.
*/
public V8ArrayBuffer getV8ArrayBuffer() {
return arrayBuffer.twin();
}
}

94
fine-j2v8/src/main/java/com/eclipsesource/v8/utils/ConcurrentV8.java

@ -0,0 +1,94 @@
/*******************************************************************************
* Copyright (c) 2016 Brandon Sanders
* 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:
* Brandon Sanders - initial API and implementation and/or initial documentation
******************************************************************************/
package com.eclipsesource.v8.utils;
import com.eclipsesource.v8.V8;
/**
* Wrapper class for an {@link V8} instance that allows
* a V8 instance to be invoked from across threads without explicitly acquiring
* or releasing locks.
*
* This class does not guarantee the safety of any objects stored in or accessed
* from the wrapped V8 instance; it only enables callers to interact with a V8
* instance from any thread. The V8 instance represented by this class should
* still be treated with thread safety in mind
*
* @author Brandon Sanders [brandon@alicorn.io]
* @author R. Ian Bull - Additional API
*/
public final class ConcurrentV8 {
private V8 v8 = null;
/**
* Create a new ConcurrentV8. A ConcurrentV8 allows multiple
* threads to work with the same V8 engine by releasing
* the locks between calls.
*/
public ConcurrentV8() {
v8 = V8.createV8Runtime();
v8.getLocker().release();
}
/**
* Returns the V8 runtime backing by this ConcurrentV8
*
* @return The V8 runtime backing this ConcurrentV8
*/
public V8 getV8() {
return v8;
}
/**
* Runs an {@link V8Runnable} on the V8 thread.
*
* <b>Note: </b> This method executes synchronously, not asynchronously;
* it will not return until the passed {@link V8Runnable} is done
* executing. The method is also synchronized, so it will block until it
* gets a chance to run.
*
* @param runnable {@link V8Runnable} to run.
*/
public synchronized void run(final V8Runnable runnable) {
try {
v8.getLocker().acquire();
runnable.run(v8);
} finally {
if ((v8 != null) && (v8.getLocker() != null) && v8.getLocker().hasLock()) {
v8.getLocker().release();
}
}
}
/**
* Releases the underlying {@link V8} instance.
*
* This method should be invoked once you're done using this object,
* otherwise a large amount of garbage could be left on the JVM due to
* native resources.
*
* <b>Note:</b> If this method has already been called once, it
* will do nothing.
*/
public void release() {
if ((v8 != null) && !v8.isReleased()) {
// Release the V8 instance from the V8 thread context.
run(new V8Runnable() {
@Override
public void run(final V8 v8) {
if ((v8 != null) && !v8.isReleased()) {
v8.close();
}
}
});
}
}
}

138
fine-j2v8/src/main/java/com/eclipsesource/v8/utils/MemoryManager.java

@ -0,0 +1,138 @@
/*******************************************************************************
* Copyright (c) 2016 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.utils;
import java.util.ArrayList;
import java.util.Iterator;
import com.eclipsesource.v8.ReferenceHandler;
import com.eclipsesource.v8.V8;
import com.eclipsesource.v8.V8Value;
/**
* A memory manager that tracks all V8 Handles while the object is registered.
* Once released, all V8 handles that were created while the memory manager
* was active, will be released.
*
* It is important that no V8 handles (V8Objects, V8Arrays, etc...) that are
* created while the memory manager is active, are persisted.
*
*/
public class MemoryManager {
private MemoryManagerReferenceHandler memoryManagerReferenceHandler;
private V8 v8;
private ArrayList<V8Value> references = new ArrayList<V8Value>();
private boolean releasing = false;
private boolean released = false;
/**
* Creates and registered a Memory Manager. After this, all V8 handles will be
* tracked until release is called.
*
* @param v8 The V8 runtime to register this Memory Manager on
*/
public MemoryManager(final V8 v8) {
this.v8 = v8;
memoryManagerReferenceHandler = new MemoryManagerReferenceHandler();
v8.addReferenceHandler(memoryManagerReferenceHandler);
}
/**
* Returns the number of handles currently being tracked by this
* memory manager.
*
* Throws an IllegalStateException if the memory manager is used after it's
* been released.
*
* @return The object reference count
*/
public int getObjectReferenceCount() {
checkReleased();
return references.size();
}
/**
* Persist an object that is currently being managed by this Manager.
*
* Objects that are being managed by a MemoryManager will be released
* once the MemoryManager is released. If an object is persisted, it will
* be remove from the MemoryManager's control and therefore will not
* be released.
*
* @param object The object to persist
*/
public void persist(final V8Value object) {
v8.getLocker().checkThread();
checkReleased();
references.remove(object);
}
/**
* Checks if the memory manager has been released or not. Released memory
* managers can no longer be used.
*
* @return True if this memory manager has been released, false otherwise.
*/
public boolean isReleased() {
return released;
}
/**
* Releases this Memory Manager and all V8Objects that were created while
* this memory manager was active.
*/
public void release() {
v8.getLocker().checkThread();
if (released) {
return;
}
releasing = true;
try {
for (V8Value reference : references) {
reference.close();
}
v8.removeReferenceHandler(memoryManagerReferenceHandler);
references.clear();
} finally {
releasing = false;
}
released = true;
}
private void checkReleased() {
if (released) {
throw new IllegalStateException("Memory manager released");
}
}
private class MemoryManagerReferenceHandler implements ReferenceHandler {
@Override
public void v8HandleCreated(final V8Value object) {
references.add(object);
}
@Override
public void v8HandleDisposed(final V8Value object) {
if (!releasing) {
Iterator<V8Value> iterator = references.iterator();
while (iterator.hasNext()) {
if (iterator.next() == object) {
iterator.remove();
return;
}
}
}
}
}
}

55
fine-j2v8/src/main/java/com/eclipsesource/v8/utils/SingleTypeAdapter.java

@ -0,0 +1,55 @@
/*******************************************************************************
* Copyright (c) 2017 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.utils;
/**
* Adapt all instances of a single type from JavaScript to Java.
* The TypeAdapter can be used with the V8ObjectUtils to allow users to customize
* the conversion.
*/
public abstract class SingleTypeAdapter implements TypeAdapter {
private int typeToAdapt;
/**
* Create a SingleTypeAdapter
*
* @param typeToAdapt The V8 Type this TypeAdapter should be applied to.
*/
public SingleTypeAdapter(final int typeToAdapt) {
this.typeToAdapt = typeToAdapt;
}
/*
* (non-Javadoc)
* @see com.eclipsesource.v8.utils.TypeAdapter#adapt(int, java.lang.Object)
*/
@Override
public Object adapt(final int type, final Object value) {
if (type == typeToAdapt) {
return adapt(value);
}
return TypeAdapter.DEFAULT;
}
/**
* Adapt an object from V8 to Java.
*
* If the value is a V8Value (V8Object) then it will be released after
* this method is called. If you wish to retain the object, call
* ((V8Value)value).twin();
*
* @param value The V8 Object to be converted.
* @return The adapted Java Object or {@link TypeAdapter#DEFAULT} for the default conversion.
*/
public abstract Object adapt(final Object value);
}

39
fine-j2v8/src/main/java/com/eclipsesource/v8/utils/TypeAdapter.java

@ -0,0 +1,39 @@
/*******************************************************************************
* Copyright (c) 2017 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.utils;
/**
* An interface which allows a plug-able conversion from V8Value types to Java objects.
* The TypeAdapter can be used with the V8ObjectUtils to allow users to customize
* the conversion.
*/
public interface TypeAdapter {
/**
* A default adapter that if returned in {@link TypeAdapter#adapt(int, Object)}, will result
* in the default type adaption.
*/
public static final Object DEFAULT = new Object();
/**
* Adapt an object from V8 to Java.
*
* If the value is a V8Value (V8Object) then it will be released after
* this method is called. If you wish to retain the object, call
* ((V8Value)value).twin();
*
* @param type The Type of the object to be adapted.
* @param value The V8 Object to be converted.
* @return The adapted Java Object or {@link TypeAdapter#DEFAULT} for the default conversion.
*/
public Object adapt(int type, Object value);
}

73
fine-j2v8/src/main/java/com/eclipsesource/v8/utils/TypedArray.java

@ -0,0 +1,73 @@
package com.eclipsesource.v8.utils;
/*******************************************************************************
* Copyright (c) 2019 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
******************************************************************************/
import com.eclipsesource.v8.V8;
import com.eclipsesource.v8.V8ArrayBuffer;
import com.eclipsesource.v8.V8TypedArray;
/**
* A lightweight handle to a V8TypedArray. This handle provides
* access to a V8TypedArray. This handle does not need to be
* closed, but if the type array is accessed using getV8TypedArray
* then the result must be closed.
*
* The underlying V8TypedArray may be reclaimed by the JavaScript
* garbage collector. To check if it's still available, use
* isAvailable.
*/
public class TypedArray {
private V8TypedArray typedArray;
TypedArray(final V8TypedArray typedArray) {
this.typedArray = (V8TypedArray) typedArray.twin().setWeak();
}
/**
* Create a new TypedArray from an ArrayBuffer.
*
* @param v8 the V8Runtime on which to create the TypedArray
* @param buffer the ArrayBuffer to use to back the TypedArray
* @param type the Type of Array to create
* @param offset the Offset into the ArrayBuffer in which to map the TyepdArray
* @param size the Size of the TypedArray
*/
public TypedArray(final V8 v8, final ArrayBuffer buffer, final int type, final int offset, final int size) {
V8ArrayBuffer v8ArrayBuffer = buffer.getV8ArrayBuffer();
V8TypedArray v8typedArray = new V8TypedArray(v8, v8ArrayBuffer, type, offset, size);
try {
typedArray = (V8TypedArray) v8typedArray.twin().setWeak();
} finally {
v8ArrayBuffer.close();
v8typedArray.close();
}
}
/**
* Determine if the underlying V8TypedArray is still available, or if it's been cleaned up by the JavaScript
* garbage collector.
*
* @return true if the underlying V8TypedArray is still available, false otherwise.
*/
public boolean isAvailable() {
return !typedArray.isReleased();
}
/**
* Returns the underlying V8TypedArray.
* @return the underlying V8TypedArray.
*/
public V8TypedArray getV8TypedArray() {
return (V8TypedArray) typedArray.twin();
}
}

253
fine-j2v8/src/main/java/com/eclipsesource/v8/utils/V8Executor.java

@ -0,0 +1,253 @@
/*******************************************************************************
* Copyright (c) 2015 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.utils;
import java.util.LinkedList;
import com.eclipsesource.v8.JavaVoidCallback;
import com.eclipsesource.v8.Releasable;
import com.eclipsesource.v8.V8;
import com.eclipsesource.v8.V8Array;
import com.eclipsesource.v8.V8Object;
/**
* Executes a JS Script on a new V8 runtime in its own thread, and once finished,
* will optionally wait on a message queue. If the executor is *not* long running,
* when the JS Script finishes, the executor will shutdown. If the executor
* *is* long running, the the script will execute, and when finished, the executor
* will wait for messages to arrive. When messages arrive, the messageHandler
* will be invoked with the contents of the message.
* <p>
* Executors can be shutdown in two different ways. forceTermination() will
* stop any executing scripts and immediately terminate the executor. shutdown()
* will indicate that the executor should shutdown, but this will only happen
* once any scripts finish executing and the message queue becomes empty.
*/
public class V8Executor extends Thread {
private final String script;
private V8 runtime;
private String result;
private volatile boolean terminated = false;
private volatile boolean shuttingDown = false;
private volatile boolean forceTerminating = false;
private Exception exception = null;
private LinkedList<String[]> messageQueue = new LinkedList<String[]>();
private boolean longRunning;
private String messageHandler;
/**
* Create a new executor and execute the given script on it. Once
* the script has finished executing, the executor can optionally
* wait on a message queue.
*
* @param script The script to execute on this executor.
* @param longRunning True to indicate that this executor should be longRunning.
* @param messageHandler The name of the message handler that should be notified
* when messages are delivered.
*/
public V8Executor(final String script, final boolean longRunning, final String messageHandler) {
this.script = script;
this.longRunning = longRunning;
this.messageHandler = messageHandler;
}
/**
* Create a new executor and execute the given script on it.
*
* @param script The script to execute on this executor.
*/
public V8Executor(final String script) {
this(script, false, null);
}
/**
* Override to provide a custom setup for this V8 runtime.
* This method can be overridden to configure the V8 runtime,
* for example, to add callbacks or to add some additional
* functionality to the global scope.
*
* @param runtime The runtime to configure.
*/
protected void setup(final V8 runtime) {
}
/**
* Gets the result of the JavaScript that was executed
* on this executor.
*
* @return The result of the JS Script that was executed on
* this executor.
*/
public String getResult() {
return result;
}
/**
* Posts a message to the receiver to be processed by the executor
* and sent to the V8 runtime via the messageHandler.
*
* @param message The message to send to the messageHandler
*/
public void postMessage(final String... message) {
synchronized (this) {
messageQueue.add(message);
notify();
}
}
/*
* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run() {
synchronized (this) {
runtime = V8.createV8Runtime();
runtime.registerJavaMethod(new ExecutorTermination(), "__j2v8__checkThreadTerminate");
setup(runtime);
}
try {
if (!forceTerminating) {
Object scriptResult = runtime.executeScript("__j2v8__checkThreadTerminate();\n" + script, getName(), -1);
if (scriptResult != null) {
result = scriptResult.toString();
}
if (scriptResult instanceof Releasable) {
((Releasable) scriptResult).release();
}
}
while (!forceTerminating && longRunning) {
synchronized (this) {
if (messageQueue.isEmpty() && !shuttingDown) {
wait();
}
if ((messageQueue.isEmpty() && shuttingDown) || forceTerminating) {
return;
}
}
if (!messageQueue.isEmpty()) {
String[] message = messageQueue.remove(0);
V8Array parameters = new V8Array(runtime);
V8Array strings = new V8Array(runtime);
try {
for (String string : message) {
strings.push(string);
}
parameters.push(strings);
runtime.executeVoidFunction(messageHandler, parameters);
} finally {
strings.close();
parameters.close();
}
}
}
} catch (Exception e) {
exception = e;
} finally {
synchronized (this) {
if (runtime.getLocker().hasLock()) {
runtime.close();
runtime = null;
}
terminated = true;
}
}
}
/**
* Determines if an exception was thrown during the JavaScript execution.
*
* @return True if an exception was thrown during the JavaScript execution,
* false otherwise.
*/
public boolean hasException() {
return exception != null;
}
/**
* Gets the exception that was thrown during the JavaScript execution.
*
* @return The exception that was thrown during the JavaScript execution,
* or null if no such exception was thrown.
*/
public Exception getException() {
return exception;
}
/**
* Determines if the executor has terminated.
*
* @return True if the executor has terminated, false otherwise.
*/
public boolean hasTerminated() {
return terminated;
}
/**
* Forces the executor to shutdown immediately. Any currently executing
* JavaScript will be interrupted and all outstanding messages will be
* ignored.
*/
public void forceTermination() {
synchronized (this) {
forceTerminating = true;
shuttingDown = true;
if (runtime != null) {
runtime.terminateExecution();
}
notify();
}
}
/**
* Indicates to the executor that it should shutdown. Any currently
* executing JavaScript will be allowed to finish, and any outstanding
* messages will be processed. Only once the message queue is empty,
* will the executor actually shtutdown.
*/
public void shutdown() {
synchronized (this) {
shuttingDown = true;
notify();
}
}
/**
* Returns true if shutdown() or forceTermination() was called to
* shutdown this executor.
*
* @return True if shutdown() or forceTermination() was called, false otherwise.
*/
public boolean isShuttingDown() {
return shuttingDown;
}
/**
* Returns true if forceTermination was called to shutdown
* this executor.
*
* @return True if forceTermination() was called, false otherwise.
*/
public boolean isTerminating() {
return forceTerminating;
}
class ExecutorTermination implements JavaVoidCallback {
@Override
public void invoke(final V8Object receiver, final V8Array parameters) {
if (forceTerminating) {
throw new RuntimeException("V8Thread Termination");
}
}
}
}

185
fine-j2v8/src/main/java/com/eclipsesource/v8/utils/V8Map.java

@ -0,0 +1,185 @@
/*******************************************************************************
* Copyright (c) 2015 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.utils;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.eclipsesource.v8.Releasable;
import com.eclipsesource.v8.V8Value;
/**
* A Map that maps V8Values to arbitrary Java Objects.
* Once stored in the map, the keys (V8Values) can be released
* as the map will handle their resource management for you.
* <p>
* Once the map is no longer needed, it should be released. To
* tie a map to the lifecycle of a V8 runtime, it can be registered
* as a resource with V8.registerResource.
*/
public class V8Map<V> implements Map<V8Value, V>, Releasable {
private Map<V8Value, V> map;
private Map<V8Value, V8Value> twinMap;
/**
* Creates a V8Map.
*/
public V8Map() {
map = new HashMap<V8Value, V>();
twinMap = new HashMap<V8Value, V8Value>();
}
/*
* (non-Javadoc)
* @see java.io.Closeable#close()
*/
@Override
public void close() {
this.clear();
}
/**
* Releases all the resources associated with this map. A
* map can be used again once it's released, although
* if it's used again it should be released again.
*/
@Override
@Deprecated
public void release() {
close();
}
/*
* (non-Javadoc)
* @see java.util.Map#size()
*/
@Override
public int size() {
return map.size();
}
/*
* (non-Javadoc)
* @see java.util.Map#isEmpty()
*/
@Override
public boolean isEmpty() {
return map.isEmpty();
}
/*
* (non-Javadoc)
* @see java.util.Map#containsKey(java.lang.Object)
*/
@Override
public boolean containsKey(final Object key) {
return map.containsKey(key);
}
/*
* (non-Javadoc)
* @see java.util.Map#containsValue(java.lang.Object)
*/
@Override
public boolean containsValue(final Object value) {
return map.containsValue(value);
}
/*
* (non-Javadoc)
* @see java.util.Map#get(java.lang.Object)
*/
@Override
public V get(final Object key) {
return map.get(key);
}
/*
* (non-Javadoc)
* @see java.util.Map#put(java.lang.Object, java.lang.Object)
*/
@Override
public V put(final V8Value key, final V value) {
this.remove(key);
V8Value twin = key.twin();
twinMap.put(twin, twin);
return map.put(twin, value);
}
/*
* (non-Javadoc)
* @see java.util.Map#remove(java.lang.Object)
*/
@Override
public V remove(final Object key) {
V result = map.remove(key);
V8Value twin = twinMap.remove(key);
if (twin != null) {
twin.close();
}
return result;
}
/*
* (non-Javadoc)
* @see java.util.Map#putAll(java.util.Map)
*/
@Override
public void putAll(final Map<? extends V8Value, ? extends V> m) {
for (Entry<? extends V8Value, ? extends V> entry : m.entrySet()) {
this.put(entry.getKey(), entry.getValue());
}
}
/*
* (non-Javadoc)
* @see java.util.Map#clear()
*/
@Override
public void clear() {
map.clear();
for (V8Value V8Value : twinMap.keySet()) {
V8Value.close();
}
twinMap.clear();
}
/*
* (non-Javadoc)
* @see java.util.Map#keySet()
*/
@Override
public Set<V8Value> keySet() {
return map.keySet();
}
/*
* (non-Javadoc)
* @see java.util.Map#values()
*/
@Override
public Collection<V> values() {
return map.values();
}
/*
* (non-Javadoc)
* @see java.util.Map#entrySet()
*/
@Override
public Set<Entry<V8Value, V>> entrySet() {
return map.entrySet();
}
}

690
fine-j2v8/src/main/java/com/eclipsesource/v8/utils/V8ObjectUtils.java

@ -0,0 +1,690 @@
/*******************************************************************************
* 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.utils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.eclipsesource.v8.Releasable;
import com.eclipsesource.v8.V8;
import com.eclipsesource.v8.V8Array;
import com.eclipsesource.v8.V8ArrayBuffer;
import com.eclipsesource.v8.V8Object;
import com.eclipsesource.v8.V8TypedArray;
import com.eclipsesource.v8.V8Value;
/**
* A set of static helper methods to convert V8Objects / V8Arrays to
* java.util Maps and Lists and back again. These conversions
* perform a deep copy.
*/
public class V8ObjectUtils {
private static final Object IGNORE = new Object();
private static final TypeAdapter DEFAULT_TYPE_ADAPTER = new DefaultTypeAdapter();
/**
* Create a Java Object from a result from V8. V8 can return
* basic Java types, or V8Values (V8Object, V8Array, etc...). This method
* will attempt to convert the result into a pure Java object using a
* deep copy.
* <p>
* If the input is basic Java type (Integer, Double, Boolean, String)
* it will be returned. If the input is a V8Value, it will be converted.
* <p>
* All elements in the V8Object are released after they are accessed.
* However, the root object itself is not released.
*
* @param v8Object The input to convert.
* @return A Java object representing the input.
*/
public static Object getValue(final Object v8Object) {
return getValue(v8Object, DEFAULT_TYPE_ADAPTER);
}
/**
* Create a Java Object from a result from V8 using a {@link TypeAdapter} to convert
* objects. V8 can return basic Java types or V8Values (V8Object, V8Array, etc...). This
* method will attempt to convert the result into a pure Java object using
* a deep copy.
* <p>
* If the input is basic Java type (Integer, Double, Boolean, String)
* it will be returned. If the input is a V8Value, it will be converted.
* <p>
* All elements in the V8Object are released after they are accessed.
* However, the root object itself is not released.
*
* @param v8Object The input to convert.
* @param adapter The {@link TypeAdapter} to use for the object conversions.
* @return A Java object representing the input.
*/
public static Object getValue(final Object v8Object, final TypeAdapter adapter) {
V8Map<Object> cache = new V8Map<Object>();
try {
if (v8Object instanceof V8Value) {
int type = ((V8Value) v8Object).getV8Type();
return getValue(v8Object, type, cache, adapter);
} else {
return v8Object;
}
} finally {
cache.close();
}
}
/**
* Creates a Map from a V8Object using a deep copy. All elements
* in the V8Object are released after they are accessed. However, the root
* object itself is not released.
*
* @param object The root of the V8Object graph.
* @return A map representing a deep copy of the V8Object rooted at 'object'.
*/
public static Map<String, ? super Object> toMap(final V8Object object) {
return toMap(object, DEFAULT_TYPE_ADAPTER);
}
/**
* Creates a Map from a V8Object using a deep copy and a TypeAdapter to handle
* type conversions. All elements in the V8Object are released after they are accessed.
* However, the root object itself is not released.
*
* @param object The root of the V8Object graph.
* @param adapter The {@link TypeAdapter} to use for the object conversions.
* @return A map representing a deep copy of the V8Object rooted at 'object'.
*/
public static Map<String, ? super Object> toMap(final V8Object object, final TypeAdapter adapter) {
V8Map<Object> cache = new V8Map<Object>();
try {
return toMap(object, cache, adapter);
} finally {
cache.close();
}
}
/**
* Creates a List from a V8Array using a deep copy. All elements
* in the V8Array are released after they are accessed. However, the root
* array itself is not released.
*
* @param array The root of the V8Array graph.
* @return A list representing a deep copy of the V8Array rooted at 'array'.
*/
public static List<? super Object> toList(final V8Array array) {
return toList(array, DEFAULT_TYPE_ADAPTER);
}
/**
* Creates a List from a V8Array using a deep copy and a TypeAdapter to handle
* type conversions. All elements in the V8Array are released after they are accessed.
* However, the root array itself is not released.
*
* @param array The root of the V8Array graph.
* @param adapter The {@link TypeAdapter} to use for the object conversions.
* @return A list representing a deep copy of the V8Array rooted at 'array'.
*/
public static List<? super Object> toList(final V8Array array, final TypeAdapter adapter) {
V8Map<Object> cache = new V8Map<Object>();
try {
return toList(array, cache, adapter);
} finally {
cache.close();
}
}
/**
* Populates a Java array from a V8Array. The type of the array must be specified.
* Currently, only INTEGER, DOUBLE, BOOLEAN and STRING are supported.
* The V8Array must only contain elements of type 'arrayType'. The result
* can be optionally passed in as a parameter.
* <p>
* This method will use J2V8's bulk array copy making it faster than iterating over
* all the elements in the array.
*
* @param array The V8Array to convert to a Java Array.
* @param arrayType The type of the V8Array to convert.
* @param result The array to use as the result. If null, a new array will be created.
* @return A Java array representing a V8Array.
*/
public static Object getTypedArray(final V8Array array, final int arrayType, final Object result) {
int length = array.length();
if (arrayType == V8Value.INTEGER) {
int[] intArray = (int[]) result;
if ((intArray == null) || (intArray.length < length)) {
intArray = new int[length];
}
array.getIntegers(0, length, intArray);
return intArray;
} else if (arrayType == V8Value.DOUBLE) {
double[] doubleArray = (double[]) result;
if ((doubleArray == null) || (doubleArray.length < length)) {
doubleArray = new double[length];
}
array.getDoubles(0, length, doubleArray);
return doubleArray;
} else if (arrayType == V8Value.BOOLEAN) {
boolean[] booleanArray = (boolean[]) result;
if ((booleanArray == null) || (booleanArray.length < length)) {
booleanArray = new boolean[length];
}
array.getBooleans(0, length, booleanArray);
return booleanArray;
} else if (arrayType == V8Value.STRING) {
String[] stringArray = (String[]) result;
if ((stringArray == null) || (stringArray.length < length)) {
stringArray = new String[length];
}
array.getStrings(0, length, stringArray);
return stringArray;
} else if (arrayType == V8Value.BYTE) {
byte[] byteArray = (byte[]) result;
if ((byteArray == null) || (byteArray.length < length)) {
byteArray = new byte[length];
}
array.getBytes(0, length, byteArray);
return byteArray;
}
throw new RuntimeException("Unsupported bulk load type: " + arrayType);
}
/**
* Creates a Java array from a V8Array. The type of the Array must be specified.
* Currently, only INTEGER, DOUBLE, BOOLEAN and STRING are supported.
* The V8Array must only contain elements of type 'arrayType'.
* <p>
* This method will use J2V8's bulk array copy making it faster than iterating over
* all the elements in the array.
*
* @param array The V8Array to convert to a Java Array.
* @param arrayType The type of the V8Array to convert.
* @return A Java array representing a V8Array.
*/
public static Object getTypedArray(final V8Array array, final int arrayType) {
int length = array.length();
if (arrayType == V8Value.INTEGER) {
return array.getIntegers(0, length);
} else if (arrayType == V8Value.DOUBLE) {
return array.getDoubles(0, length);
} else if (arrayType == V8Value.BOOLEAN) {
return array.getBooleans(0, length);
} else if (arrayType == V8Value.STRING) {
return array.getStrings(0, length);
}
throw new RuntimeException("Unsupported bulk load type: " + arrayType);
}
/**
* Creates a V8Object from a java.util.Map. This is a deep copy, so if the map
* contains other maps (or lists) they will also be converted.
*
* @param v8 The runtime on which to create the result.
* @param map The map to convert to a V8Object.
* @return A V8Object representing the map.
*/
public static V8Object toV8Object(final V8 v8, final Map<String, ? extends Object> map) {
Map<Object, V8Value> cache = new Hashtable<Object, V8Value>();
try {
return toV8Object(v8, map, cache).twin();
} finally {
for (V8Value v8Object : cache.values()) {
v8Object.close();
}
}
}
/**
* Creates a V8Array from a java.util.List. This is a deep copy, so if the list
* contains other lists (or maps) they will also be converted.
*
* @param v8 The runtime on which to create the result.
* @param list The list to convert to a V8Array.
* @return A V8Array representing the list.
*/
public static V8Array toV8Array(final V8 v8, final List<? extends Object> list) {
Map<Object, V8Value> cache = new Hashtable<Object, V8Value>();
try {
return toV8Array(v8, list, cache).twin();
} finally {
for (V8Value v8Object : cache.values()) {
v8Object.close();
}
}
}
/**
* Returns an object usable with a V8 Runtime which represents
* the parameter 'value'. If 'value' is an Integer, Boolean, Double
* or String, then 'value' is simply returned as these are directly
* usable on V8. If 'value' is a map / list, then it's converted to
* a V8Object / V8Array first.
* <p>
* If the result is a V8Value, it must be released.
*
* @param v8 The runtime on which to create V8Values.
* @param value The value to convert to an object usable with V8
* @return An object which can be used directly with a V8 runtime.
*/
public static Object getV8Result(final V8 v8, final Object value) {
if (value == null) {
return null;
}
Map<Object, V8Value> cache = new Hashtable<Object, V8Value>();
try {
Object result = getV8Result(v8, value, cache);
if (result instanceof V8Value) {
return ((V8Value) result).twin();
}
return result;
} finally {
for (V8Value v8Object : cache.values()) {
v8Object.close();
}
}
}
/**
* Pushes a Java Object to a V8Array by first converting it to a V8Value if needed.
* If the value is a boxed primitive, then the primitive will be pushed. If the object
* is a Map / List then a deep copy will be performed, converting the object to a
* V8Object / V8Array first.
*
* @param v8 The runtime on which to create any needed V8Values.
* @param array The array to push the elements to.
* @param value The value to push to the array.
*/
public static void pushValue(final V8 v8, final V8Array array, final Object value) {
Map<Object, V8Value> cache = new Hashtable<Object, V8Value>();
try {
pushValue(v8, array, value, cache);
} finally {
for (V8Value v8Object : cache.values()) {
v8Object.close();
}
}
}
/**
* Gets a Java Object representing the value at the given index in the V8Array.
* If the value is a primitive (int, boolean or double) then a boxed instance
* is returned. If the value is a String, then a String is returned. If
* the value is a V8Object or V8Array, then a Map or List is returned.
*
* @param array The array on which to lookup the value. The array is not
* released.
* @param index The index whose element to lookup.
* @return A Java Object representing the value at a given index.
*/
public static Object getValue(final V8Array array, final int index) {
V8Map<Object> cache = new V8Map<Object>();
Object object = null;
int type = V8Value.UNDEFINED;
try {
object = array.get(index);
type = array.getType(index);
Object result = getValue(object, type, cache, DEFAULT_TYPE_ADAPTER);
if ((result == object) && (result instanceof V8Value)) {
return ((V8Value) result).twin();
}
return result;
} finally {
if (object instanceof Releasable) {
((Releasable) object).release();
}
cache.close();
}
}
/**
* Gets a Java Object representing the value at the given index in the V8Array.
* A TypeAdapter is used to convert values from V8Objects to Java Objects.
* If the value is a primitive (int, boolean or double) then a boxed instance
* is returned. If the value is a String, then a String is returned. If
* the value is a V8Object or V8Array, then a Map or List is returned.
*
* @param array The array on which to lookup the value. The array is not
* released.
* @param index The index whose element to lookup.
* @param adapter The {@link TypeAdapter} to use for the object conversions.
* @return A Java Object representing the value at a given index.
*/
public static Object getValue(final V8Array array, final int index, final TypeAdapter adapter) {
V8Map<Object> cache = new V8Map<Object>();
Object object = null;
int type = V8Value.UNDEFINED;
try {
object = array.get(index);
type = array.getType(index);
Object result = getValue(object, type, cache, adapter);
if ((result == object) && (result instanceof V8Value)) {
return ((V8Value) result).twin();
}
return result;
} finally {
if (object instanceof Releasable) {
((Releasable) object).release();
}
cache.close();
}
}
/**
* Gets a Java Object representing the value with the given key in the V8Object.
* If the value is a primitive (int, boolean or double) then a boxed instance
* is returned. If the value is a String, then a String is returned. If
* the value is a V8Object or V8Array, then a Map or List is returned.
*
* @param object The object on which to lookup the value. The object is not
* released.
* @param key The key to use to lookup the value.
* @return A Java Object representing the value at a given key.
*/
public static Object getValue(final V8Object object, final String key) {
return getValue(object, key, DEFAULT_TYPE_ADAPTER);
}
/**
* Gets a Java Object representing the value with the given key in the V8Object.
* A TypeAdapter is used to convert values from V8Objects to Java Objects.
* If the value is a primitive (int, boolean or double) then a boxed instance
* is returned. If the value is a String, then a String is returned. If
* the value is a V8Object or V8Array, then a Map or List is returned.
*
* @param v8Object The object on which to lookup the value. The object is not
* released.
* @param key The key to use to lookup the value.
* @param adapter The {@link TypeAdapter} to use for the object conversions.
* @return A Java Object representing the value at a given key.
*/
public static Object getValue(final V8Object v8Object, final String key, final TypeAdapter adapter) {
V8Map<Object> cache = new V8Map<Object>();
Object object = null;
int type = V8Value.UNDEFINED;
try {
object = v8Object.get(key);
type = v8Object.getType(key);
Object result = getValue(object, type, cache, adapter);
if ((result == object) && (result instanceof V8Value)) {
return ((V8Value) result).twin();
}
return result;
} finally {
if (object instanceof Releasable) {
((Releasable) object).release();
}
cache.close();
}
}
@SuppressWarnings("unchecked")
private static Map<String, ? super Object> toMap(final V8Object v8Object, final V8Map<Object> cache, final TypeAdapter adapter) {
if (v8Object == null) {
return Collections.emptyMap();
}
if (cache.containsKey(v8Object)) {
return (Map<String, ? super Object>) cache.get(v8Object);
}
Map<String, ? super Object> result = new V8PropertyMap<Object>();
cache.put(v8Object, result);
String[] keys = v8Object.getKeys();
for (String key : keys) {
Object object = null;
int type = V8Value.UNDEFINED;
try {
object = v8Object.get(key);
type = v8Object.getType(key);
Object value = getValue(object, type, cache, adapter);
if (value != IGNORE) {
result.put(key, value);
}
} finally {
if (object instanceof Releasable) {
((Releasable) object).release();
}
}
}
return result;
}
@SuppressWarnings("unchecked")
private static List<? super Object> toList(final V8Array array, final V8Map<Object> cache, final TypeAdapter adapter) {
if (array == null) {
return Collections.emptyList();
}
if (cache.containsKey(array)) {
return (List<? super Object>) cache.get(array);
}
List<? super Object> result = new ArrayList<Object>();
cache.put(array, result);
for (int i = 0; i < array.length(); i++) {
Object object = null;
int type = V8Value.UNDEFINED;
try {
object = array.get(i);
type = array.getType(i);
Object value = getValue(object, type, cache, adapter);
if (value != IGNORE) {
result.add(value);
}
} finally {
if (object instanceof Releasable) {
((Releasable) object).release();
}
}
}
return result;
}
private static V8TypedArray toV8TypedArray(final V8 v8, final TypedArray typeArray, final Map<Object, V8Value> cache) {
if (cache.containsKey(typeArray)) {
return (V8TypedArray) cache.get(typeArray);
}
V8TypedArray result = typeArray.getV8TypedArray();
cache.put(typeArray, result);
return result;
}
private static V8ArrayBuffer toV8ArrayBuffer(final V8 v8, final ArrayBuffer arrayBuffer, final Map<Object, V8Value> cache) {
if (cache.containsKey(arrayBuffer)) {
return (V8ArrayBuffer) cache.get(arrayBuffer);
}
V8ArrayBuffer result = arrayBuffer.getV8ArrayBuffer();
cache.put(arrayBuffer, result);
return result;
}
private static V8Object toV8Object(final V8 v8, final Map<String, ? extends Object> map, final Map<Object, V8Value> cache) {
if (cache.containsKey(map)) {
return (V8Object) cache.get(map);
}
V8Object result = new V8Object(v8);
cache.put(map, result);
try {
for (Entry<String, ? extends Object> entry : map.entrySet()) {
setValue(v8, result, entry.getKey(), entry.getValue(), cache);
}
} catch (IllegalStateException e) {
result.close();
throw e;
}
return result;
}
private static V8Array toV8Array(final V8 v8, final List<? extends Object> list, final Map<Object, V8Value> cache) {
if (cache.containsKey(new ListWrapper(list))) {
return (V8Array) cache.get(new ListWrapper(list));
}
V8Array result = new V8Array(v8);
cache.put(new ListWrapper(list), result);
try {
for (int i = 0; i < list.size(); i++) {
Object value = list.get(i);
pushValue(v8, result, value, cache);
}
} catch (IllegalStateException e) {
result.close();
throw e;
}
return result;
}
@SuppressWarnings("unchecked")
private static Object getV8Result(final V8 v8, final Object value, final Map<Object, V8Value> cache) {
if (cache.containsKey(value)) {
return cache.get(value);
}
if (value instanceof Map<?, ?>) {
return toV8Object(v8, (Map<String, ? extends Object>) value, cache);
} else if (value instanceof List<?>) {
return toV8Array(v8, (List<? extends Object>) value, cache);
} else if (value instanceof TypedArray) {
return toV8TypedArray(v8, (TypedArray) value, cache);
} else if (value instanceof ArrayBuffer) {
return toV8ArrayBuffer(v8, (ArrayBuffer) value, cache);
}
return value;
}
@SuppressWarnings({"unchecked", "rawtypes", "resource"})
private static void pushValue(final V8 v8, final V8Array result, final Object value, final Map<Object, V8Value> cache) {
if (value == null) {
result.pushUndefined();
} else if (value instanceof Integer) {
result.push(value);
} else if (value instanceof Long) {
result.push(Double.valueOf((Long) value));
} else if (value instanceof Double) {
result.push(value);
} else if (value instanceof Float) {
result.push(value);
} else if (value instanceof String) {
result.push((String) value);
} else if (value instanceof Boolean) {
result.push(value);
} else if (value instanceof TypedArray) {
V8TypedArray v8TypedArray = toV8TypedArray(v8, (TypedArray) value, cache);
result.push(v8TypedArray);
} else if (value instanceof ArrayBuffer) {
V8ArrayBuffer v8ArrayBuffer = toV8ArrayBuffer(v8, (ArrayBuffer) value, cache);
result.push(v8ArrayBuffer);
} else if (value instanceof V8Value) {
result.push((V8Value) value);
} else if (value instanceof Map) {
V8Object object = toV8Object(v8, (Map) value, cache);
result.push(object);
} else if (value instanceof List) {
V8Array array = toV8Array(v8, (List) value, cache);
result.push(array);
} else {
throw new IllegalStateException("Unsupported Object of type: " + value.getClass());
}
}
@SuppressWarnings({"unchecked", "rawtypes", "resource"})
private static void setValue(final V8 v8, final V8Object result, final String key, final Object value, final Map<Object, V8Value> cache) {
if (value == null) {
result.addUndefined(key);
} else if (value instanceof Integer) {
result.add(key, (Integer) value);
} else if (value instanceof Long) {
result.add(key, (Long) value);
} else if (value instanceof Double) {
result.add(key, (Double) value);
} else if (value instanceof Float) {
result.add(key, (Float) value);
} else if (value instanceof String) {
result.add(key, (String) value);
} else if (value instanceof Boolean) {
result.add(key, (Boolean) value);
} else if (value instanceof TypedArray) {
V8TypedArray v8TypedArray = toV8TypedArray(v8, (TypedArray) value, cache);
result.add(key, v8TypedArray);
} else if (value instanceof ArrayBuffer) {
V8ArrayBuffer v8ArrayBuffer = toV8ArrayBuffer(v8, (ArrayBuffer) value, cache);
result.add(key, v8ArrayBuffer);
} else if (value instanceof V8Value) {
result.add(key, (V8Value) value);
} else if (value instanceof Map) {
V8Object object = toV8Object(v8, (Map) value, cache);
result.add(key, object);
} else if (value instanceof List) {
V8Array array = toV8Array(v8, (List) value, cache);
result.add(key, array);
} else {
throw new IllegalStateException("Unsupported Object of type: " + value.getClass());
}
}
private static Object getValue(final Object value, final int valueType, final V8Map<Object> cache, final TypeAdapter adapter) {
Object adapterResult = adapter.adapt(valueType, value);
if (TypeAdapter.DEFAULT != adapterResult) {
return adapterResult;
}
switch (valueType) {
case V8Value.INTEGER:
case V8Value.DOUBLE:
case V8Value.BOOLEAN:
case V8Value.STRING:
return value;
case V8Value.V8_FUNCTION:
return IGNORE;
case V8Value.V8_ARRAY_BUFFER:
return new ArrayBuffer((V8ArrayBuffer) value);
case V8Value.V8_TYPED_ARRAY:
return new TypedArray((V8TypedArray) value);
case V8Value.V8_ARRAY:
return toList((V8Array) value, cache, adapter);
case V8Value.V8_OBJECT:
return toMap((V8Object) value, cache, adapter);
case V8Value.NULL:
return null;
case V8Value.UNDEFINED:
return V8.getUndefined();
default:
throw new IllegalStateException("Cannot convert type " + V8Value.getStringRepresentation(valueType));
}
}
private V8ObjectUtils() {
}
static class DefaultTypeAdapter implements TypeAdapter {
@Override
public Object adapt(final int type, final Object value) {
return TypeAdapter.DEFAULT;
}
}
static class ListWrapper {
private List<? extends Object> list;
public ListWrapper(final List<? extends Object> list) {
this.list = list;
}
@Override
public boolean equals(final Object obj) {
if (obj instanceof ListWrapper) {
return ((ListWrapper) obj).list == list;
}
return false;
}
@Override
public int hashCode() {
return System.identityHashCode(list);
}
}
}

176
fine-j2v8/src/main/java/com/eclipsesource/v8/utils/V8PropertyMap.java

@ -0,0 +1,176 @@
/*******************************************************************************
* Copyright (c) 2015 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.utils;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
/**
* A custom map is needed because the existing HashMaps
* do not allow self containment, and Hashtables do not
* allow nulls as values.
*
* This class is not considered API.
*/
class V8PropertyMap<V> implements Map<String, V> {
private Hashtable<String, V> map = new Hashtable<String, V>();
private Set<String> nulls = new HashSet<String>();
/*
* (non-Javadoc)
* @see java.util.Map#size()
*/
@Override
public int size() {
return map.size() + nulls.size();
}
/*
* (non-Javadoc)
* @see java.util.Map#isEmpty()
*/
@Override
public boolean isEmpty() {
return map.isEmpty() && nulls.isEmpty();
}
/*
* (non-Javadoc)
* @see java.util.Map#containsKey(java.lang.Object)
*/
@Override
public boolean containsKey(final Object key) {
return map.containsKey(key) || nulls.contains(key);
}
/*
* (non-Javadoc)
* @see java.util.Map#containsValue(java.lang.Object)
*/
@Override
public boolean containsValue(final Object value) {
if ((value == null) && !nulls.isEmpty()) {
return true;
} else if (value == null) {
return false;
}
return map.containsValue(value);
}
/*
* (non-Javadoc)
* @see java.util.Map#get(java.lang.Object)
*/
@Override
public V get(final Object key) {
if (nulls.contains(key)) {
return null;
}
return map.get(key);
}
/*
* (non-Javadoc)
* @see java.util.Map#put(java.lang.Object, java.lang.Object)
*/
@Override
public V put(final String key, final V value) {
if (value == null) {
if (map.containsKey(key)) {
map.remove(key);
}
nulls.add(key);
return null;
}
if (nulls.contains(key)) {
nulls.remove(key);
}
return map.put(key, value);
}
/*
* (non-Javadoc)
* @see java.util.Map#remove(java.lang.Object)
*/
@Override
public V remove(final Object key) {
if (nulls.contains(key)) {
nulls.remove(key);
return null;
}
return map.remove(key);
}
/*
* (non-Javadoc)
* @see java.util.Map#putAll(java.util.Map)
*/
@Override
public void putAll(final Map<? extends String, ? extends V> m) {
for (Entry<? extends String, ? extends V> entry : m.entrySet()) {
this.put(entry.getKey(), entry.getValue());
}
}
/*
* (non-Javadoc)
* @see java.util.Map#clear()
*/
@Override
public void clear() {
map.clear();
nulls.clear();
}
/*
* (non-Javadoc)
* @see java.util.Map#keySet()
*/
@Override
public Set<String> keySet() {
HashSet<String> result = new HashSet<String>(map.keySet());
result.addAll(nulls);
return result;
}
/*
* (non-Javadoc)
* @see java.util.Map#values()
*/
@Override
public Collection<V> values() {
ArrayList<V> result = new ArrayList<V>(map.values());
for (int i = 0; i < nulls.size(); i++) {
result.add(null);
}
return result;
}
/*
* (non-Javadoc)
* @see java.util.Map#entrySet()
*/
@Override
public Set<Entry<String, V>> entrySet() {
HashSet<Entry<String, V>> result = new HashSet<Entry<String, V>>(map.entrySet());
for (String nullKey : nulls) {
result.add(new SimpleEntry<String, V>(nullKey, null));
}
return result;
}
}

29
fine-j2v8/src/main/java/com/eclipsesource/v8/utils/V8Runnable.java

@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (c) 2015 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.utils;
import com.eclipsesource.v8.V8;
/**
* Classes can implement this interface to execute arbitrary code on
* isolated V8 runtime on its own thread. Instances of classes that
* implement this interface can be passed to V8Thread.
*/
public interface V8Runnable {
/**
* Execute the code on the provided runtime.
*
* @param runtime The V8 runtime assigned to this runnable.
*/
public void run(final V8 runtime);
}

57
fine-j2v8/src/main/java/com/eclipsesource/v8/utils/V8Thread.java

@ -0,0 +1,57 @@
/*******************************************************************************
* Copyright (c) 2015 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.utils;
import com.eclipsesource.v8.V8;
/**
* A Thread with its own V8 runtime. The thread will create a runtime,
* and execute a runnable on that runtime. When the thread ends,
* the runtime will be released.
*
* It's suggested that you *DO NOT* release the lock on the runtime.
* If the lock is released, you will need to ensure that the runtime
* is properly released.
*/
public class V8Thread extends Thread {
private final V8Runnable target;
private V8 runtime;
/**
* Create as new Thread with its own V8Runtime.
*
* @param target The code to execute with the given runtime.
*/
public V8Thread(final V8Runnable target) {
this.target = target;
}
/*
* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run() {
runtime = V8.createV8Runtime();
try {
target.run(runtime);
} finally {
synchronized (this) {
if (runtime.getLocker().hasLock()) {
runtime.close();
runtime = null;
}
}
}
}
}

BIN
fine-j2v8/src/main/resources/libj2v8-linux-x86_64.so

Binary file not shown.

BIN
fine-j2v8/src/main/resources/libj2v8-macosx-aarch_64.dylib

Binary file not shown.

BIN
fine-j2v8/src/main/resources/libj2v8-macosx-x86_64.dylib

Binary file not shown.

BIN
fine-j2v8/src/main/resources/libj2v8-windows-x86_64.dll

Binary file not shown.
Loading…
Cancel
Save