Removed code that stored configuration in DB
[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 /**
85  * The type Configuration utils.
86  */
87 public class ConfigurationUtils {
88     private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationUtils.class);
89     private static final String CONFIGURATION_TYPE_NOT_SUPPORTED = "Configuration type not supported:";
90
91     private ConfigurationUtils() {
92     }
93
94     private static final Map<Class, Class> ARRAY_CLASS_MAP;
95
96     static {
97         Map<Class, Class> arrayTypes = new HashMap<>();
98         arrayTypes.put(Byte.class, Byte[].class);
99         arrayTypes.put(Short.class, Short[].class);
100         arrayTypes.put(Integer.class, Integer[].class);
101         arrayTypes.put(Long.class, Long[].class);
102         arrayTypes.put(Float.class, Float[].class);
103         arrayTypes.put(Double.class, Double[].class);
104         arrayTypes.put(Boolean.class, Boolean[].class);
105         arrayTypes.put(Character.class, Character[].class);
106         arrayTypes.put(String.class, String[].class);
107         ARRAY_CLASS_MAP = Collections.unmodifiableMap(arrayTypes);
108     }
109
110     /**
111      * Gets thread factory.
112      *
113      * @return the thread factory
114      */
115     public static ThreadFactory getThreadFactory() {
116         return r1 -> {
117             Thread thread = Executors.privilegedThreadFactory().newThread(r1);
118             thread.setDaemon(true);
119             return thread;
120         };
121     }
122
123     /**
124      * Gets all files.
125      *
126      * @param file          the file
127      * @param recursive     the recursive
128      * @param onlyDirectory the only directory
129      * @return the all files
130      */
131     public static Collection<File> getAllFiles(File file, boolean recursive, boolean onlyDirectory) {
132         ArrayList<File> collection = new ArrayList<>();
133         if (file.isDirectory() && file.exists()) {
134             File[] files = file.listFiles();
135             for (File innerFile : files) {
136                 if (innerFile.isFile() && !onlyDirectory) {
137                     collection.add(innerFile);
138                 } else if (innerFile.isDirectory()) {
139                     collection.add(innerFile);
140                     if (recursive) {
141                         collection.addAll(getAllFiles(innerFile, recursive, onlyDirectory));
142                     }
143                 }
144             }
145         }
146         return collection;
147     }
148
149     /**
150      * Gets comma saperated list.
151      *
152      * @param list the list
153      * @return the comma separated list
154      */
155     public static String getCommaSeparatedList(List list) {
156         return ((Stream<String>) list.stream().filter(o -> o != null && !o.toString().trim().isEmpty()).map(o -> o.toString().trim())).collect(Collectors.joining(","));
157     }
158
159     /**
160      * Gets comma saperated list.
161      *
162      * @param list the list
163      * @return the comma saperated list
164      */
165     public static String getCommaSeparatedList(String[] list) {
166         return getCommaSeparatedList(list == null ? Arrays.asList() : Arrays.asList(list));
167     }
168
169     /**
170      * Gets config type.
171      *
172      * @param url the url
173      * @return the config type
174      */
175     public static ConfigurationType getConfigType(URL url) {
176         return Enum.valueOf(ConfigurationType.class,
177                 url.getFile().substring(url.getFile().lastIndexOf('.') + 1).toUpperCase());
178     }
179
180     /**
181      * Gets config type.
182      *
183      * @param file the file
184      * @return the config type
185      */
186     public static ConfigurationType getConfigType(File file) {
187         return Enum.valueOf(ConfigurationType.class,
188                 file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf('.') + 1)
189                         .toUpperCase());
190     }
191
192     /**
193      * Is config boolean.
194      *
195      * @param url the url
196      * @return the boolean
197      */
198     public static boolean isConfig(URL url) {
199         return isConfig(url.getFile());
200     }
201
202     /**
203      * Is config boolean.
204      *
205      * @param file the file
206      * @return the boolean
207      */
208     public static boolean isConfig(File file) {
209         return file != null && file.exists() && isConfig(file.getName());
210     }
211
212     /**
213      * Is config boolean.
214      *
215      * @param file the file
216      * @return the boolean
217      */
218     public static boolean isConfig(String file) {
219         file = file.toUpperCase().substring(file.lastIndexOf('!') + 1);
220         file = file.substring(file.lastIndexOf('/') + 1);
221         return file.matches(
222                 "CONFIG(-\\w*){0,1}(-" + "(" + ConfigurationMode.OVERRIDE + "|" + ConfigurationMode.MERGE
223                         + "|" + ConfigurationMode.UNION + ")){0,1}" + "\\.("
224                         + ConfigurationType.PROPERTIES.name() + "|" + ConfigurationType.XML.name() + "|"
225                         + ConfigurationType.JSON.name() + "|" + ConfigurationType.YAML.name() + ")$")
226                 || file.matches("CONFIG(.)*\\.(" + ConfigurationType.PROPERTIES.name() + "|"
227                 + ConfigurationType.XML.name() + "|" + ConfigurationType.JSON.name() + "|"
228                 + ConfigurationType.YAML.name() + ")$");
229     }
230
231     /**
232      * Gets namespace.
233      *
234      * @param url the url
235      * @return the namespace
236      */
237     public static String getNamespace(URL url) {
238
239         Optional<String> namespace = getConfiguration(url).flatMap(ConfigurationUtils::getNamespace).map(String::toUpperCase);
240
241         return namespace.orElseGet(() -> getNamespace(url.getFile().toUpperCase()));
242     }
243
244     /**
245      * Gets namespace.
246      *
247      * @param file the file
248      * @return the namespace
249      */
250     public static String getNamespace(File file) {
251         Optional<String> namespace = getConfiguration(file)
252                 .flatMap(ConfigurationUtils::getNamespace)
253                 .map(String::toUpperCase);
254         return namespace.orElseGet(() -> getNamespace(file.getName().toUpperCase()));
255     }
256
257     private static Optional<String> getNamespace(Configuration config) {
258         return ofNullable(config)
259                 .flatMap(configuration -> ofNullable(configuration.getString(Constants.NAMESPACE_KEY)))
260                 .map(String::toUpperCase);
261     }
262
263     /**
264      * Gets namespace.
265      *
266      * @param file the file
267      * @return the namespace
268      */
269     public static String getNamespace(String file) {
270         file = file.toUpperCase().substring(file.lastIndexOf('!') + 1);
271         file = file.substring(file.lastIndexOf('/') + 1);
272         Pattern pattern = Pattern.compile(
273                 "CONFIG(-\\w*){0,1}(-" + "(" + ConfigurationMode.OVERRIDE + "|" + ConfigurationMode.MERGE
274                         + "|" + ConfigurationMode.UNION + ")){0,1}" + "\\.("
275                         + ConfigurationType.PROPERTIES.name() + "|" + ConfigurationType.XML.name() + "|"
276                         + ConfigurationType.JSON.name() + "|" + ConfigurationType.YAML.name() + ")$");
277         Matcher matcher = pattern.matcher(file);
278         boolean b1 = matcher.matches();
279         if (b1) {
280             if (matcher.group(1) != null) {
281                 String moduleName = matcher.group(1).substring(1);
282                 return moduleName.equalsIgnoreCase(ConfigurationMode.OVERRIDE.name())
283                         || moduleName.equalsIgnoreCase(ConfigurationMode.UNION.name())
284                         || moduleName.equalsIgnoreCase(ConfigurationMode.MERGE.name())
285                         ? Constants.DEFAULT_NAMESPACE : moduleName;
286             } else {
287                 return Constants.DEFAULT_NAMESPACE;
288             }
289         } else if (isConfig(file)) {
290             return Constants.DEFAULT_NAMESPACE;
291         }
292
293         return null;
294     }
295
296     /**
297      * Gets merge strategy.
298      *
299      * @param url the url
300      * @return the merge strategy
301      */
302     public static ConfigurationMode getMergeStrategy(URL url) {
303         Optional<ConfigurationMode> configurationMode = getConfiguration(url).flatMap(ConfigurationUtils::getMergeStrategy).flatMap(ConfigurationUtils::convertConfigurationMode);
304         return configurationMode.orElseGet(() -> getMergeStrategy(url.getFile().toUpperCase()));
305     }
306
307     private static Optional<ConfigurationMode> convertConfigurationMode(String configMode) {
308         ConfigurationMode configurationMode = null;
309         try {
310             configurationMode = ConfigurationMode.valueOf(configMode);
311         } catch (Exception exception) {
312             LOGGER.error("Could not find convert {} into configuration mode", configMode);
313         }
314         return Optional.ofNullable(configurationMode);
315     }
316
317     private static Optional<String> getMergeStrategy(Configuration config) {
318         return ofNullable(config)
319                 .flatMap(configuration -> ofNullable(configuration.getString(Constants.MODE_KEY)))
320                 .map(String::toUpperCase);
321     }
322
323
324     /**
325      * Gets merge strategy.
326      *
327      * @param file the file
328      * @return the merge strategy
329      */
330     public static ConfigurationMode getMergeStrategy(File file) {
331         Optional<ConfigurationMode> configurationMode = getConfiguration(file).flatMap(ConfigurationUtils::getMergeStrategy).flatMap(ConfigurationUtils::convertConfigurationMode);
332         return configurationMode.orElseGet(() -> getMergeStrategy(file.getName().toUpperCase()));
333     }
334
335     /**
336      * Gets merge strategy.
337      *
338      * @param file the file
339      * @return the merge strategy
340      */
341     public static ConfigurationMode getMergeStrategy(String file) {
342         file = file.toUpperCase().substring(file.lastIndexOf('!') + 1);
343         file = file.substring(file.lastIndexOf('/') + 1);
344         Pattern pattern = Pattern.compile(
345                 "CONFIG(-\\w*){0,1}(-" + "(" + ConfigurationMode.OVERRIDE + "|" + ConfigurationMode.MERGE
346                         + "|" + ConfigurationMode.UNION + ")){0,1}" + "\\.("
347                         + ConfigurationType.PROPERTIES.name() + "|" + ConfigurationType.XML.name() + "|"
348                         + ConfigurationType.JSON.name() + "|" + ConfigurationType.YAML.name() + ")$");
349         Matcher matcher = pattern.matcher(file);
350         boolean b1 = matcher.matches();
351         if (b1) {
352             for (int i = 1; i <= matcher.groupCount(); i++) {
353                 String modeName = matcher.group(i);
354                 if (modeName != null) {
355                     modeName = modeName.substring(1);
356                 }
357                 try {
358                     return Enum.valueOf(ConfigurationMode.class, modeName);
359                 } catch (Exception exception) {
360                     //do nothing
361                 }
362             }
363         }
364
365         return null;
366     }
367
368     /**
369      * Gets configuration.
370      *
371      * @param url the url
372      * @return the configuration
373      */
374     public static Optional<FileBasedConfiguration> getConfiguration(URL url) {
375         FileBasedConfiguration builder = null;
376         try {
377             ConfigurationType configType = ConfigurationUtils.getConfigType(url);
378             switch (configType) {
379                 case PROPERTIES:
380                     builder = new Configurations().fileBased(PropertiesConfiguration.class, url);
381                     break;
382                 case XML:
383                     builder = new Configurations().fileBased(XMLConfiguration.class, url);
384                     break;
385                 case JSON:
386                     builder = new Configurations().fileBased(JsonConfiguration.class, url);
387                     break;
388                 case YAML:
389                     builder = new Configurations().fileBased(YamlConfiguration.class, url);
390                     break;
391                 default:
392                     throw new ConfigurationException(CONFIGURATION_TYPE_NOT_SUPPORTED + configType);
393             }
394         } catch (ConfigurationException exception) {
395             exception.printStackTrace();
396         }
397         return ofNullable(builder);
398     }
399
400     /**
401      * Gets configuration.
402      *
403      * @param file the file
404      * @return the configuration
405      */
406     public static Optional<FileBasedConfiguration> getConfiguration(File file) {
407         FileBasedConfiguration builder = null;
408         try {
409             ConfigurationType configType = ConfigurationUtils.getConfigType(file);
410             switch (configType) {
411                 case PROPERTIES:
412                     builder = new Configurations().fileBased(PropertiesConfiguration.class, file);
413                     break;
414                 case XML:
415                     builder = new Configurations().fileBased(XMLConfiguration.class, file);
416                     break;
417                 case JSON:
418                     builder = new Configurations().fileBased(JsonConfiguration.class, file);
419                     break;
420                 case YAML:
421                     builder = new Configurations().fileBased(YamlConfiguration.class, file);
422                     break;
423                 default:
424                     throw new ConfigurationException(CONFIGURATION_TYPE_NOT_SUPPORTED + configType);
425             }
426         } catch (ConfigurationException exception) {
427             exception.printStackTrace();
428         }
429         return ofNullable(builder);
430     }
431
432     /**
433      * Gets collection generic type.
434      *
435      * @param field the field
436      * @return the collection generic type
437      */
438     public static Class getCollectionGenericType(Field field) {
439         Type type = field.getGenericType();
440
441         if (type instanceof ParameterizedType) {
442
443             ParameterizedType paramType = (ParameterizedType) type;
444             Type[] arr = paramType.getActualTypeArguments();
445
446             for (Type tp : arr) {
447                 Class<?> clzz = (Class<?>) tp;
448                 if (isWrapperClass(clzz)) {
449                     return clzz;
450                 } else {
451                     throw new RuntimeException("Collection of type " + clzz.getName() + " not supported.");
452                 }
453             }
454         }
455         return String[].class;
456     }
457
458
459     /**
460      * Gets array class.
461      *
462      * @param clazz the clazz
463      * @return the array class
464      */
465     public static Class getArrayClass(Class clazz) {
466         return ARRAY_CLASS_MAP.getOrDefault(clazz, null);
467     }
468
469     /**
470      * Gets all class path resources.
471      *
472      * @return the all class path resources
473      */
474     public static List<URL> getAllClassPathResources() {
475         return CPScanner.scanResources(new ResourceFilter());
476     }
477
478     /**
479      * Gets configuration builder.
480      *
481      * @param url the url
482      * @return the configuration builder
483      */
484     public static BasicConfigurationBuilder<FileBasedConfiguration> getConfigurationBuilder(URL url) {
485         ConfigurationType configType = ConfigurationUtils.getConfigType(url);
486         ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder = getFileBasedConfigurationReloadingFileBasedConfigurationBuilder(
487                 configType);
488         builder.configure(new Parameters().fileBased().setURL(url)
489                 .setListDelimiterHandler(new DefaultListDelimiterHandler(',')));
490         return builder;
491     }
492
493     /**
494      * Gets configuration builder.
495      *
496      * @param file     the file
497      * @param autoSave the auto save
498      * @return the configuration builder
499      */
500     public static BasicConfigurationBuilder<FileBasedConfiguration> getConfigurationBuilder(File file,
501                                                                                             boolean autoSave) {
502         ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder;
503         ConfigurationType configType = ConfigurationUtils.getConfigType(file);
504         builder = getFileBasedConfigurationReloadingFileBasedConfigurationBuilder(configType);
505         builder.configure(new Parameters().fileBased().setFile(file)
506                 .setListDelimiterHandler(new DefaultListDelimiterHandler(',')));
507         builder.setAutoSave(autoSave);
508         return builder;
509     }
510
511     private static ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> getFileBasedConfigurationReloadingFileBasedConfigurationBuilder(
512             ConfigurationType configType) {
513         ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder;
514         switch (configType) {
515             case PROPERTIES:
516                 builder = new ReloadingFileBasedConfigurationBuilder<>(PropertiesConfiguration.class);
517                 break;
518             case XML:
519                 builder = new ReloadingFileBasedConfigurationBuilder<>(XMLConfiguration.class);
520                 break;
521             case JSON:
522                 builder = new ReloadingFileBasedConfigurationBuilder<>(JsonConfiguration.class);
523                 break;
524             case YAML:
525                 builder = new ReloadingFileBasedConfigurationBuilder<>(YamlConfiguration.class);
526                 break;
527             default:
528                 throw new IllegalArgumentException(CONFIGURATION_TYPE_NOT_SUPPORTED + configType);
529         }
530         return builder;
531     }
532
533     /**
534      * Read t.
535      *
536      * @param <T>       the type parameter
537      * @param config    the config
538      * @param clazz     the clazz
539      * @param keyPrefix the key prefix
540      * @return the t
541      * @throws Exception the exception
542      */
543     public static <T> T read(Configuration config, Class<T> clazz, String keyPrefix)
544             throws Exception {
545         Config confAnnot =
546                 clazz.getAnnotation(Config.class);
547         if (confAnnot != null) {
548             keyPrefix += (confAnnot.key() + ".");
549         }
550         T objToReturn = clazz.newInstance();
551         for (Field field : clazz.getDeclaredFields()) {
552             Config fieldConfAnnot =
553                     field.getAnnotation(Config.class);
554             if (fieldConfAnnot != null) {
555                 field.setAccessible(true);
556                 field.set(objToReturn, config.getProperty(keyPrefix + fieldConfAnnot.key()));
557             } else if (field.getType().getAnnotation(Config.class) != null) {
558                 field.set(objToReturn, read(config, field.getType(), keyPrefix));
559             }
560         }
561         return objToReturn;
562     }
563
564     /**
565      * Gets property.
566      *
567      * @param config          the config
568      * @param key             the key
569      * @param processingHints the processing hints
570      * @return the property
571      */
572     public static Object getProperty(Configuration config, String key, int processingHints) {
573         if (!isDirectLookup(processingHints)) {
574             if (config instanceof AgglomerateConfiguration) {
575                 return ((AgglomerateConfiguration) config).getPropertyValue(key);
576             } else if (config instanceof CompositeConfiguration) {
577                 CompositeConfiguration conf = (CompositeConfiguration) config;
578                 for (int i = 0; i < conf.getNumberOfConfigurations(); i++) {
579                     if (conf.getConfiguration(i) instanceof AgglomerateConfiguration) {
580                         return ((AgglomerateConfiguration) conf.getConfiguration(i)).getPropertyValue(key);
581                     } else if (isNodeSpecific(processingHints)) {
582                         Object obj = conf.getConfiguration(i).getProperty(key);
583                         if (obj != null) {
584                             return obj;
585                         }
586                     }
587                 }
588             }
589         }
590         return config.getProperty(key);
591     }
592
593     /**
594      * Gets primitive array.
595      *
596      * @param collection the collection
597      * @param clazz      the clazz
598      * @return the primitive array
599      */
600     public static Object getPrimitiveArray(Collection collection, Class clazz) {
601         if (clazz == int.class) {
602             int[] array = new int[collection.size()];
603             Object[] objArray = collection.toArray();
604             for (int i = 0; i < collection.size(); i++) {
605                 array[i] = (int) objArray[i];
606             }
607             return array;
608         }
609         if (clazz == byte.class) {
610             byte[] array = new byte[collection.size()];
611             Object[] objArray = collection.toArray();
612             for (int i = 0; i < collection.size(); i++) {
613                 array[i] = (byte) objArray[i];
614             }
615             return array;
616         }
617         if (clazz == short.class) {
618             short[] array = new short[collection.size()];
619             Object[] objArray = collection.toArray();
620             for (int i = 0; i < collection.size(); i++) {
621                 array[i] = (short) objArray[i];
622             }
623             return array;
624         }
625         if (clazz == long.class) {
626             long[] array = new long[collection.size()];
627             Object[] objArray = collection.toArray();
628             for (int i = 0; i < collection.size(); i++) {
629                 array[i] = (long) objArray[i];
630             }
631             return array;
632         }
633         if (clazz == float.class) {
634             float[] array = new float[collection.size()];
635             Object[] objArray = collection.toArray();
636             for (int i = 0; i < collection.size(); i++) {
637                 array[i] = (float) objArray[i];
638             }
639             return array;
640         }
641         if (clazz == double.class) {
642             double[] array = new double[collection.size()];
643             Object[] objArray = collection.toArray();
644             for (int i = 0; i < collection.size(); i++) {
645                 array[i] = (double) objArray[i];
646             }
647             return array;
648         }
649         if (clazz == boolean.class) {
650             boolean[] array = new boolean[collection.size()];
651             Object[] objArray = collection.toArray();
652             for (int i = 0; i < collection.size(); i++) {
653                 array[i] = (boolean) objArray[i];
654             }
655             return array;
656         }
657         return null;
658     }
659
660     /**
661      * Is wrapper class boolean.
662      *
663      * @param clazz the clazz
664      * @return the boolean
665      */
666     public static boolean isWrapperClass(Class clazz) {
667         return clazz == String.class || clazz == Boolean.class || clazz == Character.class
668                 || Number.class.isAssignableFrom(clazz);
669     }
670
671     /**
672      * Gets collection string.
673      *
674      * @param input the input
675      * @return the collection string
676      */
677     public static String getCollectionString(String input) {
678         Pattern pattern = Pattern.compile("^\\[(.*)\\]$");
679         Matcher matcher = pattern.matcher(input);
680         if (matcher.matches()) {
681             input = matcher.group(1);
682         }
683         return input;
684     }
685
686     /**
687      * Is collection boolean.
688      *
689      * @param input the input
690      * @return the boolean
691      */
692     public static boolean isCollection(String input) {
693         Pattern pattern = Pattern.compile("^\\[(.*)\\]$");
694         Matcher matcher = pattern.matcher(input);
695         return matcher.matches();
696     }
697
698     /**
699      * Process variables if present string.
700      *
701      * @param tenant    the tenant
702      * @param namespace the namespace
703      * @param data      the data
704      * @return the string
705      */
706     public static String processVariablesIfPresent(String tenant, String namespace, String data) {
707         Pattern pattern = Pattern.compile("^.*\\$\\{(.*)\\}.*");
708         Matcher matcher = pattern.matcher(data);
709         if (matcher.matches()) {
710             String key = matcher.group(1);
711             if (key.toUpperCase().startsWith("ENV:")) {
712                 String envValue = System.getenv(key.substring(4));
713                 return processVariablesIfPresent(tenant, namespace, data.replaceAll("\\$\\{" + key + "\\}",
714                         envValue == null ? "" : envValue.replace("\\", "\\\\")));
715             } else if (key.toUpperCase().startsWith("SYS:")) {
716                 String sysValue = System.getProperty(key.substring(4));
717                 return processVariablesIfPresent(tenant, namespace, data.replaceAll("\\$\\{" + key + "\\}",
718                         sysValue == null ? "" : sysValue.replace("\\", "\\\\")));
719             } else {
720                 String propertyValue = ConfigurationUtils.getCollectionString(
721                         ConfigurationManager.lookup().getAsStringValues(tenant, namespace, key).toString());
722                 return processVariablesIfPresent(tenant, namespace, data.replaceAll("\\$\\{" + key + "\\}",
723                         propertyValue == null ? "" : propertyValue.replace("\\", "\\\\")));
724             }
725         } else {
726             return data;
727         }
728     }
729
730     /**
731      * Gets file contents.
732      *
733      * @param path the path
734      * @return the file contents
735      */
736     public static String getFileContents(String path) {
737         try {
738             if (path != null) {
739                 return IOUtils.toString(new URL(path));
740             }
741         } catch (Exception exception) {
742             exception.printStackTrace();
743         }
744         return null;
745     }
746
747     /**
748      * Gets file contents.
749      *
750      * @param path the path
751      * @return the file contents
752      */
753     public static String getFileContents(Path path) {
754         try {
755             if (path != null) {
756                 return new String(Files.readAllBytes(path));
757             }
758         } catch (Exception exception) {
759             exception.printStackTrace();
760         }
761         return null;
762     }
763
764     /**
765      * Gets concrete collection.
766      *
767      * @param clazz the clazz
768      * @return the concrete collection
769      */
770     public static Collection getConcreteCollection(Class clazz) {
771         switch (clazz.getName()) {
772             case "java.util.Collection":
773             case "java.util.List":
774                 return new ArrayList<>();
775             case "java.util.Set":
776                 return new HashSet<>();
777             case "java.util.SortedSet":
778                 return new TreeSet<>();
779             case "java.util.Queue":
780                 return new ConcurrentLinkedQueue<>();
781             case "java.util.Deque":
782                 return new ArrayDeque<>();
783             case "java.util.concurrent.TransferQueue":
784                 return new LinkedTransferQueue<>();
785             case "java.util.concurrent.BlockingQueue":
786                 return new LinkedBlockingQueue<>();
787             default:
788                 return null;
789         }
790     }
791
792     /**
793      * Gets default for.
794      *
795      * @param clazz the clazz
796      * @return the default for
797      */
798     public static Object getDefaultFor(Class clazz) {
799         if (byte.class == clazz) {
800             return new Byte("0");
801         } else if (short.class == clazz) {
802             return new Short("0");
803         } else if (int.class == clazz) {
804             return new Integer("0");
805         } else if (float.class == clazz) {
806             return new Float("0");
807         } else if (long.class == clazz) {
808             return new Long("0");
809         } else if (double.class == clazz) {
810             return new Double("0");
811         } else if (boolean.class == clazz) {
812             return Boolean.FALSE;
813         }
814         return (char) 0;
815     }
816
817     /**
818      * Gets compatible collection for abstract def.
819      *
820      * @param clazz the clazz
821      * @return the compatible collection for abstract def
822      */
823     public static Collection getCompatibleCollectionForAbstractDef(Class clazz) {
824         if (BlockingQueue.class.isAssignableFrom(clazz)) {
825             return getConcreteCollection(BlockingQueue.class);
826         }
827         if (TransferQueue.class.isAssignableFrom(clazz)) {
828             return getConcreteCollection(TransferQueue.class);
829         }
830         if (Deque.class.isAssignableFrom(clazz)) {
831             return getConcreteCollection(Deque.class);
832         }
833         if (Queue.class.isAssignableFrom(clazz)) {
834             return getConcreteCollection(Queue.class);
835         }
836         if (SortedSet.class.isAssignableFrom(clazz)) {
837             return getConcreteCollection(SortedSet.class);
838         }
839         if (Set.class.isAssignableFrom(clazz)) {
840             return getConcreteCollection(Set.class);
841         }
842         if (List.class.isAssignableFrom(clazz)) {
843             return getConcreteCollection(List.class);
844         }
845         return null;
846     }
847
848     /**
849      * Gets configuration repository key.
850      *
851      * @param array the array
852      * @return the configuration repository key
853      */
854     public static String getConfigurationRepositoryKey(String[] array) {
855         Deque<String> stack = new ArrayDeque<>();
856         stack.push(Constants.DEFAULT_TENANT);
857         for (String element : array) {
858             stack.push(element);
859         }
860         String toReturn = stack.pop();
861         return stack.pop() + Constants.KEY_ELEMENTS_DELEMETER + toReturn;
862     }
863
864     /**
865      * Gets configuration repository key.
866      *
867      * @param file the file
868      * @return the configuration repository key
869      */
870     public static String getConfigurationRepositoryKey(File file) {
871         return getConfigurationRepositoryKey(
872                 ConfigurationUtils.getNamespace(file).split(Constants.TENANT_NAMESPACE_SAPERATOR));
873     }
874
875     /**
876      * Gets configuration repository key.
877      *
878      * @param url the url
879      * @return the configuration repository key
880      */
881     public static String getConfigurationRepositoryKey(URL url) {
882         return getConfigurationRepositoryKey(
883                 ConfigurationUtils.getNamespace(url).split(Constants.TENANT_NAMESPACE_SAPERATOR));
884     }
885
886     /**
887      * To map linked hash map.
888      *
889      * @param config the config
890      * @return the linked hash map
891      */
892     public static LinkedHashMap toMap(Configuration config) {
893         Iterator<String> iterator = config.getKeys();
894         LinkedHashMap<String, String> map = new LinkedHashMap<>();
895         while (iterator.hasNext()) {
896             String key = iterator.next();
897             if (!(key.equals(Constants.MODE_KEY) || key.equals(Constants.NAMESPACE_KEY)
898                     || key.equals(Constants.LOAD_ORDER_KEY))) {
899                 map.put(key, config.getProperty(key).toString());
900             }
901         }
902
903         return map;
904     }
905
906     /**
907      * Diff map.
908      *
909      * @param orig   the orig
910      * @param latest the latest
911      * @return the map
912      */
913     public static Map diff(LinkedHashMap orig, LinkedHashMap latest) {
914         orig = new LinkedHashMap<>(orig);
915         latest = new LinkedHashMap<>(latest);
916         List<String> set = new ArrayList(orig.keySet());
917         for (String key : set) {
918             if (latest.remove(key, orig.get(key))) {
919                 orig.remove(key);
920             }
921         }
922         Set<String> keys = latest.keySet();
923         for (String key : keys) {
924             orig.remove(key);
925         }
926         set = new ArrayList(orig.keySet());
927         for (String key : set) {
928             latest.put(key, "");
929         }
930         return new HashMap<>(latest);
931     }
932
933     /**
934      * Is array boolean.
935      *
936      * @param tenant          the tenant
937      * @param namespace       the namespace
938      * @param key             the key
939      * @param processingHints the processing hints
940      * @return the boolean
941      * @throws Exception the exception
942      */
943     public static boolean isArray(String tenant, String namespace, String key, int processingHints)
944             throws Exception {
945         Object obj = ConfigurationUtils
946                 .getProperty(ConfigurationRepository.lookup().getConfigurationFor(tenant, namespace), key,
947                         processingHints);
948         return (obj != null) && ConfigurationUtils.isCollection(obj.toString());
949     }
950
951     /**
952      * Is direct lookup boolean.
953      *
954      * @param hints the hints
955      * @return the boolean
956      */
957     public static boolean isDirectLookup(int hints) {
958         return (hints & LATEST_LOOKUP.value()) == LATEST_LOOKUP.value();
959     }
960
961     /**
962      * Is external lookup boolean.
963      *
964      * @param hints the hints
965      * @return the boolean
966      */
967     public static boolean isExternalLookup(int hints) {
968         return (hints & EXTERNAL_LOOKUP.value()) == EXTERNAL_LOOKUP.value();
969     }
970
971     /**
972      * Is node specific boolean.
973      *
974      * @param hints the hints
975      * @return the boolean
976      */
977     public static boolean isNodeSpecific(int hints) {
978         return (hints & NODE_SPECIFIC.value()) == NODE_SPECIFIC.value();
979     }
980
981     public static boolean isZeroLengthArray(Class clazz, Object obj) {
982         if (clazz.isArray() && clazz.getComponentType().isPrimitive()) {
983             if (clazz.getComponentType() == int.class) {
984                 return ((int[]) obj).length == 0;
985             } else if (clazz.getComponentType() == byte.class) {
986                 return ((byte[]) obj).length == 0;
987             } else if (clazz.getComponentType() == short.class) {
988                 return ((short[]) obj).length == 0;
989             } else if (clazz.getComponentType() == float.class) {
990                 return ((float[]) obj).length == 0;
991             } else if (clazz.getComponentType() == boolean.class) {
992                 return ((boolean[]) obj).length == 0;
993             } else if (clazz.getComponentType() == double.class) {
994                 return ((double[]) obj).length == 0;
995             } else if (clazz.getComponentType() == long.class) {
996                 return ((long[]) obj).length == 0;
997             } else {
998                 return ((Object[]) obj).length == 0;
999             }
1000         }
1001
1002         return false;
1003     }
1004
1005     /**
1006      * Checks if value is blank
1007      *
1008      * @param value
1009      * @return
1010      */
1011     public static boolean isBlank(String value) {
1012         return value == null || value.trim().length() == 0;
1013     }
1014 }