-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extended search #35
Closed
Closed
Extended search #35
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,61 +11,71 @@ | |
|
||
import java.io.*; | ||
import java.lang.reflect.Method; | ||
import java.net.MalformedURLException; | ||
import java.net.URL; | ||
import java.util.ArrayList; | ||
import java.util.Random; | ||
import java.util.Set; | ||
import java.util.regex.Pattern; | ||
|
||
/** | ||
* Used to optionally extract and load a JNI library. | ||
* Used to find and load a JNI library, eventually after having extracted it. | ||
* | ||
* It will search for the library in order at the following locations: | ||
* <ol> | ||
* <li> in the custom library path: If the "library.${name}.path" System property is set to a directory | ||
* <li> in the custom library path: If the "<code>library.${name}.path</code>" System property is set to a directory, | ||
* subdirectories are searched: | ||
* <ol> | ||
* <li> "${name}-${version}" if the version can be determined. | ||
* <li> "${name}" | ||
* <li> "<code>${platform}/${arch}</code>" | ||
* <li> "<code>${platform}</code>" | ||
* <li> "<code>${os}</code>" | ||
* <li> "<code></code>" | ||
* </ol> | ||
* for 2 namings of the library: | ||
* <ol> | ||
* <li> as "<code>${name}-${version}</code>" library name if the version can be determined. | ||
* <li> as "<code>${name}</code>" library name | ||
* </ol> | ||
* <li> system library path: This is where the JVM looks for JNI libraries by default. | ||
* <ol> | ||
* <li> "${name}-${version}" if the version can be determined. | ||
* <li> "${name}" | ||
* <li> as "<code>${name}${bit-model}-${version}</code>" library name if the version can be determined. | ||
* <li> as "<code>${name}-${version}</code>" library name if the version can be determined. | ||
* <li> as "<code>${name}</code>" library name | ||
* </ol> | ||
* <li> classpath path: If the JNI library can be found on the classpath, it will get extracted | ||
* and and then loaded. This way you can embed your JNI libraries into your packaged JAR files. | ||
* and then loaded. This way you can embed your JNI libraries into your packaged JAR files. | ||
* They are looked up as resources in this order: | ||
* <ol> | ||
* <li> "META-INF/native/${platform}/${arch}/${library}" : Store your library here if you want to embed | ||
* <li> "<code>META-INF/native/${platform}/${arch}/${library[-version]}</code>": Store your library here if you want to embed | ||
* more than one platform JNI library on different processor archs in the jar. | ||
* <li> "META-INF/native/${platform}/${library}" : Store your library here if you want to embed more | ||
* <li> "<code>META-INF/native/${platform}/${library[-version]}</code>": Store your library here if you want to embed more | ||
* than one platform JNI library in the jar. | ||
* <li> "META-INF/native/${library}": Store your library here if your JAR is only going to embedding one | ||
* <li> "<code>META-INF/native/${os}/${library[-version]}</code>": Store your library here if you want to embed more | ||
* than one platform JNI library in the jar but don't want to take bit model into account. | ||
* <li> "<code>META-INF/native/${library[-version]}</code>": Store your library here if your JAR is only going to embedding one | ||
* platform library. | ||
* </ol> | ||
* The file extraction is attempted until it succeeds in the following directories. | ||
* <ol> | ||
* <li> The directory pointed to by the "library.${name}.path" System property (if set) | ||
* <li> a temporary directory (uses the "java.io.tmpdir" System property) | ||
* <li> The directory pointed to by the "<code>library.${name}.path</code>" System property (if set) | ||
* <li> a temporary directory (uses the "<code>java.io.tmpdir</code>" System property) | ||
* </ol> | ||
* </ol> | ||
* | ||
* where: | ||
* <ul> | ||
* <li>"${name}" is the name of library | ||
* <li>"${version}" is the value of "library.${name}.version" System property if set. | ||
* <li>"<code>${name}</code>" is the name of library | ||
* <li>"<code>${version}</code>" is the value of "<code>library.${name}.version</code>" System property if set. | ||
* Otherwise it is set to the ImplementationVersion property of the JAR's Manifest</li> | ||
* <li>"${os}" is your operating system, for example "osx", "linux", or "windows"</li> | ||
* <li>"${bit-model}" is "64" if the JVM process is a 64 bit process, otherwise it's "32" if the | ||
* <li>"<code>${os}</code>" is your operating system, for example "<code>osx</code>", "<code>linux</code>", or "<code>windows</code>"</li> | ||
* <li>"<code>${bit-model}</code>" is "<code>64</code>" if the JVM process is a 64 bit process, otherwise it's "<code>32</code>" if the | ||
* JVM is a 32 bit process</li> | ||
* <li>"${arch}" is the architecture for the processor, for example "amd64" or "sparcv9"</li> | ||
* <li>"${platform}" is "${os}${bit-model}", for example "linux32" or "osx64" </li> | ||
* <li>"${library}": is the normal jni library name for the platform. For example "${name}.dll" on | ||
* windows, "lib${name}.jnilib" on OS X, and "lib${name}.so" on linux</li> | ||
* <li>"<code>${arch}</code>" is the architecture for the processor, for example "<code>amd64</code>" or "<code>sparcv9</code>"</li> | ||
* <li>"<code>${platform}</code>" is "<code>${os}${bit-model}</code>", for example "<code>linux32</code>" or "<code>osx64</code>" </li> | ||
* <li>"<code>${library[-version]}</code>": is the normal jni library name for the platform (eventually with <code>-${version}</code>) suffix. | ||
* For example "<code>${name}.dll</code>" on | ||
* windows, "<code>lib${name}.jnilib</code>" on OS X, and "<code>lib${name}.so</code>" on linux</li> | ||
* </ul> | ||
* | ||
* @author <a href="http://hiramchirino.com">Hiram Chirino</a> | ||
* @see System#mapLibraryName(String) | ||
*/ | ||
public class Library { | ||
|
||
|
@@ -154,13 +164,19 @@ private void doLoad() { | |
} | ||
ArrayList<String> errors = new ArrayList<String>(); | ||
|
||
String[] specificDirs = getSpecificSearchDirs(); | ||
String libFilename = map(name); | ||
String versionlibFilename = (version == null) ? null : map(name + "-" + version); | ||
|
||
/* Try loading library from a custom library path */ | ||
String customPath = System.getProperty("library."+name+".path"); | ||
if (customPath != null) { | ||
if( version!=null && load(errors, file(customPath, map(name + "-" + version))) ) | ||
return; | ||
if( load(errors, file(customPath, map(name))) ) | ||
return; | ||
for ( String dir: specificDirs ) { | ||
if( version!=null && load(errors, file(customPath, dir, versionlibFilename)) ) | ||
return; | ||
if( load(errors, file(customPath, dir, libFilename)) ) | ||
return; | ||
} | ||
} | ||
|
||
/* Try loading library from java library path */ | ||
|
@@ -174,59 +190,91 @@ private void doLoad() { | |
|
||
/* Try extracting the library from the jar */ | ||
if( classLoader!=null ) { | ||
if( exractAndLoad(errors, version, customPath, getArchSpecifcResourcePath()) ) | ||
return; | ||
if( exractAndLoad(errors, version, customPath, getPlatformSpecifcResourcePath()) ) | ||
return; | ||
if( exractAndLoad(errors, version, customPath, getOperatingSystemSpecifcResourcePath()) ) | ||
return; | ||
// For the simpler case where only 1 platform lib is getting packed into the jar | ||
if( exractAndLoad(errors, version, customPath, getResorucePath()) ) | ||
return; | ||
for ( String dir: specificDirs ) { | ||
if( version!=null && extractAndLoad(errors, customPath, dir, versionlibFilename) ) | ||
return; | ||
if( extractAndLoad(errors, customPath, dir, libFilename) ) | ||
return; | ||
} | ||
} | ||
|
||
/* Failed to find the library */ | ||
throw new UnsatisfiedLinkError("Could not load library. Reasons: " + errors.toString()); | ||
} | ||
|
||
final public String getArchSpecifcResourcePath() { | ||
return "META-INF/native/"+ getPlatform() + "/" + System.getProperty("os.arch") + "/" +map(name); | ||
/** | ||
* Search directories for library:<ul> | ||
* <li><code>${platform}/${arch}</code> to enable platform JNI library for different processor archs</li> | ||
* <li><code>${platform}</code> to enable platform JNI library</li> | ||
* <li><code>${os}</code> to enable OS JNI library</li> | ||
* <li>no directory</li> | ||
* </ul> | ||
* @return the list | ||
*/ | ||
final public String[] getSpecificSearchDirs() { | ||
return new String[] { | ||
getPlatform() + "/" + System.getProperty("os.arch"), | ||
getPlatform(), | ||
getOperatingSystem(), | ||
null | ||
}; | ||
} | ||
|
||
final public String getOperatingSystemSpecifcResourcePath() { | ||
return getPlatformSpecifcResourcePath(getOperatingSystem()); | ||
@Deprecated | ||
final public String getArchSpecifcResourcePath() { | ||
return getPlatformSpecifcResourcePath(getPlatform() + "/" + System.getProperty("os.arch")); | ||
} | ||
@Deprecated | ||
final public String getPlatformSpecifcResourcePath() { | ||
return getPlatformSpecifcResourcePath(getPlatform()); | ||
} | ||
final public String getPlatformSpecifcResourcePath(String platform) { | ||
return "META-INF/native/"+platform+"/"+map(name); | ||
@Deprecated | ||
final public String getOperatingSystemSpecifcResourcePath() { | ||
return getPlatformSpecifcResourcePath(getOperatingSystem()); | ||
} | ||
|
||
final public String getResorucePath() { | ||
@Deprecated | ||
final public String getResourcePath() { | ||
return "META-INF/native/"+map(name); | ||
} | ||
|
||
@Deprecated | ||
final public String getLibraryFileName() { | ||
return map(name); | ||
} | ||
|
||
|
||
private boolean exractAndLoad(ArrayList<String> errors, String version, String customPath, String resourcePath) { | ||
@Deprecated | ||
final public String getPlatformSpecifcResourcePath(String platform) { | ||
return "META-INF/native/"+platform+"/"+map(name); | ||
} | ||
|
||
@Deprecated | ||
final public String getResorucePath() { | ||
return getResourcePath(); | ||
} | ||
|
||
/** | ||
* Extract <code>META-INF/native/${dir}/${filename}</code> resource to a temporary file | ||
* in customPath (if defined) or java.io.tmpdir | ||
* @param errors list of error messages gathered during the whole loading mechanism | ||
* @param customPath custom path to store the temporary file (can be null) | ||
* @param dir the directory | ||
* @param filename the file name | ||
* @return a boolean telling if the library was found and loaded | ||
*/ | ||
private boolean extractAndLoad(ArrayList<String> errors, String customPath, String dir, String filename) { | ||
String resourcePath = "META-INF/native/" + ( dir == null ? "" : (dir + '/')) + filename; | ||
URL resource = classLoader.getResource(resourcePath); | ||
if( resource !=null ) { | ||
|
||
String libName = name + "-" + getBitModel(); | ||
if( version !=null) { | ||
libName += "-" + version; | ||
} | ||
String []libNameParts = map(libName).split("\\."); | ||
String prefix = libNameParts[0]+"-"; | ||
String suffix = "."+libNameParts[1]; | ||
if( resource ==null ) { | ||
errors.add( "resource " + resourcePath + " not found" ); | ||
} else { | ||
String []libNameParts = resourcePath.substring(16).replace('/','_').split("\\."); | ||
String tmpFilePrefix = libNameParts[0]+"-"; | ||
String tmpFileSuffix = "."+libNameParts[1]; | ||
|
||
if( customPath!=null ) { | ||
// Try to extract it to the custom path... | ||
File target = extract(errors, resource, prefix, suffix, file(customPath)); | ||
File target = extracttoTmpFile(errors, resource, tmpFilePrefix, tmpFileSuffix, file(customPath)); | ||
if( target!=null ) { | ||
if( load(errors, target) ) { | ||
return true; | ||
|
@@ -236,7 +284,7 @@ private boolean exractAndLoad(ArrayList<String> errors, String version, String c | |
|
||
// Fall back to extracting to the tmp dir | ||
customPath = System.getProperty("java.io.tmpdir"); | ||
File target = extract(errors, resource, prefix, suffix, file(customPath)); | ||
File target = extracttoTmpFile(errors, resource, tmpFilePrefix, tmpFileSuffix, file(customPath)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. |
||
if( target!=null ) { | ||
if( load(errors, target) ) { | ||
return true; | ||
|
@@ -251,7 +299,7 @@ private File file(String ...paths) { | |
for (String path : paths) { | ||
if( rc == null ) { | ||
rc = new File(path); | ||
} else { | ||
} else if( path != null ) { | ||
rc = new File(rc, path); | ||
} | ||
} | ||
|
@@ -271,7 +319,7 @@ private String map(String libName) { | |
return libName; | ||
} | ||
|
||
private File extract(ArrayList<String> errors, URL source, String prefix, String suffix, File directory) { | ||
private File extracttoTmpFile(ArrayList<String> errors, URL source, String tmpFilePrefix, String tpmFileSuffix, File directory) { | ||
File target = null; | ||
if (directory != null) { | ||
directory = directory.getAbsoluteFile(); | ||
|
@@ -280,7 +328,7 @@ private File extract(ArrayList<String> errors, URL source, String prefix, String | |
FileOutputStream os = null; | ||
InputStream is = null; | ||
try { | ||
target = File.createTempFile(prefix, suffix, directory); | ||
target = File.createTempFile(tmpFilePrefix, tpmFileSuffix, directory); | ||
is = source.openStream(); | ||
if (is != null) { | ||
byte[] buffer = new byte[4096]; | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extractToTmpFile
?