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

org.refcodes.properties.AbstractResourcePropertiesBuilder Maven / Gradle / Ivy

Go to download

This artifact provides means to read configuration data from various different locations such as properties from JAR files, file system files or remote HTTP addresses or GIT repositories.

The newest version!
// /////////////////////////////////////////////////////////////////////////////
// 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;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.refcodes.data.Delimiter;
import org.refcodes.data.Scheme;
import org.refcodes.exception.MarshalException;
import org.refcodes.exception.Trap;
import org.refcodes.exception.UnmarshalException;
import org.refcodes.properties.ResourceProperties.ResourcePropertiesBuilder;
import org.refcodes.runtime.ConfigLocator;
import org.refcodes.runtime.Execution;
import org.refcodes.struct.CanonicalMap;
import org.refcodes.struct.PathMap;
import org.refcodes.struct.Property;
import org.refcodes.struct.Relation;
import org.refcodes.struct.ext.factory.CanonicalMapFactory;

/**
 * Implementation of the mutable {@link ResourcePropertiesBuilder} interface.
 */
public abstract class AbstractResourcePropertiesBuilder extends PropertiesBuilderImpl implements ResourcePropertiesBuilder {

	private static final long serialVersionUID = 1L;

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

	protected final DocumentMetrics _documentMetrics;
	protected File _propertiesFile;

	/**
	 * The {@link CanonicalMapFactory} cannot be instantiated as a member
	 * variable as a super-class's constructor uses a method defined in this
	 * sub-class which uses this factory. This will result in an uninitialized
	 * factory when the super-constructor invokes the according method.
	 * Therefore with the method {@link #getCanonicalMapFactory()} we use lazy
	 * instantiation to overcome this challenge.
	 */
	private CanonicalMapFactory _factory = null;

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

	/**
	 * Create an empty {@link AbstractResourcePropertiesBuilder} instance using
	 * the default path delimiter "/" ({@link Delimiter#PATH}) for the path
	 * declarations.
	 */
	protected AbstractResourcePropertiesBuilder() {
		_documentMetrics = DocumentNotation.DEFAULT;
	}

	/**
	 * Create a {@link AbstractResourcePropertiesBuilder} instance containing
	 * the elements of the provided {@link Map} instance using the default path
	 * delimiter "/" ({@link Delimiter#PATH}) for the path declarations.
	 *
	 * @param aProperties the properties to be added.
	 */
	public AbstractResourcePropertiesBuilder( Map aProperties ) {
		super( aProperties );
		_documentMetrics = DocumentNotation.DEFAULT;
	}

	/**
	 * Create a {@link AbstractResourcePropertiesBuilder} instance containing
	 * the elements of the provided {@link Map} instance using the default path
	 * delimiter "/" ({@link Delimiter#PATH}) for the path declarations.
	 *
	 * @param aProperties the properties to be added.
	 * @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 AbstractResourcePropertiesBuilder( Map aProperties, DocumentMetrics aDocumentMetrics ) {
		super( aProperties );
		_documentMetrics = aDocumentMetrics;
	}

	/**
	 * Create a {@link AbstractResourcePropertiesBuilder} instance containing
	 * the elements as of {@link MutablePathMap#insert(Object)} using the
	 * default path delimiter "/" ({@link Delimiter#PATH}) for the path
	 * declarations: "Inspects the given object and adds all elements found in
	 * the given object. Elements of type {@link Map}, {@link Collection} and
	 * arrays are identified and handled as of their type: The path for each
	 * value in a {@link Map} is appended with its according key. The path for
	 * each value in a {@link Collection} or array is appended with its
	 * according index of occurrence (in case of a {@link List} or an array, its
	 * actual index). In case of reflection, the path for each member is
	 * appended with its according mamber's name. All elements (e.g. the members
	 * and values) are inspected recursively which results in the according
	 * paths of the terminating values."
	 *
	 * @param aObj The object from which the elements are to be added.
	 */
	public AbstractResourcePropertiesBuilder( Object aObj ) {
		super( aObj );
		_documentMetrics = DocumentNotation.DEFAULT;
	}

	/**
	 * Create a {@link AbstractResourcePropertiesBuilder} instance containing
	 * the elements as of {@link MutablePathMap#insert(Object)} using the
	 * default path delimiter "/" ({@link Delimiter#PATH}) for the path
	 * declarations: "Inspects the given object and adds all elements found in
	 * the given object. Elements of type {@link Map}, {@link Collection} and
	 * arrays are identified and handled as of their type: The path for each
	 * value in a {@link Map} is appended with its according key. The path for
	 * each value in a {@link Collection} or array is appended with its
	 * according index of occurrence (in case of a {@link List} or an array, its
	 * actual index). In case of reflection, the path for each member is
	 * appended with its according mamber's name. All elements (e.g. the members
	 * and values) are inspected recursively which results in the according
	 * paths of the terminating values."
	 *
	 * @param aObj The object from which the elements are to be added.
	 * @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 AbstractResourcePropertiesBuilder( Object aObj, DocumentMetrics aDocumentMetrics ) {
		super( aObj );
		_documentMetrics = aDocumentMetrics;
	}

	/**
	 * Create an empty {@link AbstractResourcePropertiesBuilder} instance using
	 * the default path delimiter "/" ({@link Delimiter#PATH}) for the path
	 * declarations.
	 *
	 * @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.).
	 */
	protected AbstractResourcePropertiesBuilder( DocumentMetrics aDocumentMetrics ) {
		_documentMetrics = aDocumentMetrics;
	}

	/**
	 * Loads the properties from the given file's path.
	 *
	 * @param aResourceClass The class which's class loader is to take care of
	 *        loading the properties (from inside a JAR).
	 * @param aFilePath The file path of the class's resources from which to
	 *        load the properties.
	 * 
	 * @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.
	 */
	protected AbstractResourcePropertiesBuilder( Class aResourceClass, String aFilePath ) throws IOException, ParseException {
		_documentMetrics = DocumentNotation.DEFAULT;
		loadFrom( aResourceClass, aFilePath );
	}

	/**
	 * Loads the properties from the given file's path.
	 *
	 * @param aResourceClass The class which's class loader is to take care of
	 *        loading the properties (from inside a JAR).
	 * @param aFilePath The file path of the class's resources from which to
	 *        load the 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.).
	 * 
	 * @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.
	 */
	protected AbstractResourcePropertiesBuilder( Class aResourceClass, String aFilePath, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
		_documentMetrics = aDocumentMetrics;
		loadFrom( aResourceClass, aFilePath );
	}

	/**
	 * Loads the properties from the given file's path. In case you enable the
	 * "seek" argument, then the properties are, if the file does not exist,
	 * loaded from the first folder containing such a file as of the
	 * specification for the method {@link ConfigLocator#getFolders()}.
	 *
	 * @param aResourceClass The class which's class loader is to take care of
	 *        loading the properties (from inside a JAR).
	 * @param aFilePath The file path of the class's resources from which to
	 *        load the properties.
	 * @param aConfigLocator The {@link ConfigLocator} describes the locations
	 *        to additional crawl for the desired 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.
	 */
	protected AbstractResourcePropertiesBuilder( Class aResourceClass, String aFilePath, ConfigLocator aConfigLocator ) throws IOException, ParseException {
		_documentMetrics = DocumentNotation.DEFAULT;
		seekFrom( aResourceClass, aFilePath, aConfigLocator );
	}

	/**
	 * Loads the properties from the given file's path. In case you enable the
	 * "seek" argument, then the properties are, if the file does not exist,
	 * loaded from the first folder containing such a file as of the
	 * specification for the method {@link ConfigLocator#getFolders()}.
	 *
	 * @param aResourceClass The class which's class loader is to take care of
	 *        loading the properties (from inside a JAR).
	 * @param aFilePath The file path of the class's resources from which to
	 *        load the properties.
	 * @param aConfigLocator The {@link ConfigLocator} describes the locations
	 *        to additional crawl for the desired file.
	 * @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.).
	 * 
	 * @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.
	 */
	protected AbstractResourcePropertiesBuilder( Class aResourceClass, String aFilePath, ConfigLocator aConfigLocator, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
		_documentMetrics = aDocumentMetrics;
		seekFrom( aResourceClass, aFilePath, aConfigLocator );
	}

	/**
	 * Loads the properties from the given {@link File}.
	 *
	 * @param aFile The {@link File} from which to load the properties.
	 * 
	 * @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.
	 */
	protected AbstractResourcePropertiesBuilder( File aFile ) throws IOException, ParseException {
		_documentMetrics = DocumentNotation.DEFAULT;
		loadFrom( aFile );
	}

