71dd457e6f7fbe8c3902dd90e10ad5b853cfec2c
[sdc.git] /
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  * Modifications Copyright (c) 2019 Samsung
17  *
18  */
19 package org.onap.config;
20
21 import static java.util.Optional.ofNullable;
22 import static org.onap.config.api.Hint.EXTERNAL_LOOKUP;
23 import static org.onap.config.api.Hint.LATEST_LOOKUP;
24 import static org.onap.config.api.Hint.NODE_SPECIFIC;
25
26 import com.virtlink.commons.configuration2.jackson.JsonConfiguration;
27 import io.github.classgraph.ClassGraph;
28 import io.github.classgraph.ScanResult;
29 import java.io.File;
30 import java.io.IOException;
31 import java.lang.reflect.Array;
32 import java.lang.reflect.Field;
33 import java.lang.reflect.ParameterizedType;
34 import java.lang.reflect.Type;
35 import java.net.MalformedURLException;
36 import java.net.URL;
37 import java.nio.charset.Charset;
38 import java.nio.file.FileVisitResult;
39 import java.nio.file.Files;
40 import java.nio.file.Path;
41 import java.nio.file.SimpleFileVisitor;
42 import java.nio.file.attribute.BasicFileAttributes;
43 import java.util.ArrayDeque;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Collection;
47 import java.util.Collections;
48 import java.util.Deque;
49 import java.util.HashMap;
50 import java.util.HashSet;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.Objects;
54 import java.util.Optional;
55 import java.util.Queue;
56 import java.util.Set;
57 import java.util.SortedSet;
58 import java.util.TreeSet;
59 import java.util.concurrent.BlockingQueue;
60 import java.util.concurrent.ConcurrentLinkedQueue;
61 import java.util.concurrent.LinkedBlockingQueue;
62 import java.util.concurrent.LinkedTransferQueue;
63 import java.util.concurrent.TransferQueue;
64 import java.util.function.Predicate;
65 import java.util.regex.Matcher;
66 import java.util.regex.Pattern;
67 import java.util.stream.Collectors;
68 import org.apache.commons.configuration2.CompositeConfiguration;
69 import org.apache.commons.configuration2.Configuration;
70 import org.apache.commons.configuration2.FileBasedConfiguration;
71 import org.apache.commons.configuration2.PropertiesConfiguration;
72 import org.apache.commons.configuration2.XMLConfiguration;
73 import org.apache.commons.configuration2.builder.BasicConfigurationBuilder;
74 import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
75 import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
76 import org.apache.commons.configuration2.builder.fluent.Configurations;
77 import org.apache.commons.configuration2.builder.fluent.Parameters;
78 import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
79 import org.apache.commons.configuration2.ex.ConfigurationException;
80 import org.apache.commons.io.IOUtils;
81 import org.onap.config.api.Config;
82 import org.onap.config.api.ConfigurationManager;
83 import org.onap.config.impl.YamlConfiguration;
84 import org.onap.config.type.ConfigurationMode;
85 import org.onap.config.type.ConfigurationType;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
88
89 public class ConfigurationUtils {
90
91     private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationUtils.class);
92     private static final String CONFIGURATION_TYPE_NOT_SUPPORTED = "Configuration type not supported:";
93     private static final Map<Class<?>, Class<?>> ARRAY_CLASS_MAP;
94     private static final String CONFIG_REGEX_TPL_OPT_1 = "CONFIG(-\\w*){0,1}(-(%s|%s|%s)){0,1}\\.(%s|%s|%s|%s)$";
95     private static final String CONFIG_REGEX_TPL_OPT_2 = "CONFIG(.)*\\.(%s|%s|%s|%s)$";
96
97     static {
98         Map<Class<?>, Class<?>> arrayTypes = new HashMap<>();
99         arrayTypes.put(Byte.class, Byte[].class);
100         arrayTypes.put(Short.class, Short[].class);
101         arrayTypes.put(Integer.class, Integer[].class);
102         arrayTypes.put(Long.class, Long[].class);
103         arrayTypes.put(Float.class, Float[].class);
104         arrayTypes.put(Double.class, Double[].class);
105         arrayTypes.put(Boolean.class, Boolean[].class);
106         arrayTypes.put(Character.class, Character[].class);
107         arrayTypes.put(String.class, String[].class);
108         ARRAY_CLASS_MAP = Collections.unmodifiableMap(arrayTypes);
109     }
110
111     private ConfigurationUtils() {
112         // prevent instantiation
113     }
114
115     public static Collection<File> getAllFiles(File file, boolean recursive, boolean onlyDirectory) {
116         ArrayList<File> collection = new ArrayList<>();
117         Path rootPath = file.toPath();
118         try {
119             Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
120                 @Override
121                 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
122                     super.preVisitDirectory(dir, attrs);
123                     if (rootPath.equals(dir)) {
124                         return FileVisitResult.CONTINUE;
125                     }
126                     collection.add(dir.toFile());
127                     return recursive ? FileVisitResult.CONTINUE : FileVisitResult.SKIP_SUBTREE;
128                 }
129
130                 @Override
131                 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
132                     super.visitFile(file, attrs);
133                     if (!onlyDirectory) {
134                         collection.add(file.toFile());
135                     }
136                     return FileVisitResult.CONTINUE;
137                 }
138             });
139         } catch (IOException e) {
140             LOGGER.error("Failed to walk through directories starting from: {}.", file.toString(), e);
141         }
142         return collection;
143     }
144
145     public static String getCommaSeparatedList(String[] list) {
146         return (list == null) || (list.length == 0) ? "" : getCommaSeparatedList(Arrays.asList(list));
147     }
148
149     public static String getCommaSeparatedList(List<?> list) {
150         if ((list == null) || list.isEmpty()) {
151             return "";
152         }
153         return list.stream().filter(o -> o != null && !o.toString().trim().isEmpty()).map(o -> o.toString().trim()).collect(Collectors.joining(","));
154     }
155
156     public static boolean isConfig(URL url) {
157         return isConfig(url.getFile());
158     }
159
160     public static boolean isConfig(String file) {
161         file = file.toUpperCase().substring(file.lastIndexOf('!') + 1);
162         file = file.substring(file.lastIndexOf('/') + 1);
163         return file.matches(String.format(CONFIG_REGEX_TPL_OPT_1, ConfigurationMode.OVERRIDE, ConfigurationMode.MERGE, ConfigurationMode.UNION,
164             ConfigurationType.PROPERTIES.name(), ConfigurationType.XML.name(), ConfigurationType.JSON.name(), ConfigurationType.YAML.name())) || file
165             .matches(String
166                 .format(CONFIG_REGEX_TPL_OPT_2, ConfigurationType.PROPERTIES.name(), ConfigurationType.XML.name(), ConfigurationType.JSON.name(),
167                     ConfigurationType.YAML.name()));
168     }
169
170     public static boolean isConfig(File file) {
171         return file != null && file.exists() && isConfig(file.getName());
172     }
173
174     private static Optional<String> readNamespace(Configuration config) {
175         return ofNullable(config).flatMap(configuration -> ofNullable(configuration.getString(Constants.NAMESPACE_KEY))).map(String::toUpperCase);
176     }
177
178     private static Optional<String> readMergeStrategy(Configuration config) {
179         return ofNullable(config).flatMap(configuration -> ofNullable(configuration.getString(Constants.MODE_KEY))).map(String::toUpperCase);
180     }
181
182     public static ConfigurationMode getMergeStrategy(File file) {
183         Optional<ConfigurationMode> configurationMode = getConfiguration(file).flatMap(ConfigurationUtils::readMergeStrategy)
184             .flatMap(ConfigurationUtils::convertConfigurationMode);
185         return configurationMode.orElseGet(() -> getMergeStrategy(file.getName().toUpperCase()));
186     }
187
188     public static ConfigurationMode getMergeStrategy(URL url) {
189         Optional<ConfigurationMode> configurationMode = getConfiguration(url).flatMap(ConfigurationUtils::readMergeStrategy)
190             .flatMap(ConfigurationUtils::convertConfigurationMode);
191         return configurationMode.orElseGet(() -> getMergeStrategy(url.getFile().toUpperCase()));
192     }
193
194     public static ConfigurationMode getMergeStrategy(String file) {
195         file = file.toUpperCase().substring(file.lastIndexOf('!') + 1);
196         file = file.substring(file.lastIndexOf('/') + 1);
197         Pattern pattern = Pattern.compile(String
198             .format(CONFIG_REGEX_TPL_OPT_1, ConfigurationMode.OVERRIDE, ConfigurationMode.MERGE, ConfigurationMode.UNION,
199                 ConfigurationType.PROPERTIES.name(), ConfigurationType.XML.name(), ConfigurationType.JSON.name(), ConfigurationType.YAML.name()));
200         Matcher matcher = pattern.matcher(file);
201         boolean b1 = matcher.matches();
202         if (b1) {
203             for (int i = 1; i <= matcher.groupCount(); i++) {
204                 String modeName = matcher.group(i);
205                 if (modeName != null) {
206                     modeName = modeName.substring(1);
207                 }
208                 try {
209                     return Enum.valueOf(ConfigurationMode.class, modeName);
210                 } catch (Exception exception) {
211                     LOGGER.debug("Configuration mode for merge strategy '{}' not found", modeName, exception);
212                 }
213             }
214         }
215         return null;
216     }
217
218     public static Optional<FileBasedConfiguration> getConfiguration(URL url) {
219         try {
220             ConfigurationType configType = ConfigurationUtils.getConfigType(url);
221             switch (configType) {
222                 case PROPERTIES:
223                     return Optional.of(new Configurations().fileBased(PropertiesConfiguration.class, url));
224                 case XML:
225                     return Optional.of(new Configurations().fileBased(XMLConfiguration.class, url));
226                 case JSON:
227                     return Optional.of(new Configurations().fileBased(JsonConfiguration.class, url));
228                 case YAML:
229                     return Optional.of(new Configurations().fileBased(YamlConfiguration.class, url));
230                 default:
231                     throw new ConfigurationException(CONFIGURATION_TYPE_NOT_SUPPORTED + configType);
232             }
233         } catch (ConfigurationException exception) {
234             LOGGER.error("Error reading configuration at {}.", url.toString(), exception);
235         }
236         return Optional.empty();
237     }
238
239     public static Optional<FileBasedConfiguration> getConfiguration(File file) {
240         try {
241             return getConfiguration(file.getAbsoluteFile().toURI().toURL());
242         } catch (MalformedURLException e) {
243             throw new IllegalStateException("Malformed URL: " + file.getAbsolutePath());
244         }
245     }
246
247     public static ConfigurationType getConfigType(File file) {
248         Objects.requireNonNull(file, "File cannot be null");
249         return Enum.valueOf(ConfigurationType.class, file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf('.') + 1).toUpperCase());
250     }
251
252     public static ConfigurationType getConfigType(URL url) {
253         Objects.requireNonNull(url, "URL cannot be null");
254         return Enum.valueOf(ConfigurationType.class, url.getFile().substring(url.getFile().lastIndexOf('.') + 1).toUpperCase());
255     }
256
257     private static Optional<ConfigurationMode> convertConfigurationMode(String configMode) {
258         ConfigurationMode configurationMode = null;
259         try {
260             configurationMode = ConfigurationMode.valueOf(configMode);
261         } catch (Exception exception) {
262             LOGGER.error("Could not find convert {} into configuration mode.", configMode, exception);
263         }
264         return Optional.ofNullable(configurationMode);
265     }
266
267     public static Class<?> getCollectionGenericType(Field field) {
268         Type type = field.getGenericType();
269         if (type instanceof ParameterizedType) {
270             ParameterizedType paramType = (ParameterizedType) type;
271             Type[] arr = paramType.getActualTypeArguments();
272             if (arr.length > 0) {
273                 Class<?> clazz = (Class<?>) arr[0];
274                 if (isWrapperClass(clazz)) {
275                     return clazz;
276                 } else {
277                     throw new IllegalArgumentException("Collection of type " + clazz.getName() + " not supported.");
278                 }
279             }
280         }
281         return String[].class;
282     }
283
284     public static boolean isWrapperClass(Class<?> clazz) {
285         Predicate<Class<?>> predicateWrapper = type -> type == String.class || type == Boolean.class || type == Character.class || Number.class
286             .isAssignableFrom(type);
287         return isA(predicateWrapper, clazz);
288     }
289
290     public static boolean isAPrimitive(Class<?> clazz) {
291         return isA(Class::isPrimitive, clazz);
292     }
293
294     /**
295      * Check if clazz implementing Map iface
296      */
297     public static boolean isAMap(Class<?> clazz) {
298         Predicate<Class<?>> predicateMap = Map.class::isAssignableFrom;
299         return isA(predicateMap, clazz);
300     }
301
302     /**
303      * Check if clazz implementing Collection iface
304      */
305     public static boolean isACollection(Class<?> clazz) {
306         Predicate<Class<?>> predicateCollection = Collection.class::isAssignableFrom;
307         return isA(predicateCollection, clazz);
308     }
309
310     /**
311      * Check if clazz is a primitive or primitive wrapper
312      */
313     public static boolean isAPrimitiveOrWrapper(Class<?> clazz) {
314         Predicate<Class<?>> predicatePrimitive = Class::isPrimitive;
315         Predicate<Class<?>> predicateWrapper = ConfigurationUtils::isWrapperClass;
316         return isA(predicatePrimitive.or(predicateWrapper), clazz);
317     }
318
319     /**
320      * Check if clazz is array of primitives or array of primitives wrappers
321      */
322     public static boolean isAPrimitivesOrWrappersArray(Class<?> clazz) {
323         Predicate<Class<?>> predicatePrimitivesOrWrappersArray = type -> ConfigurationUtils.isAWrappersArray(type) || ConfigurationUtils
324             .isAPrimitivesArray(type);
325         return isA(predicatePrimitivesOrWrappersArray, clazz);
326     }
327
328     /**
329      * Check is clazz is array of primitives
330      */
331     public static boolean isAPrimitivesArray(Class<?> clazz) {
332         Predicate<Class<?>> predicateArray = Class::isArray;
333         Predicate<Class<?>> predicateComponentPrimitive = type -> type.getComponentType().isPrimitive();
334         return isA(predicateArray.and(predicateComponentPrimitive), clazz);
335     }
336
337     /**
338      * Check is clazz is array of primitives wrappers
339      */
340     public static boolean isAWrappersArray(Class<?> clazz) {
341         Predicate<Class<?>> predicateArray = Class::isArray;
342         Predicate<Class<?>> predicateComponentWrapper = type -> isWrapperClass(type.getComponentType());
343         return isA(predicateArray.and(predicateComponentWrapper), clazz);
344     }
345
346     private static boolean isA(Predicate<Class<?>> predicate, Class<?> clazz) {
347         return predicate.test(clazz);
348     }
349
350     public static Class<?> getArrayClass(Class<?> clazz) {
351         return ARRAY_CLASS_MAP.getOrDefault(clazz, null);
352     }
353
354     public static List<URL> getAllClassPathResources() {
355         try (ScanResult scanResult = new ClassGraph().scan()) {
356             return scanResult.getAllResources().getURLs();
357         }
358     }
359
360     public static BasicConfigurationBuilder<FileBasedConfiguration> getConfigurationBuilder(File file) {
361         FileBasedConfigurationBuilder<FileBasedConfiguration> builder;
362         ConfigurationType configType = ConfigurationUtils.getConfigType(file);
363         builder = getFileBasedConfigurationBuilder(configType);
364         builder.configure(new Parameters().fileBased().setFile(file).setListDelimiterHandler(new DefaultListDelimiterHandler(',')));
365         return builder;
366     }
367
368     public static BasicConfigurationBuilder<FileBasedConfiguration> getConfigurationBuilder(URL url) {
369         ConfigurationType configType = ConfigurationUtils.getConfigType(url);
370         ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder = getFileBasedConfigurationBuilder(configType);
371         builder.configure(new Parameters().fileBased().setURL(url).setListDelimiterHandler(new DefaultListDelimiterHandler(',')));
372         return builder;
373     }
374
375     private static ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> getFileBasedConfigurationBuilder(ConfigurationType configType) {
376         ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder;
377         switch (configType) {
378             case PROPERTIES:
379                 builder = new ReloadingFileBasedConfigurationBuilder<>(PropertiesConfiguration.class);
380                 break;
381             case XML:
382                 builder = new ReloadingFileBasedConfigurationBuilder<>(XMLConfiguration.class);
383                 break;
384             case JSON:
385                 builder = new ReloadingFileBasedConfigurationBuilder<>(JsonConfiguration.class);
386                 break;
387             case YAML:
388                 builder = new ReloadingFileBasedConfigurationBuilder<>(YamlConfiguration.class);
389                 break;
390             default:
391                 throw new IllegalArgumentException(CONFIGURATION_TYPE_NOT_SUPPORTED + configType);
392         }
393         return builder;
394     }
395
396     public static <T> T read(Configuration config, Class<T> clazz, String keyPrefix) throws Exception {
397         Config confAnnotation = clazz.getAnnotation(Config.class);
398         if (confAnnotation != null) {
399             keyPrefix += (confAnnotation.key() + ".");
400         }
401         T objToReturn = clazz.newInstance();
402         for (Field field : clazz.getDeclaredFields()) {
403             Config fieldAnnotation = field.getAnnotation(Config.class);
404             if (fieldAnnotation != null) {
405                 field.setAccessible(true);
406                 field.set(objToReturn, config.getProperty(keyPrefix + fieldAnnotation.key()));
407             } else if (field.getType().getAnnotation(Config.class) != null) {
408                 field.set(objToReturn, read(config, field.getType(), keyPrefix));
409             }
410         }
411         return objToReturn;
412     }
413
414     public static Object getPrimitiveArray(Collection<?> collection, Class<?> clazz) {
415         switch (clazz.getName()) {
416             case "int":
417                 return getIntsPrimitiveArray(collection);
418             case "byte":
419                 return getBytesPrimitiveArray(collection);
420             case "short":
421                 return getShortsPrimitiveArray(collection);
422             case "long":
423                 return getLongsPrimitiveArray(collection);
424             case "float":
425                 return getFloatsPrimitiveArray(collection);
426             case "double":
427                 return getDoublesPrimitiveArray(collection);
428             case "boolean":
429                 return getBooleansPrimitiveArray(collection);
430             case "char":
431                 return getCharsPrimitiveArray(collection);
432             default:
433                 return null;
434         }
435     }
436
437     public static Object getWrappersArray(Collection<?> collection, Class<?> clazz) {
438         Object array = null;
439         if (isWrapperClass(clazz)) {
440             int collectionSize = collection.size();
441             array = Array.newInstance(clazz, collection.size());
442             Object[] objArray = collection.toArray();
443             System.arraycopy(objArray, 0, array, 0, collectionSize);
444         }
445         return array;
446     }
447
448     public static String getCollectionString(String input) {
449         Pattern pattern = Pattern.compile("^\\[(.*)\\]$");
450         Matcher matcher = pattern.matcher(input);
451         if (matcher.matches()) {
452             input = matcher.group(1);
453         }
454         return input;
455     }
456
457     public static String processVariablesIfPresent(String tenant, String namespace, String data) {
458         Pattern pattern = Pattern.compile("^.*\\$\\{(.*)\\}.*");
459         Matcher matcher = pattern.matcher(data);
460         if (matcher.matches()) {
461             final int substringStartIndex = 4;
462             String key = matcher.group(1);
463             String value;
464             if (key.toUpperCase().startsWith("ENV:")) {
465                 value = System.getenv(key.substring(substringStartIndex));
466             } else if (key.toUpperCase().startsWith("SYS:")) {
467                 value = System.getProperty(key.substring(substringStartIndex));
468             } else {
469                 value = ConfigurationUtils.getCollectionString(ConfigurationManager.lookup().getAsStringValues(tenant, namespace, key).toString());
470             }
471             return processVariablesIfPresent(tenant, namespace,
472                 data.replaceAll("\\$\\{" + key + "}", value == null ? "" : value.replace("\\", "\\\\")));
473         } else {
474             return data;
475         }
476     }
477
478     public static String getFileContents(String path) {
479         try {
480             if (path != null) {
481                 return IOUtils.toString(new URL(path), Charset.defaultCharset());
482             }
483         } catch (Exception exception) {
484             LOGGER.error("Error while getting '{}' content", path, exception);
485         }
486         return null;
487     }
488
489     public static String getFileContents(Path path) {
490         try {
491             if (path != null) {
492                 return new String(Files.readAllBytes(path));
493             }
494         } catch (Exception exception) {
495             LOGGER.error("Error while getting '{}' content", path.toString(), exception);
496         }
497         return null;
498     }
499
500     public static Object getDefaultFor(Class<?> clazz) {
501         if (byte.class == clazz) {
502             return new Byte("0");
503         } else if (short.class == clazz) {
504             return new Short("0");
505         } else if (int.class == clazz) {
506             return new Integer("0");
507         } else if (float.class == clazz) {
508             return new Float("0");
509         } else if (long.class == clazz) {
510             return new Long("0");
511         } else if (double.class == clazz) {
512             return new Double("0");
513         } else if (boolean.class == clazz) {
514             return Boolean.FALSE;
515         }
516         return (char) 0;
517     }
518
519     public static Collection getCompatibleCollectionForAbstractDef(Class<?> clazz) {
520         if (TransferQueue.class.isAssignableFrom(clazz)) {
521             return getConcreteCollection(TransferQueue.class);
522         }
523         if (BlockingQueue.class.isAssignableFrom(clazz)) {
524             return getConcreteCollection(BlockingQueue.class);
525         }
526         if (Deque.class.isAssignableFrom(clazz)) {
527             return getConcreteCollection(Deque.class);
528         }
529         if (Queue.class.isAssignableFrom(clazz)) {
530             return getConcreteCollection(Queue.class);
531         }
532         if (SortedSet.class.isAssignableFrom(clazz)) {
533             return getConcreteCollection(SortedSet.class);
534         }
535         if (Set.class.isAssignableFrom(clazz)) {
536             return getConcreteCollection(Set.class);
537         }
538         if (List.class.isAssignableFrom(clazz)) {
539             return getConcreteCollection(List.class);
540         }
541         throw new IllegalArgumentException("Only corresponding array classes and any are allowed as argument."
542             + "assignable from TransferQueue, BlockingQueue, Deque, Queue, SortedSet, Set, List class");
543     }
544
545     public static Collection getConcreteCollection(Class<?> clazz) {
546         switch (clazz.getName()) {
547             case "java.util.Collection":
548             case "java.util.List":
549                 return new ArrayList<>();
550             case "java.util.Set":
551                 return new HashSet<>();
552             case "java.util.SortedSet":
553                 return new TreeSet<>();
554             case "java.util.Queue":
555                 return new ConcurrentLinkedQueue<>();
556             case "java.util.Deque":
557                 return new ArrayDeque<>();
558             case "java.util.concurrent.TransferQueue":
559                 return new LinkedTransferQueue<>();
560             case "java.util.concurrent.BlockingQueue":
561                 return new LinkedBlockingQueue<>();
562             default:
563                 throw new IllegalArgumentException("Only corresponding array classes and any are allowed as argument."
564                     + "assignable from TransferQueue, BlockingQueue, Deque, Queue, SortedSet, Set, List class");
565         }
566     }
567
568     public static String getConfigurationRepositoryKey(File file) {
569         return getConfigurationRepositoryKey(ConfigurationUtils.getNamespace(file).split(Constants.TENANT_NAMESPACE_SEPARATOR));
570     }
571
572     public static String getConfigurationRepositoryKey(URL url) {
573         return getConfigurationRepositoryKey(ConfigurationUtils.getNamespace(url).split(Constants.TENANT_NAMESPACE_SEPARATOR));
574     }
575
576     public static String getConfigurationRepositoryKey(String[] array) {
577         Deque<String> stack = new ArrayDeque<>();
578         stack.push(Constants.DEFAULT_TENANT);
579         for (String element : array) {
580             stack.push(element);
581         }
582         String toReturn = stack.pop();
583         return stack.pop() + Constants.KEY_ELEMENTS_DELIMITER + toReturn;
584     }
585
586     public static String getNamespace(File file) {
587         Optional<String> namespace = getConfiguration(file).flatMap(ConfigurationUtils::readNamespace).map(String::toUpperCase);
588         return namespace.orElseGet(() -> getNamespace(file.getName().toUpperCase()));
589     }
590
591     public static String getNamespace(String file) {
592         file = file.toUpperCase().substring(file.lastIndexOf('!') + 1);
593         file = file.substring(file.lastIndexOf('/') + 1);
594         Pattern pattern = Pattern.compile(String
595             .format(CONFIG_REGEX_TPL_OPT_1, ConfigurationMode.OVERRIDE, ConfigurationMode.MERGE, ConfigurationMode.UNION,
596                 ConfigurationType.PROPERTIES.name(), ConfigurationType.XML.name(), ConfigurationType.JSON.name(), ConfigurationType.YAML.name()));
597         Matcher matcher = pattern.matcher(file);
598         boolean b1 = matcher.matches();
599         if (b1) {
600             if (matcher.group(1) != null) {
601                 String moduleName = matcher.group(1).substring(1);
602                 return moduleName.equalsIgnoreCase(ConfigurationMode.OVERRIDE.name()) || moduleName.equalsIgnoreCase(ConfigurationMode.UNION.name())
603                     || moduleName.equalsIgnoreCase(ConfigurationMode.MERGE.name()) ? Constants.DEFAULT_NAMESPACE : moduleName;
604             } else {
605                 return Constants.DEFAULT_NAMESPACE;
606             }
607         } else if (isConfig(file)) {
608             return Constants.DEFAULT_NAMESPACE;
609         }
610         return null;
611     }
612
613     public static String getNamespace(URL url) {
614         Optional<String> namespace = getConfiguration(url).flatMap(ConfigurationUtils::readNamespace).map(String::toUpperCase);
615         return namespace.orElseGet(() -> getNamespace(url.getFile().toUpperCase()));
616     }
617
618     public static Object getProperty(Configuration config, String key, int processingHints) {
619         if (!isDirectLookup(processingHints) && isNodeSpecific(processingHints) && (config instanceof CompositeConfiguration)) {
620             CompositeConfiguration conf = (CompositeConfiguration) config;
621             for (int i = 0; i < conf.getNumberOfConfigurations(); i++) {
622                 Object obj = conf.getConfiguration(i).getProperty(key);
623                 if (obj != null) {
624                     return obj;
625                 }
626             }
627         }
628         return config.getProperty(key);
629     }
630
631     public static boolean isCollection(String input) {
632         Pattern pattern = Pattern.compile("^\\[(.*)\\]$");
633         Matcher matcher = pattern.matcher(input);
634         return matcher.matches();
635     }
636
637     public static boolean isDirectLookup(int hints) {
638         return (hints & LATEST_LOOKUP.value()) == LATEST_LOOKUP.value();
639     }
640
641     public static boolean isNodeSpecific(int hints) {
642         return (hints & NODE_SPECIFIC.value()) == NODE_SPECIFIC.value();
643     }
644
645     public static boolean isExternalLookup(int hints) {
646         return (hints & EXTERNAL_LOOKUP.value()) == EXTERNAL_LOOKUP.value();
647     }
648
649     public static boolean isZeroLengthArray(Class<?> clazz, Object obj) {
650         if (isAPrimitivesArray(clazz)) {
651             if (clazz.getComponentType() == int.class) {
652                 return ((int[]) obj).length == 0;
653             } else if (clazz.getComponentType() == byte.class) {
654                 return ((byte[]) obj).length == 0;
655             } else if (clazz.getComponentType() == short.class) {
656                 return ((short[]) obj).length == 0;
657             } else if (clazz.getComponentType() == float.class) {
658                 return ((float[]) obj).length == 0;
659             } else if (clazz.getComponentType() == boolean.class) {
660                 return ((boolean[]) obj).length == 0;
661             } else if (clazz.getComponentType() == double.class) {
662                 return ((double[]) obj).length == 0;
663             } else if (clazz.getComponentType() == long.class) {
664                 return ((long[]) obj).length == 0;
665             } else {
666                 return ((Object[]) obj).length == 0;
667             }
668         }
669         return false;
670     }
671
672     public static boolean isBlank(String value) {
673         return value == null || value.trim().isEmpty();
674     }
675
676     // private methods section starts here
677     private static int[] getIntsPrimitiveArray(Collection<?> collection) {
678         int collectionSize = collection.size();
679         int[] array = new int[collectionSize];
680         Object[] objArray = collection.toArray();
681         for (int i = 0; i < collectionSize; i++) {
682             array[i] = (int) objArray[i];
683         }
684         return array;
685     }
686
687     private static byte[] getBytesPrimitiveArray(Collection<?> collection) {
688         int collectionSize = collection.size();
689         byte[] array = new byte[collectionSize];
690         Object[] objArray = collection.toArray();
691         for (int i = 0; i < collectionSize; i++) {
692             array[i] = (byte) objArray[i];
693         }
694         return array;
695     }
696
697     private static short[] getShortsPrimitiveArray(Collection<?> collection) {
698         int collectionSize = collection.size();
699         short[] array = new short[collectionSize];
700         Object[] objArray = collection.toArray();
701         for (int i = 0; i < collectionSize; i++) {
702             array[i] = (short) objArray[i];
703         }
704         return array;
705     }
706
707     private static long[] getLongsPrimitiveArray(Collection<?> collection) {
708         int collectionSize = collection.size();
709         long[] array = new long[collectionSize];
710         Object[] objArray = collection.toArray();
711         for (int i = 0; i < collectionSize; i++) {
712             array[i] = (long) objArray[i];
713         }
714         return array;
715     }
716
717     private static float[] getFloatsPrimitiveArray(Collection<?> collection) {
718         int collectionSize = collection.size();
719         float[] array = new float[collectionSize];
720         Object[] objArray = collection.toArray();
721         for (int i = 0; i < collectionSize; i++) {
722             array[i] = (float) objArray[i];
723         }
724         return array;
725     }
726
727     private static double[] getDoublesPrimitiveArray(Collection<?> collection) {
728         int collectionSize = collection.size();
729         double[] array = new double[collectionSize];
730         Object[] objArray = collection.toArray();
731         for (int i = 0; i < collectionSize; i++) {
732             array[i] = (double) objArray[i];
733         }
734         return array;
735     }
736
737     private static boolean[] getBooleansPrimitiveArray(Collection<?> collection) {
738         int collectionSize = collection.size();
739         boolean[] array = new boolean[collectionSize];
740         Object[] objArray = collection.toArray();
741         for (int i = 0; i < collectionSize; i++) {
742             array[i] = (boolean) objArray[i];
743         }
744         return array;
745     }
746
747     private static char[] getCharsPrimitiveArray(Collection<?> collection) {
748         int collectionSize = collection.size();
749         char[] array = new char[collectionSize];
750         Object[] objArray = collection.toArray();
751         for (int i = 0; i < collectionSize; i++) {
752             array[i] = (char) objArray[i];
753         }
754         return array;
755     }
756 }