diff --git a/src/main/java/com/eclipsesource/v8/LibraryLoader.java b/src/main/java/com/eclipsesource/v8/LibraryLoader.java index 4fbf7405c..37d12df0e 100644 --- a/src/main/java/com/eclipsesource/v8/LibraryLoader.java +++ b/src/main/java/com/eclipsesource/v8/LibraryLoader.java @@ -7,7 +7,6 @@ * * Contributors: * EclipseSource - initial API and implementation - * Wolfgang Steiner - code separation PlatformDetector/LibraryLoader ******************************************************************************/ package com.eclipsesource.v8; @@ -28,86 +27,53 @@ class LibraryLoader { 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 - *
NOTE: Vendors are only included for linux systems
- * @return The filename string has the following structure: - *{arch}-[vendor]-{operating_system}
- */
- 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;
+ private static String computeLibraryShortName() {
+ String base = "j2v8";
+ String osSuffix = getOS();
+ String archSuffix = getArchSuffix();
+ return base + "_" + osSuffix + "_" + archSuffix;
}
- public static String computeLibraryFullName(boolean withLinuxVendor) {
- return "lib" + computeLibraryShortName(withLinuxVendor) + "." + PlatformDetector.OS.getLibFileExtension();
+ private static String computeLibraryFullName() {
+ return "lib" + computeLibraryShortName() + "." + getOSFileExtension();
}
- 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;
+ static void loadLibrary(final String tempDirectory) {
+ if ( isAndroid() ) {
+ System.loadLibrary("j2v8");
+ return;
+ }
+ StringBuffer message = new StringBuffer();
+ String libShortName = computeLibraryShortName();
+ String libFullName = computeLibraryFullName();
+ String ideLocation = System.getProperty("user.dir") + SEPARATOR + "jni" + SEPARATOR + computeLibraryFullName();
+
+ String path = null;
/* Try loading library from java library path */
if (load(libFullName, message)) {
- return true;
+ return;
}
if (load(libShortName, message)) {
- return true;
+ return;
}
/* Try loading library from the IDE location */
if (new File(ideLocation).exists()) {
if (load(ideLocation, message)) {
- return true;
+ return;
}
}
- 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))
+ if (extract(path + SEPARATOR + libFullName, libFullName, message)) {
return;
+ }
/* Failed to find the library */
throw new UnsatisfiedLinkError("Could not load J2V8 library. Reasons: " + message.toString()); //$NON-NLS-1$
@@ -132,11 +98,6 @@ static boolean load(final String libName, final StringBuffer message) {
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;
@@ -183,7 +144,7 @@ static boolean extract(final String fileName, final String mappedName, final Str
}
static void chmod(final String permision, final String path) {
- if (PlatformDetector.OS.isWindows()) {
+ if (isWindows()) {
return;
}
try {
@@ -191,4 +152,69 @@ static void chmod(final String permision, final String path) {
} catch (Throwable e) {
}
}
+
+ static String getOsName() {
+ return System.getProperty("os.name") + System.getProperty("java.specification.vendor");
+ }
+
+ static boolean isWindows() {
+ return getOsName().startsWith("Windows");
+ }
+
+ static boolean isMac() {
+ return getOsName().startsWith("Mac");
+ }
+
+ static boolean isLinux() {
+ return getOsName().startsWith("Linux");
+ }
+
+ static boolean isNativeClient() {
+ return getOsName().startsWith("nacl");
+ }
+
+ static boolean isAndroid() {
+ return getOsName().contains("Android");
+ }
+
+ static String getArchSuffix() {
+ String arch = System.getProperty("os.arch");
+ if (arch.equals("i686")) {
+ return "x86";
+ } else if (arch.equals("amd64")) {
+ return "x86_64";
+ } else if (arch.equals("nacl")) {
+ return "armv7l";
+ } else if (arch.equals("aarch64")) {
+ return "armv7l";
+ }
+ return arch;
+ }
+
+ static String getOSFileExtension() {
+ if (isWindows()) {
+ return "dll";
+ } else if (isMac()) {
+ return "dylib";
+ } else if (isLinux()) {
+ return "so";
+ } else if (isNativeClient()) {
+ return "so";
+ }
+ throw new UnsatisfiedLinkError("Unsupported platform: " + getOsName());
+ }
+
+ static String getOS() {
+ if (isWindows()) {
+ return "win32";
+ } else if (isMac()) {
+ return "macosx";
+ } else if (isLinux() && !isAndroid()) {
+ return "linux";
+ } else if (isAndroid()) {
+ return "android";
+ }
+ throw new UnsatisfiedLinkError("Unsupported platform: " + getOsName());
+ }
+
}
diff --git a/src/main/java/com/eclipsesource/v8/V8.java b/src/main/java/com/eclipsesource/v8/V8.java
index fea065bb1..c0881e1a3 100644
--- a/src/main/java/com/eclipsesource/v8/V8.java
+++ b/src/main/java/com/eclipsesource/v8/V8.java
@@ -249,16 +249,12 @@ private void notifyReferenceDisposed(final V8Value object) {
private static void checkNativeLibraryLoaded() {
if (!nativeLibraryLoaded) {
- String vendorName = LibraryLoader.computeLibraryShortName(true);
- String baseName = LibraryLoader.computeLibraryShortName(false);
- String message = "J2V8 native library not loaded (" + baseName + "/" + vendorName + ")";
-
if (nativeLoadError != null) {
- throw new IllegalStateException(message, nativeLoadError);
+ throw new IllegalStateException("J2V8 native library not loaded", nativeLoadError);
} else if (nativeLoadException != null) {
- throw new IllegalStateException(message, nativeLoadException);
+ throw new IllegalStateException("J2V8 native library not loaded", nativeLoadException);
} else {
- throw new IllegalStateException(message);
+ throw new IllegalStateException("J2V8 native library not loaded");
}
}
}
@@ -1567,19 +1563,6 @@ protected void releaseMethodDescriptor(final long v8RuntimePtr, final long metho
private native static boolean _isRunning(final long v8RuntimePtr);
- private native static boolean _isNodeCompatible();
-
- public static boolean isNodeCompatible() {
- if (!nativeLibraryLoaded) {
- synchronized (lock) {
- if (!nativeLibraryLoaded) {
- load(null);
- }
- }
- }
- return _isNodeCompatible();
- }
-
void addObjRef(final V8Value reference) {
objectReferences++;
if (!referenceHandlers.isEmpty()) {
diff --git a/src/test/java/com/eclipsesource/v8/LibraryLoaderTest.java b/src/test/java/com/eclipsesource/v8/LibraryLoaderTest.java
index 5ae5aa801..6b6daed06 100644
--- a/src/test/java/com/eclipsesource/v8/LibraryLoaderTest.java
+++ b/src/test/java/com/eclipsesource/v8/LibraryLoaderTest.java
@@ -7,21 +7,10 @@
*
* Contributors:
* EclipseSource - initial API and implementation
- * Wolfgang Steiner - code separation PlatformDetector/LibraryLoader
******************************************************************************/
package com.eclipsesource.v8;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.File;
-import java.io.PrintWriter;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-
-import java.util.HashMap;
import org.junit.After;
import org.junit.Before;
@@ -33,136 +22,104 @@ public class LibraryLoaderTest {
private String vendor;
private String arch;
- private Field releaseFilesField;
- private String[] releaseFiles;
-
- static void makeFinalStaticAccessible(Field field) {
- field.setAccessible(true);
-
- try {
- // on certain JVMs this is not present and will throw the exceptions below (e.g. the Android Dalvik VM)
- Field modifiersField = Field.class.getDeclaredField("modifiers");
- modifiersField.setAccessible(true);
- modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
- }
- catch (NoSuchFieldException e) {}
- catch (IllegalAccessException e) {}
- }
-
@Before
- public void setup() throws Exception {
+ public void setup() {
osName = System.getProperty("os.name");
vendor = System.getProperty("java.specification.vendor");
arch = System.getProperty("os.arch");
-
- Class> vendorClass = PlatformDetector.Vendor.class;
- releaseFilesField = vendorClass.getDeclaredField("LINUX_OS_RELEASE_FILES");
- makeFinalStaticAccessible(releaseFilesField);
-
- releaseFiles = (String[])releaseFilesField.get(null);
}
@After
- public void tearDown() throws Exception {
+ public void tearDown() {
System.setProperty("os.name", osName);
System.setProperty("java.specification.vendor", vendor);
System.setProperty("os.arch", arch);
-
- releaseFilesField.set(null, releaseFiles);
}
@Test
- public void testAndroidLibNameStructure() throws Exception {
- System.setProperty("os.name", "Android");
- System.setProperty("java.specification.vendor", "...");
- System.setProperty("os.arch", "x64");
+ public void testGetOSMac() {
+ System.setProperty("os.name", "Mac OS X");
- performTests(Platform.ANDROID, null, ".so");
+ assertEquals("macosx", LibraryLoader.getOS());
+ }
- System.setProperty("os.name", "...");
- System.setProperty("java.specification.vendor", "Android");
- System.setProperty("os.arch", "x64");
+ @Test
+ public void testGetOSLinux() {
+ System.setProperty("os.name", "Linux");
- performTests(Platform.ANDROID, null, ".so");
+ assertEquals("linux", LibraryLoader.getOS());
}
@Test
- public void testLinuxLibNameStructure() throws Exception {
+ public void testGetOSWindows() {
+ System.setProperty("os.name", "Windows");
- // skip this test on android
- if (PlatformDetector.OS.isAndroid())
- return;
+ assertEquals("win32", LibraryLoader.getOS());
+ }
+ @Test
+ public void testGetOSAndroid() {
System.setProperty("os.name", "Linux");
- System.setProperty("java.specification.vendor", "OSS");
- System.setProperty("os.arch", "x64");
+ System.setProperty("java.specification.vendor", "The Android Project");
+
+ assertEquals("android", LibraryLoader.getOS());
+ }
- final String os_release_test_path = "./test-mockup-os-release";
- final String test_vendor = "linux_vendor";
+ @Test
+ public void testGetOSFileExtensionNativeClient() {
+ System.setProperty("os.name", "naclthe android project");
+ System.setProperty("java.specification.vendor", "The Android Project");
- // mock /etc/os-release file
- releaseFilesField.set(null, new String[] { os_release_test_path });
+ assertEquals("so", LibraryLoader.getOSFileExtension());
+ }
- PrintWriter out = new PrintWriter(os_release_test_path);
- out.println(
- "NAME=The-Linux-Vendor\n" +
- "VERSION=\"towel_42\"\n" +
- "ID=" + test_vendor + "\n" +
- "VERSION_ID=42\n"
- );
- out.close();
+ @Test
+ public void testGetArchxNaCl() {
+ System.setProperty("os.arch", "nacl");
- performTests(Platform.LINUX, test_vendor, ".so");
+ assertEquals("armv7l", LibraryLoader.getArchSuffix());
+ }
+
+ @Test
+ public void testGetArchaarch64() {
+ System.setProperty("os.arch", "aarch64");
+
+ assertEquals("armv7l", LibraryLoader.getArchSuffix());
}
@Test
- public void testMacOSXLibNameStructure() throws Exception {
- System.setProperty("os.name", "MacOSX");
- System.setProperty("java.specification.vendor", "Apple");
- System.setProperty("os.arch", "x64");
+ public void testGetArchx86() {
+ System.setProperty("os.arch", "x86");
- performTests(Platform.MACOSX, null, ".dylib");
+ assertEquals("x86", LibraryLoader.getArchSuffix());
}
@Test
- public void testWindowsLibNameStructure() throws Exception {
- System.setProperty("os.name", "Windows");
- System.setProperty("java.specification.vendor", "Microsoft");
- System.setProperty("os.arch", "x64");
+ public void testGetArchx86_64() {
+ System.setProperty("os.arch", "x86_64");
+
+ assertEquals("x86_64", LibraryLoader.getArchSuffix());
+ }
- performTests(Platform.WINDOWS, null, ".dll");
+ @Test
+ public void testGetArchx64FromAmd64() {
+ System.setProperty("os.arch", "amd64");
+
+ assertEquals("x86_64", LibraryLoader.getArchSuffix());
}
- private void performTests(String expectedOsName, String expectedVendor, String expectedLibExtension) {
- // API calls
- String libName = LibraryLoader.computeLibraryShortName(true);
- String[] parts = libName.split("-");
-
- // test assertions
- int i = 0;
- int expectedParts = expectedVendor != null ? 4 : 3;
- assertEquals(expectedParts, parts.length);
- assertEquals("j2v8", parts[i++]);
- if (expectedVendor != null)
- assertEquals(expectedVendor, parts[i++]);
- assertEquals(expectedOsName, parts[i++]);
- assertEquals("x86_64", parts[i++]);
-
- // API calls
- libName = LibraryLoader.computeLibraryShortName(false);
- parts = libName.split("-");
-
- // test assertions
- assertEquals(3, parts.length);
- assertEquals("j2v8", parts[0]);
- assertEquals(expectedOsName, parts[1]);
- assertEquals("x86_64", parts[2]);
-
- // API calls
- libName = LibraryLoader.computeLibraryFullName(false);
-
- // test assertions
- assertTrue(libName.startsWith("libj2v8"));
- assertTrue(libName.endsWith(expectedLibExtension));
+ @Test
+ public void testGetArcharmv7l() {
+ System.setProperty("os.arch", "armv7l");
+
+ assertEquals("armv7l", LibraryLoader.getArchSuffix());
}
+
+ @Test
+ public void test686isX86() {
+ System.setProperty("os.arch", "i686");
+
+ assertEquals("x86", LibraryLoader.getArchSuffix());
+ }
+
}
diff --git a/src/test/java/com/eclipsesource/v8/NodeJSTest.java b/src/test/java/com/eclipsesource/v8/NodeJSTest.java
index a6ccef1e1..3d2aa95c7 100644
--- a/src/test/java/com/eclipsesource/v8/NodeJSTest.java
+++ b/src/test/java/com/eclipsesource/v8/NodeJSTest.java
@@ -13,7 +13,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
import java.io.File;
import java.io.IOException;
@@ -21,7 +20,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
public class NodeJSTest {
@@ -30,35 +28,21 @@ public class NodeJSTest {
@Before
public void setup() {
- if (skipTest())
- return;
-
nodeJS = NodeJS.createNodeJS();
}
@After
public void tearDown() {
- if (skipTest())
- return;
-
nodeJS.release();
}
- private static boolean skipTest() {
- return !V8.isNodeCompatible();
- }
-
- private final static String skipMessage = "Skipped test (Node.js features not included in native library)";
-
@Test
public void testCreateNodeJS() {
- assumeFalse(skipMessage, skipTest()); // conditional skip
assertNotNull(nodeJS);
}
@Test
public void testSingleThreadAccess_Require() throws InterruptedException {
- assumeFalse(skipMessage, skipTest()); // conditional skip
final boolean[] result = new boolean[] { false };
Thread t = new Thread(new Runnable() {
@Override
@@ -80,7 +64,6 @@ public void run() {
@Test
public void testGetVersion() {
- assumeFalse(skipMessage, skipTest()); // conditional skip
String result = nodeJS.getNodeVersion();
assertEquals("7.4.0", result);
@@ -88,7 +71,6 @@ public void testGetVersion() {
@Test
public void testSingleThreadAccess_HandleMessage() throws InterruptedException {
- assumeFalse(skipMessage, skipTest()); // conditional skip
final boolean[] result = new boolean[] { false };
Thread t = new Thread(new Runnable() {
@Override
@@ -108,7 +90,6 @@ public void run() {
@Test
public void testSingleThreadAccess_IsRunning() throws InterruptedException {
- assumeFalse(skipMessage, skipTest()); // conditional skip
final boolean[] result = new boolean[] { false };
Thread t = new Thread(new Runnable() {
@Override
@@ -128,7 +109,6 @@ public void run() {
@Test
public void testExecuteNodeScript_Startup() throws IOException {
- assumeFalse(skipMessage, skipTest()); // conditional skip
nodeJS.release();
File testScript = createTemporaryScriptFile("global.passed = true;", "testScript");
@@ -141,7 +121,6 @@ public void testExecuteNodeScript_Startup() throws IOException {
@Test
public void testExecNodeScript() throws IOException {
- assumeFalse(skipMessage, skipTest()); // conditional skip
nodeJS.release();
File testScript = createTemporaryScriptFile("global.passed = true;", "testScript");
@@ -155,7 +134,6 @@ public void testExecNodeScript() throws IOException {
@Test
public void testExecuteNodeScript_viaRequire() throws IOException {
- assumeFalse(skipMessage, skipTest()); // conditional skip
nodeJS.release();
File testScript = createTemporaryScriptFile("global.passed = true;", "testScript");
@@ -169,7 +147,6 @@ public void testExecuteNodeScript_viaRequire() throws IOException {
@Test
public void testExports() throws IOException {
- assumeFalse(skipMessage, skipTest()); // conditional skip
nodeJS.release();
File testScript = createTemporaryScriptFile("exports.foo=7", "testScript");
diff --git a/src/test/java/com/eclipsesource/v8/V8RuntimeNotLoadedTest.java b/src/test/java/com/eclipsesource/v8/V8RuntimeNotLoadedTest.java
index 0dbbb8bff..cd40f5098 100644
--- a/src/test/java/com/eclipsesource/v8/V8RuntimeNotLoadedTest.java
+++ b/src/test/java/com/eclipsesource/v8/V8RuntimeNotLoadedTest.java
@@ -11,8 +11,6 @@
package com.eclipsesource.v8;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeFalse;
import java.lang.reflect.Field;
import java.net.URLClassLoader;
@@ -34,16 +32,6 @@ public class V8RuntimeNotLoadedTest {
private static final String JAVA_LIBRARY_PATH = "java.library.path";
private String existingLibraryPath;
- /**
- * NOTE: we need to skip these tests, because on Android the SystemClassLoader
- * can not be cast to an URLClassLoader and some other issues (see TestClassLoader below)
- */
- private static boolean skipTest() {
- return PlatformDetector.OS.isAndroid();
- }
-
- private final static String skipMessage = "Skipped test (not implemented for Android)";
-
@Before
public void before() throws Exception {
existingLibraryPath = System.getProperty(JAVA_LIBRARY_PATH);
@@ -57,34 +45,21 @@ public void after() throws Exception {
@Test
public void testJ2V8NotEnabled() {
- assumeFalse(skipMessage, skipTest()); // conditional skip
-
assertFalse(V8.isLoaded());
}
- @Test(expected = UnsatisfiedLinkError.class)
+ @Test(expected = IllegalStateException.class)
public void testJ2V8CannotCreateRuntime() {
- assumeFalse(skipMessage, skipTest()); // conditional skip
-
String oldValue = System.getProperty("os.arch");
System.setProperty("os.arch", "unknown");
try {
V8.createV8Runtime();
- }
- catch (UnsatisfiedLinkError ex) {
- assertEquals("Unsupported arch: unknown", ex.getMessage());
- throw ex;
- }
- finally {
+ } finally {
System.setProperty("os.arch", oldValue);
}
}
private static void setLibraryPath(final String path) throws Exception {
- // we need to skip here too, because "sys_paths" also does not exist on Android
- if (skipTest())
- return;
-
System.setProperty(JAVA_LIBRARY_PATH, path);
// set sys_paths to null so that java.library.path will be reevalueted next time it is needed
@@ -101,9 +76,6 @@ public SeparateClassloaderTestRunner(final Class> clazz) throws Initialization
private static Class> getFromTestClassloader(final Class> clazz) throws InitializationError {
try {
- if (skipTest())
- return clazz;
-
ClassLoader testClassLoader = new TestClassLoader();
return Class.forName(clazz.getName(), true, testClassLoader);
} catch (ClassNotFoundException e) {
@@ -113,7 +85,6 @@ private static Class> getFromTestClassloader(final Class> clazz) throws Init
public static class TestClassLoader extends URLClassLoader {
public TestClassLoader() {
- // TODO: this crashes on Android (see: https://stackoverflow.com/q/31920245)
super(((URLClassLoader) getSystemClassLoader()).getURLs());
}