	/**
	 * Loads the properties from the given {@link File}.
	 *
	 * @param aFile The {@link File} from which to load the 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.).
	 * 
	 * @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.
	 */
	protected AbstractResourcePropertiesBuilder( File aFile, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
		_documentMetrics = aDocumentMetrics;
		loadFrom( aFile );
	}

	/**
	 * Loads or seeks the properties from the given {@link File}. In case you
	 * enable the "seek" argument, then the properties are, if the file does not
	 * exist, loaded from the first folder containing such a file as of the
	 * specification for the method {@link ConfigLocator#getFolders()}.
	 *
	 * @param aFile The {@link File} from which to load the properties.
	 * @param aConfigLocator The {@link ConfigLocator} describes the locations
	 *        to additional crawl for the desired 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.
	 */
	protected AbstractResourcePropertiesBuilder( File aFile, ConfigLocator aConfigLocator ) throws IOException, ParseException {
		_documentMetrics = DocumentNotation.DEFAULT;
		seekFrom( aFile, aConfigLocator );
	}

	/**
	 * Loads or seeks the properties from the given {@link File}. In case you
	 * enable the "seek" argument, then the properties are, if the file does not
	 * exist, loaded from the first folder containing such a file as of the
	 * specification for the method {@link ConfigLocator#getFolders()}.
	 *
	 * @param aFile The {@link File} from which to load the properties.
	 * @param aConfigLocator The {@link ConfigLocator} describes the locations
	 *        to additional crawl for the desired file.
	 * @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.).
	 * 
	 * @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.
	 */
	protected AbstractResourcePropertiesBuilder( File aFile, ConfigLocator aConfigLocator, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
		_documentMetrics = aDocumentMetrics;
		seekFrom( aFile, aConfigLocator );
	}

	/**
	 * Reads the properties from the given {@link InputStream}.
	 *
	 * @param aInputStream The {@link InputStream} from which to read the
	 *        properties.
	 * 
	 * @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.
	 */
	protected AbstractResourcePropertiesBuilder( InputStream aInputStream ) throws IOException, ParseException {
		_documentMetrics = DocumentNotation.DEFAULT;
		loadFrom( aInputStream );
	}

	/**
	 * Reads the properties from the given {@link InputStream}.
	 *
	 * @param aInputStream The {@link InputStream} from which to read the
	 *        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.).
	 * 
	 * @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.
	 */
	protected AbstractResourcePropertiesBuilder( InputStream aInputStream, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
		_documentMetrics = aDocumentMetrics;
		loadFrom( aInputStream );
	}

	/**
	 * Create a {@link AbstractResourcePropertiesBuilder} instance containing
	 * the elements of the provided {@link Properties} instance using the
	 * default path delimiter "/" ({@link Delimiter#PATH}) for the path
	 * declarations.
	 *
	 * @param aProperties the properties to be added.
	 * @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.).
	 */
	protected AbstractResourcePropertiesBuilder( Properties aProperties, DocumentMetrics aDocumentMetrics ) {
		super( aProperties );
		_documentMetrics = aDocumentMetrics;
	}

	/**
	 * Create a {@link AbstractResourcePropertiesBuilder} instance containing
	 * the elements of the provided {@link PropertiesBuilder} instance using the
	 * default path delimiter "/" ({@link Delimiter#PATH}) for the path
	 * declarations.
	 *
	 * @param aProperties the properties to be added.
	 * @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.).
	 */
	protected AbstractResourcePropertiesBuilder( PropertiesBuilder aProperties, DocumentMetrics aDocumentMetrics ) {
		super( aProperties );
		_documentMetrics = aDocumentMetrics;
	}

	/**
	 * Loads the properties from the given file's path.
	 *
	 * @param aFilePath The path to the file from which to load the 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.).
	 * 
	 * @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.
	 */
	protected AbstractResourcePropertiesBuilder( String aFilePath, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
		_documentMetrics = aDocumentMetrics;
		loadFrom( aFilePath );
	}

	/**
	 * Loads the properties from the given file's path. In case you enable the
	 * "seek" argument, then the properties are, if the file does not exist,
	 * loaded from the first folder containing such a file as of the
	 * specification for the method {@link ConfigLocator#getFolders()}.
	 *
	 * @param aFilePath The path to the file from which to load the properties.
	 * @param aConfigLocator The {@link ConfigLocator} describes the locations
	 *        to additional crawl for the desired 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.
	 */
	protected AbstractResourcePropertiesBuilder( String aFilePath, ConfigLocator aConfigLocator ) throws IOException, ParseException {
		_documentMetrics = DocumentNotation.DEFAULT;
		seekFrom( aFilePath, aConfigLocator );
	}

