diff --git a/jme3-core/src/main/java/com/jme3/system/Platform.java b/jme3-core/src/main/java/com/jme3/system/Platform.java index b964b5a50..6b9592040 100644 --- a/jme3-core/src/main/java/com/jme3/system/Platform.java +++ b/jme3-core/src/main/java/com/jme3/system/Platform.java @@ -1,100 +1,113 @@ -/* - * Copyright (c) 2009-2012 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.jme3.system; - -public enum Platform { - - /** - * Microsoft Windows 32 bit - */ - Windows32, - - /** - * Microsoft Windows 64 bit - */ - Windows64, - - /** - * Linux 32 bit - */ - Linux32, - - /** - * Linux 64 bit - */ - Linux64, - - /** - * Apple Mac OS X 32 bit - */ - MacOSX32, - - /** - * Apple Mac OS X 64 bit - */ - MacOSX64, - - /** - * Apple Mac OS X 32 bit PowerPC - */ - MacOSX_PPC32, - - /** - * Apple Mac OS X 64 bit PowerPC - */ - MacOSX_PPC64, - - /** - * Android ARM5 - */ - Android_ARM5, - - /** - * Android ARM6 - */ - Android_ARM6, - - /** - * Android ARM7 - */ - Android_ARM7, - - /** - * Android x86 - */ - Android_X86, - - iOS_X86, - - iOS_ARM; - +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.system; + +public enum Platform { + + /** + * Microsoft Windows 32 bit + */ + Windows32, + + /** + * Microsoft Windows 64 bit + */ + Windows64(true), + + /** + * Linux 32 bit + */ + Linux32, + + /** + * Linux 64 bit + */ + Linux64(true), + + /** + * Apple Mac OS X 32 bit + */ + MacOSX32, + + /** + * Apple Mac OS X 64 bit + */ + MacOSX64(true), + + /** + * Apple Mac OS X 32 bit PowerPC + */ + MacOSX_PPC32, + + /** + * Apple Mac OS X 64 bit PowerPC + */ + MacOSX_PPC64(true), + + /** + * Android ARM5 + */ + Android_ARM5, + + /** + * Android ARM6 + */ + Android_ARM6, + + /** + * Android ARM7 + */ + Android_ARM7, + + /** + * Android x86 + */ + Android_X86, + + iOS_X86, + + iOS_ARM; + + private final boolean is64bit; + + public boolean is64Bit() { + return is64bit; + } + + private Platform(boolean is64bit) { + this.is64bit = is64bit; + } + + private Platform() { + this(false); + } } \ No newline at end of file diff --git a/jme3-desktop/src/main/java/com/jme3/system/NativeLibrary.java b/jme3-desktop/src/main/java/com/jme3/system/NativeLibrary.java new file mode 100644 index 000000000..5ef77eec1 --- /dev/null +++ b/jme3-desktop/src/main/java/com/jme3/system/NativeLibrary.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.system; + +/** + * Holds information about a native library for a particular platform. + * + * @author Kirill Vainer + */ +final class NativeLibrary { + + private final String name; + private final Platform platform; + private final boolean isJNI; + private final String pathInNativesJar; + + /** + * Key for map to find a library for a name and platform. + */ + static final class Key { + + private final String name; + private final Platform platform; + + public Key(String name, Platform platform) { + this.name = name; + this.platform = platform; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 79 * hash + this.name.hashCode(); + hash = 79 * hash + this.platform.hashCode(); + return hash; + } + + @Override + public boolean equals(Object obj) { + final Key other = (Key) obj; + if (!this.name.equals(other.name)) { + return false; + } + if (this.platform != other.platform) { + return false; + } + return true; + } + } + + /** + * The name of the library. + * Generally only used as a way to uniquely identify the library. + * + * @return name of the library. + */ + public String getName() { + return name; + } + + /** + * The OS + architecture combination for which this library + * should be extracted. + * + * @return platform associated to this native library + */ + public Platform getPlatform() { + return platform; + } + + /** + * If this library is a JNI library. + * + * @return True if JNI library, false if native code (e.g. C/C++) library. + */ + public boolean isJNI() { + return isJNI; + } + + /** + * Path inside the natives jar or classpath where the library is located. + * + * This library must be compatible with the {@link #getPlatform() platform} + * which this library is associated with. + * + * @return path to the library in the classpath + */ + public String getPathInNativesJar() { + return pathInNativesJar; + } + + /** + * Create a new NativeLibrary. + */ + public NativeLibrary(String name, Platform platform, String pathInNativesJar, boolean isJNI) { + this.name = name; + this.platform = platform; + this.pathInNativesJar = pathInNativesJar; + this.isJNI = isJNI; + } + + /** + * Create a new NativeLibrary. + */ + public NativeLibrary(String name, Platform platform, String pathInNativesJar) { + this(name, platform, pathInNativesJar, true); + } +} diff --git a/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java b/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java new file mode 100644 index 000000000..e85f6e86a --- /dev/null +++ b/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.system; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.HashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Utility class to register, extract, and load native libraries. + *
+ * Register your own libraries via the + * {@link #registerNativeLibrary(java.lang.String, com.jme3.system.Platform, java.lang.String, boolean) } + * method, for each platform. + * You can then extract this library (depending on platform), by + * using {@link #loadNativeLibrary(java.lang.String, boolean) }. + *
+ * Example:
+ *
+ * NativeLibraryLoader.registerNativeLibrary("mystuff", Platform.Windows32, "native/windows/mystuff.dll");
+ * NativeLibraryLoader.registerNativeLibrary("mystuff", Platform.Windows64, "native/windows/mystuff64.dll");
+ * NativeLibraryLoader.registerNativeLibrary("mystuff", Platform.Linux32,   "native/linux/libmystuff.so");
+ * NativeLibraryLoader.registerNativeLibrary("mystuff", Platform.Linux64,   "native/linux/libmystuff64.so");
+ * NativeLibraryLoader.registerNativeLibrary("mystuff", Platform.MacOSX32,  "native/macosx/libmystuff.jnilib");
+ * NativeLibraryLoader.registerNativeLibrary("mystuff", Platform.MacOSX64,  "native/macosx/libmystuff.jnilib");
+ * 
+ *
+ * This will register the library. Load it via:
+ *
+ * NativeLibraryLoader.loadNativeLibrary("mystuff", true);
+ * 
+ * It will load the right library automatically based on the platform. + * + * @author Kirill Vainer + */ +public final class NativeLibraryLoader { + + private static final Logger logger = Logger.getLogger(NativeLibraryLoader.class.getName()); + private static final byte[] buf = new byte[1024 * 100]; + private static File extractionFolderOverride = null; + private static File extractionFolder = null; + + private static final HashMap nativeLibraryMap + = new HashMap(); + + /** + * Register a new known library. + * + * This simply registers a known library, the actual extraction and loading + * is performed by calling {@link #loadNativeLibrary(java.lang.String, boolean) }. + * + * @param name The name / ID of the library (not OS or architecture specific). + * @param platform The platform for which the in-natives-jar path has + * been specified for. + * @param path The path inside the natives-jar or classpath + * corresponding to this library. Must be compatible with the platform + * argument. + * @param isJNI True if this is a JNI library, false if this is a regular + * native (C/C++) library. + */ + public static void registerNativeLibrary(String name, Platform platform, + String path, boolean isJNI) { + nativeLibraryMap.put(new NativeLibrary.Key(name, platform), + new NativeLibrary(name, platform, path, isJNI)); + } + + /** + * Register a new known JNI library. + * + * This simply registers a known library, the actual extraction and loading + * is performed by calling {@link #loadNativeLibrary(java.lang.String, boolean) }. + * + * This method should be called several times for each library name, + * each time specifying a different platform + path combination. + * + * @param name The name / ID of the library (not OS or architecture specific). + * @param platform The platform for which the in-natives-jar path has + * been specified for. + * @param path The path inside the natives-jar or classpath + * corresponding to this library. Must be compatible with the platform + * argument. + */ + public static void registerNativeLibrary(String name, Platform platform, + String path) { + registerNativeLibrary(name, platform, path, true); + } + + static { + // LWJGL + registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl.dll"); + registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl64.dll"); + registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl.so"); + registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl64.so"); + registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.jnilib"); + registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.jnilib"); + + // OpenAL + registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll", false); + registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL64.dll", false); + registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal.so", false); + registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal64.so", false); + registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", false); + registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", false); + + // BulletJme + registerNativeLibrary("bulletjme", Platform.Windows32, "native/windows/x86/bulletjme.dll", false); + registerNativeLibrary("bulletjme", Platform.Windows64, "native/windows/x86_64/bulletjme.dll", false); + registerNativeLibrary("bulletjme", Platform.Linux32, "native/linux/x86/libbulletjme.so", false); + registerNativeLibrary("bulletjme", Platform.Linux64, "native/linux/x86_64/libbulletjme.so", false); + registerNativeLibrary("bulletjme", Platform.MacOSX32, "native/macosx/x86/libbulletjme.jnilib", false); + registerNativeLibrary("bulletjme", Platform.MacOSX64, "native/macosx/x86_64/libbulletjme.jnilib", false); + + // JInput + registerNativeLibrary("jinput", Platform.Windows32, "native/windows/jinput-raw.dll"); + registerNativeLibrary("jinput", Platform.Windows64, "native/windows/jinput-raw_64.dll"); + registerNativeLibrary("jinput", Platform.Linux32, "native/windows/libjinput-linux.so"); + registerNativeLibrary("jinput", Platform.Linux64, "native/windows/libjinput-linux64.so"); + registerNativeLibrary("jinput", Platform.MacOSX32, "native/macosx/libjinput-osx.jnilib"); + registerNativeLibrary("jinput", Platform.MacOSX64, "native/macosx/libjinput-osx.jnilib"); + + // JInput Auxiliary (only required on Windows) + registerNativeLibrary("jinput-dx8", Platform.Windows32, "native/windows/jinput-dx8.dll"); + registerNativeLibrary("jinput-dx8", Platform.Windows64, "native/windows/jinput-dx8_64.dll"); + registerNativeLibrary("jinput-dx8", Platform.Linux32, null); + registerNativeLibrary("jinput-dx8", Platform.Linux64, null); + registerNativeLibrary("jinput-dx8", Platform.MacOSX32, null); + registerNativeLibrary("jinput-dx8", Platform.MacOSX64, null); + } + + private NativeLibraryLoader() { + } + + /** + * Specify a custom location where native libraries should + * be extracted to. Ensure this is a unique path not used + * by other applications to extract their libraries. + * + * @param path Path where to extract native libraries. + */ + public static void setCustomExtractionFolder(String path) { + extractionFolderOverride = new File(path).getAbsoluteFile(); + } + + public static File getExtractionFolder() { + if (extractionFolderOverride != null) { + return extractionFolderOverride; + } + if (extractionFolder == null) { + File workingFolder = new File("").getAbsoluteFile(); + if (!workingFolder.canWrite()) { + setExtractionDirToStorageDir(); + } else { + try { + File file = new File(workingFolder + File.separator + ".jmetestwrite"); + file.createNewFile(); + file.delete(); + extractionFolder = workingFolder; + } catch (Exception e) { + setExtractionDirToStorageDir(); + } + } + } + return extractionFolder; + } + + private static void setExtractionDirToStorageDir() { + logger.log(Level.WARNING, "Working directory is not writable. Using home directory instead."); + extractionFolder = new File(JmeSystem.getStorageFolder(), + "natives_" + Integer.toHexString(computeNativesHash())); + if (!extractionFolder.exists()) { + extractionFolder.mkdir(); + } + } + + private static int computeNativesHash() { + URLConnection conn = null; + try { + String classpath = System.getProperty("java.class.path"); + URL url = Thread.currentThread().getContextClassLoader().getResource("com/jme3/system/Natives.class"); + + StringBuilder sb = new StringBuilder(url.toString()); + if (sb.indexOf("jar:") == 0) { + sb.delete(0, 4); + sb.delete(sb.indexOf("!"), sb.length()); + sb.delete(sb.lastIndexOf("/") + 1, sb.length()); + } + try { + url = new URL(sb.toString()); + } catch (MalformedURLException ex) { + throw new UnsupportedOperationException(ex); + } + + conn = url.openConnection(); + int hash = classpath.hashCode() ^ (int) conn.getLastModified(); + return hash; + } catch (IOException ex) { + throw new UnsupportedOperationException(ex); + } finally { + if (conn != null) { + try { + conn.getInputStream().close(); + conn.getOutputStream().close(); + } catch (IOException ex) { } + } + } + } + + /** + * First extracts the native library and then loads it. + * + * @param name The name of the library to load. + * @param isRequired If true and the library fails to load, throw exception. If + * false, do nothing if it fails to load. + */ + public static void loadNativeLibrary(String name, boolean isRequired) { + if (JmeSystem.isLowPermissions()) { + throw new UnsupportedOperationException("JVM is running under " + + "reduced permissions. Cannot load native libraries."); + } + + Platform platform = JmeSystem.getPlatform(); + NativeLibrary library = nativeLibraryMap.get(new NativeLibrary.Key(name, platform)); + + if (library == null) { + // No library exists for this platform. + if (isRequired) { + throw new UnsatisfiedLinkError( + "The required native library '" + name + "'" + + " is not available for your OS: " + platform); + } else { + logger.log(Level.FINE, "The optional native library ''{0}''" + + " is not available for your OS: {1}", + new Object[]{name, platform}); + return; + } + } + + String pathInJar = library.getPathInNativesJar(); + + if (pathInJar == null) { + // This platform does not require the native library to be loaded. + return; + } + + String fileNameInJar; + if (pathInJar.contains("/")) { + fileNameInJar = pathInJar.substring(pathInJar.lastIndexOf("/") + 1); + } else { + fileNameInJar = pathInJar; + } + + URL url = Thread.currentThread().getContextClassLoader().getResource(pathInJar); + + if (url == null) { + // Try the root of the classpath as well. + url = Thread.currentThread().getContextClassLoader().getResource(fileNameInJar); + } + + if (url == null) { + // Attempt to load it as a system library. + try { + System.loadLibrary(name); + logger.log(Level.FINE, "Loaded system installed " + + "version of native library: {0}", name); + } catch (UnsatisfiedLinkError e) { + if (isRequired) { + throw new UnsatisfiedLinkError( + "The required native library '" + name + "'" + + " was not found in the classpath via '" + pathInJar + "'"); + } else { + logger.log(Level.FINE, "The optional native library ''{0}''" + + " was not found in the classpath via ''{1}''", + new Object[]{name, pathInJar}); + } + } + + return; + } + + // The library has been found and is ready to be extracted. + // Determine what filename it should be extracted as. + String loadedAsFileName; + if (library.isJNI()) { + String nameWithArch; + + // Append "64" to path + // so that we don't overwrite the 32-bit version. + if (platform.is64Bit()) { + nameWithArch = name + "64"; + } else { + nameWithArch = name; + } + + // JNI libraries on Mac / JDK6 use jnilib extension. + // JNI libraries on Mac / JDK7 use dylib extension. + loadedAsFileName = System.mapLibraryName(nameWithArch); + } else { + // Not a JNI library. + // Just use the original filename as it is in the JAR. + loadedAsFileName = fileNameInJar; + } + + File extactionDirectory = getExtractionFolder(); + URLConnection conn; + InputStream in; + + try { + conn = url.openConnection(); + in = conn.getInputStream(); + } catch (IOException ex) { + // Maybe put more detail here? Not sure.. + throw new UnsatisfiedLinkError("Failed to open file: '" + url + + "'. Error: " + ex); + } + + File targetFile = new File(extactionDirectory, loadedAsFileName); + OutputStream out = null; + try { + if (targetFile.exists()) { + // OK, compare last modified date of this file to + // file in jar + long targetLastModified = targetFile.lastModified(); + long sourceLastModified = conn.getLastModified(); + + // Allow ~1 second range for OSes that only support low precision + if (targetLastModified + 1000 > sourceLastModified) { + logger.log(Level.FINE, "Not copying library {0}. " + + "Latest already extracted.", + loadedAsFileName); + return; + } + } + + out = new FileOutputStream(targetFile); + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + + in.close(); + in = null; + out.close(); + out = null; + + // NOTE: On OSes that support "Date Created" property, + // this will cause the last modified date to be lower than + // date created which makes no sense + targetFile.setLastModified(conn.getLastModified()); + } catch (IOException ex) { + if (ex.getMessage().contains("used by another process")) { + return; + } else { + throw new UnsatisfiedLinkError("Failed to extract native " + + "library to: " + targetFile); + } + } finally { + // Not sure if we always want to load it. + // Maybe specify this as a per library setting. + System.load(targetFile.getAbsolutePath()); + + if(in != null){ + try { in.close(); } catch (IOException ex) { } + } + if(out != null){ + try { out.close(); } catch (IOException ex) { } + } + } + + logger.log(Level.FINE, "Loaded native library from ''{0}'' into ''{1}''", + new Object[]{url, targetFile}); + } + +} diff --git a/jme3-examples/src/main/java/jme3test/app/TestNativeLoader.java b/jme3-examples/src/main/java/jme3test/app/TestNativeLoader.java new file mode 100644 index 000000000..c8642ff9d --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/app/TestNativeLoader.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.app; + +import com.jme3.system.NativeLibraryLoader; +import com.jme3.util.JmeFormatter; +import java.util.logging.ConsoleHandler; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Try to load some natives. + * + * @author Kirill Vainer + */ +public class TestNativeLoader { + + public static void main(String[] args) { + Logger.getLogger("").getHandlers()[0].setLevel(Level.ALL); + Logger.getLogger("").setLevel(Level.ALL); + + NativeLibraryLoader.loadNativeLibrary("lwjgl", true); + NativeLibraryLoader.loadNativeLibrary("jinput", true); + NativeLibraryLoader.loadNativeLibrary("openal", true); + NativeLibraryLoader.loadNativeLibrary("bulletjme", false); + } +} diff --git a/jme3-lwjgl/build.gradle b/jme3-lwjgl/build.gradle index 6ed29fc60..7ab51cd65 100644 --- a/jme3-lwjgl/build.gradle +++ b/jme3-lwjgl/build.gradle @@ -5,5 +5,5 @@ if (!hasProperty('mainClass')) { dependencies { compile project(':jme3-core') compile project(':jme3-desktop') - compile 'org.lwjgl.lwjgl:lwjgl:2.9.0' + compile 'org.lwjgl.lwjgl:lwjgl:2.9.1' }