> ambiguous) {
+ StringBuffer classes = new StringBuffer();
+
+ int i = 0;
+ for (Class extends T> clazz : ambiguous) {
+ if (i++ != 0) {
+ classes.append(", ");
+ }
+
+ classes.append(clazz.getCanonicalName());
+ }
+
+ return bundle.ambigousStrategyResolution(type.getCanonicalName(), classes.toString());
+ }
+}
+
diff --git a/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/annotation/Configuration.java b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/annotation/Configuration.java
new file mode 100644
index 0000000..3c519bf
--- /dev/null
+++ b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/annotation/Configuration.java
@@ -0,0 +1,82 @@
+package org.demoiselle.jee.configuration.annotation;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Stereotype;
+import javax.enterprise.util.Nonbinding;
+import javax.inject.Named;
+import javax.interceptor.InterceptorBinding;
+
+import org.demoiselle.jee.configuration.ConfigType;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ *
+ * Identifies a configuration class, that is, a structure reserved to store configuration values retrieved from a
+ * given resource file or system variables.
+ *
+ *
+ * Configuration resources are application scoped, meaning only one instance can ever exist in
+ * a running application. For that reason usually configuration fields are immutable, to avoid
+ * changes made in one context affecting other contexts in a running application.
+ *
+ * A Configuration is:
+ *
+ * - defined when annotated with {@code @Configuration}
+ * - automatically injected whenever {@code @Inject} is used
+ *
+ *
+ * @author SERPRO
+ */
+@ApplicationScoped
+@Named
+@InterceptorBinding
+@Stereotype
+@Target(TYPE)
+@Retention(RUNTIME)
+public @interface Configuration {
+
+ /**
+ * Define the default prefix.
+ */
+ String DEFAULT_PREFIX = "demoiselle";
+
+ /**
+ * Define the default resource.
+ */
+ String DEFAULT_RESOURCE = "demoiselle";
+
+ /**
+ * Defines the resource type to be used: a properties file, an XML file, or system variables.
+ * If not specified, a properties resource file is to be considered.
+ *
+ * @return ConfigType Type of configuration resource file to look for
+ */
+ @Nonbinding ConfigType type() default ConfigType.PROPERTIES;
+
+ /**
+ * Defines an optional prefix to be used on every parameter key.
+ * For instance, if prefix is set to "demoiselle.pagination"
and an attribute named
+ * defaultPageSize
is found in the class, the corresponding key
+ * demoiselle.pagination.defaultPageSize
is expected to be read in the resource file.
+ *
+ * @return String prefix common to all attributes to be read by the configuration class
+ */
+ @Nonbinding String prefix() default DEFAULT_PREFIX;
+
+ /**
+ * Defines the resource file name to be read by this configuration class. There is no need to specify file extension
+ * in the case of properties or XML resources.
+ * For instance, when resource is set to "bookmark"
and the type set to properties, a corresponding
+ * file named bookmark.properties
is considered.
+ * If not specified, the default configuration file demoiselle.properties
is used instead.
+ *
+ * @return String Name of the resource file to look for (minus file extension)
+ */
+ @Nonbinding String resource() default DEFAULT_RESOURCE;
+
+}
diff --git a/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/ConfigurationValueExtractor.java b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/ConfigurationValueExtractor.java
new file mode 100644
index 0000000..6f974af
--- /dev/null
+++ b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/ConfigurationValueExtractor.java
@@ -0,0 +1,51 @@
+package org.demoiselle.jee.configuration.extractor;
+
+import java.lang.reflect.Field;
+
+import org.apache.commons.configuration2.Configuration;
+
+/**
+ *
+ * Interface that defines how to convert values extracted from configuration
+ * files to fields in a class annotated with {@link Configuration}.
+ *
+ *
+ *
+ * Primitive types like int
and float
, their wrapper
+ * counterparts like {@link Integer} and {@link Float} and the {@link String} class
+ * can already be converted by the framework, this interface is reserved for specialized
+ * classes.
+ *
+ *
+ * @author SERPRO
+ */
+public interface ConfigurationValueExtractor {
+
+ /**
+ * Method that must appropriately extract the value from a property file and set this value to a
+ * field in a configuration class.
+ *
+ * @param prefix
+ * optional parte of property name that must be concatenated with key to form the whole
+ * property name.
+ * @param key
+ * key of the property.
+ * @param field
+ * configuration field to be setted.
+ * @param configuration
+ * a configuration object.
+ * @return current value of this property
+ * @throws Exception if the value can't be extracted from the property file
+ */
+ Object getValue(String prefix, String key, Field field, Configuration configuration) throws Exception;
+
+ /**
+ * Checks if the extractor class is appropriate to extract values to the type of deffined by parameter
+ * field.
+ *
+ * @param field
+ * field to be checked.
+ * @return true
if this extractor can convert this field into the extractor's final type
+ */
+ boolean isSupported(Field field);
+}
diff --git a/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationArrayValueExtractor.java b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationArrayValueExtractor.java
new file mode 100644
index 0000000..42ef76c
--- /dev/null
+++ b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationArrayValueExtractor.java
@@ -0,0 +1,24 @@
+package org.demoiselle.jee.configuration.extractor.impl;
+
+import java.lang.reflect.Field;
+
+import javax.enterprise.context.Dependent;
+
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.DataConfiguration;
+import org.demoiselle.jee.configuration.extractor.ConfigurationValueExtractor;
+import org.demoiselle.jee.core.annotation.Priority;
+import static org.demoiselle.jee.core.annotation.Priority.*;
+
+@Dependent
+@Priority(L2_PRIORITY)
+public class ConfigurationArrayValueExtractor implements ConfigurationValueExtractor {
+
+ public Object getValue(String prefix, String key, Field field, Configuration configuration) throws Exception {
+ return new DataConfiguration(configuration).getArray(field.getType().getComponentType(), prefix + key);
+ }
+
+ public boolean isSupported(Field field) {
+ return field.getType().isArray();
+ }
+}
diff --git a/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationClassValueExtractor.java b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationClassValueExtractor.java
new file mode 100644
index 0000000..85411e2
--- /dev/null
+++ b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationClassValueExtractor.java
@@ -0,0 +1,65 @@
+package org.demoiselle.jee.configuration.extractor.impl;
+
+import java.lang.reflect.Field;
+
+import java.net.URL;
+
+import javax.enterprise.context.Dependent;
+
+import org.apache.commons.configuration2.Configuration;
+import org.demoiselle.jee.configuration.extractor.ConfigurationValueExtractor;
+import org.demoiselle.jee.core.annotation.Priority;
+
+import static org.demoiselle.jee.core.annotation.Priority.*;
+
+@Dependent
+@Priority(L2_PRIORITY)
+public class ConfigurationClassValueExtractor implements ConfigurationValueExtractor {
+
+ public Object getValue(String prefix, String key, Field field, Configuration configuration) throws Exception {
+ Object value = null;
+ String canonicalName = configuration.getString(prefix + key);
+
+ if (canonicalName != null) {
+ value = forName(canonicalName);
+ }
+
+ return value;
+ }
+
+ public boolean isSupported(Field field) {
+ return field.getType() == Class.class;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Class forName(final String className) throws ClassNotFoundException {
+ ClassLoader classLoader = getClassLoaderForClass(className);
+ return (Class) Class.forName(className, true, classLoader);
+ }
+
+ public ClassLoader getClassLoaderForClass(final String canonicalName) {
+ return getClassLoaderForResource(canonicalName.replaceAll("\\.", "/") + ".class");
+ }
+
+ public ClassLoader getClassLoaderForResource(final String resource) {
+ final String stripped = resource.charAt(0) == '/' ? resource.substring(1) : resource;
+
+ URL url = null;
+ ClassLoader result = Thread.currentThread().getContextClassLoader();
+
+ if (result != null) {
+ url = result.getResource(stripped);
+ }
+
+ if (url == null) {
+ result = getClass().getClassLoader();
+ url = getClass().getClassLoader().getResource(stripped);
+ }
+
+ if (url == null) {
+ result = null;
+ }
+
+ return result;
+ }
+}
diff --git a/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationEnumValueExtractor.java b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationEnumValueExtractor.java
new file mode 100644
index 0000000..93b5d09
--- /dev/null
+++ b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationEnumValueExtractor.java
@@ -0,0 +1,42 @@
+package org.demoiselle.jee.configuration.extractor.impl;
+
+import java.lang.reflect.Field;
+
+import javax.enterprise.context.Dependent;
+
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.ex.ConversionException;//
+import org.demoiselle.jee.configuration.extractor.ConfigurationValueExtractor;
+import org.demoiselle.jee.configuration.message.ConfigurationMessage;
+import org.demoiselle.jee.core.annotation.Priority;
+import static org.demoiselle.jee.core.annotation.Priority.*;
+
+@Dependent
+@Priority(L2_PRIORITY)
+public class ConfigurationEnumValueExtractor implements ConfigurationValueExtractor {
+
+ private transient ConfigurationMessage bundle;
+
+ public Object getValue(String prefix, String key, Field field, Configuration configuration) throws Exception {
+ String value = configuration.getString(prefix + key);
+
+ if (value != null && !value.trim().equals("")) {
+ Object enums[] = field.getType().getEnumConstants();
+
+ for (int i = 0; i < enums.length; i++) {
+ if (((Enum>) enums[i]).name().equals(value)) {
+ return enums[i];
+ }
+ }
+ } else {
+ return null;
+ }
+
+ throw new ConversionException(bundle.configurationNotConversion(value, field.getDeclaringClass().getCanonicalName()));
+ }
+
+ public boolean isSupported(Field field) {
+ return field.getType().isEnum();
+ }
+
+}
diff --git a/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationMapValueExtractor.java b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationMapValueExtractor.java
new file mode 100644
index 0000000..d1d4707
--- /dev/null
+++ b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationMapValueExtractor.java
@@ -0,0 +1,52 @@
+package org.demoiselle.jee.configuration.extractor.impl;
+
+import java.lang.reflect.Field;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.enterprise.context.Dependent;
+
+import org.apache.commons.configuration2.Configuration;
+import org.demoiselle.jee.configuration.extractor.ConfigurationValueExtractor;
+import org.demoiselle.jee.core.annotation.Priority;
+
+import static org.demoiselle.jee.core.annotation.Priority.*;
+
+
+@Dependent
+@Priority(L2_PRIORITY)
+public class ConfigurationMapValueExtractor implements ConfigurationValueExtractor {
+
+ public Object getValue(String prefix, String key, Field field, Configuration configuration) throws Exception {
+ Map value = null;
+
+ String regexp = "^(" + prefix + ")(" + key + ")(\\.(\\w+))?$";
+ Pattern pattern = Pattern.compile(regexp);
+
+ for (Iterator iter = configuration.getKeys(); iter.hasNext();) {
+ String iterKey = iter.next();
+ Matcher matcher = pattern.matcher(iterKey);
+
+ if (matcher.matches()) {
+ String confKey = matcher.group(1) + matcher.group(2) + ( matcher.group(3)!=null ? matcher.group(3) : "" );
+
+ if (value == null) {
+ value = new HashMap<>();
+ }
+
+ String mapKey = matcher.group(4) == null ? "default" : matcher.group(4);
+ value.put(mapKey, configuration.getString(confKey));
+ }
+ }
+
+ return value;
+ }
+
+ public boolean isSupported(Field field) {
+ return field.getType() == Map.class;
+ }
+}
diff --git a/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationPrimitiveOrWrapperValueExtractor.java b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationPrimitiveOrWrapperValueExtractor.java
new file mode 100644
index 0000000..c8d0271
--- /dev/null
+++ b/demoiselle-configuration/src/main/java/org/demoiselle/jee/configuration/extractor/impl/ConfigurationPrimitiveOrWrapperValueExtractor.java
@@ -0,0 +1,55 @@
+package org.demoiselle.jee.configuration.extractor.impl;
+
+import java.lang.reflect.Field;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.enterprise.context.Dependent;
+
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.DataConfiguration;
+import org.apache.commons.configuration2.ex.ConversionException;
+import org.apache.commons.lang3.ClassUtils;
+import org.demoiselle.jee.configuration.extractor.ConfigurationValueExtractor;
+
+import org.demoiselle.jee.core.annotation.Priority;
+
+import static org.demoiselle.jee.core.annotation.Priority.*;
+
+@Dependent
+@Priority(L2_PRIORITY)
+public class ConfigurationPrimitiveOrWrapperValueExtractor implements ConfigurationValueExtractor {
+
+ private static final Set