	/**
	 * Loads the properties from the given file's path. In case you enable the
	 * "seek" argument, then the properties are, if the file does not exist,
	 * loaded from the first folder containing such a file as of the
	 * specification for the method {@link ConfigLocator#getFolders()}.
	 *
	 * @param aFilePath The path to the file from which to load the properties.
	 * @param aConfigLocator The {@link ConfigLocator} describes the locations
	 *        to additional crawl for the desired file.
	 * @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.).
	 * 
	 * @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.
	 */
	protected AbstractResourcePropertiesBuilder( String aFilePath, ConfigLocator aConfigLocator, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
		_documentMetrics = aDocumentMetrics;
		seekFrom( aFilePath, aConfigLocator );
	}

	/**
	 * Loads the properties from the given {@link URL}.
	 *
	 * @param aUrl The {@link URL} from which to read the 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.).
	 * 
	 * @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.
	 */
	protected AbstractResourcePropertiesBuilder( URL aUrl, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
		_documentMetrics = aDocumentMetrics;
		loadFrom( aUrl );
	}

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

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void flush() throws IOException {
		try {
			saveTo( _propertiesFile );
		}
		catch ( IOException e ) {
			throw new IOException( "Cannot flush properties to file <" + _propertiesFile.getAbsolutePath() + "!", e );
		}
	}

