aboutsummaryrefslogtreecommitdiff
path: root/src/Java/miscutil/core/util/aeonbits
diff options
context:
space:
mode:
Diffstat (limited to 'src/Java/miscutil/core/util/aeonbits')
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/Accessible.java156
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/Config.java345
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/ConfigCache.java145
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/ConfigFactory.java136
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/ConfigURIFactory.java53
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/Converter.java35
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/Converters.java314
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/DefaultFactory.java103
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/Delegate.java20
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/DelegateMethodHandle.java41
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/Factory.java91
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/HotReloadLogic.java103
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/JMXSupport.java109
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/LoadersManager.java95
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/Mutable.java118
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/Preprocessor.java20
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/PreprocessorResolver.java47
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/PropertiesInvocationHandler.java141
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/PropertiesManager.java584
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/PropertiesMapper.java47
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/Reloadable.java70
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/SplitAndTrimTokenizer.java33
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/StrSubstitutor.java86
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/Tokenizer.java29
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/TokenizerResolver.java76
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/Util.java266
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/VariablesExpander.java41
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/event/Event.java31
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/event/ReloadEvent.java77
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/event/ReloadListener.java33
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/event/RollbackBatchException.java37
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/event/RollbackException.java34
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/event/RollbackOperationException.java35
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/event/TransactionalPropertyChangeListener.java33
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/event/TransactionalReloadListener.java28
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/event/UnmodifiableProperties.java64
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/event/package-info.java17
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/loaders/Loader.java50
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/loaders/PropertiesLoader.java57
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/loaders/XMLLoader.java162
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/loaders/package-info.java12
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/package-info.java51
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/util/Collections.java81
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/util/Reflection.java68
-rw-r--r--src/Java/miscutil/core/util/aeonbits/owner/util/package-info.java12
45 files changed, 4186 insertions, 0 deletions
diff --git a/src/Java/miscutil/core/util/aeonbits/owner/Accessible.java b/src/Java/miscutil/core/util/aeonbits/owner/Accessible.java
new file mode 100644
index 0000000000..cbd770f4a8
--- /dev/null
+++ b/src/Java/miscutil/core/util/aeonbits/owner/Accessible.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2012-2015, Luigi R. Viggiano
+ * All rights reserved.
+ *
+ * This software is distributable under the BSD license.
+ * See the terms of the BSD license in the documentation provided with this software.
+ */
+
+package miscutil.core.util.aeonbits.owner;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * <p>Allows a <tt>Config</tt> object to access the contents of the properties, providing utility methods to perform
+ * consequent operations.</p>
+ * <p>Example:</p>
+ * <pre>
+ * public interface MyConfig extends Config, Accessible {
+ * int someProperty();
+ * }
+ *
+ * public void doSomething() {
+ * MyConfig cfg = ConfigFactory.create(MyConfig.class);
+ * cfg.list(System.out);
+ * }
+ * </pre>
+ * <p>These methods will print the list of properties, see {@link java.util.Properties#list(java.io.PrintStream)} and
+ * {@link java.util.Properties#list(java.io.PrintWriter)}.</p>
+ *
+ * @author Luigi R. Viggiano
+ * @since 1.0.4
+ */
+public interface Accessible extends Config {
+
+ /**
+ * Prints this property list out to the specified output stream. This method is useful for debugging.
+ *
+ * @param out an output stream.
+ * @throws ClassCastException if any key in this property list is not a string.
+ * @see java.util.Properties#list(java.io.PrintStream)
+ * @since 1.0.4
+ */
+ void list(PrintStream out);
+
+ /**
+ * Prints this property list out to the specified output stream. This method is useful for debugging.
+ *
+ * @param out an output stream.
+ * @throws ClassCastException if any key in this property list is not a string.
+ * @see java.util.Properties#list(java.io.PrintWriter)
+ * @since 1.0.4
+ */
+ void list(PrintWriter out);
+
+ /**
+ * Stores the underlying properties into an {@link java.io.OutputStream}.
+ * <p>
+ * Notice that method {@link java.util.Properties#store(java.io.Writer, String)} is not implemented since it's not
+ * available in JDK 1.5 (while the target of this library is Java 1.5+).
+ *
+ * @param out an output stream.
+ * @param comments a description of the property list.
+ * @throws IOException if writing this property list to the specified output stream throws an <tt>IOException</tt>.
+ * @see java.util.Properties#store(java.io.OutputStream, String)
+ * @since 1.0.4
+ */
+ void store(OutputStream out, String comments) throws IOException;
+
+ /**
+ * Fills the given {@link java.util.Map} with the properties contained by this object. <br>
+ * This is useful to extract the content of the config object into a {@link java.util.Map}.
+ * <p>
+ * Notice that you can specify a properties object as parameter instead of a map,
+ * since {@link java.util.Properties} implements the {@link java.util.Map} interface.
+ *
+ * @param map the {@link java.util.Map} to fill.
+ * @since 1.0.9
+ */
+ void fill(Map map);
+
+ /**
+ * Searches for the property with the specified key in this property list.
+ * If the key is not found in this property list, the default property list,
+ * and its defaults, recursively, are then checked. The method returns
+ * <code>null</code> if the property is not found.
+ *
+ * @param key the property key.
+ * @return the value in this property list with the specified key value.
+ * @see java.util.Properties#getProperty(String)
+ * @since 1.0.4
+ */
+ String getProperty(String key);
+
+ /**
+ * Searches for the property with the specified key in this property list.
+ * If the key is not found in this property list, the default property list,
+ * and its defaults, recursively, are then checked. The method returns the
+ * default value argument if the property is not found.
+ *
+ * @param key the property key.
+ * @param defaultValue a default value.
+ * @return the value in this property list with the specified key value.
+ * @see java.util.Properties#getProperty(String, String)
+ *
+ * @since 1.0.4
+ */
+ String getProperty(String key, String defaultValue);
+
+ /**
+ * Emits an XML document representing all of the properties contained
+ * in this table.
+ *
+ * <p> An invocation of this method of the form <tt>props.storeToXML(os,
+ * comment)</tt> behaves in exactly the same way as the invocation
+ * <tt>props.storeToXML(os, comment, "UTF-8");</tt>.
+ *
+ * @param os the output stream on which to emit the XML document.
+ * @param comment a description of the property list, or <code>null</code>
+ * if no comment is desired.
+ * @throws IOException if writing to the specified output stream
+ * results in an <tt>IOException</tt>.
+ * @throws NullPointerException if <code>os</code> is null.
+ * @throws ClassCastException if this <code>Properties</code> object
+ * contains any keys or values that are not
+ * <code>Strings</code>.
+ * @since 1.0.5
+ */
+ void storeToXML(OutputStream os, String comment) throws IOException;
+
+ /**
+ * Returns a set of keys in this property list
+ * including distinct keys in the default property list if a key
+ * of the same name has not already been found from the main
+ * properties list.
+ * <p>
+ * The returned set is not backed by the <tt>Properties</tt> object.
+ * Changes to this <tt>Properties</tt> are not reflected in the set,
+ * or vice versa.
+ *
+ * @return a set of keys in this property list, including the keys in the
+ * default property list.
+ * @throws ClassCastException if any key in this property list
+ * is not a string.
+ * @see java.util.Properties#defaults
+ * @see java.util.Properties#stringPropertyNames()
+ * @see java.util.Properties#propertyNames()
+ * @since 1.0.5
+ */
+ Set<String> propertyNames();
+
+}
diff --git a/src/Java/miscutil/core/util/aeonbits/owner/Config.java b/src/Java/miscutil/core/util/aeonbits/owner/Config.java
new file mode 100644
index 0000000000..ab7fa23cc1
--- /dev/null
+++ b/src/Java/miscutil/core/util/aeonbits/owner/Config.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2012-2015, Luigi R. Viggiano
+ * All rights reserved.
+ *
+ * This software is distributable under the BSD license.
+ * See the terms of the BSD license in the documentation provided with this software.
+ */
+
+package miscutil.core.util.aeonbits.owner;
+
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.net.URI;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static miscutil.core.util.aeonbits.owner.Config.HotReloadType.SYNC;
+import static miscutil.core.util.aeonbits.owner.Config.LoadType.FIRST;
+import static miscutil.core.util.aeonbits.owner.Util.ignore;
+import static miscutil.core.util.aeonbits.owner.Util.reverse;
+
+/**
+ * Marker interface that must be implemented by all Config sub-interfaces.
+ * <p>
+ * Sub-interfaces may also extend {@link Accessible} to allow some debugging facility, or {@link Reloadable} to allow the
+ * user to programmatically reload properties.
+ * </p>
+ *
+ * @author Luigi R. Viggiano
+ * @see java.util.Properties
+ */
+public interface Config extends Serializable {
+
+ /**
+ * Specifies the policy for loading the properties files. By default the first available properties file specified
+ * by {@link Sources} will be loaded, see {@link LoadType#FIRST}. User can also specify that the load policy is
+ * {@link LoadType#MERGE} to have the properties files merged: properties are loaded in order from the first file to
+ * the last, if there are conflicts in properties names the earlier files loaded prevail.
+ *
+ * @since 1.0.2
+ */
+ @Retention(RUNTIME)
+ @Target(TYPE)
+ @Documented
+ @interface LoadPolicy {
+ LoadType value() default FIRST;
+ }
+
+ /**
+ * Specifies the source from which to load the properties file. It has to be specified in a URI string format.
+ * By default, allowed protocols are the ones allowed by {@link java.net.URL} plus
+ * <tt>classpath:path/to/resource.properties</tt>, but user can specify his own additional protocols.
+ *
+ * @since 1.0.2
+ */
+ @Retention(RUNTIME)
+ @Target(TYPE)
+ @Documented
+ @interface Sources {
+ String[] value();
+ }
+
+ /**
+ * Default value to be used if no property is found. No quoting (other than normal Java string quoting) is done.
+ */
+ @Retention(RUNTIME)
+ @Target(METHOD)
+ @Documented
+ @interface DefaultValue {
+ String value();
+ }
+
+ /**
+ * The key used for lookup for the property. If not present, the key will be generated based on the unqualified
+ * method name.
+ */
+ @Retention(RUNTIME)
+ @Target(METHOD)
+ @Documented
+ @interface Key {
+ String value();
+ }
+
+ /**
+ * Specifies the policy type to use to load the {@link miscutil.core.util.aeonbits.owner.Config.Sources} files for properties.
+ *
+ * @since 1.0.2
+ */
+ enum LoadType {
+
+ /**
+ * The first available of the specified sources will be loaded.
+ */
+ FIRST {
+ @Override
+ Properties load(List<URI> uris, LoadersManager loaders) {
+ Properties result = new Properties();
+ for (URI uri : uris)
+ try {
+ loaders.load(result, uri);
+ break;
+ } catch (IOException ex) {
+ // happens when a file specified in the sources is not found or cannot be read.
+ ignore();
+ }
+ return result;
+ }
+ },
+
+ /**
+ * All the specified sources will be loaded and merged. If the same property key is
+ * specified from more than one source, the one specified first will prevail.
+ */
+ MERGE {
+ @Override
+ Properties load(List<URI> uris, LoadersManager loaders) {
+ Properties result = new Properties();
+ for (URI uri : reverse(uris))
+ try {
+ loaders.load(result, uri);
+ } catch (IOException ex) {
+ // happens when a file specified in the sources is not found or cannot be read.
+ ignore();
+ }
+ return result;
+ }
+ };
+
+ abstract Properties load(List<URI> uris, LoadersManager loaders);
+ }
+
+ /**
+ * Specify that the class implements hot reloading of properties from filesystem baked {@link Sources} (hot
+ * reloading can't be applied to all types of URIs).
+ * <p>
+ * It is possible to specify an interval to indicate how frequently the library shall check the files for
+ * modifications and perform the reload.
+ * </p>
+ * Examples:
+ * <pre>
+ * &#64;HotReload // will check for file changes every 5 seconds.
+ * &#64;Sources("file:foo/bar/baz.properties")
+ * interface MyConfig extends Config { ... }
+ *
+ * &#64;HotReload(2) // will check for file changes every 2 seconds.
+ * &#64;Sources("file:foo/bar/baz.properties")
+ * interface MyConfig extends Config { ... }
+ *
+ * &#64;HotReload(500, unit = TimeUnit.MILLISECONDS); // will check for file changes every 500 milliseconds.
+ * &#64;Sources("file:foo/bar/baz.properties")
+ * interface MyConfig extends Config { ... }
+ *
+ * &#64;HotReload(type=HotReloadType.ASYNC); // will use ASYNC reload type: will span a separate thread
+ * // that will check for the file change every 5 seconds (default).
+ * &#64;Sources("file:foo/bar/baz.properties")
+ * interface MyConfig extends Config { ... }
+ *
+ * &#64;HotReload(2, type=HotReloadType.ASYNC); // will use ASYNC reload type and will check every 2 seconds.
+ * &#64;Sources("file:foo/bar/baz.properties")
+ * interface MyConfig extends Config { ... }
+ * </pre>
+ *
+ * <p>
+ * To intercept the {@link miscutil.core.util.aeonbits.owner.event.ReloadEvent} see {@link Reloadable#addReloadListener(miscutil.core.util.aeonbits.owner.event.ReloadListener)}.
+ *
+ * @since 1.0.4
+ */
+ @Retention(RUNTIME)
+ @Target(TYPE)
+ @Documented
+ @interface HotReload {
+ /**
+ * The interval, expressed in seconds (by default), to perform checks on the filesystem to identify modified
+ * files and eventually perform the reloading of the properties. By default is 5 seconds.
+ *
+ * @return the hot reload value; default is 5.
+ */
+ long value() default 5;
+
+ /**
+ * <p>
+ * The time unit for the interval. By default it is {@link TimeUnit#SECONDS}.
+ * </p>
+ * <p>
+ * Date resolution vary from filesystem to filesystem.<br>
+ * For instance, for Ext3, ReiserFS and HSF+ the date resolution is of 1 second.<br>
+ * For FAT32 the date resolution for the last modified time is 2 seconds. <br>
+ * For Ext4 the date resolution is in nanoseconds.
+ * </p>
+ * <p>
+ * So, it is a good idea to express the time unit in seconds or more, since higher time resolution
+ * will probably not be supported by the underlying filesystem.
+ * </p>
+ * @return the time unit; default is SECONDS.
+ */
+ TimeUnit unit() default SECONDS;
+
+ /**
+ * The type of HotReload to use. It can be:
+ *
+ * <p>
+ * {@link HotReloadType#SYNC Synchronous}: the configuration file is checked when a method is invoked on the
+ * config object. So if the config object is not used for some time, the configuration doesn't get reloaded,
+ * until its next usage. i.e. until next method invocation.
+ * <p>
+ * {@link HotReloadType#ASYNC}: the configuration file is checked by a background thread despite the fact that
+ * the config object is used or not.
+ *
+ * @return the hot reload type; default is SYNC.
+ */
+ HotReloadType type() default SYNC;
+ }
+
+ /**
+ * Allows to specify which type of HotReload should be applied.
+ */
+ enum HotReloadType {
+ /**
+ * The hot reload will happen when one of the methods is invoked on the <tt>Config</tt> class.
+ */
+ SYNC,
+
+ /**
+ * The hot reload will happen in background at the specified interval.
+ */
+ ASYNC
+ }
+
+ /**
+ * Specifies to disable some of the features supported by the API.
+ * This may be useful in case the user prefers to implement by his own, or just has troubles with something that
+ * is unwanted.
+ * Features that can be disabled are specified in the enum {@link DisableableFeature}.
+ *
+ * @since 1.0.4
+ */
+ @Retention(RUNTIME)
+ @Target({METHOD, TYPE})
+ @Documented
+ @interface DisableFeature {
+ DisableableFeature[] value();
+ }
+
+ /**
+ * This enum contains the features that can be disabled using the annotation {@link DisableFeature}.
+ *
+ * @since 1.0.4
+ */
+ enum DisableableFeature {
+ VARIABLE_EXPANSION,
+ PARAMETER_FORMATTING
+ }
+
+ /**
+ * Specifies simple <tt>{@link String}</tt> as separator to tokenize properties values specified as a
+ * single string value, into elements for vectors and collections.
+ * The value specified is used as per {@link String#split(String, int)} with int=-1, every element is also
+ * trimmed out from spaces using {@link String#trim()}.
+ *
+ * Notice that {@link TokenizerClass} and {@link Separator} do conflict with each-other when they are both specified
+ * together on the same level:
+ * <ul>
+ * <li>
+ * You cannot specify {@link TokenizerClass} and {@link Separator} both together on the same method
+ * </li>
+ * <li>
+ * You cannot specify {@link TokenizerClass} and {@link Separator} both together on the same class
+ * </li>
+ * </ul>
+ * in the two above cases an {@link UnsupportedOperationException} will be thrown when the corresponding conversion
+ * is executed.
+ *
+ * @since 1.0.4
+ */
+ @Retention(RUNTIME)
+ @Target({METHOD, TYPE})
+ @Documented
+ @interface Separator {
+ /**
+ * @return the value specified is used as per {@link java.lang.String#split(String, int)} with int=-1
+ */
+ String value();
+ }
+
+ /**
+ * Specifies a <tt>{@link Tokenizer}</tt> class to allow the user to define a custom logic to split
+ * the property value into tokens to be used as single elements for vectors and collections.
+ *
+ * Notice that {@link TokenizerClass} and {@link Separator} do conflict with each-other when they are both specified
+ * together on the same level:
+ * <ul>
+ * <li>
+ * You cannot specify {@link TokenizerClass} and {@link Separator} both together on the same method
+ * </li>
+ * <li>
+ * You cannot specify {@link TokenizerClass} and {@link Separator} both together on the same class
+ * </li>
+ * </ul>
+ * in the two above cases an {@link UnsupportedOperationException} will be thrown when the corresponding conversion
+ * is executed.
+ *
+ * @since 1.0.4
+ */
+ @Retention(RUNTIME)
+ @Target({METHOD, TYPE})
+ @Documented
+ @interface TokenizerClass {
+ Class<? extends Tokenizer> value();
+ }
+
+ /**
+ * Specifies a <tt>{@link Converter}</tt> class to allow the user to define a custom conversion logic for the
+ * type returned by the method. If the method returns a collection, the Converter is used to convert a single
+ * element.
+ */
+ @Retention(RUNTIME)
+ @Target(METHOD)
+ @Documented
+ @interface ConverterClass {
+ Class<? extends Converter> value();
+ }
+
+ /**
+ * Specifies a <tt>{@link Preprocessor}</tt> class to allow the user to define a custom logic to pre-process
+ * the property value before being used by the library.
+ *
+ * @since 1.0.9
+ */
+ @Retention(RUNTIME)
+ @Target({METHOD, TYPE})
+ @Documented
+ @interface PreprocessorClasses {
+ Class<? extends Preprocessor>[] value();
+ }
+
+}
diff --git a/src/Java/miscutil/core/util/aeonbits/owner/ConfigCache.java b/src/Java/miscutil/core/util/aeonbits/owner/ConfigCache.java
new file mode 100644
index 0000000000..5a061e56f8
--- /dev/null
+++ b/src/Java/miscutil/core/util/aeonbits/owner/ConfigCache.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2012-2015, Luigi R. Viggiano
+ * All rights reserved.
+ *
+ * This software is distributable under the BSD license.
+ * See the terms of the BSD license in the documentation provided with this software.
+ */
+
+package miscutil.core.util.aeonbits.owner;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Utility class caching Config instances that can be used as Singletons.
+ *
+ * This class is designed to be thread safe.
+ *
+ * @author Luigi R. Viggiano
+ * @since 1.0.6
+ */
+public final class ConfigCache {
+ private static final ConcurrentMap<Object, Config> CACHE = new ConcurrentHashMap<Object, Config>();
+
+ /** Don't let anyone instantiate this class */
+ private ConfigCache() {}
+
+ /**
+ * Gets from the cache or create, an instance of the given class using the given imports.
+ * The factory used to create new instances is the static {@link ConfigFactory#INSTANCE}.
+ *
+ * @param clazz the interface extending from {@link Config} that you want to instantiate.
+ * @param imports additional variables to be used to resolve the properties.
+ * @param <T> type of the interface.
+ * @return an object implementing the given interface, that can be taken from the cache,
+ * which maps methods to property values.
+ */
+ public static <T extends Config> T getOrCreate(Class<? extends T> clazz, Map<?, ?>... imports) {
+ return getOrCreate(ConfigFactory.INSTANCE, clazz, clazz, imports);
+ }
+
+ /**
+ * Gets from the cache or create, an instance of the given class using the given imports.
+ *
+ * @param factory the factory to use to eventually create the instance.
+ * @param clazz the interface extending from {@link Config} that you want to instantiate.
+ * @param imports additional variables to be used to resolve the properties.
+ * @param <T> type of the interface.
+ * @return an object implementing the given interface, that can be taken from the cache,
+ * which maps methods to property values.
+ */
+ public static <T extends Config> T getOrCreate(Factory factory, Class<? extends T> clazz, Map<?, ?>... imports) {
+ return getOrCreate(factory, clazz, clazz, imports);
+ }
+
+ /**
+ * Gets from the cache or create, an instance of the given class using the given imports.
+ * The factory used to create new instances is the static {@link ConfigFactory#INSTANCE}.
+ *
+ * @param key the key object to be used to identify the instance in the cache.
+ * @param clazz the interface extending from {@link Config} that you want to instantiate.
+ * @param imports additional variables to be used to resolve the properties.
+ * @param <T> type of the interface.
+ * @return an object implementing the given interface, that can be taken from the cache,
+ * which maps methods to property values.
+ */
+ public static <T extends Config> T getOrCreate(Object key, Class<? extends T> clazz, Map<?, ?>... imports) {
+ return getOrCreate(ConfigFactory.INSTANCE, key, clazz, imports);
+ }
+
+ /**
+ * Gets from the cache or create, an instance of the given class using the given imports.
+ *