Fixed sonar issues
[sdc.git] / common / onap-common-configuration-management / onap-configuration-management-core / src / main / java / org / onap / config / impl / ConfigurationImpl.java
1 /*
2  * Copyright © 2016-2018 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.config.impl;
18
19 import static org.onap.config.ConfigurationUtils.isBlank;
20
21 import java.io.File;
22 import java.lang.reflect.Constructor;
23 import java.lang.reflect.Field;
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Modifier;
26 import java.net.URL;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Set;
36 import java.util.concurrent.atomic.AtomicReference;
37 import java.util.function.Predicate;
38 import java.util.stream.Collectors;
39
40 import org.apache.commons.configuration2.ex.ConfigurationException;
41 import org.onap.config.ConfigurationUtils;
42 import org.onap.config.Constants;
43 import org.onap.config.NonConfigResource;
44 import org.onap.config.api.Config;
45 import org.onap.config.api.Hint;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 public class ConfigurationImpl implements org.onap.config.api.Configuration {
50
51     private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationImpl.class);
52
53     private static final String KEY_CANNOT_BE_NULL = "Key can't be null.";
54     private static final NonConfigResource NON_CONFIG_RESOURCE = new NonConfigResource();
55     private static final Map<String, AggregateConfiguration> MODULE_CONFIG_STORE = new HashMap<>();
56
57     static {
58         if (!loadClassPathConfigurationsAndResources()
59                 || !loadAdditionalConfigurationsAndResources()
60                 || !loadTenantConfigurations()) {
61             throw new IllegalStateException("Failed to initialize configuration");
62         }
63         populateFinalConfigurationIncrementally(MODULE_CONFIG_STORE);
64         loadNodeSpecificConfigurations();
65     }
66
67     @Override
68     public <T> T get(String tenant, String namespace, String key, Class<T> clazz, Hint... hints) {
69         String[] tenantNamespaceArray;
70         if (tenant == null && namespace != null) {
71             tenantNamespaceArray = namespace.split(Constants.TENANT_NAMESPACE_SEPARATOR);
72             if (tenantNamespaceArray.length > 1) {
73                 tenant = tenantNamespaceArray[0];
74                 namespace = tenantNamespaceArray[1];
75             }
76         }
77
78         tenant = ConfigurationRepository.lookup().isValidTenant(tenant) ? tenant.toUpperCase() : Constants.DEFAULT_TENANT;
79         namespace = ConfigurationRepository.lookup().isValidNamespace(namespace) ? namespace.toUpperCase() : Constants.DEFAULT_NAMESPACE;
80         hints = hints == null || hints.length == 0 ? new Hint[]{Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC} : hints;
81         T returnValue;
82         returnValue = getInternal(tenant, namespace, key, clazz, hints);
83         if ((returnValue == null || ConfigurationUtils.isZeroLengthArray(clazz, returnValue))
84                 && !Constants.DEFAULT_TENANT.equals(tenant)) {
85             returnValue = getInternal(Constants.DEFAULT_TENANT, namespace, key, clazz, hints);
86         }
87         if ((returnValue == null || ConfigurationUtils.isZeroLengthArray(clazz, returnValue))
88                 && !Constants.DEFAULT_NAMESPACE.equals(namespace)) {
89             returnValue = getInternal(tenant, Constants.DEFAULT_NAMESPACE, key, clazz, hints);
90         }
91         if ((returnValue == null || ConfigurationUtils.isZeroLengthArray(clazz, returnValue))
92                 && !Constants.DEFAULT_NAMESPACE.equals(namespace) && !Constants.DEFAULT_TENANT.equals(tenant)) {
93             returnValue = getInternal(Constants.DEFAULT_TENANT, Constants.DEFAULT_NAMESPACE, key, clazz, hints);
94         }
95         if (returnValue == null && ConfigurationUtils.isAPrimitive(clazz)) {
96             returnValue = (T) ConfigurationUtils.getDefaultFor(clazz);
97         }
98         return returnValue;
99     }
100
101     @Override
102     public <T> Map<String, T> populateMap(String tenantId, String namespace, String key, Class<T> clazz) {
103         final String calculatedTenantId = calculateTenant(tenantId);
104         final String calculatedNamespace = calculateNamespace(namespace);
105         Map<String, T> map = new HashMap<>();
106         Iterator<String> keys;
107         try {
108             keys = ConfigurationRepository.lookup().getConfigurationFor(calculatedTenantId, calculatedNamespace).getKeys(key);
109             keys.forEachRemaining(k -> {
110                 if (k.startsWith(key + ".")) {
111                     k = k.substring(key.length() + 1);
112                     String subkey = k.substring(0, k.indexOf('.'));
113                     if (!map.containsKey(subkey)) {
114                         map.put(subkey, get(calculatedTenantId, calculatedNamespace, key + "." + subkey, clazz));
115                     }
116                 }
117             });
118         } catch (Exception e) {
119             LOGGER.warn(
120                     "Couldn't populate map fot tenant: {}, namespace: {}, key: {}, type: {}",
121                     tenantId,
122                     namespace,
123                     key,
124                     clazz.getSimpleName(),
125                     e
126             );
127         }
128         return map;
129     }
130
131     @Override
132     public Map<Object, Object> generateMap(String tenantId, String namespace, String key) {
133         final String calculatedTenantId = calculateTenant(tenantId);
134         final String calculatedNamespace = calculateNamespace(namespace);
135         Map<Object, Object> parentMap = new HashMap<>();
136         Iterator<String> configKeys;
137         try {
138             if (isBlank(key)) {
139                 configKeys = ConfigurationRepository.lookup().getConfigurationFor(calculatedTenantId, calculatedNamespace).getKeys();
140             } else {
141                 configKeys = ConfigurationRepository.lookup().getConfigurationFor(calculatedTenantId, calculatedNamespace).getKeys(key);
142             }
143             configKeys.forEachRemaining(subKey -> {
144                 if (!isBlank(key) && !subKey.startsWith(key + ".")) {
145                     configKeys.remove();
146                 }
147                 parseConfigSubKeys(subKey, key, calculatedTenantId, calculatedNamespace, parentMap);
148             });
149         } catch (Exception e) {
150             LOGGER.warn(
151                     "Couldn't generate map fot tenant: {}, namespace: {}, key: {}",
152                     tenantId,
153                     namespace,
154                     key,
155                     e
156             );
157         }
158         return parentMap;
159     }
160
161     private static boolean loadClassPathConfigurationsAndResources() {
162         List<URL> classpathResources = ConfigurationUtils.getAllClassPathResources();
163         Predicate<URL> predicate = ConfigurationUtils::isConfig;
164         Map<Boolean, List<URL>> resources = classpathResources.stream().collect(Collectors.partitioningBy(predicate));
165         List<URL> configResources = resources.get(true);
166         List<URL> nonConfigResources = resources.get(false);
167         AtomicReference<Boolean> successFlagHolder = new AtomicReference<>(true);
168
169         configResources.forEach(url -> successFlagHolder.set(setUpdateModuleConfigStore(url)));
170
171         nonConfigResources.forEach(NON_CONFIG_RESOURCE::add);
172
173         return successFlagHolder.get();
174     }
175
176     private static boolean loadAdditionalConfigurationsAndResources() {
177         String configLocation = System.getProperty("config.location");
178         AtomicReference<Boolean> successFlagHolder = new AtomicReference<>(true);
179         if (!isBlank(configLocation)) {
180             File root = new File(configLocation);
181             Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
182             Predicate<File> filePredicate = ConfigurationUtils::isConfig;
183             Map<Boolean, List<File>> resources = filesystemResources.stream().collect(Collectors.partitioningBy(filePredicate));
184             List<File> configResources = resources.get(true);
185             List<File> nonConfigResources = resources.get(false);
186
187             configResources.forEach(file -> successFlagHolder.set(setUpdateModuleConfigStore(file)));
188
189             nonConfigResources.forEach(NON_CONFIG_RESOURCE::add);
190         }
191         return successFlagHolder.get();
192     }
193
194     private static boolean loadTenantConfigurations() {
195         String tenantConfigLocation = System.getProperty("tenant.config.location");
196         AtomicReference<Boolean> successFlagHolder = new AtomicReference<>(true);
197         if (!isBlank(tenantConfigLocation)) {
198             File root = new File(tenantConfigLocation);
199             Collection<File> tenantsRoot = ConfigurationUtils.getAllFiles(root, false, true);
200             Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
201
202             Map<Boolean, List<File>> resources = filesystemResources.stream().collect(Collectors.partitioningBy(ConfigurationUtils::isConfig));
203             Collection<File> tenantResources = resources.get(true);
204
205             tenantResources.forEach(configFile -> {
206                 AtomicReference<String> moduleNameHolder = new AtomicReference<>(ConfigurationUtils.getNamespace(configFile));
207                 Predicate<File> startsWithRootPredicate = tenantRoot -> configFile.getAbsolutePath().startsWith(tenantRoot.getAbsolutePath());
208                 Collection<File> matchesTenantRoot = tenantsRoot.stream().filter(startsWithRootPredicate).collect(Collectors.toCollection(ArrayList::new));
209                 AtomicReference<String[]> altResource = new AtomicReference<>();
210                 matchesTenantRoot.forEach(file -> altResource.set(
211                         (file.getName().toUpperCase() + Constants.TENANT_NAMESPACE_SEPARATOR + moduleNameHolder.get())
212                                 .split(Constants.TENANT_NAMESPACE_SEPARATOR)
213                         )
214                 );
215                 successFlagHolder.set(setUpdateModuleConfigStore(configFile, altResource.get()));
216             });
217         }
218         return successFlagHolder.get();
219     }
220
221     private static void loadNodeSpecificConfigurations() {
222         String nodeConfigLocation = System.getProperty("node.config.location");
223         if (!isBlank(nodeConfigLocation)) {
224             File root = new File(nodeConfigLocation);
225             Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
226             filesystemResources.stream().filter(ConfigurationUtils::isConfig).forEach(
227                     file -> ConfigurationRepository.lookup().populateOverrideConfiguration(
228                             ConfigurationUtils.getConfigurationRepositoryKey(
229                                     ConfigurationUtils.getNamespace(file).split(Constants.TENANT_NAMESPACE_SEPARATOR)), file)
230             );
231         }
232     }
233
234     private static void populateFinalConfigurationIncrementally(Map<String, AggregateConfiguration> configs) {
235         if (configs.get(Constants.DEFAULT_TENANT + Constants.KEY_ELEMENTS_DELIMITER + Constants.DB_NAMESPACE) != null) {
236             ConfigurationRepository.lookup().populateConfiguration(
237                     Constants.DEFAULT_TENANT + Constants.KEY_ELEMENTS_DELIMITER + Constants.DB_NAMESPACE,
238                     configs.remove(Constants.DEFAULT_TENANT + Constants.KEY_ELEMENTS_DELIMITER + Constants.DB_NAMESPACE)
239                             .getFinalConfiguration());
240         }
241         Set<String> modules = configs.keySet();
242         modules.forEach(
243                 m -> ConfigurationRepository.lookup().populateConfiguration(m, configs.get(m).getFinalConfiguration())
244         );
245     }
246
247     private static <T> boolean setUpdateModuleConfigStore(T resource, String... namedResources) {
248         boolean success = true;
249         String moduleName;
250         try {
251             if (namedResources == null || namedResources.length == 0) {
252                 moduleName = getConfigurationRepositoryKeyWrapper(resource);
253             } else {
254                 moduleName = getConfigurationRepositoryKeyWrapper(namedResources);
255             }
256             moduleAddConfigWrapper(moduleName, resource);
257         } catch (Exception e) {
258             success = false;
259             LOGGER.error("Error occurred while processing config resource {}", resource, e);
260         }
261         return success;
262     }
263
264     private static <T> String getConfigurationRepositoryKeyWrapper(T resource) throws ConfigurationException {
265         switch (resource.getClass().getSimpleName()) {
266             case "URL":
267                 return ConfigurationUtils.getConfigurationRepositoryKey((URL) resource);
268             case "File":
269                 return ConfigurationUtils.getConfigurationRepositoryKey((File) resource);
270             case "String[]":
271                 return ConfigurationUtils.getConfigurationRepositoryKey((String[]) resource);
272             default:
273                 throw new ConfigurationException("Unsupported resource type.");
274         }
275     }
276
277     private static <T> void moduleAddConfigWrapper(String moduleName, T resource) throws ConfigurationException {
278         AggregateConfiguration moduleConfig = MODULE_CONFIG_STORE.get(moduleName);
279         if (moduleConfig == null) {
280             moduleConfig = new AggregateConfiguration();
281             MODULE_CONFIG_STORE.put(moduleName, moduleConfig);
282         }
283         switch (resource.getClass().getSimpleName()) {
284             case "URL":
285                 moduleConfig.addConfig((URL) resource);
286                 break;
287             case "File":
288                 moduleConfig.addConfig((File) resource);
289                 break;
290             default:
291                 throw new ConfigurationException("Unsupported resource type.");
292         }
293     }
294
295     private void parseConfigSubKeys(String subKey, String keyPrefix, String tenantId, String namespace, Map<Object, Object> targetMap) {
296         String value = getAsString(tenantId, namespace, subKey);
297         if (!isBlank(keyPrefix) && subKey.startsWith(keyPrefix + ".")) {
298             subKey = subKey.substring(keyPrefix.trim().length() + 1);
299         }
300         while (subKey.contains(".")) {
301             String subSubKey = subKey.substring(0, subKey.indexOf('.'));
302             subKey = subKey.substring(subKey.indexOf('.') + 1);
303             if (!targetMap.containsKey(subSubKey)) {
304                 Map<Object, Object> subMap = new HashMap<>();
305                 targetMap.put(subSubKey, subMap);
306                 targetMap = subMap;
307             } else {
308                 targetMap = (Map<Object, Object>) targetMap.get(subSubKey);
309             }
310         }
311         targetMap.put(subKey, value);
312     }
313
314     protected <T> T getInternal(String tenant, String namespace, String key, Class<T> clazz, Hint... hints) {
315         int processingHints = Hint.DEFAULT.value();
316         if (hints != null) {
317             for (Hint hint : hints) {
318                 processingHints = processingHints | hint.value();
319             }
320         }
321
322         tenant = calculateTenant(tenant);
323         namespace = calculateNamespace(namespace);
324
325         if (isBlank(key) && !clazz.isAnnotationPresent(Config.class)) {
326             throw new IllegalArgumentException(KEY_CANNOT_BE_NULL);
327         }
328
329         if (clazz == null) {
330             throw new IllegalArgumentException("clazz is null.");
331         }
332
333         if (ConfigurationUtils.isAPrimitive(clazz)) {
334             clazz = getWrapperClass(clazz);
335         }
336         try {
337             if (ConfigurationUtils.isWrapperClass(clazz)) {
338                 return getWrapperTypeValue(tenant, namespace, key, clazz, processingHints);
339             } else if (ConfigurationUtils.isAPrimitivesOrWrappersArray(clazz)) {
340                 return getArrayTypeValue(tenant, namespace, key, clazz, processingHints);
341             } else if (clazz.isAnnotationPresent(Config.class)) {
342                 return getAnnotatedTypeValue(tenant, namespace, clazz, isBlank(key) ? "" : (key + "."), hints);
343             } else {
344                 throw new IllegalArgumentException(
345                         "Only primitive classes, wrapper classes, corresponding array classes and any "
346                                 + "class decorated with @org.openecomp.config.api.Config are allowed as argument.");
347             }
348         } catch (Exception exception) {
349             LOGGER.warn(
350                     "Failed to get internal value fot tenant: {}, namespace: {}, key: {}, type: {}",
351                     tenant,
352                     namespace,
353                     key,
354                     clazz.getSimpleName(),
355                     exception
356             );
357         }
358         return null;
359     }
360
361     private <T> T getWrapperTypeValue(String tenant, String namespace, String key, Class<T> clazz, int processingHints) throws Exception {
362         Object obj = ConfigurationUtils.getProperty(
363                 ConfigurationRepository.lookup().getConfigurationFor(tenant, namespace), key, processingHints);
364         if (obj != null) {
365             if (ConfigurationUtils.isCollection(obj.toString())) {
366                 obj = ConfigurationUtils.getCollectionString(obj.toString());
367             }
368             String value = ConfigurationUtils.processVariablesIfPresent(
369                     tenant,
370                     namespace,
371                     obj.toString().split(",")[0]
372             );
373             return (T) getTypeValue(value, clazz, processingHints);
374         }
375         return null;
376     }
377
378     private <T> T getArrayTypeValue(String tenant, String namespace, String key, Class<T> clazz, int processingHints) throws Exception {
379         Object obj = ConfigurationUtils.getProperty(
380                 ConfigurationRepository.lookup().getConfigurationFor(tenant, namespace), key, processingHints);
381         if (obj != null) {
382             Class componentType = clazz.getComponentType();
383             if (ConfigurationUtils.isAPrimitivesArray(clazz)) {
384                 componentType = getWrapperClass(componentType);
385             }
386             String collString = ConfigurationUtils.getCollectionString(obj.toString());
387             ArrayList<String> tempCollection = new ArrayList<>();
388             for (String itemValue : collString.split(",")) {
389                 tempCollection.add(ConfigurationUtils.processVariablesIfPresent(tenant, namespace, itemValue));
390             }
391             Collection<T> collection = convert(
392                     ConfigurationUtils.getCollectionString(Arrays.toString(tempCollection.toArray())),
393                     (Class<T>) componentType,
394                     processingHints
395             );
396             if (ConfigurationUtils.isAPrimitivesArray(clazz)) {
397                 return (T) ConfigurationUtils.getPrimitiveArray(collection, componentType);
398             } else {
399                 return (T) collection.toArray(getZeroLengthArrayFor(getWrapperClass(componentType)));
400             }
401         } else {
402             return null;
403         }
404     }
405
406     private static String calculateNamespace(String namespace) {
407
408         if (isBlank(namespace)) {
409             return Constants.DEFAULT_NAMESPACE;
410         }
411
412         return namespace.toUpperCase();
413     }
414
415     private static String calculateTenant(String tenant) {
416
417         if (isBlank(tenant)) {
418             return Constants.DEFAULT_TENANT;
419         }
420
421         return tenant.toUpperCase();
422     }
423
424     private <T> T getAnnotatedTypeValue(String tenant, String namespace, Class<T> clazz, String keyPrefix, Hint... hints)
425             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
426
427         Config confAnnotation = clazz.getAnnotation(Config.class);
428         if (confAnnotation != null && confAnnotation.key().length() > 0 && !keyPrefix.endsWith(".")) {
429             keyPrefix += (confAnnotation.key() + ".");
430         }
431         Constructor<T> constructor = clazz.getDeclaredConstructor();
432         constructor.setAccessible(true);
433         T objToReturn = constructor.newInstance();
434         for (Field field : clazz.getDeclaredFields()) {
435             field.setAccessible(true);
436             Config fieldConfAnnotation = field.getAnnotation(Config.class);
437             Class<?> fieldType = field.getType();
438             if (fieldConfAnnotation != null) {
439                 if (ConfigurationUtils.isAPrimitiveOrWrapper(fieldType) ||
440                         ConfigurationUtils.isAPrimitivesOrWrappersArray(fieldType)) {
441                     setPrimitiveField(field, objToReturn, tenant, namespace, keyPrefix, hints);
442                 }
443                 if (ConfigurationUtils.isACollection(fieldType)) {
444                     setCollectionField(field, objToReturn, tenant, namespace, keyPrefix, hints);
445                 }
446                 if (ConfigurationUtils.isAMap(fieldType)) {
447                     setMapField(field, objToReturn, tenant, namespace, keyPrefix);
448                 }
449             }
450         }
451         return objToReturn;
452     }
453
454     private void setPrimitiveField(Field field, Object objToReturn, String tenant, String namespace, String keyPrefix, Hint[] hints)
455             throws IllegalAccessException {
456         String fieldConfAnnotationKey = field.getAnnotation(Config.class).key();
457         Class<?> fieldType = field.getType();
458         field.set(objToReturn, get(tenant, namespace, keyPrefix + fieldConfAnnotationKey, fieldType, hints));
459     }
460
461     private void setMapField(Field field, Object objToReturn, String tenant, String namespace, String keyPrefix)
462             throws IllegalAccessException {
463         String fieldConfAnnotationKey = field.getAnnotation(Config.class).key();
464         field.set(objToReturn, generateMap(tenant, namespace, keyPrefix + fieldConfAnnotationKey));
465     }
466
467     private void setCollectionField(Field field, Object objToReturn, String tenant, String namespace, String keyPrefix, Hint[] hints)
468             throws IllegalAccessException, InvocationTargetException, InstantiationException {
469         String fieldConfAnnotationKey = field.getAnnotation(Config.class).key();
470         Class<?> fieldType = field.getType();
471         Object obj = get(tenant, namespace, keyPrefix + fieldConfAnnotationKey,
472                 ConfigurationUtils.getArrayClass(ConfigurationUtils.getCollectionGenericType(field)),
473                 hints);
474         if (obj != null) {
475             List<Object> list = Arrays.asList((Object[]) obj);
476             Class clazzToInstantiate;
477             if (fieldType.isInterface()) {
478                 clazzToInstantiate = ConfigurationUtils.getConcreteCollection(fieldType).getClass();
479             } else if (Modifier.isAbstract(fieldType.getModifiers())) {
480                 clazzToInstantiate =
481                         ConfigurationUtils.getCompatibleCollectionForAbstractDef(fieldType)
482                                 .getClass();
483             } else {
484                 clazzToInstantiate = fieldType;
485             }
486             Constructor construct = getConstructorWithArguments(clazzToInstantiate, Collection.class);
487
488             if (construct != null) {
489                 construct.setAccessible(true);
490                 field.set(objToReturn, construct.newInstance(list));
491             } else {
492                 construct = getConstructorWithArguments(clazzToInstantiate, Integer.class,
493                         Boolean.class, Collection.class);
494                 if (construct != null) {
495                     construct.setAccessible(true);
496                     field.set(objToReturn, construct.newInstance(list.size(), true, list));
497                 }
498             }
499         }
500     }
501
502     private Constructor getConstructorWithArguments(Class<?> clazz, Class<?>... classes) {
503         try {
504             return clazz.getDeclaredConstructor(classes);
505         } catch (Exception exception) {
506             LOGGER.warn("Failed to get {} constructor.", clazz.getSimpleName(), exception);
507             return null;
508         }
509     }
510
511     private Class getWrapperClass(Class<?> clazz) {
512         if (byte.class == clazz) {
513             return Byte.class;
514         } else if (short.class == clazz) {
515             return Short.class;
516         } else if (int.class == clazz) {
517             return Integer.class;
518         } else if (long.class == clazz) {
519             return Long.class;
520         } else if (float.class == clazz) {
521             return Float.class;
522         } else if (double.class == clazz) {
523             return Double.class;
524         } else if (char.class == clazz) {
525             return Character.class;
526         } else if (boolean.class == clazz) {
527             return Boolean.class;
528         }
529         return clazz;
530     }
531
532     private <T> T getTypeValue(Object obj, Class<T> clazz, int processingHint) {
533         if (obj == null || obj.toString().trim().length() == 0) {
534             return null;
535         } else {
536             obj = obj.toString().trim();
537         }
538         if (String.class.equals(clazz)) {
539             return getValueForStringType(obj, processingHint);
540         }
541         if (Number.class.isAssignableFrom(clazz)) {
542             return getValueForNumbersType(obj, clazz);
543         }
544         if (Boolean.class.equals(clazz)) {
545             return (T) Boolean.valueOf(obj.toString());
546         }
547         if (Character.class.equals(clazz)) {
548             return (T) Character.valueOf(obj.toString().charAt(0));
549         }
550         return null;
551     }
552
553     private <T> T getValueForStringType(Object obj, int processingHint) {
554         if (obj.toString().startsWith("@") && ConfigurationUtils.isExternalLookup(processingHint)) {
555             String subString = obj.toString().substring(1).trim();
556             String contents = ConfigurationUtils.getFileContents(
557                     NON_CONFIG_RESOURCE.locate(subString));
558             if (contents == null) {
559                 contents = ConfigurationUtils.getFileContents(subString);
560             }
561             if (contents != null) {
562                 obj = contents;
563             }
564         }
565         return (T) obj.toString();
566     }
567
568     private <T> T getValueForNumbersType(Object obj, Class<T> clazz) {
569         Double doubleValue = Double.valueOf(obj.toString());
570         switch (clazz.getName()) {
571             case "java.lang.Byte":
572                 Byte byteVal = doubleValue.byteValue();
573                 return (T) byteVal;
574             case "java.lang.Short":
575                 Short shortVal = doubleValue.shortValue();
576                 return (T) shortVal;
577             case "java.lang.Integer":
578                 Integer intVal = doubleValue.intValue();
579                 return (T) intVal;
580             case "java.lang.Long":
581                 Long longVal = doubleValue.longValue();
582                 return (T) longVal;
583             case "java.lang.Float":
584                 Float floatVal = doubleValue.floatValue();
585                 return (T) floatVal;
586             case "java.lang.Double":
587                 return (T) doubleValue;
588             default:
589                 return null;
590         }
591     }
592
593     private <T> T[] getZeroLengthArrayFor(Class<T> clazz) {
594         Object objToReturn = null;
595         if (ConfigurationUtils.isAPrimitive(clazz)) {
596             objToReturn = ConfigurationUtils.getPrimitiveArray(Collections.emptyList(), clazz);
597         } else if (ConfigurationUtils.isWrapperClass(clazz)) {
598             objToReturn = ConfigurationUtils.getWrappersArray(Collections.emptyList(), clazz);
599         }
600         return (T[]) objToReturn;
601     }
602
603     private <T> Collection<T> convert(String commaSeparatedValues, Class<T> clazz, int processingHints) {
604         ArrayList<T> collection = new ArrayList<>();
605         for (String value : commaSeparatedValues.split(",")) {
606             try {
607                 T type1 = getTypeValue(value, clazz, processingHints);
608                 if (type1 != null) {
609                     collection.add(type1);
610                 }
611             } catch (RuntimeException re) {
612                 LOGGER.warn("Failed to convert {}", commaSeparatedValues, re);
613             }
614         }
615         return collection;
616     }
617 }