From 590f254ad4f3d9077e144758d49849330aa46fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Boutemy?= Date: Sat, 18 Mar 2017 16:25:17 +0100 Subject: [PATCH 1/2] fixed typos and improved javadoc --- .../fusesource/hawtjni/runtime/Library.java | 64 ++++++++++--------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/hawtjni-runtime/src/main/java/org/fusesource/hawtjni/runtime/Library.java b/hawtjni-runtime/src/main/java/org/fusesource/hawtjni/runtime/Library.java index be51a193..bdfe3f85 100755 --- a/hawtjni-runtime/src/main/java/org/fusesource/hawtjni/runtime/Library.java +++ b/hawtjni-runtime/src/main/java/org/fusesource/hawtjni/runtime/Library.java @@ -11,61 +11,61 @@ 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: *
    - *
  1. in the custom library path: If the "library.${name}.path" System property is set to a directory + *
  2. in the custom library path: If the "library.${name}.path" System property is set to a directory *
      - *
    1. "${name}-${version}" if the version can be determined. - *
    2. "${name}" + *
    3. as "${name}-${version}" library name if the version can be determined. + *
    4. as "${name}" library name *
    *
  3. system library path: This is where the JVM looks for JNI libraries by default. *
      - *
    1. "${name}-${version}" if the version can be determined. - *
    2. "${name}" + *
    3. as "${name}-${version}" library name if the version can be determined. + *
    4. as "${name}" library name *
    *
  4. 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: *
      - *
    1. "META-INF/native/${platform}/${arch}/${library}" : Store your library here if you want to embed + *
    2. "META-INF/native/${platform}/${arch}/${library}": Store your library here if you want to embed * more than one platform JNI library on different processor archs in the jar. - *
    3. "META-INF/native/${platform}/${library}" : Store your library here if you want to embed more + *
    4. "META-INF/native/${platform}/${library}": Store your library here if you want to embed more * than one platform JNI library in the jar. - *
    5. "META-INF/native/${library}": Store your library here if your JAR is only going to embedding one + *
    6. "META-INF/native/${os}/${library}": 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. + *
    7. "META-INF/native/${library}": Store your library here if your JAR is only going to embedding one * platform library. *
    * The file extraction is attempted until it succeeds in the following directories. *
      - *
    1. The directory pointed to by the "library.${name}.path" System property (if set) - *
    2. a temporary directory (uses the "java.io.tmpdir" System property) + *
    3. The directory pointed to by the "library.${name}.path" System property (if set) + *
    4. a temporary directory (uses the "java.io.tmpdir" System property) *
    *
* * where: * * * @author Hiram Chirino + * @see System#mapLibraryName(String) */ public class Library { @@ -174,14 +174,14 @@ private void doLoad() { /* Try extracting the library from the jar */ if( classLoader!=null ) { - if( exractAndLoad(errors, version, customPath, getArchSpecifcResourcePath()) ) + if( extractAndLoad(errors, version, customPath, getArchSpecifcResourcePath()) ) return; - if( exractAndLoad(errors, version, customPath, getPlatformSpecifcResourcePath()) ) + if( extractAndLoad(errors, version, customPath, getPlatformSpecifcResourcePath()) ) return; - if( exractAndLoad(errors, version, customPath, getOperatingSystemSpecifcResourcePath()) ) + if( extractAndLoad(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()) ) + if( extractAndLoad(errors, version, customPath, getResourcePath()) ) return; } @@ -190,9 +190,8 @@ private void doLoad() { } final public String getArchSpecifcResourcePath() { - return "META-INF/native/"+ getPlatform() + "/" + System.getProperty("os.arch") + "/" +map(name); + return getPlatformSpecifcResourcePath(getPlatform() + "/" + System.getProperty("os.arch")); } - final public String getOperatingSystemSpecifcResourcePath() { return getPlatformSpecifcResourcePath(getOperatingSystem()); } @@ -203,7 +202,12 @@ final public String getPlatformSpecifcResourcePath(String platform) { return "META-INF/native/"+platform+"/"+map(name); } + @Deprecated final public String getResorucePath() { + return getResourcePath(); + } + + final public String getResourcePath() { return "META-INF/native/"+map(name); } @@ -212,7 +216,7 @@ final public String getLibraryFileName() { } - private boolean exractAndLoad(ArrayList errors, String version, String customPath, String resourcePath) { + private boolean extractAndLoad(ArrayList errors, String version, String customPath, String resourcePath) { URL resource = classLoader.getResource(resourcePath); if( resource !=null ) { From 8fa44a1189e51b84f77991d38a330fa171918ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Boutemy?= Date: Sun, 19 Mar 2017 11:51:49 +0100 Subject: [PATCH 2/2] search in library.$name.path like in META-INF/native resources --- .../fusesource/hawtjni/runtime/Library.java | 134 ++++++++++++------ 1 file changed, 89 insertions(+), 45 deletions(-) diff --git a/hawtjni-runtime/src/main/java/org/fusesource/hawtjni/runtime/Library.java b/hawtjni-runtime/src/main/java/org/fusesource/hawtjni/runtime/Library.java index bdfe3f85..7698624a 100755 --- a/hawtjni-runtime/src/main/java/org/fusesource/hawtjni/runtime/Library.java +++ b/hawtjni-runtime/src/main/java/org/fusesource/hawtjni/runtime/Library.java @@ -20,13 +20,22 @@ * * It will search for the library in order at the following locations: *
    - *
  1. in the custom library path: If the "library.${name}.path" System property is set to a directory + *
  2. in the custom library path: If the "library.${name}.path" System property is set to a directory, + * subdirectories are searched: + *
      + *
    1. "${platform}/${arch}" + *
    2. "${platform}" + *
    3. "${os}" + *
    4. "" + *
    + * for 2 namings of the library: *
      *
    1. as "${name}-${version}" library name if the version can be determined. *
    2. as "${name}" library name *
    *
  3. system library path: This is where the JVM looks for JNI libraries by default. *
      + *
    1. as "${name}${bit-model}-${version}" library name if the version can be determined. *
    2. as "${name}-${version}" library name if the version can be determined. *
    3. as "${name}" library name *
    @@ -34,13 +43,13 @@ * 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: *
      - *
    1. "META-INF/native/${platform}/${arch}/${library}": Store your library here if you want to embed + *
    2. "META-INF/native/${platform}/${arch}/${library[-version]}": Store your library here if you want to embed * more than one platform JNI library on different processor archs in the jar. - *
    3. "META-INF/native/${platform}/${library}": Store your library here if you want to embed more + *
    4. "META-INF/native/${platform}/${library[-version]}": Store your library here if you want to embed more * than one platform JNI library in the jar. - *
    5. "META-INF/native/${os}/${library}": Store your library here if you want to embed more + *
    6. "META-INF/native/${os}/${library[-version]}": 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. - *
    7. "META-INF/native/${library}": Store your library here if your JAR is only going to embedding one + *
    8. "META-INF/native/${library[-version]}": Store your library here if your JAR is only going to embedding one * platform library. *
    * The file extraction is attempted until it succeeds in the following directories. @@ -60,8 +69,9 @@ * JVM is a 32 bit process
  4. *
  5. "${arch}" is the architecture for the processor, for example "amd64" or "sparcv9"
  6. *
  7. "${platform}" is "${os}${bit-model}", for example "linux32" or "osx64"
  8. - *
  9. "${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
  10. + *
  11. "${library[-version]}": is the normal jni library name for the platform (eventually with -${version}) suffix. + * For example "${name}.dll" on + * windows, "lib${name}.jnilib" on OS X, and "lib${name}.so" on linux
  12. * * * @author Hiram Chirino @@ -154,13 +164,19 @@ private void doLoad() { } ArrayList errors = new ArrayList(); + 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,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:
      + *
    • ${platform}/${arch} to enable platform JNI library for different processor archs
    • + *
    • ${platform} to enable platform JNI library
    • + *
    • ${os} to enable OS JNI library
    • + *
    • no directory
    • + *
    + * @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 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 META-INF/native/${dir}/${filename} 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 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; @@ -240,7 +284,7 @@ private boolean extractAndLoad(ArrayList 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)); if( target!=null ) { if( load(errors, target) ) { return true; @@ -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); } } @@ -275,7 +319,7 @@ private String map(String libName) { return libName; } - private File extract(ArrayList errors, URL source, String prefix, String suffix, File directory) { + private File extracttoTmpFile(ArrayList errors, URL source, String tmpFilePrefix, String tpmFileSuffix, File directory) { File target = null; if (directory != null) { directory = directory.getAbsoluteFile(); @@ -284,7 +328,7 @@ private File extract(ArrayList 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];