Architectural overview and configuration

Burningwave Core is based on the concept of component and component container. A component is a dynamic object that perform functionality related to the domain it belong to. A component container contains a set of dynamic components and could be of two types:

  • static component container
  • dynamic component container

More than one dynamic container can be created, while only one static container can exists.

Static component container

It is represented by the org.burningwave.core.assembler.StaticComponentContainer class that provides the following fields for each component supplied:

public static final org.burningwave.core.concurrent.QueuedTasksExecutor.Group BackgroundExecutor;
public static final org.burningwave.core.classes.PropertyAccessor ByFieldOrByMethodPropertyAccessor;
public static final org.burningwave.core.classes.PropertyAccessor ByMethodOrByFieldPropertyAccessor;
public static final org.burningwave.core.jvm.LowLevelObjectsHandler.ByteBufferHandler ByteBufferHandler;
public static final org.burningwave.core.Cache Cache;
public static final org.burningwave.core.classes.Classes Classes;
public static final org.burningwave.core.classes.Classes.Loaders ClassLoaders;
public static final org.burningwave.core.classes.Constructors Constructors;
public static final org.burningwave.core.io.FileSystemHelper FileSystemHelper;
public static final org.burningwave.core.classes.Fields Fields;
public static final org.burningwave.core.iterable.Properties GlobalProperties;
public static final org.burningwave.core.iterable.IterableObjectHelper IterableObjectHelper;
public static final org.burningwave.core.jvm.JVMInfo JVMInfo;
public static final org.burningwave.core.jvm.LowLevelObjectsHandler LowLevelObjectsHandler;
public static final org.burningwave.core.ManagedLogger.Repository ManagedLoggersRepository;
public static final org.burningwave.core.classes.Members Members;
public static final org.burningwave.core.classes.Methods Methods;
public static final org.burningwave.core.Objects Objects;
public static final org.burningwave.core.Strings.Paths Paths;
public static final org.burningwave.core.io.Resources Resources;
public static final org.burningwave.core.io.Streams Streams;
public static final org.burningwave.core.classes.SourceCodeHandler SourceCodeHandler;
public static final org.burningwave.core.Strings Strings;
public static final org.burningwave.core.Throwables Throwables;

… That can be used within your application, simply adding a static import to your compilation unit, i.e.:

package org.burningwave.core.examples.staticcomponents;

import static org.burningwave.core.assembler.StaticComponentContainer.ClassLoaders;
import static org.burningwave.core.assembler.StaticComponentContainer.ManagedLoggersRepository;

public class UseOfStaticComponentsExample {
    
    public void yourMethod(){
        ManagedLoggersRepository.logInfo(UseOfStaticComponentsExample.class, "Master class loader is {}", ClassLoaders.getMaster(Thread.currentThread().getContextClassLoader()));
    }

}

Configuration

The configuration of this type of container is done via burningwave.static.properties file or via burningwave.static.default.properties file: the library searches for the first file and if it does not find it, then it searches for the second file and if neither this one is found then the library sets the default configuration programmatically. The default configuration loaded programmatically if no configuration file is found is the following:

#With this value the library will search if org.slf4j.Logger is present and, in this case,
#the SLF4JManagedLoggerRepository will be instantiated, otherwise the SimpleManagedLoggerRepository will be instantiated
managed-logger.repository=autodetect
#to increase performance set it to false
managed-logger.repository.enabled=true
static-component-container.clear-temporary-folder-on-init=false
static-component-container.hide-banner-on-init=false
streams.default-buffer-size=1024
streams.default-byte-buffer-allocation-mode=ByteBuffer::allocateDirect

If in your custom burningwave.static.properties or burningwave.static.default.properties file one of this default properties is not found, the relative default value here in the box above is assumed. Here an example of a burningwave.static.properties file with all configurable properties:

#other possible values are: autodetect, org.burningwave.core.SimpleManagedLoggerRepository
managed-logger.repository=org.burningwave.core.SLF4JManagedLoggerRepository
#to increase performance set it to false
managed-logger.repository.enabled=true
managed-logger.repository.logging.debug.disabled-for=\
    org.burningwave.core.io.FileSystemItem;\
    org.burningwave.core.classes.PathMemoryClassLoader;\
    org.burningwave.core.classes.MemoryClassLoader;
streams.default-buffer-size=0.5Kb
#other possible value is ByteBuffer::allocate
streams.default-byte-buffer-allocation-mode=ByteBuffer::allocateDirect
static-component-container.clear-temporary-folder-on-init=true
static-component-container.hide-banner-on-init=false

Dynamic component container

It is represented by the org.burningwave.core.assembler.ComponentContainer class that provides the following methods for each component supplied:

public ByteCodeHunter getByteCodeHunter();
public ClassFactory getClassFactory();
public ClassHunter getClassHunter();
public ClassPathHunter getClassPathHelper();
public ClassPathHunter getClassPathHunter();
public CodeExecutor getCodeExecutor();
public FunctionalInterfaceFactory getFunctionalInterfaceFactory();
public JavaMemoryCompiler getJavaMemoryCompiler();
public PathHelper getPathHelper();
public PathScannerClassLoader getPathScannerClassLoader();

… That can be used within your application, simply as follow:

package org.burningwave.core.examples.componentcontainer;

import org.burningwave.core.assembler.ComponentContainer;
import org.burningwave.core.assembler.ComponentSupplier;
import org.burningwave.core.classes.ClassFactory;
import org.burningwave.core.classes.ClassHunter;
import org.burningwave.core.io.PathHelper;
import org.burningwave.core.iterable.Properties;

public class RetrievingDynamicComponentContainerAndComponents {

    public static void execute() throws Throwable {
        //In this case we are retrieving the singleton component container instance
        ComponentSupplier componentSupplier = ComponentContainer.getInstance();
        
        //In this case we are creating a component container by using a custom configuration file
        ComponentSupplier customComponentSupplier = ComponentContainer.create("your-custom-properties-file.properties");
        
        //In this case we are creating a component container programmatically by using a custom properties object
        Properties configProps = new Properties();
        configProps.put(ClassFactory.Configuration.Key.DEFAULT_CLASS_LOADER, Thread.currentThread().getContextClassLoader());
        configProps.put(ClassHunter.Configuration.Key.DEFAULT_PATH_SCANNER_CLASS_LOADER, componentSupplier.getPathScannerClassLoader());
        ComponentSupplier customComponentSupplier2 = ComponentContainer.create(configProps);
        
        PathHelper pathHelper = componentSupplier.getPathHelper();
        ClassFactory classFactory = customComponentSupplier.getClassFactory();
        ClassHunter classHunter = customComponentSupplier2.getClassHunter();
       
    }   
    
}

Configuration

The configuration of this type of container can be done via Properties file or programmatically via a Properties object. If you use the singleton instance obtained via ComponentContainer.getInstance() method, you must create a burningwave.properties file and put it on base path of your classpath project. The default configuration automatically loaded if no configuration file is found is the following:

class-factory.byte-code-hunter.search-config.check-file-option=\
    ${hunters.default-search-config.check-file-option}
#default classloader used by the ClassFactory to load generated classes
class-factory.default-class-loader=\
    (Supplier<ClassLoader>)() -> ((ComponentSupplier)parameter[0]).getPathScannerClassLoader()
#This variable is empty by default and can be valorized by developer and it is
#included by 'class-factory.default-class-loader.imports' property
class-factory.default-class-loader.additional-imports=
class-factory.default-class-loader.imports=\  
    ${class-factory.default-class-loader.additional-imports};\
    org.burningwave.core.assembler.ComponentSupplier;\
    java.util.function.Function;\
    org.burningwave.core.io.FileSystemItem;\
    org.burningwave.core.classes.PathScannerClassLoader;\
    java.util.function.Supplier;
class-factory.default-class-loader.name=\
    org.burningwave.core.classes.DefaultClassLoaderRetrieverForClassFactory
class-hunter.default-path-scanner-class-loader=\
    (Supplier<PathScannerClassLoader>)() -> ((ComponentSupplier)parameter[0]).getPathScannerClassLoader()
