2 * Copyright (c) 2009-2010 jMonkeyEngine
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 package com.jme3.system;
35 import java.net.MalformedURLException;
37 import java.net.URLConnection;
38 import java.util.logging.Level;
39 import java.util.logging.Logger;
42 * Helper class for extracting the natives (dll, so) from the jars.
43 * This class should only be used internally.
45 public class Natives {
47 private static final Logger logger = Logger.getLogger(Natives.class.getName());
48 private static final byte[] buf = new byte[1024];
49 private static File workingDir = new File("").getAbsoluteFile();
51 public static void setExtractionDir(String name) {
52 workingDir = new File(name).getAbsoluteFile();
55 protected static void extractNativeLib(String sysName, String name) throws IOException {
56 extractNativeLib(sysName, name, false, true);
59 protected static void extractNativeLib(String sysName, String name, boolean load) throws IOException {
60 extractNativeLib(sysName, name, load, true);
63 protected static void extractNativeLib(String sysName, String name, boolean load, boolean warning) throws IOException {
64 String fullname = System.mapLibraryName(name);
66 String path = "native/" + sysName + "/" + fullname;
67 URL url = Thread.currentThread().getContextClassLoader().getResource(path);
70 if (sysName.equals("macosx")) {
71 fullname = fullname.replace(".dylib", ".jnilib");
72 String path2 = "native/" + sysName + "/" + fullname;
73 // logger.warning("retry "+path2);
74 url = Thread.currentThread().getContextClassLoader().getResource(path2);
77 logger.log(Level.WARNING, "Cannot locate native library: {0}/{1}",
78 new String[]{sysName, fullname});
84 logger.log(Level.WARNING, "Cannot locate native library: {0}/{1}",
85 new String[]{sysName, fullname});
91 URLConnection conn = url.openConnection();
92 InputStream in = conn.getInputStream();
93 File targetFile = new File(workingDir, fullname);
94 // logger.info("targetFile = "+targetFile.getPath());
95 if (targetFile.exists()){
96 // OK, compare last modified date of this file to
98 long targetLastModified = targetFile.lastModified();
99 long sourceLastModified = conn.getLastModified();
101 // Allow ~1 second range for OSes that only support low precision
102 if (targetLastModified + 1000 > sourceLastModified){
103 logger.log(Level.FINE, "Not copying library {0}. Latest already extracted.", fullname);
108 OutputStream out = new FileOutputStream(targetFile);
110 while ((len = in.read(buf)) > 0) {
111 out.write(buf, 0, len);
116 // NOTE: On OSes that support "Date Created" property,
117 // this will cause the last modified date to be lower than
118 // date created which makes no sense
119 targetFile.setLastModified(conn.getLastModified());
120 } catch (FileNotFoundException ex) {
121 if (ex.getMessage().contains("used by another process")) {
128 logger.log(Level.INFO, "Load native library {0}", targetFile.getAbsolutePath());
129 System.load(targetFile.getAbsolutePath());
132 logger.log(Level.FINE, "Copied {0} to {1}", new Object[]{fullname, targetFile});
135 private static String getExtractionDir() {
136 URL temp = Natives.class.getResource("");
138 StringBuilder sb = new StringBuilder(temp.toString());
139 if (sb.indexOf("jar:") == 0) {
141 sb.delete(sb.indexOf("!"), sb.length());
142 sb.delete(sb.lastIndexOf("/") + 1, sb.length());
145 return new URL(sb.toString()).toString();
146 } catch (MalformedURLException ex) {
153 protected static boolean isUsingNativeBullet(){
155 Class clazz = Class.forName("com.jme3.bullet.util.NativeMeshUtil");
156 return clazz != null;
157 } catch (ClassNotFoundException ex) {
162 protected static void extractNativeLibs(Platform platform, AppSettings settings) throws IOException {
163 String renderer = settings.getRenderer();
164 String audioRenderer = settings.getAudioRenderer();
165 boolean needLWJGL = false;
166 boolean needOAL = false;
167 boolean needJInput = false;
168 boolean needNativeBullet = isUsingNativeBullet();
169 if (renderer != null) {
170 if (renderer.startsWith("LWJGL")) {
174 if (audioRenderer != null) {
175 if (audioRenderer.equals("LWJGL")) {
180 needJInput = settings.useJoysticks();
183 logger.log(Level.INFO, "Extraction Directory #1: {0}", getExtractionDir());
184 logger.log(Level.INFO, "Extraction Directory #2: {0}", workingDir.toString());
185 // logger.log(Level.INFO, "Extraction Directory #3: {0}", System.getProperty("user.dir"));
186 // LWJGL supports this feature where
187 // it can load libraries from this path.
188 // This is a fallback method in case the OS doesn't load
189 // native libraries from the working directory (e.g Linux).
190 System.setProperty("org.lwjgl.librarypath", workingDir.toString());
196 extractNativeLib("windows", "lwjgl64");
199 extractNativeLib("windows", "OpenAL64");
202 extractNativeLib("windows", "jinput-dx8_64");
203 extractNativeLib("windows", "jinput-raw_64");
205 if (needNativeBullet) {
206 extractNativeLib("windows", "bulletjme64", true, false);
211 extractNativeLib("windows", "lwjgl");
214 extractNativeLib("windows", "OpenAL32");
217 extractNativeLib("windows", "jinput-dx8");
218 extractNativeLib("windows", "jinput-raw");
220 if (needNativeBullet) {
221 extractNativeLib("windows", "bulletjme", true, false);
226 extractNativeLib("linux", "lwjgl64");
229 extractNativeLib("linux", "jinput-linux64");
232 extractNativeLib("linux", "openal64");
234 if (needNativeBullet) {
235 extractNativeLib("linux", "bulletjme64", true, false);
240 extractNativeLib("linux", "lwjgl");
243 extractNativeLib("linux", "jinput-linux");
246 extractNativeLib("linux", "openal");
248 if (needNativeBullet) {
249 extractNativeLib("linux", "bulletjme", true, false);
254 extractNativeLib("solaris", "lwjgl64");
257 // extractNativeLib("solaris", "jinput-linux64");
260 extractNativeLib("solaris", "openal64");
262 if (needNativeBullet) {
263 extractNativeLib("solaris", "bulletjme64", true, false);
268 extractNativeLib("solaris", "lwjgl");
271 // extractNativeLib("solaris", "jinput-linux");
274 extractNativeLib("solaris", "openal");
276 if (needNativeBullet) {
277 extractNativeLib("solaris", "bulletjme", true, false);
285 extractNativeLib("macosx", "lwjgl");
288 extractNativeLib("macosx", "openal");
290 extractNativeLib("macosx", "jinput-osx");
292 if (needNativeBullet) {
293 extractNativeLib("macosx", "bulletjme", true, false);