org.refcodes.decoupling.ext.application.ApplicationReactor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of refcodes-decoupling-ext-application Show documentation
Show all versions of refcodes-decoupling-ext-application Show documentation
Artifact extending the refcodes-decoupling artifact with out of the box
application functionality such as properties management (alongside profiles
support) and CLI support, an event bus (application bus) as well as lifecycle
management.
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany and licensed
// under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// -----------------------------------------------------------------------------
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// -----------------------------------------------------------------------------
// Apache License, v2.0 ("http://www.apache.org/licenses/LICENSE-2.0")
// -----------------------------------------------------------------------------
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////
package org.refcodes.decoupling.ext.application;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.ParseException;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.refcodes.cli.ArgsSyntaxException;
import org.refcodes.component.Initializable;
import org.refcodes.component.InitializeException;
import org.refcodes.component.StartException;
import org.refcodes.component.Startable;
import org.refcodes.component.StopException;
import org.refcodes.decoupling.AmbigousClaimException;
import org.refcodes.decoupling.AmbigousDependencyException;
import org.refcodes.decoupling.AmbigousFactoryException;
import org.refcodes.decoupling.AmbigousInitializerException;
import org.refcodes.decoupling.CircularDependencyException;
import org.refcodes.decoupling.Claim;
import org.refcodes.decoupling.Context;
import org.refcodes.decoupling.Dependency;
import org.refcodes.decoupling.DependencyBuilder;
import org.refcodes.decoupling.DuplicateClaimException;
import org.refcodes.decoupling.DuplicateDependencyException;
import org.refcodes.decoupling.FactoryClaim;
import org.refcodes.decoupling.InitializerClaim;
import org.refcodes.decoupling.InstallDependencyException;
import org.refcodes.decoupling.InstanceMode;
import org.refcodes.decoupling.Reactor;
import org.refcodes.decoupling.UnsatisfiedClaimException;
import org.refcodes.decoupling.UnsatisfiedDependencyException;
import org.refcodes.decoupling.UnsatisfiedFactoryException;
import org.refcodes.decoupling.UnsatisfiedInitializerException;
import org.refcodes.eventbus.ext.application.ApplicationBus;
import org.refcodes.exception.Trap;
import org.refcodes.properties.ProfileProperties;
import org.refcodes.properties.Properties;
import org.refcodes.properties.ext.application.ApplicationProperties;
import org.refcodes.properties.ext.application.ApplicationPropertiesAccessor;
import org.refcodes.runtime.ConfigLocator;
import org.refcodes.runtime.Execution;
/**
* The {@link ApplicationReactor} enables harnessing the
* {@link ApplicationProperties} alongside the {@link ApplicationProperties}
* profile support (as of {@link ProfileProperties#getRuntimeProfiles()}) by
* automatically placing an accordingly configured {@link ApplicationProperties}
* instance into the container and enabling it for injection. The
* {@link ApplicationProperties} {@link Dependency}'s alias is set to
* {@value #APPLICATION_PROPERTIES_ALIAS} (as of this class's constant
* {@link #APPLICATION_PROPERTIES_ALIAS}). Also if declared by a
* {@link Dependency}, an {@link ApplicationBus} singleton is provided for
* asynchronous communication between the components.
*/
public class ApplicationReactor extends Reactor implements ApplicationPropertiesAccessor {
// /////////////////////////////////////////////////////////////////////////
// STATICS:
// /////////////////////////////////////////////////////////////////////////
private static final Logger LOGGER = Logger.getLogger( ApplicationReactor.class.getName() );
// /////////////////////////////////////////////////////////////////////////
// CONSTANTS:
// /////////////////////////////////////////////////////////////////////////
/**
* The {@link ApplicationContext} {@link Dependency}'s alias to be used.
*/
public static final String APPLICATION_CONTEXT_ALIAS = "applicationContext";
/**
* The {@link ApplicationProperties} {@link Dependency}'s alias to be used.
*/
public static final String APPLICATION_PROPERTIES_ALIAS = "applicationProperties";
/**
* The {@link ApplicationBus} {@link Dependency}'s alias to be used.
*/
public static final String APPLICATION_BUS_ALIAS = "applicationBus";
/**
* The {@link ProfilesMode} determines how to handle implicit profiles
* information as provided by the {@link ApplicationProperties} instance
* (implicitly added as {@link Dependency} by the
* {@link ApplicationReactor}).
*/
public enum ProfilesMode {
/**
* None profile is being applied at all. Any profiles as being provided
* upon initialization to the according constructors by the
* {@link ApplicationProperties} (or any sub-type of the
* {@link ProfileProperties}) are ignored.
*/
NONE,
/**
* The profiles as being provided upon initialization to the according
* constructors by the {@link ApplicationProperties} are determined and
* used for the overall configuration. If {@link Properties} other(!)
* than a sub-type of the {@link ProfileProperties} (such as the
* {@link ApplicationProperties}) were provided manually, then
* determination of the profiles will result in none profiles (as of
* {@link #NONE}) being set!
*/
DETERMINED
}
// /////////////////////////////////////////////////////////////////////////
// VARIABLES:
// /////////////////////////////////////////////////////////////////////////
protected ApplicationProperties _properties;
// /////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS:
// /////////////////////////////////////////////////////////////////////////
/**
* Constructs a {@link ApplicationReactor} instance.
*/
public ApplicationReactor() {
_properties = new ApplicationProperties();
}
/**
* Constructs a {@link ApplicationReactor} instance.
*
* @param aProperties The {@link ApplicationProperties} to use as initial
* configuration.
*/
public ApplicationReactor( ApplicationProperties aProperties ) {
_properties = aProperties;
}
/**
* Create a {@link ApplicationReactor} using the provided
* {@link ApplicationProperties} instance.
*
* @param aInputStream The {@link InputStream} pointing to the properties to
* be loaded.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
*
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public ApplicationReactor( InputStream aInputStream ) throws IOException, ParseException {
final ApplicationProperties theProperties = new ApplicationProperties();
theProperties.withInputStream( aInputStream );
_properties = theProperties;
}
/**
* Create a {@link ApplicationReactor} using the provided
* {@link ApplicationProperties} instance.
*
* @param aInputStream The {@link InputStream} pointing to the properties to
* be loaded.
*
* @param aArgs The command line arguments to be evaluated.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
*
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
* @throws ArgsSyntaxException thrown in case of a command line arguments
* mismatch regarding provided and expected args.
*/
public ApplicationReactor( InputStream aInputStream, String[] aArgs ) throws IOException, ParseException, ArgsSyntaxException {
final ApplicationProperties theProperties = new ApplicationProperties();
theProperties.withInputStream( aInputStream );
theProperties.evalArgs( aArgs );
_properties = theProperties;
}
/**
* Create a {@link ApplicationReactor} using the provided
* {@link ApplicationProperties} instance.
*
* @param aUrl The {@link URL} pointing to the properties to be loaded.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
*
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public ApplicationReactor( URL aUrl ) throws IOException, ParseException {
final ApplicationProperties theProperties = new ApplicationProperties();
theProperties.withUrl( aUrl );
_properties = theProperties;
}
/**
* Create a {@link ApplicationReactor} using the provided
* {@link ApplicationProperties} instance.
*
* @param aUrl The {@link URL} pointing to the properties to be loaded.
*
* @param aArgs The command line arguments to be evaluated.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
*
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
* @throws ArgsSyntaxException thrown in case of a command line arguments
* mismatch regarding provided and expected args.
*/
public ApplicationReactor( URL aUrl, String[] aArgs ) throws IOException, ParseException, ArgsSyntaxException {
final ApplicationProperties theProperties = new ApplicationProperties();
theProperties.withUrl( aUrl );
theProperties.evalArgs( aArgs );
_properties = theProperties;
}
/**
* Create a {@link ApplicationReactor} using the provided
* {@link ApplicationProperties} instance.
*
* @param aFile The {@link File} pointing to the properties to be loaded.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
*
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public ApplicationReactor( File aFile ) throws IOException, ParseException {
final ApplicationProperties theProperties = new ApplicationProperties();
theProperties.withFile( aFile, ConfigLocator.APPLICATION_DIR );
_properties = theProperties;
}
/**
* Create a {@link ApplicationReactor} using the provided
* {@link ApplicationProperties} instance.
*
* @param aFile The {@link File} pointing to the properties to be loaded.
*
* @param aArgs The command line arguments to be evaluated.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
*
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
* @throws ArgsSyntaxException thrown in case of a command line arguments
* mismatch regarding provided and expected args.
*/
public ApplicationReactor( File aFile, String[] aArgs ) throws IOException, ParseException, ArgsSyntaxException {
final ApplicationProperties theProperties = new ApplicationProperties();
theProperties.withFile( aFile, ConfigLocator.APPLICATION_DIR );
theProperties.evalArgs( aArgs );
_properties = theProperties;
}
/**
* Create a {@link ApplicationReactor} using the provided
* {@link ApplicationProperties} instance.
*
* @param aFile The {@link File} pointing to the properties to be loaded.
*
* @param aConfigLocator The {@link ConfigLocator} to be used when seeking
* for the given {@link File}.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
*
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public ApplicationReactor( File aFile, ConfigLocator aConfigLocator ) throws IOException, ParseException {
final ApplicationProperties theProperties = new ApplicationProperties();
theProperties.withFile( aFile, aConfigLocator );
_properties = theProperties;
}
/**
* Create a {@link ApplicationReactor} using the provided
* {@link ApplicationProperties} instance.
*
* @param aFile The {@link File} pointing to the properties to be loaded.
* @param aConfigLocator The {@link ConfigLocator} to be used when seeking
* for the given {@link File}.
* @param aArgs the args
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
* @throws ArgsSyntaxException thrown in case of a command line arguments
* mismatch regarding provided and expected args.
*/
public ApplicationReactor( File aFile, ConfigLocator aConfigLocator, String[] aArgs ) throws IOException, ParseException, ArgsSyntaxException {
final ApplicationProperties theProperties = new ApplicationProperties();
theProperties.withFile( aFile, aConfigLocator );
theProperties.evalArgs( aArgs );
_properties = theProperties;
}
/**
* Create a {@link ApplicationReactor} using the provided
* {@link ApplicationProperties} instance.
*
* @param aFilePath The properties' file path pointing to the properties to
* be loaded.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
*
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public ApplicationReactor( String aFilePath ) throws IOException, ParseException {
final ApplicationProperties theProperties = new ApplicationProperties();
theProperties.withResourceClass( aFilePath, ConfigLocator.APPLICATION_DIR );
_properties = theProperties;
}
/**
* Create a {@link ApplicationReactor} using the provided
* {@link ApplicationProperties} instance.
*
* @param aFilePath The properties' file path pointing to the properties to
* be loaded.
*
* @param aArgs The command line arguments to be evaluated.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
*
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
* @throws ArgsSyntaxException thrown in case of a command line arguments
* mismatch regarding provided and expected args.
*/
public ApplicationReactor( String aFilePath, String[] aArgs ) throws IOException, ParseException, ArgsSyntaxException {
final ApplicationProperties theProperties = new ApplicationProperties();
theProperties.withResourceClass( aFilePath, ConfigLocator.APPLICATION_DIR );
theProperties.evalArgs( aArgs );
_properties = theProperties;
}
/**
* Create a {@link ApplicationReactor} using the provided
* {@link ApplicationProperties} instance.
*
* @param aFilePath The properties' file path pointing to the properties to
* be loaded.
*
* @param aConfigLocator The {@link ConfigLocator} to be used when seeking
* for the given {@link String}.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
*
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public ApplicationReactor( String aFilePath, ConfigLocator aConfigLocator ) throws IOException, ParseException {
final ApplicationProperties theProperties = new ApplicationProperties();
theProperties.withResourceClass( aFilePath, aConfigLocator );
_properties = theProperties;
}
/**
* Create a {@link ApplicationReactor} using the provided
* {@link ApplicationProperties} instance.
*
* @param aFilePath The properties' file path pointing to the properties to
* be loaded.
* @param aConfigLocator The {@link ConfigLocator} to be used when seeking
* for the given {@link String}.
* @param aArgs the args
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
* @throws ArgsSyntaxException thrown in case of a command line arguments
* mismatch regarding provided and expected args.
*/
public ApplicationReactor( String aFilePath, ConfigLocator aConfigLocator, String[] aArgs ) throws IOException, ParseException, ArgsSyntaxException {
final ApplicationProperties theProperties = new ApplicationProperties();
theProperties.withResourceClass( aFilePath, aConfigLocator );
theProperties.evalArgs( aArgs );
_properties = theProperties;
}
// /////////////////////////////////////////////////////////////////////////
// INJECTION:
// /////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////
// METHODS:
// /////////////////////////////////////////////////////////////////////////
/**
* Adds a specially fabricated {@link Dependency} to the {@link Reactor}
* which's {@link DependencyBuilder} is returned for fluently configuring
* your {@link Dependency}: The {@link Dependency} will be initialized by
* default by the {@link ApplicationReactor} instance's underlying
* {@link Properties} instance (being instantiated by the
* {@link ApplicationReactor}).
*
* This is a shortcut for configuring and applying a {@link FactoryClaim}
* with the according {@link Properties} to your {@link Dependency}:
*
*
* addDependency( aType ).withFactory( Properties.class, ( p ) -> p.toType( aType ), "applicationProperties" );
*
*
* @param The type of the {@link Dependency}.
*
* @param aType The type of the {@link Dependency}.
*
* @return An instance of the {@link DependencyBuilder} class which is used
* to fluently configure your {@link Dependency}.
*/
public DependencyBuilder addConfiguration( Class aType ) {
final DependencyBuilder theBuilder = new DependencyBuilder<>( aType ).withFactory( Properties.class, ( p ) -> p.toType( aType ), APPLICATION_PROPERTIES_ALIAS );
_dependencies.add( theBuilder );
return theBuilder;
}
/**
* Adds a specially fabricated {@link Dependency} to the {@link Reactor}
* which's {@link DependencyBuilder} is returned for fluently configuring
* your {@link Dependency}: The {@link Dependency} will be initialized by
* default by the {@link ApplicationReactor} instance's underlying
* {@link Properties} instance (being instantiated by the
* {@link ApplicationReactor}).
*
* This is a shortcut for configuring and applying a {@link FactoryClaim}
* with the according {@link Properties} to your {@link Dependency}:
*
*
* addDependency( aType ).withFactory( Properties.class, ( p ) -> p.toType( "service.datasource", aType ), "applicationProperties" );
*
*
* @param The type of the {@link Dependency}.
*
* @param aType The type of the {@link Dependency}.
*
* @param aNamespace The namespace within the {@link Properties} managed by
* the {@link ApplicationReactor}. The namespace can be regarded a
* property key's prefix.
*
* @return An instance of the {@link DependencyBuilder} class which is used
* to fluently configure your {@link Dependency}.
*/
public DependencyBuilder addConfiguration( Class aType, String aNamespace ) {
final DependencyBuilder theBuilder = new DependencyBuilder<>( aType ).withFactory( Properties.class, ( p ) -> p.toType( aNamespace, aType ), APPLICATION_PROPERTIES_ALIAS );
_dependencies.add( theBuilder );
return theBuilder;
}
/**
* Adds a specially fabricated {@link Dependency} to the {@link Reactor}
* which's {@link DependencyBuilder} is returned for fluently configuring
* your {@link Dependency}: The {@link Dependency} will be initialized by
* default by the {@link ApplicationReactor} instance's underlying
* {@link Properties} instance (being instantiated by the
* {@link ApplicationReactor}).
*
* This is a shortcut for configuring and applying a {@link FactoryClaim}
* with the according {@link Properties} to your {@link Dependency}:
*
*
* addDependency( aType ).withFactory( Properties.class, ( p ) -> p.toType( "service.datasource", aType ), "applicationProperties" );
*
*
* @param The type of the {@link Dependency}.
*
* @param aType The type of the {@link Dependency}.
*
* @param aNamespace The namespace within the {@link Properties} managed by
* the {@link ApplicationReactor}. The namespace can be regarded a
* property key's prefix.
*
* @return An instance of the {@link DependencyBuilder} class which is used
* to fluently configure your {@link Dependency}.
*/
public DependencyBuilder addConfiguration( Class aType, Object aNamespace ) {
final DependencyBuilder theBuilder = new DependencyBuilder<>( aType ).withFactory( Properties.class, ( p ) -> p.toType( aNamespace, aType ), APPLICATION_PROPERTIES_ALIAS );
_dependencies.add( theBuilder );
return theBuilder;
}
/**
* Adds a specially fabricated {@link Dependency} to the {@link Reactor}
* which's {@link DependencyBuilder} is returned for fluently configuring
* your {@link Dependency}: The {@link Dependency} will be initialized by
* default by the {@link ApplicationReactor} instance's underlying
* {@link Properties} instance (being instantiated by the
* {@link ApplicationReactor}).
*
* This is a shortcut for configuring and applying a {@link FactoryClaim}
* with the according {@link Properties} to your {@link Dependency}:
*
*
* addDependency( aType ).withFactory( Properties.class, ( p ) -> p.toType( aType. "service", "datasource" ), "applicationProperties" );
*
*
* @param The type of the {@link Dependency}.
*
* @param aType The type of the {@link Dependency}.
*
* @param aNamespaceElements The namespace elements denoting the namespace
* (not requiring denoting any delimiters separating the namespace
* elements from each other) within the {@link Properties} managed by
* the {@link ApplicationReactor}. The namespace can be regarded a
* property key's prefix.
*
* @return An instance of the {@link DependencyBuilder} class which is used
* to fluently configure your {@link Dependency}.
*/
public DependencyBuilder addConfiguration( Class aType, String... aNamespaceElements ) {
final DependencyBuilder theBuilder = new DependencyBuilder<>( aType ).withFactory( Properties.class, ( p ) -> p.toType( aType, aNamespaceElements ), APPLICATION_PROPERTIES_ALIAS );
_dependencies.add( theBuilder );
return theBuilder;
}
/**
* Adds a specially fabricated {@link Dependency} to the {@link Reactor}
* which's {@link DependencyBuilder} is returned for fluently configuring
* your {@link Dependency}: The {@link Dependency} will be initialized by
* default by the {@link ApplicationReactor} instance's underlying
* {@link Properties} instance (being instantiated by the
* {@link ApplicationReactor}).
*
* This is a shortcut for configuring and applying a {@link FactoryClaim}
* with the according {@link Properties} to your {@link Dependency}:
*
*
* addDependency( aType ).withFactory( Properties.class, ( p ) -> p.toType( aType. "service", "datasource" ), "applicationProperties" );
*
*
* @param The type of the {@link Dependency}.
*
* @param aType The type of the {@link Dependency}.
*
* @param aNamespaceElements The namespace elements denoting the namespace
* (not requiring denoting any delimiters separating the namespace
* elements from each other) within the {@link Properties} managed by
* the {@link ApplicationReactor}. The namespace can be regarded a
* property key's prefix.
*
* @return An instance of the {@link DependencyBuilder} class which is used
* to fluently configure your {@link Dependency}.
*/
public DependencyBuilder addConfiguration( Class aType, Object... aNamespaceElements ) {
final DependencyBuilder theBuilder = new DependencyBuilder<>( aType ).withFactory( Properties.class, ( p ) -> p.toType( aType, aNamespaceElements ), APPLICATION_PROPERTIES_ALIAS );
_dependencies.add( theBuilder );
return theBuilder;
}
/**
* Adds a specially fabricated {@link Dependency} to the {@link Reactor}
* which's {@link DependencyBuilder} is returned for fluently configuring
* your {@link Dependency}: The {@link Dependency} will be initialized by
* default by the {@link ApplicationReactor} instance's underlying
* {@link Properties} instance (being instantiated by the
* {@link ApplicationReactor}).
*
* This is a shortcut for configuring and applying a {@link FactoryClaim}
* with the according {@link Properties} to your {@link Dependency}:
*
*
* addDependency( aType ).withFactory( Properties.class, ( p ) -> p.toType( aType. someNameSpaceList ), "applicationProperties" );
*
*
* @param The type of the {@link Dependency}.
*
* @param aType The type of the {@link Dependency}.
*
* @param aNamespaceElements The namespace elements denoting the namespace
* (not requiring denoting any delimiters separating the namespace
* elements from each other) within the {@link Properties} managed by
* the {@link ApplicationReactor}. The namespace can be regarded a
* property key's prefix.
*
* @return An instance of the {@link DependencyBuilder} class which is used
* to fluently configure your {@link Dependency}.
*/
public DependencyBuilder addConfiguration( Class aType, Collection> aNamespaceElements ) {
final DependencyBuilder theBuilder = new DependencyBuilder<>( aType ).withFactory( Properties.class, ( p ) -> p.toType( aNamespaceElements, aType ), APPLICATION_PROPERTIES_ALIAS );
_dependencies.add( theBuilder );
return theBuilder;
}
/**
* {@inheritDoc}
*
* Uses the profiles as provided by the {@link Properties} initialized with
* as of the according constructors.
*/
@Override
public ApplicationContext createContext() throws AmbigousDependencyException, UnsatisfiedDependencyException, CircularDependencyException, DuplicateDependencyException, DuplicateClaimException, UnsatisfiedClaimException, AmbigousClaimException, AmbigousInitializerException, UnsatisfiedInitializerException, AmbigousFactoryException, UnsatisfiedFactoryException, InstallDependencyException {
return createContext( toProfiles() );
}
/**
* {@inheritDoc}
*/
@Override
public ApplicationContext createContext( String... aProfiles ) throws AmbigousDependencyException, UnsatisfiedDependencyException, CircularDependencyException, DuplicateDependencyException, DuplicateClaimException, UnsatisfiedClaimException, AmbigousClaimException, AmbigousInitializerException, UnsatisfiedInitializerException, AmbigousFactoryException, UnsatisfiedFactoryException, InstallDependencyException {
return createContext( (Object[]) aProfiles );
}
/**
* Creates the {@link ApplicationContext} and invokes the
* {@link Initializable#initialize()} methods before invoking the
* {@link Startable#start()} methods on all dependencies' instances. The
* {@link ApplicationContext} returned then is in lifecycle status
* {@link ApplicationContext#isRunning()}.
*
* @param aProfilesMode the {@link ProfilesMode} determining on how to
* handle implicit profiles information as provided by the
* {@link ApplicationProperties} instance (implicitly added as
* {@link Dependency} by the {@link ApplicationReactor}).
*
* @return The accordingly created {@link ApplicationContext} instance.
*
* @throws AmbigousDependencyException is thrown in case for a required
* {@link Dependency} there are more than one matching
* {@link Dependency} candidates in the {@link Reactor}.
* @throws UnsatisfiedDependencyException is thrown in case for a required
* {@link Dependency} none matching {@link Dependency} candidates in
* the {@link Reactor} have been found (taking the profiles applied
* into account) for the constructors of the given
* {@link Dependency}.
* @throws CircularDependencyException is thrown in case there is some
* (transitive) circular dependency between two {@link Dependency}
* instances.
* @throws DuplicateDependencyException is thrown in case there are multiple
* identical dependencies applicable by the {@link Reactor}.
* @throws DuplicateClaimException is thrown in case there are multiple
* identical claims declared by a {@link Dependency}.
* @throws UnsatisfiedClaimException is thrown in case a {@link Claim}
* instance cannot be satisfied by any known {@link Dependency}
* instance.
* @throws AmbigousClaimException is thrown in case one {@link Claim} can be
* matched by multiple dependencies.
* @throws AmbigousInitializerException is thrown in case one
* {@link InitializerClaim} instance can be matched by multiple
* dependencies.
* @throws UnsatisfiedInitializerException is thrown in case a
* {@link InitializerClaim} instance cannot be satisfied by any
* known {@link Dependency} instance.
* @throws AmbigousFactoryException is thrown in case one
* {@link FactoryClaim} instance can be matched by multiple
* dependencies.
* @throws UnsatisfiedFactoryException is thrown in case a
* {@link FactoryClaim} instance cannot be satisfied by any known
* {@link Dependency} instance.
* @throws InstallDependencyException is thrown when trying to install a
* {@link Dependency} into the {@link Context}, though installing
* failed die to the dependency throwing an exception during the
* process of installing (e.g. instantiation).
*/
public ApplicationContext createContext( ProfilesMode aProfilesMode ) throws AmbigousDependencyException, UnsatisfiedDependencyException, CircularDependencyException, DuplicateDependencyException, DuplicateClaimException, UnsatisfiedClaimException, AmbigousClaimException, AmbigousInitializerException, UnsatisfiedInitializerException, AmbigousFactoryException, UnsatisfiedFactoryException, InstallDependencyException {
Object[] theProfiles = {};
if ( aProfilesMode == ProfilesMode.DETERMINED ) {
theProfiles = toProfiles();
}
return createContext( theProfiles );
}
/**
* {@inheritDoc}
*/
@Override
public ApplicationContext createContext( Object... aProfiles ) throws AmbigousDependencyException, UnsatisfiedDependencyException, CircularDependencyException, DuplicateDependencyException, DuplicateClaimException, UnsatisfiedClaimException, AmbigousClaimException, AmbigousInitializerException, UnsatisfiedInitializerException, AmbigousFactoryException, UnsatisfiedFactoryException, InstallDependencyException {
String[] theProfiles = {};
if ( aProfiles != null && aProfiles.length != 0 ) {
theProfiles = new String[aProfiles.length];
for ( int i = 0; i < theProfiles.length; i++ ) {
theProfiles[i] = aProfiles[i] != null ? aProfiles[i].toString() : null;
}
}
addDependency( _properties.toRuntimeProfile( theProfiles ) ).withAlias( APPLICATION_PROPERTIES_ALIAS ).withInstanceMetrics( InstanceMode.SINGLETON_BY_DEFAULT ).withProfiles( aProfiles );
try {
addDependency( ApplicationBus.class ).withAlias( APPLICATION_BUS_ALIAS ).withInstanceMetrics( InstanceMode.SINGLETON_ON_DEMAND ).withProfiles( aProfiles );
}
catch ( Exception | Error ignore ) {
// The "refcodes-eventbus-ext-application" dependency is optional!
}
final ApplicationContext theCtx = (ApplicationContext) super.createContext( aProfiles );
addDependency( theCtx ).withAlias( APPLICATION_CONTEXT_ALIAS ).withInstanceMetrics( InstanceMode.SINGLETON_BY_DEFAULT ).withProfiles( aProfiles );
initialize( theCtx );
start( theCtx );
final Thread theHook = new Thread( () -> {
try {
theCtx.stop();
}
catch ( StopException e ) {
LOGGER.log( Level.WARNING, "Cannot (completely) stop the context as of: " + e.toMessage(), e );
}
try {
theCtx.destroy();
}
catch ( RuntimeException e ) {
LOGGER.log( Level.WARNING, "Cannot (completely) destroy the context as of: " + Trap.asMessage( e ), e );
}
} );
theHook.setDaemon( true );
Execution.addShutdownHook( theHook );
return theCtx;
}
/**
* Retrieves the initial properties (configuration) represented by this
* {@link ApplicationProperties} instance.
*
* @return The according initial configuration.
*/
@Override
public ApplicationProperties getApplicationProperties() {
return _properties;
}
// /////////////////////////////////////////////////////////////////////////
// HOOKS:
// /////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
@Override
protected ApplicationContext toContext( Object[] aProfiles ) {
final ApplicationContext theCtx = new ApplicationContext( aProfiles );
addDependency( theCtx ).withAlias( APPLICATION_CONTEXT_ALIAS ).withInstanceMetrics( InstanceMode.SINGLETON_BY_DEFAULT ).withProfiles( aProfiles );
return theCtx;
}
// /////////////////////////////////////////////////////////////////////////
// HELPER:
// /////////////////////////////////////////////////////////////////////////
private void initialize( ApplicationContext aCtx ) throws InstallDependencyException {
try {
aCtx.doInitialize();
}
catch ( InitializeException e ) {
throw new IllegalStateException( "Cannot initialize the application context!", e );
}
for ( Object eObj : aCtx.getInstances() ) {
if ( eObj instanceof Initializable eComponent && eComponent != aCtx ) {
try {
eComponent.initialize();
}
catch ( InitializeException e ) {
final Dependency> theDependency = aCtx.getDependencyByInstance( eComponent );
throw new InstallDependencyException( "Cannot initialize the dependency <{0}>!", theDependency, e );
}
}
}
}
private void start( ApplicationContext aCtx ) throws InstallDependencyException {
try {
aCtx.doStart();
}
catch ( StartException e ) {
throw new IllegalStateException( "Cannot start the application context!", e );
}
for ( Object eObj : aCtx.getInstances() ) {
if ( eObj instanceof Startable eComponent && eComponent != aCtx ) {
try {
eComponent.start();
}
catch ( StartException e ) {
final Dependency> theDependency = aCtx.getDependencyByInstance( eComponent );
throw new InstallDependencyException( "Cannot start the dependency <{0}>!", theDependency, e );
}
}
}
}
private Object[] toProfiles() {
return _properties instanceof ProfileProperties ? ((ProfileProperties) _properties).getRuntimeProfiles() : new Object[] {};
}
// /////////////////////////////////////////////////////////////////////////
// INNER CLASSES:
// /////////////////////////////////////////////////////////////////////////
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy