All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.refcodes.properties.ext.application.ApplicationProperties Maven / Gradle / Ivy

// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany, distributed
// on an "AS IS" BASIS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, and licen-
// sed 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/TEXT-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.properties.ext.application;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import org.refcodes.cli.ArgsFilter;
import org.refcodes.cli.ArgsSyntaxException;
import org.refcodes.cli.Condition;
import org.refcodes.cli.Example;
import org.refcodes.cli.Operand;
import org.refcodes.cli.ParseArgs;
import org.refcodes.cli.SyntaxMetrics;
import org.refcodes.cli.SyntaxNotation;
import org.refcodes.cli.Term;
import org.refcodes.data.AsciiColorPalette;
import org.refcodes.exception.BugException;
import org.refcodes.mixin.SecretAccessor.SecretBuilder;
import org.refcodes.mixin.SecretAccessor.SecretMutator;
import org.refcodes.properties.AbstractPropertiesDecorator;
import org.refcodes.properties.DocumentMetrics;
import org.refcodes.properties.EnvironmentProperties;
import org.refcodes.properties.PolyglotPropertiesBuilder.PolyglotPropertiesBuilderFactory;
import org.refcodes.properties.ProfileProperties;
import org.refcodes.properties.ProfilePropertiesProjection;
import org.refcodes.properties.Properties;
import org.refcodes.properties.PropertiesBuilderImpl;
import org.refcodes.properties.PropertiesPrecedence.PropertiesPrecedenceBuilder;
import org.refcodes.properties.PropertiesPrecedenceBuilderComposite;
import org.refcodes.properties.PropertiesPrecedenceComposite;
import org.refcodes.properties.ReloadMode;
import org.refcodes.properties.ResourceLoaderBuilder;
import org.refcodes.properties.ResourceProperties;
import org.refcodes.properties.SystemProperties;
import org.refcodes.properties.ext.cli.ArgsParserProperties;
import org.refcodes.properties.ext.cli.ArgsParserPropertiesAccessor;
import org.refcodes.properties.ext.cli.ParseArgsProperties;
import org.refcodes.properties.ext.obfuscation.ObfuscationProperties;
import org.refcodes.properties.ext.obfuscation.ObfuscationPropertiesBuilderDecorator;
import org.refcodes.properties.ext.obfuscation.ObfuscationPropertiesDecorator;
import org.refcodes.properties.ext.obfuscation.ObfuscationResourceProperties.ObfuscationResourcePropertiesBuilder;
import org.refcodes.properties.ext.obfuscation.ObfuscationResourcePropertiesBuilderDecorator;
import org.refcodes.runtime.ConfigLocator;
import org.refcodes.runtime.Execution;
import org.refcodes.runtime.SystemContext;
import org.refcodes.security.DecryptionException;
import org.refcodes.security.EncryptionException;
import org.refcodes.security.alt.chaos.ChaosKey;
import org.refcodes.security.alt.chaos.ChaosTextDecrypter;
import org.refcodes.security.alt.chaos.ChaosTextEncrypter;
import org.refcodes.textual.Font;
import org.refcodes.textual.SecretHintBuilder;
import org.refcodes.textual.TextBoxGrid;
import org.refcodes.textual.TextBoxStyle;

/**
 * {@link ApplicationProperties} are composed of various {@link Properties}
 * flavors such as {@link ParseArgsProperties}, {@link SystemProperties},
 * {@link EnvironmentProperties} and {@link ResourceProperties} with a
 * precedence in this order, encapsulated by a
 * {@link ProfilePropertiesProjection} in order for you, the developer, to
 * conveniently harness the power of the {@link Properties} functionality. You
 * may also add a {@link Properties} instance programmatically to manually
 * provide properties (via {@link #withProperties(Properties)}). The later you
 * add {@link Properties}, the lower their precedence. After construction the
 * use {@link #withFile(java.io.File)}, {@link #withUrl(java.net.URL)} or the
 * like to load the properties from external resources. After construction use
 * {@link #withEvalArgs(String[])} or the like to parse the command line
 * arguments (implementations might provide a constructor such as
 * {@link ApplicationProperties#ApplicationProperties(String[])} for the command
 * line arguments if you do not require a command syntax notation).
 * {@link ApplicationProperties} represent a composition of the different
 * {@link Properties} flavors, therefore providing functionality from the
 * {@link ParseArgsProperties} as well as from the {@link ResourceProperties}
 * types.
 */
public class ApplicationProperties extends AbstractPropertiesDecorator implements SecretMutator, SecretBuilder, ParseArgsProperties, ResourceProperties, ResourceLoaderBuilder, ProfileProperties, ArgsParserPropertiesAccessor {

	// /////////////////////////////////////////////////////////////////////////
	// CONSTANTS:
	// /////////////////////////////////////////////////////////////////////////

	// /////////////////////////////////////////////////////////////////////////
	// VARIABLES:
	// /////////////////////////////////////////////////////////////////////////

	private final SystemProperties _systemProperties = new SystemProperties();
	private final EnvironmentProperties _environmentProperties = new EnvironmentProperties();
	private ParseArgsProperties _parseArgsProperties = null;
	private final List _resourceProperties = new ArrayList<>();
	private final PropertiesPrecedenceBuilder _propertiesPrecedence = new PropertiesPrecedenceBuilderComposite();
	private String _secret;
	private boolean _isPostConstructed = false;
	private PolyglotPropertiesBuilderFactory _factory;

	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTORS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Constructs a {@link ApplicationProperties} instance with no
	 * {@link Condition} for parsing command line arguments. As no syntax
	 * notation is required by the constructor (no root {@link Condition}), no
	 * syntax validation is done. Therefore the properties are heuristically
	 * determined from the provided command line arguments when invoking
	 * {@link #withEvalArgs(String[])}.
	 */
	public ApplicationProperties() {
		this( new PolyglotPropertiesBuilderFactory() );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with no
	 * {@link Condition} for parsing command line arguments. As no syntax
	 * notation is required by the constructor (no root {@link Condition}), no
	 * syntax validation is done. Therefore the properties are heuristically
	 * determined from the provided command line arguments when invoking
	 * {@link #withEvalArgs(String[])}.
	 *
	 * @param aDocumentMetrics Provides various metrics which may be tweaked
	 *        when marshaling or unmarshaling documents of various nations (such
	 *        as INI, XML, YAML, JSON, TOML, PROPERTIES, etc.).
	 */
	public ApplicationProperties( DocumentMetrics aDocumentMetrics ) {
		this( new PolyglotPropertiesBuilderFactory( aDocumentMetrics ) );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with no args syntax
	 * {@link Term} node for parsing command line arguments. As no syntax
	 * notation is required by the constructor (no root args syntax {@link Term}
	 * node), no syntax validation is done. Therefore the properties are
	 * heuristically determined from the provided command line arguments when
	 * invoking {@link #withEvalArgs(String[])}.
	 *
	 * @param aPropertiesBuilderFactory The factory to use when constructing
	 *        {@link ResourceProperties} instances.
	 */
	public ApplicationProperties( PolyglotPropertiesBuilderFactory aPropertiesBuilderFactory ) {
		_parseArgsProperties = new ArgsParserProperties();
		_factory = aPropertiesBuilderFactory;
		_secret = toEncrypted( SystemContext.HOST.toContextString() );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with a custom secret
	 * for obfuscation.
	 *
	 * @param aPropertiesBuilderFactory The factory to use when constructing
	 *        {@link ResourceProperties} instances.
	 * @param aSecret The secret to be used when encountering upon obfuscated
	 *        properties.
	 */
	public ApplicationProperties( PolyglotPropertiesBuilderFactory aPropertiesBuilderFactory, String aSecret ) {
		_parseArgsProperties = new ArgsParserProperties();
		_secret = toEncrypted( aSecret );
		_factory = aPropertiesBuilderFactory;
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with no args syntax
	 * {@link Term} node for parsing command line arguments: As no syntax
	 * notation is required by the constructor (no root args syntax {@link Term}
	 * node), no syntax validation is done. Therefore the properties are
	 * heuristically determined from the provided command line arguments.
	 *
	 * @param aPropertiesBuilderFactory The factory to use when constructing
	 *        {@link ResourceProperties} instances.
	 * @param aArgs The command line arguments to be evaluated.
	 */
	public ApplicationProperties( PolyglotPropertiesBuilderFactory aPropertiesBuilderFactory, String[] aArgs ) {
		_parseArgsProperties = new ArgsParserProperties( aArgs );
		_factory = aPropertiesBuilderFactory;
		_secret = toEncrypted( SystemContext.HOST.toContextString() );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with no args syntax
	 * {@link Term} node for parsing command line arguments: As no syntax
	 * notation is required by the constructor (no root args syntax {@link Term}
	 * node), no syntax validation is done. Therefore the properties are
	 * heuristically determined from the provided command line arguments. Also
	 * constructs a {@link ApplicationProperties} instance with a custom secret
	 * for obfuscation.
	 *
	 * @param aPropertiesBuilderFactory The factory to use when constructing
	 *        {@link ResourceProperties} instances.
	 * @param aArgs The command line arguments to be evaluated.
	 * @param aSecret The secret to be used when encountering upon obfuscated
	 *        properties.
	 */
	public ApplicationProperties( PolyglotPropertiesBuilderFactory aPropertiesBuilderFactory, String[] aArgs, String aSecret ) {
		_parseArgsProperties = new ArgsParserProperties( aArgs );
		_secret = toEncrypted( aSecret );
		_factory = aPropertiesBuilderFactory;
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with no args syntax
	 * {@link Term} node for parsing command line arguments: As no syntax
	 * notation is required by the constructor (no args syntax {@link Term}
	 * node), no syntax validation is done. Therefore the properties are
	 * heuristically determined from the provided command line arguments. Also
	 * constructs the {@link ApplicationProperties} with the given obfuscation
	 * mode
	 *
	 * @param aPropertiesBuilderFactory The factory to use when constructing
	 *        {@link ResourceProperties} instances.
	 * @param aArgs The command line arguments to be evaluated.
	 * @param aObfuscationMode The {@link SystemContext} specifies which level
	 *        of obfuscation is to be used when encountering upon obfuscated
	 *        properties: E.g. obfuscation may be bound to the host, the
	 *        "secret" used for obfuscation being the same for all applications
	 *        on the same host or obfuscation may be bound to the application,
	 *        being different for different applications on the same host.
	 */
	public ApplicationProperties( PolyglotPropertiesBuilderFactory aPropertiesBuilderFactory, String[] aArgs, SystemContext aObfuscationMode ) {
		_parseArgsProperties = new ArgsParserProperties( aArgs );
		_secret = toEncrypted( aObfuscationMode.toContextString() );
		_factory = aPropertiesBuilderFactory;
	}

	/**
	 * Constructs the {@link ApplicationProperties} with the given obfuscation
	 * mode.
	 *
	 * @param aPropertiesBuilderFactory The factory to use when constructing
	 *        {@link ResourceProperties} instances.
	 * @param aObfuscationMode The {@link SystemContext} specifies which level
	 *        of obfuscation is to be used when encountering upon obfuscated
	 *        properties: E.g. obfuscation may be bound to the host, the
	 *        "secret" used for obfuscation being the same for all applications
	 *        on the same host or obfuscation may be bound to the application,
	 *        being different for different applications on the same host.
	 */
	public ApplicationProperties( PolyglotPropertiesBuilderFactory aPropertiesBuilderFactory, SystemContext aObfuscationMode ) {
		_parseArgsProperties = new ArgsParserProperties();
		_secret = toEncrypted( aObfuscationMode.toContextString() );
		_factory = aPropertiesBuilderFactory;
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with the given args
	 * syntax {@link Term} node used to parse command line arguments.
	 *
	 * @param aPropertiesBuilderFactory The factory to use when constructing
	 *        {@link ResourceProperties} instances.
	 * @param aArgsSyntax The root condition being the node from which parsing
	 *        the command line arguments starts. Parse the command line
	 *        arguments via {@link #evalArgs(String[])}.
	 */
	public ApplicationProperties( PolyglotPropertiesBuilderFactory aPropertiesBuilderFactory, Term aArgsSyntax ) {
		_parseArgsProperties = new ArgsParserProperties( aArgsSyntax );
		_factory = aPropertiesBuilderFactory;
		_secret = toEncrypted( SystemContext.HOST.toContextString() );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with the given args
	 * syntax {@link Term} node used to parse command line arguments. Also
	 * constructs a {@link ApplicationProperties} instance with a custom secret
	 * for obfuscation.
	 *
	 * @param aPropertiesBuilderFactory The factory to use when constructing
	 *        {@link ResourceProperties} instances.
	 * @param aArgsSyntax The root condition being the node from which parsing
	 *        the command line arguments starts. Parse the command line
	 *        arguments via {@link #evalArgs(String[])}.
	 * @param aSecret The secret to be used when encountering upon obfuscated
	 *        properties.
	 */
	public ApplicationProperties( PolyglotPropertiesBuilderFactory aPropertiesBuilderFactory, Term aArgsSyntax, String aSecret ) {
		_parseArgsProperties = new ArgsParserProperties( aArgsSyntax );
		_secret = toEncrypted( aSecret );
		_factory = aPropertiesBuilderFactory;
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with the given args
	 * syntax {@link Term} node used to parse command line arguments. Also
	 * constructs the {@link ApplicationProperties} with the given obfuscation
	 * mode.
	 *
	 * @param aPropertiesBuilderFactory The factory to use when constructing
	 *        {@link ResourceProperties} instances.
	 * @param aArgsSyntax The root condition being the node from which parsing
	 *        the command line arguments starts. Parse the command line
	 *        arguments via {@link #evalArgs(String[])}.
	 * @param aObfuscationMode The {@link SystemContext} specifies which level
	 *        of obfuscation is to be used when encountering upon obfuscated
	 *        properties: E.g. obfuscation may be bound to the host, the
	 *        "secret" used for obfuscation being the same for all applications
	 *        on the same host or obfuscation may be bound to the application,
	 *        being different for different applications on the same host.
	 */
	public ApplicationProperties( PolyglotPropertiesBuilderFactory aPropertiesBuilderFactory, Term aArgsSyntax, SystemContext aObfuscationMode ) {
		_parseArgsProperties = new ArgsParserProperties( aArgsSyntax );
		_secret = toEncrypted( aObfuscationMode.toContextString() );
		_factory = aPropertiesBuilderFactory;
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with a custom secret
	 * for obfuscation.
	 * 
	 * @param aSecret The secret to be used when encountering upon obfuscated
	 *        properties.
	 */
	public ApplicationProperties( String aSecret ) {
		this( new PolyglotPropertiesBuilderFactory(), aSecret );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with a custom secret
	 * for obfuscation.
	 *
	 * @param aSecret The secret to be used when encountering upon obfuscated
	 *        properties.
	 * @param aDocumentMetrics Provides various metrics which may be tweaked
	 *        when marshaling or unmarshaling documents of various nations (such
	 *        as INI, XML, YAML, JSON, TOML, PROPERTIES, etc.).
	 */
	public ApplicationProperties( String aSecret, DocumentMetrics aDocumentMetrics ) {
		this( new PolyglotPropertiesBuilderFactory( aDocumentMetrics ), aSecret );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with no
	 * {@link Condition} for parsing command line arguments: As no syntax
	 * notation is required by the constructor (no root {@link Condition}), no
	 * syntax validation is done. Therefore the properties are heuristically
	 * determined from the provided command line arguments.
	 * 
	 * @param aArgs The command line arguments to be evaluated.
	 */
	public ApplicationProperties( String[] aArgs ) {
		this( new PolyglotPropertiesBuilderFactory(), aArgs );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with no
	 * {@link Condition} for parsing command line arguments: As no syntax
	 * notation is required by the constructor (no root {@link Condition}), no
	 * syntax validation is done. Therefore the properties are heuristically
	 * determined from the provided command line arguments.
	 *
	 * @param aArgs The command line arguments to be evaluated.
	 * @param aDocumentMetrics Provides various metrics which may be tweaked
	 *        when marshaling or unmarshaling documents of various nations (such
	 *        as INI, XML, YAML, JSON, TOML, PROPERTIES, etc.).
	 */
	public ApplicationProperties( String[] aArgs, DocumentMetrics aDocumentMetrics ) {
		this( new PolyglotPropertiesBuilderFactory( aDocumentMetrics ), aArgs );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with no
	 * {@link Condition} for parsing command line arguments: As no syntax
	 * notation is required by the constructor (no root {@link Condition}), no
	 * syntax validation is done. Therefore the properties are heuristically
	 * determined from the provided command line arguments. Also constructs a
	 * {@link ApplicationProperties} instance with a custom secret for
	 * obfuscation.
	 * 
	 * @param aArgs The command line arguments to be evaluated.
	 * @param aSecret The secret to be used when encountering upon obfuscated
	 *        properties.
	 */
	public ApplicationProperties( String[] aArgs, String aSecret ) {
		this( new PolyglotPropertiesBuilderFactory(), aArgs, aSecret );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with no
	 * {@link Condition} for parsing command line arguments: As no syntax
	 * notation is required by the constructor (no root {@link Condition}), no
	 * syntax validation is done. Therefore the properties are heuristically
	 * determined from the provided command line arguments. Also constructs a
	 * {@link ApplicationProperties} instance with a custom secret for
	 * obfuscation.
	 *
	 * @param aArgs The command line arguments to be evaluated.
	 * @param aSecret The secret to be used when encountering upon obfuscated
	 *        properties.
	 * @param aDocumentMetrics Provides various metrics which may be tweaked
	 *        when marshaling or unmarshaling documents of various nations (such
	 *        as INI, XML, YAML, JSON, TOML, PROPERTIES, etc.).
	 */
	public ApplicationProperties( String[] aArgs, String aSecret, DocumentMetrics aDocumentMetrics ) {
		this( new PolyglotPropertiesBuilderFactory( aDocumentMetrics ), aArgs, aSecret );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with no
	 * {@link Condition} for parsing command line arguments: As no syntax
	 * notation is required by the constructor (no root {@link Condition}), no
	 * syntax validation is done. Therefore the properties are heuristically
	 * determined from the provided command line arguments. Also constructs the
	 * {@link ApplicationProperties} with the given obfuscation mode
	 * 
	 * @param aArgs The command line arguments to be evaluated.
	 * @param aObfuscationMode The {@link SystemContext} specifies which level
	 *        of obfuscation is to be used when encountering upon obfuscated
	 *        properties: E.g. obfuscation may be bound to the host, the
	 *        "secret" used for obfuscation being the same for all applications
	 *        on the same host or obfuscation may be bound to the application,
	 *        being different for different applications on the same host.
	 */
	public ApplicationProperties( String[] aArgs, SystemContext aObfuscationMode ) {
		this( new PolyglotPropertiesBuilderFactory(), aArgs, aObfuscationMode );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with no
	 * {@link Condition} for parsing command line arguments: As no syntax
	 * notation is required by the constructor (no root {@link Condition}), no
	 * syntax validation is done. Therefore the properties are heuristically
	 * determined from the provided command line arguments. Also constructs the
	 * {@link ApplicationProperties} with the given obfuscation mode
	 *
	 * @param aArgs The command line arguments to be evaluated.
	 * @param aObfuscationMode The {@link SystemContext} specifies which level
	 *        of obfuscation is to be used when encountering upon obfuscated
	 *        properties: E.g. obfuscation may be bound to the host, the
	 *        "secret" used for obfuscation being the same for all applications
	 *        on the same host or obfuscation may be bound to the application,
	 *        being different for different applications on the same host.
	 * @param aDocumentMetrics Provides various metrics which may be tweaked
	 *        when marshaling or unmarshaling documents of various nations (such
	 *        as INI, XML, YAML, JSON, TOML, PROPERTIES, etc.).
	 */
	public ApplicationProperties( String[] aArgs, SystemContext aObfuscationMode, DocumentMetrics aDocumentMetrics ) {
		this( new PolyglotPropertiesBuilderFactory( aDocumentMetrics ), aArgs, aObfuscationMode );
	}

	/**
	 * Constructs the {@link ApplicationProperties} with the given obfuscation
	 * mode.
	 *
	 * @param aObfuscationMode The {@link SystemContext} specifies which level
	 *        of obfuscation is to be used when encountering upon obfuscated
	 *        properties: E.g. obfuscation may be bound to the host, the
	 *        "secret" used for obfuscation being the same for all applications
	 *        on the same host or obfuscation may be bound to the application,
	 *        being different for different applications on the same host.
	 */
	public ApplicationProperties( SystemContext aObfuscationMode ) {
		this( new PolyglotPropertiesBuilderFactory(), aObfuscationMode );
	}

	/**
	 * Constructs the {@link ApplicationProperties} with the given obfuscation
	 * mode.
	 *
	 * @param aObfuscationMode The {@link SystemContext} specifies which level
	 *        of obfuscation is to be used when encountering upon obfuscated
	 *        properties: E.g. obfuscation may be bound to the host, the
	 *        "secret" used for obfuscation being the same for all applications
	 *        on the same host or obfuscation may be bound to the application,
	 *        being different for different applications on the same host.
	 * @param aDocumentMetrics Provides various metrics which may be tweaked
	 *        when marshaling or unmarshaling documents of various nations (such
	 *        as INI, XML, YAML, JSON, TOML, PROPERTIES, etc.).
	 */
	public ApplicationProperties( SystemContext aObfuscationMode, DocumentMetrics aDocumentMetrics ) {
		this( new PolyglotPropertiesBuilderFactory( aDocumentMetrics ), aObfuscationMode );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with the given
	 * {@link Condition} used to parse command line arguments.
	 * 
	 * @param aArgsSyntax The root condition being the node from which parsing
	 *        the command line arguments starts. Parse the command line
	 *        arguments via {@link #evalArgs(String[])}.
	 */
	public ApplicationProperties( Term aArgsSyntax ) {
		this( new PolyglotPropertiesBuilderFactory(), aArgsSyntax );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with the given
	 * {@link Condition} used to parse command line arguments.
	 *
	 * @param aArgsSyntax The root condition being the node from which parsing
	 *        the command line arguments starts. Parse the command line
	 *        arguments via {@link #evalArgs(String[])}.
	 * @param aDocumentMetrics Provides various metrics which may be tweaked
	 *        when marshaling or unmarshaling documents of various nations (such
	 *        as INI, XML, YAML, JSON, TOML, PROPERTIES, etc.).
	 */
	public ApplicationProperties( Term aArgsSyntax, DocumentMetrics aDocumentMetrics ) {
		this( new PolyglotPropertiesBuilderFactory( aDocumentMetrics ), aArgsSyntax );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with the given
	 * {@link Condition} used to parse command line arguments. Also constructs a
	 * {@link ApplicationProperties} instance with a custom secret for
	 * obfuscation.
	 * 
	 * @param aArgsSyntax The root condition being the node from which parsing
	 *        the command line arguments starts. Parse the command line
	 *        arguments via {@link #evalArgs(String[])}.
	 * @param aSecret The secret to be used when encountering upon obfuscated
	 *        properties.
	 */
	public ApplicationProperties( Term aArgsSyntax, String aSecret ) {
		this( new PolyglotPropertiesBuilderFactory(), aArgsSyntax, aSecret );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with the given
	 * {@link Condition} used to parse command line arguments. Also constructs a
	 * {@link ApplicationProperties} instance with a custom secret for
	 * obfuscation.
	 *
	 * @param aArgsSyntax The root condition being the node from which parsing
	 *        the command line arguments starts. Parse the command line
	 *        arguments via {@link #evalArgs(String[])}.
	 * @param aSecret The secret to be used when encountering upon obfuscated
	 *        properties.
	 * @param aDocumentMetrics Provides various metrics which may be tweaked
	 *        when marshaling or unmarshaling documents of various nations (such
	 *        as INI, XML, YAML, JSON, TOML, PROPERTIES, etc.).
	 */
	public ApplicationProperties( Term aArgsSyntax, String aSecret, DocumentMetrics aDocumentMetrics ) {
		this( new PolyglotPropertiesBuilderFactory( aDocumentMetrics ), aArgsSyntax, aSecret );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with the given
	 * {@link Condition} used to parse command line arguments. Also constructs
	 * the {@link ApplicationProperties} with the given obfuscation mode.
	 * 
	 * @param aArgsSyntax The root condition being the node from which parsing
	 *        the command line arguments starts. Parse the command line
	 *        arguments via {@link #evalArgs(String[])}.
	 * @param aObfuscationMode The {@link SystemContext} specifies which level
	 *        of obfuscation is to be used when encountering upon obfuscated
	 *        properties: E.g. obfuscation may be bound to the host, the
	 *        "secret" used for obfuscation being the same for all applications
	 *        on the same host or obfuscation may be bound to the application,
	 *        being different for different applications on the same host.
	 */
	public ApplicationProperties( Term aArgsSyntax, SystemContext aObfuscationMode ) {
		this( new PolyglotPropertiesBuilderFactory(), aArgsSyntax, aObfuscationMode );
	}

	/**
	 * Constructs a {@link ApplicationProperties} instance with the given
	 * {@link Condition} used to parse command line arguments. Also constructs
	 * the {@link ApplicationProperties} with the given obfuscation mode.
	 *
	 * @param aArgsSyntax The root condition being the node from which parsing
	 *        the command line arguments starts. Parse the command line
	 *        arguments via {@link #evalArgs(String[])}.
	 * @param aObfuscationMode The {@link SystemContext} specifies which level
	 *        of obfuscation is to be used when encountering upon obfuscated
	 *        properties: E.g. obfuscation may be bound to the host, the
	 *        "secret" used for obfuscation being the same for all applications
	 *        on the same host or obfuscation may be bound to the application,
	 *        being different for different applications on the same host.
	 * @param aDocumentMetrics Provides various metrics which may be tweaked
	 *        when marshaling or unmarshaling documents of various nations (such
	 *        as INI, XML, YAML, JSON, TOML, PROPERTIES, etc.).
	 */
	public ApplicationProperties( Term aArgsSyntax, SystemContext aObfuscationMode, DocumentMetrics aDocumentMetrics ) {
		this( new PolyglotPropertiesBuilderFactory( aDocumentMetrics ), aArgsSyntax, aObfuscationMode );
	}

	// /////////////////////////////////////////////////////////////////////////
	// METHODS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void addExample( Example aExampleUsage ) {
		_parseArgsProperties.addExample( aExampleUsage );
	}

	/**
	 * Reads the {@link ResourcePropertiesBuilder} from the given data sink.
	 *
	 * @param aResourceClass The class which's class loader is to take care of
	 *        loading the properties (from inside a JAR).
	 * @param aFilePath The data sink from which to read the
	 *        {@link ResourcePropertiesBuilder}.
	 * @param aConfigLocator The {@link ConfigLocator} specifying where to seek
	 *        for properties.
	 * 
	 * @return the according {@link ResourcePropertiesBuilder} instance.
	 * 
	 * @throws IOException Thrown in case there were problems reading the data
	 *         sink.
	 * @throws ParseException Thrown in case there were problems parsing the
	 *         data from the data sink.
	 */
	public ResourcePropertiesBuilder addResourceProperties( Class aResourceClass, String aFilePath, ConfigLocator aConfigLocator ) throws IOException, ParseException {
		ResourcePropertiesBuilder theProperties = _factory.toProperties( aResourceClass, aFilePath, aConfigLocator );
		try {
			theProperties = new ObfuscationResourcePropertiesBuilderDecorator( theProperties, toDecrypted( _secret ) );
		}
		catch ( IOException ignore ) {}
		_resourceProperties.add( theProperties );
		_propertiesPrecedence.appendProperties( new ObfuscationPropertiesDecorator( theProperties, toDecrypted( _secret ) ) );
		return theProperties;
	}

	/**
	 * Reads the {@link ResourcePropertiesBuilder} from the given data sink.
	 *
	 * @param aFile The data sink from which to read the
	 *        {@link ResourcePropertiesBuilder}.
	 * @param aConfigLocator The {@link ConfigLocator} specifying where to seek
	 *        for properties.
	 * 
	 * @return the according {@link ResourcePropertiesBuilder} instance.
	 * 
	 * @throws IOException Thrown in case there were problems reading the data
	 *         sink.
	 * @throws ParseException Thrown in case there were problems parsing the
	 *         data from the data sink.
	 */
	public ResourcePropertiesBuilder addResourceProperties( File aFile, ConfigLocator aConfigLocator ) throws IOException, ParseException {
		ResourcePropertiesBuilder theProperties = _factory.toProperties( aFile, aConfigLocator );
		try {
			theProperties = new ObfuscationResourcePropertiesBuilderDecorator( theProperties, toDecrypted( _secret ) );
		}
		catch ( IOException ignore ) {}
		_resourceProperties.add( theProperties );
		_propertiesPrecedence.appendProperties( new ObfuscationPropertiesDecorator( theProperties, toDecrypted( _secret ) ) );
		return theProperties;
	}

	/**
	 * Reads the {@link ResourceProperties} from the given data sink.
	 *
	 * @param aInputStream The data sink from which to read the
	 *        {@link ResourceProperties}.
	 * 
	 * @return the according {@link ResourcePropertiesBuilder} instance.
	 * 
	 * @throws IOException Thrown in case there were problems reading the data
	 *         sink.
	 * @throws ParseException Thrown in case there were problems parsing the
	 *         data from the data sink.
	 */
	public ResourcePropertiesBuilder addResourceProperties( InputStream aInputStream ) throws IOException, ParseException {
		final ResourcePropertiesBuilder theProperties = _factory.toProperties( aInputStream );
		_resourceProperties.add( theProperties );
		_propertiesPrecedence.appendProperties( new ObfuscationPropertiesDecorator( theProperties, toDecrypted( _secret ) ) );
		return theProperties;
	}

	/**
	 * Reads the {@link ResourceProperties} from the given data sink.
	 *
	 * @param aUrl The data sink from which to read the
	 *        {@link ResourceProperties}.
	 * 
	 * @return the according {@link ResourcePropertiesBuilder} instance.
	 * 
	 * @throws IOException Thrown in case there were problems reading the data
	 *         sink.
	 * @throws ParseException Thrown in case there were problems parsing the
	 *         data from the data sink.
	 */
	public ResourcePropertiesBuilder addResourceProperties( URL aUrl ) throws IOException, ParseException {
		final ResourcePropertiesBuilder theProperties = _factory.toProperties( aUrl );
		_resourceProperties.add( theProperties );
		_propertiesPrecedence.appendProperties( new ObfuscationPropertiesBuilderDecorator( theProperties, toDecrypted( _secret ) ) );
		return theProperties;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean containsKey( Object aKey ) {
		if ( getProperties() == null ) {
			throw new IllegalStateException( "You must properly construct and then initialize your instance via #postConstruct() !" );
		}
		return super.containsKey( aKey );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void errorLn( String aLine ) {
		_parseArgsProperties.errorLn( aLine );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Operand[] evalArgs( List aArgs ) throws ArgsSyntaxException {
		return _parseArgsProperties.evalArgs( aArgs );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Operand[] evalArgs( String aToPath, List aArgs ) throws ArgsSyntaxException {
		return _parseArgsProperties.evalArgs( aToPath, aArgs );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Operand[] evalArgs( String aToPath, String[] aArgs ) throws ArgsSyntaxException {
		return _parseArgsProperties.evalArgs( aToPath, aArgs );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Operand[] evalArgs( String[] aArgs ) throws ArgsSyntaxException {
		return _parseArgsProperties.evalArgs( aArgs );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String get( Object aKey ) {
		if ( getProperties() == null ) {
			throw new IllegalStateException( "You must properly construct and then initialize your instance via #postConstruct() !" );
		}
		return super.get( aKey );
	}

	/**
	 * {@inheritDoc}
	 * 
	 * The {@link ParseArgsProperties} are those properties derived from the
	 * command line arguments (as of the {@link #getArgsSyntax()}).
	 */
	@Override
	public ParseArgsProperties getArgsParserProperties() {
		return _parseArgsProperties;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Term getArgsSyntax() {
		return _parseArgsProperties.getArgsSyntax();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getArgumentEscapeCode() {
		return _parseArgsProperties.getArgumentEscapeCode();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getBannerBorderEscapeCode() {
		return _parseArgsProperties.getBannerBorderEscapeCode();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getBannerEscapeCode() {
		return _parseArgsProperties.getBannerEscapeCode();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Font getBannerFont() {
		return _parseArgsProperties.getBannerFont();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public char[] getBannerFontPalette() {
		return _parseArgsProperties.getBannerFontPalette();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getCommandEscapeCode() {
		return _parseArgsProperties.getCommandEscapeCode();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getConsoleWidth() {
		return _parseArgsProperties.getConsoleWidth();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getCopyright() {
		return _parseArgsProperties.getCopyright();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public char getDelimiter() {
		if ( getProperties() == null ) {
			throw new IllegalStateException( "You must properly construct and then initialize your instance via #postConstruct() !" );
		}
		return super.getDelimiter();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getDescription() {
		return _parseArgsProperties.getDescription();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getDescriptionEscapeCode() {
		return _parseArgsProperties.getDescriptionEscapeCode();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Example[] getExamples() {
		return _parseArgsProperties.getExamples();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getLicense() {
		return _parseArgsProperties.getLicense();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getLineBreak() {
		return _parseArgsProperties.getLineBreak();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getLineSeparatorEscapeCode() {
		return _parseArgsProperties.getLineSeparatorEscapeCode();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getLongOptionPrefix() {
		return _parseArgsProperties.getLongOptionPrefix();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getMaxConsoleWidth() {
		return _parseArgsProperties.getMaxConsoleWidth();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getName() {
		return _parseArgsProperties.getName();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getOptionEscapeCode() {
		return _parseArgsProperties.getOptionEscapeCode();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getResetEscapeCode() {
		return _parseArgsProperties.getResetEscapeCode();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public char getSeparatorLnChar() {
		return _parseArgsProperties.getSeparatorLnChar();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Character getShortOptionPrefix() {
		return _parseArgsProperties.getShortOptionPrefix();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public SyntaxMetrics getSyntaxMetrics() {
		return _parseArgsProperties.getSyntaxMetrics();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public TextBoxGrid getTextBoxGrid() {
		return _parseArgsProperties.getTextBoxGrid();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getTitle() {
		return _parseArgsProperties.getTitle();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isEmpty() {
		if ( getProperties() == null ) {
			throw new IllegalStateException( "You must properly construct and then initialize your instance via #postConstruct() !" );
		}
		return super.isEmpty();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isEscapeCodesEnabled() {
		return _parseArgsProperties.isEscapeCodesEnabled();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Set keySet() {
		if ( getProperties() == null ) {
			throw new IllegalStateException( "You must properly construct and then initialize your instance via #postConstruct() !" );
		}
		return super.keySet();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void printBanner() {
		_parseArgsProperties.printBanner();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void printCopyright() {
		_parseArgsProperties.printCopyright();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void printDescription() {
		_parseArgsProperties.printDescription();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void printExamples() {
		_parseArgsProperties.printExamples();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void printHeader() {
		_parseArgsProperties.printHeader();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void printHelp() {
		_parseArgsProperties.printHelp();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void printLicense() {
		_parseArgsProperties.printLicense();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void printLn() {
		_parseArgsProperties.printLn();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void printLn( String aLine ) {
		_parseArgsProperties.printLn( aLine );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void printOptions() {
		_parseArgsProperties.printOptions();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void printSeparatorLn() {
		_parseArgsProperties.printSeparatorLn();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void printSynopsis() {
		_parseArgsProperties.printSynopsis();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Properties reload() throws IOException, ParseException {
		final PropertiesBuilder theProperties = new PropertiesBuilderImpl();
		for ( int i = _resourceProperties.size() - 1; i >= 0; i-- ) {
			theProperties.insert( _resourceProperties.get( i ).reload() );
		}
		return theProperties;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Properties reload( ReloadMode aReloadMode ) throws IOException, ParseException {
		final PropertiesBuilder theProperties = new PropertiesBuilderImpl();
		for ( int i = _resourceProperties.size() - 1; i >= 0; i-- ) {
			theProperties.insert( _resourceProperties.get( i ).reload( aReloadMode ) );
		}
		return theProperties;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void reset() {
		_parseArgsProperties.reset();

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Properties retrieveFrom( String aFromPath ) {
		if ( getProperties() == null ) {
			throw new IllegalStateException( "You must properly construct and then initialize your instance via #postConstruct() !" );
		}
		return super.retrieveFrom( aFromPath );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Properties retrieveTo( String aToPath ) {
		if ( getProperties() == null ) {
			throw new IllegalStateException( "You must properly construct and then initialize your instance via #postConstruct() !" );
		}
		return super.retrieveTo( aToPath );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setArgsSyntax( Term aArgsSyntax ) {
		if ( _isPostConstructed ) {
			throw new IllegalStateException( "The runtime properties have already been post-constructed as the properties have already been accessed, you must call this method before first accessing any property!" );
		}
		_parseArgsProperties = new ArgsParserProperties( aArgsSyntax );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setArgumentEscapeCode( String aParamEscCode ) {
		_parseArgsProperties.setArgumentEscapeCode( aParamEscCode );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setBannerBorderEscapeCode( String aBannerBorderEscCode ) {
		_parseArgsProperties.setBannerBorderEscapeCode( aBannerBorderEscCode );

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setBannerEscapeCode( String aBannerEscCode ) {
		_parseArgsProperties.setBannerEscapeCode( aBannerEscCode );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setBannerFont( Font aBannerFont ) {
		_parseArgsProperties.setBannerFont( aBannerFont );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setBannerFontPalette( AsciiColorPalette aBannerFontPalette ) {
		_parseArgsProperties.setBannerFontPalette( aBannerFontPalette.getPalette() );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setBannerFontPalette( char[] aColorPalette ) {
		_parseArgsProperties.setBannerFontPalette( aColorPalette );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setCommandEscapeCode( String aCommandEscCode ) {
		_parseArgsProperties.setCommandEscapeCode( aCommandEscCode );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setConsoleWidth( int aConsoleWidth ) {
		_parseArgsProperties.setConsoleWidth( aConsoleWidth );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setCopyright( String aCopyrightNote ) {
		_parseArgsProperties.setCopyright( aCopyrightNote );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setDescription( String aDescription ) {
		_parseArgsProperties.setDescription( aDescription );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setDescriptionEscapeCode( String aParamDescriptionEscCode ) {
		_parseArgsProperties.setDescriptionEscapeCode( aParamDescriptionEscCode );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setErrorOut( PrintStream aErrorOut ) {
		_parseArgsProperties.setErrorOut( aErrorOut );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setEscapeCodesEnabled( boolean isEscCodeEnabled ) {
		_parseArgsProperties.setEscapeCodesEnabled( isEscCodeEnabled );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setExamples( Example[] aExamples ) {
		_parseArgsProperties.setExamples( aExamples );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setLicense( String aLicenseNote ) {
		_parseArgsProperties.setLicense( aLicenseNote );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setLineBreak( String aLineBreak ) {
		_parseArgsProperties.setLineBreak( aLineBreak );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setLineSeparatorEscapeCode( String aLineSeparatorEscCode ) {
		_parseArgsProperties.setLineSeparatorEscapeCode( aLineSeparatorEscCode );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setLongOptionPrefix( String aLongOptionPrefix ) {
		_parseArgsProperties.setLongOptionPrefix( aLongOptionPrefix );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setMaxConsoleWidth( int aMaxConsoleWidth ) {
		_parseArgsProperties.setMaxConsoleWidth( aMaxConsoleWidth );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setName( String aName ) {
		_parseArgsProperties.setName( aName );
	}

	/**
	 * Specifies the obfuscation mode to be used.
	 * 
	 * @param aObfuscationMode The {@link SystemContext} specifies which level
	 *        of obfuscation is to be used when encountering upon obfuscated
	 *        properties: E.g. obfuscation may be bound to the host, the
	 *        "secret" used for obfuscation being the same for all applications
	 *        on the same host or obfuscation may be bound to the application,
	 *        being different for different applications on the same host.
	 */
	public void setObfuscationMode( SystemContext aObfuscationMode ) {
		if ( _isPostConstructed ) {
			throw new IllegalStateException( "The runtime properties have already been post-constructed as the properties have already been accessed, you must call this method before first accessing any property!" );
		}
		_secret = toEncrypted( aObfuscationMode.toContextString() );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setOptionEscapeCode( String aOptEscCode ) {
		_parseArgsProperties.setOptionEscapeCode( aOptEscCode );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setResetEscapeCode( String aResetEscCode ) {
		_parseArgsProperties.setResetEscapeCode( aResetEscCode );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setSecret( String aSecret ) {
		if ( _isPostConstructed ) {
			throw new IllegalStateException( "The runtime properties have already been post-constructed as the properties have already been accessed, you must call this method before first accessing any property!" );
		}
		_secret = toEncrypted( aSecret );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setSeparatorLnChar( char aSeparatorChar ) {
		_parseArgsProperties.setSeparatorLnChar( aSeparatorChar );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setShortOptionPrefix( Character aShortOptionPrefix ) {
		_parseArgsProperties.setShortOptionPrefix( aShortOptionPrefix );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setStandardOut( PrintStream aStandardOut ) {
		_parseArgsProperties.setStandardOut( aStandardOut );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setSyntaxMetrics( SyntaxMetrics aSyntaxMetrics ) {
		_parseArgsProperties.setSyntaxMetrics( aSyntaxMetrics );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setTextBoxGrid( TextBoxGrid aTextBoxGrid ) {
		_parseArgsProperties.setTextBoxGrid( aTextBoxGrid );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setTitle( String aTitle ) {
		_parseArgsProperties.setTitle( aTitle );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int size() {
		if ( getProperties() == null ) {
			throw new IllegalStateException( "You must properly construct and then initialize your instance via #postConstruct() !" );
		}
		return super.size();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Object toDataStructure( String aFromPath ) {
		if ( getProperties() == null ) {
			throw new IllegalStateException( "You must properly construct and then initialize your instance via #postConstruct() !" );
		}
		return super.toDataStructure( aFromPath );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Properties toRuntimeProfile( String... aProfiles ) {
		final Properties theSysProperties = ( toObfuscationProperties( _systemProperties ) );
		final Properties theEnvProperties = ( toObfuscationProperties( _environmentProperties ) );
		final Properties theArgsProperties = ( toObfuscationProperties( _parseArgsProperties ) );
		if ( ( aProfiles == null || aProfiles.length == 0 ) && _resourceProperties.size() != 0 ) {
			final Properties[] theAllProperties = new Properties[3 + _resourceProperties.size()];
			theAllProperties[0] = theSysProperties;
			theAllProperties[1] = theEnvProperties;
			theAllProperties[2] = theArgsProperties;
			for ( int i = 0; i < _resourceProperties.size(); i++ ) {
				theAllProperties[3 + i] = _resourceProperties.get( i );
			}
			return new PropertiesPrecedenceComposite( theAllProperties );
		}
		return new PropertiesPrecedenceComposite( theSysProperties, theEnvProperties, theArgsProperties, ProfileProperties.super.toRuntimeProfile( aProfiles ) );
	}

	/**
	 * Returns the serialized format as of the {@link ResourcePropertiesBuilder}
	 * instance being produced upon invocation of the
	 * {@link PolyglotPropertiesBuilderFactory#toProperties(Properties)} method.
	 * {@inheritDoc}
	 */
	@Override
	public String toSerialized() {
		return _factory.toProperties( this ).toSerialized();
	}

	/**
	 * Returns the serialized format as of the {@link ResourcePropertiesBuilder}
	 * instance being produced upon invocation of the
	 * {@link PolyglotPropertiesBuilderFactory#toProperties(Properties)} method.
	 * {@inheritDoc}
	 */
	@Override
	public String toSerialized( char aDelimiter ) {
		return _factory.toProperties( this ).toSerialized( aDelimiter );
	}

	/**
	 * Returns the serialized format as of the {@link ResourcePropertiesBuilder}
	 * instance being produced upon invocation of the
	 * {@link PolyglotPropertiesBuilderFactory#toProperties(Properties)} method.
	 * {@inheritDoc}
	 */
	@Override
	public String toSerialized( String aComment, char aDelimiter ) {
		return _factory.toProperties( this ).toSerialized( aComment, aDelimiter );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Collection values() {
		if ( getProperties() == null ) {
			throw new IllegalStateException( "You must properly construct and then initialize your instance via #postConstruct() !" );
		}
		return super.values();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withAddExample( Example aExample ) {
		addExample( aExample );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withAddExample( String aDescription, Operand... aOperands ) {
		addExample( aDescription, aOperands );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withArgsSyntax( Term aArgsSyntax ) {
		setArgsSyntax( aArgsSyntax );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withArgumentEscapeCode( String aParamEscCode ) {
		setArgumentEscapeCode( aParamEscCode );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withBannerBorderEscapeCode( String aBannerBorderEscCode ) {
		setBannerBorderEscapeCode( aBannerBorderEscCode );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withBannerEscapeCode( String aBannerEscCode ) {
		setBannerEscapeCode( aBannerEscCode );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withBannerFont( Font aBannerFont ) {
		setBannerFont( aBannerFont );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withBannerFontPalette( AsciiColorPalette aBannerFontPalette ) {
		setBannerFontPalette( aBannerFontPalette );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withBannerFontPalette( char[] aColorPalette ) {
		setBannerFontPalette( aColorPalette );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withCommandEscapeCode( String aCommandEscCode ) {
		setCommandEscapeCode( aCommandEscCode );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withConsoleWidth( int aConsoleWidth ) {
		setConsoleWidth( aConsoleWidth );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withCopyright( String aCopyrightNote ) {
		setCopyright( aCopyrightNote );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withDescription( String aDescription ) {
		setDescription( aDescription );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withDescriptionEscapeCode( String aDescriptionEscCode ) {
		setDescriptionEscapeCode( aDescriptionEscCode );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withErrorOut( PrintStream aErrorOut ) {
		setErrorOut( aErrorOut );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withEscapeCodesEnabled( boolean isEscCodeEnabled ) {
		setEscapeCodesEnabled( isEscCodeEnabled );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withEvalArgs( List aArgs ) throws ArgsSyntaxException {
		evalArgs( aArgs );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withEvalArgs( List aArgs, ArgsFilter aArgsFilter ) throws ArgsSyntaxException {
		evalArgs( aArgs, aArgsFilter );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withEvalArgs( List aArgs, Pattern aFilterExp ) throws ArgsSyntaxException {
		evalArgs( aArgs, aFilterExp );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withEvalArgs( String aToPath, List aArgs ) throws ArgsSyntaxException {
		evalArgs( aToPath, aArgs );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withEvalArgs( String aToPath, String[] aArgs ) throws ArgsSyntaxException {
		evalArgs( aToPath, aArgs );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withEvalArgs( String[] aArgs ) throws ArgsSyntaxException {
		evalArgs( aArgs );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withEvalArgs( String[] aArgs, ArgsFilter aArgsFilter ) throws ArgsSyntaxException {
		evalArgs( aArgs, aArgsFilter );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withEvalArgs( String[] aArgs, Pattern aFilterExp ) throws ArgsSyntaxException {
		evalArgs( aArgs, aFilterExp );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withExamples( Collection aExample ) {
		ParseArgsProperties.super.withExamples( aExample );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withExamples( Example[] aExample ) {
		ParseArgsProperties.super.withExamples( aExample );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withFile( File aFile ) throws IOException, ParseException {
		addResourceProperties( aFile, ConfigLocator.ALL );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withFile( File aFile, ConfigLocator aConfigLocator ) throws IOException, ParseException {
		addResourceProperties( aFile, aConfigLocator );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withInputStream( InputStream aInputStream ) throws IOException, ParseException {
		addResourceProperties( aInputStream );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withLicense( String aLicenseNote ) {
		setLicense( aLicenseNote );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withLineBreak( String aLineBreak ) {
		setLineBreak( aLineBreak );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withLineSeparatorEscapeCode( String aLineSeparatorEscCode ) {
		setLineSeparatorEscapeCode( aLineSeparatorEscCode );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withLongOptionPrefix( String aLongOptionPrefix ) {
		setLongOptionPrefix( aLongOptionPrefix );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withMaxConsoleWidth( int aMaxConsoleWidth ) {
		setMaxConsoleWidth( aMaxConsoleWidth );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withName( String aName ) {
		setName( aName );
		return this;
	}

	/**
	 * Builder method for the obfuscation mode property returning the builder
	 * for applying multiple build operations.
	 * 
	 * @param aObfuscationMode The obfuscation mode as of
	 *        {@link #setObfuscationMode(SystemContext)}.
	 * 
	 * @return The builder for applying multiple build operations.
	 */
	public ApplicationProperties withObfuscationMode( SystemContext aObfuscationMode ) {
		setObfuscationMode( aObfuscationMode );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withOptionEscapeCode( String aOptionEscCode ) {
		setOptionEscapeCode( aOptionEscCode );
		return this;
	}

	/**
	 * A hook for you to provide {@link Properties} programmatically. The later
	 * you add {@link Properties}, the lower their precedence.
	 * 
	 * @param aProperties The {@link Properties} to be added.
	 * 
	 * @return This instance as of the builder pattern to apply method chaining.
	 */
	public ApplicationProperties withProperties( Properties aProperties ) {
		addProperties( aProperties );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withResetEscapeCode( String aResetEscCode ) {
		setResetEscapeCode( aResetEscCode );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withResourceClass( Class aResourceClass, String aFilePath ) throws IOException, ParseException {
		return withResourceClass( aResourceClass, aFilePath, ConfigLocator.ALL );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withResourceClass( Class aResourceClass, String aFilePath, ConfigLocator aConfigLocator ) throws IOException, ParseException {
		addResourceProperties( aResourceClass, aFilePath, aConfigLocator );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withResourceClass( String aFilePath ) throws IOException, ParseException {
		return withResourceClass( Execution.getMainClass(), aFilePath );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withSecret( String aSecret ) {
		setSecret( aSecret );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withSeparatorLnChar( char aSeparatorChar ) {
		setSeparatorLnChar( aSeparatorChar );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withShortOptionPrefix( Character aShortOptionPrefix ) {
		setShortOptionPrefix( aShortOptionPrefix );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withStandardOut( PrintStream aStandardOut ) {
		setStandardOut( aStandardOut );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withSyntaxMetrics( SyntaxMetrics aSyntaxMetrics ) {
		setSyntaxMetrics( aSyntaxMetrics );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ParseArgs withSyntaxMetrics( SyntaxNotation aSyntaxNotation ) {
		setSyntaxMetrics( aSyntaxNotation );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withTextBoxGrid( TextBoxGrid aTextBoxGrid ) {
		setTextBoxGrid( aTextBoxGrid );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withTextBoxGrid( TextBoxStyle aTextBoxStyle ) {
		setTextBoxGrid( aTextBoxStyle );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withTitle( String aTitle ) {
		setTitle( aTitle );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationProperties withUrl( URL aUrl ) throws IOException, ParseException {
		addResourceProperties( aUrl );
		return this;
	}

	// /////////////////////////////////////////////////////////////////////////
	// HOOKS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Adds the properties.
	 *
	 * @param aProperties the properties
	 */
	protected void addProperties( Properties aProperties ) {
		if ( aProperties instanceof ResourcePropertiesBuilder ) {
			try {
				final ObfuscationResourcePropertiesBuilder theObfuscation = new ObfuscationResourcePropertiesBuilderDecorator( (ResourcePropertiesBuilder) aProperties, toDecrypted( _secret ) );
				_resourceProperties.add( theObfuscation );
				_propertiesPrecedence.appendProperties( theObfuscation );
			}
			catch ( IOException e ) {
				_resourceProperties.add( (ResourceProperties) aProperties );
				_propertiesPrecedence.appendProperties( aProperties );
			}
		}
		else if ( aProperties instanceof ResourceProperties ) {
			final ObfuscationProperties theObfuscation = new ObfuscationPropertiesDecorator( aProperties, toDecrypted( _secret ) );
			_resourceProperties.add( (ResourceProperties) aProperties );
			_propertiesPrecedence.appendProperties( theObfuscation );
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected Properties getProperties() {
		if ( !_isPostConstructed ) {
			postConstruct();
		}
		return super.getProperties();
	}

	// /////////////////////////////////////////////////////////////////////////
	// HELPER:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * After constructor execution do a post construct.
	 */
	private void postConstruct() {
		if ( !_isPostConstructed ) {
			synchronized ( this ) {
				if ( !_isPostConstructed ) {
					_propertiesPrecedence.prependProperties( toObfuscationProperties( _environmentProperties ) );
					_propertiesPrecedence.prependProperties( toObfuscationProperties( _systemProperties ) );
					_propertiesPrecedence.prependProperties( toObfuscationProperties( _parseArgsProperties ) );
					for ( ResourceProperties eProperties : _resourceProperties ) {
						if ( !_propertiesPrecedence.containsProperties( eProperties ) ) {
							_propertiesPrecedence.appendProperties( new ObfuscationPropertiesDecorator( eProperties, toDecrypted( _secret ) ) );
						}
					}
					setProperties( new ProfilePropertiesProjection( _propertiesPrecedence ) );
					_isPostConstructed = true;
				}
			}
		}
	}

	private String toDecrypted( String aValue ) {
		try {
			return new ChaosTextDecrypter( new ChaosKey( SystemContext.HOST_USER_APPLICATION_SESSION.toContextString() ) ).toDecrypted( aValue );
		}
		catch ( DecryptionException e ) {
			throw new BugException( "Encountered a bug while decrypting value <" + SecretHintBuilder.asString( aValue ) + "> with <" + SystemContext.HOST_USER_APPLICATION_SESSION + "> system context!", e );
		}
	}

	private String toEncrypted( String aValue ) {
		try {
			return new ChaosTextEncrypter( new ChaosKey( SystemContext.HOST_USER_APPLICATION_SESSION.toContextString() ) ).toEncrypted( aValue );
		}
		catch ( EncryptionException e ) {
			throw new BugException( "Encountered a bug while encrypting value <" + SecretHintBuilder.asString( aValue ) + "> with <" + SystemContext.HOST_USER_APPLICATION_SESSION + "> system context!", e );
		}
	}

	private ObfuscationPropertiesDecorator toObfuscationProperties( Properties aProperties ) {
		return new ObfuscationPropertiesDecorator( aProperties, toDecrypted( _secret ) );
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy