Skip to content
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
wants to merge 2 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,36 @@
*
* It will search for the library in order at the following locations:
* <ol>
* <li> in the custom library path: If the "<code>library.${name}.path</code>" 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> "<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> as "<code>${name}${bit-model}-${version}</code>" library name if the version can be determined.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you add that? System library path (LD_LIBRARY_PATH, rpath) will unlikely contain the bit model. It looks unnecessary to me.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did I add to documentation what was done in code?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then this is OK, assumed you have changed the code too. It's an unrelated change though.

* <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 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> "<code>META-INF/native/${platform}/${arch}/${library}</code>": 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this version necessary for our usecase? Especially because only one version of the native library should exist once in the classpath OR the JAR from central contains its version anyway.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

once again, I'm not judging anything: I'm just keeping existing features, even if I never used it myself

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

* more than one platform JNI library on different processor archs in the jar.
* <li> "<code>META-INF/native/${platform}/${library}</code>": 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> "<code>META-INF/native/${os}/${library}</code>": Store your library here if you want to embed more
* <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}</code>": Store your library here if your JAR is only going to embedding one
* <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.
Expand All @@ -60,8 +69,9 @@
* JVM is a 32 bit process</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}</code>": is the normal jni library name for the platform. 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>
* <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>
Expand Down Expand Up @@ -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 */
Expand All @@ -174,63 +190,91 @@ private void doLoad() {

/* Try extracting the library from the jar */
if( classLoader!=null ) {
if( extractAndLoad(errors, version, customPath, getArchSpecifcResourcePath()) )
return;
if( extractAndLoad(errors, version, customPath, getPlatformSpecifcResourcePath()) )
return;
if( extractAndLoad(errors, version, customPath, getOperatingSystemSpecifcResourcePath()) )
return;
// For the simpler case where only 1 platform lib is getting packed into the jar
if( extractAndLoad(errors, version, customPath, getResourcePath()) )
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());
}

/**
* 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
};
}

@Deprecated
final public String getArchSpecifcResourcePath() {
return getPlatformSpecifcResourcePath(getPlatform() + "/" + System.getProperty("os.arch"));
}
final public String getOperatingSystemSpecifcResourcePath() {
return getPlatformSpecifcResourcePath(getOperatingSystem());
}
@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 getResorucePath() {
return getResourcePath();
final public String getOperatingSystemSpecifcResourcePath() {
return getPlatformSpecifcResourcePath(getOperatingSystem());
}

@Deprecated
final public String getResourcePath() {
return "META-INF/native/"+map(name);
}

@Deprecated
final public String getLibraryFileName() {
return map(name);
}


private boolean extractAndLoad(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));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extractToTmpFile?

if( target!=null ) {
if( load(errors, target) ) {
return true;
Expand All @@ -240,7 +284,7 @@ private boolean extractAndLoad(ArrayList<String> errors, String version, String

// 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));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

if( target!=null ) {
if( load(errors, target) ) {
return true;
Expand All @@ -255,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);
}
}
Expand All @@ -275,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();
Expand All @@ -284,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];
Expand Down