org.refcodes.properties.PolyglotProperties 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")
// together with the GPL linking exception applied; as being applied by the GNU
// Classpath ("http://www.gnu.org/software/classpath/license.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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.refcodes.data.Delimiter;
import org.refcodes.properties.JavaProperties.JavaPropertiesFactory;
import org.refcodes.properties.JsonProperties.JsonPropertiesFactory;
import org.refcodes.properties.PolyglotPropertiesBuilder.PolyglotPropertiesBuilderFactory;
import org.refcodes.properties.TomlProperties.TomlPropertiesFactory;
import org.refcodes.properties.XmlProperties.XmlPropertiesFactory;
import org.refcodes.properties.YamlProperties.YamlPropertiesFactory;
import org.refcodes.runtime.ConfigLocator;
/**
* Implementation of the {@link ResourceProperties} interface with support of so
* called "{@link PolyglotProperties}" (or just "properties"). For
* {@link PolyglotProperties}, see "https://en.wikipedia.org/wiki/.properties".
*/
public class PolyglotProperties extends AbstractResourcePropertiesDecorator {
// /////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS:
// /////////////////////////////////////////////////////////////////////////
/**
* Loads the {@link PolyglotProperties} 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.
*/
public PolyglotProperties( Class> aResourceClass, String aFilePath ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory().toProperties( aResourceClass, aFilePath ) );
}
/**
* Loads the {@link PolyglotProperties} 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 When set to true
then unmarshaling
* (XML) documents will preserve the preserve the root element
* (envelope). As an (XML) document requires a root element, the root
* element often is provided merely as of syntactic reasons and must
* be omitted as of semantic reasons. Unmarshaling functionality
* therefore by default skips the root elelemt, as this is considered
* merely to serve as an envelope. This behavior can be overridden by
* setting this property to true
.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public PolyglotProperties( Class> aResourceClass, String aFilePath, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory( aDocumentMetrics ).toProperties( aResourceClass, aFilePath ) );
}
/**
* Loads the {@link PolyglotProperties} from the given file's path. A
* provided {@link ConfigLocator} describes the locations to additional
* crawl for the desired file. Finally (if nothing else succeeds) the
* properties are loaded by the provided class's class loader which takes
* care of loading the properties (in case the file path is a relative path,
* also the absolute path with a prefixed path delimiter "/" is probed).
*
* @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.
*/
public PolyglotProperties( Class> aResourceClass, String aFilePath, ConfigLocator aConfigLocator ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory().toProperties( aResourceClass, aFilePath, aConfigLocator ) );
}
/**
* Loads the {@link PolyglotProperties} from the given file's path. A
* provided {@link ConfigLocator} describes the locations to additional
* crawl for the desired file. Finally (if nothing else succeeds) the
* properties are loaded by the provided class's class loader which takes
* care of loading the properties (in case the file path is a relative path,
* also the absolute path with a prefixed path delimiter "/" is probed).
*
* @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 When set to true
then unmarshaling
* (XML) documents will preserve the preserve the root element
* (envelope). As an (XML) document requires a root element, the root
* element often is provided merely as of syntactic reasons and must
* be omitted as of semantic reasons. Unmarshaling functionality
* therefore by default skips the root elelemt, as this is considered
* merely to serve as an envelope. This behavior can be overridden by
* setting this property to true
.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public PolyglotProperties( Class> aResourceClass, String aFilePath, ConfigLocator aConfigLocator, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory( aDocumentMetrics ).toProperties( aResourceClass, aFilePath, aConfigLocator ) );
}
/**
* Loads the {@link PolyglotProperties} 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.
*/
public PolyglotProperties( File aFile ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory().toProperties( aFile ) );
}
/**
* Loads the {@link PolyglotProperties} from the given {@link File}.
*
* @param aFile The {@link File} from which to load the properties.
* @param aDocumentMetrics When set to true
then unmarshaling
* (XML) documents will preserve the preserve the root element
* (envelope). As an (XML) document requires a root element, the root
* element often is provided merely as of syntactic reasons and must
* be omitted as of semantic reasons. Unmarshaling functionality
* therefore by default skips the root elelemt, as this is considered
* merely to serve as an envelope. This behavior can be overridden by
* setting this property to true
.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public PolyglotProperties( File aFile, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory( aDocumentMetrics ).toProperties( aFile ) );
}
/**
* Loads or seeks the {@link PolyglotProperties} from the given
* {@link File}. A provided {@link ConfigLocator} describes the locations to
* additional crawl for the desired file.
*
* @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.
*/
public PolyglotProperties( File aFile, ConfigLocator aConfigLocator ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory().toProperties( aFile, aConfigLocator ) );
}
/**
* Loads or seeks the {@link PolyglotProperties} from the given
* {@link File}. A provided {@link ConfigLocator} describes the locations to
* additional crawl for the desired file.
*
* @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 When set to true
then unmarshaling
* (XML) documents will preserve the preserve the root element
* (envelope). As an (XML) document requires a root element, the root
* element often is provided merely as of syntactic reasons and must
* be omitted as of semantic reasons. Unmarshaling functionality
* therefore by default skips the root elelemt, as this is considered
* merely to serve as an envelope. This behavior can be overridden by
* setting this property to true
.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public PolyglotProperties( File aFile, ConfigLocator aConfigLocator, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory( aDocumentMetrics ).toProperties( aFile, aConfigLocator ) );
}
/**
* Reads the {@link PolyglotProperties} 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.
*/
public PolyglotProperties( InputStream aInputStream ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory().toProperties( aInputStream ) );
}
/**
* Reads the {@link PolyglotProperties} from the given {@link InputStream}.
*
* @param aInputStream The {@link InputStream} from which to read the
* properties.
* @param aDocumentMetrics When set to true
then unmarshaling
* (XML) documents will preserve the preserve the root element
* (envelope). As an (XML) document requires a root element, the root
* element often is provided merely as of syntactic reasons and must
* be omitted as of semantic reasons. Unmarshaling functionality
* therefore by default skips the root elelemt, as this is considered
* merely to serve as an envelope. This behavior can be overridden by
* setting this property to true
.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public PolyglotProperties( InputStream aInputStream, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory( aDocumentMetrics ).toProperties( aInputStream ) );
}
/**
* Create a {@link PolyglotProperties} instance containing the elements of
* the provided {@link Map} instance using the default path delimiter "/"
* ({@link Delimiter#PATH}) for the path declarations.
*
* @param aMap the properties to be added.
*/
public PolyglotProperties( Map, ?> aMap ) {
super( new PolyglotPropertiesFactory().toProperties( aMap ) );
}
/**
* Create a {@link PolyglotProperties} instance containing the elements of
* the provided {@link Map} instance using the default path delimiter "/"
* ({@link Delimiter#PATH}) for the path declarations.
*
* @param aMap the properties to be added.
* @param aDocumentMetrics When set to true
then unmarshaling
* (XML) documents will preserve the preserve the root element
* (envelope). As an (XML) document requires a root element, the root
* element often is provided merely as of syntactic reasons and must
* be omitted as of semantic reasons. Unmarshaling functionality
* therefore by default skips the root elelemt, as this is considered
* merely to serve as an envelope. This behavior can be overridden by
* setting this property to true
.
*/
public PolyglotProperties( Map, ?> aMap, DocumentMetrics aDocumentMetrics ) {
super( new PolyglotPropertiesFactory( aDocumentMetrics ).toProperties( aMap ) );
}
/**
* Create a {@link PolyglotProperties} 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 PolyglotProperties( Object aObj ) {
super( new PolyglotPropertiesFactory().toProperties( aObj ) );
}
/**
* Create a {@link PolyglotProperties} 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 When set to true
then unmarshaling
* (XML) documents will preserve the preserve the root element
* (envelope). As an (XML) document requires a root element, the root
* element often is provided merely as of syntactic reasons and must
* be omitted as of semantic reasons. Unmarshaling functionality
* therefore by default skips the root elelemt, as this is considered
* merely to serve as an envelope. This behavior can be overridden by
* setting this property to true
.
*/
public PolyglotProperties( Object aObj, DocumentMetrics aDocumentMetrics ) {
super( new PolyglotPropertiesFactory( aDocumentMetrics ).toProperties( aObj ) );
}
/**
* Create a {@link PolyglotProperties} 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.
*/
public PolyglotProperties( Properties aProperties ) {
super( new PolyglotPropertiesFactory().toProperties( aProperties ) );
}
/**
* Create a {@link PolyglotProperties} 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 When set to true
then unmarshaling
* (XML) documents will preserve the preserve the root element
* (envelope). As an (XML) document requires a root element, the root
* element often is provided merely as of syntactic reasons and must
* be omitted as of semantic reasons. Unmarshaling functionality
* therefore by default skips the root elelemt, as this is considered
* merely to serve as an envelope. This behavior can be overridden by
* setting this property to true
.
*/
public PolyglotProperties( Properties aProperties, DocumentMetrics aDocumentMetrics ) {
super( new PolyglotPropertiesFactory( aDocumentMetrics ).toProperties( aProperties ) );
}
/**
* Create a {@link PolyglotProperties} instance containing the elements of
* the provided {@link PropertiesBuilder} instance using the default path
* delimiter "/" ({@link Delimiter#PATH}) for the path declarations.
*
* @param aPropertiesBuilder the properties to be added.
*/
public PolyglotProperties( PropertiesBuilder aPropertiesBuilder ) {
super( new PolyglotPropertiesFactory().toProperties( aPropertiesBuilder ) );
}
/**
* Create a {@link PolyglotProperties} instance containing the elements of
* the provided {@link PropertiesBuilder} instance using the default path
* delimiter "/" ({@link Delimiter#PATH}) for the path declarations.
*
* @param aPropertiesBuilder the properties to be added.
* @param aDocumentMetrics When set to true
then unmarshaling
* (XML) documents will preserve the preserve the root element
* (envelope). As an (XML) document requires a root element, the root
* element often is provided merely as of syntactic reasons and must
* be omitted as of semantic reasons. Unmarshaling functionality
* therefore by default skips the root elelemt, as this is considered
* merely to serve as an envelope. This behavior can be overridden by
* setting this property to true
.
*/
public PolyglotProperties( PropertiesBuilder aPropertiesBuilder, DocumentMetrics aDocumentMetrics ) {
super( new PolyglotPropertiesFactory( aDocumentMetrics ).toProperties( aPropertiesBuilder ) );
}
/**
* Loads the {@link PolyglotProperties} from the given file's path.
*
* @param aFilePath The path to the 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.
*/
public PolyglotProperties( String aFilePath ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory().toProperties( aFilePath ) );
}
/**
* Loads the {@link PolyglotProperties} from the given file's path.
*
* @param aFilePath The path to the file from which to load the properties.
* @param aDocumentMetrics When set to true
then unmarshaling
* (XML) documents will preserve the preserve the root element
* (envelope). As an (XML) document requires a root element, the root
* element often is provided merely as of syntactic reasons and must
* be omitted as of semantic reasons. Unmarshaling functionality
* therefore by default skips the root elelemt, as this is considered
* merely to serve as an envelope. This behavior can be overridden by
* setting this property to true
.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public PolyglotProperties( String aFilePath, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory( aDocumentMetrics ).toProperties( aFilePath ) );
}
/**
* Loads the {@link PolyglotProperties} from the given file's path. A
* provided {@link ConfigLocator} describes the locations to additional
* crawl for the desired file.
*
* @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.
*/
public PolyglotProperties( String aFilePath, ConfigLocator aConfigLocator ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory().toProperties( aFilePath, aConfigLocator ) );
}
/**
* Loads the {@link PolyglotProperties} from the given file's path. A
* provided {@link ConfigLocator} describes the locations to additional
* crawl for the desired file.
*
* @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 When set to true
then unmarshaling
* (XML) documents will preserve the preserve the root element
* (envelope). As an (XML) document requires a root element, the root
* element often is provided merely as of syntactic reasons and must
* be omitted as of semantic reasons. Unmarshaling functionality
* therefore by default skips the root elelemt, as this is considered
* merely to serve as an envelope. This behavior can be overridden by
* setting this property to true
.
*
* @throws IOException thrown in case accessing or processing the properties
* file failed.
* @throws ParseException Signals that an error has been reached
* unexpectedly while parsing the data to be loaded.
*/
public PolyglotProperties( String aFilePath, ConfigLocator aConfigLocator, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory( aDocumentMetrics ).toProperties( aFilePath, aConfigLocator ) );
}
/**
* Loads the {@link PolyglotProperties} from the given {@link URL}.
*
* @param aUrl The {@link URL} 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.
*/
public PolyglotProperties( URL aUrl ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory().toProperties( aUrl ) );
}
/**
* Loads the {@link PolyglotProperties} 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.
*/
public PolyglotProperties( URL aUrl, DocumentMetrics aDocumentMetrics ) throws IOException, ParseException {
super( new PolyglotPropertiesFactory( aDocumentMetrics ).toProperties( aUrl ) );
}
// /////////////////////////////////////////////////////////////////////////
// INNER CLASSES:
// /////////////////////////////////////////////////////////////////////////
/**
* The {@link PolyglotPropertiesFactory} is a meta factory using a
* collection of {@link ResourcePropertiesFactory} instances to deliver
* {@link ResourceProperties} instances. In case a properties file for a
* filename was not found, then the according factories filename extension
* ({@link ResourcePropertiesFactory#getFilenameSuffixes()}) is append to
* the filename and probing is repeated. Any factory method such as
* {@link #toProperties(Map)}, {@link #toProperties(Object)},
* {@link #toProperties(Properties)} or
* {@link #toProperties(PropertiesBuilder)} will return
* {@link ResourceProperties} created by the first added
* {@link ResourcePropertiesFactory} instance.
*/
public static class PolyglotPropertiesFactory implements ResourcePropertiesFactory {
// /////////////////////////////////////////////////////////////////////
// VARIABLES:
// /////////////////////////////////////////////////////////////////////
private final List _factories = new ArrayList<>();
// /////////////////////////////////////////////////////////////////////
// CONSTRUCTORS:
// /////////////////////////////////////////////////////////////////////
/**
* Initializes the {@link PolyglotPropertiesBuilderFactory} with a
* predefined set of {@link ResourcePropertiesBuilderFactory} instances.
*/
public PolyglotPropertiesFactory() {
this( DocumentNotation.DEFAULT );
}
/**
* Initializes the {@link PolyglotPropertiesFactory} with a predefined
* set of {@link ResourcePropertiesFactory} instances.
*
* @param aDocumentMetrics When set to true
then
* unmarshaling (XML) documents will preserve the preserve the
* root element (envelope). As an (XML) document requires a root
* element, the root element often is provided merely as of
* syntactic reasons and must be omitted as of semantic reasons.
* Unmarshaling functionality therefore by default skips the root
* elelemt, as this is considered merely to serve as an envelope.
* This behavior can be overridden by setting this property to
* true
.
*/
public PolyglotPropertiesFactory( DocumentMetrics aDocumentMetrics ) {
_factories.add( new TomlPropertiesFactory( aDocumentMetrics ) );
_factories.add( new YamlPropertiesFactory() );
_factories.add( new XmlPropertiesFactory( aDocumentMetrics ) );
_factories.add( new JsonPropertiesFactory() );
_factories.add( new JavaPropertiesFactory( aDocumentMetrics ) ); // Last as them Java properties eat all notations
}
/**
* Initializes the {@link PolyglotPropertiesFactory} with the given
* {@link ResourcePropertiesFactory} instances. Them factories will be
* queried in the order being provided.
*
* @param aFactories The factories to be added.
*/
public PolyglotPropertiesFactory( ResourcePropertiesFactory... aFactories ) {
for ( ResourcePropertiesFactory eFactory : aFactories ) {
_factories.add( eFactory );
}
}
// /////////////////////////////////////////////////////////////////////
// METHODS:
// /////////////////////////////////////////////////////////////////////
/**
* Returns the filename extensions of the ResourcePropertiesFactory in
* the given order. {@inheritDoc}
*/
@Override
public String[] getFilenameSuffixes() {
final List theExtensions = new ArrayList<>();
String[] eExtensions;
for ( ResourcePropertiesFactory _factorie : _factories ) {
eExtensions = _factorie.getFilenameSuffixes();
if ( eExtensions != null ) {
for ( String eExtension : eExtensions ) {
theExtensions.add( eExtension );
}
}
}
return theExtensions.toArray( new String[theExtensions.size()] );
}
/**
* {@inheritDoc}
*/
@Override
public ResourceProperties toProperties( Class> aResourceClass, String aFilePath, ConfigLocator aConfigLocator ) throws IOException, ParseException {
Exception theCause = null;
// Keep the precedence |-->
try {
return toPropertiesFromFilePath( aFilePath, aConfigLocator );
}
catch ( Exception e ) {
if ( theCause == null ) {
theCause = e;
}
}
// Keep the precedence <--|
for ( ResourcePropertiesFactory eFactory : _factories ) {
try {
return eFactory.toProperties( aResourceClass, aFilePath, aConfigLocator );
}
catch ( Exception e ) {
if ( theCause == null ) {
theCause = e;
}
}
}
// Test with the factorie's filename extension |-->
String[] eExtensions;
for ( ResourcePropertiesFactory eFactory : _factories ) {
eExtensions = eFactory.getFilenameSuffixes();
if ( eExtensions != null ) {
for ( String eExtension : eExtensions ) {
try {
return eFactory.toProperties( aResourceClass, aFilePath + eExtension, aConfigLocator );
}
catch ( Exception e ) {
if ( theCause == null ) {
theCause = e;
}
}
}
}
}
// Test with the factorie's filename extension <--|
if ( theCause instanceof IOException ) {
throw (IOException) theCause;
}
if ( theCause instanceof ParseException ) {
throw (ParseException) theCause;
}
throw new IOException( "No configuration file with name (scheme) <" + aFilePath + "> found, where a suffix (if applicable) might by one of the following: " + Arrays.toString( getFilenameSuffixes() ) );
}
/**
* {@inheritDoc}
*/
@Override
public ResourceProperties toProperties( File aFile, ConfigLocator aConfigLocator ) throws IOException, ParseException {
Exception theCause = null;
// Keep the precedence |-->
try {
return toPropertiesFromFilePath( aFile.getPath(), aConfigLocator );
}
catch ( Exception e ) {
if ( theCause == null ) {
theCause = e;
}
}
// Keep the precedence <--|
for ( ResourcePropertiesFactory eFactory : _factories ) {
try {
return eFactory.toProperties( aFile, aConfigLocator );
}
catch ( Exception e ) {
if ( theCause == null ) {
theCause = e;
}
}
}
// Test with the factorie's filename extension |-->
File eFile;
String[] eExtensions;
for ( ResourcePropertiesFactory eFactory : _factories ) {
eExtensions = eFactory.getFilenameSuffixes();
if ( eExtensions != null ) {
for ( String eExtension : eExtensions ) {
eFile = new File( aFile.getAbsolutePath() + eExtension );
try {
return eFactory.toProperties( eFile, aConfigLocator );
}
catch ( Exception e ) {
if ( theCause == null ) {
theCause = e;
}
}
}
}
}
// Test with the factorie's filename extension <--|
if ( theCause instanceof IOException ) {
throw (IOException) theCause;
}
if ( theCause instanceof ParseException ) {
throw (ParseException) theCause;
}
throw new IOException( "No configuration file with name (scheme) <" + aFile.toPath() + "> found, where a suffix (if applicable) might by one of the following: " + Arrays.toString( getFilenameSuffixes() ) );
}
/**
* {@inheritDoc}
*/
@Override
public ResourceProperties toProperties( InputStream aInputStream ) throws IOException, ParseException {
Exception theCause = null;
final byte[] theBytes = toByteArray( aInputStream );
for ( ResourcePropertiesFactory eFactory : _factories ) {
try {
return eFactory.toProperties( new ByteArrayInputStream( theBytes ) );
}
catch ( Exception e ) {
if ( theCause == null ) {
theCause = e;
}
}
}
if ( theCause instanceof IOException ) {
throw (IOException) theCause;
}
if ( theCause instanceof ParseException ) {
throw (ParseException) theCause;
}
throw new IOException( "No configuration file for the given InputStream found!" );
}
/**
* Will return {@link ResourceProperties} created by the first added
* {@link ResourcePropertiesFactory} instance. {@inheritDoc}
*/
@Override
public ResourceProperties toProperties( Map, ?> aProperties ) {
return _factories.get( 0 ).toProperties( aProperties );
}
/**
* Will return {@link ResourceProperties} created by the first added
* {@link ResourcePropertiesFactory} instance. {@inheritDoc}
*/
@Override
public ResourceProperties toProperties( Object aObj ) {
return _factories.get( 0 ).toProperties( aObj );
}
/**
* Will return {@link ResourceProperties} created by the first added
* {@link ResourcePropertiesFactory} instance. {@inheritDoc}
*/
@Override
public ResourceProperties toProperties( Properties aProperties ) {
return _factories.get( 0 ).toProperties( aProperties );
}
/**
* Will return {@link ResourceProperties} created by the first added
* {@link ResourcePropertiesFactory} instance. {@inheritDoc}
*/
@Override
public ResourceProperties toProperties( PropertiesBuilder aProperties ) {
return _factories.get( 0 ).toProperties( aProperties );
}
/**
* {@inheritDoc}
*/
@Override
public ResourceProperties toProperties( String aFilePath, ConfigLocator aConfigLocator ) throws IOException, ParseException {
return toProperties( null, aFilePath, aConfigLocator );
}
/**
* {@inheritDoc}
*/
@Override
public ResourceProperties toProperties( URL aUrl ) throws IOException, ParseException {
Exception theCause = null;
// Try file extension's factory first |-->
try {
final ResourcePropertiesFactory theFactory = fromFilenameExtension( aUrl.toExternalForm() );
if ( theFactory != null ) {
return theFactory.toProperties( aUrl );
}
}
catch ( Exception e ) {
if ( theCause == null ) {
theCause = e;
}
}
// Try file extension's factory first <--|
for ( ResourcePropertiesFactory eFactory : _factories ) {
try {
return eFactory.toProperties( aUrl );
}
catch ( Exception e ) {
if ( theCause == null ) {
theCause = e;
}
}
}
// Test with the factorie's filename extension |-->
URL eUrl;
String[] eExtensions;
for ( ResourcePropertiesFactory eFactory : _factories ) {
eExtensions = eFactory.getFilenameSuffixes();
if ( eExtensions != null ) {
for ( String eExtension : eExtensions ) {
eUrl = new URL( aUrl.toExternalForm() + eExtension );
try {
return eFactory.toProperties( eUrl );
}
catch ( Exception e ) {
if ( theCause == null ) {
theCause = e;
}
}
}
}
}
// Test with the factorie's filename extension <--|
if ( theCause instanceof IOException ) {
throw (IOException) theCause;
}
if ( theCause instanceof ParseException ) {
throw (ParseException) theCause;
}
throw new IOException( "No configuration file with (base) URL <" + aUrl.toExternalForm() + "> found!" );
}
// /////////////////////////////////////////////////////////////////////
// HELPER:
// /////////////////////////////////////////////////////////////////////
private ResourcePropertiesFactory fromFilenameExtension( String aFilePath ) {
String[] eExtensions;
for ( ResourcePropertiesFactory eFactory : _factories ) {
eExtensions = eFactory.getFilenameSuffixes();
if ( eExtensions != null ) {
for ( String eExtension : eExtensions ) {
if ( aFilePath.endsWith( eExtension ) ) {
return eFactory;
}
}
}
}
return null;
}
private ResourceProperties toPropertiesFromFilePath( String aFilePath, ConfigLocator aConfigLocator ) throws IOException, ParseException {
Exception theCause = null;
final File theFile = new File( aFilePath );
File eFile;
if ( theFile.exists() ) {
try {
final ResourcePropertiesFactory theFactory = fromFilenameExtension( theFile.getAbsolutePath() );
if ( theFactory != null ) {
return theFactory.toProperties( theFile, ConfigLocator.ABSOLUTE );
}
}
catch ( IOException | ParseException e ) {
if ( theCause == null ) {
theCause = e;
}
}
}
else {
for ( ResourcePropertiesFactory eFactory : _factories ) {
for ( String eExtension : eFactory.getFilenameSuffixes() ) {
eFile = new File( aFilePath + eExtension );
if ( eFile.exists() ) {
try {
return eFactory.toProperties( eFile, ConfigLocator.ABSOLUTE );
}
catch ( IOException | ParseException e ) {
if ( theCause == null ) {
theCause = e;
}
}
}
}
}
if ( aConfigLocator != null && aConfigLocator != ConfigLocator.ABSOLUTE ) {
for ( File eDir : aConfigLocator.getFolders() ) {
for ( ResourcePropertiesFactory eFactory : _factories ) {
for ( String eExtension : eFactory.getFilenameSuffixes() ) {
eFile = new File( eDir, aFilePath + eExtension );
if ( eFile.exists() ) {
try {
return eFactory.toProperties( eFile, ConfigLocator.ABSOLUTE );
}
catch ( IOException | ParseException e ) {
if ( theCause == null ) {
theCause = e;
}
}
}
}
}
}
}
}
if ( theCause instanceof IOException ) {
throw (IOException) theCause;
}
if ( theCause instanceof ParseException ) {
throw (ParseException) theCause;
}
throw new IOException( "No configuration file with name (scheme) <" + aFilePath + "> found, where the suffix may by one of the following: " + Arrays.toString( getFilenameSuffixes() ) );
}
// /////////////////////////////////////////////////////////////////////
// HOOKS:
// /////////////////////////////////////////////////////////////////////
/**
* Converts a byte array from an {@link InputStream}.
*
* @param aInputStream The {@link InputStream} to be converted.
*
* @return The byte array from the {@link InputStream}.
*
* @throws IOException Thrown in case there were problems reading the
* {@link InputStream}.
*/
public static byte[] toByteArray( InputStream aInputStream ) throws IOException {
final ByteArrayOutputStream theBuffer = new ByteArrayOutputStream();
int eRead;
final byte[] theData = new byte[16384];
while ( ( eRead = aInputStream.read( theData, 0, theData.length ) ) != -1 ) {
theBuffer.write( theData, 0, eRead );
}
theBuffer.flush();
return theBuffer.toByteArray();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy