From 722dde63df58e144bff8933de6c662fe8c1e08e4 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Wed, 24 Jan 2024 01:02:44 +0100 Subject: [PATCH] Native libraries: system property `flatlaf.nativeLibraryPath` now supports loading native libraries named the same as on Maven central; improved log messages for loading fails (issue #797) --- CHANGELOG.md | 6 ++ .../formdev/flatlaf/FlatSystemProperties.java | 24 ++++-- .../formdev/flatlaf/ui/FlatNativeLibrary.java | 80 +++++++++++++------ 3 files changed, 82 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4079cd45..99b69683 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ FlatLaf Change Log ## 3.4-SNAPSHOT +#### New features and improvements + +- Native libraries: System property `flatlaf.nativeLibraryPath` now supports + loading native libraries named the same as on Maven central. Improved log + messages for loading fails. + #### Fixed bugs - JIDE CommandMenuBar: Fixed `ClassCastException` when JIDE command bar displays diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatSystemProperties.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatSystemProperties.java index 6b360fdf..d0ce1907 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatSystemProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatSystemProperties.java @@ -172,19 +172,33 @@ public interface FlatSystemProperties String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary"; /** - * Specifies a directory in which the native FlatLaf libraries have been extracted. + * Specifies a directory in which the FlatLaf native libraries are searched for. * The path can be absolute or relative to current application working directory. * This can be used to avoid extraction of the native libraries to the temporary directory at runtime. *

- * If the value is {@code "system"}, then {@link System#loadLibrary(String)} is - * used to load the native library. - * Searches for the native library in classloader of caller + * If the value is {@code "system"} (supported since FlatLaf 2.6), + * then {@link System#loadLibrary(String)} is used to load the native library. + * This searches for the native library in classloader of caller * (using {@link ClassLoader#findLibrary(String)}) and in paths specified * in system properties {@code sun.boot.library.path} and {@code java.library.path}. - * (supported since FlatLaf 2.6) *

* If the native library can not be loaded from the given path (or via {@link System#loadLibrary(String)}), * then the embedded native library is extracted to the temporary directory and loaded from there. + *

+ * The file names of the native libraries must be either: + *

+ *

+ * Note: Since FlatLaf 3.1 it is recommended to download the + * FlatLaf native libraries from Maven central and distribute them with your + * application in the same directory as flatlaf.jar. + * Then it is not necessary to set this system property. + * See https://www.formdev.com/flatlaf/native-libraries/ + * for details. * * @since 2 */ diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java index 0fb7c3c2..2ca2de5c 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java @@ -117,13 +117,32 @@ class FlatNativeLibrary if( library.isLoaded() ) return library; - LoggingFacade.INSTANCE.logSevere( "Did not find library " + libraryName + " in java.library.path, using extracted library instead", null ); + LoggingFacade.INSTANCE.logSevere( "Did not find library '" + System.mapLibraryName( libraryName ) + + "' in java.library.path '" + System.getProperty( "java.library.path" ) + + "', using extracted library instead", null ); } else { + // try standard library naming scheme + // (same as in flatlaf.jar in package 'com/formdev/flatlaf/natives') File libraryFile = new File( libraryPath, System.mapLibraryName( libraryName ) ); if( libraryFile.exists() ) return new NativeLibrary( libraryFile, true ); - LoggingFacade.INSTANCE.logSevere( "Did not find external library " + libraryFile + ", using extracted library instead", null ); + // try Maven naming scheme + // (see https://www.formdev.com/flatlaf/native-libraries/) + String libraryName2 = null; + File jarFile = getJarFile(); + if( jarFile != null ) { + libraryName2 = buildLibraryName( jarFile, classifier, ext ); + File libraryFile2 = new File( libraryPath, libraryName2 ); + if( libraryFile2.exists() ) + return new NativeLibrary( libraryFile2, true ); + } + + LoggingFacade.INSTANCE.logSevere( "Did not find library '" + + libraryFile.getName() + + (libraryName2 != null ? ("' or '" + libraryName2) : "") + + "' in '" + libraryFile.getParentFile().getAbsolutePath() + + "', using extracted library instead", null ); } } @@ -151,6 +170,33 @@ class FlatNativeLibrary * flatlaf-3.1-linux-x86_64.so */ private static File findLibraryBesideJar( String classifier, String ext ) { + // get location of FlatLaf jar (or fat/uber application jar) + File jarFile = getJarFile(); + if( jarFile == null ) + return null; + + // build library file + String libraryName = buildLibraryName( jarFile, classifier, ext ); + File parent = jarFile.getParentFile(); + + // check whether native library exists in same directory as jar + File libraryFile = new File( parent, libraryName ); + if( libraryFile.isFile() ) + return libraryFile; + + // if jar is in "lib" directory, then also check whether native library exists + // in "../bin" directory + if( parent.getName().equalsIgnoreCase( "lib" ) ) { + libraryFile = new File( parent.getParentFile(), "bin/" + libraryName ); + if( libraryFile.isFile() ) + return libraryFile; + } + + // native library not found + return null; + } + + private static File getJarFile() { try { // get location of FlatLaf jar CodeSource codeSource = FlatNativeLibrary.class.getProtectionDomain().getCodeSource(); @@ -168,31 +214,19 @@ class FlatNativeLibrary if( !jarFile.isFile() ) return null; - // build library file - String jarName = jarFile.getName(); - String jarBasename = jarName.substring( 0, jarName.lastIndexOf( '.' ) ); - File parent = jarFile.getParentFile(); - String libraryName = jarBasename - + (jarBasename.contains( "flatlaf" ) ? "" : "-flatlaf") - + '-' + classifier + '.' + ext; - - // check whether native library exists in same directory as jar - File libraryFile = new File( parent, libraryName ); - if( libraryFile.isFile() ) - return libraryFile; - - // if jar is in "lib" directory, then also check whether library exists - // in "../bin" directory - if( parent.getName().equalsIgnoreCase( "lib" ) ) { - libraryFile = new File( parent.getParentFile(), "bin/" + libraryName ); - if( libraryFile.isFile() ) - return libraryFile; - } + return jarFile; } catch( Exception ex ) { LoggingFacade.INSTANCE.logSevere( ex.getMessage(), ex ); + return null; } + } - return null; + private static String buildLibraryName( File jarFile, String classifier, String ext ) { + String jarName = jarFile.getName(); + String jarBasename = jarName.substring( 0, jarName.lastIndexOf( '.' ) ); + return jarBasename + + (jarBasename.contains( "flatlaf" ) ? "" : "-flatlaf") + + '-' + classifier + '.' + ext; } private static void loadJAWT() {