As mentioned in this post, WebStart launch under Firefox currently fails due to the current directory being the Firefox program directory.
Rather than continuing to litter libraries around the filesystem, I think it is better to choose one location for them. This patch attempts to use the following paths, in order, and chooses the first one that is writeable:
the directory manually set by the developer using Natives.setExtractionDir(), if any
{user.home}/.jme3-natives
{java.io.tmpdir}/.jme3-natives
previous method of using jar’s parent directory
{user.dir} (current working directory)
The only problem I can see with this is if the user has two jME3 programs running simultaneously and they require different native library versions (which would have been a problem anyway if they were run from the same directory, e.g. Downloads directory).
If this is perceived to be a problem, the extraction could be changed to use a temporary filename for extracting each library on each run, and delete these temp files using a shutdown hook.
[patch]
Index: src/desktop/com/jme3/system/Natives.java
===================================================================
— src/desktop/com/jme3/system/Natives.java (revision 6661)
+++ src/desktop/com/jme3/system/Natives.java (revision )
@@ -39,7 +39,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -52,10 +53,81 @@
private static final Logger logger = Logger.getLogger(Natives.class.getName());
private static final byte[] buf = new byte[1024];
- private static File workingDir = new File("").getAbsoluteFile();
- private static File extractionDir = null;
+
- protected static void autoDetectExtractionDir() {
+
-
for (int i = 0; i < 4; ++i) {<br />
-
File dir = null;<br />
-
switch (i) {<br />
-
case 0:<br />
-
dir = new File(System.getProperty("user.home"), ".jme3-natives");<br />
-
dir.mkdirs(); // don't check return result, let testDirectoryWriteable handle it<br />
-
break;<br />
-
case 1:<br />
-
dir = new File(System.getProperty("java.io.tmpdir", ".jme3-natives"));<br />
-
dir.mkdirs(); // don't check return result, let testDirectoryWriteable handle it<br />
-
break;<br />
-
case 2:<br />
-
dir = getParentDir();<br />
-
break;<br />
-
case 3:<br />
-
dir = new File(System.getProperty("user.dir"));<br />
-
break;<br />
-
}<br />
+
-
logger.log(Level.INFO, "Extraction Directory #" + (i + 1) + ": " + dir);<br />
-
if (dir == null) continue;<br />
+
-
if (testDirectoryWriteable(dir)) {<br />
-
extractionDir = dir.getAbsoluteFile();<br />
-
logger.log(Level.INFO, "Chosen Extraction Directory: " + dir);<br />
-
return;<br />
-
}<br />
-
}<br />
+
-
logger.log(Level.SEVERE, "Unable to find a writeable extraction directory.");<br />
-
throw new RuntimeException("Unable to find a writeable directory to extract native libraries.");<br />
- }
+
+
- /**
-
* Test that the given directory exists and can be written in.<br />
-
*<br />
-
* @param dir the directory to test.<br />
-
* @return true if the directory exists and is writeable<br />
-
*/<br />
- public static boolean testDirectoryWriteable(File dir) {
-
if (!dir.isDirectory()) {<br />
-
return false;<br />
-
}<br />
+
-
File testFile;<br />
-
try {<br />
-
testFile = File.createTempFile("jme3", null, dir);<br />
+
-
//test write<br />
-
FileOutputStream os = new FileOutputStream(testFile);<br />
-
try {<br />
-
os.write(65);<br />
-
} finally {<br />
-
os.close();<br />
-
}<br />
+
-
if (!testFile.delete()) {<br />
-
logger.log(Level.WARNING, "Unable to delete test file " + testFile);<br />
-
return false;<br />
-
}<br />
+
-
return true;<br />
-
} catch (IOException e) {<br />
-
return false;<br />
-
}<br />
- }
+
public static void setExtractionDir(String name){
-
workingDir = new File(name).getAbsoluteFile();<br />
-
extractionDir = new File(name).getAbsoluteFile();<br />
}
protected static void extractNativeLib(String sysName, String name) throws IOException{
@@ -65,11 +137,11 @@
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
//InputStream in = Natives.class.getResourceAsStream();
if (in == null) {
-
logger.log(Level.WARNING, "Cannot locate native library: {0}/{1}",<br />
-
logger.log(Level.WARNING, "Cannot locate native library: {0}/{1}",<br />
new String[]{ sysName, fullname} );
return;
}
-
File targetFile = new File(workingDir, fullname);<br />
-
File targetFile = new File(extractionDir, fullname);<br />
try {
OutputStream out = new FileOutputStream(targetFile);
int len;
@@ -86,9 +158,11 @@
}
logger.log(Level.FINE, "Copied {0} to {1}", new Object[]{fullname, targetFile});
+
-
Runtime.getRuntime().load(targetFile.getAbsolutePath());<br />
}
- private static String getExtractionDir(){
- private static File getParentDir() {
URL temp = Natives.class.getResource("");
if (temp != null) {
StringBuilder sb = new StringBuilder(temp.toString());
@@ -98,11 +172,17 @@
sb.delete(sb.lastIndexOf("/") + 1, sb.length());
}
try {
-
return new URL(sb.toString()).toString();<br />
-
} catch (MalformedURLException ex) {<br />
-
URI uri = new URI(sb.toString());<br />
-
String scheme = uri.getScheme();<br />
-
if (scheme != null && scheme.equalsIgnoreCase("file")) {<br />
-
return new File(uri);<br />
-
} else {<br />
-
return null;<br />
-
}<br />
-
return null;<br />
-
}<br />
-
} catch (URISyntaxException e) {<br />
-
return null;<br />
-
}<br />
-
}<br />
-
}<br />
return null;
}
@@ -135,15 +215,19 @@
}
needJInput = settings.useJoysticks();
-
if (extractionDir == null) {<br />
-
autoDetectExtractionDir();<br />
-
}<br />
+
if (needLWJGL){
-
logger.log(Level.INFO, "Extraction Directory #1: {0}", getExtractionDir());<br />
-
logger.log(Level.INFO, "Extraction Directory #2: {0}", workingDir.toString());<br />
-
logger.log(Level.INFO, "Extraction Directory #3: {0}", System.getProperty("user.dir"));<br />
// LWJGL supports this feature where
// it can load libraries from this path.
// This is a fallback method in case the OS doesn’t load
// native libraries from the working directory (e.g Linux).
-
System.setProperty("org.lwjgl.librarypath", workingDir.toString());<br />
-
System.setProperty("org.lwjgl.librarypath", extractionDir.toString());<br />
}
switch (platform){
[/patch]
-davidc