Browse Source
* commit 'c25524bd8bcad9ef31b7f8d8cafbae07a8dadaf3': REPORT-83447 改下注释 REPORT-83447 驱动管理mysql自定义连接和druid监控不兼容 REPORT-83322 j2v8引擎升级之后,内置到third中 REPORT-80538 feat: 打包修复 REPORT-80538 feat: 引入skywalking的sdkfinal/11.0
superman
2 years ago
55 changed files with 8510 additions and 3 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.
@ -0,0 +1,32 @@
|
||||
<!-- |
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more |
||||
~ contributor license agreements. See the NOTICE file distributed with |
||||
~ this work for additional information regarding copyright ownership. |
||||
~ The ASF licenses this file to You 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. |
||||
~ |
||||
--> |
||||
|
||||
<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"> |
||||
<parent> |
||||
<groupId>com.fr.third</groupId> |
||||
<artifactId>step1</artifactId> |
||||
<version>${revision}</version> |
||||
<relativePath>../base-third-project/base-third-step1</relativePath> |
||||
</parent> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<artifactId>fine-skywalking-toolkit-trace</artifactId> |
||||
<packaging>jar</packaging> |
||||
|
||||
<url>http://maven.apache.org</url> |
||||
</project> |
@ -0,0 +1,49 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You 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 org.apache.skywalking.apm.toolkit.trace; |
||||
|
||||
/** |
||||
* provide custom api that set tag for current active span. |
||||
*/ |
||||
public class ActiveSpan { |
||||
/** |
||||
* @param key tag key |
||||
* @param value tag value |
||||
*/ |
||||
public static void tag(String key, String value) { |
||||
} |
||||
|
||||
public static void error() { |
||||
} |
||||
|
||||
public static void error(String errorMsg) { |
||||
} |
||||
|
||||
public static void error(Throwable throwable) { |
||||
} |
||||
|
||||
public static void debug(String debugMsg) { |
||||
} |
||||
|
||||
public static void info(String infoMsg) { |
||||
} |
||||
|
||||
public static void setOperationName(String operationName) { |
||||
} |
||||
} |
@ -0,0 +1,39 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You 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 org.apache.skywalking.apm.toolkit.trace; |
||||
|
||||
import java.util.concurrent.Callable; |
||||
|
||||
@TraceCrossThread |
||||
public class CallableWrapper<V> implements Callable<V> { |
||||
final Callable<V> callable; |
||||
|
||||
public static <V> CallableWrapper<V> of(Callable<V> r) { |
||||
return new CallableWrapper<>(r); |
||||
} |
||||
|
||||
public CallableWrapper(Callable<V> callable) { |
||||
this.callable = callable; |
||||
} |
||||
|
||||
@Override |
||||
public V call() throws Exception { |
||||
return callable.call(); |
||||
} |
||||
} |
@ -0,0 +1,40 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You 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 org.apache.skywalking.apm.toolkit.trace; |
||||
|
||||
import java.util.function.Consumer; |
||||
|
||||
@TraceCrossThread |
||||
public class ConsumerWrapper<V> implements Consumer<V> { |
||||
final Consumer<V> consumer; |
||||
|
||||
public ConsumerWrapper(Consumer<V> consumer) { |
||||
this.consumer = consumer; |
||||
} |
||||
|
||||
public static <V> ConsumerWrapper<V> of(Consumer<V> consumer) { |
||||
return new ConsumerWrapper(consumer); |
||||
} |
||||
|
||||
@Override |
||||
public void accept(V v) { |
||||
this.consumer.accept(v); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,40 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You 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 org.apache.skywalking.apm.toolkit.trace; |
||||
|
||||
import java.util.function.Function; |
||||
|
||||
@TraceCrossThread |
||||
public class FunctionWrapper<T, R> implements Function<T, R> { |
||||
final Function<T, R> function; |
||||
|
||||
public FunctionWrapper(Function<T, R> function) { |
||||
this.function = function; |
||||
} |
||||
|
||||
public static <T, R> FunctionWrapper<T, R> of(Function<T, R> function) { |
||||
return new FunctionWrapper(function); |
||||
} |
||||
|
||||
@Override |
||||
public R apply(T t) { |
||||
return this.function.apply(t); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,35 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You 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 org.apache.skywalking.apm.toolkit.trace; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Inherited; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* After the exception status checker activated in the agent, the span wouldn't be marked as error status if the |
||||
* exception has this annotation. |
||||
*/ |
||||
@Target(ElementType.TYPE) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Inherited |
||||
public @interface IgnoredException { |
||||
} |
@ -0,0 +1,36 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You 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 org.apache.skywalking.apm.toolkit.trace; |
||||
|
||||
@TraceCrossThread |
||||
public class RunnableWrapper implements Runnable { |
||||
final Runnable runnable; |
||||
|
||||
public RunnableWrapper(Runnable runnable) { |
||||
this.runnable = runnable; |
||||
} |
||||
|
||||
public static RunnableWrapper of(Runnable r) { |
||||
return new RunnableWrapper(r); |
||||
} |
||||
|
||||
@Override |
||||
public void run() { |
||||
this.runnable.run(); |
||||
} |
||||
} |
@ -0,0 +1,39 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You 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 org.apache.skywalking.apm.toolkit.trace; |
||||
|
||||
import java.util.function.Supplier; |
||||
|
||||
@TraceCrossThread |
||||
public class SupplierWrapper<V> implements Supplier<V> { |
||||
final Supplier<V> supplier; |
||||
|
||||
public static <V> SupplierWrapper<V> of(Supplier<V> r) { |
||||
return new SupplierWrapper<>(r); |
||||
} |
||||
|
||||
public SupplierWrapper(Supplier<V> supplier) { |
||||
this.supplier = supplier; |
||||
} |
||||
|
||||
@Override |
||||
public V get() { |
||||
return supplier.get(); |
||||
} |
||||
} |
@ -0,0 +1,47 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You 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 org.apache.skywalking.apm.toolkit.trace; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Repeatable; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* Tag the current active span with key {@link #key()} and value {@link #value()}, if there is no active span, this |
||||
* annotation takes no effect. |
||||
* |
||||
* @see Tags |
||||
*/ |
||||
@Target(ElementType.METHOD) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Repeatable(Tags.class) |
||||
public @interface Tag { |
||||
/** |
||||
* @return the key of the tag to be injected into the current active span |
||||
*/ |
||||
String key(); |
||||
|
||||
/** |
||||
* @return the value of the tag to be injected into the current active span, in the form of the customized |
||||
* enhancement rules, for more information, refer to https://github.com/apache/skywalking/blob/master/docs/en/setup/service-agent/java-agent/Customize-enhance-trace.md#how-to-configure
|
||||
*/ |
||||
String value(); |
||||
} |
@ -0,0 +1,46 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You 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 org.apache.skywalking.apm.toolkit.trace; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* A wrapper annotation for {@link Tag} that allows to apply multiple tags to a single method span, |
||||
* |
||||
* <pre> |
||||
* @Tag(key = "tag1", value = "arg[0]") |
||||
* @Tag(key = "tag2", value = "arg[1]") |
||||
* public void test(String param1, String param2) { |
||||
* // ...
|
||||
* } |
||||
* </pre> |
||||
* |
||||
* @see Tag |
||||
*/ |
||||
@Target(ElementType.METHOD) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
public @interface Tags { |
||||
/** |
||||
* @see Tag |
||||
*/ |
||||
Tag[] value(); |
||||
} |
@ -0,0 +1,38 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You 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 org.apache.skywalking.apm.toolkit.trace; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* The agent create local span if the method that annotation with {@link Trace}. The value of span operation name will |
||||
* fetch by {@link #operationName()}. if the value of {@link #operationName()} is blank string. the operation name will |
||||
* be set the class name + method name. |
||||
*/ |
||||
@Target(ElementType.METHOD) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
public @interface Trace { |
||||
/** |
||||
* @return operation name, the default value is blank string. |
||||
*/ |
||||
String operationName() default ""; |
||||
} |
@ -0,0 +1,76 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You 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 org.apache.skywalking.apm.toolkit.trace; |
||||
|
||||
import java.util.Optional; |
||||
|
||||
/** |
||||
* Try to access the sky-walking tracer context. The context is not existed, always. only the middleware, component, or |
||||
* rpc-framework are supported in the current invoke stack, in the same thread, the context will be available. |
||||
* <p> |
||||
*/ |
||||
public class TraceContext { |
||||
|
||||
/** |
||||
* Try to get the traceId of current trace context. |
||||
* |
||||
* @return traceId, if it exists, or empty {@link String}. |
||||
*/ |
||||
public static String traceId() { |
||||
return ""; |
||||
} |
||||
|
||||
/** |
||||
* Try to get the segmentId of current trace context. |
||||
* |
||||
* @return segmentId, if it exists, or empty {@link String}. |
||||
*/ |
||||
public static String segmentId() { |
||||
return ""; |
||||
} |
||||
|
||||
/** |
||||
* Try to get the spanId of current trace context. The spanId is a negative number when the trace context is |
||||
* missing. |
||||
* |
||||
* @return spanId, if it exists, or empty {@link String}. |
||||
*/ |
||||
public static int spanId() { |
||||
return -1; |
||||
} |
||||
|
||||
/** |
||||
* Try to get the custom value from trace context. |
||||
* |
||||
* @return custom data value. |
||||
*/ |
||||
public static Optional<String> getCorrelation(String key) { |
||||
return Optional.empty(); |
||||
} |
||||
|
||||
/** |
||||
* Put the custom key/value into trace context. |
||||
* |
||||
* @return previous value if it exists. |
||||
*/ |
||||
public static Optional<String> putCorrelation(String key, String value) { |
||||
return Optional.empty(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,30 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You 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 org.apache.skywalking.apm.toolkit.trace; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
@Target(ElementType.TYPE) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
public @interface TraceCrossThread { |
||||
|
||||
} |
Loading…
Reference in new issue