pengda
2 years ago
41 changed files with 7951 additions and 0 deletions
@ -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> |
@ -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); |
||||||
|
|
||||||
|
} |
@ -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); |
||||||
|
|
||||||
|
} |
@ -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) { |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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"; |
||||||
|
} |
@ -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]+", ""); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
|
||||||
|
} |
@ -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(); |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
package com.eclipsesource.v8; |
||||||
|
|
||||||
|
public interface SignatureProvider { |
||||||
|
public byte[] getSignature(String uri); |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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 don’t 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"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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); |
||||||
|
|
||||||
|
} |
@ -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); |
||||||
|
|
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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); |
||||||
|
|
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue