001package fr.ifremer.adagio.core.config;
002
003/*
004 * #%L
005 * SIH-Adagio Core Shared
006 * $Id: EnumerationsInitializationHelper.java 11870 2013-12-03 10:10:32Z tc1fbb1 $
007 * $HeadURL: https://forge.ifremer.fr/svn/sih-adagio/trunk/adagio/core-shared/src/main/java/fr/ifremer/adagio/core/dao/EnumerationsInitializationHelper.java $
008 * %%
009 * Copyright (C) 2012 - 2013 Ifremer
010 * %%
011 * This program is free software: you can redistribute it and/or modify
012 * it under the terms of the GNU Affero General Public License as published by
013 * the Free Software Foundation, either version 3 of the License, or
014 * (at your option) any later version.
015 * 
016 * This program is distributed in the hope that it will be useful,
017 * but WITHOUT ANY WARRANTY; without even the implied warranty of
018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
019 * GNU General Public License for more details.
020 * 
021 * You should have received a copy of the GNU Affero General Public License
022 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
023 * #L%
024 */
025
026import java.io.IOException;
027import java.io.InputStream;
028import java.util.Arrays;
029import java.util.List;
030import java.util.Properties;
031import java.util.Set;
032
033import org.apache.commons.collections4.CollectionUtils;
034import org.apache.commons.lang3.ArrayUtils;
035import org.apache.commons.logging.Log;
036import org.apache.commons.logging.LogFactory;
037import org.nuiton.config.ApplicationConfig;
038import org.nuiton.util.RecursiveProperties;
039import org.reflections.Reflections;
040import org.reflections.util.FilterBuilder;
041import org.springframework.beans.factory.BeanInitializationException;
042import org.springframework.context.ApplicationContext;
043import org.springframework.core.io.Resource;
044
045import com.google.common.base.Preconditions;
046import com.google.common.collect.Lists;
047
048import fr.ifremer.adagio.core.dao.technical.AdagioEnumerationDef;
049
050/**
051 * Classe utilitaire pour vérifier que les valeurs d'énumération sont correctement configurées.
052 * 
053 * @author Benoit Lavenier <benoit.lavenier@e-is.pro>
054 */
055public class AdagioEnumerationHelper {
056    /** Logger. */
057    private static final Log log = LogFactory.getLog(AdagioEnumerationHelper.class);
058
059    private static final String MODEL_PACKAGE_NAME = "fr.ifremer.adagio.core.dao";
060    
061    private static List<AdagioEnumerationDef<?>> cachedModelEnumsAsConfigOptions = null;
062
063    public static List<AdagioEnumerationDef<?>> getAllModelEnumerations() {
064        if (cachedModelEnumsAsConfigOptions != null) {
065            return cachedModelEnumsAsConfigOptions;
066        }
067
068        // Retrieve enumerations classes used in adagio
069        Reflections reflections = Reflections.collect();
070        if (reflections == null) {
071            reflections = new Reflections(MODEL_PACKAGE_NAME);
072        }
073        Set<Class<? extends AdagioEnumerationDef>> enumerationClasses = 
074            reflections.getSubTypesOf(AdagioEnumerationDef.class);
075        if (log.isDebugEnabled()) {
076            log.debug(String.format("%s enumeration classes detected in package [%s]", enumerationClasses.size(), MODEL_PACKAGE_NAME));
077        }
078        
079        List<AdagioEnumerationDef<?>> options = Lists.newArrayList();
080        for(Class<? extends AdagioEnumerationDef> enumClass : enumerationClasses) {
081            AdagioEnumerationDef<?>[] enums = enumClass.getEnumConstants();
082            if (ArrayUtils.isEmpty(enums)) {
083                log.warn(String.format("Enumeration class [%s] has no value. Skipped.", enumClass.getName()));
084            }
085            else {
086                for (AdagioEnumerationDef<?> aEnum : enums) {
087                    AdagioEnumerationDef<?> configOption = (AdagioEnumerationDef<?>) aEnum;
088                    options.add(configOption);
089                }
090            }
091        }
092        
093        cachedModelEnumsAsConfigOptions = options; 
094        if (log.isDebugEnabled()) {
095            log.debug(String.format("%s enumeration values detected in package [%s]", options.size(), MODEL_PACKAGE_NAME));
096        }
097        
098        return cachedModelEnumsAsConfigOptions;
099    }
100    
101    public static void reload(ApplicationConfig applicationConfig, List<org.springframework.core.io.Resource> resources) {
102
103        Properties enumerationProperties = new RecursiveProperties();
104        if (log.isDebugEnabled()) {
105            log.debug(String.format("Starting to load enumeration values..."));
106        }
107        
108        for (Resource resource : resources) {
109            InputStream is = null;
110            try {
111                if (log.isDebugEnabled()) {
112                    log.debug("Load enumeration file: " +
113                            resource.getURI().toString());
114                }
115                is = resource.getInputStream();
116                enumerationProperties.load(is);
117            } catch (IOException e) {
118                log.warn(String.format("Could not load enumeration file: %s. File skipped.", resource.getFilename()));
119            } finally {
120                try {
121                    is.close();
122                }
123                catch(IOException e) { }
124            }
125        }
126        
127        // Set each property as a default option for enumeration
128        for (Object key: enumerationProperties.keySet()) {
129            String value = enumerationProperties.getProperty((String)key);
130            applicationConfig.setDefaultOption(AdagioEnumerationDef.CONFIG_OPTION_PREFIX + (String)key, value);
131            if (log.isTraceEnabled()) {
132                log.trace(String.format(" %s%s (%)", AdagioEnumerationDef.CONFIG_OPTION_PREFIX, (String)key, value));
133            }
134        }
135        
136        // Refresh enumeration values
137        List<AdagioEnumerationDef<?>> modelOptions = getAllModelEnumerations();
138        for (AdagioEnumerationDef enumDef : modelOptions) {
139            Class clazz = enumDef.getType();
140            String key = enumDef.getKey();
141            String stringValue = applicationConfig.getOption(key);
142            
143            Object value = applicationConfig.getOption(clazz, key);
144            if (value != null 
145                && !enumDef.getValue().equals(value)) {
146                
147                // Check for conversion error
148                if (stringValue.equals(value.toString()) == false) {
149                    log.warn(String.format("Incompatible value '%s' for property '%s' (%s expected): Value skipped.", stringValue, key, enumDef.getType().getSimpleName()));
150                }
151                else {
152                    Object oldValue = enumDef.getValue();
153                    try {
154                        enumDef.setValue(value);
155                    }
156                    catch(ClassCastException cce) {
157                        log.warn(String.format("Could not set %s with value %s", key, value));
158                    }
159                    if (log.isTraceEnabled()) {
160                        log.trace(String.format(" %s (%s -> %s)", key, oldValue, value));
161                    }
162                }
163            }
164        }
165    }
166
167}