View Javadoc
1   package fr.ifremer.quadrige3.core.config;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: Quadrige3 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.quadrige3.core.dao.technical.QuadrigeEnumerationDef;
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.Arrays;
43  import java.util.List;
44  import java.util.Properties;
45  import java.util.Set;
46  
47  /**
48   * Classe utilitaire pour vérifier que les valeurs d'énumération sont correctement configurées.
49   *
50   * @author Lionel Touseau <lionel.touseau@e-is.pro>
51   */
52  public class QuadrigeEnumerationHelper {
53      
54      /**
55       * Logger.
56       */
57      private static final Log log = LogFactory.getLog(QuadrigeEnumerationHelper.class);
58  
59      private static final String MODEL_PACKAGE_NAME = "fr.ifremer.quadrige3.core.dao";
60  
61      private static List<QuadrigeEnumerationDef<?>> cachedModelEnumsAsConfigOptions = null;
62  
63      /**
64       * <p>getAllModelEnumerations.</p>
65       *
66       * @return a {@link java.util.List} object.
67       */
68      @SuppressWarnings("rawtypes")
69      public static List<QuadrigeEnumerationDef<?>> getAllModelEnumerations() {
70          if (cachedModelEnumsAsConfigOptions != null) {
71              return cachedModelEnumsAsConfigOptions;
72          }
73  
74          // Retrieve enumerations classes used in quadrige3
75          Reflections reflections = Reflections.collect();
76          if (reflections == null) {
77              reflections = new Reflections(MODEL_PACKAGE_NAME);
78          }
79          Set<Class<? extends QuadrigeEnumerationDef>> enumerationClasses
80              = reflections.getSubTypesOf(QuadrigeEnumerationDef.class);
81          if (log.isDebugEnabled()) {
82              log.debug(String.format("%s enumeration classes detected in package [%s]", enumerationClasses.size(), MODEL_PACKAGE_NAME));
83          }
84  
85          List<QuadrigeEnumerationDef<?>> options = Lists.newArrayList();
86          for (Class<? extends QuadrigeEnumerationDef> enumClass : enumerationClasses) {
87              QuadrigeEnumerationDef<?>[] enums = enumClass.getEnumConstants();
88              if (ArrayUtils.isEmpty(enums)) {
89                  log.warn(String.format("Enumeration class [%s] has no value. Skipped.", enumClass.getName()));
90              }
91              else {
92                  options.addAll(Arrays.asList(enums));
93              }
94          }
95  
96          cachedModelEnumsAsConfigOptions = options;
97          if (log.isDebugEnabled()) {
98              log.debug(String.format("%s enumeration values detected in package [%s]", options.size(), MODEL_PACKAGE_NAME));
99          }
100 
101         return cachedModelEnumsAsConfigOptions;
102     }
103 
104     /**
105      * <p>reload.</p>
106      *
107      * @param applicationConfig a {@link org.nuiton.config.ApplicationConfig} object.
108      * @param resources a {@link java.util.List} object.
109      */
110     @SuppressWarnings({"rawtypes", "unchecked"})
111     public static void reload(ApplicationConfig applicationConfig, List<org.springframework.core.io.Resource> resources) {
112 
113         Properties enumerationProperties = new RecursiveProperties();
114         if (log.isDebugEnabled()) {
115             log.debug("Starting to load enumeration values...");
116         }
117 
118         for (Resource resource : resources) {
119             InputStreamReader isr = null;
120             try {
121                 if (log.isDebugEnabled()) {
122                     log.debug("Load enumeration file: "
123                         + resource.getURI().toString());
124                 }
125                 isr = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8);
126                 enumerationProperties.load(isr);
127             } catch (IOException e) {
128                 log.warn(String.format("Could not load enumeration file: %s. File skipped.", resource.getFilename()));
129             } finally {
130                 IOUtils.closeQuietly(isr);
131             }
132         }
133 
134         // Set each property as a default option for enumeration
135         for (Object key : enumerationProperties.keySet()) {
136             String value = enumerationProperties.getProperty((String) key);
137             applicationConfig.setDefaultOption(QuadrigeEnumerationDef.CONFIG_OPTION_PREFIX + key, value);
138             if (log.isTraceEnabled()) {
139                 log.trace(String.format(" %s%s (%s)", QuadrigeEnumerationDef.CONFIG_OPTION_PREFIX, key, value));
140             }
141         }
142 
143         // Refresh enumeration values
144         List<QuadrigeEnumerationDef<?>> modelOptions = getAllModelEnumerations();
145         for (QuadrigeEnumerationDef enumDef : modelOptions) {
146             Class clazz = enumDef.getType();
147             String key = enumDef.getKey();
148             String stringValue = applicationConfig.getOption(key);
149 
150             Object value = applicationConfig.getOption(clazz, key);
151             if (value != null
152                 && !enumDef.getValue().equals(value)) {
153 
154                 // Check for conversion error
155                 if (!stringValue.equals(value.toString())) {
156                     log.warn(String.format("Incompatible value '%s' for property '%s' (%s expected): Value skipped.", stringValue, key, enumDef.getType().getSimpleName()));
157                 }
158                 else {
159                     Object oldValue = enumDef.getValue();
160                     try {
161                         enumDef.setValue(value);
162                     } catch (ClassCastException cce) {
163                         log.warn(String.format("Could not set %s with value %s", key, value));
164                     }
165                     if (log.isTraceEnabled()) {
166                         log.trace(String.format(" %s (%s -> %s)", key, oldValue, value));
167                     }
168                 }
169             }
170         }
171     }
172     
173 }