From 64c272f0af59dba8f19f092c5134cdbe9eb9fac3 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Wed, 18 Sep 2024 14:54:54 +0200 Subject: [PATCH] chore(java): dropped shadow, NativeUtils as class file --- dist/java/build.gradle | 25 +-- dist/java/src/mp/code/BufferController.java | 2 +- dist/java/src/mp/code/Client.java | 2 +- dist/java/src/mp/code/CursorController.java | 2 +- dist/java/src/mp/code/Extensions.java | 22 +-- dist/java/src/mp/code/NativeUtils.java | 160 ++++++++++++++++++++ dist/java/src/mp/code/Workspace.java | 2 +- 7 files changed, 171 insertions(+), 44 deletions(-) create mode 100644 dist/java/src/mp/code/NativeUtils.java diff --git a/dist/java/build.gradle b/dist/java/build.gradle index 12abedf..1cdc1d2 100644 --- a/dist/java/build.gradle +++ b/dist/java/build.gradle @@ -1,14 +1,11 @@ -import com.vanniktech.maven.publish.SonatypeHost - plugins { id 'java-library' id "com.vanniktech.maven.publish" version "0.29.0" - id 'com.github.johnrengelman.shadow' version '8.1.1' id 'com.google.osdetector' version '1.7.3' } group = 'mp.code' -version = '0.0.1' +version = '0.0.2' java { sourceCompatibility = targetCompatibility = JavaVersion.VERSION_11 @@ -16,7 +13,6 @@ java { repositories { mavenCentral() - maven { url 'https://jitpack.io' } } sourceSets { @@ -24,7 +20,6 @@ sourceSets { } dependencies { - implementation 'com.github.adamheinrich:native-utils:master-SNAPSHOT' compileOnly 'org.projectlombok:lombok:1.18.34' annotationProcessor 'org.projectlombok:lombok:1.18.34' } @@ -34,13 +29,15 @@ tasks.register('cargoBuild', Exec) { commandLine 'cargo', 'build', '--release', '--features=java' } +jar.archiveClassifier = osdetector.classifier + def rustDir = projectDir.toPath() .parent .parent .resolve('target') .resolve('release') .toFile() -shadowJar { +processResources { dependsOn cargoBuild outputs.upToDateWhen { false } // no caching from(rustDir) { @@ -49,22 +46,12 @@ shadowJar { include('*dylib') into('natives/') } - - archiveClassifier = osdetector.classifier - dependencies { - include(dependency('com.github.adamheinrich:native-utils:master-SNAPSHOT')) - } } -build.finalizedBy shadowJar - +import com.vanniktech.maven.publish.SonatypeHost mavenPublishing { - //publishToMavenCentral(SonatypeHost.S01) // for snapshots - publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) // central repository - // publishToMavenCentral(SonatypeHost.DEFAULT) // default - + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL, true) signAllPublications() - coordinates(project.group, rootProject.name, project.version) pom { diff --git a/dist/java/src/mp/code/BufferController.java b/dist/java/src/mp/code/BufferController.java index df08a8b..220a339 100644 --- a/dist/java/src/mp/code/BufferController.java +++ b/dist/java/src/mp/code/BufferController.java @@ -122,6 +122,6 @@ protected void finalize() { } static { - Extensions.loadLibraryIfNotPresent(); + NativeUtils.loadLibraryIfNeeded(); } } diff --git a/dist/java/src/mp/code/Client.java b/dist/java/src/mp/code/Client.java index e9b715e..1d20a92 100644 --- a/dist/java/src/mp/code/Client.java +++ b/dist/java/src/mp/code/Client.java @@ -152,6 +152,6 @@ protected void finalize() { } static { - Extensions.loadLibraryIfNotPresent(); + NativeUtils.loadLibraryIfNeeded(); } } diff --git a/dist/java/src/mp/code/CursorController.java b/dist/java/src/mp/code/CursorController.java index 2b1f36d..7d2ce6a 100644 --- a/dist/java/src/mp/code/CursorController.java +++ b/dist/java/src/mp/code/CursorController.java @@ -99,6 +99,6 @@ protected void finalize() { } static { - Extensions.loadLibraryIfNotPresent(); + NativeUtils.loadLibraryIfNeeded(); } } diff --git a/dist/java/src/mp/code/Extensions.java b/dist/java/src/mp/code/Extensions.java index 34c2984..6bd12a3 100644 --- a/dist/java/src/mp/code/Extensions.java +++ b/dist/java/src/mp/code/Extensions.java @@ -37,27 +37,7 @@ public final class Extensions { */ public static native void setupTracing(String path, boolean debug); - private static boolean loaded = false; - static synchronized void loadLibraryIfNotPresent() { - if(loaded) return; - try { - String os = System.getProperty("os.name").toLowerCase(); - - String filename; - if(os.startsWith("windows")) { - filename = "/natives/codemp.dll"; - } else if(os.startsWith("mac")) { - filename = "/natives/libcodemp.dylib";; - } else filename = "/natives/libcodemp.so"; - cz.adamh.utils.NativeUtils.loadLibraryFromJar(filename); - - loaded = true; - } catch(IOException e) { - throw new RuntimeException(e); - } - } - static { - Extensions.loadLibraryIfNotPresent(); + NativeUtils.loadLibraryIfNeeded(); } } diff --git a/dist/java/src/mp/code/NativeUtils.java b/dist/java/src/mp/code/NativeUtils.java new file mode 100644 index 0000000..9253d7d --- /dev/null +++ b/dist/java/src/mp/code/NativeUtils.java @@ -0,0 +1,160 @@ +/* + * Class NativeUtils is published under the The MIT License: + * + * Copyright (c) 2012 Adam Heinrich + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package mp.code; + +import java.io.*; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.ProviderNotFoundException; +import java.nio.file.StandardCopyOption; +import java.util.Objects; + +/** + * A simple library class which helps with loading dynamic libraries stored in the + * JAR archive. These libraries usually contain implementation of some methods in + * native code (using JNI - Java Native Interface). + * @see http://adamheinrich.com/blog/2012/how-to-load-native-jni-library-from-jar + * @see https://github.com/adamheinrich/native-utils + */ +class NativeUtils { + + /** + * The minimum length a prefix for a file has to have according to {@link File#createTempFile(String, String)}}. + */ + private static final int MIN_PREFIX_LENGTH = 3; + + /** + * Prefix of the temporary folder where the native is stored. + */ + public static final String NATIVE_FOLDER_PATH_PREFIX = "nativeutils"; + + /** + * Temporary directory which will contain the DLLs. + */ + private static File temporaryDir; + + /** + * Private constructor - this class will never be instanced + */ + private NativeUtils() {} + + /** + * Loads library from current JAR archive. + * The file from JAR is copied into system temporary directory and then loaded. The temporary file is deleted after + * exiting. + * Method uses String as filename because the pathname is "abstract", not system-dependent. + * @param path The path of file inside JAR as absolute path (beginning with '/'), e.g. /package/File.ext + * @throws IOException If temporary file creation or read/write operation fails + * @throws IllegalArgumentException If source file (param path) does not exist + * @throws IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters + * (restriction of {@link File#createTempFile(java.lang.String, java.lang.String)}). + * @throws FileNotFoundException If the file could not be found inside the JAR. + */ + @SuppressWarnings("ResultOfMethodCallIgnored") + private static void loadLibraryFromJar(String path) throws IOException { + if(null == path || !path.startsWith("/")) { + throw new IllegalArgumentException("The path has to be absolute (start with '/')."); + } + + // Obtain filename from path + String[] parts = path.split("/"); + String filename = (parts.length > 1) ? parts[parts.length - 1] : null; + + // Check if the filename is okay + if(filename == null || filename.length() < MIN_PREFIX_LENGTH) { + throw new IllegalArgumentException("The filename has to be at least 3 characters long."); + } + + // Prepare temporary file + if(temporaryDir == null) { + temporaryDir = createTempDirectory(); + temporaryDir.deleteOnExit(); + } + + File temp = new File(temporaryDir, filename); + + try(InputStream is = NativeUtils.class.getResourceAsStream(path)) { + Files.copy(Objects.requireNonNull(is), temp.toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + temp.delete(); + throw e; + } catch (NullPointerException e) { + temp.delete(); + throw new FileNotFoundException("File " + path + " was not found inside JAR."); + } + + try { + System.load(temp.getAbsolutePath()); + } finally { + if(isPosixCompliant()) { + // Assume POSIX compliant file system, can be deleted after loading + temp.delete(); + } else { + // Assume non-POSIX, and don't delete until last file descriptor closed + temp.deleteOnExit(); + } + } + } + + private static boolean isPosixCompliant() { + try { + return FileSystems.getDefault() + .supportedFileAttributeViews() + .contains("posix"); + } catch (FileSystemNotFoundException | ProviderNotFoundException | SecurityException e) { + return false; + } + } + + private static File createTempDirectory() throws IOException { + String tempDir = System.getProperty("java.io.tmpdir"); + File generatedDir = new File(tempDir, NativeUtils.NATIVE_FOLDER_PATH_PREFIX + System.nanoTime()); + + if(!generatedDir.mkdir()) + throw new IOException("Failed to create temp directory " + generatedDir.getName()); + + return generatedDir; + } + + private static boolean loaded = false; + static synchronized void loadLibraryIfNeeded() { + if(loaded) return; + try { + String os = System.getProperty("os.name").toLowerCase(); + + String filename; + if(os.startsWith("windows")) { + filename = "/natives/codemp.dll"; + } else if(os.startsWith("mac")) { + filename = "/natives/libcodemp.dylib";; + } else filename = "/natives/libcodemp.so"; + loadLibraryFromJar(filename); + + loaded = true; + } catch(IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/dist/java/src/mp/code/Workspace.java b/dist/java/src/mp/code/Workspace.java index 419a193..c833030 100644 --- a/dist/java/src/mp/code/Workspace.java +++ b/dist/java/src/mp/code/Workspace.java @@ -177,7 +177,7 @@ protected void finalize() { } static { - Extensions.loadLibraryIfNotPresent(); + NativeUtils.loadLibraryIfNeeded(); } /**