From c07d38170c0148e7bfd568ca8efc78a4f5c3b275 Mon Sep 17 00:00:00 2001 From: Cleverson Sacramento Date: Wed, 3 Apr 2013 18:15:12 -0300 Subject: [PATCH] Criando estratégias de extração de valores das classes de configuração --- impl/core/src/main/java/br/gov/frameworkdemoiselle/configuration/ConfigurationValueExtractor.java | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/ConfigurationBootstrap.java | 18 ++++++++++++++++-- impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationArrayValueExtractor.java | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationClassValueExtractor.java | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationLoader.java | 119 +++++++++++++++++++++++++++++++---------------------------------------------------------------------------------------- impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationLoaderBackup.java | 470 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationMapValueExtractor.java | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationPrimitiveOrWrapperValueExtractor.java | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationStringValueExtractor.java | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ impl/core/src/test/java/br/gov/frameworkdemoiselle/configuration/AbstractConfigurationTest.java | 11 +++++++++++ 10 files changed, 933 insertions(+), 90 deletions(-) create mode 100644 impl/core/src/main/java/br/gov/frameworkdemoiselle/configuration/ConfigurationValueExtractor.java create mode 100644 impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationArrayValueExtractor.java create mode 100644 impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationClassValueExtractor.java create mode 100644 impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationLoaderBackup.java create mode 100644 impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationMapValueExtractor.java create mode 100644 impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationPrimitiveOrWrapperValueExtractor.java create mode 100644 impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationStringValueExtractor.java diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/configuration/ConfigurationValueExtractor.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/configuration/ConfigurationValueExtractor.java new file mode 100644 index 0000000..7775558 --- /dev/null +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/configuration/ConfigurationValueExtractor.java @@ -0,0 +1,48 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.configuration; + +import java.lang.reflect.Field; + +import org.apache.commons.configuration.DataConfiguration; + +public interface ConfigurationValueExtractor { + + Object getValue(String prefix, String key, Field field, DataConfiguration configuration, Object defaultValue); + + boolean isSupported(Field field); +} diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/ConfigurationBootstrap.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/ConfigurationBootstrap.java index 93cfae7..ffb8f8b 100644 --- a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/ConfigurationBootstrap.java +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/ConfigurationBootstrap.java @@ -53,13 +53,18 @@ import javassist.NotFoundException; import javax.enterprise.event.Observes; import javax.enterprise.inject.spi.AnnotatedType; import javax.enterprise.inject.spi.BeanManager; -import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.ProcessAnnotatedType; +import org.slf4j.Logger; + import br.gov.frameworkdemoiselle.configuration.Configuration; +import br.gov.frameworkdemoiselle.configuration.ConfigurationValueExtractor; import br.gov.frameworkdemoiselle.internal.implementation.ConfigurationImpl; +import br.gov.frameworkdemoiselle.internal.producer.LoggerProducer; + +public class ConfigurationBootstrap extends AbstractStrategyBootstrap { -public class ConfigurationBootstrap implements Extension { + private Logger logger; private static final Map>> cacheClassLoader = Collections .synchronizedMap(new HashMap>>()); @@ -130,4 +135,13 @@ public class ConfigurationBootstrap implements Extension { return clazzProxy; } + + @Override + protected Logger getLogger() { + if (logger == null) { + logger = LoggerProducer.create(TransactionBootstrap.class); + } + + return logger; + } } diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationArrayValueExtractor.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationArrayValueExtractor.java new file mode 100644 index 0000000..06d7904 --- /dev/null +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationArrayValueExtractor.java @@ -0,0 +1,57 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.internal.configuration; + +import java.lang.reflect.Field; + +import org.apache.commons.configuration.DataConfiguration; + +import br.gov.frameworkdemoiselle.configuration.ConfigurationValueExtractor; + +public class ConfigurationArrayValueExtractor implements ConfigurationValueExtractor { + + @Override + public Object getValue(String prefix, String key, Field field, DataConfiguration configuration, + Object defaultValue) { + return configuration.getArray(field.getType().getComponentType(), prefix + key, defaultValue); + } + + @Override + public boolean isSupported(Field field) { + return field.getType().isArray(); + } +} diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationClassValueExtractor.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationClassValueExtractor.java new file mode 100644 index 0000000..171d07b --- /dev/null +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationClassValueExtractor.java @@ -0,0 +1,73 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.internal.configuration; + +import java.lang.reflect.Field; + +import org.apache.commons.configuration.DataConfiguration; + +import br.gov.frameworkdemoiselle.configuration.ConfigurationException; +import br.gov.frameworkdemoiselle.configuration.ConfigurationValueExtractor; +import br.gov.frameworkdemoiselle.util.Reflections; + +public class ConfigurationClassValueExtractor implements ConfigurationValueExtractor { + + @Override + public Object getValue(String prefix, String key, Field field, DataConfiguration configuration, + Object defaultValue) { + Object value = defaultValue; + String canonicalName = configuration.getString(prefix + key); + + if (canonicalName != null) { + ClassLoader classLoader = Reflections.getClassLoaderForClass(canonicalName); + + try { + value = Class.forName(canonicalName, true, classLoader); + } catch (ClassNotFoundException cause) { + // TODO Lançar a mensagem correta + throw new ConfigurationException(null, cause); + } + } + + return value; + } + + @Override + public boolean isSupported(Field field) { + return field.getType() == Class.class; + } +} diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationLoader.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationLoader.java index 25d9e08..aa67281 100644 --- a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationLoader.java +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationLoader.java @@ -41,29 +41,27 @@ import static br.gov.frameworkdemoiselle.configuration.ConfigType.SYSTEM; import java.io.Serializable; import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.Iterator; +import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import javax.inject.Inject; import javax.validation.constraints.NotNull; import org.apache.commons.configuration.AbstractConfiguration; -import org.apache.commons.configuration.ConversionException; import org.apache.commons.configuration.DataConfiguration; import org.apache.commons.configuration.FileConfiguration; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.configuration.XMLConfiguration; -import org.apache.commons.lang.ClassUtils; import br.gov.frameworkdemoiselle.annotation.Ignore; import br.gov.frameworkdemoiselle.annotation.Name; import br.gov.frameworkdemoiselle.configuration.ConfigType; import br.gov.frameworkdemoiselle.configuration.Configuration; import br.gov.frameworkdemoiselle.configuration.ConfigurationException; +import br.gov.frameworkdemoiselle.configuration.ConfigurationValueExtractor; +import br.gov.frameworkdemoiselle.internal.bootstrap.ConfigurationBootstrap; +import br.gov.frameworkdemoiselle.util.Beans; import br.gov.frameworkdemoiselle.util.Reflections; /** @@ -88,6 +86,11 @@ public class ConfigurationLoader implements Serializable { private List fields; + private List extractors; + + @Inject + private ConfigurationBootstrap bootstrap; + public void load(Object object) throws ConfigurationException { this.object = object; @@ -96,6 +99,7 @@ public class ConfigurationLoader implements Serializable { loadType(); loadResource(); loadConfiguration(); + loadExtractors(); if (this.configuration != null) { loadPrefix(); @@ -118,6 +122,15 @@ public class ConfigurationLoader implements Serializable { this.type = object.getClass().getAnnotation(Configuration.class).type(); } + private void loadResource() { + if (this.type != SYSTEM) { + String name = this.object.getClass().getAnnotation(Configuration.class).resource(); + String extension = this.type.toString().toLowerCase(); + + this.resource = name + "." + extension; + } + } + private void loadConfiguration() { AbstractConfiguration conf; @@ -151,12 +164,11 @@ public class ConfigurationLoader implements Serializable { this.configuration = (conf == null ? null : new DataConfiguration(conf)); } - private void loadResource() { - if (this.type != SYSTEM) { - String name = this.object.getClass().getAnnotation(Configuration.class).resource(); - String extension = this.type.toString().toLowerCase(); + private void loadExtractors() { + this.extractors = new ArrayList(); - this.resource = name + "." + extension; + for (Class extractorClass : this.bootstrap.getCache()) { + this.extractors.add(Beans.getReference(extractorClass)); } } @@ -193,93 +205,24 @@ public class ConfigurationLoader implements Serializable { } Object defaultValue = Reflections.getFieldValue(field, this.object); - Object finalValue = getValue(field.getType(), getKey(field), defaultValue); + Object finalValue = getValue(field, field.getType(), getKey(field), defaultValue); Reflections.setFieldValue(field, this.object, finalValue); } - private Object getValue(Class type, String key, Object defaultValue) { - Object value; - - if (type.isArray()) { - value = getArrayValue(type, key, defaultValue); - - } else if (type == Map.class) { - value = getMapValue(type, key, defaultValue); - - } else if (type == Class.class) { - value = getClassValue(type, key, defaultValue); - - } else { - value = getPrimitiveOrWrappedValue(type, key, defaultValue); - } - - return value; - } + private Object getValue(Field field, Class type, String key, Object defaultValue) { + Object value = null; - private Object getArrayValue(Class type, String key, Object defaultValue) { - return this.configuration.getArray(type.getComponentType(), this.prefix + key, defaultValue); - } - - private Object getMapValue(Class type, String key, Object defaultValue) { - @SuppressWarnings("unchecked") - Map value = (Map) defaultValue; - - String regexp = "^(" + this.prefix + ")((.+)\\.)?(" + key + ")$"; - Pattern pattern = Pattern.compile(regexp); - - for (Iterator iter = this.configuration.getKeys(); iter.hasNext();) { - String iterKey = iter.next(); - Matcher matcher = pattern.matcher(iterKey); - - if (matcher.matches()) { - String confKey = matcher.group(1) + (matcher.group(2) == null ? "" : matcher.group(2)) - + matcher.group(4); - - if (value == null) { - value = new HashMap(); - } - - String mapKey = matcher.group(3) == null ? "default" : matcher.group(3); - value.put(mapKey, this.configuration.getString(confKey)); - } - } - - return value; - } - - private Object getClassValue(Class type, String key, Object defaultValue) { - Object value = defaultValue; - String canonicalName = this.configuration.getString(this.prefix + key); - - if (canonicalName != null) { - ClassLoader classLoader = Reflections.getClassLoaderForClass(canonicalName); - - try { - value = Class.forName(canonicalName, true, classLoader); - } catch (ClassNotFoundException cause) { - // TODO Lançar a mensagem correta - throw new ConfigurationException(null, cause); + for (ConfigurationValueExtractor extractor : this.extractors) { + if (extractor.isSupported(field)) { + value = extractor.getValue(this.prefix, key, field, configuration, defaultValue); + break; } } return value; } - @SuppressWarnings("unchecked") - private Object getPrimitiveOrWrappedValue(Class type, String key, Object defaultValue) { - Object value; - - try { - value = this.configuration.get(ClassUtils.primitiveToWrapper(type), this.prefix + key, defaultValue); - - } catch (ConversionException cause) { - value = defaultValue; - } - - return value; - } - private String getKey(Field field) { String key = ""; diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationLoaderBackup.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationLoaderBackup.java new file mode 100644 index 0000000..d000408 --- /dev/null +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationLoaderBackup.java @@ -0,0 +1,470 @@ +/* +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.internal.configuration; + +import java.io.FileNotFoundException; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.net.URL; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.validation.constraints.NotNull; + +import org.apache.commons.configuration.DataConfiguration; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.commons.configuration.SystemConfiguration; +import org.apache.commons.configuration.XMLConfiguration; +import org.slf4j.Logger; + +import br.gov.frameworkdemoiselle.annotation.Ignore; +import br.gov.frameworkdemoiselle.annotation.Name; +import br.gov.frameworkdemoiselle.configuration.ConfigType; +import br.gov.frameworkdemoiselle.configuration.Configuration; +import br.gov.frameworkdemoiselle.configuration.ConfigurationException; +import br.gov.frameworkdemoiselle.internal.producer.LoggerProducer; +import br.gov.frameworkdemoiselle.internal.producer.ResourceBundleProducer; +import br.gov.frameworkdemoiselle.util.Reflections; +import br.gov.frameworkdemoiselle.util.ResourceBundle; +import br.gov.frameworkdemoiselle.util.Strings; + +/** + * This component loads a config class annotated with {@link Configuration} by filling its attributes with {@link Param} + * according to a {@link ConfigType}. + * + * @author SERPRO + */ +public class ConfigurationLoaderBackup implements Serializable { + + private static final long serialVersionUID = 1L; + + private ResourceBundle bundle; + + private Logger logger; + + /** + * Loads a config class filling it with the corresponding values. + * + * @param object + * config object + * @throws ConfigurationException + */ + public void load(Object object) throws ConfigurationException { + Class config = object.getClass(); + + getLogger().debug(getBundle().getString("loading-configuration-class", config.getName())); + + for (Field field : Reflections.getNonStaticFields(config)) { + loadField(field, object, config); + } + } + + private void loadField(Field field, Object object, Class clazz) { + if (!field.isAnnotationPresent(Ignore.class) && clazz.isAnnotationPresent(Configuration.class)) { + String resource = clazz.getAnnotation(Configuration.class).resource(); + ConfigType type = clazz.getAnnotation(Configuration.class).type(); + org.apache.commons.configuration.Configuration config = getConfiguration(resource, type); + + if (config != null) { + Key key = new Key(field, clazz, config); + Object value = getValue(key, field, config); + validate(field, key, value, resource); + setValue(field, key, object, value); + } + } + } + + private void setValue(Field field, Key key, Object object, Object value) { + if (value != null) { + Reflections.setFieldValue(field, object, value); + getLogger().debug( + getBundle().getString("configuration-field-loaded", key.toString(), field.getName(), value)); + } + } + + private void validate(Field field, Key key, Object value, String resource) { + if (field.isAnnotationPresent(NotNull.class) && value == null) { + throw new ConfigurationException(getBundle().getString("configuration-attribute-is-mandatory", + key.toString(), resource)); + } + } + + /** + * Returns the configuration class according to specified resource name and configuration type. + * + * @param resource + * @param type + * @return a configuration + */ + private org.apache.commons.configuration.Configuration getConfiguration(String resource, ConfigType type) { + org.apache.commons.configuration.Configuration result = null; + + try { + URL url; + + switch (type) { + case SYSTEM: + result = new SystemConfiguration(); + break; + + case PROPERTIES: + url = getResourceAsURL(resource + ".properties"); + + if (url != null) { + result = new DataConfiguration(new PropertiesConfiguration(url)); + } else { + getLogger().warn(getBundle().getString("resource-not-found", resource + ".properties")); + } + + break; + + case XML: + url = getResourceAsURL(resource + ".xml"); + + if (url != null) { + result = new DataConfiguration(new XMLConfiguration(url)); + } else { + getLogger().warn(getBundle().getString("resource-not-found", resource + ".xml")); + } + + break; + + default: + throw new ConfigurationException(getBundle().getString("configuration-type-not-implemented-yet", + type.name())); + } + + } catch (Exception cause) { + throw new ConfigurationException(getBundle().getString("error-creating-configuration-from-resource", + resource), cause); + } + + return result; + } + + @SuppressWarnings("unchecked") + private T getValue(Key key, Field field, org.apache.commons.configuration.Configuration config) { + Object value; + + Class fieldClass = (Class) field.getType(); + + if (fieldClass.isArray()) { + value = getArray(key, field, config); + + } else if (fieldClass.equals(Map.class)) { + value = getMap(key, field, config); + + } else if (fieldClass.equals(Properties.class)) { + value = getProperty(key, config); + + } else if (fieldClass.equals(Class.class)) { + value = getClass(key, field, config); + + } else { + value = getBasic(key, field, config); + } + + return (T) value; + } + + @SuppressWarnings("unchecked") + private Object getMap(Key key, Field field, org.apache.commons.configuration.Configuration config) { + Map value = null; + + String regexp = "^(" + key.getPrefix() + ")((.+)\\.)?(" + key.getName() + ")$"; + Pattern pattern = Pattern.compile(regexp); + Matcher matcher; + + String iterKey; + String mapKey; + String confKey; + + for (Iterator iter = config.getKeys(); iter.hasNext();) { + iterKey = iter.next(); + matcher = pattern.matcher(iterKey); + + if (matcher.matches()) { + confKey = matcher.group(1) + (matcher.group(2) == null ? "" : matcher.group(2)) + matcher.group(4); + + if (value == null) { + value = new HashMap(); + } + + mapKey = matcher.group(3) == null ? "default" : matcher.group(3); + value.put(mapKey, config.getProperty(confKey)); + } + } + + return value; + } + + private Object getArray(Key key, Field field, org.apache.commons.configuration.Configuration config) { + Object value = null; + + Class fieldClass = (Class) field.getType(); + + try { + Method method; + String methodName = "get"; + + methodName += Strings.firstToUpper(fieldClass.getSimpleName()); + methodName = Strings.removeChars(methodName, '[', ']'); + + methodName += "Array"; + + method = config.getClass().getMethod(methodName, String.class); + value = method.invoke(config, key.toString()); + + } catch (Throwable cause) { + throw new ConfigurationException(getBundle().getString("error-converting-to-type", fieldClass.getName()), + cause); + } + + return value; + } + + private Object getBasic(Key key, Field field, org.apache.commons.configuration.Configuration config) { + Object value = null; + + Class fieldClass = (Class) field.getType(); + + try { + Method method; + String methodName = "get"; + + methodName += discoveryGenericType(field); + methodName += Strings.firstToUpper(fieldClass.getSimpleName()); + + if (!fieldClass.isPrimitive()) { + method = config.getClass().getMethod(methodName, String.class, fieldClass); + value = method.invoke(config, key.toString(), null); + + } else if (config.containsKey(key.toString())) { + method = config.getClass().getMethod(methodName, String.class); + value = method.invoke(config, key.toString()); + } + + } catch (Throwable cause) { + throw new ConfigurationException(getBundle().getString("error-converting-to-type", fieldClass.getName()), + cause); + } + + return value; + } + + private Object getClass(Key key, Field field, org.apache.commons.configuration.Configuration config) { + Object value = null; + + try { + String canonicalName = config.getString(key.toString()); + + if (canonicalName != null) { + ClassLoader classLoader = getClassLoaderForClass(canonicalName); + value = Class.forName(canonicalName, true, classLoader); + } + + } catch (Exception cause) { + // TODO Lançar a mensagem correta + throw new ConfigurationException(null, cause); + } + + return value; + } + + /** + * Discovery the Generic's type. for example: the generic's type of List list is an Integer type + * + * @param field + * @return + */ + private String discoveryGenericType(Field field) { + + Type genericFieldType = field.getGenericType(); + + if (genericFieldType instanceof ParameterizedType) { + ParameterizedType type = (ParameterizedType) genericFieldType; + Type[] fieldArgumentTypes = type.getActualTypeArguments(); + for (Type fieldArgumentType : fieldArgumentTypes) { + @SuppressWarnings("rawtypes") + Class fieldArgumentClass = (Class) fieldArgumentType; + + if ("String".equals(fieldArgumentClass.getSimpleName())) { + return ""; + } + + return fieldArgumentClass.getSimpleName(); + } + } + + return ""; + } + + private Object getProperty(Key key, org.apache.commons.configuration.Configuration config) { + Object value = null; + + @SuppressWarnings("unchecked") + Iterator iterator = config.getKeys(key.toString()); + if (iterator.hasNext()) { + Properties props = new Properties(); + + while (iterator.hasNext()) { + String fullKey = iterator.next(); + String prefix = key.toString() + "."; + String unprefixedKey = fullKey.substring(prefix.length()); + props.put(unprefixedKey, config.getString(fullKey)); + } + + value = props; + } + + return value; + } + + public static ClassLoader getClassLoaderForClass(final String canonicalName) throws FileNotFoundException { + return getClassLoaderForResource(canonicalName.replaceAll("\\.", "/") + ".class"); + } + + public static ClassLoader getClassLoaderForResource(final String resource) throws FileNotFoundException { + final String stripped = resource.startsWith("/") ? resource.substring(1) : resource; + + URL url = null; + ClassLoader result = Thread.currentThread().getContextClassLoader(); + + if (result != null) { + url = result.getResource(stripped); + } + + if (url == null) { + result = ConfigurationLoader.class.getClassLoader(); + url = ConfigurationLoader.class.getClassLoader().getResource(stripped); + } + + if (url == null) { + result = null; + } + + return result; + } + + public static URL getResourceAsURL(final String resource) throws FileNotFoundException { + ClassLoader classLoader = getClassLoaderForResource(resource); + return classLoader != null ? classLoader.getResource(resource) : null; + } + + private ResourceBundle getBundle() { + if (bundle == null) { + bundle = ResourceBundleProducer.create("demoiselle-core-bundle"); + } + + return bundle; + } + + private Logger getLogger() { + if (logger == null) { + logger = LoggerProducer.create(ConfigurationLoader.class); + } + + return logger; + } + + private final class Key { + + private String prefix; + + private String name; + + private String key; + + private Key(final Field field, final Class type, final org.apache.commons.configuration.Configuration config) { + + this.prefix = type.getAnnotation(Configuration.class).prefix(); + if (this.prefix == null) { + this.prefix = ""; + } + + if (field.isAnnotationPresent(Name.class)) { + this.name = getNameByAnnotation(field); + } else { + this.name = getNameByField(field); + } + + this.key = this.prefix + this.name; + + if (!config.containsKey(this.key)) { + getLogger().debug(getBundle().getString("key-not-found", this.key)); + } + } + + private String getNameByAnnotation(Field field) { + String result; + + Name nameAnnotation = field.getAnnotation(Name.class); + if (Strings.isEmpty(nameAnnotation.value())) { + throw new ConfigurationException(getBundle().getString("configuration-name-attribute-cant-be-empty")); + } else { + result = nameAnnotation.value(); + } + + return result; + } + + private String getNameByField(Field field) { + return field.getName(); + } + + public String getPrefix() { + return prefix; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return this.key; + } + } +} diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationMapValueExtractor.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationMapValueExtractor.java new file mode 100644 index 0000000..ae8bfcb --- /dev/null +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationMapValueExtractor.java @@ -0,0 +1,85 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.internal.configuration; + +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 org.apache.commons.configuration.DataConfiguration; + +import br.gov.frameworkdemoiselle.configuration.ConfigurationValueExtractor; + +public class ConfigurationMapValueExtractor implements ConfigurationValueExtractor { + + @Override + public Object getValue(String prefix, String key, Field field, DataConfiguration configuration, + Object defaultValue) { + @SuppressWarnings("unchecked") + Map value = (Map) defaultValue; + + String regexp = "^(" + prefix + ")((.+)\\.)?(" + key + ")$"; + 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) == null ? "" : matcher.group(2)) + + matcher.group(4); + + if (value == null) { + value = new HashMap(); + } + + String mapKey = matcher.group(3) == null ? "default" : matcher.group(3); + value.put(mapKey, configuration.getString(confKey)); + } + } + + return value; + } + + @Override + public boolean isSupported(Field field) { + return field.getType() == Map.class; + } +} diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationPrimitiveOrWrapperValueExtractor.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationPrimitiveOrWrapperValueExtractor.java new file mode 100644 index 0000000..da7a135 --- /dev/null +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationPrimitiveOrWrapperValueExtractor.java @@ -0,0 +1,85 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.internal.configuration; + +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.configuration.ConversionException; +import org.apache.commons.configuration.DataConfiguration; +import org.apache.commons.lang.ClassUtils; + +import br.gov.frameworkdemoiselle.configuration.ConfigurationValueExtractor; + +public class ConfigurationPrimitiveOrWrapperValueExtractor implements ConfigurationValueExtractor { + + private static final Set wrappers = new HashSet(); + + static { + wrappers.add(Boolean.class); + wrappers.add(Byte.class); + wrappers.add(Character.class); + wrappers.add(Short.class); + wrappers.add(Integer.class); + wrappers.add(Long.class); + wrappers.add(Double.class); + wrappers.add(Float.class); + wrappers.add(Void.TYPE); + } + + @Override + @SuppressWarnings("unchecked") + public Object getValue(String prefix, String key, Field field, DataConfiguration configuration, + Object defaultValue) { + Object value; + + try { + value = configuration.get(ClassUtils.primitiveToWrapper(field.getType()), prefix + key, defaultValue); + + } catch (ConversionException cause) { + value = defaultValue; + } + + return value; + } + + @Override + public boolean isSupported(Field field) { + return field.getType().isPrimitive() || wrappers.contains(field.getType()); + } +} diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationStringValueExtractor.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationStringValueExtractor.java new file mode 100644 index 0000000..4842a7e --- /dev/null +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ConfigurationStringValueExtractor.java @@ -0,0 +1,57 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.internal.configuration; + +import java.lang.reflect.Field; + +import org.apache.commons.configuration.DataConfiguration; + +import br.gov.frameworkdemoiselle.configuration.ConfigurationValueExtractor; + +public class ConfigurationStringValueExtractor implements ConfigurationValueExtractor { + + @Override + public Object getValue(String prefix, String key, Field field, DataConfiguration configuration, + Object defaultValue) { + return configuration.getString(prefix + key, (String) defaultValue); + } + + @Override + public boolean isSupported(Field field) { + return field.getType() == String.class; + } +} diff --git a/impl/core/src/test/java/br/gov/frameworkdemoiselle/configuration/AbstractConfigurationTest.java b/impl/core/src/test/java/br/gov/frameworkdemoiselle/configuration/AbstractConfigurationTest.java index 7f566db..67bdeff 100644 --- a/impl/core/src/test/java/br/gov/frameworkdemoiselle/configuration/AbstractConfigurationTest.java +++ b/impl/core/src/test/java/br/gov/frameworkdemoiselle/configuration/AbstractConfigurationTest.java @@ -48,7 +48,12 @@ import br.gov.frameworkdemoiselle.annotation.Ignore; import br.gov.frameworkdemoiselle.annotation.Name; import br.gov.frameworkdemoiselle.internal.bootstrap.ConfigurationBootstrap; import br.gov.frameworkdemoiselle.internal.bootstrap.CoreBootstrap; +import br.gov.frameworkdemoiselle.internal.configuration.ConfigurationArrayValueExtractor; +import br.gov.frameworkdemoiselle.internal.configuration.ConfigurationClassValueExtractor; import br.gov.frameworkdemoiselle.internal.configuration.ConfigurationLoader; +import br.gov.frameworkdemoiselle.internal.configuration.ConfigurationMapValueExtractor; +import br.gov.frameworkdemoiselle.internal.configuration.ConfigurationPrimitiveOrWrapperValueExtractor; +import br.gov.frameworkdemoiselle.internal.configuration.ConfigurationStringValueExtractor; import br.gov.frameworkdemoiselle.internal.producer.LocaleProducer; import br.gov.frameworkdemoiselle.internal.producer.LoggerProducer; import br.gov.frameworkdemoiselle.internal.producer.ResourceBundleProducer; @@ -65,6 +70,12 @@ public abstract class AbstractConfigurationTest { result.add(CoreBootstrap.class); result.add(ConfigurationBootstrap.class); result.add(ConfigurationLoader.class); + result.add(ConfigurationValueExtractor.class); + result.add(ConfigurationArrayValueExtractor.class); + result.add(ConfigurationMapValueExtractor.class); + result.add(ConfigurationClassValueExtractor.class); + result.add(ConfigurationStringValueExtractor.class); + result.add(ConfigurationPrimitiveOrWrapperValueExtractor.class); result.add(Beans.class); result.add(ResourceBundleProducer.class); result.add(LoggerProducer.class); -- libgit2 0.21.2