diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f398c33..c30b486 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/snaploader-examples/build.gradle b/snaploader-examples/build.gradle index 057c1b7..989f057 100644 --- a/snaploader-examples/build.gradle +++ b/snaploader-examples/build.gradle @@ -52,6 +52,10 @@ tasks.register("TestMultiThreading") { application.mainClass = 'electrostatic4j.snaploader.examples.TestMultiThreading' } +tasks.register("TestRetryExhaustionException") { + application.mainClass = 'electrostatic4j.snaploader.examples.TestRetryExhaustionException' +} + task copyLibs(type: Copy) { from (libsDir) { include '**/*.jar' diff --git a/snaploader-examples/libs/corrupted-lib.jar b/snaploader-examples/libs/corrupted-lib.jar new file mode 100644 index 0000000..7a02ff8 Binary files /dev/null and b/snaploader-examples/libs/corrupted-lib.jar differ diff --git a/snaploader-examples/src/main/java/electrostatic4j/snaploader/examples/TestRetryExhaustionException.java b/snaploader-examples/src/main/java/electrostatic4j/snaploader/examples/TestRetryExhaustionException.java new file mode 100644 index 0000000..70de1ee --- /dev/null +++ b/snaploader-examples/src/main/java/electrostatic4j/snaploader/examples/TestRetryExhaustionException.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2023-2025, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Electrostatic-Sandbox' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package electrostatic4j.snaploader.examples; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import electrostatic4j.snaploader.LibraryInfo; +import electrostatic4j.snaploader.LoadingCriterion; +import electrostatic4j.snaploader.NativeBinaryLoader; +import electrostatic4j.snaploader.filesystem.DirectoryPath; +import electrostatic4j.snaploader.platform.NativeDynamicLibrary; +import electrostatic4j.snaploader.platform.util.DefaultDynamicLibraries; +import electrostatic4j.snaploader.platform.util.NativeVariant; +import electrostatic4j.snaploader.platform.util.PlatformPredicate; +import electrostatic4j.snaploader.platform.util.PropertiesProvider; + +/** + * Tests retry exhaustion on a broken library. + * + * @author pavl_g. + */ +public class TestRetryExhaustionException { + public static void main(String[] args) throws Exception { + + final Path compressionPath = Paths.get(PropertiesProvider.USER_DIR.getSystemProperty(), "libs", "corrupted-lib.jar"); + final Path extractionPath = Files.createDirectories(Paths.get(PropertiesProvider.USER_DIR.getSystemProperty(), "libs", + NativeVariant.OS_NAME.getProperty(), NativeVariant.OS_ARCH.getProperty())); + + final LibraryInfo libraryInfo = new LibraryInfo(new DirectoryPath(compressionPath.toString()), new DirectoryPath("lib/placeholder"), + "jmealloc", new DirectoryPath(extractionPath.toString())); + + final NativeDynamicLibrary[] libraries = new NativeDynamicLibrary[] { + DefaultDynamicLibraries.LINUX_X86_64, + DefaultDynamicLibraries.LINUX_X86, + new NativeDynamicLibrary("lib/windows/x86", "libjmealloc.dll", PlatformPredicate.WIN_X86), + new NativeDynamicLibrary("lib/windows/x86-64", "libjmealloc.dll", PlatformPredicate.WIN_X86_64), + DefaultDynamicLibraries.MAC_X86, + DefaultDynamicLibraries.MAC_X86_64, + }; + + final NativeBinaryLoader loader = new NativeBinaryLoader(libraryInfo); + + loader.registerNativeLibraries(libraries).initPlatformLibrary(); + loader.setLoggingEnabled(true); + loader.setRetryWithCleanExtraction(true); + /* Native dynamic library properties */ + printDetails(loader); + loader.loadLibrary(LoadingCriterion.INCREMENTAL_LOADING); + } + + public static void printDetails(NativeBinaryLoader loader) { + System.out.println("--------------------------------------------------------------"); + System.out.println("OS: " + NativeVariant.OS_NAME.getProperty()); + System.out.println("ARCH: " + NativeVariant.OS_ARCH.getProperty()); + System.out.println("VM: " + NativeVariant.JVM.getProperty()); + System.out.println("--------------------------------------------------------------"); + System.out.println("Jar Path: " + loader.getNativeDynamicLibrary().getJarPath()); + System.out.println("Library Directory: " + loader.getNativeDynamicLibrary().getPlatformDirectory()); + System.out.println("Compressed library path: " + loader.getNativeDynamicLibrary().getCompressedLibrary()); + System.out.println("Extracted library absolute path: " + loader.getNativeDynamicLibrary().getExtractedLibrary()); + System.out.println("Is Extracted: " + loader.getNativeDynamicLibrary().isExtracted()); + System.out.println("--------------------------------------------------------------"); + } +} diff --git a/snaploader/build.gradle b/snaploader/build.gradle index c5e1323..5aaaa3f 100644 --- a/snaploader/build.gradle +++ b/snaploader/build.gradle @@ -4,12 +4,12 @@ plugins { } tasks.register("generateJavadocJar", Jar) { - classifier = 'javadoc' + archiveClassifier.set("javadoc") from javadoc } tasks.register("generateSourcesJar", Jar) { - classifier = 'sources' + archiveClassifier.set("sources") from sourceSets.main.allSource } diff --git a/snaploader/src/main/java/electrostatic4j/snaploader/NativeBinaryLoader.java b/snaploader/src/main/java/electrostatic4j/snaploader/NativeBinaryLoader.java index 6bdf0d0..d6e2894 100644 --- a/snaploader/src/main/java/electrostatic4j/snaploader/NativeBinaryLoader.java +++ b/snaploader/src/main/java/electrostatic4j/snaploader/NativeBinaryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader + * Copyright (c) 2023-2025, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,6 +46,7 @@ import electrostatic4j.snaploader.library.LibraryLocator; import electrostatic4j.snaploader.platform.NativeDynamicLibrary; import electrostatic4j.snaploader.platform.util.NativeVariant; +import electrostatic4j.snaploader.throwable.LoadingRetryExhaustionException; import electrostatic4j.snaploader.throwable.UnSupportedSystemError; import electrostatic4j.snaploader.util.SnapLoaderLogger; @@ -84,6 +85,10 @@ public class NativeBinaryLoader { */ protected boolean retryWithCleanExtraction; + protected int maxNumberOfLoadingFailure = 2; + + protected int numberOfLoadingFailure = 0; + /** * Instantiates a native dynamic library loader to extract and load a system-specific native dynamic library. */ @@ -234,12 +239,18 @@ public FileLocalizingListener getLibraryLocalizingListener() { return libraryLocalizingListener; } + public void setMaxNumberOfLoadingFailure(int maxNumberOfLoadingFailure) { + this.maxNumberOfLoadingFailure = Math.abs(maxNumberOfLoadingFailure); + } + /** * Loads a native binary using the platform-dependent object, for Android; * the library is loaded by its basename (variant is managed internally by the android sdk). * * @param library the platform-specific library to load * @throws IOException in case the binary to be extracted is not found on the specified jar + * @throws LoadingRetryExhaustionException if the number of loading failure exceeds the specified + * number. */ protected void loadBinary(NativeDynamicLibrary library) throws Exception { try { @@ -264,10 +275,17 @@ protected void loadBinary(NativeDynamicLibrary library) throws Exception { } /* Retry with clean extract */ if (isRetryWithCleanExtraction()) { - cleanExtractBinary(library); if (nativeBinaryLoadingListener != null) { nativeBinaryLoadingListener.onRetryCriterionExecution(this); } + // limit the number of retries to maxNumberOfLoadingFailure + if (numberOfLoadingFailure >= maxNumberOfLoadingFailure) { + numberOfLoadingFailure = 0; /* reset the number to zero trials */ + throw new LoadingRetryExhaustionException("Library loading retries exceeded the maximum!"); + } + ++numberOfLoadingFailure; + // Jump call -> Possible Recursive Call + cleanExtractBinary(library); } } } @@ -281,7 +299,7 @@ protected void loadBinary(NativeDynamicLibrary library) throws Exception { */ protected void cleanExtractBinary(NativeDynamicLibrary library) throws Exception { libraryExtractor = initializeLibraryExtractor(library); - SnapLoaderLogger.log(Level.INFO, getClass().getName(), "cleanExtractBinary", + SnapLoaderLogger.log(Level.INFO, getClass().getName(), "cleanExtractBinary", "File extractor handler initialized!"); /* CLEAR RESOURCES AND RESET OBJECTS ON-EXTRACTION */ libraryExtractor.setExtractionListener(new FileExtractionListener() { diff --git a/snaploader/src/main/java/electrostatic4j/snaploader/throwable/LoadingRetryExhaustionException.java b/snaploader/src/main/java/electrostatic4j/snaploader/throwable/LoadingRetryExhaustionException.java new file mode 100644 index 0000000..fa594fd --- /dev/null +++ b/snaploader/src/main/java/electrostatic4j/snaploader/throwable/LoadingRetryExhaustionException.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023-2025, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Electrostatic-Sandbox' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package electrostatic4j.snaploader.throwable; + +/** + * Thrown to indicate that loading retries have reached their maximum. + * + * @author pavl_g. + */ +public class LoadingRetryExhaustionException extends RuntimeException { + public LoadingRetryExhaustionException() { + } + + public LoadingRetryExhaustionException(String message) { + super(message); + } + + public LoadingRetryExhaustionException(String message, Throwable cause) { + super(message, cause); + } + + public LoadingRetryExhaustionException(Throwable cause) { + super(cause); + } + + public LoadingRetryExhaustionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +}