Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,9 @@ jobs:
- name: Run TestCpuFeatures
run: ./gradlew :snaploader-examples:TestCpuFeatures :snaploader-examples:run

- name: Run TestBrokenFeatures
run: ./gradlew :snaploader-examples:ReflectiveLauncher :snaploader-examples:run --args="electrostatic4j.snaploader.examples.TestBrokenFeatures"

- name: List extracted files
run: ls ./snaploader-examples/libs/

Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* Copyright (c) 2023-2026, 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 electrostatic4j.snaploader.examples;

import electrostatic4j.snaploader.LibraryInfo;
import electrostatic4j.snaploader.NativeBinaryLoader;
import electrostatic4j.snaploader.NativeBinaryLoadingListener;
import electrostatic4j.snaploader.filesystem.DirectoryPath;
import electrostatic4j.snaploader.filesystem.FileExtractionListener;
import electrostatic4j.snaploader.filesystem.FileExtractor;
import electrostatic4j.snaploader.filesystem.FileLocator;
import electrostatic4j.snaploader.platform.util.DefaultDynamicLibraries;
import electrostatic4j.snaploader.platform.NativeDynamicLibrary;
import electrostatic4j.snaploader.platform.util.NativeVariant;
import electrostatic4j.snaploader.platform.util.PlatformPredicate;
import electrostatic4j.snaploader.platform.util.DefaultPropertiesProvider;
import electrostatic4j.snaploader.LoadingCriterion;
import electrostatic4j.snaploader.util.CallingStackMetaData;

/**
* Tests basic features of the {@link NativeBinaryLoader} API.
*
* @author pavl_g
*/
public final class TestBrokenFeatures {

protected static final LibraryInfo libraryInfo = new LibraryInfo(getJarFilePath(),
new DirectoryPath(DefaultDynamicLibraries.LINUX_X86.getPlatformDirectory()),
getLibraryBaseName(),
getLibrariesAbsolutePath());

protected static NativeBinaryLoader loader;

public static final NativeDynamicLibrary[] libraries = new NativeDynamicLibrary[] {
DefaultDynamicLibraries.LINUX_X86,
new NativeDynamicLibrary("nonexistent/directory", "junk", PlatformPredicate.LINUX_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,
};

public static void main(String[] args) throws Exception {
if (loader == null) {
loader = new NativeBinaryLoader(libraryInfo);
}
loader.registerNativeLibraries(libraries).initPlatformLibrary();
loader.setLoggingEnabled(false);
loader.setRetryWithCleanExtraction(true);
/* Native dynamic library properties */
printDetails(loader);
loader.setNativeBinaryLoadingListener(new NativeBinaryLoadingListener() {
@Override
public void onLoadingSuccess(NativeBinaryLoader nativeBinaryLoader, CallingStackMetaData callingStackMetaData) {

Check notice on line 84 in snaploader-examples/src/main/java/electrostatic4j/snaploader/examples/TestBrokenFeatures.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

snaploader-examples/src/main/java/electrostatic4j/snaploader/examples/TestBrokenFeatures.java#L84

Document empty method body

}

@Override
public void onLoadingFailure(NativeBinaryLoader nativeBinaryLoader, CallingStackMetaData callingStackMetaData) {
System.err.println(callingStackMetaData.getErrorCause());
}

@Override
public void onRetryCriterionExecution(NativeBinaryLoader nativeBinaryLoader, CallingStackMetaData callingStackMetaData) {

Check notice on line 94 in snaploader-examples/src/main/java/electrostatic4j/snaploader/examples/TestBrokenFeatures.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

snaploader-examples/src/main/java/electrostatic4j/snaploader/examples/TestBrokenFeatures.java#L94

Document empty method body

}
});

loader.setLibraryExtractionListener(new FileExtractionListener() {
@Override
public void onExtractionCompleted(FileExtractor fileExtractor) {
System.out.println("Extracted Successfully!");
}

@Override
public void onExtractionFailure(FileExtractor fileExtractor, Throwable throwable) {
System.err.println(throwable.toString());
}

@Override
public void onExtractionFinalization(FileExtractor fileExtractor, FileLocator fileLocator) {
System.out.println("Finalization State has been reached!");
}
});

loader.loadLibrary(LoadingCriterion.INCREMENTAL_LOADING);
}

protected static void printDetails(NativeBinaryLoader loader) {
System.out.println("--------------------------------------------------------------");
System.out.println("OS: " + NativeVariant.OS_NAME.getProperty());
System.out.println("ARCH: " + NativeVariant.OS_ARCH.getProperty());
System.out.println("VM: " + NativeVariant.JVM.getProperty());
System.out.println("--------------------------------------------------------------");
System.out.println("Jar Path: " + loader.getNativeDynamicLibrary().getJarPath());
System.out.println("Library Directory: " + loader.getNativeDynamicLibrary().getPlatformDirectory());
System.out.println("Compressed library path: " + loader.getNativeDynamicLibrary().getCompressedLibrary());
System.out.println("Extracted library absolute path: " + loader.getNativeDynamicLibrary().getExtractedLibrary());
System.out.println("Is Extracted: " + loader.getNativeDynamicLibrary().isExtracted());
System.out.println("--------------------------------------------------------------");
}

protected static DirectoryPath getLibrariesAbsolutePath() {
return new DirectoryPath(DefaultPropertiesProvider.USER_DIR.getSystemProperty(), "libs");
}

protected static DirectoryPath getJarFilePath() {
return new DirectoryPath(getLibrariesAbsolutePath().getPath(), getJarFile());
}

protected static String getNativeDynamicLibraryPath() {
return getLibrariesAbsolutePath().getPath() +
DefaultPropertiesProvider.FILE_SEPARATOR.getSystemProperty() +
"lib" + getLibraryBaseName() + ".so";
}

protected static String getJarFile() {
return "jme3-alloc-desktop-1.0.0-pre-gamma-2.jar";
}

protected static String getLibraryBaseName() {
return "jmealloc";
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023-2025, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader
* Copyright (c) 2023-2026, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -33,6 +33,7 @@
package electrostatic4j.snaploader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.util.Arrays;
Expand All @@ -49,6 +50,7 @@
import electrostatic4j.snaploader.platform.util.NativeVariant;
import electrostatic4j.snaploader.platform.util.PropertiesControllerNamespace;
import electrostatic4j.snaploader.platform.util.PropertiesController;
import electrostatic4j.snaploader.throwable.LibraryNotFoundException;
import electrostatic4j.snaploader.throwable.LoadingRetryExhaustionException;
import electrostatic4j.snaploader.throwable.UnSupportedSystemError;
import electrostatic4j.snaploader.util.CallingStackMetaData;
Expand Down Expand Up @@ -183,12 +185,13 @@ public NativeBinaryLoader loadLibrary(LoadingCriterion criterion) throws Excepti
throw new IllegalArgumentException("Native library data structures cannot be null!");
}
// commands and loads the library from the system directories
if (NativeVariant.Os.isAndroid() || criterion == LoadingCriterion.SYSTEM_LOAD) {
if (NativeVariant.Os.isAndroid() ||
criterion == LoadingCriterion.SYSTEM_LOAD) {
loadSystemBinary(nativeDynamicLibrary);
loadingCriterion = LoadingCriterion.SYSTEM_LOAD;
return this;
}
if (criterion == LoadingCriterion.INCREMENTAL_LOADING && nativeDynamicLibrary.isExtracted()) {
if (criterion == LoadingCriterion.INCREMENTAL_LOADING) {
loadBinary(nativeDynamicLibrary, criterion);
loadingCriterion = LoadingCriterion.INCREMENTAL_LOADING;
return this;
Expand Down Expand Up @@ -336,14 +339,17 @@ protected void loadSystemBinary(NativeDynamicLibrary dynamicLibrary) {
*/
protected void loadBinary(NativeDynamicLibrary library, LoadingCriterion loadingCriterion) throws Exception {
try {
if (!nativeDynamicLibrary.exists()) {
throw new LibraryNotFoundException("Library " + nativeDynamicLibrary.getExtractedLibrary() + " not found!");
}
System.load(library.getExtractedLibrary());
SnapLoaderLogger.log(Level.INFO, getClass().getName(), "loadBinary", "Successfully loaded library: "
+ library.getExtractedLibrary());
if (nativeBinaryLoadingListener != null) {
nativeBinaryLoadingListener.onLoadingSuccess(this,
new CallingStackMetaData(Thread.currentThread().getStackTrace()[1], loadingCriterion));
}
} catch (final UnsatisfiedLinkError error) {
} catch (final UnsatisfiedLinkError | FileNotFoundException error) {
SnapLoaderLogger.log(Level.SEVERE, getClass().getName(), "loadBinary", "Cannot load the dynamic library: "
+ library.getExtractedLibrary(), error);
if (nativeBinaryLoadingListener != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ public class FileExtractor implements OutputStreamProvider {
*/
protected String destination;

protected File extractableFile;

private static final int EOF = -1; /* End-of-filesystem */

/**
Expand Down Expand Up @@ -103,6 +105,7 @@ public void initialize(int size) throws Exception {
return;
}
this.fileOutputStream = new FileOutputStream(destination);
extractableFile = new File(destination);
SnapLoaderLogger.log(Level.INFO, getClass().getName(), "initialize(int)",
"File extractor initialized with hash key #" + getHashKey());
} catch (Exception e) {
Expand Down Expand Up @@ -149,6 +152,14 @@ public void extract() throws IOException, FileNotFoundException {
fileExtractionListener.onExtractionCompleted(this);
}
} catch (Exception e) {
// ensure deleting the blank created files
// by the Java Legacy FileOutputStream upon failure!

// blank created files; create an opaque behavior
// that triggers an UnSatisfiedLinkError: file is too short
// as a result of trying to load corrupted files
// on the next runtime...
delete();
if (fileExtractionListener != null) {
fileExtractionListener.onExtractionFailure(this, e);
}
Expand All @@ -160,6 +171,20 @@ public void extract() throws IOException, FileNotFoundException {
}
}

/**
* Deletes the associated file created by the Legacy
* Java OutputStream {@link FileExtractor#getFileOutputStream()}.
*
* @return true if the file has been deleted, false otherwise if the
* file is not defined or doesn't exist.
*/
protected boolean delete() {
if (extractableFile == null || !extractableFile.exists()) {
return false;
}
return extractableFile.delete();
}

@Override
public void close() throws Exception {
if (fileOutputStream != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@ public void initWithLibraryInfo(LibraryInfo libraryInfo) {
}
}

public boolean exists() {
if (jarPath == null || libraryFile == null || directoryPath == null) {
return false;
}
return new File(getExtractedLibrary()).exists();
}

/**
* Retrieves the absolute path for the jar compression as specified by the {@link LibraryInfo} API.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2023-2026, The Electrostatic-Sandbox Distributed Simulation Framework, jSnapLoader
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'Electrostatic-Sandbox' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package electrostatic4j.snaploader.throwable;

import java.io.FileNotFoundException;

/**
* A business exception that is thrown to indicate that a library, that is
* tried to be loaded, doesn't exist.
*
* @author pavl_g
*/
public class LibraryNotFoundException extends FileNotFoundException {
public LibraryNotFoundException(String message) {
super(message);
}
}
Loading