	/**
	 * {@inheritDoc} In case the resource has not been loaded from a writable
	 * {@link File}, then calling this method will return false.
	 */
	@Override
	public boolean isFlushable() {
		return _propertiesFile != null && _propertiesFile.canWrite();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Properties loadFrom( File aFile ) throws IOException, ParseException {
		try ( InputStream theInputStream = new FileInputStream( aFile ) ) {
			final Properties theResult = loadFrom( theInputStream );
			_propertiesFile = aFile;
			return theResult;
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Properties loadFrom( InputStream aInputStream ) throws IOException, ParseException {
		final BufferedInputStream theInputStream = new BufferedInputStream( aInputStream );
		final Map theProperties = _documentMetrics.toProperties( getDelimiter() );
		final CanonicalMapBuilder theCanonicalMap;
		try {
			theCanonicalMap = getCanonicalMapFactory().fromMarshaled( theInputStream, theProperties );
		}
		catch ( UnmarshalException e ) {
			throw new ParseException( "Error parsing properties at offset <" + e.getOffset() + ">:" + Trap.asMessage( e ), e.getOffset() );
		}
		final Properties theResult = new PropertiesImpl( theCanonicalMap );
		insert( theResult );
		return theResult;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Properties reload() throws IOException, ParseException {
		return reload( ReloadMode.KEEP_ORPHANS );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Properties reload( ReloadMode aReloadMode ) throws IOException, ParseException {
		if ( _propertiesFile == null ) {
			throw new IllegalArgumentException( "There is no resource (supporting reloading, such as an input stream) attached to these properties." );
		}
		final Properties theResult = loadFrom( _propertiesFile );
		if ( aReloadMode == ReloadMode.ORPHAN_REMOVAL ) {
			final Set theKeys = new HashSet<>( keySet() );
			for ( String eKey : theKeys ) {
				if ( !theResult.containsKey( eKey ) ) {
					remove( eKey );
				}
			}
		}
		return theResult;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public File saveTo( File aFile, String aComment, char aDelimiter ) throws IOException {
		try ( OutputStream theOutputStream = new BufferedOutputStream( new FileOutputStream( aFile ) ) ) {
			saveTo( theOutputStream, aComment, aDelimiter );
		}
		_propertiesFile = aFile;
		return aFile;
	}

	/**
	 * The comment is ignored for the JSON format as JSON does not(!) support
	 * any comments! {@inheritDoc}
	 */
	@Override
	public void saveTo( OutputStream aOutputStream, String aComment, char aDelimiter ) throws IOException {
		final Map theProperties = _documentMetrics.toProperties( aComment, aDelimiter );
		try {
			final String theMarshaled = getCanonicalMapFactory().toMarshaled( this, theProperties );
			final OutputStreamWriter theWriter = new OutputStreamWriter( aOutputStream );
			theWriter.write( theMarshaled );
			theWriter.flush();
		}
		catch ( MarshalException e ) {
			throw new IOException( e );
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Properties seekFrom( Class aResourceClass, String aFilePath, ConfigLocator aConfigLocator ) throws IOException, ParseException {

		final List theProbedFiles = new ArrayList<>();
		IOException aCause = null;
		File eFile = new File( aFilePath );

		// ConfigLocator.ABSOLUTE |-->
		if ( aConfigLocator != null && aConfigLocator == ConfigLocator.ABSOLUTE ) {
			if ( eFile.isAbsolute() ) {
				theProbedFiles.add( eFile.getAbsolutePath() );
				if ( aResourceClass != null ) {
					try {
						return loadFrom( aResourceClass, aFilePath );
					}
					catch ( IOException e ) {}
				}
				return loadFrom( aFilePath );
			}
		}
		// ConfigLocator.ABSOLUTE <--|

		else {
			Properties theResult = null;

			// Absolute path? |-->
			theProbedFiles.add( eFile.getAbsolutePath() );
			if ( eFile.isAbsolute() && eFile.exists() && eFile.isFile() && eFile.canRead() ) {
				theResult = loadFrom( eFile );
				return theResult;
			}
			// Absolute path? <--|

			// Config-Locations |-->
			if ( aConfigLocator == null ) {
				aConfigLocator = ConfigLocator.ALL;
			}
			eFile = aConfigLocator.toFile( aFilePath );
			if ( eFile != null ) {
				theResult = loadFrom( eFile );
				return theResult;
			}
			final File[] theFolders = aConfigLocator.getFolders();
			for ( File eFolder : theFolders ) {
				theProbedFiles.add( eFolder.getAbsolutePath() );
			}
			// Config-Locations <--|

			// Try JAR |-->
			try {
				if ( aResourceClass == null ) {
					aResourceClass = Execution.getMainClass();
				}
				final URL theResource = aResourceClass.getResource( aFilePath );
				InputStream theInputStream = aResourceClass.getResourceAsStream( aFilePath );
				if ( theInputStream == null && !aFilePath.startsWith( "" + Delimiter.PATH.getChar() ) ) {
					theInputStream = aResourceClass.getResourceAsStream( Delimiter.PATH.getChar() + aFilePath );
				}
				if ( theInputStream != null ) {
					theResult = loadFrom( theInputStream );
					if ( theResource != null ) {
						try {
							_propertiesFile = new File( theResource.toURI() );
						}
						catch ( URISyntaxException e ) {
							/* at least we were able to load! */
						}
					}
					return theResult;
				}
				theProbedFiles.add( theResource != null ? theResource.toExternalForm() : Scheme.JAR.getMarker() + aFilePath + "@" + aResourceClass.getName() );
			}
			catch ( IOException e ) {
				aCause = e;
			}
			// Try JAR <--|
		}
		// Nothing found |-->
		final StringBuilder theProbedLocations = new StringBuilder();
		final Iterator e = theProbedFiles.iterator();
		while ( e.hasNext() ) {
			theProbedLocations.append( e.next() );
			if ( e.hasNext() ) {
				theProbedLocations.append( ", " );
			}
		}
		throw new IOException( "Cannot find a properties file <" + aFilePath + "> (or <" + aFilePath + ".*>, depending on the implementation) at any of the supported locations: " + theProbedLocations.toString(), aCause );
		// Nothing found <--|
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsert( Object aObj ) {
		insert( aObj );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsert( PathMap aFrom ) {
		insert( aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertBetween( Collection aToPathElements, Object aFrom, Collection aFromPathElements ) {
		insertBetween( aToPathElements, aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertBetween( Collection aToPathElements, PathMap aFrom, Collection aFromPathElements ) {
		insertBetween( aToPathElements, aFrom, aFromPathElements );
		return this;
	}

	//	/**
	//	 * {@inheritDoc}
	//	 */
	//	@Override
	//	public ResourcePropertiesBuilder withPut( Object aPath, String aValue ) {
	//		put( toPath( aPath ), aValue );
	//		return this;
	//	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertBetween( Object aToPath, Object aFrom, Object aFromPath ) {
		insertBetween( aToPath, aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertBetween( Object aToPath, PathMap aFrom, Object aFromPath ) {
		insertBetween( aToPath, aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertBetween( Object[] aToPathElements, Object aFrom, Object[] aFromPathElements ) {
		insertBetween( aToPathElements, aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertBetween( Object[] aToPathElements, PathMap aFrom, Object[] aFromPathElements ) {
		insertBetween( aToPathElements, aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertBetween( String aToPath, Object aFrom, String aFromPath ) {
		insertBetween( aToPath, aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertBetween( String aToPath, PathMap aFrom, String aFromPath ) {
		insertBetween( aToPath, aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertBetween( String[] aToPathElements, Object aFrom, String[] aFromPathElements ) {
		insertBetween( aToPathElements, aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertBetween( String[] aToPathElements, PathMap aFrom, String[] aFromPathElements ) {
		insertBetween( aToPathElements, aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertFrom( Object aFrom, Collection aFromPathElements ) {
		insertFrom( aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertFrom( Object aFrom, Object aFromPath ) {
		insertFrom( aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertFrom( Object aFrom, Object... aFromPathElements ) {
		withInsertFrom( aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertFrom( Object aFrom, String aFromPath ) {
		insertFrom( aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertFrom( Object aFrom, String... aFromPathElements ) {
		insertFrom( aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertFrom( PathMap aFrom, Collection aFromPathElements ) {
		insertFrom( aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertFrom( PathMap aFrom, Object aFromPath ) {
		insertFrom( aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertFrom( PathMap aFrom, Object... aFromPathElements ) {
		withInsertFrom( aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertFrom( PathMap aFrom, String aFromPath ) {
		insertFrom( aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertFrom( PathMap aFrom, String... aFromPathElements ) {
		insertFrom( aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertTo( Collection aToPathElements, Object aFrom ) {
		insertTo( aToPathElements, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertTo( Collection aToPathElements, PathMap aFrom ) {
		insertTo( aToPathElements, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertTo( Object aToPath, Object aFrom ) {
		insertTo( aToPath, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertTo( Object aToPath, PathMap aFrom ) {
		insertTo( aToPath, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertTo( Object[] aToPathElements, Object aFrom ) {
		insertTo( aToPathElements, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertTo( Object[] aToPathElements, PathMap aFrom ) {
		insertTo( aToPathElements, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertTo( String aToPath, Object aFrom ) {
		insertTo( aToPath, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertTo( String aToPath, PathMap aFrom ) {
		insertTo( aToPath, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertTo( String[] aToPathElements, Object aFrom ) {
		insertTo( aToPathElements, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withInsertTo( String[] aToPathElements, PathMap aFrom ) {
		insertTo( aToPathElements, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMerge( Object aObj ) {
		merge( aObj );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMerge( PathMap aFrom ) {
		merge( aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeBetween( Collection aToPathElements, Object aFrom, Collection aFromPathElements ) {
		mergeBetween( aToPathElements, aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeBetween( Collection aToPathElements, PathMap aFrom, Collection aFromPathElements ) {
		mergeBetween( aToPathElements, aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeBetween( Object aToPath, Object aFrom, Object aFromPath ) {
		mergeBetween( aToPath, aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeBetween( Object aToPath, PathMap aFrom, Object aFromPath ) {
		mergeBetween( aToPath, aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeBetween( Object[] aToPathElements, Object aFrom, Object[] aFromPathElements ) {
		mergeBetween( aToPathElements, aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeBetween( Object[] aToPathElements, PathMap aFrom, Object[] aFromPathElements ) {
		mergeBetween( aToPathElements, aFromPathElements, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeBetween( String aToPath, Object aFrom, String aFromPath ) {
		mergeBetween( aToPath, aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeBetween( String aToPath, PathMap aFrom, String aFromPath ) {
		mergeBetween( aToPath, aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeBetween( String[] aToPathElements, Object aFrom, String[] aFromPathElements ) {
		mergeBetween( aToPathElements, aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeBetween( String[] aToPathElements, PathMap aFrom, String[] aFromPathElements ) {
		mergeBetween( aToPathElements, aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeFrom( Object aFrom, Collection aFromPathElements ) {
		mergeFrom( aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeFrom( Object aFrom, Object aFromPath ) {
		mergeFrom( aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeFrom( Object aFrom, Object... aFromPathElements ) {
		mergeFrom( aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeFrom( Object aFrom, String aFromPath ) {
		mergeFrom( aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeFrom( Object aFrom, String... aFromPathElements ) {
		mergeFrom( aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeFrom( PathMap aFrom, Collection aFromPathElements ) {
		mergeFrom( aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeFrom( PathMap aFrom, Object aFromPath ) {
		mergeFrom( aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeFrom( PathMap aFrom, Object... aFromPathElements ) {
		mergeFrom( aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeFrom( PathMap aFrom, String aFromPath ) {
		mergeFrom( aFrom, aFromPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeFrom( PathMap aFrom, String... aFromPathElements ) {
		mergeFrom( aFrom, aFromPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeTo( Collection aToPathElements, Object aFrom ) {
		mergeTo( aToPathElements, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeTo( Collection aToPathElements, PathMap aFrom ) {
		mergeTo( aToPathElements, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeTo( Object aToPath, Object aFrom ) {
		mergeTo( aToPath, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeTo( Object aToPath, PathMap aFrom ) {
		mergeTo( aToPath, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeTo( Object[] aToPathElements, Object aFrom ) {
		mergeTo( aToPathElements, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeTo( Object[] aToPathElements, PathMap aFrom ) {
		mergeTo( aToPathElements, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeTo( String aToPath, Object aFrom ) {
		mergeTo( aToPath, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeTo( String aToPath, PathMap aFrom ) {
		mergeTo( aToPath, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeTo( String[] aToPathElements, Object aFrom ) {
		mergeTo( aToPathElements, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withMergeTo( String[] aToPathElements, PathMap aFrom ) {
		mergeTo( aToPathElements, aFrom );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPut( Collection aPathElements, String aValue ) {
		put( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPut( Object[] aPathElements, String aValue ) {
		put( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPut( Property aProperty ) {
		put( aProperty );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPut( Relation aProperty ) {
		put( aProperty );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPut( String aKey, String aValue ) {
		put( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPut( String[] aKey, String aValue ) {
		put( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutBoolean( Collection aPathElements, Boolean aValue ) {
		putBoolean( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutBoolean( Object aKey, Boolean aValue ) {
		putBoolean( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutBoolean( Object[] aPathElements, Boolean aValue ) {
		putBoolean( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutBoolean( String aKey, Boolean aValue ) {
		putBoolean( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutBoolean( String[] aPathElements, Boolean aValue ) {
		putBoolean( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutByte( Collection aPathElements, Byte aValue ) {
		putByte( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutByte( Object aKey, Byte aValue ) {
		putByte( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutByte( Object[] aPathElements, Byte aValue ) {
		putByte( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutByte( String aKey, Byte aValue ) {
		putByte( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutByte( String[] aPathElements, Byte aValue ) {
		putByte( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutChar( Collection aPathElements, Character aValue ) {
		putChar( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutChar( Object aKey, Character aValue ) {
		putChar( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutChar( Object[] aPathElements, Character aValue ) {
		putChar( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutChar( String aKey, Character aValue ) {
		putChar( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutChar( String[] aPathElements, Character aValue ) {
		putChar( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public  ResourcePropertiesBuilder withPutClass( Collection aPathElements, Class aValue ) {
		putClass( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public  ResourcePropertiesBuilder withPutClass( Object aKey, Class aValue ) {
		putClass( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public  ResourcePropertiesBuilder withPutClass( Object[] aPathElements, Class aValue ) {
		putClass( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public  ResourcePropertiesBuilder withPutClass( String aKey, Class aValue ) {
		putClass( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public  ResourcePropertiesBuilder withPutClass( String[] aPathElements, Class aValue ) {
		putClass( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDirAt( Collection aPathElements, int aIndex, Object aDir ) {
		putDirAt( aPathElements, aIndex, aDir );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDirAt( Collection aPathElements, int aIndex, PathMap aDir ) {
		putDirAt( aPathElements, aIndex, aDir );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDirAt( int aIndex, Object aDir ) {
		putDirAt( aIndex, aDir );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDirAt( int aIndex, PathMap aDir ) {
		putDirAt( aIndex, aDir );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDirAt( Object aPath, int aIndex, Object aDir ) {
		putDirAt( aPath, aIndex, aDir );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDirAt( Object aPath, int aIndex, PathMap aDir ) {
		putDirAt( aPath, aIndex, aDir );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDirAt( Object[] aPathElements, int aIndex, Object aDir ) {
		putDirAt( aPathElements, aIndex, aDir );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDirAt( Object[] aPathElements, int aIndex, PathMap aDir ) {
		putDirAt( aPathElements, aIndex, aDir );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDirAt( String aPath, int aIndex, Object aDir ) {
		putDirAt( aPath, aIndex, aDir );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDirAt( String aPath, int aIndex, PathMap aDir ) {
		putDirAt( aPath, aIndex, aDir );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDirAt( String[] aPathElements, int aIndex, Object aDir ) {
		putDirAt( aPathElements, aIndex, aDir );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDirAt( String[] aPathElements, int aIndex, PathMap aDir ) {
		putDirAt( aPathElements, aIndex, aDir );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDouble( Collection aPathElements, Double aValue ) {
		putDouble( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDouble( Object aKey, Double aValue ) {
		putDouble( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDouble( Object[] aPathElements, Double aValue ) {
		putDouble( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDouble( String aKey, Double aValue ) {
		putDouble( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutDouble( String[] aPathElements, Double aValue ) {
		putDouble( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public > ResourcePropertiesBuilder withPutEnum( Collection aPathElements, E aValue ) {
		putEnum( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public > ResourcePropertiesBuilder withPutEnum( Object aKey, E aValue ) {
		putEnum( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public > ResourcePropertiesBuilder withPutEnum( Object[] aPathElements, E aValue ) {
		putEnum( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public > ResourcePropertiesBuilder withPutEnum( String aKey, E aValue ) {
		putEnum( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public > ResourcePropertiesBuilder withPutEnum( String[] aPathElements, E aValue ) {
		putEnum( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutFloat( Collection aPathElements, Float aValue ) {
		putFloat( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutFloat( Object aKey, Float aValue ) {
		putFloat( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutFloat( Object[] aPathElements, Float aValue ) {
		putFloat( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutFloat( String aKey, Float aValue ) {
		putFloat( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutFloat( String[] aPathElements, Float aValue ) {
		putFloat( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutInt( Collection aPathElements, Integer aValue ) {
		putInt( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutInt( Object aKey, Integer aValue ) {
		putInt( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutInt( Object[] aPathElements, Integer aValue ) {
		putInt( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutInt( String aKey, Integer aValue ) {
		putInt( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutInt( String[] aPathElements, Integer aValue ) {
		putInt( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutLong( Collection aPathElements, Long aValue ) {
		putLong( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutLong( Object aKey, Long aValue ) {
		putLong( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutLong( Object[] aPathElements, Long aValue ) {
		putLong( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutLong( String aKey, Long aValue ) {
		putLong( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutLong( String[] aPathElements, Long aValue ) {
		putLong( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutShort( Collection aPathElements, Short aValue ) {
		putShort( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutShort( Object aKey, Short aValue ) {
		putShort( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutShort( Object[] aPathElements, Short aValue ) {
		putShort( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutShort( String aKey, Short aValue ) {
		putShort( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutShort( String[] aPathElements, Short aValue ) {
		putShort( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutString( Collection aPathElements, String aValue ) {
		putString( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutString( Object aKey, String aValue ) {
		putString( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutString( Object[] aPathElements, String aValue ) {
		putString( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutString( String aKey, String aValue ) {
		putString( aKey, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withPutString( String[] aPathElements, String aValue ) {
		putString( aPathElements, aValue );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withRemoveFrom( Collection aPathElements ) {
		removeFrom( aPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withRemoveFrom( Object aPath ) {
		removeFrom( aPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withRemoveFrom( Object... aPathElements ) {
		removeFrom( aPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withRemoveFrom( String aPath ) {
		removeFrom( aPath );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withRemoveFrom( String... aPathElements ) {
		removeFrom( aPathElements );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourcePropertiesBuilder withRemovePaths( String... aPathElements ) {
		removeFrom( aPathElements );
		return this;
	}

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

	/**
	 * Abstract method to be implemented by the sub-classes returning the
	 * concrete {@link CanonicalMapFactory} responsible to fabricate the
	 * {@link CanonicalMap} instances as of the required notation.
	 * 
	 * @return The {@link CanonicalMapFactory} supporting the required notation.
	 */
	protected abstract CanonicalMapFactory createCanonicalMapFactory();

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

	/**
	 * The {@link CanonicalMapFactory} cannot be instantiated as a member
	 * variable as a super-class's constructor uses a method defined in this
	 * sub-class which uses this factory. This will result in an uninitialized
	 * factory when the super-constructor invokes the according method.
	 * Therefore with the method {@link #getCanonicalMapFactory()} we use lazy
	 * instantiation to overcome this challenge.
	 * 
	 * @return The lazily created {@link CanonicalMapFactory}.
	 */
	private CanonicalMapFactory getCanonicalMapFactory() {
		if ( _factory == null ) {
			synchronized ( this ) {
				if ( _factory == null ) {
					_factory = createCanonicalMapFactory();
				}
			}
		}
		return _factory;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy