Skip to content

A high-performance cross-platform native Library loader API for JVM Applications

License

Notifications You must be signed in to change notification settings

Electrostat-Lab/jSnapLoader

Repository files navigation

jSnapLoader Codacy Badge

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 The main problem that entailed building this project had been to have something similar to the JME's NativeLibraryLoader, but for a better version with more capabilities (such as: loading libraries from external Jars and having a generic file extraction interface). Sample = $P = [\cup_{n = 0}^N P_n]$ - Formula (Mapping relations in the form antecedents to descendants) = $\forall{P}\exists{S}\ F(P, S)$
Generalized Approach The generalized approach was deemed insufficient; as it will not add on the JME's NativeLibraryLoader, and thus the project will be insignificant. The generalized approach entails building something that directly encapsulates concrete buffered byte stream calls to ZipFileSystem interfaces for the native libraries only within the same classpath, and that actually is a bad practice to build APIs on concretions, instead as the Ontology entails, abstractions and using levels of indirections should play the most part in developing a new system. Sample = $S = [\cup_{n = 0}^N S_n]$ - Formula (Mapping relations in the form descendants to antecedents) = $\forall{S}\exists{P}\ F(S, P)$
jSnapLoader-specific Approach The jSnapLoader-specific approach is quite genuine, nevertheless it's not unique. The essential design entails the basic use of the System-Entity-Structure (SES) Framework; which essentially decomposes the the bulky actions of the library, first from the perspective of behavior into deterministic finite-states, and then from the structural perspective into the components that execute these states; the net result is having a freely-floating decomposed components. The next step was regrouping those components (using common properties from predicate calculus) and finding abstractions for them, and finally capturing relations between those components and similar systems (i.e., FileSystem APIs). This structural way of thinking has resulted in the production of beneficial compilation units that could serve other purposes and not entailed specifically to serve native library extraction and loading. $\forall{P_{loader}}\ \exists{S_{loader}}\ F(P_{loader}, S_{loader})$
Framework Decomposition The decomposition had been successfully inducted into a FileLocator interface with a validation strategy, a FileExtractor interface with the full ability to control native IO resources, and a LibraryLoader interface with the ability to build and register platform predicates to support any new unsupported systems. $$F = \cup_{n = 0}^N \ (P_{loader}, S_{loader})_{n}$$ $$= [(P_{file-locator}, S_{file-locator}), (P_{file-extractor}, S_{file-extractor}),$$ $$(P_{library-locator}, S'_{file-locator}), (P_{library-extractor}, S'_{file-extractor}), (P_{library-loader}, S_{library-loader})]$$ ;where $S'_{clazz}$ S prime represents a solution of class 'clazz'.
Common problems, robustness, and re-usability of solutions To extend the robustness (rigidity) of the solution, multiple similar problems could utilize classes of solutions from the same kind; for instance, the problem library-locator could use a solution of the class file-locator; thus this could be explained by a uniqueness formula as regard to the formal language. $$\forall{p}\ \in{P},\ \exists{s} \in{S},\ \forall{s'} \in{S} [(p_{loader}, s_{loader}) \land\ (p_{loader}, s'_{loader})\ \implies\ [s_{loader} = s'_{loader}]$$
Framework Enhancements The PlatformPredicate interface wasn't planned from the start; it has been added as an enhancement for the library to accomodate the changes and the addition of new platforms robustly without changing the internal API. In fact, I give credits to Jolt-jni for implicitly opening the vision to add them. Furthermore, the addition of the FileLocalizingListener, the FileExtractionListener, and the NativeLibraryLoadingListener binds the user API to the framework API giving jSnapLoader a more added robustness value overtime. $$E = \cup_{n = 0}^N \ (E_{loader}, S_{loader})_{n}$$ $$= [(E_{system-detection-listeners}, S_{system-detection-listeners}), (E_{locator-listeners}, S_{locator-listeners}), (E_{extractor-listeners}, S_{extractor-listeners}),$$ $$(E_{loader-listeners}, S_{loader-listeners}), (E_{system-exception}, S_{system-exception})]$$
Credits for other systems Credits should go for the jSnapLoader's users, Serial4j, Jolt-jni, and Electrostatic4j. Those implicitly and continously have pushed the API over to become better. ---

Software Architectural Paradigm:

Architectural-Paradigm-Placement

Quick Building and running examples:

┌─[pavl-machine@pavl-machine]─[/home/twisted/GradleProjects/jSnapLoader]
└──╼ $./gradlew clean && \
      ./gradlew build && \
      ./gradlew :snaploader-examples:run

BUILD SUCCESSFUL in 943ms
2 actionable tasks: 2 executed

BUILD SUCCESSFUL in 1s
7 actionable tasks: 7 executed

BUILD SUCCESSFUL in 1s
4 actionable tasks: 1 executed, 3 up-to-date

Run specific example by name:

┌─[pavl-machine@pavl-machine]─[/home/twisted/GradleProjects/jSnapLoader]
└──╼ $./gradlew :snaploader-examples:TestZipExtractor \
                :snaploader-examples:run

BUILD SUCCESSFUL in 1s
4 actionable tasks: 2 executed, 2 up-to-date

Plug-and-play usage:

Project build files:

[build.gradle]

dependencies {
    implementation "io.github.electrostat-lab:snaploader:1.1.1-stable"
}

[settings.gradle]

pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
...
// project Gradle modules includes

Library Implementation:

  1. The most straightforward way:
    /**
    * Examines the cross-platform capabilities of jSnapLoader.
    *
    * @author pavl_g.
    */
    public class TestCrossPlatformClassPathLoading {
    public static void main(String[] args) throws Exception {
    final LibraryInfo libraryInfo = new LibraryInfo(new DirectoryPath("lib/independent"), "jmealloc", DirectoryPath.USER_DIR);
    final NativeDynamicLibrary[] libraries = new NativeDynamicLibrary[] {
    DefaultDynamicLibraries.ANDROID_ALL,
    DefaultDynamicLibraries.LINUX_X86,
    DefaultDynamicLibraries.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,
    };
    final NativeBinaryLoader loader = new NativeBinaryLoader(libraryInfo);
    loader.registerNativeLibraries(libraries).initPlatformLibrary();
    loader.setLoggingEnabled(true);
    loader.setRetryWithCleanExtraction(true);
    /* Native dynamic library properties */
    printDetails(loader);
    loader.loadLibrary(LoadingCriterion.INCREMENTAL_LOADING);
    }
  • This way utilizes the classpath on the stock Jar archive to locate, extract and load the native binaries.
  • It first defines a library info object with a pointer to the classpath (aka. wrapped null string path), and a default path that will be used in case the platform path for the selected platform predicate is not assigned, then a basename for the library to be operated, and finally the current working directory as an extraction path.
  1. A Superior control:
    /**
    * A finer version of {@link TestBasicFeatures} utilizing the platform-independent
    * nio.file APIs.
    *
    * @author pavl_g
    */
    public final class TestBasicFeatures2 {
    public static void main(String[] args) throws Exception {
    final Path compressionPath = Paths.get(PropertiesProvider.USER_DIR.getSystemProperty(), "libs", TestBasicFeatures.getJarFile());
    final Path extractionPath = Files.createDirectories(Paths.get(PropertiesProvider.USER_DIR.getSystemProperty(), "libs",
    NativeVariant.OS_NAME.getProperty(), NativeVariant.OS_ARCH.getProperty()));
    final LibraryInfo libraryInfo = new LibraryInfo(new DirectoryPath(compressionPath.toString()), new DirectoryPath("lib/placeholder"),
    "jmealloc", new DirectoryPath(extractionPath.toString()));
    final NativeDynamicLibrary[] libraries = new NativeDynamicLibrary[] {
    DefaultDynamicLibraries.LINUX_X86,
    DefaultDynamicLibraries.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,
    };
    final NativeBinaryLoader loader = new NativeBinaryLoader(libraryInfo);
    loader.registerNativeLibraries(libraries).initPlatformLibrary();
    loader.setLoggingEnabled(true);
    loader.setRetryWithCleanExtraction(true);
    /* Native dynamic library properties */
    printDetails(loader);
    loader.loadLibrary(LoadingCriterion.INCREMENTAL_LOADING);
    }
  • This way utilizes the java.nio.file.Paths and java.nio.file.Path APIs to build platform-independent directory paths, and it's deemed the most superior way, especially for vague systems; thus it's considered the most robust way, and the best cross-platform strategy; because it depends on the Java implementation for this specific runtime.
  1. Full control (external Jar localizing, platform predicates, and platform-independent extraction paths):
  1. Extract and load libraries with user-defined fallback routines for anti-loading failure:

Introduced in 1.1.1-stable.

/**
* A suggested cross-platform algorithm to use fallback mechanisms for Jolt-Jni.
* <p>
* <ul>
* <li> This is an efficient implementation that follows best
* practices for software engineering, and the computational theory. </li>
* <li> This is a theoretical implementation technique. </li>
* <li> Feel free to copy-paste to your projects and modify as required. </li>
* <li> Open issues as required. </li>
* </ul>
* </p>
*
* @author pavl_g.
*/
public class NativeDllLoader implements NativeBinaryLoadingListener, FileLocalizingListener {
/**
* Instance reference for the associated binary loader.
*/
protected final NativeBinaryLoader loader;
/**
* Instance reference for libraries with base features
* for the {@link NativeDllLoader#loadBaseLibraries(LoadingCriterion)}
* as a fallback mechanism.
*/
protected NativeDynamicLibrary[] baseLibs;
/**
* Instance reference for libraries with CPU-based specific features
* for the {@link NativeDllLoader#loadCpuEnhancedLibs(LoadingCriterion)} routine.
*/
protected NativeDynamicLibrary[] cpuEnhancedLibs;
/**
* Instantiates a DLL Loader wrapper setting its logging, retry criteria,
* and setting up its loading listeners.
*
* @param baseLibs the base feature libraries group (not null).
* @param cpuEnhancedLibs the cpu enhanced libraries group (not null).
* @param info the cross-platform library info metadata (not null).
* @param enableLogging true to enable snap-loader logger and failure logs (default: false).
* @param enableRetryCriterion true to enable retrying when loading from a jar file (default: false).
* @throws IllegalArgumentException if the caller stack has passed undefined library groups and/or
* undefined library information reference.
*/
public NativeDllLoader(NativeDynamicLibrary[] baseLibs, NativeDynamicLibrary[] cpuEnhancedLibs,
LibraryInfo info, boolean enableLogging, boolean enableRetryCriterion) {
this(info, enableLogging, enableRetryCriterion);
if (baseLibs == null || cpuEnhancedLibs == null) {
throw new IllegalArgumentException("Libraries groups cannot be null!");
}
this.baseLibs = baseLibs;
this.cpuEnhancedLibs = cpuEnhancedLibs;
}
/**
* Instantiates a DLL Loader wrapper setting its logging, retry criteria,
* and setting up its loading listeners.
*
* @param enableLogging enables the API level logger (default: false).
* @param enableRetryCriterion enables retrying with clean extraction (default: false).
* when loading failure for {@link LoadingCriterion#INCREMENTAL_LOADING}
* routine.
* @throws IllegalArgumentException if the caller stack has passed an undefined library information
* reference.
*/
public NativeDllLoader(LibraryInfo info, boolean enableLogging, boolean enableRetryCriterion) {
if (info == null) {
throw new IllegalArgumentException("Cannot proceed with no library information!");
}
loader = new ConcurrentNativeBinaryLoader(List.of(), info);
loader.setLoggingEnabled(enableLogging);
loader.setRetryWithCleanExtraction(enableRetryCriterion);
loader.setNativeBinaryLoadingListener(this);
loader.setLibraryLocalizingListener(this);
}
/**
* Loads the base defined libraries providing an anti-failure routine
* for loading from archive commands. This routine is thread-safe with other object routines.
*
* <p>
* Possible execution stack:
* Legend:
* <code>
* ">>" represents the initial state of the automata
* "*" represents the terminal state of the automata; after
* which the stack is owned by another machine.
* "**" represents an imminent failure signal.
* "->" represents a machine transitional delta.
* </code>
* <ul>
* <li> Case 1:
* <code> >> loadBaseLibraries(LoadingCriterion.INCREMENTAL_LOADING) ->
* if (failure-cause == UnSupportedSystemError) -> exit() -> **.
* </code>
* </li>
* <li> Case 2:
* <code> >> loadBaseLibraries(LoadingCriterion.INCREMENTAL_LOADING) ->
* if (failure-cause == LoadingRetryExhaustionException) -> onLoadingFailure()
* -> loadBaseLibraries(LoadingCriterion.SYSTEM_LOAD) ->
* if (failure-cause == UnsatisfiedLinkError) -> exit() -> **.
* </code>
* </li>
* </ul>
* </p>
*
* @param criterion the loading criterion, it's recommended to start with
* {@link LoadingCriterion#INCREMENTAL_LOADING}; moreover
* start with the {@link NativeDllLoader#loadCpuEnhancedLibs(LoadingCriterion)} (not null).
* @throws Exception if I/O event or thread signal interrupt occurs.
*/
public synchronized void loadBaseLibraries(LoadingCriterion criterion) throws Exception {
if (criterion == null) {
throw new IllegalArgumentException("Cannot proceed with null loading criterion!");
}
try {
loader.registerNativeLibraries(baseLibs)
.initPlatformLibrary()
.loadLibrary(criterion);
} catch (UnSupportedSystemError e) {
signalImminentFailure(
new CallingStackMetaData(Thread.currentThread().getStackTrace()[1], criterion, e));
} catch (LoadingRetryExhaustionException e) {
// re-route retry failure to the same anti-failure routine
this.onLoadingFailure(loader,
new CallingStackMetaData(Thread.currentThread().getStackTrace()[1], criterion, e));
}
}
/**
* Loads the registered CPU-enhanced libraries. Providing an anti-failure routine
* for loading from archive commands. This is thread-safe with other routines.
*
* <p>
* Possible execution stack:
* <ul>
* <li> Case 1 (Notice UnSupportedSystemError is thrown from the initPlatformLibrary
* during which system selection is performed):
* <code> >> exec: loadCpuEnhancedLibs(LoadingCriterion.INCREMENTAL_LOADING) ->
* if (failure-cause == UnSupportedSystemError) -> onLoadingFailure ->
* exec: loadBaseLibraries(LoadingCriterion.INCREMENTAL_LOADING) -> *.
* </code>
* </li>
* <li> Case 2:
* <code> >> exec: loadCpuEnhancedLibs(LoadingCriterion.INCREMENTAL_LOADING) ->
* if (failure-cause == LoadingRetryExhaustionException) -> loadCpuEnhancedLibs(LoadingCriterion.SYSTEM_LOAD)
* if (failure-cause == UnsatisfiedLinkError) -> onLoadingFailure -> exec: loadBaseLibraries(LoadingCriterion.INCREMENTAL_LOADING)
* -> *.
* </code>
* </li>
* <li> Case 3:
* <code>
* >> ...Some states... -> Any other failure cause -> exit() -> *.
* </code>
* </li>
* </ul>
* </p>
*
* @param criterion the type of loading; it's recommended to start with {@link LoadingCriterion#INCREMENTAL_LOADING}.
* @throws Exception if I/O event or thread signal interrupt occurs.
*/
public synchronized void loadCpuEnhancedLibs(LoadingCriterion criterion) throws Exception {
if (criterion == null) {
throw new IllegalArgumentException("Cannot proceed with null loading criterion!");
}
try {
loader.registerNativeLibraries(cpuEnhancedLibs)
.initPlatformLibrary()
.loadLibrary(criterion);
} catch (UnSupportedSystemError e) {
// re-route system not found and retry failure to the same anti-failure routine
this.onLoadingFailure(loader,
new CallingStackMetaData(Thread.currentThread().getStackTrace()[1], criterion, e));
} catch (LoadingRetryExhaustionException e) {
// retry with SYSTEM_LOAD
// notice that LoadingRetryExhaustionException will never
// happen with LoadingCriterion.SYSTEM_LOAD
// the LoadingRetryExhaustionException is thrown as a result
// of greater than 2 times throwing "UnSatisfiedLinkError" on the
// INCREMENTAL Loading Stack (i.e., extracting stack).
loadCpuEnhancedLibs(LoadingCriterion.SYSTEM_LOAD);
}
}
@Override
public void onLoadingSuccess(NativeBinaryLoader nativeBinaryLoader, CallingStackMetaData callingStackMetaData) {
// initialize Jolt-Jni and physics update system
// handling lifecycle to the internal Jolt-Physics Native
// copied from Jolt-Jni Example
String configuration = Jolt.getConfigurationString();
/*
* Depending which native library was loaded, the configuration string
* should be one of the following:
*
* On LINUX_X86_64 platforms, either
* Single precision x86 64-bit with instructions: SSE2 SSE4.1 SSE4.2 AVX AVX2 F16C LZCNT TZCNT FMADD (Debug Renderer) (16-bit ObjectLayer) (Assertions) (ObjectStream) (Debug) (C++ RTTI) (C++ Exceptions)
* or
* Single precision x86 64-bit with instructions: SSE2 (Debug Renderer) (16-bit ObjectLayer) (Assertions) (ObjectStream) (Debug) (C++ RTTI) (C++ Exceptions)
*
* On WIN_X86_64 platforms, either
* Single precision x86 64-bit with instructions: SSE2 SSE4.1 SSE4.2 AVX AVX2 F16C LZCNT TZCNT (FP Exceptions) (Debug Renderer) (16-bit ObjectLayer) (Assertions) (ObjectStream) (Debug) (C++ RTTI) (C++ Exceptions)
* or
* Single precision x86 64-bit with instructions: SSE2 (FP Exceptions) (Debug Renderer) (16-bit ObjectLayer) (Assertions) (ObjectStream) (Debug) (C++ RTTI) (C++ Exceptions)
*/
System.out.println(configuration);
}
@Override
public synchronized void onLoadingFailure(NativeBinaryLoader nativeBinaryLoader, CallingStackMetaData callingStackMetaData) {
// validate input!
if (callingStackMetaData == null || callingStackMetaData.getCallingStack() == null ||
callingStackMetaData.getErrorCause() == null || callingStackMetaData.getLoadingCriterion() == null) {
throw new IllegalArgumentException("Failure stack metadata structure cannot be null!");
}
final String callingMethod = callingStackMetaData.getCallingStack().getMethodName();
// log calling stack!
SnapLoaderLogger.log(Level.INFO, callingStackMetaData.getCallingStack().getClassName(),
callingStackMetaData.getCallingStack().getMethodName(),
"Failure Stack", callingStackMetaData.getErrorCause());
try {
if (callingStackMetaData.getErrorCause() instanceof LoadingRetryExhaustionException) {
if (callingMethod.contains("loadCpuEnhancedLibs")) {
// try cpu enhanced libs from system directory
loadCpuEnhancedLibs(LoadingCriterion.SYSTEM_LOAD);
} else if (callingMethod.contains("loadBaseLibraries")) {
// try loading base libraries from system directories if loading is exhausted!
loadBaseLibraries(LoadingCriterion.SYSTEM_LOAD);
}
} else if (callingStackMetaData.getErrorCause() instanceof UnsatisfiedLinkError) {
if (callingMethod.contains("loadCpuEnhancedLibs")) {
// no retry criteria?
// or loading from system directory?
// Exit the loadCpuEnhancedLibs stack frames!
loadBaseLibraries(LoadingCriterion.INCREMENTAL_LOADING);
} else if (callingMethod.contains("loadBaseLibraries")) {
signalImminentFailure(callingStackMetaData);
}
} else if (callingStackMetaData.getErrorCause() instanceof FilesystemResourceInitializationException) {
if (callingMethod.contains("onFileLocalizationFailure")) {
loadCpuEnhancedLibs(LoadingCriterion.SYSTEM_LOAD);
}
}
} catch (Exception e) {
signalImminentFailure(callingStackMetaData);
}
}

  1. Load libraries supporting specific CPU features by testing for those ISA Extensions using NativeVariant.Cpu.hasExtensions(...):

Introduced in 1.1.0-stable.

/**
* Tests selection between native libraries based on CPU features.
*
* @author Stephen Gold [email protected]
*/
public final class TestCpuFeatures {
public static void main(String[] argv) {
// Test for each of the relevant CPU features:
System.out.println("avx = " + NativeVariant.Cpu.hasExtensions("avx"));
System.out.println("avx2 = " + NativeVariant.Cpu.hasExtensions("avx2"));
System.out.println("bmi1 = " + NativeVariant.Cpu.hasExtensions("bmi1"));
System.out.println("f16c = " + NativeVariant.Cpu.hasExtensions("f16c"));
System.out.println("fma = " + NativeVariant.Cpu.hasExtensions("fma"));
System.out.println("sse4_1 = " + NativeVariant.Cpu.hasExtensions("sse4_1"));
System.out.println("sse4_2 = " + NativeVariant.Cpu.hasExtensions("sse4_2"));
// Define a custom predicate for Linux with all 7 CPU features:
PlatformPredicate linuxWithFma = new PlatformPredicate(
PlatformPredicate.LINUX_X86_64,
"avx", "avx2", "bmi1", "f16c", "fma", "sse4_1", "sse4_2");
System.out.println("linuxWithFma = " + linuxWithFma.evaluatePredicate());
// Define a custom predicate for Windows with 4 CPU features:
PlatformPredicate windowsWithAvx2 = new PlatformPredicate(
PlatformPredicate.WIN_X86_64,
"avx", "avx2", "sse4_1", "sse4_2");
System.out.println("windowsWithAvx2 = " + windowsWithAvx2.evaluatePredicate());
System.out.flush();
LibraryInfo info = new LibraryInfo(
new DirectoryPath("linux/x86-64/com/github/stephengold"),
"joltjni", DirectoryPath.USER_DIR);
NativeBinaryLoader loader = new NativeBinaryLoader(info);
NativeDynamicLibrary[] libraries = {
new NativeDynamicLibrary("linux/x86-64-fma/com/github/stephengold", linuxWithFma), // must precede vanilla LINUX_X86_64
new NativeDynamicLibrary("linux/x86-64/com/github/stephengold", PlatformPredicate.LINUX_X86_64),
new NativeDynamicLibrary("windows/x86-64-avx2/com/github/stephengold", windowsWithAvx2), // must precede vanilla WIN_X86_64
new NativeDynamicLibrary("windows/x86-64/com/github/stephengold", PlatformPredicate.WIN_X86_64)
};
loader.registerNativeLibraries(libraries).initPlatformLibrary();
loader.setLoggingEnabled(true);
loader.setRetryWithCleanExtraction(true);
try {
loader.loadLibrary(LoadingCriterion.CLEAN_EXTRACTION);
} catch (Exception e) {
throw new IllegalStateException("Failed to load the joltjni library!");
}

Appendix:

Features:

  • Platform-specific dynamic libraries' registration.
  • Platform-specific dynamic libraries building using platform-specific predicates (NEW).
  • Locate and load external dynamic libraries directly.
  • File Locator and extractor routines (classpath - external jar).
  • Extract native libraries from the stock jar library (classpath).
  • Locate external jars and extract native libraries from them.
  • Define an extract directory.
  • Retry Criterion with clean extraction (NEW).
  • Exposed the platform-dependent library NativeDynamicLibrary (NEW).
  • Exposed the NativeVariant providing system properties.
  • EventDispatchers: Extraction Listeners, Loading Listeners, and System Detection Listeners.
  • Filesystem Failure Throwable Exceptions: binds the user API to the jSnapLoader lifecycle.
  • Tight handling of memory leaks; as a result of file locator and/or file extractor failures.
  • Memory logging of the stream providers' handlers using the object hash keys.
  • CPU Features check (NEW).
  • Framework-based loaded classes check (NEW).
  • Load libraries from System Directories (Note: Default Mode for Android).
  • Extract automatically based on the application name and version.

Documentation-list:

  • Architecture paradigm.
  • API documentation.
  • Java-Doc page.

Credits:

Projects:

Those projects had contributed implicitly and/or explicitly and must be recognized:

  • Serial4j: was the initial trigger for this project.
  • Jolt-jni: was and still the drive to continue this project.
  • snap-jolt: provides an extensive testing environment for the API on a professional basis (including Linux-Arm); that is to extract and load Jolt-Jni, a Java binding library for Jolt-Physics framework.
  • Electrostatic4j: will be the future supporter for this project.

People:

I owe these people a cup of coffee for their gracious contributions, when we eventually meet:

Pure Science:

  • Discrete mathematics and Ontology.
  • The System-Entity-Structure (SES) Framework for System-design.
  • The Tricotyledeon theory of system design by W.A.Wymore (T3SD).
  • The Finite-automata theory.