View Javadoc
1   package fr.ifremer.quadrige2.core.config;
2   
3   /*-
4    * #%L
5    * Quadrige2 Core :: Quadrige2 Core Shared
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2017 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   * 
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * 
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  
27  
28  import com.google.common.collect.Lists;
29  import fr.ifremer.quadrige2.core.dao.technical.Quadrige2EnumerationDef;
30  import org.apache.commons.io.IOUtils;
31  import org.apache.commons.lang3.ArrayUtils;
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.nuiton.config.ApplicationConfig;
35  import org.nuiton.util.RecursiveProperties;
36  import org.reflections.Reflections;
37  import org.springframework.core.io.Resource;
38  
39  import java.io.IOException;
40  import java.io.InputStreamReader;
41  import java.nio.charset.StandardCharsets;
42  import java.util.List;
43  import java.util.Properties;
44  import java.util.Set;
45  
46  /**
47   * Classe utilitaire pour vérifier que les valeurs d'énumération sont correctement configurées.
48   *
49   * @author Lionel Touseau <lionel.touseau@e-is.pro>
50   */
51  public class Quadrige2EnumerationHelper {
52      
53      /**
54       * Logger.
55       */
56      private static final Log log = LogFactory.getLog(Quadrige2EnumerationHelper.class);
57  
58      private static final String MODEL_PACKAGE_NAME = "fr.ifremer.quadrige2.core.dao";
59  
60      private static List<Quadrige2EnumerationDef<?>> cachedModelEnumsAsConfigOptions = null;
61  
62      /**
63       * <p>getAllModelEnumerations.</p>
64       *
65       * @return a {@link java.util.List} object.
66       */
67      @SuppressWarnings("rawtypes")
68      public static List<Quadrige2EnumerationDef<?>> getAllModelEnumerations() {
69          if (cachedModelEnumsAsConfigOptions != null) {
70              return cachedModelEnumsAsConfigOptions;
71          }
72  
73          // Retrieve enumerations classes used in quadrige2
74          Reflections reflections = Reflections.collect();
75          if (reflections == null) {
76              reflections = new Reflections(MODEL_PACKAGE_NAME);
77          }
78          Set<Class<? extends Quadrige2EnumerationDef>> enumerationClasses
79              = reflections.getSubTypesOf(Quadrige2EnumerationDef.class);
80          if (log.isDebugEnabled()) {
81              log.debug(String.format("%s enumeration classes detected in package [%s]", enumerationClasses.size(), MODEL_PACKAGE_NAME));
82          }
83  
84          List<Quadrige2EnumerationDef<?>> options = Lists.newArrayList();
85          for (Class<? extends Quadrige2EnumerationDef> enumClass : enumerationClasses) {
86              Quadrige2EnumerationDef<?>[] enums = enumClass.getEnumConstants();
87              if (ArrayUtils.isEmpty(enums)) {
88                  log.warn(String.format("Enumeration class [%s] has no value. Skipped.", enumClass.getName()));
89              }
90              else {
91                  for (Quadrige2EnumerationDef<?> aEnum : enums) {
92                      Quadrige2EnumerationDef<?> configOption = (Quadrige2EnumerationDef<?>) aEnum;
93                      options.add(configOption);
94                  }
95              }
96          }
97  
98          cachedModelEnumsAsConfigOptions = options;
99          if (log.isDebugEnabled()) {
100             log.debug(String.format("%s enumeration values detected in package [%s]", options.size(), MODEL_PACKAGE_NAME));
101         }
102 
103         return cachedModelEnumsAsConfigOptions;
104     }
105 
106     /**
107      * <p>reload.</p>
108      *
109      * @param applicationConfig a {@link org.nuiton.config.ApplicationConfig} object.
110      * @param resources a {@link java.util.List} object.
111      */
112     @SuppressWarnings({"rawtypes", "unchecked"})
113     public static void reload(ApplicationConfig applicationConfig, List<org.springframework.core.io.Resource> resources) {
114 
115         Properties enumerationProperties = new RecursiveProperties();
116         if (log.isDebugEnabled()) {
117             log.debug(String.format("Starting to load enumeration values..."));
118         }
119 
120         for (Resource resource : resources) {
121             InputStreamReader isr = null;
122             try {
123                 if (log.isDebugEnabled()) {
124                     log.debug("Load enumeration file: "
125                         + resource.getURI().toString());
126                 }
127                 isr = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8);
128                 enumerationProperties.load(isr);
129             } catch (IOException e) {
130                 log.warn(String.format("Could not load enumeration file: %s. File skipped.", resource.getFilename()));
131             } finally {
132                 IOUtils.closeQuietly(isr);
133             }
134         }
135 
136         // Set each property as a default option for enumeration
137         for (Object key : enumerationProperties.keySet()) {
138             String value = enumerationProperties.getProperty((String) key);
139             applicationConfig.setDefaultOption(Quadrige2EnumerationDef.CONFIG_OPTION_PREFIX + (String) key, value);
140             if (log.isTraceEnabled()) {
141                 log.trace(String.format(" %s%s (%s)", Quadrige2EnumerationDef.CONFIG_OPTION_PREFIX, (String) key, value));
142             }
143         }
144 
145         // Refresh enumeration values
146         List<Quadrige2EnumerationDef<?>> modelOptions = getAllModelEnumerations();
147         for (Quadrige2EnumerationDef enumDef : modelOptions) {
148             Class clazz = enumDef.getType();
149             String key = enumDef.getKey();
150             String stringValue = applicationConfig.getOption(key);
151 
152             Object value = applicationConfig.getOption(clazz, key);
153             if (value != null
154                 && !enumDef.getValue().equals(value)) {
155 
156                 // Check for conversion error
157                 if (!stringValue.equals(value.toString())) {
158                     log.warn(String.format("Incompatible value '%s' for property '%s' (%s expected): Value skipped.", stringValue, key, enumDef.getType().getSimpleName()));
159                 }
160                 else {
161                     Object oldValue = enumDef.getValue();
162                     try {
163                         enumDef.setValue(value);
164                     } catch (ClassCastException cce) {
165                         log.warn(String.format("Could not set %s with value %s", key, value));
166                     }
167                     if (log.isTraceEnabled()) {
168                         log.trace(String.format(" %s (%s -> %s)", key, oldValue, value));
169                     }
170                 }
171             }
172         }
173     }
174     
175 }