#This variable is empty by default and can be valorized by developer and it is
#included by 'class-hunter.default-path-scanner-class-loader.imports' property
class-hunter.default-path-scanner-class-loader.additional-imports=
class-hunter.default-path-scanner-class-loader.imports=\
    ${class-hunter.default-path-scanner-class-loader.additional-imports};\
    org.burningwave.core.assembler.ComponentSupplier;\
    org.burningwave.core.io.FileSystemItem;\
    org.burningwave.core.classes.PathScannerClassLoader;\
    java.util.function.Supplier;
class-hunter.default-path-scanner-class-loader.name=\
    org.burningwave.core.classes.DefaultPathScannerClassLoaderRetrieverForClassHunter
class-hunter.new-isolated-path-scanner-class-loader.search-config.check-file-option=\
    ${hunters.default-search-config.check-file-option}
class-path-helper.class-path-hunter.search-config.check-file-option=\
    ${hunters.default-search-config.check-file-option}
hunters.default-search-config.check-file-option=\
    ${path-scanner-class-loader.search-config.check-file-option}
hunters.path-loading-lock=forPath
path-scanner-class-loader.parent=\
    Thread.currentThread().getContextClassLoader()
path-scanner-class-loader.parent.imports=\
    ${path-scanner-class-loader.parent.additional-imports};\
    org.burningwave.core.assembler.ComponentSupplier;\
    org.burningwave.core.io.FileSystemItem;\
    org.burningwave.core.classes.PathScannerClassLoader;\
    java.util.function.Supplier;
path-scanner-class-loader.parent.name=\
    org.burningwave.core.classes.ParentClassLoaderRetrieverForPathScannerClassLoader
#other possible values are: checkFileName, checkFileName|checkFileSignature, checkFileName&checkFileSignature
path-scanner-class-loader.search-config.check-file-option=checkFileName
#This variable is empty by default and can be valorized by developer and it is
#included by 'paths.class-factory.default-class-loader.class-repositories' property
paths.class-factory.default-class-loader.additional-class-repositories=
#this variable indicates all the paths from which the classes 
#must be taken if during the definition of the compiled classes
#on classloader there will be classes not found
paths.class-factory.default-class-loader.class-repositories=
    ${paths.java-memory-compiler.class-paths};\
    ${paths.java-memory-compiler.class-repositories};\
    ${paths.class-factory.default-class-loader.additional-class-repositories}
paths.hunters.default-search-config.paths=\
    ${paths.main-class-paths};\
    ${paths.main-class-paths.extension};\
    ${paths.main-class-repositories};
#This variable is empty by default and can be valorized by developer and it is
#included by 'paths.paths.java-memory-compiler.class-paths' property
paths.java-memory-compiler.additional-class-paths=
#this variable indicates all the class paths used by the JavaMemoryCompiler
#component for compiling
paths.java-memory-compiler.class-paths=\
    ${paths.main-class-paths};\
    ${paths.main-class-paths.extension};\
    ${paths.java-memory-compiler.additional-class-paths}
#This variable is empty by default and can be valorized by developer. and it is
#included by 'paths.java-memory-compiler.class-repositories' property
paths.java-memory-compiler.additional-class-repositories=
#All paths inserted here will be analyzed by JavaMemoryCompiler component in case 
#of compilation failure to search for class paths of all classes imported by sources 
paths.java-memory-compiler.class-repositories=\
    ${paths.main-class-repositories};\
    ${paths.java-memory-compiler.additional-class-repositories};
paths.main-class-paths=${system.properties:java.class.path}
paths.main-class-paths.extension=\
    //${system.properties:java.home}/lib//children:.*?\.jar;\
    //${system.properties:java.home}/lib/ext//children:.*?\.jar;
paths.main-class-repositories=//${system.properties:java.home}/jmods//children:.*?\.jmod;

If in your custom burningwave.properties file one of this default properties is not found, the relative default value here in the box above is assumed.

If you create a component container instance through method ComponentContainer.create(String relativeConfigFileName), you can specify the file name of your properties file and you can locate it everywhere in your classpath project but remember to use a relative path in this case, i.e.: if you name your file “custom-config-file.properties” and put it in package “org.burningwave” you must create the component container as follow:

ComponentContainer.create("org/burningwave/custom-config-file.properties")

Here an example of a burningwave.properties file with all configurable properties :

class-factory.byte-code-hunter.search-config.check-file-option=\
    checkFileName&checkFileSignature
class-factory.default-class-loader.parent=Thread.currentThread().getContextClassLoader()
class-factory.default-class-loader=PathScannerClassLoader.create(\
    ${class-factory.default-class-loader.parent},\
    ((ComponentSupplier)parameter[0]).getPathHelper(),\
    FileSystemItem.Criteria.forClassTypeFiles(\
        FileSystemItem.CheckingOption.FOR_NAME\
    )\
)
class-factory.default-class-loader.additional-imports=java.util.function.Consumer;
class-factory.default-class-loader.imports=\
    ${class-factory.default-class-loader.additional-imports};\
    org.burningwave.core.assembler.ComponentSupplier;\
    java.util.function.Function;\
    org.burningwave.core.io.FileSystemItem;\
    org.burningwave.core.classes.PathScannerClassLoader;\
    java.util.function.Supplier;
class-factory.default-class-loader.name=\
    org.burningwave.core.classes.DefaultClassLoaderRetrieverForClassFactory
class-hunter.default-path-scanner-class-loader=\
    (Supplier<PathScannerClassLoader>)() -> ((ComponentSupplier)parameter[0]).getPathScannerClassLoader()
class-hunter.default-path-scanner-class-loader.additional-imports=java.util.function.Consumer;
class-hunter.default-path-scanner-class-loader.imports=\
    ${class-hunter.default-path-scanner-class-loader.additional-imports};\
    org.burningwave.core.assembler.ComponentSupplier;\
    org.burningwave.core.io.FileSystemItem;\
    org.burningwave.core.classes.PathScannerClassLoader;\
    java.util.function.Supplier;
class-hunter.default-path-scanner-class-loader.name=\
    org.burningwave.core.classes.DefaultPathScannerClassLoaderRetrieverForClassHunter
class-hunter.new-isolated-path-scanner-class-loader.search-config.check-file-option=\
    ${hunters.default-search-config.check-file-option}
class-path-helper.class-path-hunter.search-config.check-file-option=\
    ${hunters.default-search-config.check-file-option}
hunters.default-search-config.check-file-option=\
    ${path-scanner-class-loader.search-config.check-file-option}
hunters.path-loading-lock=forPath
path-scanner-class-loader.parent=\
    Thread.currentThread().getContextClassLoader()
path-scanner-class-loader.parent.imports=\
    ${path-scanner-class-loader.parent.additional-imports};\
    org.burningwave.core.assembler.ComponentSupplier;\
    org.burningwave.core.io.FileSystemItem;\
    org.burningwave.core.classes.PathScannerClassLoader;\
    java.util.function.Supplier;
path-scanner-class-loader.parent.name=\
    org.burningwave.core.classes.ParentClassLoaderRetrieverForPathScannerClassLoader
path-scanner-class-loader.search-config.check-file-option=checkFileName
paths.class-factory.default-class-loader.class-repositories=
    ${paths.java-memory-compiler.class-paths};\
    ${paths.java-memory-compiler.class-repositories};\
    ${paths.class-factory.default-class-loader.additional-class-repositories}
paths.hunters.default-search-config.paths=\
    ${paths.main-class-paths};\
    ${paths.main-class-paths.extension};\
    ${paths.main-class-repositories};
paths.java-memory-compiler.class-paths=\
    ${paths.main-class-paths};\
    ${paths.main-class-paths.extension};\
    ${paths.java-memory-compiler.additional-class-paths}
paths.java-memory-compiler.class-repositories=\
    ${paths.main-class-repositories};\
    ${paths.java-memory-compiler.additional-class-repositories};
paths.main-class-paths=${system.properties:java.class.path}
paths.main-class-paths.extension=\
    //${system.properties:java.home}/lib//children:.*?\.jar;\
    //${system.properties:java.home}/lib/ext//children:.*?\.jar;
paths.main-class-repositories=//${system.properties:java.home}/jmods//children:.*?\.jmod;
paths.java-memory-compiler.additional-class-paths=\
    C:/some paths 1/some library 1.jar;\
    C:/some paths 2/some library 2.jar;
paths.java-memory-compiler.additional-class-repositories=\
    C:/some paths 3;\
    C:/some paths 4;
paths.class-factory.default-class-loader.additional-class-repositories=\
    C:/some paths 5;\
    C:/some paths 6;