Skip to content

Commit

Permalink
Merge pull request #27 from Electrostat-Lab/final-optimizations
Browse files Browse the repository at this point in the history
Final optimizations: Logging API - StreamProviders API - Memory Logging
  • Loading branch information
pavly-gerges authored Aug 4, 2024
2 parents 8c761fe + f1c3b09 commit 848115e
Show file tree
Hide file tree
Showing 15 changed files with 393 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
import electrostatic.snaploader.filesystem.FileLocator;
import electrostatic.snaploader.filesystem.ZipCompressionType;
import electrostatic.snaploader.platform.util.PropertiesProvider;
import electrostatic.snaploader.util.SnapLoaderLogger;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand All @@ -49,9 +51,12 @@
public class TestFilesystemMemoryLeak {
public static void main(String[] args) throws IOException {
/* Locates the image inside the Zip Compression */
SnapLoaderLogger.setLoggingEnabled(true);
final FileLocator fileLocator = new FileLocator(getZipAbsolutePath(), getFilePath(), ZipCompressionType.ZIP);
/* Extracts the image filesystem from the Zip Compression */
final FileExtractor fileExtractor = new FileExtractor(fileLocator, getExtractionPath());
fileLocator.initialize(0);
fileExtractor.initialize(0);
/* CLOSE/CLEAR I/O Resources */
fileExtractor.setExtractionListener(new FileExtractionListener() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

import electrostatic.snaploader.LoadingCriterion;
import electrostatic.snaploader.ConcurrentNativeBinaryLoader;
import electrostatic.snaploader.UnSupportedSystemError;
import electrostatic.snaploader.throwable.UnSupportedSystemError;
import electrostatic.snaploader.platform.util.DefaultDynamicLibraries;
import electrostatic.snaploader.platform.NativeDynamicLibrary;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import electrostatic.snaploader.filesystem.FileLocator;
import electrostatic.snaploader.filesystem.ZipCompressionType;
import electrostatic.snaploader.platform.util.PropertiesProvider;
import electrostatic.snaploader.throwable.FilesystemResourceScavengingException;

/**
* Tests extracting an image compression from a Zip compression type filesystem using {@link FileExtractor} API.
Expand All @@ -54,6 +55,8 @@ public static void main(String[] args) throws IOException {
final FileLocator fileLocator = new FileLocator(getZipAbsolutePath(), getFilePath(), ZipCompressionType.ZIP);
/* Extracts the image filesystem from the Zip Compression */
final FileExtractor fileExtractor = new FileExtractor(fileLocator, getExtractionPath());
fileLocator.initialize(0);
fileExtractor.initialize(0);
/* CLOSE/CLEAR I/O Resources */
fileExtractor.setExtractionListener(new FileExtractionListener() {
@Override
Expand All @@ -70,11 +73,8 @@ public void onExtractionFailure(FileExtractor fileExtractor, Throwable throwable
public void onExtractionFinalization(FileExtractor fileExtractor, FileLocator fileLocator) {
try {
fileExtractor.close();
fileLocator.close();
Logger.getLogger(TestZipExtractor.class.getName())
.log(Level.INFO, "Filesystem Resources Closed!");
} catch (IOException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new FilesystemResourceScavengingException(e);
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.lang.UnsatisfiedLinkError;
import electrostatic.snaploader.filesystem.FileExtractionListener;
import electrostatic.snaploader.filesystem.FileExtractor;
Expand All @@ -46,6 +45,8 @@
import electrostatic.snaploader.library.LibraryLocator;
import electrostatic.snaploader.platform.NativeDynamicLibrary;
import electrostatic.snaploader.platform.util.NativeVariant;
import electrostatic.snaploader.throwable.UnSupportedSystemError;
import electrostatic.snaploader.util.SnapLoaderLogger;

/**
* A cross-platform utility for extracting and loading native binaries based on
Expand All @@ -55,11 +56,6 @@
*/
public class NativeBinaryLoader {

/**
* NativeBinaryLoader logger object.
*/
protected static final Logger logger = Logger.getLogger(NativeBinaryLoader.class.getName());

protected final LibraryInfo libraryInfo;

protected List<NativeDynamicLibrary> registeredLibraries;
Expand All @@ -82,11 +78,6 @@ public class NativeBinaryLoader {
*/
protected NativeDynamicLibrary nativeDynamicLibrary;

/**
* Flag for enable/disable logging.
*/
protected boolean loggingEnabled;

/**
* Flag for retry loading with clean extract if UnSatisfiedLinkError is thrown.
*/
Expand Down Expand Up @@ -173,28 +164,19 @@ public NativeBinaryLoader loadLibrary(LoadingCriterion criterion) throws IOExcep
/**
* Retrieves the native dynamic library object representing the library to extract and load.
*
* @return an object representing the platform dependent native dynamic library
* @return an object representing the platform-dependent native dynamic library
*/
public NativeDynamicLibrary getNativeDynamicLibrary() {
return nativeDynamicLibrary;
}

/**
* Enables the logging for this object, default value is false.
*
*
* @param loggingEnabled true to enable logging, false otherwise
*/
public void setLoggingEnabled(boolean loggingEnabled) {
this.loggingEnabled = loggingEnabled;
}

/**
* Tests the logging flag, default value is false.
*
* @return true if the logging flag is enabled, false otherwise
*/
public boolean isLoggingEnabled() {
return loggingEnabled;
SnapLoaderLogger.setLoggingEnabled(loggingEnabled);
}

/**
Expand Down Expand Up @@ -252,26 +234,30 @@ public FileLocalizingListener getLibraryLocalizingListener() {
}

/**
* Loads a native binary using the platform dependent object, for android,
* Loads a native binary using the platform-dependent object, for Android;
* the library is loaded by its basename (variant is managed internally by the android sdk).
*
* @param library the platform-specific library to load
* @throws IOException in case the binary to be extracted is not found on the specified jar
*/
protected void loadBinary(NativeDynamicLibrary library) throws IOException {
try {
/* sanity check for android java vm (the dalvik) */
/* sanity-check for android java vm (the dalvik) */
if (NativeVariant.Os.isAndroid()) {
System.loadLibrary(libraryInfo.getBaseName());
SnapLoaderLogger.log(Level.INFO, getClass().getName(),"loadBinary", "Successfully loaded library for Android: "
+ library.getExtractedLibrary());
return;
}
System.load(library.getExtractedLibrary());
log(Level.INFO, "loadBinary", "Successfully loaded library: " + library.getExtractedLibrary(), null);
SnapLoaderLogger.log(Level.INFO, getClass().getName(),"loadBinary", "Successfully loaded library: "
+ library.getExtractedLibrary());
if (nativeBinaryLoadingListener != null) {
nativeBinaryLoadingListener.onLoadingSuccess(this);
}
} catch (final UnsatisfiedLinkError error) {
log(Level.SEVERE, "loadBinary", "Cannot load the dynamic library: " + library.getExtractedLibrary(), error);
SnapLoaderLogger.log(Level.SEVERE, getClass().getName(), "loadBinary", "Cannot load the dynamic library: "
+ library.getExtractedLibrary(), error);
if (nativeBinaryLoadingListener != null) {
nativeBinaryLoadingListener.onLoadingFailure(this);
}
Expand All @@ -289,28 +275,29 @@ protected void loadBinary(NativeDynamicLibrary library) throws IOException {
* Cleanly extracts and loads the native binary to the current [user.dir].
*
* @param library the platform-specific library to extract and load
* @throws IOException in case the binary to be extracted is not found on the specified jar or an
* interrupted I/O operation has occured
* @throws IOException in case the binary to be extracted is not found on the specified jar, or an
* interrupted I/O operation has occurred
*/
protected void cleanExtractBinary(NativeDynamicLibrary library) throws IOException {
libraryExtractor = initializeLibraryExtractor(library);
log(Level.INFO, "cleanExtractBinary", "File extractor handler initialized!", null);
SnapLoaderLogger.log(Level.INFO, getClass().getName(), "cleanExtractBinary",
"File extractor handler initialized!");
/* CLEAR RESOURCES AND RESET OBJECTS ON-EXTRACTION */
libraryExtractor.setExtractionListener(new FileExtractionListener() {
@Override
public void onExtractionCompleted(FileExtractor fileExtractor) {
try {
// free resources
// removes file locks on some OS
libraryExtractor.getFileLocator().close();
libraryExtractor.close();
libraryExtractor = null;
log(Level.INFO, "cleanExtractBinary", "Extracted successfully to " + library.getExtractedLibrary(), null);
log(Level.INFO, "cleanExtractBinary", "Filesystem Resources closed!", null);
SnapLoaderLogger.log(Level.INFO, getClass().getName(), "cleanExtractBinary",
"Extracted successfully to " + library.getExtractedLibrary());
// load the native binary
loadBinary(library);
} catch (Exception e) {
log(Level.SEVERE, "cleanExtractBinary", "Error while loading the binary!", e);
SnapLoaderLogger.log(Level.SEVERE, getClass().getName(), "cleanExtractBinary",
"Error while loading the binary!", e);
}

// bind the extraction lifecycle to the user application
Expand All @@ -321,7 +308,8 @@ public void onExtractionCompleted(FileExtractor fileExtractor) {

@Override
public void onExtractionFailure(FileExtractor fileExtractor, Throwable throwable) {
log(Level.SEVERE, "cleanExtractBinary", "Extraction has failed!", throwable);
SnapLoaderLogger.log(Level.SEVERE, getClass().getName(),
"cleanExtractBinary", "Extraction has failed!", throwable);

// bind the extraction lifecycle to the user application
if (libraryExtractionListener != null) {
Expand All @@ -332,18 +320,13 @@ public void onExtractionFailure(FileExtractor fileExtractor, Throwable throwable
@Override
public void onExtractionFinalization(FileExtractor fileExtractor, FileLocator fileLocator) {
try {
if (fileLocator != null &&
fileLocator.getFileInputStream() != null) {
fileLocator.close();
log(Level.INFO, "cleanExtractBinary", "File locator Resources closed!", null);
}
if (fileExtractor != null &&
fileExtractor.getFileOutputStream() != null) {
fileExtractor.close();
log(Level.INFO, "cleanExtractBinary", "File extractor Resources closed!", null);
}
} catch (IOException e) {
log(Level.SEVERE, "cleanExtractBinary", "Error while closing the resources!", e);
} catch (Exception e) {
SnapLoaderLogger.log(Level.SEVERE, getClass().getName(),
"cleanExtractBinary", "Error while closing the resources!", e);
}

// bind the extraction lifecycle to the user application
Expand All @@ -370,16 +353,18 @@ protected FileExtractor initializeLibraryExtractor(NativeDynamicLibrary library)
} else {
extractor = new LibraryExtractor(library.getCompressedLibrary(), library.getExtractedLibrary());
}
extractor.initialize(0);
final LibraryLocator fileLocator = preInitLibraryLocator(extractor);
fileLocator.initializeLocator();
fileLocator.initialize(0);
return extractor;
}

protected LibraryLocator preInitLibraryLocator(FileExtractor extractor) {
extractor.getFileLocator().setFileLocalizingListener(new FileLocalizingListener() {
@Override
public void onFileLocalizationSuccess(FileLocator locator) {
log(Level.INFO, "initializeLibraryExtractor", "Locating native libraries has succeeded!", null);
SnapLoaderLogger.log(Level.INFO, getClass().getName(), "initializeLibraryExtractor",
"Locating native libraries has succeeded!");

// bind the library locator lifecycle to the user application
if (libraryLocalizingListener != null) {
Expand All @@ -389,13 +374,13 @@ public void onFileLocalizationSuccess(FileLocator locator) {

@Override
public void onFileLocalizationFailure(FileLocator locator, Throwable throwable) {
log(Level.SEVERE, "initializeLibraryExtractor", "Locating native libraries has failed!", throwable);
SnapLoaderLogger.log(Level.SEVERE, getClass().getName(), "initializeLibraryExtractor",
"Locating native libraries has failed!", throwable);
try {
extractor.close();
locator.close();
log(Level.INFO, "initializeLibraryExtractor", "Filesystem resources closed!", null);
} catch (IOException e) {
log(Level.SEVERE, "initializeLibraryExtractor", "File locator closure failed!", e);
} catch (Exception e) {
SnapLoaderLogger.log(Level.SEVERE, getClass().getName(),
"initializeLibraryExtractor", "File locator closure failed!", e);
}

// bind the library locator lifecycle to the user application
Expand All @@ -406,23 +391,4 @@ public void onFileLocalizationFailure(FileLocator locator, Throwable throwable)
});
return (LibraryLocator) extractor.getFileLocator();
}

/**
* Log data with a level and a throwable (optional).
*
* @param level the logger level
* @param sourceMethod the source of this call
* @param msg a string formatted message to display
* @param throwable optional param for error messages
*/
protected void log(Level level, String sourceMethod, String msg, Throwable throwable) {
if (!isLoggingEnabled()) {
return;
}
if (throwable == null) {
logger.logp(level, this.getClass().getName(), sourceMethod, msg);
} else {
logger.logp(level, this.getClass().getName(), sourceMethod, msg, throwable);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
package electrostatic.snaploader;

import electrostatic.snaploader.platform.NativeDynamicLibrary;
import electrostatic.snaploader.throwable.UnSupportedSystemError;

/**
* Provides executable functions binding the user applications to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@

package electrostatic.snaploader.filesystem;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import electrostatic.snaploader.throwable.FilesystemResourceInitializationException;
import electrostatic.snaploader.util.SnapLoaderLogger;

import java.io.*;
import java.util.logging.Level;

/**
* Extracts a filesystem from a zip compression to a destination filesystem.
Expand Down Expand Up @@ -76,7 +76,7 @@ public class FileExtractor implements OutputStreamProvider {
*/
public FileExtractor(FileLocator fileLocator, String destination) throws FileNotFoundException {
this.fileLocator = fileLocator;
this.fileOutputStream = new FileOutputStream(destination);
this.destination = destination;
}

/**
Expand All @@ -85,6 +85,25 @@ public FileExtractor(FileLocator fileLocator, String destination) throws FileNot
protected FileExtractor() {
}

@Override
public void initialize(int size) {
try {
if (size > 0) {
this.fileOutputStream = new BufferedOutputStream(
new FileOutputStream(destination), size);
SnapLoaderLogger.log(Level.INFO, getClass().getName(), "initialize(int)",
"File extractor initialized with hash key #" + getHashKey());
return;
}
this.fileOutputStream = new FileOutputStream(destination);
SnapLoaderLogger.log(Level.INFO, getClass().getName(), "initialize(int)",
"File extractor initialized with hash key #" + getHashKey());
} catch (FileNotFoundException e) {
throw new FilesystemResourceInitializationException(
"Failed to initialize the file extractor handler #" + getHashKey(), e);
}
}

/**
* Commands and Extract the specified filesystem to the specified destination filesystem.
* <p>
Expand Down Expand Up @@ -133,11 +152,21 @@ public void extract() throws IOException, FileNotFoundException {
}

@Override
public void close() throws IOException {
public void close() throws Exception {
if (fileOutputStream != null) {
fileOutputStream.close();
fileOutputStream = null;
}

// close the associated file locator resources
if (getFileLocator() != null && getFileLocator().getFileInputStream() != null) {
getFileLocator().close();
SnapLoaderLogger.log(Level.INFO, getClass().getName(), "close",
"Delegation for file locator resources closure has succeeded!");
}

SnapLoaderLogger.log(Level.INFO, getClass().getName(), "close",
"File extractor #" + getHashKey() + " resources closed!");
}

@Override
Expand Down
Loading

0 comments on commit 848115e

Please sign in to comment.