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