From 34e1b5251e97de2add6cf241775cf8e9db2dfeea Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 05:36:33 -0400 Subject: [PATCH 01/55] Added the ability to use PlatformPredicates to build new platform libraries --- .../examples/TestBasicFeatures.java | 25 ++- .../examples/TestMultiThreading.java | 15 +- .../examples/TestMultipleLoads.java | 0 .../snaploader/examples/TestZipExtractor.java | 36 +++- .../ConcurrentNativeBinaryLoader.java | 5 +- .../snaploader/LibraryInfo.java | 12 +- .../snaploader/LoadingCriterion.java | 0 .../snaploader/NativeBinaryLoader.java | 193 +++++++++++------- .../snaploader/UnSupportedSystemError.java | 2 +- .../filesystem}/ConcurrentFileExtractor.java | 14 +- .../filesystem}/ExtractionListener.java | 13 +- .../snaploader/filesystem}/FileExtractor.java | 34 +-- .../snaploader/filesystem}/FileLocator.java | 22 +- .../filesystem}/InputStreamProvider.java | 8 +- .../filesystem}/OutputStreamProvider.java | 12 +- .../filesystem}/ZipCompressionType.java | 6 +- .../snaploader/filesystem}/package-info.java | 2 +- .../snaploader/library/LibraryExtractor.java | 24 +-- .../snaploader/library/LibraryLocator.java | 14 +- .../snaploader/library/package-info.java | 2 +- .../snaploader/package-info.java | 0 .../platform/NativeDynamicLibrary.java | 130 ++++++------ .../snaploader/platform/package-info.java | 0 .../platform/util}/NativeVariant.java | 57 ++++-- .../platform/util/PlatformPredicate.java | 78 +++++++ .../platform/util}/PropertiesProvider.java | 6 +- 26 files changed, 456 insertions(+), 254 deletions(-) rename snaploader-examples/src/main/java/{com/avrsandbox => electrostatic}/snaploader/examples/TestBasicFeatures.java (81%) rename snaploader-examples/src/main/java/{com/avrsandbox => electrostatic}/snaploader/examples/TestMultiThreading.java (85%) rename snaploader-examples/src/main/java/{com/avrsandbox => electrostatic}/snaploader/examples/TestMultipleLoads.java (100%) rename snaploader-examples/src/main/java/{com/avrsandbox => electrostatic}/snaploader/examples/TestZipExtractor.java (72%) rename snaploader/src/main/java/{com/avrsandbox => electrostatic}/snaploader/ConcurrentNativeBinaryLoader.java (92%) rename snaploader/src/main/java/{com/avrsandbox => electrostatic}/snaploader/LibraryInfo.java (90%) rename snaploader/src/main/java/{com/avrsandbox => electrostatic}/snaploader/LoadingCriterion.java (100%) rename snaploader/src/main/java/{com/avrsandbox => electrostatic}/snaploader/NativeBinaryLoader.java (61%) rename snaploader/src/main/java/{com/avrsandbox => electrostatic}/snaploader/UnSupportedSystemError.java (96%) rename snaploader/src/main/java/{com/avrsandbox/snaploader/file => electrostatic/snaploader/filesystem}/ConcurrentFileExtractor.java (83%) rename snaploader/src/main/java/{com/avrsandbox/snaploader/file => electrostatic/snaploader/filesystem}/ExtractionListener.java (80%) rename snaploader/src/main/java/{com/avrsandbox/snaploader/file => electrostatic/snaploader/filesystem}/FileExtractor.java (75%) rename snaploader/src/main/java/{com/avrsandbox/snaploader/file => electrostatic/snaploader/filesystem}/FileLocator.java (80%) rename snaploader/src/main/java/{com/avrsandbox/snaploader/file => electrostatic/snaploader/filesystem}/InputStreamProvider.java (92%) rename snaploader/src/main/java/{com/avrsandbox/snaploader/file => electrostatic/snaploader/filesystem}/OutputStreamProvider.java (86%) rename snaploader/src/main/java/{com/avrsandbox/snaploader/file => electrostatic/snaploader/filesystem}/ZipCompressionType.java (94%) rename snaploader/src/main/java/{com/avrsandbox/snaploader/file => electrostatic/snaploader/filesystem}/package-info.java (97%) rename snaploader/src/main/java/{com/avrsandbox => electrostatic}/snaploader/library/LibraryExtractor.java (74%) rename snaploader/src/main/java/{com/avrsandbox => electrostatic}/snaploader/library/LibraryLocator.java (88%) rename snaploader/src/main/java/{com/avrsandbox => electrostatic}/snaploader/library/package-info.java (94%) rename snaploader/src/main/java/{com/avrsandbox => electrostatic}/snaploader/package-info.java (100%) rename snaploader/src/main/java/{com/avrsandbox => electrostatic}/snaploader/platform/NativeDynamicLibrary.java (50%) rename snaploader/src/main/java/{com/avrsandbox => electrostatic}/snaploader/platform/package-info.java (100%) rename snaploader/src/main/java/{com/avrsandbox/snaploader/platform => electrostatic/snaploader/platform/util}/NativeVariant.java (66%) create mode 100644 snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java rename snaploader/src/main/java/{com/avrsandbox/snaploader/platform => electrostatic/snaploader/platform/util}/PropertiesProvider.java (94%) diff --git a/snaploader-examples/src/main/java/com/avrsandbox/snaploader/examples/TestBasicFeatures.java b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java similarity index 81% rename from snaploader-examples/src/main/java/com/avrsandbox/snaploader/examples/TestBasicFeatures.java rename to snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java index cb46b9d..cb983ce 100644 --- a/snaploader-examples/src/main/java/com/avrsandbox/snaploader/examples/TestBasicFeatures.java +++ b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java @@ -32,10 +32,13 @@ package com.avrsandbox.snaploader.examples; import java.io.IOException; + import com.avrsandbox.snaploader.LibraryInfo; import com.avrsandbox.snaploader.NativeBinaryLoader; -import com.avrsandbox.snaploader.platform.NativeVariant; -import com.avrsandbox.snaploader.platform.PropertiesProvider; +import com.avrsandbox.snaploader.platform.util.DefaultDynamicLibraries; +import com.avrsandbox.snaploader.platform.NativeDynamicLibrary; +import com.avrsandbox.snaploader.platform.util.NativeVariant; +import com.avrsandbox.snaploader.platform.util.PropertiesProvider; import com.avrsandbox.snaploader.LoadingCriterion; /** @@ -52,10 +55,20 @@ public final class TestBasicFeatures { protected static NativeBinaryLoader loader; + public static final NativeDynamicLibrary[] libraries = new NativeDynamicLibrary[] { + DefaultDynamicLibraries.LINUX_X86, + DefaultDynamicLibraries.LINUX_X86_64, + DefaultDynamicLibraries.WIN_X86, + DefaultDynamicLibraries.WIN_X86_64, + DefaultDynamicLibraries.MAC_X86, + DefaultDynamicLibraries.MAC_X86_64, + }; + public static void main(String[] args) throws IOException { if (loader == null) { - loader = new NativeBinaryLoader(libraryInfo).initPlatformLibrary(); + loader = new NativeBinaryLoader(libraryInfo); } + loader.registerNativeLibraries(libraries).initPlatformLibrary(); loader.setLoggingEnabled(true); loader.setRetryWithCleanExtraction(true); /* Native dynamic library properties */ @@ -65,9 +78,9 @@ public static void main(String[] args) throws IOException { protected static void printDetails(NativeBinaryLoader loader) { System.out.println("--------------------------------------------------------------"); - System.out.println("OS: " + NativeVariant.NAME.getProperty()); - System.out.println("ARCH: " + NativeVariant.ARCH.getProperty()); - System.out.println("VM: " + NativeVariant.VM.getProperty()); + 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().getLibraryDirectory()); diff --git a/snaploader-examples/src/main/java/com/avrsandbox/snaploader/examples/TestMultiThreading.java b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultiThreading.java similarity index 85% rename from snaploader-examples/src/main/java/com/avrsandbox/snaploader/examples/TestMultiThreading.java rename to snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultiThreading.java index b35136f..d18322b 100644 --- a/snaploader-examples/src/main/java/com/avrsandbox/snaploader/examples/TestMultiThreading.java +++ b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultiThreading.java @@ -32,9 +32,13 @@ package com.avrsandbox.snaploader.examples; import java.io.IOException; +import java.util.Arrays; + import com.avrsandbox.snaploader.LoadingCriterion; import com.avrsandbox.snaploader.ConcurrentNativeBinaryLoader; import com.avrsandbox.snaploader.UnSupportedSystemError; +import com.avrsandbox.snaploader.platform.util.DefaultDynamicLibraries; +import com.avrsandbox.snaploader.platform.NativeDynamicLibrary; /** * Tests multi-threading and thread locks. @@ -86,7 +90,16 @@ public void run() { }, "Thread-Three"); public static void main(String[] args) throws UnSupportedSystemError, IOException { - TestBasicFeatures.loader = new ConcurrentNativeBinaryLoader(TestBasicFeatures.libraryInfo).initPlatformLibrary(); + final NativeDynamicLibrary[] libraries = new NativeDynamicLibrary[] { + DefaultDynamicLibraries.LINUX_X86, + DefaultDynamicLibraries.LINUX_X86_64, + DefaultDynamicLibraries.WIN_X86, + DefaultDynamicLibraries.WIN_X86_64, + DefaultDynamicLibraries.MAC_X86, + DefaultDynamicLibraries.MAC_X86_64, + }; + TestBasicFeatures.loader = new ConcurrentNativeBinaryLoader(Arrays.asList(libraries), + TestBasicFeatures.libraryInfo).initPlatformLibrary(); TestBasicFeatures.loader.setLoggingEnabled(true); TestBasicFeatures.printDetails(TestBasicFeatures.loader); diff --git a/snaploader-examples/src/main/java/com/avrsandbox/snaploader/examples/TestMultipleLoads.java b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultipleLoads.java similarity index 100% rename from snaploader-examples/src/main/java/com/avrsandbox/snaploader/examples/TestMultipleLoads.java rename to snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultipleLoads.java diff --git a/snaploader-examples/src/main/java/com/avrsandbox/snaploader/examples/TestZipExtractor.java b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestZipExtractor.java similarity index 72% rename from snaploader-examples/src/main/java/com/avrsandbox/snaploader/examples/TestZipExtractor.java rename to snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestZipExtractor.java index 0bc3fb5..50e1082 100644 --- a/snaploader-examples/src/main/java/com/avrsandbox/snaploader/examples/TestZipExtractor.java +++ b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestZipExtractor.java @@ -32,13 +32,15 @@ package com.avrsandbox.snaploader.examples; import java.io.IOException; -import com.avrsandbox.snaploader.file.FileExtractor; -import com.avrsandbox.snaploader.file.FileLocator; -import com.avrsandbox.snaploader.file.ZipCompressionType; -import com.avrsandbox.snaploader.platform.PropertiesProvider; + +import com.avrsandbox.snaploader.filesystem.ExtractionListener; +import com.avrsandbox.snaploader.filesystem.FileExtractor; +import com.avrsandbox.snaploader.filesystem.FileLocator; +import com.avrsandbox.snaploader.filesystem.ZipCompressionType; +import com.avrsandbox.snaploader.platform.util.PropertiesProvider; /** - * Tests extracting an image compression from a Zip compression type file using {@link FileExtractor} API. + * Tests extracting an image compression from a Zip compression type filesystem using {@link FileExtractor} API. * * @author pavl_g */ @@ -47,10 +49,30 @@ public class TestZipExtractor { public static void main(String[] args) throws IOException { /* Locates the image inside the Zip Compression */ final FileLocator fileLocator = new FileLocator(getZipAbsolutePath(), getFilePath(), ZipCompressionType.ZIP); - /* Extracts the image file from the Zip Compression */ + /* Extracts the image filesystem from the Zip Compression */ final FileExtractor fileExtractor = new FileExtractor(fileLocator, getExtractionPath()); /* CLOSE/CLEAR I/O Resources */ - fileExtractor.setExtractionListener(() -> clearResources(fileExtractor)); + fileExtractor.setExtractionListener(new ExtractionListener() { + @Override + public void onExtractionCompleted(FileExtractor fileExtractor) { + + } + + @Override + public void onExtractionFailure(FileExtractor fileExtractor, Throwable throwable) { + + } + + @Override + public void onExtractionFinalization(FileExtractor fileExtractor, FileLocator fileLocator) { + try { + fileExtractor.close(); + fileLocator.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }); fileExtractor.extract(); } diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/ConcurrentNativeBinaryLoader.java b/snaploader/src/main/java/electrostatic/snaploader/ConcurrentNativeBinaryLoader.java similarity index 92% rename from snaploader/src/main/java/com/avrsandbox/snaploader/ConcurrentNativeBinaryLoader.java rename to snaploader/src/main/java/electrostatic/snaploader/ConcurrentNativeBinaryLoader.java index b9c0265..cb92ddb 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/ConcurrentNativeBinaryLoader.java +++ b/snaploader/src/main/java/electrostatic/snaploader/ConcurrentNativeBinaryLoader.java @@ -32,6 +32,7 @@ package com.avrsandbox.snaploader; import java.io.IOException; +import java.util.List; import java.util.concurrent.locks.ReentrantLock; import com.avrsandbox.snaploader.platform.NativeDynamicLibrary; @@ -52,8 +53,8 @@ public class ConcurrentNativeBinaryLoader extends NativeBinaryLoader { * * @param libraryInfo a data structure object holding the platform independent data for the library to load */ - public ConcurrentNativeBinaryLoader(LibraryInfo libraryInfo) { - super(libraryInfo); + public ConcurrentNativeBinaryLoader(final List registeredLibraries, final LibraryInfo libraryInfo) { + super(registeredLibraries, libraryInfo); } @Override diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/LibraryInfo.java b/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java similarity index 90% rename from snaploader/src/main/java/com/avrsandbox/snaploader/LibraryInfo.java rename to snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java index a5893f3..6c9cf98 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/LibraryInfo.java +++ b/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java @@ -72,10 +72,10 @@ public String getBaseName() { } /** - * Retrieves the jar file path, the jar is the compression used to locate the native dynamic library to + * Retrieves the jar filesystem path, the jar is the compression used to locate the native dynamic library to * be extracted and loaded by {@link NativeBinaryLoader}. * - * @return the jar absolute file path in a string format, "null" if the classpath is specified instead of + * @return the jar absolute filesystem path in a string format, "null" if the classpath is specified instead of * an external jar compression */ public String getJarPath() { @@ -85,7 +85,7 @@ public String getJarPath() { /** * Retrieves the directory inside the compression used for locating the native dynamic library. * - * @return the path to the dynamic library file inside the compression, "null" if the + * @return the path to the dynamic library filesystem inside the compression, "null" if the * default variant-based directories are set to be used */ public String getDirectory() { @@ -103,10 +103,10 @@ public String getExtractionDir() { } /** - * Sets the absolute path to the jar file to locate the native dynamic library to be - * extracted and loaded, "null" to use the "classpath (the stock jar)"" to load the library file. + * Sets the absolute path to the jar filesystem to locate the native dynamic library to be + * extracted and loaded, "null" to use the "classpath (the stock jar)"" to load the library filesystem. * - * @param jarPath the absolute path to the jar file to locate the library to be extracted, "null" to + * @param jarPath the absolute path to the jar filesystem to locate the library to be extracted, "null" to * use the "classpath" (aka. the stock jar) */ public void setJarPath(String jarPath) { diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/LoadingCriterion.java b/snaploader/src/main/java/electrostatic/snaploader/LoadingCriterion.java similarity index 100% rename from snaploader/src/main/java/com/avrsandbox/snaploader/LoadingCriterion.java rename to snaploader/src/main/java/electrostatic/snaploader/LoadingCriterion.java diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/NativeBinaryLoader.java b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java similarity index 61% rename from snaploader/src/main/java/com/avrsandbox/snaploader/NativeBinaryLoader.java rename to snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java index acdacec..48ffc85 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/NativeBinaryLoader.java +++ b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java @@ -32,13 +32,17 @@ package com.avrsandbox.snaploader; import java.io.IOException; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import java.lang.UnsatisfiedLinkError; -import com.avrsandbox.snaploader.file.FileExtractor; + +import com.avrsandbox.snaploader.filesystem.ExtractionListener; +import com.avrsandbox.snaploader.filesystem.FileExtractor; +import com.avrsandbox.snaploader.filesystem.FileLocator; import com.avrsandbox.snaploader.library.LibraryExtractor; import com.avrsandbox.snaploader.platform.NativeDynamicLibrary; -import com.avrsandbox.snaploader.platform.NativeVariant; +import com.avrsandbox.snaploader.platform.util.NativeVariant; /** * A cross-platform utility for extracting and loading native binaries based on @@ -52,11 +56,14 @@ public class NativeBinaryLoader { * NativeBinaryLoader logger object. */ protected static final Logger logger = Logger.getLogger(NativeBinaryLoader.class.getName()); - - /** - * A data structure that wraps the general platform independent dynamic library info. - */ - protected LibraryInfo libraryInfo; + + protected final LibraryInfo libraryInfo; + + protected List registeredLibraries; + + protected NativeBinaryLoadingListener nativeBinaryLoadingListener; + + protected SystemFoundListener systemFoundListener; /** * An Output stream concrete provider for library extraction. @@ -79,43 +86,92 @@ public class NativeBinaryLoader { protected boolean retryWithCleanExtraction; /** - * Instantiates a native dynamic library loader to extract and load a system specific native dynamic library. - * - * @param libraryInfo a data structure object representing the basic dynamic library info + * Instantiates a native dynamic library loader to extract and load a system-specific native dynamic library. */ - public NativeBinaryLoader(LibraryInfo libraryInfo) { + public NativeBinaryLoader(final LibraryInfo libraryInfo) { this.libraryInfo = libraryInfo; } /** - * Initializes the platform dependent native dynamic library. + * Instantiates a native dynamic library loader to extract and load a system-specific native dynamic library. + */ + public NativeBinaryLoader(final List registeredLibraries, final LibraryInfo libraryInfo) { + this(libraryInfo); + this.registeredLibraries = registeredLibraries; + } + + public NativeBinaryLoader registerNativeLibraries(NativeDynamicLibrary[] nativeDynamicLibraries) { + this.registeredLibraries = List.of(nativeDynamicLibraries); + return this; + } + + public List getRegisteredLibraries() { + return registeredLibraries; + } + + public void setNativeBinaryLoadingListener(NativeBinaryLoadingListener nativeBinaryLoadingListener) { + this.nativeBinaryLoadingListener = nativeBinaryLoadingListener; + } + + public NativeBinaryLoadingListener getNativeBinaryLoadingListener() { + return nativeBinaryLoadingListener; + } + + public void setSystemFoundListener(SystemFoundListener systemFoundListener) { + this.systemFoundListener = systemFoundListener; + } + + public SystemFoundListener getSystemFoundListener() { + return systemFoundListener; + } + + /** + * Initializes the platform-dependent native dynamic library. * * @return this instance for chained invocations * @throws UnSupportedSystemError if the OS is not supported by jSnapLoader */ public NativeBinaryLoader initPlatformLibrary() throws UnSupportedSystemError { - NativeDynamicLibrary.initWithLibraryInfo(libraryInfo); - if (NativeVariant.isLinux()) { - setupLinuxBinary(); - } else if (NativeVariant.isWindows()) { - setupWindowsBinary(); - } else if (NativeVariant.isMac()) { - setupMacBinary(); - } else { - throw new UnSupportedSystemError(NativeVariant.NAME.getProperty(), NativeVariant.ARCH.getProperty()); + final boolean[] isSystemFound = new boolean[] {false}; + // search for the compatible library using the predefined predicate + // a predicate is a conditional statement composed of multiple propositions + // representing the complete system variant (OS + ARCH + VM). + registeredLibraries.forEach(nativeDynamicLibrary -> { + if (isSystemFound[0]) { + return; + } + // re-evaluate the library info part + if (libraryInfo != null) { + nativeDynamicLibrary.initWithLibraryInfo(libraryInfo); + } + if (nativeDynamicLibrary.getPredicate()) { + this.nativeDynamicLibrary = nativeDynamicLibrary; + isSystemFound[0] = true; + } + }); + + // execute system found listeners + if (systemFoundListener != null) { + if (isSystemFound[0]) { + systemFoundListener.onSystemFound(this, nativeDynamicLibrary); + } else { + systemFoundListener.onSystemNotFound(this); + throw new UnSupportedSystemError(NativeVariant.OS_NAME.getProperty(), + NativeVariant.OS_ARCH.getProperty()); + } } return this; } /** - * Extracts and loads the system and the architecture specific library from the output jar to the [user.dir] + * Extracts and loads the system and the architecture-specific library from the output jar to the [user.dir] * according to a loading criterion (incremental-load or clean-extract). * - * @param criterion the loading criterion, either {@link LoadingCriterion#INCREMENTAL_LOADING} or {@link LoadingCriterion#CLEAN_EXTRACTION} + * @param criterion the initial loading criterion, either {@link LoadingCriterion#INCREMENTAL_LOADING} or {@link LoadingCriterion#CLEAN_EXTRACTION} * @return this instance for chained invocations - * @throws IOException if the library to extract is not present in the jar file + * @throws IOException if the library to extract is not present in the jar filesystem */ - public NativeBinaryLoader loadLibrary(LoadingCriterion criterion) throws IOException { + public NativeBinaryLoader loadLibrary(LoadingCriterion criterion) throws IOException { if (criterion == LoadingCriterion.INCREMENTAL_LOADING && nativeDynamicLibrary.isExtracted()) { loadBinary(nativeDynamicLibrary); return this; @@ -169,48 +225,6 @@ public boolean isRetryWithCleanExtraction() { return retryWithCleanExtraction; } - /** - * Sets-up the architecture specific library {@link NativeBinaryLoader#getNativeDynamicLibrary()} for linux systems. - * - * @see NativeDynamicLibrary#LINUX_x86 - * @see NativeDynamicLibrary#LINUX_x86_64 - */ - protected void setupLinuxBinary() { - if (!NativeVariant.isX86()) { - this.nativeDynamicLibrary = NativeDynamicLibrary.LINUX_x86_64; - } else { - this.nativeDynamicLibrary = NativeDynamicLibrary.LINUX_x86; - } - } - - /** - * Sets-up the architecture specific library {@link NativeBinaryLoader#getNativeDynamicLibrary()} for windows systems. - * - * @see NativeDynamicLibrary#WIN_x86 - * @see NativeDynamicLibrary#WIN_x86_64 - */ - protected void setupWindowsBinary() { - if (!NativeVariant.isX86()) { - this.nativeDynamicLibrary = NativeDynamicLibrary.WIN_x86_64; - } else { - this.nativeDynamicLibrary = NativeDynamicLibrary.WIN_x86; - } - } - - /** - * Sets-up the architecture specific library {@link NativeBinaryLoader#getNativeDynamicLibrary()} for mac systems. - * - * @see NativeDynamicLibrary#MAC_x86 - * @see NativeDynamicLibrary#MAC_x86_64 - */ - protected void setupMacBinary() { - if (!NativeVariant.isX86()) { - this.nativeDynamicLibrary = NativeDynamicLibrary.MAC_x86_64; - } else { - this.nativeDynamicLibrary = NativeDynamicLibrary.MAC_x86; - } - } - /** * 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). @@ -227,11 +241,20 @@ protected void loadBinary(NativeDynamicLibrary library) throws IOException { } System.load(library.getExtractedLibrary()); log(Level.INFO, "loadBinary", "Successfully loaded library: " + library.getExtractedLibrary(), null); + if (nativeBinaryLoadingListener != null) { + nativeBinaryLoadingListener.onLoadingSuccess(this); + } } catch (final UnsatisfiedLinkError error) { log(Level.SEVERE, "loadBinary", "Cannot load the dynamic library: " + library.getExtractedLibrary(), error); + if (nativeBinaryLoadingListener != null) { + nativeBinaryLoadingListener.onLoadingFailure(this); + } /* Retry with clean extract */ if (isRetryWithCleanExtraction()) { cleanExtractBinary(library); + if (nativeBinaryLoadingListener != null) { + nativeBinaryLoadingListener.onRetryCriterionExecution(this); + } } } } @@ -246,26 +269,42 @@ protected void loadBinary(NativeDynamicLibrary library) throws IOException { protected void cleanExtractBinary(NativeDynamicLibrary library) throws IOException { libraryExtractor = initializeLibraryExtractor(library); /* CLEAR RESOURCES AND RESET OBJECTS ON-EXTRACTION */ - libraryExtractor.setExtractionListener(() -> { - try{ - libraryExtractor.getFileLocator().close(); - libraryExtractor.close(); - libraryExtractor = null; + libraryExtractor.setExtractionListener(new ExtractionListener() { + @Override + public void onExtractionCompleted(FileExtractor fileExtractor) { log(Level.INFO, "cleanExtractBinary", "Extracted successfully to " + library.getExtractedLibrary(), null); - loadBinary(library); - } catch (Exception e) { - log(Level.SEVERE, "cleanExtractBinary", "Error while closing the resources!", e); + try { + loadBinary(library); + } catch (IOException e) { + log(Level.SEVERE, "cleanExtractBinary", "Error while loading the binary!", e); + } + } + + @Override + public void onExtractionFailure(FileExtractor fileExtractor, Throwable throwable) { + log(Level.SEVERE, "cleanExtractBinary", "Extraction has failed!", throwable); + } + + @Override + public void onExtractionFinalization(FileExtractor fileExtractor, FileLocator fileLocator) { + try { + fileLocator.close(); + fileExtractor.close(); + } catch (IOException e) { + log(Level.SEVERE, "cleanExtractBinary", "Error while closing the resources!", e); + } } }); libraryExtractor.extract(); + libraryExtractor = null; } /** - * Initializes a file extrator object if the file extractor object associated with this loader isnot defined. + * Initializes a filesystem extrator object if the filesystem extractor object associated with this loader isnot defined. * * @param library the native dynamic library to load * @return a new FileExtractor object that represents an output stream provider - * @throws IOException if the jar file to be located is not found, or if the extraction destination is not found + * @throws IOException if the jar filesystem to be located is not found, or if the extraction destination is not found */ protected FileExtractor initializeLibraryExtractor(NativeDynamicLibrary library) throws IOException { if (library.getJarPath() != null) { diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/UnSupportedSystemError.java b/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java similarity index 96% rename from snaploader/src/main/java/com/avrsandbox/snaploader/UnSupportedSystemError.java rename to snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java index 83e9a60..13d2f39 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/UnSupportedSystemError.java +++ b/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java @@ -48,7 +48,7 @@ public class UnSupportedSystemError extends UnsatisfiedLinkError { /** - * Thrown if the system detects an un-supported system binaries of the current OS. + * Thrown if the system detects an unsupported system binaries of the current OS. * * @param os the current operating system (os) name * @param arch the current operating system (os) processor architecture diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/file/ConcurrentFileExtractor.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ConcurrentFileExtractor.java similarity index 83% rename from snaploader/src/main/java/com/avrsandbox/snaploader/file/ConcurrentFileExtractor.java rename to snaploader/src/main/java/electrostatic/snaploader/filesystem/ConcurrentFileExtractor.java index c84e661..423a7b0 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/file/ConcurrentFileExtractor.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ConcurrentFileExtractor.java @@ -29,14 +29,14 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.file; +package com.avrsandbox.snaploader.filesystem; import java.io.FileNotFoundException; import java.io.IOException; import java.util.concurrent.locks.ReentrantLock; /** - * A thread-safe implementation of the file extractor API. + * A thread-safe implementation of the filesystem extractor API. * * @author pavl_g */ @@ -48,18 +48,18 @@ public class ConcurrentFileExtractor extends FileExtractor { protected final ReentrantLock lock = new ReentrantLock(); /** - * Instantiates a thread-safe file extractor instance. + * Instantiates a thread-safe filesystem extractor instance. * - * @param fileLocator locates a file inside a zip compression - * @param destination an absolute file path representing the extraction destination file - * @throws FileNotFoundException if the destination file path is not found + * @param fileLocator locates a filesystem inside a zip compression + * @param destination an absolute filesystem path representing the extraction destination filesystem + * @throws FileNotFoundException if the destination filesystem path is not found */ public ConcurrentFileExtractor(FileLocator fileLocator, String destination) throws FileNotFoundException { super(fileLocator, destination); } /** - * Instantiates an empty file extractor instance. + * Instantiates an empty filesystem extractor instance. */ protected ConcurrentFileExtractor() { super(); diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/file/ExtractionListener.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ExtractionListener.java similarity index 80% rename from snaploader/src/main/java/com/avrsandbox/snaploader/file/ExtractionListener.java rename to snaploader/src/main/java/electrostatic/snaploader/filesystem/ExtractionListener.java index c2f7256..512040b 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/file/ExtractionListener.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ExtractionListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,10 +29,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.file; + +package electrostatic.snaploader.filesystem; /** - * A thread safe listener for the extraction process. + * A listener for the extraction process. * * @see FileExtractor#extract() * @author pavl_g @@ -42,5 +43,9 @@ public interface ExtractionListener { /** * Dispatched by the {@link FileExtractor#extract()} when the extraction process is completed. */ - void onExtractionCompleted(); + void onExtractionCompleted(FileExtractor fileExtractor); + + void onExtractionFailure(FileExtractor fileExtractor, Throwable throwable); + + void onExtractionFinalization(FileExtractor fileExtractor, FileLocator fileLocator); } diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/file/FileExtractor.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java similarity index 75% rename from snaploader/src/main/java/com/avrsandbox/snaploader/file/FileExtractor.java rename to snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java index f1a07dd..45d2a51 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/file/FileExtractor.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java @@ -29,7 +29,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.file; +package com.avrsandbox.snaploader.filesystem; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -38,14 +38,14 @@ import java.io.OutputStream; /** - * Extracts a file from a zip compression to a destination file. + * Extracts a filesystem from a zip compression to a destination filesystem. * * @author pavl_g */ public class FileExtractor implements OutputStreamProvider { /** - * Locates a file inside a zip compression. + * Locates a filesystem inside a zip compression. */ protected FileLocator fileLocator; @@ -60,17 +60,17 @@ public class FileExtractor implements OutputStreamProvider { protected ExtractionListener extractionListener; /** - * An absolute path for the destination file of the extraction process. + * An absolute path for the destination filesystem of the extraction process. */ protected String destination; - private static final int EOF = -1; /* End-of-file */ + private static final int EOF = -1; /* End-of-filesystem */ /** - * Instantiates a file extractor object with a file locator and a destination file. + * Instantiates a filesystem extractor object with a filesystem locator and a destination filesystem. * - * @param fileLocator locates a file inside a zip compression - * @param destination an absolute file path representing the extraction destination file - * @throws FileNotFoundException if the destination file path is not found + * @param fileLocator locates a filesystem inside a zip compression + * @param destination an absolute filesystem path representing the extraction destination filesystem + * @throws FileNotFoundException if the destination filesystem path is not found */ public FileExtractor(FileLocator fileLocator, String destination) throws FileNotFoundException { this.fileLocator = fileLocator; @@ -78,13 +78,13 @@ public FileExtractor(FileLocator fileLocator, String destination) throws FileNot } /** - * Instantiates an empty file extractor. + * Instantiates an empty filesystem extractor. */ protected FileExtractor() { } /** - * Commands and Extracts the specified file to the specified destination file. + * Commands and Extract the specified filesystem to the specified destination filesystem. * * @throws IOException if the input/output streams has failed or an interrupted I/O operation has occured */ @@ -97,9 +97,17 @@ public void extract() throws IOException { /* use the bytes as the buffer length to write valid data */ fileOutputStream.write(buffer, 0, bytes); } + if (extractionListener != null) { + extractionListener.onExtractionCompleted(this); + } + } catch (Exception e) { + if (extractionListener != null) { + extractionListener.onExtractionFailure(this, e); + } + // release the native resources anyway! } finally { if (extractionListener != null) { - extractionListener.onExtractionCompleted(); + extractionListener.onExtractionFinalization(this, fileLocator); } } } @@ -121,7 +129,7 @@ public InputStreamProvider getFileLocator() { } /** - * Sets the extraction listener action to dispatch the {@link ExtractionListener#onExtractionCompleted()} + * Sets the extraction listener action to dispatch the {@link ExtractionListener#onExtractionCompleted(FileExtractor)} * when the extraction task is completed. * * @param extractionListener an implementation object of the extraction listener dispatched when the diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/file/FileLocator.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java similarity index 80% rename from snaploader/src/main/java/com/avrsandbox/snaploader/file/FileLocator.java rename to snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java index ff30418..e78e4b5 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/file/FileLocator.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java @@ -29,7 +29,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.file; +package com.avrsandbox.snaploader.filesystem; import java.io.IOException; import java.io.InputStream; @@ -37,26 +37,26 @@ import java.util.zip.ZipFile; /** - * An Input Stream Provider that locates a file inside a zip compression and provides an - * input stream object for the located file entry. + * An Input Stream Provider that locates a filesystem inside a zip compression and provides an + * input stream object for the located filesystem entry. * * @author pavl_g */ public class FileLocator implements InputStreamProvider { /** - * The input stream associated with the located file. + * The input stream associated with the located filesystem. */ protected InputStream fileInputStream; /** - * Locates a file inside an external zip compression, the zip file is defined as a {@link ZipFile} object and - * the locatable file is defined as a {@link ZipEntry} object. + * Locates a filesystem inside an external zip compression, the zip filesystem is defined as a {@link ZipFile} object and + * the locatable filesystem is defined as a {@link ZipEntry} object. + *

+ * Warning: This object leaks an input stream. * - * This object leaks an input stream. - * - * @param directory the absolute path for the external jar file - * @param filePath the path to the file to be extracted + * @param directory the absolute path for the external jar filesystem + * @param filePath the path to the filesystem to be extracted * @param compressionType the type of the zip compression, ZIP or JAR * * @throws IOException if the jar to be located is not found or an interrupted I/O exception has occured @@ -68,7 +68,7 @@ public FileLocator(String directory, String filePath, ZipCompressionType compres } /** - * Instantiates an empty file locator object. + * Instantiates an empty filesystem locator object. */ protected FileLocator() { } diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/file/InputStreamProvider.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java similarity index 92% rename from snaploader/src/main/java/com/avrsandbox/snaploader/file/InputStreamProvider.java rename to snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java index 313f192..6e9cd60 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/file/InputStreamProvider.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java @@ -29,12 +29,12 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.file; +package com.avrsandbox.snaploader.filesystem; import java.io.InputStream; /** - * Defines an interface for an input stream provider that locates a file and provides + * Defines an interface for an input stream provider that locates a filesystem and provides * an {@link InputStream} object. * * @author pavl_g @@ -42,9 +42,9 @@ public interface InputStreamProvider extends AutoCloseable { /** - * Retrieves the input stream object associated with this file entry. + * Retrieves the input stream object associated with this filesystem entry. * - * @return an input stream object for this located file + * @return an input stream object for this located filesystem */ InputStream getFileInputStream(); } diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/file/OutputStreamProvider.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/OutputStreamProvider.java similarity index 86% rename from snaploader/src/main/java/com/avrsandbox/snaploader/file/OutputStreamProvider.java rename to snaploader/src/main/java/electrostatic/snaploader/filesystem/OutputStreamProvider.java index b291150..f6277c3 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/file/OutputStreamProvider.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/OutputStreamProvider.java @@ -29,22 +29,22 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.file; +package com.avrsandbox.snaploader.filesystem; import java.io.OutputStream; /** - * Defines an interface for an output stream provider to locate and extract a file from a zip compression, - * the output stream provider object is associated with an input stream provider object that locates this file. + * Defines an interface for an output stream provider to locate and extract a filesystem from a zip compression, + * the output stream provider object is associated with an input stream provider object that locates this filesystem. * * @author pavl_g */ public interface OutputStreamProvider extends AutoCloseable { /** - * Retrieves the input stream provider object (the file locator object). + * Retrieves the input stream provider object (the filesystem locator object). * - * @return an input stream provider object that is the file locator object + * @return an input stream provider object that is the filesystem locator object */ InputStreamProvider getFileLocator(); @@ -52,7 +52,7 @@ public interface OutputStreamProvider extends AutoCloseable { * Retrieves the output stream object associated with this provider, the output stream is * associated with the * - * @return an output stream provider object to extract the file + * @return an output stream provider object to extract the filesystem */ OutputStream getFileOutputStream(); } diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/file/ZipCompressionType.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ZipCompressionType.java similarity index 94% rename from snaploader/src/main/java/com/avrsandbox/snaploader/file/ZipCompressionType.java rename to snaploader/src/main/java/electrostatic/snaploader/filesystem/ZipCompressionType.java index 1162538..61ec520 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/file/ZipCompressionType.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ZipCompressionType.java @@ -29,7 +29,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.file; +package com.avrsandbox.snaploader.filesystem; import java.io.IOException; import java.util.jar.JarFile; @@ -71,9 +71,9 @@ public enum ZipCompressionType { /** * Creates a new zip compression object by its path based on the compression symbol. * - * @param directory the zip-file absolute path + * @param directory the zip-filesystem absolute path * @return a new zip compression object based on the compression type specified by the compression symbol - * @throws IOException if the zip file is not found, or an interrupted I/O operation has occured + * @throws IOException if the zip filesystem is not found, or an interrupted I/O operation has occured */ protected ZipFile createNewCompressionObject(String directory) throws IOException { if (compressionObject == null) { diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/file/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/package-info.java similarity index 97% rename from snaploader/src/main/java/com/avrsandbox/snaploader/file/package-info.java rename to snaploader/src/main/java/electrostatic/snaploader/filesystem/package-info.java index 54da040..b2fadb0 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/file/package-info.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/package-info.java @@ -33,4 +33,4 @@ /** * Provides I/O stream provider interfaces for {@link com.avrsandbox.snaploader.library.LibraryLocator} and {@link com.avrsandbox.snaploader.library.LibraryExtractor}. */ -package com.avrsandbox.snaploader.file; +package com.avrsandbox.snaploader.filesystem; diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/library/LibraryExtractor.java b/snaploader/src/main/java/electrostatic/snaploader/library/LibraryExtractor.java similarity index 74% rename from snaploader/src/main/java/com/avrsandbox/snaploader/library/LibraryExtractor.java rename to snaploader/src/main/java/electrostatic/snaploader/library/LibraryExtractor.java index 0360fcb..886e538 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/library/LibraryExtractor.java +++ b/snaploader/src/main/java/electrostatic/snaploader/library/LibraryExtractor.java @@ -32,8 +32,8 @@ package com.avrsandbox.snaploader.library; import java.io.IOException; -import com.avrsandbox.snaploader.file.ConcurrentFileExtractor; -import com.avrsandbox.snaploader.file.FileExtractor; +import com.avrsandbox.snaploader.filesystem.ConcurrentFileExtractor; +import com.avrsandbox.snaploader.filesystem.FileExtractor; /** * Represents a thread-safe dynamic library (.so, .dll, .dylib) extractor based on the {@link FileExtractor}. @@ -43,24 +43,24 @@ public class LibraryExtractor extends ConcurrentFileExtractor { /** - * Instantiates a native dynamic library extractor with a jar path, library path and extract destination file path. + * Instantiates a native dynamic library extractor with a jar path, library path and extract destination filesystem path. * - * @param jarPath an absolute path to the jar file containing the library - * @param libraryPath the path of the library inside the jar file - * @param destination the extraction destination file path - * @throws IOException if the jar file to be located is not found, or if the extraction destination is not found + * @param jarPath an absolute path to the jar filesystem containing the library + * @param libraryPath the path of the library inside the jar filesystem + * @param destination the extraction destination filesystem path + * @throws IOException if the jar filesystem to be located is not found, or if the extraction destination is not found */ public LibraryExtractor(String jarPath, String libraryPath, String destination) throws IOException { super(new LibraryLocator(jarPath, libraryPath), destination); } /** - * Instantiates a native dynamic library extractor with a library path and an extract destination file path. This - * object locates a dynmaic native library inside the stock jar file based on a classpath input stream. + * Instantiates a native dynamic library extractor with a library path and an extract destination filesystem path. This + * object locates a dynamic native library inside the stock jar filesystem based on a classpath input stream. * - * @param libraryPath the path of the library inside the jar file - * @param destination the extraction destination file path - * @throws IOException if the jar file to be located is not found, or if the extraction destination is not found + * @param libraryPath the path of the library inside the jar filesystem + * @param destination the extraction destination filesystem path + * @throws IOException if the jar filesystem to be located is not found, or if the extraction destination is not found */ public LibraryExtractor(String libraryPath, String destination) throws IOException { super(new LibraryLocator(libraryPath), destination); diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/library/LibraryLocator.java b/snaploader/src/main/java/electrostatic/snaploader/library/LibraryLocator.java similarity index 88% rename from snaploader/src/main/java/com/avrsandbox/snaploader/library/LibraryLocator.java rename to snaploader/src/main/java/electrostatic/snaploader/library/LibraryLocator.java index 0c22fee..b9f2748 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/library/LibraryLocator.java +++ b/snaploader/src/main/java/electrostatic/snaploader/library/LibraryLocator.java @@ -34,21 +34,21 @@ import java.io.IOException; import java.util.jar.JarFile; import java.util.zip.ZipEntry; -import com.avrsandbox.snaploader.file.ZipCompressionType; -import com.avrsandbox.snaploader.file.FileLocator; +import com.avrsandbox.snaploader.filesystem.ZipCompressionType; +import com.avrsandbox.snaploader.filesystem.FileLocator; /** - * Locates a library inside a jar file, the probable source for the native dynamic libraries to extract and load. + * Locates a library inside a jar filesystem, the probable source for the native dynamic libraries to extract and load. * * @author pavl_g */ public class LibraryLocator extends FileLocator { /** - * Locates the library inside the stock jar file. + * Locates the library inside the stock jar filesystem. * This object leaks an input stream. * - * @param libraryPath the path to the dynamic native library inside that jar file + * @param libraryPath the path to the dynamic native library inside that jar filesystem */ public LibraryLocator(String libraryPath) { this.fileInputStream = LibraryLocator.class.getClassLoader().getResourceAsStream(libraryPath); @@ -59,8 +59,8 @@ public LibraryLocator(String libraryPath) { * the native library is defined as a {@link ZipEntry}. * This object leaks an input stream. * - * @param directory the absolute path for the external jar file - * @param libraryPath the path to the dynamic native library inside that jar file + * @param directory the absolute path for the external jar filesystem + * @param libraryPath the path to the dynamic native library inside that jar filesystem * @throws IOException if the jar to be located is not found or an interrupt I/O operation has occured */ public LibraryLocator(String directory, String libraryPath) throws IOException { diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/library/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/library/package-info.java similarity index 94% rename from snaploader/src/main/java/com/avrsandbox/snaploader/library/package-info.java rename to snaploader/src/main/java/electrostatic/snaploader/library/package-info.java index 51c2661..bd6bd7c 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/library/package-info.java +++ b/snaploader/src/main/java/electrostatic/snaploader/library/package-info.java @@ -31,6 +31,6 @@ */ /** - * Provides specialized implementation for {@link com.avrsandbox.snaploader.file.FileLocator} and {@link com.avrsandbox.snaploader.file.FileExtractor}. + * Provides specialized implementation for {@link com.avrsandbox.snaploader.filesystem.FileLocator} and {@link com.avrsandbox.snaploader.filesystem.FileExtractor}. */ package com.avrsandbox.snaploader.library; \ No newline at end of file diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/package-info.java similarity index 100% rename from snaploader/src/main/java/com/avrsandbox/snaploader/package-info.java rename to snaploader/src/main/java/electrostatic/snaploader/package-info.java diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/platform/NativeDynamicLibrary.java b/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java similarity index 50% rename from snaploader/src/main/java/com/avrsandbox/snaploader/platform/NativeDynamicLibrary.java rename to snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java index 560afd8..624b891 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/platform/NativeDynamicLibrary.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,112 +29,99 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.platform; + +package electrostatic.snaploader.platform; import java.io.File; -import com.avrsandbox.snaploader.LibraryInfo; +import electrostatic.snaploader.LibraryInfo; +import electrostatic.snaploader.NativeBinaryLoader; +import electrostatic.snaploader.platform.util.NativeVariant; +import electrostatic.snaploader.platform.util.PlatformPredicate; +import electrostatic.snaploader.platform.util.PropertiesProvider; /** - * Represents a native binary domain with a {@link NativeDynamicLibrary#libraryDirectory} and a {@link NativeDynamicLibrary#library}. - * - * Internal use only. + * Represents a filesystem to a platform-specific binary inside + * a compression with a predicate; if the predicate evaluates, the + * library is loaded by the {@link NativeBinaryLoader}. * * @author pavl_g */ -public enum NativeDynamicLibrary { - - /** - * Represents a linux x86 binary with 64-bit instruction set. - */ - LINUX_x86_64(null, "lib/linux/x86-64", null, null), - +public class NativeDynamicLibrary { + /** - * Represents a linux x86 binary with 32-bit instruction set. + * The absolute path for the Jar file to + * extract and load the library from. */ - LINUX_x86(null, "lib/linux/x86", null, null), + protected String jarPath; /** - * Represents a mac x86 binary with 64-bit instruction set. + * The library path inside the compression (i.e., Jar file). */ - MAC_x86_64(null, "lib/macos/x86-64", null, null), + protected String libraryDirectory; /** - * Represents a mac x86 binary with 32-bit instruction set. + * A designator for the library name with the platform extension + * (basename + extension). */ - MAC_x86(null, "lib/macos/x86", null, null), + protected String library; /** - * Represents a windows x86 binary with 64-bit instruction set. + * A designator for the extraction directory of the + * native library. */ - WIN_x86_64(null, "lib/windows/x86-64", null, null), + protected String extractionDir; /** - * Represents a windows x86 binary with 32-bit instruction set. + * The platform-specific predicate; that if evaluated as + * true, the respective native library object will be + * assigned by the {@link NativeBinaryLoader} to be extracted + * and loaded. */ - WIN_x86(null, "lib/windows/x86", null, null); - - private String jarPath; - private String libraryDirectory; - private String library; - private String extractionDir; + protected PlatformPredicate platformPredicate; /** - * Creates a Native dynamic library from a relative directory and a library file. + * Creates a Native dynamic library from a relative directory and a library filesystem. * - * @param jarPath the absolute path to the jar compression - * @param libraryDirectory the library directory inside the jar compression, "null" for the default library directory. - * @param library the library filename - * @param extractionDir the absolute path to the extraction directory + * @param platformDirectory the library directory inside the jar compression, "null" for the default library directory. + * @param platformPredicate the predicate to test against; that if evaluated as true, the native library will be selected + * to be loaded by the native loader */ - NativeDynamicLibrary(String jarPath, String libraryDirectory, String library, String extractionDir) { - this.jarPath = jarPath; - this.libraryDirectory = libraryDirectory; - this.library = library; - this.extractionDir = extractionDir; + public NativeDynamicLibrary(String platformDirectory, + PlatformPredicate platformPredicate) { + this.libraryDirectory = platformDirectory; + this.platformPredicate = platformPredicate; } /** * Initializes the native dynamic library with the library info. - * + * * @param libraryInfo wraps abstract data representing the native library */ - public static void initWithLibraryInfo(LibraryInfo libraryInfo) { + public void initWithLibraryInfo(LibraryInfo libraryInfo) { + String ext = ".so"; + + if (NativeVariant.isMac()) { + ext = ".dylib"; + } else if (NativeVariant.isWindows()) { + ext = ".dll"; + } + /* Initializes the library basename */ if (libraryInfo.getBaseName() != null) { - NativeDynamicLibrary.LINUX_x86.library = "lib" + libraryInfo.getBaseName() + ".so"; - NativeDynamicLibrary.LINUX_x86_64.library = "lib" + libraryInfo.getBaseName() + ".so"; - NativeDynamicLibrary.MAC_x86.library = "lib" + libraryInfo.getBaseName() + ".dylib"; - NativeDynamicLibrary.MAC_x86_64.library = "lib" + libraryInfo.getBaseName() + ".dylib"; - NativeDynamicLibrary.WIN_x86.library = "lib" + libraryInfo.getBaseName() + ".dll"; - NativeDynamicLibrary.WIN_x86_64.library = "lib" + libraryInfo.getBaseName() + ".dll"; + library = "lib" + libraryInfo.getBaseName() + ext; } - + /* Initializes the library jar path to locate before extracting, "null" to use the classpath */ - NativeDynamicLibrary.LINUX_x86.jarPath = libraryInfo.getJarPath(); - NativeDynamicLibrary.LINUX_x86_64.jarPath = libraryInfo.getJarPath(); - NativeDynamicLibrary.MAC_x86.jarPath = libraryInfo.getJarPath(); - NativeDynamicLibrary.MAC_x86_64.jarPath = libraryInfo.getJarPath(); - NativeDynamicLibrary.WIN_x86.jarPath = libraryInfo.getJarPath(); - NativeDynamicLibrary.WIN_x86_64.jarPath = libraryInfo.getJarPath(); + jarPath = libraryInfo.getJarPath(); /* Initializes the library with an extraction path, "null" to extract to the current user directory */ - NativeDynamicLibrary.LINUX_x86.extractionDir = libraryInfo.getExtractionDir(); - NativeDynamicLibrary.LINUX_x86_64.extractionDir = libraryInfo.getExtractionDir(); - NativeDynamicLibrary.MAC_x86.extractionDir = libraryInfo.getExtractionDir(); - NativeDynamicLibrary.MAC_x86_64.extractionDir = libraryInfo.getExtractionDir(); - NativeDynamicLibrary.WIN_x86.extractionDir = libraryInfo.getExtractionDir(); - NativeDynamicLibrary.WIN_x86_64.extractionDir = libraryInfo.getExtractionDir(); + extractionDir = libraryInfo.getExtractionDir(); /* Initializes the library directory within the jar, "null" for the default library directory */ if (libraryInfo.getDirectory() != null) { - NativeDynamicLibrary.LINUX_x86.libraryDirectory = libraryInfo.getDirectory(); - NativeDynamicLibrary.LINUX_x86_64.libraryDirectory = libraryInfo.getDirectory(); - NativeDynamicLibrary.MAC_x86.libraryDirectory = libraryInfo.getDirectory(); - NativeDynamicLibrary.MAC_x86_64.libraryDirectory = libraryInfo.getDirectory(); - NativeDynamicLibrary.WIN_x86.libraryDirectory = libraryInfo.getDirectory(); - NativeDynamicLibrary.WIN_x86_64.libraryDirectory = libraryInfo.getDirectory(); + libraryDirectory = libraryInfo.getDirectory(); } - } + } /** * Retrieves the absolute path for the jar compression as specified by the {@link LibraryInfo} API. @@ -166,7 +153,7 @@ public String getCompressedLibrary() { /** * Retrieves the absolute path for the native library as supposed to be on the extraction directory. * - * @return the absolute path composed of the extraction directory and the library name and system specific extension + * @return the absolute path composed of the extraction directory and the library name and system-specific extension */ public String getExtractedLibrary() { if (extractionDir != null) { @@ -184,4 +171,13 @@ public String getExtractedLibrary() { public boolean isExtracted() { return new File(getExtractedLibrary()).exists(); } + + /** + * Retrieves the platform-specific predicate to test against. + * + * @return the predefined platform-specific predicate object. + */ + public PlatformPredicate getPlatformPredicate() { + return platformPredicate; + } } diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/platform/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/platform/package-info.java similarity index 100% rename from snaploader/src/main/java/com/avrsandbox/snaploader/platform/package-info.java rename to snaploader/src/main/java/electrostatic/snaploader/platform/package-info.java diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/platform/NativeVariant.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java similarity index 66% rename from snaploader/src/main/java/com/avrsandbox/snaploader/platform/NativeVariant.java rename to snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java index 042b1a4..e207465 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/platform/NativeVariant.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java @@ -29,10 +29,10 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.platform; +package com.avrsandbox.snaploader.platform.util; /** - * Represents a native variant (OS + ARCH + VM), each of which is represented as an object of a property. + * Wraps objects for native variant constituents (OS + ARCH={CPU + INSTRUCT_SET} + VM). * * @author pavl_g */ @@ -41,17 +41,17 @@ public enum NativeVariant { /** * The Operating system name property for this variant. */ - NAME(System.getProperty("os.name")), + OS_NAME(System.getProperty("os.name")), /** * The Operating system architecture. */ - ARCH(System.getProperty("os.arch")), + OS_ARCH(System.getProperty("os.arch")), /** * The current java virtual machine. */ - VM(System.getProperty("java.vm.name")); + JVM(System.getProperty("java.vm.name")); private static final String Linux = "Linux"; private static final String Windows = "Windows"; @@ -70,7 +70,7 @@ public enum NativeVariant { * @return true if the current OS is a Linux, false otherwise. */ public static boolean isLinux() { - return NativeVariant.NAME.getProperty().contains(NativeVariant.Linux); + return NativeVariant.OS_NAME.getProperty().contains(NativeVariant.Linux); } /** @@ -79,7 +79,7 @@ public static boolean isLinux() { * @return true if the current OS is a Windows, false otherwise. */ public static boolean isWindows() { - return NativeVariant.NAME.getProperty().contains(NativeVariant.Windows); + return NativeVariant.OS_NAME.getProperty().contains(NativeVariant.Windows); } /** @@ -88,7 +88,7 @@ public static boolean isWindows() { * @return true if the current OS is a Mac, false otherwise. */ public static boolean isMac() { - return NativeVariant.NAME.getProperty().contains(NativeVariant.Mac); + return NativeVariant.OS_NAME.getProperty().contains(NativeVariant.Mac); } /** @@ -97,25 +97,52 @@ public static boolean isMac() { * @return true if the current OS is an Android, false otherwise. */ public static boolean isAndroid() { - return VM.getProperty().contains(NativeVariant.Dalvik); + return JVM.getProperty().contains(NativeVariant.Dalvik); } /** - * Tests whether the current system architecture is a 64-bit intel chipset. + * Tests whether the current system architecture is a 64-bit chipset. * - * @return true if the current OS architecture is a 64-bit intel chipset, false otherwise. + * @return true if the current OS architecture is a 64-bit chipset, false otherwise. */ public static boolean isX86_64() { - return ARCH.getProperty().contains("64"); + return OS_ARCH.getProperty().contains("64"); } /** - * Tests whether the current system architecture is a 32-bit intel chipset. + * Tests whether the current system architecture is a plain x86 chipset. * - * @return true if the current OS architecture is a 32-bit intel chipset, false otherwise. + * @return true if the current OS architecture is a plain x86 chipset, false otherwise. */ public static boolean isX86() { - return ARCH.getProperty().equals("x86"); + return OS_ARCH.getProperty().contains("x86"); + } + + /** + * Tests whether the current system architecture is a 32-bit chipset. + * + * @return true if the current OS architecture is a 32-bit chipset, false otherwise. + */ + public static boolean is32() { + return OS_ARCH.getProperty().contains("32"); + } + + /** + * Tests whether the current CPU vendor is an AMD vendor (e.g., Intel Chipset). + * + * @return true if the current CPU vendor is an AMD vendor. + */ + public static boolean isAMD() { + return OS_ARCH.getProperty().contains("amd"); + } + + /** + * Tests whether the current CPU vendor is an ARM vendor (e.g., Broadcom Chipset). + * + * @return true if the current CPU vendor is an ARM vendor. + */ + public static boolean isARM() { + return OS_ARCH.getProperty().contains("arm"); } /** diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java new file mode 100644 index 0000000..57eee92 --- /dev/null +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023-2024, 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 'AvrSandbox' 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 electrostatic.snaploader.platform.util; + +/** + * Wraps a platform-specific predicate; that if all of its propositions evaluated + * as true, the respective platform library will be assigned to be extracted + * and loaded by the loader object in-command. + * + * @author pavl_g + */ +public final class PlatformPredicate { + + public static final PlatformPredicate LINUX_X86 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isX86()); + public static final PlatformPredicate LINUX_X86_64 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isAMD() && NativeVariant.is64()); + public static final PlatformPredicate LINUX_ARM_32 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isARM() && NativeVariant.is32()); + public static final PlatformPredicate LINUX_ARM_64 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isARM() && NativeVariant.is64()); + public static final PlatformPredicate MACOS_X86 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isX86()); + public static final PlatformPredicate MACOS_X86_64 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isAMD() && NativeVariant.is64()); + public static final PlatformPredicate MACOS_ARM_32 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isARM() && NativeVariant.is32()); + public static final PlatformPredicate MACOS_ARM_64 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isARM() && NativeVariant.is64()); + public static final PlatformPredicate WIN_X86 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isX86()); + public static final PlatformPredicate WIN_X86_64 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isAMD() && NativeVariant.is64()); + public static final PlatformPredicate WIN_ARM_32 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isARM() && NativeVariant.is32()); + public static final PlatformPredicate WIN_ARM_64 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isARM() && NativeVariant.is64()); + + private final boolean predicate; + + /** + * Instantiates a platform-specific predicate object + * that wraps a predicate composed of multiple + * propositions appended by logical operations. + * + * @param predicate a raw boolean predicate to evaluate against + */ + public PlatformPredicate(boolean predicate) { + this.predicate = predicate; + } + + /** + * Evaluate the propositions of the predefined platform-predicate. + * + * @return true if the + */ + public boolean evaluatePredicate() { + return predicate; + } +} diff --git a/snaploader/src/main/java/com/avrsandbox/snaploader/platform/PropertiesProvider.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PropertiesProvider.java similarity index 94% rename from snaploader/src/main/java/com/avrsandbox/snaploader/platform/PropertiesProvider.java rename to snaploader/src/main/java/electrostatic/snaploader/platform/util/PropertiesProvider.java index cd447d9..84de828 100644 --- a/snaploader/src/main/java/com/avrsandbox/snaploader/platform/PropertiesProvider.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PropertiesProvider.java @@ -29,7 +29,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.platform; +package com.avrsandbox.snaploader.platform.util; /** * Provides platform-dependent system properties for the current running machine. @@ -51,12 +51,12 @@ public enum PropertiesProvider { USER_HOME(System.getProperty("user.home")), /** - * Provides a string representation for the platform-dependent file separator. + * Provides a string representation for the platform-dependent filesystem separator. */ FILE_SEPARATOR(System.getProperty("file.separator")), /** - * Provides a string representation for the file separator of the Zip specification. + * Provides a string representation for the filesystem separator of the Zip specification. */ ZIP_FILE_SEPARATOR("/"), From 51bd83f489f63fce93ad5a4f7365fbcce868b385 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 05:38:58 -0400 Subject: [PATCH 02/55] NativeVariant: added missing propositional statements --- .../snaploader/platform/util/NativeVariant.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java index e207465..fbfb6b7 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.platform.util; + +package electrostatic.snaploader.platform.util; /** * Wraps objects for native variant constituents (OS + ARCH={CPU + INSTRUCT_SET} + VM). @@ -102,17 +103,17 @@ public static boolean isAndroid() { /** * Tests whether the current system architecture is a 64-bit chipset. - * + * * @return true if the current OS architecture is a 64-bit chipset, false otherwise. */ - public static boolean isX86_64() { + public static boolean is64() { return OS_ARCH.getProperty().contains("64"); } /** - * Tests whether the current system architecture is a plain x86 chipset. - * - * @return true if the current OS architecture is a plain x86 chipset, false otherwise. + * Tests whether the current system architecture is of an x86 chipset, typically 32-bit intel chipsets. + * + * @return true if the current OS architecture is of an x86 chipset, false otherwise. */ public static boolean isX86() { return OS_ARCH.getProperty().contains("x86"); From 39a982d65f0bfc67502a9249a33dc5ea84b8467b Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 05:41:21 -0400 Subject: [PATCH 03/55] Added DefaultDynamicLibraries namespace class specifically for Serial4j-like setups --- .../util/DefaultDynamicLibraries.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 snaploader/src/main/java/electrostatic/snaploader/platform/util/DefaultDynamicLibraries.java diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/DefaultDynamicLibraries.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/DefaultDynamicLibraries.java new file mode 100644 index 0000000..684a740 --- /dev/null +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/DefaultDynamicLibraries.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023-2024, 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 'AvrSandbox' 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 electrostatic.snaploader.platform.util; + +import electrostatic.snaploader.platform.NativeDynamicLibrary; + +/** + * Defines default helper objects for plug-and-play usage. + *

+ * In order to add more predicated variants, extend + * this namespace class and add more static objects. + * + * @author pavl_g + */ +public class DefaultDynamicLibraries { + + /** + * Represents a linux x86 binary with 64-bit instruction set. + */ + public static NativeDynamicLibrary LINUX_X86_64 = + new NativeDynamicLibrary("lib/linux/x86-64", PlatformPredicate.LINUX_X86_64); + + /** + * Represents a linux x86 binary with 32-bit instruction set. + */ + public static NativeDynamicLibrary LINUX_X86 = + new NativeDynamicLibrary("lib/linux/x86", PlatformPredicate.LINUX_X86); + + /** + * Represents a mac x86 binary with 64-bit instruction set. + */ + public static NativeDynamicLibrary MAC_X86_64 = + new NativeDynamicLibrary("lib/macos/x86-64", PlatformPredicate.MACOS_X86_64); + + /** + * Represents a mac x86 binary with 32-bit instruction set. + */ + public static NativeDynamicLibrary MAC_X86 = + new NativeDynamicLibrary("lib/macos/x86", PlatformPredicate.MACOS_X86); + + /** + * Represents a windows x86 binary with 64-bit instruction set. + */ + public static NativeDynamicLibrary WIN_X86_64 = + new NativeDynamicLibrary("lib/windows/x86-64", PlatformPredicate.WIN_X86_64); + + /** + * Represents a windows x86 binary with 32-bit instruction set. + */ + public static NativeDynamicLibrary WIN_X86 = + new NativeDynamicLibrary("lib/windows/x86", PlatformPredicate.WIN_X86); + + private DefaultDynamicLibraries() { + } +} From 2009a1a0c6a87f1fadf602054e2a81ef12d177f0 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 05:42:24 -0400 Subject: [PATCH 04/55] platform/util: enhancements to the PropertiesProvider and package-info --- .../platform/util/PropertiesProvider.java | 5 +-- .../platform/util/package-info.java | 36 +++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 snaploader/src/main/java/electrostatic/snaploader/platform/util/package-info.java diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PropertiesProvider.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PropertiesProvider.java index 84de828..a409b52 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PropertiesProvider.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PropertiesProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.platform.util; + +package electrostatic.snaploader.platform.util; /** * Provides platform-dependent system properties for the current running machine. diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/package-info.java new file mode 100644 index 0000000..7c553ea --- /dev/null +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/package-info.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023-2024, 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 'AvrSandbox' 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. + */ + +/** + * Provides utilities to handle platform-specific binaries. + */ +package electrostatic.snaploader.platform.util; \ No newline at end of file From 564a99d443a26ce87b383e9eb2f9fd33146dc3d6 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 05:43:09 -0400 Subject: [PATCH 05/55] platform/package-info: package Javadoc --- .../java/electrostatic/snaploader/platform/package-info.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/platform/package-info.java index 3b0e98b..862fcae 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/package-info.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,4 +33,4 @@ /** * Provides platform-dependent specifications to handle the abstract interface for the jSnapLoader. */ -package com.avrsandbox.snaploader.platform; \ No newline at end of file +package electrostatic.snaploader.platform; \ No newline at end of file From f1853288e2eb87aef0ea98bdc2adcda05be2ba88 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:09:54 -0400 Subject: [PATCH 06/55] Added SystemDetectionListener interface --- .../snaploader/SystemDetectionListener.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 snaploader/src/main/java/electrostatic/snaploader/SystemDetectionListener.java diff --git a/snaploader/src/main/java/electrostatic/snaploader/SystemDetectionListener.java b/snaploader/src/main/java/electrostatic/snaploader/SystemDetectionListener.java new file mode 100644 index 0000000..380dd45 --- /dev/null +++ b/snaploader/src/main/java/electrostatic/snaploader/SystemDetectionListener.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023-2024, 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 'AvrSandbox' 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 electrostatic.snaploader; + +import electrostatic.snaploader.platform.NativeDynamicLibrary; + +/** + * Provides executable functions binding the user applications to + * the system detection lifecycle. + *

+ * Note: All the functions on this interface are dispatched + * by the {@link NativeBinaryLoader#loadLibrary(LoadingCriterion)}. + * + * @author pavl_g + */ +public interface SystemDetectionListener { + + /** + * Dispatched when a system predicate is evaluated as true against the + * system in this runtime. + * + * @param nativeBinaryLoader the dispatching loader. + * @param nativeDynamicLibrary the native library object with an evaluated predicate. + */ + void onSystemFound(NativeBinaryLoader nativeBinaryLoader, NativeDynamicLibrary nativeDynamicLibrary); + + /** + * Dispatched when all the registered system predicates are evaluated as false + * against the current system in this runtime. In this case, a {@link UnSupportedSystemError} + * is also thrown on the user application environment. + * + * @param nativeBinaryLoader the dispatching loader + */ + void onSystemNotFound(NativeBinaryLoader nativeBinaryLoader); +} From d13a927b3c912c48a5ebe7f8cfb352d30f3ba2d3 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:11:18 -0400 Subject: [PATCH 07/55] Migration to the Electrostatic-Sandbox project --- .../snaploader/library/LibraryExtractor.java | 9 +++++---- .../electrostatic/snaploader/library/LibraryLocator.java | 9 +++++---- .../electrostatic/snaploader/library/package-info.java | 6 +++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/library/LibraryExtractor.java b/snaploader/src/main/java/electrostatic/snaploader/library/LibraryExtractor.java index 886e538..a30d005 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/library/LibraryExtractor.java +++ b/snaploader/src/main/java/electrostatic/snaploader/library/LibraryExtractor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,11 +29,12 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.library; + +package electrostatic.snaploader.library; import java.io.IOException; -import com.avrsandbox.snaploader.filesystem.ConcurrentFileExtractor; -import com.avrsandbox.snaploader.filesystem.FileExtractor; +import electrostatic.snaploader.filesystem.ConcurrentFileExtractor; +import electrostatic.snaploader.filesystem.FileExtractor; /** * Represents a thread-safe dynamic library (.so, .dll, .dylib) extractor based on the {@link FileExtractor}. diff --git a/snaploader/src/main/java/electrostatic/snaploader/library/LibraryLocator.java b/snaploader/src/main/java/electrostatic/snaploader/library/LibraryLocator.java index b9f2748..f2097ff 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/library/LibraryLocator.java +++ b/snaploader/src/main/java/electrostatic/snaploader/library/LibraryLocator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,13 +29,14 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.library; + +package electrostatic.snaploader.library; import java.io.IOException; import java.util.jar.JarFile; import java.util.zip.ZipEntry; -import com.avrsandbox.snaploader.filesystem.ZipCompressionType; -import com.avrsandbox.snaploader.filesystem.FileLocator; +import electrostatic.snaploader.filesystem.ZipCompressionType; +import electrostatic.snaploader.filesystem.FileLocator; /** * Locates a library inside a jar filesystem, the probable source for the native dynamic libraries to extract and load. diff --git a/snaploader/src/main/java/electrostatic/snaploader/library/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/library/package-info.java index bd6bd7c..077472a 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/library/package-info.java +++ b/snaploader/src/main/java/electrostatic/snaploader/library/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,6 +31,6 @@ */ /** - * Provides specialized implementation for {@link com.avrsandbox.snaploader.filesystem.FileLocator} and {@link com.avrsandbox.snaploader.filesystem.FileExtractor}. + * Provides specialized implementation for {@link electrostatic.snaploader.filesystem.FileLocator} and {@link electrostatic.snaploader.filesystem.FileExtractor}. */ -package com.avrsandbox.snaploader.library; \ No newline at end of file +package electrostatic.snaploader.library; \ No newline at end of file From 8558bdda2bd8ff1eedcfe2038cd82dfc81ebfe53 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:12:04 -0400 Subject: [PATCH 08/55] Added NativeBinaryLoadingListener interface --- .../NativeBinaryLoadingListener.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoadingListener.java diff --git a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoadingListener.java b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoadingListener.java new file mode 100644 index 0000000..18045f5 --- /dev/null +++ b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoadingListener.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2023-2024, 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 'AvrSandbox' 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 electrostatic.snaploader; + +import electrostatic.snaploader.platform.NativeDynamicLibrary; + +/** + * Provides executable functions binding the user applications to + * the loading lifecycle. + *

+ * Note: All the functions on this interface are dispatched + * by the {@link NativeBinaryLoader#loadBinary(NativeDynamicLibrary)}. + * + * @author pavl_g + */ +public interface NativeBinaryLoadingListener { + + /** + * Dispatched when loading the system-specific binary has succeeded. + * + * @param nativeBinaryLoader the dispatching loader + */ + void onLoadingSuccess(NativeBinaryLoader nativeBinaryLoader); + + /** + * Dispatched when loading the system-specific binary has failed. + * + * @param nativeBinaryLoader the dispatching loader + */ + void onLoadingFailure(NativeBinaryLoader nativeBinaryLoader); + + /** + * Dispatched when loading the system-specific binary has failed, + * and the retry criterion has been executed. + *

+ * Note: this dispatching function could be overridden to add + * your own anti-failure mechanisms (i.e., Retry Criterion). + * + * @param nativeBinaryLoader the dispatching loader + */ + void onRetryCriterionExecution(NativeBinaryLoader nativeBinaryLoader); +} From 889f080cd2bc8e35a6c1b3e4f7e80cb24723c442 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:12:57 -0400 Subject: [PATCH 09/55] ExtractionListener: onFailure and onFinialization --- .../filesystem/ExtractionListener.java | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/ExtractionListener.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ExtractionListener.java index 512040b..e8170df 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/ExtractionListener.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ExtractionListener.java @@ -33,19 +33,43 @@ package electrostatic.snaploader.filesystem; /** - * A listener for the extraction process. - * - * @see FileExtractor#extract() + * Provides executable functions ensuring tight binding the user applications to + * the extraction lifecycle. + *

+ * Note: All the functions on this interface are dispatched + * by the {@link FileExtractor#extract()}. + *

+ * Warning: this listener interface is an essential component of + * developing custom system loaders; as it requires freeing the native stream resources + * manually through the {@link ExtractionListener#onExtractionFinalization(FileExtractor, FileLocator)}. + * If not freeing the resources with this interface was attained, then a try-with resources could be used. + * * @author pavl_g */ public interface ExtractionListener { /** - * Dispatched by the {@link FileExtractor#extract()} when the extraction process is completed. + * Dispatched when the extraction process is completed. + * + * @param fileExtractor the extractor in-command. */ void onExtractionCompleted(FileExtractor fileExtractor); + /** + * Dispatched when the extraction process has failed with a throwable + * component. + * + * @param fileExtractor the extractor in-command. + * @param throwable the throwable captured from the FileExtractor API. + */ void onExtractionFailure(FileExtractor fileExtractor, Throwable throwable); + /** + * Dispatched when the extraction process is finalized, at this point, manually + * freeing active resources should be attained. + * + * @param fileExtractor the extractor in-command. + * @param fileLocator the file locator used by the extractor to locate files inside compressions. + */ void onExtractionFinalization(FileExtractor fileExtractor, FileLocator fileLocator); } From 138785190a7bd23b135b28d07af180345d7575d1 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:14:46 -0400 Subject: [PATCH 10/55] FileExtractor: better handling of the extraction lifecycle to avoid memory leaks when failure occurs and provide anti-failure machanisms --- .../snaploader/filesystem/FileExtractor.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java index 45d2a51..23f9c6b 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.filesystem; + +package electrostatic.snaploader.filesystem; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -63,6 +64,7 @@ public class FileExtractor implements OutputStreamProvider { * An absolute path for the destination filesystem of the extraction process. */ protected String destination; + private static final int EOF = -1; /* End-of-filesystem */ /** @@ -90,6 +92,14 @@ protected FileExtractor() { */ public void extract() throws IOException { try { + /* uses buffered streams */ + /* buffered byte streams provide a constant memory allocation + * according to the file size in bytes, + * this constant memory allocation is then treated + * as a pipe; either a unidirectional (simplex) or a bidirectional (duplex) + * unlike the unbuffered streams, which polls byte streams from an online + * pipe, and allocate memory according to the active bytes manipulated + * by the pipeline. */ InputStream libraryStream = fileLocator.getFileInputStream(); /* Extracts the shipped native files */ final byte[] buffer = new byte[libraryStream.available()]; From 4c47dfa94d1a20f42afd66704b1b7faa0976d013 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:15:29 -0400 Subject: [PATCH 11/55] snaploader/filesystem: the rest of migration to the Electrostatic-Sandbox project --- .../filesystem/ConcurrentFileExtractor.java | 5 +++-- .../snaploader/filesystem/FileLocator.java | 8 +++++--- .../snaploader/filesystem/InputStreamProvider.java | 5 +++-- .../snaploader/filesystem/OutputStreamProvider.java | 12 ++++++------ .../snaploader/filesystem/ZipCompressionType.java | 5 +++-- .../snaploader/filesystem/package-info.java | 6 +++--- 6 files changed, 23 insertions(+), 18 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/ConcurrentFileExtractor.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ConcurrentFileExtractor.java index 423a7b0..5aab36c 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/ConcurrentFileExtractor.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ConcurrentFileExtractor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.filesystem; + +package electrostatic.snaploader.filesystem; import java.io.FileNotFoundException; import java.io.IOException; diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java index e78e4b5..3136ee1 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.filesystem; + +package electrostatic.snaploader.filesystem; import java.io.IOException; import java.io.InputStream; @@ -53,7 +54,8 @@ public class FileLocator implements InputStreamProvider { * Locates a filesystem inside an external zip compression, the zip filesystem is defined as a {@link ZipFile} object and * the locatable filesystem is defined as a {@link ZipEntry} object. *

- * Warning: This object leaks an input stream. + * Warning: This object leaks a buffered stream, either use try-with-resources, or handle your + * memory manually! * * @param directory the absolute path for the external jar filesystem * @param filePath the path to the filesystem to be extracted diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java index 6e9cd60..505c406 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.filesystem; + +package electrostatic.snaploader.filesystem; import java.io.InputStream; diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/OutputStreamProvider.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/OutputStreamProvider.java index f6277c3..73cc01e 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/OutputStreamProvider.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/OutputStreamProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,12 +29,13 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.filesystem; + +package electrostatic.snaploader.filesystem; import java.io.OutputStream; /** - * Defines an interface for an output stream provider to locate and extract a filesystem from a zip compression, + * Defines an interface for an output stream provider to locate and extract a filesystem from a zip compression; * the output stream provider object is associated with an input stream provider object that locates this filesystem. * * @author pavl_g @@ -49,10 +50,9 @@ public interface OutputStreamProvider extends AutoCloseable { InputStreamProvider getFileLocator(); /** - * Retrieves the output stream object associated with this provider, the output stream is - * associated with the + * Retrieves the output stream object associated with this provider. * * @return an output stream provider object to extract the filesystem */ OutputStream getFileOutputStream(); -} +} \ No newline at end of file diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/ZipCompressionType.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ZipCompressionType.java index 61ec520..dc2e08e 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/ZipCompressionType.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ZipCompressionType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.filesystem; + +package electrostatic.snaploader.filesystem; import java.io.IOException; import java.util.jar.JarFile; diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/package-info.java index b2fadb0..bcd03d6 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/package-info.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,6 +31,6 @@ */ /** - * Provides I/O stream provider interfaces for {@link com.avrsandbox.snaploader.library.LibraryLocator} and {@link com.avrsandbox.snaploader.library.LibraryExtractor}. + * Provides I/O stream provider interfaces for {@link electrostatic.snaploader.library.LibraryLocator} and {@link electrostatic.snaploader.library.LibraryExtractor}. */ -package com.avrsandbox.snaploader.filesystem; +package electrostatic.snaploader.filesystem; From 6c03c9ba0b9451f7518950ec97c0e53bb147aef6 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:16:27 -0400 Subject: [PATCH 12/55] NativeBinaryLoader: API assembly and applied changes --- .../snaploader/NativeBinaryLoader.java | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java index 48ffc85..77ee4ae 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java +++ b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,20 +29,20 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader; + +package electrostatic.snaploader; import java.io.IOException; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import java.lang.UnsatisfiedLinkError; - -import com.avrsandbox.snaploader.filesystem.ExtractionListener; -import com.avrsandbox.snaploader.filesystem.FileExtractor; -import com.avrsandbox.snaploader.filesystem.FileLocator; -import com.avrsandbox.snaploader.library.LibraryExtractor; -import com.avrsandbox.snaploader.platform.NativeDynamicLibrary; -import com.avrsandbox.snaploader.platform.util.NativeVariant; +import electrostatic.snaploader.filesystem.ExtractionListener; +import electrostatic.snaploader.filesystem.FileExtractor; +import electrostatic.snaploader.filesystem.FileLocator; +import electrostatic.snaploader.library.LibraryExtractor; +import electrostatic.snaploader.platform.NativeDynamicLibrary; +import electrostatic.snaploader.platform.util.NativeVariant; /** * A cross-platform utility for extracting and loading native binaries based on @@ -63,7 +63,7 @@ public class NativeBinaryLoader { protected NativeBinaryLoadingListener nativeBinaryLoadingListener; - protected SystemFoundListener systemFoundListener; + protected SystemDetectionListener systemDetectionListener; /** * An Output stream concrete provider for library extraction. @@ -105,26 +105,6 @@ public NativeBinaryLoader registerNativeLibraries(NativeDynamicLibrary[] nativeD return this; } - public List getRegisteredLibraries() { - return registeredLibraries; - } - - public void setNativeBinaryLoadingListener(NativeBinaryLoadingListener nativeBinaryLoadingListener) { - this.nativeBinaryLoadingListener = nativeBinaryLoadingListener; - } - - public NativeBinaryLoadingListener getNativeBinaryLoadingListener() { - return nativeBinaryLoadingListener; - } - - public void setSystemFoundListener(SystemFoundListener systemFoundListener) { - this.systemFoundListener = systemFoundListener; - } - - public SystemFoundListener getSystemFoundListener() { - return systemFoundListener; - } - /** * Initializes the platform-dependent native dynamic library. * @@ -144,18 +124,18 @@ public NativeBinaryLoader initPlatformLibrary() throws UnSupportedSystemError { if (libraryInfo != null) { nativeDynamicLibrary.initWithLibraryInfo(libraryInfo); } - if (nativeDynamicLibrary.getPredicate()) { + if (nativeDynamicLibrary.getPlatformPredicate().evaluatePredicate()) { this.nativeDynamicLibrary = nativeDynamicLibrary; isSystemFound[0] = true; } }); - // execute system found listeners - if (systemFoundListener != null) { + // execute a system found listeners + if (systemDetectionListener != null) { if (isSystemFound[0]) { - systemFoundListener.onSystemFound(this, nativeDynamicLibrary); + systemDetectionListener.onSystemFound(this, nativeDynamicLibrary); } else { - systemFoundListener.onSystemNotFound(this); + systemDetectionListener.onSystemNotFound(this); throw new UnSupportedSystemError(NativeVariant.OS_NAME.getProperty(), NativeVariant.OS_ARCH.getProperty()); } @@ -164,7 +144,7 @@ public NativeBinaryLoader initPlatformLibrary() throws UnSupportedSystemError { } /** - * Extracts and loads the system and the architecture-specific library from the output jar to the [user.dir] + * Extracts and load the system and the architecture-specific library from the output jar to the [user.dir] * according to a loading criterion (incremental-load or clean-extract). * * @param criterion the initial loading criterion, either {@link LoadingCriterion#INCREMENTAL_LOADING} or {@link LoadingCriterion#CLEAN_EXTRACTION} @@ -225,6 +205,26 @@ public boolean isRetryWithCleanExtraction() { return retryWithCleanExtraction; } + public List getRegisteredLibraries() { + return registeredLibraries; + } + + public void setNativeBinaryLoadingListener(NativeBinaryLoadingListener nativeBinaryLoadingListener) { + this.nativeBinaryLoadingListener = nativeBinaryLoadingListener; + } + + public NativeBinaryLoadingListener getNativeBinaryLoadingListener() { + return nativeBinaryLoadingListener; + } + + public void setSystemFoundListener(SystemDetectionListener systemDetectionListener) { + this.systemDetectionListener = systemDetectionListener; + } + + public SystemDetectionListener getSystemFoundListener() { + return systemDetectionListener; + } + /** * 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). From d4cdc24d556228d41f797f701f847b8db1941a0d Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:17:02 -0400 Subject: [PATCH 13/55] snaploader: the rest of migration to the Electrostatic-Sandbox --- .../snaploader/ConcurrentNativeBinaryLoader.java | 7 ++++--- .../main/java/electrostatic/snaploader/LibraryInfo.java | 7 ++++--- .../java/electrostatic/snaploader/LoadingCriterion.java | 5 +++-- .../electrostatic/snaploader/UnSupportedSystemError.java | 5 +++-- .../main/java/electrostatic/snaploader/package-info.java | 4 ++-- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/ConcurrentNativeBinaryLoader.java b/snaploader/src/main/java/electrostatic/snaploader/ConcurrentNativeBinaryLoader.java index cb92ddb..38059bd 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/ConcurrentNativeBinaryLoader.java +++ b/snaploader/src/main/java/electrostatic/snaploader/ConcurrentNativeBinaryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,12 +29,13 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader; + +package electrostatic.snaploader; import java.io.IOException; import java.util.List; import java.util.concurrent.locks.ReentrantLock; -import com.avrsandbox.snaploader.platform.NativeDynamicLibrary; +import electrostatic.snaploader.platform.NativeDynamicLibrary; /** * A thread-safe implementation for the NativeBinaryLoader. diff --git a/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java b/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java index 6c9cf98..411853b 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java +++ b/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,9 +29,10 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader; -import com.avrsandbox.snaploader.platform.NativeDynamicLibrary; +package electrostatic.snaploader; + +import electrostatic.snaploader.platform.NativeDynamicLibrary; /** * Provides a library placeholder with an adjustable baseName {@link LibraryInfo#baseName}. diff --git a/snaploader/src/main/java/electrostatic/snaploader/LoadingCriterion.java b/snaploader/src/main/java/electrostatic/snaploader/LoadingCriterion.java index 76c272e..534ce58 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/LoadingCriterion.java +++ b/snaploader/src/main/java/electrostatic/snaploader/LoadingCriterion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader; + +package electrostatic.snaploader; /** * Represents an extraction/loading criterion type. diff --git a/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java b/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java index 13d2f39..a30531c 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java +++ b/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader; + +package electrostatic.snaploader; /** * A business error of type {@link UnsatisfiedLinkError} to indicate an un-supported system. diff --git a/snaploader/src/main/java/electrostatic/snaploader/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/package-info.java index 6848181..670a319 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/package-info.java +++ b/snaploader/src/main/java/electrostatic/snaploader/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,4 +33,4 @@ /** * Provides a loader api for the library, the loader extracts and loads the system specific binary on the runtime. */ -package com.avrsandbox.snaploader; +package electrostatic.snaploader; From f8e82520751f0f449913e60608377021634add52 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:17:39 -0400 Subject: [PATCH 14/55] software-architecture: added a plantuml paradigm --- architecture/architectural-paradigm.png | Bin 0 -> 108940 bytes architecture/architectural-paradigm.puml | 100 +++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 architecture/architectural-paradigm.png create mode 100644 architecture/architectural-paradigm.puml diff --git a/architecture/architectural-paradigm.png b/architecture/architectural-paradigm.png new file mode 100644 index 0000000000000000000000000000000000000000..b72a89954c7ab84c4d395a3197911f9e4bb4f940 GIT binary patch literal 108940 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 Yq31#`?U!@CApWhUtf`c__weQa1rlQa2mk;8 literal 0 HcmV?d00001 diff --git a/architecture/architectural-paradigm.puml b/architecture/architectural-paradigm.puml new file mode 100644 index 0000000..a90e5d4 --- /dev/null +++ b/architecture/architectural-paradigm.puml @@ -0,0 +1,100 @@ +@startuml +'https://plantuml.com/component-diagram + +'Structural composition +package platform { + package util { + component NativeVariant { + } + component PropertiesProvider { + } + component PlatformPredicate { + } + } + component NativeDynamicLibrary <> { + } + note top of [NativeDynamicLibrary]: // PlatformDirectory + note top of [NativeDynamicLibrary]: // Predicate + note top of [NativeDynamicLibrary]: // LibraryInfo +} + +node List <> { +} + +package snaploader { + component LoadingCriterion <> { + } + interface LoadingListeners { + } + component LibraryInfo <> { + } + + object NativeBinaryLoader { + // Platform Detection + // NativeVariant Object Instantiation + // LibraryLocator + // LibraryExtractor + } +} + +package filesystem { + component FileExtractor { + } + + component FileLocator { + } + + object LibraryExtractor { + // from StockJar + // from ExternalJar + } + + object LibraryLocator { + // StockJar + // ExternalJar + } + + component ZipCompressionType { + } + + interface StreamProvider { + } + + interface ExtractionListener { + } + + component InputStreamProvider { + } + + component OutputStreamProvider { + } +} + +'Relations +NativeDynamicLibrary ..-> NativeVariant : Depends-on +NativeDynamicLibrary ..-> PropertiesProvider : Depends-on +NativeDynamicLibrary ..-> PlatformPredicate : Depends-on +NativeDynamicLibrary ...> LibraryInfo : Depends-on + + +StreamProvider <-. InputStreamProvider : Realized-from +StreamProvider <-. OutputStreamProvider : Realized-from + +FileExtractor <-. LibraryExtractor : Realized-from +FileExtractor -(0- ExtractionListener : Assembled-by +FileLocator <-. LibraryLocator : Realized-from +ZipCompressionType <-. FileLocator : Depends-on +LibraryLocator <.. LibraryExtractor : Depends-on + +NativeBinaryLoader --(0-- LibraryExtractor : Assembled-by +NativeBinaryLoader --(0-- LoadingListeners : Assembled-by +NativeBinaryLoader --(0-- "List" : Assembled-by +NativeBinaryLoader --(0-- LibraryInfo : Indirect-assembly +NativeBinaryLoader --(0-- LoadingCriterion : Assembled-by + +'Notes +note top of "List": // List of libraries to check against their predicates +note top of "LibraryInfo": // Provides the Jar path for the locator, and the library extraction path + + +@enduml \ No newline at end of file From 8ae26c0faa83b63ad95bfb6dd8d9878d0810837c Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:18:43 -0400 Subject: [PATCH 15/55] LICENSE: migration to the Electrostatic-Sandbox Distributed Simulation Framework Project --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index d873fd5..66bc1b9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2023, AvrSandbox, jSnapLoader +Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From 5b65fafb25376fbb65307bf249478162d5a35fc3 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:19:51 -0400 Subject: [PATCH 16/55] README.md: software architectural paradigm and specification --- README.md | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fe8a67a..9b9090f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,22 @@ # jSnapLoader [![Codacy Badge](https://app.codacy.com/project/badge/Grade/50261f7cc09b4b9bacaf9f44ecc28ea9)](https://app.codacy.com/gh/Software-Hardware-Codesign/jSnapLoader/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![](https://img.shields.io/badge/jSnapLoader-latest_version-red)](https://github.com/Software-Hardware-Codesign/jSnapLoader/releases) [![](https://github.com/Software-Hardware-Codesign/jSnapLoader/actions/workflows/build-test.yml/badge.svg)]() [![](https://github.com/Software-Hardware-Codesign/jSnapLoader/actions/workflows/build-deploy.yml/badge.svg)]() -A high-performance cross-platform dynamic library loader API for JVM Applications. +A high-performance cross-platform dynamic library loader API for JVM Applications, +with highly modifiable system-specific registration using platform predicates. + +## Software Specification: + +| Item | Description | Predicate Calculus | +|---------------------------------|-------------|--------------------| +| _Problem Definition_ | | | +| _Generalized Approach_ | | | +| _jSnapLoader-specific Approach_ | | | +| _Framework Decomposition_ | | | +| _Framework Enhancements_ | | | +| _Credits for other systems_ | | | + +## Software Architectural Paradigm: +Architectural-Paradigm-Placement ## Quick Building and running examples: ```bash @@ -30,8 +45,13 @@ BUILD SUCCESSFUL in 1s 4 actionable tasks: 2 executed, 2 up-to-date ``` -## Appendix -Features: +## Plug-and-play usage: + + +## Appendix: +### Features: +- [x] Platform-specific dynamic libraries' registration. +- [x] Platform-specific dynamic libraries building using platform-specific predicates (NEW). - [x] Locate and load external dynamic libraries directly. - [x] Extract native libraries from the stock jar library (classpath). - [x] Locate external jars and extract native libraries from them. @@ -39,8 +59,10 @@ Features: - [x] Retry Criterion with clean extraction (NEW). - [x] Exposed the platform-dependent library `NativeDynamicLibrary` (NEW). - [x] Exposed the `NativeVariant` providing system properties. +- [x] EventDispatchers: Extraction Listeners, Loading Listeners, and System Detection Listeners. - [ ] Extract automatically based on the application name and version. -Documentation-list: -- [ ] Architecture paradigm. +### Documentation-list: +- [x] Architecture paradigm. - [x] API documentation. +- [ ] Java-Doc page. From 583af1392c3da31704a381a6cc4577d9db418fdd Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:20:20 -0400 Subject: [PATCH 17/55] snaploader-examples: applied API changes --- snaploader-examples/build.gradle | 10 +++++----- .../examples/TestBasicFeatures.java | 19 ++++++++++--------- .../examples/TestMultiThreading.java | 15 ++++++++------- .../examples/TestMultipleLoads.java | 5 +++-- .../snaploader/examples/TestZipExtractor.java | 15 ++++++++------- 5 files changed, 34 insertions(+), 30 deletions(-) diff --git a/snaploader-examples/build.gradle b/snaploader-examples/build.gradle index 180311f..3fc3185 100644 --- a/snaploader-examples/build.gradle +++ b/snaploader-examples/build.gradle @@ -4,23 +4,23 @@ plugins { } application { - mainClass = 'com.avrsandbox.snaploader.examples.TestBasicFeatures' + mainClass = 'electrostatic.snaploader.examples.TestBasicFeatures' } tasks.register("TestBasicFeatures") { - application.mainClass = 'com.avrsandbox.snaploader.examples.TestBasicFeatures' + application.mainClass = 'electrostatic.snaploader.examples.TestBasicFeatures' } tasks.register("TestMultipleLoads") { - application.mainClass = 'com.avrsandbox.snaploader.examples.TestMultipleLoads' + application.mainClass = 'electrostatic.snaploader.examples.TestMultipleLoads' } tasks.register("TestZipExtractor") { - application.mainClass = 'com.avrsandbox.snaploader.examples.TestZipExtractor' + application.mainClass = 'electrostatic.snaploader.examples.TestZipExtractor' } tasks.register("TestMultiThreading") { - application.mainClass = 'com.avrsandbox.snaploader.examples.TestMultiThreading' + application.mainClass = 'electrostatic.snaploader.examples.TestMultiThreading' } dependencies { diff --git a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java index cb983ce..9cdd9f2 100644 --- a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java +++ b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,17 +29,18 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.examples; + +package electrostatic.snaploader.examples; import java.io.IOException; -import com.avrsandbox.snaploader.LibraryInfo; -import com.avrsandbox.snaploader.NativeBinaryLoader; -import com.avrsandbox.snaploader.platform.util.DefaultDynamicLibraries; -import com.avrsandbox.snaploader.platform.NativeDynamicLibrary; -import com.avrsandbox.snaploader.platform.util.NativeVariant; -import com.avrsandbox.snaploader.platform.util.PropertiesProvider; -import com.avrsandbox.snaploader.LoadingCriterion; +import electrostatic.snaploader.LibraryInfo; +import electrostatic.snaploader.NativeBinaryLoader; +import electrostatic.snaploader.platform.util.DefaultDynamicLibraries; +import electrostatic.snaploader.platform.NativeDynamicLibrary; +import electrostatic.snaploader.platform.util.NativeVariant; +import electrostatic.snaploader.platform.util.PropertiesProvider; +import electrostatic.snaploader.LoadingCriterion; /** * Tests basic features of the {@link NativeBinaryLoader} API. diff --git a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultiThreading.java b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultiThreading.java index d18322b..e25913c 100644 --- a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultiThreading.java +++ b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultiThreading.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,16 +29,17 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.examples; + +package electrostatic.snaploader.examples; import java.io.IOException; import java.util.Arrays; -import com.avrsandbox.snaploader.LoadingCriterion; -import com.avrsandbox.snaploader.ConcurrentNativeBinaryLoader; -import com.avrsandbox.snaploader.UnSupportedSystemError; -import com.avrsandbox.snaploader.platform.util.DefaultDynamicLibraries; -import com.avrsandbox.snaploader.platform.NativeDynamicLibrary; +import electrostatic.snaploader.LoadingCriterion; +import electrostatic.snaploader.ConcurrentNativeBinaryLoader; +import electrostatic.snaploader.UnSupportedSystemError; +import electrostatic.snaploader.platform.util.DefaultDynamicLibraries; +import electrostatic.snaploader.platform.NativeDynamicLibrary; /** * Tests multi-threading and thread locks. diff --git a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultipleLoads.java b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultipleLoads.java index 461b0f4..a78f110 100644 --- a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultipleLoads.java +++ b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestMultipleLoads.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.examples; + +package electrostatic.snaploader.examples; import java.io.File; import java.io.IOException; diff --git a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestZipExtractor.java b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestZipExtractor.java index 50e1082..f52c0b9 100644 --- a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestZipExtractor.java +++ b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestZipExtractor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, AvrSandbox, jSnapLoader + * Copyright (c) 2023-2024, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,15 +29,16 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.avrsandbox.snaploader.examples; + +package electrostatic.snaploader.examples; import java.io.IOException; -import com.avrsandbox.snaploader.filesystem.ExtractionListener; -import com.avrsandbox.snaploader.filesystem.FileExtractor; -import com.avrsandbox.snaploader.filesystem.FileLocator; -import com.avrsandbox.snaploader.filesystem.ZipCompressionType; -import com.avrsandbox.snaploader.platform.util.PropertiesProvider; +import electrostatic.snaploader.filesystem.ExtractionListener; +import electrostatic.snaploader.filesystem.FileExtractor; +import electrostatic.snaploader.filesystem.FileLocator; +import electrostatic.snaploader.filesystem.ZipCompressionType; +import electrostatic.snaploader.platform.util.PropertiesProvider; /** * Tests extracting an image compression from a Zip compression type filesystem using {@link FileExtractor} API. From 6a358036f73a0a6bdc9298c56ed91d20bef6ff17 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:37:05 -0400 Subject: [PATCH 18/55] NativeBinaryLoader#initPlatformLibrary(): separated business exception throwing from the listener dispatch --- .../snaploader/NativeBinaryLoader.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java index 77ee4ae..3bb4d3d 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java +++ b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java @@ -131,15 +131,18 @@ public NativeBinaryLoader initPlatformLibrary() throws UnSupportedSystemError { }); // execute a system found listeners - if (systemDetectionListener != null) { - if (isSystemFound[0]) { + if (isSystemFound[0]) { + if (systemDetectionListener != null) { systemDetectionListener.onSystemFound(this, nativeDynamicLibrary); - } else { + } + } else { + if (systemDetectionListener != null) { systemDetectionListener.onSystemNotFound(this); - throw new UnSupportedSystemError(NativeVariant.OS_NAME.getProperty(), - NativeVariant.OS_ARCH.getProperty()); } + throw new UnSupportedSystemError(NativeVariant.OS_NAME.getProperty(), + NativeVariant.OS_ARCH.getProperty()); } + return this; } From 96cb1ee0000fced76e64a3d6148818153eb016eb Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 06:48:04 -0400 Subject: [PATCH 19/55] platform/util: merged the NativeVariant#isAMD() and the isX86() together as isX86() --- .../snaploader/platform/util/NativeVariant.java | 14 +++----------- .../platform/util/PlatformPredicate.java | 6 +++--- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java index fbfb6b7..47d254d 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java @@ -116,7 +116,7 @@ public static boolean is64() { * @return true if the current OS architecture is of an x86 chipset, false otherwise. */ public static boolean isX86() { - return OS_ARCH.getProperty().contains("x86"); + return OS_ARCH.getProperty().contains("x86") | OS_ARCH.getProperty().contains("amd"); } /** @@ -128,22 +128,14 @@ public static boolean is32() { return OS_ARCH.getProperty().contains("32"); } - /** - * Tests whether the current CPU vendor is an AMD vendor (e.g., Intel Chipset). - * - * @return true if the current CPU vendor is an AMD vendor. - */ - public static boolean isAMD() { - return OS_ARCH.getProperty().contains("amd"); - } - /** * Tests whether the current CPU vendor is an ARM vendor (e.g., Broadcom Chipset). * * @return true if the current CPU vendor is an ARM vendor. */ public static boolean isARM() { - return OS_ARCH.getProperty().contains("arm"); + return OS_ARCH.getProperty().contains("arm") || + OS_ARCH.getProperty().contains("aarch"); } /** diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java index 57eee92..90d59cb 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java @@ -42,15 +42,15 @@ public final class PlatformPredicate { public static final PlatformPredicate LINUX_X86 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isX86()); - public static final PlatformPredicate LINUX_X86_64 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isAMD() && NativeVariant.is64()); + public static final PlatformPredicate LINUX_X86_64 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isX86() && NativeVariant.is64()); public static final PlatformPredicate LINUX_ARM_32 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isARM() && NativeVariant.is32()); public static final PlatformPredicate LINUX_ARM_64 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isARM() && NativeVariant.is64()); public static final PlatformPredicate MACOS_X86 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isX86()); - public static final PlatformPredicate MACOS_X86_64 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isAMD() && NativeVariant.is64()); + public static final PlatformPredicate MACOS_X86_64 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isX86() && NativeVariant.is64()); public static final PlatformPredicate MACOS_ARM_32 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isARM() && NativeVariant.is32()); public static final PlatformPredicate MACOS_ARM_64 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isARM() && NativeVariant.is64()); public static final PlatformPredicate WIN_X86 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isX86()); - public static final PlatformPredicate WIN_X86_64 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isAMD() && NativeVariant.is64()); + public static final PlatformPredicate WIN_X86_64 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isX86() && NativeVariant.is64()); public static final PlatformPredicate WIN_ARM_32 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isARM() && NativeVariant.is32()); public static final PlatformPredicate WIN_ARM_64 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isARM() && NativeVariant.is64()); From 08607906f426bd8adcb3a2b0f8ed8beb03019ac6 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 07:03:08 -0400 Subject: [PATCH 20/55] NativeVariant: removed is32() proposition --- .../snaploader/platform/util/NativeVariant.java | 13 ++++++------- .../snaploader/platform/util/PlatformPredicate.java | 12 ++++++------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java index 47d254d..41b50c5 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java @@ -116,16 +116,16 @@ public static boolean is64() { * @return true if the current OS architecture is of an x86 chipset, false otherwise. */ public static boolean isX86() { - return OS_ARCH.getProperty().contains("x86") | OS_ARCH.getProperty().contains("amd"); + return OS_ARCH.getProperty().contains("x86") || OS_ARCH.getProperty().contains("i386"); } /** - * Tests whether the current system architecture is a 32-bit chipset. + * Tests whether the current CPU vendor is an AMD vendor (e.g., x86_64 Intel Chipset). * - * @return true if the current OS architecture is a 32-bit chipset, false otherwise. + * @return true if the current CPU vendor is an AMD vendor. */ - public static boolean is32() { - return OS_ARCH.getProperty().contains("32"); + public static boolean isAMD() { + return OS_ARCH.getProperty().contains("amd"); } /** @@ -134,8 +134,7 @@ public static boolean is32() { * @return true if the current CPU vendor is an ARM vendor. */ public static boolean isARM() { - return OS_ARCH.getProperty().contains("arm") || - OS_ARCH.getProperty().contains("aarch"); + return OS_ARCH.getProperty().contains("arm") || OS_ARCH.getProperty().contains("aarch"); } /** diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java index 90d59cb..da2bc8f 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java @@ -42,16 +42,16 @@ public final class PlatformPredicate { public static final PlatformPredicate LINUX_X86 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isX86()); - public static final PlatformPredicate LINUX_X86_64 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isX86() && NativeVariant.is64()); - public static final PlatformPredicate LINUX_ARM_32 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isARM() && NativeVariant.is32()); + public static final PlatformPredicate LINUX_X86_64 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isAMD() && NativeVariant.is64()); + public static final PlatformPredicate LINUX_ARM_32 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isARM()); public static final PlatformPredicate LINUX_ARM_64 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isARM() && NativeVariant.is64()); public static final PlatformPredicate MACOS_X86 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isX86()); - public static final PlatformPredicate MACOS_X86_64 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isX86() && NativeVariant.is64()); - public static final PlatformPredicate MACOS_ARM_32 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isARM() && NativeVariant.is32()); + public static final PlatformPredicate MACOS_X86_64 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isAMD() && NativeVariant.is64()); + public static final PlatformPredicate MACOS_ARM_32 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isARM()); public static final PlatformPredicate MACOS_ARM_64 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isARM() && NativeVariant.is64()); public static final PlatformPredicate WIN_X86 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isX86()); - public static final PlatformPredicate WIN_X86_64 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isX86() && NativeVariant.is64()); - public static final PlatformPredicate WIN_ARM_32 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isARM() && NativeVariant.is32()); + public static final PlatformPredicate WIN_X86_64 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isAMD() && NativeVariant.is64()); + public static final PlatformPredicate WIN_ARM_32 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isARM()); public static final PlatformPredicate WIN_ARM_64 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isARM() && NativeVariant.is64()); private final boolean predicate; From fb60dd951b78e8590f61cb93acd8c455ca71f0ec Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 07:03:47 -0400 Subject: [PATCH 21/55] workflows: use arch x86_64 as default --- .github/workflows/build-test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 29eddcb..42a306e 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -70,7 +70,8 @@ jobs: needs: build-snaploader strategy: matrix: - os: [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ] + os: [ 'ubuntu-latest', 'windows-latest', 'macos-latest' ] + architecture: [x86_64] name: Testing snaploader on ${{ matrix.os }} for x86-64 # Steps represent a sequence of tasks that will be executed as part of the job From e5f4be3e03c3ccb8001d69e341cd5b1a78770b46 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 07:07:00 -0400 Subject: [PATCH 22/55] workflows/build-test: removed macos runner --- .github/workflows/build-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 42a306e..75a67f2 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -70,7 +70,7 @@ jobs: needs: build-snaploader strategy: matrix: - os: [ 'ubuntu-latest', 'windows-latest', 'macos-latest' ] + os: [ 'ubuntu-latest', 'windows-latest' ] architecture: [x86_64] name: Testing snaploader on ${{ matrix.os }} for x86-64 From 51fb6eacbb9a01737a311d949777f22d6c4ad932 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 07:18:44 -0400 Subject: [PATCH 23/55] NativeBinaryLoader#cleanExtractBinary(NativeDynamicLibrary): release file locks before usage by the Java Loader --- .../snaploader/NativeBinaryLoader.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java index 3bb4d3d..260ecba 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java +++ b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java @@ -275,10 +275,13 @@ protected void cleanExtractBinary(NativeDynamicLibrary library) throws IOExcepti libraryExtractor.setExtractionListener(new ExtractionListener() { @Override public void onExtractionCompleted(FileExtractor fileExtractor) { - log(Level.INFO, "cleanExtractBinary", "Extracted successfully to " + library.getExtractedLibrary(), null); try { + libraryExtractor.getFileLocator().close(); + libraryExtractor.close(); + libraryExtractor = null; + log(Level.INFO, "cleanExtractBinary", "Extracted successfully to " + library.getExtractedLibrary(), null); loadBinary(library); - } catch (IOException e) { + } catch (Exception e) { log(Level.SEVERE, "cleanExtractBinary", "Error while loading the binary!", e); } } @@ -291,15 +294,20 @@ public void onExtractionFailure(FileExtractor fileExtractor, Throwable throwable @Override public void onExtractionFinalization(FileExtractor fileExtractor, FileLocator fileLocator) { try { - fileLocator.close(); - fileExtractor.close(); + if (fileLocator != null && + fileLocator.getFileInputStream() != null) { + fileLocator.close(); + } + if (fileExtractor != null && + fileExtractor.getFileOutputStream() != null) { + fileExtractor.close(); + } } catch (IOException e) { log(Level.SEVERE, "cleanExtractBinary", "Error while closing the resources!", e); } } }); libraryExtractor.extract(); - libraryExtractor = null; } /** From 6226292969d8dd3e512649093547af930c3bb8f4 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 16:15:28 -0400 Subject: [PATCH 24/55] NativeVariant: separated propositions into namespace classes and added more CPU propositions --- .../platform/util/NativeVariant.java | 232 +++++++++++++----- 1 file changed, 173 insertions(+), 59 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java index 41b50c5..1d134f1 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java @@ -34,7 +34,26 @@ /** * Wraps objects for native variant constituents (OS + ARCH={CPU + INSTRUCT_SET} + VM). - * + * + *

+ * Use the following list to build your platform predicates: + *

  • x86: 32-bit x86 architecture
  • + *
  • x86_64: 64-bit x86 architecture, often referred to as amd64
  • + *
  • amd64: Another name for x86_64
  • + *
  • i386: Another designation for 32-bit x86 architecture
  • + *
  • arm: ARM architecture
  • + *
  • aarch64: 64-bit ARM architecture
  • + *
  • sparc: SPARC architecture
  • + *
  • sparcv9: 64-bit SPARC architecture
  • + *
  • ppc: PowerPC architecture
  • + *
  • ppc64: 64-bit PowerPC architecture
  • + *
  • ppc64le: 64-bit PowerPC architecture, little-endian
  • + *
  • s390: IBM System/390 architecture
  • + *
  • s390x: 64-bit IBM System/390 architecture
  • + *
  • riscv32: 32-bit RISC-V architecture
  • + *
  • riscv64: 64-bit RISC-V architecture
  • + *

    + * * @author pavl_g */ public enum NativeVariant { @@ -66,75 +85,170 @@ public enum NativeVariant { } /** - * Tests whether the current system is a Linux. - * - * @return true if the current OS is a Linux, false otherwise. + * A namespace class exposing the Operating System Propositions. */ - public static boolean isLinux() { - return NativeVariant.OS_NAME.getProperty().contains(NativeVariant.Linux); - } + public static final class Os { + private Os() { + } + /** + * Tests whether the current system is a Linux. + * + * @return true if the current OS is a Linux, false otherwise. + */ + public static boolean isLinux() { + return NativeVariant.OS_NAME.getProperty().contains(NativeVariant.Linux); + } - /** - * Tests whether the current system is a Windows. - * - * @return true if the current OS is a Windows, false otherwise. - */ - public static boolean isWindows() { - return NativeVariant.OS_NAME.getProperty().contains(NativeVariant.Windows); - } + /** + * Tests whether the current system is a Windows. + * + * @return true if the current OS is a Windows, false otherwise. + */ + public static boolean isWindows() { + return NativeVariant.OS_NAME.getProperty().contains(NativeVariant.Windows); + } - /** - * Tests whether the current system is a Mac. - * - * @return true if the current OS is a Mac, false otherwise. - */ - public static boolean isMac() { - return NativeVariant.OS_NAME.getProperty().contains(NativeVariant.Mac); - } + /** + * Tests whether the current system is a Mac. + * + * @return true if the current OS is a Mac, false otherwise. + */ + public static boolean isMac() { + return NativeVariant.OS_NAME.getProperty().contains(NativeVariant.Mac); + } - /** - * Tests whether the current system is an Android. - * - * @return true if the current OS is an Android, false otherwise. - */ - public static boolean isAndroid() { - return JVM.getProperty().contains(NativeVariant.Dalvik); + /** + * Tests whether the current system is an Android. + * + * @return true if the current OS is an Android, false otherwise. + */ + public static boolean isAndroid() { + return JVM.getProperty().contains(NativeVariant.Dalvik); + } } /** - * Tests whether the current system architecture is a 64-bit chipset. - * - * @return true if the current OS architecture is a 64-bit chipset, false otherwise. + * A namespace class exposing the CPU propositions. */ - public static boolean is64() { - return OS_ARCH.getProperty().contains("64"); - } + public static final class Cpu { + private Cpu() { + } - /** - * Tests whether the current system architecture is of an x86 chipset, typically 32-bit intel chipsets. - * - * @return true if the current OS architecture is of an x86 chipset, false otherwise. - */ - public static boolean isX86() { - return OS_ARCH.getProperty().contains("x86") || OS_ARCH.getProperty().contains("i386"); - } + /** + * Tests whether the current environment is running + * on a RISC-V (reduced instruction-set) CPU, typically plain RISC-V means 32-bit, and + * with the added predicate {@link Cpu#is64()} adds the 64-bit + * predicate. + * + * @return true if the current runtime is operating on a RISC-V + */ + public static boolean isRiscV() { + return JVM.getProperty().contains("riscv"); + } - /** - * Tests whether the current CPU vendor is an AMD vendor (e.g., x86_64 Intel Chipset). - * - * @return true if the current CPU vendor is an AMD vendor. - */ - public static boolean isAMD() { - return OS_ARCH.getProperty().contains("amd"); - } + /** + * Tests whether the current runtime environment is operating + * on a Sparc CPU, typically plain Sparc means 32-bit. + * + * @return true if the current runtime is operating on a Sparc. + * @see Cpu#isSparcV9() + */ + public static boolean isSparc() { + return JVM.getProperty().contains("sparc"); + } - /** - * Tests whether the current CPU vendor is an ARM vendor (e.g., Broadcom Chipset). - * - * @return true if the current CPU vendor is an ARM vendor. - */ - public static boolean isARM() { - return OS_ARCH.getProperty().contains("arm") || OS_ARCH.getProperty().contains("aarch"); + /** + * Tests whether the current runtime environment is operating + * on a SparcV9 CPU, the typical 64-bit version of the Sparc CPU. + * + * @return true if the current runtime environment is running on a SparcV9. + * @see Cpu#isSparc() + */ + public static boolean isSparcV9() { + return JVM.getProperty().contains("sparcv9"); + } + + /** + * Tests whether the current runtime environment is operating + * on a PowerPc CPU, typically Ppc only means 32-bit. + * + * @return true if the current runtime environment is operating on a PPC. + * @see Cpu#isPpc64le() + */ + public static boolean isPpc() { + return JVM.getProperty().contains("ppc"); + } + + /** + * Tests whether the current runtime environment is operating + * on a PowerPc CPU, typically the 64-bit version with the little + * endian byte-order (i.e., le architecture). + * + * @return true if the current runtime environment is operating on a PPC-64-bit-le. + * @see Cpu#isPpc() + */ + public static boolean isPpc64le() { + return JVM.getProperty().contains("ppc64le"); + } + + /** + * Tests whether the current runtime environment is operating on an + * IBM System/390 CPU, typically plain s390 means the 32-bit version. + * + * @return true if the current runtime environment is operating on an IBM System/390. + * @see Cpu#isS390x() + */ + public static boolean isS390() { + return JVM.getProperty().contains("s390"); + } + + /** + * Tests whether the current runtime environment is operating on an + * IBM System/390 CPU, typically the 64-bit version. + * + * @return true if the current runtime environment is operating on an IBM System/390-64-bit. + * @see Cpu#isS390() + */ + public static boolean isS390x() { + return JVM.getProperty().contains("s390x"); + } + + /** + * Tests whether the current system architecture is a 64-bit chipset + * (NOT APPLICABLE TO ALL CPUs). + * + * @return true if the current OS architecture is a 64-bit chipset, false otherwise. + */ + public static boolean is64() { + return OS_ARCH.getProperty().contains("64"); + } + + /** + * Tests whether the current system architecture is of an x86 chipset, typically 32-bit intel chipsets. + * + * @return true if the current OS architecture is of an x86 chipset, false otherwise. + */ + public static boolean isX86() { + return OS_ARCH.getProperty().contains("x86") || OS_ARCH.getProperty().contains("i386"); + } + + /** + * Tests whether the current CPU vendor is an AMD vendor (e.g., x86_64 Intel Chipset). + * + * @return true if the current CPU vendor is an AMD vendor. + */ + public static boolean isAMD() { + return OS_ARCH.getProperty().contains("amd"); + } + + /** + * Tests whether the current CPU vendor is an ARM vendor (e.g., Broadcom Chipset). + * + * @return true if the current CPU vendor is an ARM vendor. + */ + public static boolean isARM() { + return OS_ARCH.getProperty().contains("arm") || OS_ARCH.getProperty().contains("aarch"); + } } /** From 19a11e5f9d3c12ac5c88d10ea3420708012e5198 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 16:16:16 -0400 Subject: [PATCH 25/55] PlatformPredicate: added more predicates and applied API changes --- .../platform/util/PlatformPredicate.java | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java index da2bc8f..1ba5b43 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java @@ -41,18 +41,24 @@ */ public final class PlatformPredicate { - public static final PlatformPredicate LINUX_X86 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isX86()); - public static final PlatformPredicate LINUX_X86_64 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isAMD() && NativeVariant.is64()); - public static final PlatformPredicate LINUX_ARM_32 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isARM()); - public static final PlatformPredicate LINUX_ARM_64 = new PlatformPredicate(NativeVariant.isLinux() && NativeVariant.isARM() && NativeVariant.is64()); - public static final PlatformPredicate MACOS_X86 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isX86()); - public static final PlatformPredicate MACOS_X86_64 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isAMD() && NativeVariant.is64()); - public static final PlatformPredicate MACOS_ARM_32 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isARM()); - public static final PlatformPredicate MACOS_ARM_64 = new PlatformPredicate(NativeVariant.isMac() && NativeVariant.isARM() && NativeVariant.is64()); - public static final PlatformPredicate WIN_X86 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isX86()); - public static final PlatformPredicate WIN_X86_64 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isAMD() && NativeVariant.is64()); - public static final PlatformPredicate WIN_ARM_32 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isARM()); - public static final PlatformPredicate WIN_ARM_64 = new PlatformPredicate(NativeVariant.isWindows() && NativeVariant.isARM() && NativeVariant.is64()); + public static final PlatformPredicate LINUX_X86 = new PlatformPredicate(NativeVariant.Os.isLinux() && NativeVariant.Cpu.isX86()); + public static final PlatformPredicate LINUX_X86_64 = new PlatformPredicate(NativeVariant.Os.isLinux() && NativeVariant.Cpu.isAMD() && NativeVariant.Cpu.is64()); + public static final PlatformPredicate LINUX_ARM_32 = new PlatformPredicate(NativeVariant.Os.isLinux() && NativeVariant.Cpu.isARM()); + public static final PlatformPredicate LINUX_ARM_64 = new PlatformPredicate(NativeVariant.Os.isLinux() && NativeVariant.Cpu.isARM() && NativeVariant.Cpu.is64()); + public static final PlatformPredicate LINUX_RISC_V_32 = new PlatformPredicate(NativeVariant.Os.isLinux() && NativeVariant.Cpu.isRiscV()); + public static final PlatformPredicate LINUX_RISC_V_64 = new PlatformPredicate(NativeVariant.Os.isLinux() && NativeVariant.Cpu.isRiscV() && NativeVariant.Cpu.is64()); + + public static final PlatformPredicate MACOS_X86 = new PlatformPredicate(NativeVariant.Os.isMac() && NativeVariant.Cpu.isX86()); + public static final PlatformPredicate MACOS_X86_64 = new PlatformPredicate(NativeVariant.Os.isMac() && NativeVariant.Cpu.isAMD() && NativeVariant.Cpu.is64()); + public static final PlatformPredicate MACOS_ARM_32 = new PlatformPredicate(NativeVariant.Os.isMac() && NativeVariant.Cpu.isARM()); + public static final PlatformPredicate MACOS_ARM_64 = new PlatformPredicate(NativeVariant.Os.isMac() && NativeVariant.Cpu.isARM() && NativeVariant.Cpu.is64()); + + public static final PlatformPredicate WIN_X86 = new PlatformPredicate(NativeVariant.Os.isWindows() && NativeVariant.Cpu.isX86()); + public static final PlatformPredicate WIN_X86_64 = new PlatformPredicate(NativeVariant.Os.isWindows() && NativeVariant.Cpu.isAMD() && NativeVariant.Cpu.is64()); + public static final PlatformPredicate WIN_ARM_32 = new PlatformPredicate(NativeVariant.Os.isWindows() && NativeVariant.Cpu.isARM()); + public static final PlatformPredicate WIN_ARM_64 = new PlatformPredicate(NativeVariant.Os.isWindows() && NativeVariant.Cpu.isARM() && NativeVariant.Cpu.is64()); + public static final PlatformPredicate WIN_RISC_V_32 = new PlatformPredicate(NativeVariant.Os.isWindows() && NativeVariant.Cpu.isRiscV()); + public static final PlatformPredicate WIN_RISC_V_64 = new PlatformPredicate(NativeVariant.Os.isWindows() && NativeVariant.Cpu.isRiscV()); private final boolean predicate; From c8dfcb01e20a7a7e6af28527a97e2143c88bad4e Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 16:16:43 -0400 Subject: [PATCH 26/55] Applied NativeVariant API changes --- .../java/electrostatic/snaploader/NativeBinaryLoader.java | 2 +- .../snaploader/platform/NativeDynamicLibrary.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java index 260ecba..97ec152 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java +++ b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java @@ -238,7 +238,7 @@ public SystemDetectionListener getSystemFoundListener() { protected void loadBinary(NativeDynamicLibrary library) throws IOException { try { /* sanity check for android java vm (the dalvik) */ - if (NativeVariant.isAndroid()) { + if (NativeVariant.Os.isAndroid()) { System.loadLibrary(libraryInfo.getBaseName()); return; } diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java b/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java index 624b891..3838cd9 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java @@ -100,9 +100,9 @@ public NativeDynamicLibrary(String platformDirectory, public void initWithLibraryInfo(LibraryInfo libraryInfo) { String ext = ".so"; - if (NativeVariant.isMac()) { + if (NativeVariant.Os.isMac()) { ext = ".dylib"; - } else if (NativeVariant.isWindows()) { + } else if (NativeVariant.Os.isWindows()) { ext = ".dll"; } From 60a46d4cefe146cb7d306ec46ab18b0691ed43fe Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 16:17:14 -0400 Subject: [PATCH 27/55] architecture: applied API changes --- architecture/architectural-paradigm.png | Bin 108940 -> 127742 bytes architecture/architectural-paradigm.puml | 6 +++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/architecture/architectural-paradigm.png b/architecture/architectural-paradigm.png index b72a89954c7ab84c4d395a3197911f9e4bb4f940..e71c299322372c055bddc7a7537e822377e87cb4 100644 GIT binary patch literal 127742 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 literal 108940 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 Yq31#`?U!@CApWhUtf`c__weQa1rlQa2mk;8 diff --git a/architecture/architectural-paradigm.puml b/architecture/architectural-paradigm.puml index a90e5d4..b21e306 100644 --- a/architecture/architectural-paradigm.puml +++ b/architecture/architectural-paradigm.puml @@ -4,7 +4,11 @@ 'Structural composition package platform { package util { - component NativeVariant { + component NativeVariant #22AADD { + component [Os] { + } + component [Cpu] { + } } component PropertiesProvider { } From 4fbede04d3e875bc546667c5b09f1c815b73a4e4 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 18:46:10 -0400 Subject: [PATCH 28/55] NativeVariant: fixed JavaDoc HTML errors --- .../electrostatic/snaploader/platform/util/NativeVariant.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java index 1d134f1..998fe91 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java @@ -35,7 +35,7 @@ /** * Wraps objects for native variant constituents (OS + ARCH={CPU + INSTRUCT_SET} + VM). * - *

    + *

      * Use the following list to build your platform predicates: *
    • x86: 32-bit x86 architecture
    • *
    • x86_64: 64-bit x86 architecture, often referred to as amd64
    • @@ -52,7 +52,7 @@ *
    • s390x: 64-bit IBM System/390 architecture
    • *
    • riscv32: 32-bit RISC-V architecture
    • *
    • riscv64: 64-bit RISC-V architecture
    • - *

      + *
    * * @author pavl_g */ From e110c626b6a836165ae74d20bd4ecc1e8b43da10 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 18:48:47 -0400 Subject: [PATCH 29/55] PlatformPredicate: added JavaDoc for predicate aliases --- .../platform/util/PlatformPredicate.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java index 1ba5b43..1fe831e 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java @@ -41,23 +41,84 @@ */ public final class PlatformPredicate { + /** + * Alias object for Linux on X86 Chipset. + */ public static final PlatformPredicate LINUX_X86 = new PlatformPredicate(NativeVariant.Os.isLinux() && NativeVariant.Cpu.isX86()); + + /** + * Alias object for Linux on X86-64 Chipset. + */ public static final PlatformPredicate LINUX_X86_64 = new PlatformPredicate(NativeVariant.Os.isLinux() && NativeVariant.Cpu.isAMD() && NativeVariant.Cpu.is64()); + + /** + * Alias object for Linux on arm-32 Chipset. + */ public static final PlatformPredicate LINUX_ARM_32 = new PlatformPredicate(NativeVariant.Os.isLinux() && NativeVariant.Cpu.isARM()); + + /** + * Alias object for Linux on arm-64 Chipset. + */ public static final PlatformPredicate LINUX_ARM_64 = new PlatformPredicate(NativeVariant.Os.isLinux() && NativeVariant.Cpu.isARM() && NativeVariant.Cpu.is64()); + + /** + * Alias object for Linux on RiscV-32 Chipset. + */ public static final PlatformPredicate LINUX_RISC_V_32 = new PlatformPredicate(NativeVariant.Os.isLinux() && NativeVariant.Cpu.isRiscV()); + + /** + * Alias object for Linux on RiscV-64 Chipset. + */ public static final PlatformPredicate LINUX_RISC_V_64 = new PlatformPredicate(NativeVariant.Os.isLinux() && NativeVariant.Cpu.isRiscV() && NativeVariant.Cpu.is64()); + /** + * Alias object for MacOSX on X86 Chipset. + */ public static final PlatformPredicate MACOS_X86 = new PlatformPredicate(NativeVariant.Os.isMac() && NativeVariant.Cpu.isX86()); + + /** + * Alias object for MacOSX on X86-64 Chipset. + */ public static final PlatformPredicate MACOS_X86_64 = new PlatformPredicate(NativeVariant.Os.isMac() && NativeVariant.Cpu.isAMD() && NativeVariant.Cpu.is64()); + + /** + * Alias object for MacOSX on arm-32 Chipset. + */ public static final PlatformPredicate MACOS_ARM_32 = new PlatformPredicate(NativeVariant.Os.isMac() && NativeVariant.Cpu.isARM()); + + /** + * Alias object for MacOSX on arm-64 Chipset. + */ public static final PlatformPredicate MACOS_ARM_64 = new PlatformPredicate(NativeVariant.Os.isMac() && NativeVariant.Cpu.isARM() && NativeVariant.Cpu.is64()); + /** + * Alias object for Windows on X86 Chipset. + */ public static final PlatformPredicate WIN_X86 = new PlatformPredicate(NativeVariant.Os.isWindows() && NativeVariant.Cpu.isX86()); + + /** + * Alias object for Windows on X86-64 Chipset. + */ public static final PlatformPredicate WIN_X86_64 = new PlatformPredicate(NativeVariant.Os.isWindows() && NativeVariant.Cpu.isAMD() && NativeVariant.Cpu.is64()); + + /** + * Alias object for Windows on arm-32 Chipset. + */ public static final PlatformPredicate WIN_ARM_32 = new PlatformPredicate(NativeVariant.Os.isWindows() && NativeVariant.Cpu.isARM()); + + /** + * Alias object for Windows on arm-64 Chipset. + */ public static final PlatformPredicate WIN_ARM_64 = new PlatformPredicate(NativeVariant.Os.isWindows() && NativeVariant.Cpu.isARM() && NativeVariant.Cpu.is64()); + + /** + * Alias object for Windows on RiscV-32 Chipset. + */ public static final PlatformPredicate WIN_RISC_V_32 = new PlatformPredicate(NativeVariant.Os.isWindows() && NativeVariant.Cpu.isRiscV()); + + /** + * Alias object for Windows on RiscV-64 Chipset. + */ public static final PlatformPredicate WIN_RISC_V_64 = new PlatformPredicate(NativeVariant.Os.isWindows() && NativeVariant.Cpu.isRiscV()); private final boolean predicate; From d962d3cbe2024509124beccbc594b32e8e359aa2 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 18:49:30 -0400 Subject: [PATCH 30/55] project-impl/variables.sh: migrated the groupId to electrostat-lab --- helper-scripts/project-impl/variables.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helper-scripts/project-impl/variables.sh b/helper-scripts/project-impl/variables.sh index 91b2229..d715278 100644 --- a/helper-scripts/project-impl/variables.sh +++ b/helper-scripts/project-impl/variables.sh @@ -4,7 +4,7 @@ # --------------------- sonatype_url="https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" repository="ossrh" -groupId="io.github.software-hardware-codesign" +groupId="io.github.electrostat-lab" maven_version="3.9.4" maven_bin="./apache-maven-$maven_version/bin/mvn" desktop_pomFile="./helper-scripts/project-impl/publishing/snaploader.pom" From 0c8d202b12dad56bfd049884cde7845e08f5ef20 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 18:54:15 -0400 Subject: [PATCH 31/55] NativeVariant: fixed text isnot allowed in
      tags --- .../electrostatic/snaploader/platform/util/NativeVariant.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java index 998fe91..8f4612d 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java @@ -35,8 +35,9 @@ /** * Wraps objects for native variant constituents (OS + ARCH={CPU + INSTRUCT_SET} + VM). * - *
        + *

        * Use the following list to build your platform predicates: + *

          *
        • x86: 32-bit x86 architecture
        • *
        • x86_64: 64-bit x86 architecture, often referred to as amd64
        • *
        • amd64: Another name for x86_64
        • From 866537bcbe1075d34154a0337c1fa0dfdac71728 Mon Sep 17 00:00:00 2001 From: pavl_g <60224159+Scrappers-glitch@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:09:15 -0400 Subject: [PATCH 32/55] build-deploy.yml: updated the maven-central repo URL --- .github/workflows/build-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml index d4d86f4..5ef8598 100644 --- a/.github/workflows/build-deploy.yml +++ b/.github/workflows/build-deploy.yml @@ -48,7 +48,7 @@ jobs: deploy: environment: name: maven-central - url: https://repo.maven.apache.org/maven2/io/github/software-hardware-codesign/ + url: https://repo.maven.apache.org/maven2/io/github/electrostat-lab runs-on: ${{ matrix.os }} needs: [compile-assemble] strategy: From 7ee6ba5c3f3f2c1650bebb9b7a8c22b59da299dc Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 22:25:44 -0400 Subject: [PATCH 33/55] LibraryInfo: more constructors for easier implementation --- .../electrostatic/snaploader/LibraryInfo.java | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java b/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java index 411853b..97e86db 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java +++ b/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java @@ -46,13 +46,51 @@ public final class LibraryInfo { private String baseName; private String extractionDir; + /** + * Instantiates a library info object with a basename, + * together with the current classpath, the platform directory + * as the path to locate the native library, and the current + * working directory as an extraction path. + * + * @param baseName the library basename without the extension + */ + public LibraryInfo(String baseName) { + this(null, null, baseName, null); + } + + /** + * Instantiates a library info object with a basename, + * together with the current classpath, the platform directory + * as the path to locate the native library, and a custom + * user extraction path. + * + * @param baseName the library basename without the extension + * @param extractionDir the path to a user-defined extraction directory + */ + public LibraryInfo(String baseName, String extractionDir) { + this(null, null, baseName, extractionDir); + } + + /** + * Instantiates a library info object with a basename, + * together with the current classpath, a user-defined platform-independent + * directory, and a custom user extraction path. + * + * @param directory the directory path to the binary inside the Jar file + * @param baseName the library basename without the extension + * @param extractionDir the path to a user-defined extraction directory + */ + public LibraryInfo(String directory, String baseName, String extractionDir) { + this(null, directory, baseName, extractionDir); + } + /** * Instantiates a library info data structure pointing to a library in an external jar with jarPath. * * @param jarPath a path to an external jar to locate the library inside, "null" to use the project jar (classpath). * @param directory the directory inside the compression used for locating the native dynamic library, "null" to use * the default directory defined by {@link NativeDynamicLibrary}. - * @param baseName the library basename, for example: 'lib-basename.so'. + * @param baseName the library basename, for example, 'lib-basename.so'. * @param extractionDir the extraction destination in absolute string format, "null" if the current [user.dir] is * specified as the extraction directory */ From efe93e390d752479525b02806936179d0b00c8f6 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 22:28:40 -0400 Subject: [PATCH 34/55] snaploader/build.gradle: compiler-options release for earlier Java versions downto 8 --- snaploader/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/snaploader/build.gradle b/snaploader/build.gradle index 5ec0a05..3be1ac0 100644 --- a/snaploader/build.gradle +++ b/snaploader/build.gradle @@ -13,6 +13,10 @@ tasks.register("generateSourcesJar", Jar) { from sourceSets.main.allSource } +tasks.withType(JavaCompile) { + options.release = 8 +} + jar { // assemble jar options [java -jar] manifest { attributes 'Project': "jSnaploader", From 71826e921e5df98f610dde1a3f4e753b97f837b9 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 22:48:26 -0400 Subject: [PATCH 35/55] NativeBinaryLoader: use Arrays.asList() instead of List.of() --- .../main/java/electrostatic/snaploader/NativeBinaryLoader.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java index 97ec152..b4590dd 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java +++ b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java @@ -33,6 +33,7 @@ package electrostatic.snaploader; import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -101,7 +102,7 @@ public NativeBinaryLoader(final List registeredLibraries, } public NativeBinaryLoader registerNativeLibraries(NativeDynamicLibrary[] nativeDynamicLibraries) { - this.registeredLibraries = List.of(nativeDynamicLibraries); + this.registeredLibraries = Arrays.asList(nativeDynamicLibraries); return this; } From e9a2534ac886d5ab1493d018e633aacc51a7c564 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 22:58:36 -0400 Subject: [PATCH 36/55] UnSupportedSystemError: better text formatting --- .../snaploader/UnSupportedSystemError.java | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java b/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java index a30531c..51ffa4a 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java +++ b/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java @@ -33,17 +33,10 @@ package electrostatic.snaploader; /** - * A business error of type {@link UnsatisfiedLinkError} to indicate an un-supported system. - * + * A business error of type {@link UnsatisfiedLinkError} to indicate an unsupported system. *

          - * This error is thrown when the user tries to run the library on another operating system rather than the supported systems: - *

            - *
          • Linux - x86 - x86_64
          • - *
          • Windows - x86 - x86_64
          • - *
          • Mac - x86 - x86_64
          • - *
          • Android - intel32 - intel64 - arm32 - arm64
          • - *
          - * + * This error is thrown when all the user-defined platform predicates are not met! + * * @author pavl_g */ public class UnSupportedSystemError extends UnsatisfiedLinkError { @@ -55,6 +48,6 @@ public class UnSupportedSystemError extends UnsatisfiedLinkError { * @param arch the current operating system (os) processor architecture */ public UnSupportedSystemError(final String os, final String arch) { - super("System " + os + "_" + arch + " isn't supported yet !"); + super("Platform of OS(" + os + ") and ARCH(" + arch + ") isn't supported yet!"); } } From d578fdf4abe31a859cbba8a37a04e32e5d442e68 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 23:02:46 -0400 Subject: [PATCH 37/55] PlatformPredicate.MACOS_X86_64: fixed CPU proposition --- .../snaploader/platform/util/PlatformPredicate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java index 1fe831e..d2ad188 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java @@ -79,7 +79,7 @@ public final class PlatformPredicate { /** * Alias object for MacOSX on X86-64 Chipset. */ - public static final PlatformPredicate MACOS_X86_64 = new PlatformPredicate(NativeVariant.Os.isMac() && NativeVariant.Cpu.isAMD() && NativeVariant.Cpu.is64()); + public static final PlatformPredicate MACOS_X86_64 = new PlatformPredicate(NativeVariant.Os.isMac() && NativeVariant.Cpu.isX86() && NativeVariant.Cpu.is64()); /** * Alias object for MacOSX on arm-32 Chipset. From 616d81484d1f0b3ee737500d8189526b3451279e Mon Sep 17 00:00:00 2001 From: pavl_g Date: Thu, 25 Jul 2024 23:07:38 -0400 Subject: [PATCH 38/55] abstract-sonatype-publish.sh: updated the POM XML file --- .../abstract/abstract-sonatype-publish.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/helper-scripts/abstract/abstract-sonatype-publish.sh b/helper-scripts/abstract/abstract-sonatype-publish.sh index a21048e..21b758a 100644 --- a/helper-scripts/abstract/abstract-sonatype-publish.sh +++ b/helper-scripts/abstract/abstract-sonatype-publish.sh @@ -14,25 +14,25 @@ function generateGenericPom() { jSnapLoader API \ jar \ A high-performance cross-platform dynamic library loader API for JVM Applications with file locator and file extractor interfaces. \ - https://github.com/Software-Hardware-Codesign/jSnapLoader \ + https://github.com/Electrostat-Lab/jSnapLoader \ \ \ - The AvrSandbox Project, jSnapLoader BSD-3 Clause License \ - https://github.com/Software-Hardware-Codesign/jSnapLoader/blob/master/LICENSE \ + The Electrostatic-Sandbox Distributed Simulation Project, jSnapLoader BSD-3 Clause License \ + https://github.com/Electrostat-Lab/jSnapLoader/blob/master/LICENSE \ \ \ \ \ Pavly Gerges aka. pavl_g \ pepogerges33@gmail.com \ - AvrSandbox Project \ - https://github.com/Software-Hardware-Codesign \ + Electrostat-Lab \ + https://github.com/Electrostat-Lab \ \ \ \ - scm:git://github.com/Software-Hardware-Codesign/jSnapLoader.git \ - scm:git:ssh://github.com/Software-Hardware-Codesign/jSnapLoader.git \ - https://github.com/Software-Hardware-Codesign/jSnapLoader/tree/master \ + scm:git://github.com/Electrostat-Lab/jSnapLoader.git \ + scm:git:ssh://github.com/Electrostat-Lab/jSnapLoader.git \ + https://github.com/Electrostat-Lab/jSnapLoader/tree/master \ \ \ " From ff45bff9ed92954e9481944da8de7f120de2e8c8 Mon Sep 17 00:00:00 2001 From: pavl_g <60224159+Scrappers-glitch@users.noreply.github.com> Date: Fri, 26 Jul 2024 07:06:57 -0400 Subject: [PATCH 39/55] build-test.yml: added matrix oracle JDKs for testing --- .github/workflows/build-test.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 75a67f2..073bfc8 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -20,6 +20,7 @@ jobs: strategy: matrix: os: [ 'ubuntu-latest' ] + jdk: ['8', '17', '20'] name: Build jSnapLoader # Steps represent a sequence of tasks that will be executed as part of the job @@ -27,11 +28,11 @@ jobs: - name: Checkout Job uses: actions/checkout@v3 - - name: Setup Temurin-JDK-19 + - name: Setup Oracle JDK uses: actions/setup-java@v3 with: - distribution: 'temurin' - java-version: '19' + distribution: 'oracle' + java-version: '20' - name: Compiling java run: ./gradlew --console="verbose" :snaploader:build @@ -55,11 +56,11 @@ jobs: - name: Checkout Job uses: actions/checkout@v3 - - name: Setup Oracle-JDK-19 + - name: Setup Oracle JDK uses: actions/setup-java@v3 with: - distribution: 'temurin' - java-version: '19' + distribution: 'oracle' + java-version: '20' - name: Generate javadoc run: chmod +rwx ./gradlew && ./gradlew :snaploader:generateJavadocJar @@ -79,11 +80,11 @@ jobs: - name: Checkout Job uses: actions/checkout@v3 - - name: Setup Temurin-JDK-19 + - name: Setup Oracle JDK uses: actions/setup-java@v3 with: - distribution: 'temurin' - java-version: '19' + distribution: 'oracle' + java-version: ${{ matrix.jdk }} - name: Download snaploader-SNAPSHOT.jar library uses: actions/download-artifact@v3 From 6a1e31457048b5ced3fcd2354e924db7c653760e Mon Sep 17 00:00:00 2001 From: pavl_g <60224159+Scrappers-glitch@users.noreply.github.com> Date: Fri, 26 Jul 2024 07:16:23 -0400 Subject: [PATCH 40/55] Update build-test.yml --- .github/workflows/build-test.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 073bfc8..5d403c5 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -16,11 +16,7 @@ on: jobs: build-snaploader: # runner images with architectures (variants) - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ 'ubuntu-latest' ] - jdk: ['8', '17', '20'] + runs-on: 'ubuntu-latest' name: Build jSnapLoader # Steps represent a sequence of tasks that will be executed as part of the job @@ -32,7 +28,7 @@ jobs: uses: actions/setup-java@v3 with: distribution: 'oracle' - java-version: '20' + java-version: '19' - name: Compiling java run: ./gradlew --console="verbose" :snaploader:build @@ -69,11 +65,12 @@ jobs: # runner images with architectures (variants) runs-on: ${{ matrix.os }} needs: build-snaploader + name: Testing snaploader on ${{ matrix.os }} strategy: matrix: os: [ 'ubuntu-latest', 'windows-latest' ] - architecture: [x86_64] - name: Testing snaploader on ${{ matrix.os }} for x86-64 + jdk: ['8', '17', '20'] + architecture: ['x86_64'] # Steps represent a sequence of tasks that will be executed as part of the job steps: From d947c4d14387f2a816e6c10f8539c56cf6a92707 Mon Sep 17 00:00:00 2001 From: pavl_g <60224159+Scrappers-glitch@users.noreply.github.com> Date: Fri, 26 Jul 2024 07:22:26 -0400 Subject: [PATCH 41/55] Update build-test.yml --- .github/workflows/build-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 5d403c5..ca173fd 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -69,7 +69,7 @@ jobs: strategy: matrix: os: [ 'ubuntu-latest', 'windows-latest' ] - jdk: ['8', '17', '20'] + jdk: ['17', '20'] architecture: ['x86_64'] # Steps represent a sequence of tasks that will be executed as part of the job From e19f554b2a7d8966944dce1e42cdf3782fa710da Mon Sep 17 00:00:00 2001 From: pavl_g <60224159+Scrappers-glitch@users.noreply.github.com> Date: Fri, 26 Jul 2024 07:32:36 -0400 Subject: [PATCH 42/55] build-test.yml: fallback to Java-19 --- .github/workflows/build-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index ca173fd..4dfe637 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -56,7 +56,7 @@ jobs: uses: actions/setup-java@v3 with: distribution: 'oracle' - java-version: '20' + java-version: '19' - name: Generate javadoc run: chmod +rwx ./gradlew && ./gradlew :snaploader:generateJavadocJar @@ -69,7 +69,7 @@ jobs: strategy: matrix: os: [ 'ubuntu-latest', 'windows-latest' ] - jdk: ['17', '20'] + jdk: ['17', '19'] architecture: ['x86_64'] # Steps represent a sequence of tasks that will be executed as part of the job From a90022d25beec14a4104a025f2275b199f14ed51 Mon Sep 17 00:00:00 2001 From: pavl_g <60224159+Scrappers-glitch@users.noreply.github.com> Date: Fri, 26 Jul 2024 07:42:47 -0400 Subject: [PATCH 43/55] Update build-test.yml --- .github/workflows/build-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 4dfe637..7cff196 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -65,7 +65,7 @@ jobs: # runner images with architectures (variants) runs-on: ${{ matrix.os }} needs: build-snaploader - name: Testing snaploader on ${{ matrix.os }} + name: Testing snaploader on ${{ matrix.os }}-${{ matrix.jdk }} strategy: matrix: os: [ 'ubuntu-latest', 'windows-latest' ] From 8c1cfcdffa70b150dbdd7ca31c83a56fd4522b76 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Fri, 26 Jul 2024 08:21:03 -0400 Subject: [PATCH 44/55] Added FileLocalizingListener to bind user apps with the file localizing interface --- .../filesystem/FileLocalizingListener.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocalizingListener.java diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocalizingListener.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocalizingListener.java new file mode 100644 index 0000000..2f13bc8 --- /dev/null +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocalizingListener.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023-2024, 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 electrostatic.snaploader.filesystem; + +/** + * Provides executable functions by the {@link FileLocator#validateFileLocalization()} + * to enable the binding of user applications with the file locator interface. + * + * @author pavl_g + * @see FileLocator#validateFileLocalization() + * @see FileExtractor#extract() + */ +public interface FileLocalizingListener { + + /** + * Dispatched whenever the file input stream is valid, hence the specified + * file can be localized. + * + * @param locator the associated file locator object. + * @see FileLocator#validateFileLocalization() + */ + void onFileLocalizationSuccess(FileLocator locator); + + /** + * Dispatched whenever the file input stream is invalid, hence the specified + * file cannot be localized for the extraction process. + * + * @param locator the associated file locator object. + * @param throwable the throwable object, typically indicating a failure + * to locate the file inside the compression. + */ + void onFileLocalizationFailure(FileLocator locator, Throwable throwable); +} From 3e71ec46b32a16cc4085cbccdbacd69850c09f13 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Fri, 26 Jul 2024 08:22:40 -0400 Subject: [PATCH 45/55] InputStreamProvider: integrated the FileLocalizingListener as an assembly relationship --- .../snaploader/filesystem/InputStreamProvider.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java index 505c406..a6d3206 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java @@ -48,4 +48,12 @@ public interface InputStreamProvider extends AutoCloseable { * @return an input stream object for this located filesystem */ InputStream getFileInputStream(); + + /** + * Sets the file localizing listener interface object to bind the user application + * to the file localizing lifecycle. + * + * @param fileLocalizingListener an implementation object of the file localizing listener + */ + void setFileLocalizingListener(FileLocalizingListener fileLocalizingListener); } From 389660dc359fb49df094f70caf8bf7bac760a275 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Fri, 26 Jul 2024 08:23:20 -0400 Subject: [PATCH 46/55] FileLocator: integrated the FileLocalizingListener as an assembly relationship --- .../snaploader/filesystem/FileLocator.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java index 3136ee1..b685e02 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java @@ -32,6 +32,7 @@ package electrostatic.snaploader.filesystem; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.zip.ZipEntry; @@ -50,6 +51,12 @@ public class FileLocator implements InputStreamProvider { */ protected InputStream fileInputStream; + /** + * An interface object to provide the file-localizing process with a command-state pattern; + * binding the user application interface with the file localizing lifecycle. + */ + protected FileLocalizingListener fileLocalizingListener; + /** * Locates a filesystem inside an external zip compression, the zip filesystem is defined as a {@link ZipFile} object and * the locatable filesystem is defined as a {@link ZipEntry} object. @@ -75,6 +82,28 @@ public FileLocator(String directory, String filePath, ZipCompressionType compres protected FileLocator() { } + /** + * Validates the file localization process inside the compression. + * + * @throws FileNotFoundException if the localization of the file inside + * the specified compression has failed. + */ + public void validateFileLocalization() throws FileNotFoundException { + if (fileInputStream != null) { + if (fileLocalizingListener != null) { + fileLocalizingListener.onFileLocalizationSuccess(this); + } + } else { + final FileNotFoundException fileNotFoundException = + new FileNotFoundException("File locator has failed to locate the file inside the compression!"); + + if (fileLocalizingListener != null) { + fileLocalizingListener.onFileLocalizationFailure(this, fileNotFoundException); + } + throw fileNotFoundException; + } + } + @Override public InputStream getFileInputStream() { return fileInputStream; @@ -85,4 +114,9 @@ public void close() throws IOException { fileInputStream.close(); fileInputStream = null; } + + @Override + public void setFileLocalizingListener(FileLocalizingListener fileLocalizingListener) { + this.fileLocalizingListener = fileLocalizingListener; + } } From 49e8c8ebf9b7dae6ed0d4229357a1a6365e3d450 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Fri, 26 Jul 2024 08:25:51 -0400 Subject: [PATCH 47/55] FileExtractor#extract(): better validation of the file streams from the file locator --- .../filesystem/ConcurrentFileExtractor.java | 2 +- .../snaploader/filesystem/FileExtractor.java | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/ConcurrentFileExtractor.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ConcurrentFileExtractor.java index 5aab36c..846eb02 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/ConcurrentFileExtractor.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ConcurrentFileExtractor.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java index 23f9c6b..274545b 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java @@ -87,10 +87,17 @@ protected FileExtractor() { /** * Commands and Extract the specified filesystem to the specified destination filesystem. - * - * @throws IOException if the input/output streams has failed or an interrupted I/O operation has occured + *

          + * Warning: this function leaks buffered streams; this vision was attained for freedom of use, + * but the user application must keep in mind that stream closure and resources release must be + * attained either through the extraction completed and failure listeners, or through a try-with + * resources. + * + * @throws IOException if the input/output streams has failed or an interrupted I/O operation has occurred. + * @throws FileNotFoundException if the file locator has failed to locate the file inside the compression + * for the extraction process. */ - public void extract() throws IOException { + public void extract() throws IOException, FileNotFoundException { try { /* uses buffered streams */ /* buffered byte streams provide a constant memory allocation @@ -100,9 +107,13 @@ public void extract() throws IOException { * unlike the unbuffered streams, which polls byte streams from an online * pipe, and allocate memory according to the active bytes manipulated * by the pipeline. */ + fileLocator.validateFileLocalization(); InputStream libraryStream = fileLocator.getFileInputStream(); + /* Extracts the shipped native files */ + /* Allocate a byte buffer for the buffered streams */ final byte[] buffer = new byte[libraryStream.available()]; + for (int bytes = 0; bytes != EOF; bytes = libraryStream.read(buffer)) { /* use the bytes as the buffer length to write valid data */ fileOutputStream.write(buffer, 0, bytes); From e28e1abaefafaeb4246624001ff27e79fdb8b611 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Fri, 26 Jul 2024 08:26:54 -0400 Subject: [PATCH 48/55] FileExtractor: renamed libraryStream to fileStream for generic uses --- .../electrostatic/snaploader/filesystem/FileExtractor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java index 274545b..d6111fc 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java @@ -108,13 +108,13 @@ public void extract() throws IOException, FileNotFoundException { * pipe, and allocate memory according to the active bytes manipulated * by the pipeline. */ fileLocator.validateFileLocalization(); - InputStream libraryStream = fileLocator.getFileInputStream(); + InputStream fileStream = fileLocator.getFileInputStream(); /* Extracts the shipped native files */ /* Allocate a byte buffer for the buffered streams */ - final byte[] buffer = new byte[libraryStream.available()]; + final byte[] buffer = new byte[fileStream.available()]; - for (int bytes = 0; bytes != EOF; bytes = libraryStream.read(buffer)) { + for (int bytes = 0; bytes != EOF; bytes = fileStream.read(buffer)) { /* use the bytes as the buffer length to write valid data */ fileOutputStream.write(buffer, 0, bytes); } From f787402d8e54529e43ab7da361ad78b3a3d93c24 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Fri, 26 Jul 2024 08:29:46 -0400 Subject: [PATCH 49/55] snaploader-license: replaced AvrSandbox with Electrostatic-Sandbox --- .../electrostatic/snaploader/ConcurrentNativeBinaryLoader.java | 2 +- .../src/main/java/electrostatic/snaploader/LibraryInfo.java | 2 +- .../main/java/electrostatic/snaploader/LoadingCriterion.java | 2 +- .../main/java/electrostatic/snaploader/NativeBinaryLoader.java | 2 +- .../electrostatic/snaploader/NativeBinaryLoadingListener.java | 2 +- .../java/electrostatic/snaploader/SystemDetectionListener.java | 2 +- .../java/electrostatic/snaploader/UnSupportedSystemError.java | 2 +- .../electrostatic/snaploader/filesystem/ExtractionListener.java | 2 +- .../java/electrostatic/snaploader/filesystem/FileExtractor.java | 2 +- .../java/electrostatic/snaploader/filesystem/FileLocator.java | 2 +- .../snaploader/filesystem/InputStreamProvider.java | 2 +- .../snaploader/filesystem/OutputStreamProvider.java | 2 +- .../electrostatic/snaploader/filesystem/ZipCompressionType.java | 2 +- .../java/electrostatic/snaploader/filesystem/package-info.java | 2 +- .../java/electrostatic/snaploader/library/LibraryExtractor.java | 2 +- .../java/electrostatic/snaploader/library/LibraryLocator.java | 2 +- .../java/electrostatic/snaploader/library/package-info.java | 2 +- .../src/main/java/electrostatic/snaploader/package-info.java | 2 +- .../electrostatic/snaploader/platform/NativeDynamicLibrary.java | 2 +- .../java/electrostatic/snaploader/platform/package-info.java | 2 +- .../snaploader/platform/util/DefaultDynamicLibraries.java | 2 +- .../electrostatic/snaploader/platform/util/NativeVariant.java | 2 +- .../snaploader/platform/util/PlatformPredicate.java | 2 +- .../snaploader/platform/util/PropertiesProvider.java | 2 +- .../electrostatic/snaploader/platform/util/package-info.java | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/ConcurrentNativeBinaryLoader.java b/snaploader/src/main/java/electrostatic/snaploader/ConcurrentNativeBinaryLoader.java index 38059bd..6036e8b 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/ConcurrentNativeBinaryLoader.java +++ b/snaploader/src/main/java/electrostatic/snaploader/ConcurrentNativeBinaryLoader.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java b/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java index 97e86db..c8fb0be 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java +++ b/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/LoadingCriterion.java b/snaploader/src/main/java/electrostatic/snaploader/LoadingCriterion.java index 534ce58..88b9a41 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/LoadingCriterion.java +++ b/snaploader/src/main/java/electrostatic/snaploader/LoadingCriterion.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java index b4590dd..dc053ec 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java +++ b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoader.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoadingListener.java b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoadingListener.java index 18045f5..992c995 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoadingListener.java +++ b/snaploader/src/main/java/electrostatic/snaploader/NativeBinaryLoadingListener.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/SystemDetectionListener.java b/snaploader/src/main/java/electrostatic/snaploader/SystemDetectionListener.java index 380dd45..95d64bf 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/SystemDetectionListener.java +++ b/snaploader/src/main/java/electrostatic/snaploader/SystemDetectionListener.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java b/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java index 51ffa4a..4bccc5b 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java +++ b/snaploader/src/main/java/electrostatic/snaploader/UnSupportedSystemError.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/ExtractionListener.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ExtractionListener.java index e8170df..d72c477 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/ExtractionListener.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ExtractionListener.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java index d6111fc..9b41737 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileExtractor.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java index b685e02..dd45372 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/FileLocator.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java index a6d3206..e5dcd78 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/InputStreamProvider.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/OutputStreamProvider.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/OutputStreamProvider.java index 73cc01e..40441d2 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/OutputStreamProvider.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/OutputStreamProvider.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/ZipCompressionType.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ZipCompressionType.java index dc2e08e..8ad422d 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/ZipCompressionType.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/ZipCompressionType.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/filesystem/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/filesystem/package-info.java index bcd03d6..c3301e0 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/filesystem/package-info.java +++ b/snaploader/src/main/java/electrostatic/snaploader/filesystem/package-info.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/library/LibraryExtractor.java b/snaploader/src/main/java/electrostatic/snaploader/library/LibraryExtractor.java index a30d005..88f24e9 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/library/LibraryExtractor.java +++ b/snaploader/src/main/java/electrostatic/snaploader/library/LibraryExtractor.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/library/LibraryLocator.java b/snaploader/src/main/java/electrostatic/snaploader/library/LibraryLocator.java index f2097ff..1a71580 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/library/LibraryLocator.java +++ b/snaploader/src/main/java/electrostatic/snaploader/library/LibraryLocator.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/library/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/library/package-info.java index 077472a..bf2f195 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/library/package-info.java +++ b/snaploader/src/main/java/electrostatic/snaploader/library/package-info.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/package-info.java index 670a319..21d25d4 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/package-info.java +++ b/snaploader/src/main/java/electrostatic/snaploader/package-info.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java b/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java index 3838cd9..c807512 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/platform/package-info.java index 862fcae..97748eb 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/package-info.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/package-info.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/DefaultDynamicLibraries.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/DefaultDynamicLibraries.java index 684a740..c7a7b6d 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/DefaultDynamicLibraries.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/DefaultDynamicLibraries.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java index 8f4612d..ac27eaf 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/NativeVariant.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java index d2ad188..922d7f4 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PlatformPredicate.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PropertiesProvider.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PropertiesProvider.java index a409b52..ea135b4 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/PropertiesProvider.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/PropertiesProvider.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/util/package-info.java b/snaploader/src/main/java/electrostatic/snaploader/platform/util/package-info.java index 7c553ea..90c82d8 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/util/package-info.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/util/package-info.java @@ -13,7 +13,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * * Neither the name of 'AvrSandbox' nor the names of its contributors + * * 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. * From 22c0658ba3985ef2b97a4cfc06b42ac0beb618a4 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Fri, 26 Jul 2024 15:29:06 -0400 Subject: [PATCH 50/55] NativeDynamicLibrary.: allows for a full directory designation and Win-OS library names standardizations --- .../platform/NativeDynamicLibrary.java | 64 +++++++++++++------ 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java b/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java index c807512..7f6b965 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java +++ b/snaploader/src/main/java/electrostatic/snaploader/platform/NativeDynamicLibrary.java @@ -57,13 +57,13 @@ public class NativeDynamicLibrary { /** * The library path inside the compression (i.e., Jar file). */ - protected String libraryDirectory; + protected String platformDirectory; /** * A designator for the library name with the platform extension * (basename + extension). */ - protected String library; + protected String libraryFile; /** * A designator for the extraction directory of the @@ -79,6 +79,22 @@ public class NativeDynamicLibrary { */ protected PlatformPredicate platformPredicate; + /** + * Creates a Native dynamic library from a relative directory and a library filesystem. + * + * @param platformDirectory the library directory inside the jar compression, "null" for the default library directory. + * @param libraryFile the full library name including the platform extension which if assigned + * as "null", it will make the loader rely on the library info to obtain + * the full library name. + * @param platformPredicate the predicate to test against; that if evaluated as true, the native library will be selected + * to be loaded by the native loader + */ + public NativeDynamicLibrary(String platformDirectory, String libraryFile, + PlatformPredicate platformPredicate) { + this(platformDirectory, platformPredicate); + this.libraryFile = libraryFile; + } + /** * Creates a Native dynamic library from a relative directory and a library filesystem. * @@ -88,7 +104,7 @@ public class NativeDynamicLibrary { */ public NativeDynamicLibrary(String platformDirectory, PlatformPredicate platformPredicate) { - this.libraryDirectory = platformDirectory; + this.platformDirectory = platformDirectory; this.platformPredicate = platformPredicate; } @@ -98,17 +114,23 @@ public NativeDynamicLibrary(String platformDirectory, * @param libraryInfo wraps abstract data representing the native library */ public void initWithLibraryInfo(LibraryInfo libraryInfo) { - String ext = ".so"; - - if (NativeVariant.Os.isMac()) { - ext = ".dylib"; - } else if (NativeVariant.Os.isWindows()) { - ext = ".dll"; - } - /* Initializes the library basename */ - if (libraryInfo.getBaseName() != null) { - library = "lib" + libraryInfo.getBaseName() + ext; + /* Initializes the library file if it's not initialized by the user */ + if (libraryFile == null) { + // default values for library prefix + // and library extensions + String libraryPrefix = "lib"; + String libraryExtension = ".so"; + + // reassign according to the operating system environment + if (NativeVariant.Os.isMac()) { + libraryExtension = ".dylib"; + } else if (NativeVariant.Os.isWindows()) { + libraryExtension = ".dll"; + libraryPrefix = ""; // selectively remove the prefixed value on Windows + } + + libraryFile = libraryPrefix + libraryInfo.getBaseName() + libraryExtension; } /* Initializes the library jar path to locate before extracting, "null" to use the classpath */ @@ -117,9 +139,9 @@ public void initWithLibraryInfo(LibraryInfo libraryInfo) { /* Initializes the library with an extraction path, "null" to extract to the current user directory */ extractionDir = libraryInfo.getExtractionDir(); - /* Initializes the library directory within the jar, "null" for the default library directory */ - if (libraryInfo.getDirectory() != null) { - libraryDirectory = libraryInfo.getDirectory(); + /* Fallback initializes the library directory within the jar from the library-info */ + if (platformDirectory == null) { + platformDirectory = libraryInfo.getDirectory(); } } @@ -137,8 +159,8 @@ public String getJarPath() { * * @return a string representing the location of the native dynamic library to be loaded */ - public String getLibraryDirectory() { - return libraryDirectory; + public String getPlatformDirectory() { + return platformDirectory; } /** @@ -147,7 +169,7 @@ public String getLibraryDirectory() { * @return a string representing the library path within the jar compression */ public String getCompressedLibrary() { - return libraryDirectory + PropertiesProvider.ZIP_FILE_SEPARATOR.getSystemProperty() + library; + return platformDirectory + PropertiesProvider.ZIP_FILE_SEPARATOR.getSystemProperty() + libraryFile; } /** @@ -157,10 +179,10 @@ public String getCompressedLibrary() { */ public String getExtractedLibrary() { if (extractionDir != null) { - return extractionDir + PropertiesProvider.FILE_SEPARATOR.getSystemProperty() + library; + return extractionDir + PropertiesProvider.FILE_SEPARATOR.getSystemProperty() + libraryFile; } return PropertiesProvider.USER_DIR.getSystemProperty() + - PropertiesProvider.FILE_SEPARATOR.getSystemProperty() + library; + PropertiesProvider.FILE_SEPARATOR.getSystemProperty() + libraryFile; } /** From 531381c24ad1c59e97e505f8788fdee0628260f5 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Fri, 26 Jul 2024 15:29:47 -0400 Subject: [PATCH 51/55] LibraryInfo.: documentation and code enhances --- .../electrostatic/snaploader/LibraryInfo.java | 65 +++++++++---------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java b/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java index c8fb0be..a1c30ff 100644 --- a/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java +++ b/snaploader/src/main/java/electrostatic/snaploader/LibraryInfo.java @@ -35,8 +35,26 @@ import electrostatic.snaploader.platform.NativeDynamicLibrary; /** - * Provides a library placeholder with an adjustable baseName {@link LibraryInfo#baseName}. - * + * Provides a platform-independent library placeholder with an adjustable baseName {@link LibraryInfo#baseName} + * grouping the common components among all platforms. + *

          + * Understand the API vision: + * The native dynamic API is composed of {@link NativeDynamicLibrary} which represents the + * platform-dependent entity and the {@link LibraryInfo} which represents the abstract + * platform-independent entity; the common components among them represent a backup + * on the LibraryInfo side that the API will fall back to in case the platform directory + * path is invalid. + *

          + *

            + *
          • ------------------------------ + *
          • (2).Abstract: LibraryInfo (Grouping common components among all platforms; thus platform-independent). + *
          • ------------------------------ + *
          • (1).Concrete: NativeDynamicLibrary (Grouping platform-dependent components). + *
          • ------------------------------ + *
          + *

          + * where (1).(2) designates the runtime order. + * * @author pavl_g */ public final class LibraryInfo { @@ -47,38 +65,14 @@ public final class LibraryInfo { private String extractionDir; /** - * Instantiates a library info object with a basename, - * together with the current classpath, the platform directory - * as the path to locate the native library, and the current - * working directory as an extraction path. + * Instantiates a library info data structure pointing to a library in the classpath. * - * @param baseName the library basename without the extension - */ - public LibraryInfo(String baseName) { - this(null, null, baseName, null); - } - - /** - * Instantiates a library info object with a basename, - * together with the current classpath, the platform directory - * as the path to locate the native library, and a custom - * user extraction path. - * - * @param baseName the library basename without the extension - * @param extractionDir the path to a user-defined extraction directory - */ - public LibraryInfo(String baseName, String extractionDir) { - this(null, null, baseName, extractionDir); - } - - /** - * Instantiates a library info object with a basename, - * together with the current classpath, a user-defined platform-independent - * directory, and a custom user extraction path. - * - * @param directory the directory path to the binary inside the Jar file - * @param baseName the library basename without the extension - * @param extractionDir the path to a user-defined extraction directory + * @param directory the platform-independent directory inside the compression used for locating the native dynamic library, + * this is used as a backup directory path + * in case the {@link NativeDynamicLibrary#getPlatformDirectory()} is not valid. + * @param baseName the library basename, for example, 'lib-basename.so'. + * @param extractionDir the extraction destination in absolute string format, "null" if the current [user.dir] is + * specified as the extraction directory */ public LibraryInfo(String directory, String baseName, String extractionDir) { this(null, directory, baseName, extractionDir); @@ -88,8 +82,9 @@ public LibraryInfo(String directory, String baseName, String extractionDir) { * Instantiates a library info data structure pointing to a library in an external jar with jarPath. * * @param jarPath a path to an external jar to locate the library inside, "null" to use the project jar (classpath). - * @param directory the directory inside the compression used for locating the native dynamic library, "null" to use - * the default directory defined by {@link NativeDynamicLibrary}. + * @param directory the platform-independent directory inside the compression used for locating the native dynamic library, + * this is used as a backup directory path + * in case the {@link NativeDynamicLibrary#getPlatformDirectory()} is not valid. * @param baseName the library basename, for example, 'lib-basename.so'. * @param extractionDir the extraction destination in absolute string format, "null" if the current [user.dir] is * specified as the extraction directory From e41a04e31f5fd253ae5eabdb7d56e440f1510134 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Fri, 26 Jul 2024 15:30:12 -0400 Subject: [PATCH 52/55] TestBasicFeatures: applied API changes for testing --- .../snaploader/examples/TestBasicFeatures.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java index 9cdd9f2..c706cfd 100644 --- a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java +++ b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java @@ -39,6 +39,7 @@ import electrostatic.snaploader.platform.util.DefaultDynamicLibraries; import electrostatic.snaploader.platform.NativeDynamicLibrary; import electrostatic.snaploader.platform.util.NativeVariant; +import electrostatic.snaploader.platform.util.PlatformPredicate; import electrostatic.snaploader.platform.util.PropertiesProvider; import electrostatic.snaploader.LoadingCriterion; @@ -49,8 +50,8 @@ */ public final class TestBasicFeatures { - protected static final LibraryInfo libraryInfo = new LibraryInfo(getJarFilePath(), - null, + protected static final LibraryInfo libraryInfo = new LibraryInfo(getJarFilePath(), + "lib/placeholder", getLibraryBaseName(), getLibrariesAbsolutePath()); @@ -59,8 +60,8 @@ public final class TestBasicFeatures { public static final NativeDynamicLibrary[] libraries = new NativeDynamicLibrary[] { DefaultDynamicLibraries.LINUX_X86, DefaultDynamicLibraries.LINUX_X86_64, - DefaultDynamicLibraries.WIN_X86, - DefaultDynamicLibraries.WIN_X86_64, + new NativeDynamicLibrary("lib/windows/x86", "jmealloc.dll", PlatformPredicate.WIN_X86), + new NativeDynamicLibrary("lib/windows/x86", "jmealloc.dll", PlatformPredicate.WIN_X86), DefaultDynamicLibraries.MAC_X86, DefaultDynamicLibraries.MAC_X86_64, }; @@ -84,7 +85,7 @@ protected static void printDetails(NativeBinaryLoader loader) { 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().getLibraryDirectory()); + 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()); From 8a0cfb726747aa790bd163e95e822cb8279067ab Mon Sep 17 00:00:00 2001 From: pavl_g Date: Fri, 26 Jul 2024 15:41:58 -0400 Subject: [PATCH 53/55] TestBasicFeatures: registered Win-X86-64 --- .../electrostatic/snaploader/examples/TestBasicFeatures.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java index c706cfd..a7cff49 100644 --- a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java +++ b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java @@ -61,7 +61,7 @@ public final class TestBasicFeatures { DefaultDynamicLibraries.LINUX_X86, DefaultDynamicLibraries.LINUX_X86_64, new NativeDynamicLibrary("lib/windows/x86", "jmealloc.dll", PlatformPredicate.WIN_X86), - new NativeDynamicLibrary("lib/windows/x86", "jmealloc.dll", PlatformPredicate.WIN_X86), + new NativeDynamicLibrary("lib/windows/x86-64", "jmealloc.dll", PlatformPredicate.WIN_X86_64), DefaultDynamicLibraries.MAC_X86, DefaultDynamicLibraries.MAC_X86_64, }; From 301c1035b20d95ee37e146972bc0a1499c913995 Mon Sep 17 00:00:00 2001 From: pavl_g Date: Fri, 26 Jul 2024 15:51:42 -0400 Subject: [PATCH 54/55] workflows: Eclipse Temurin JDK instead of Oracle JDK --- .github/workflows/build-test.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 7cff196..ad6d4ac 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -24,10 +24,10 @@ jobs: - name: Checkout Job uses: actions/checkout@v3 - - name: Setup Oracle JDK + - name: Setup temurin JDK uses: actions/setup-java@v3 with: - distribution: 'oracle' + distribution: 'temurin' java-version: '19' - name: Compiling java @@ -52,10 +52,10 @@ jobs: - name: Checkout Job uses: actions/checkout@v3 - - name: Setup Oracle JDK + - name: Setup temurin JDK uses: actions/setup-java@v3 with: - distribution: 'oracle' + distribution: 'temurin' java-version: '19' - name: Generate javadoc @@ -77,10 +77,10 @@ jobs: - name: Checkout Job uses: actions/checkout@v3 - - name: Setup Oracle JDK + - name: Setup temurin JDK uses: actions/setup-java@v3 with: - distribution: 'oracle' + distribution: 'temurin' java-version: ${{ matrix.jdk }} - name: Download snaploader-SNAPSHOT.jar library From a7c2a4807e769da1dcc607df0f6c176ba482789f Mon Sep 17 00:00:00 2001 From: pavl_g Date: Fri, 26 Jul 2024 15:52:07 -0400 Subject: [PATCH 55/55] TestBasicFeatures: fixed Win-OS library name --- .../electrostatic/snaploader/examples/TestBasicFeatures.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java index a7cff49..a34c0c8 100644 --- a/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java +++ b/snaploader-examples/src/main/java/electrostatic/snaploader/examples/TestBasicFeatures.java @@ -60,8 +60,8 @@ public final class TestBasicFeatures { public static final NativeDynamicLibrary[] libraries = new NativeDynamicLibrary[] { DefaultDynamicLibraries.LINUX_X86, DefaultDynamicLibraries.LINUX_X86_64, - new NativeDynamicLibrary("lib/windows/x86", "jmealloc.dll", PlatformPredicate.WIN_X86), - new NativeDynamicLibrary("lib/windows/x86-64", "jmealloc.dll", PlatformPredicate.WIN_X86_64), + 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, };