e8dc16efb6a3a11c6ecd6fc9f3390d0039899a19
[sdc.git] / common / openecomp-common-configuration-management / openecomp-configuration-management-core / src / main / java / org / openecomp / config / ConfigurationUtils.java
1 package org.openecomp.config;
2
3 import com.google.common.collect.ImmutableMap;
4 import com.virtlink.commons.configuration2.jackson.JsonConfiguration;
5 import net.sf.corn.cps.CPScanner;
6 import net.sf.corn.cps.ResourceFilter;
7 import org.apache.commons.configuration2.CompositeConfiguration;
8 import org.apache.commons.configuration2.Configuration;
9 import org.apache.commons.configuration2.FileBasedConfiguration;
10 import org.apache.commons.configuration2.PropertiesConfiguration;
11 import org.apache.commons.configuration2.XMLConfiguration;
12 import org.apache.commons.configuration2.builder.BasicConfigurationBuilder;
13 import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
14 import org.apache.commons.configuration2.builder.fluent.Configurations;
15 import org.apache.commons.configuration2.builder.fluent.Parameters;
16 import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
17 import org.apache.commons.configuration2.ex.ConfigurationException;
18 import org.apache.commons.io.IOUtils;
19 import org.openecomp.config.api.ConfigurationManager;
20 import org.openecomp.config.impl.AgglomerateConfiguration;
21 import org.openecomp.config.impl.ConfigurationDataSource;
22 import org.openecomp.config.impl.ConfigurationRepository;
23 import org.openecomp.config.impl.YamlConfiguration;
24 import org.openecomp.config.type.ConfigurationMode;
25 import org.openecomp.config.type.ConfigurationType;
26
27 import javax.sql.DataSource;
28 import java.io.File;
29 import java.lang.reflect.Field;
30 import java.lang.reflect.ParameterizedType;
31 import java.lang.reflect.Type;
32 import java.net.URL;
33 import java.nio.file.Files;
34 import java.nio.file.Path;
35 import java.sql.Connection;
36 import java.sql.PreparedStatement;
37 import java.sql.ResultSet;
38 import java.sql.Statement;
39 import java.util.ArrayDeque;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collection;
43 import java.util.Deque;
44 import java.util.HashMap;
45 import java.util.HashSet;
46 import java.util.Iterator;
47 import java.util.LinkedHashMap;
48 import java.util.List;
49 import java.util.Map;
50 import java.util.Queue;
51 import java.util.Set;
52 import java.util.SortedSet;
53 import java.util.TreeSet;
54 import java.util.concurrent.BlockingQueue;
55 import java.util.concurrent.ConcurrentLinkedQueue;
56 import java.util.concurrent.Executors;
57 import java.util.concurrent.LinkedBlockingQueue;
58 import java.util.concurrent.LinkedTransferQueue;
59 import java.util.concurrent.ThreadFactory;
60 import java.util.concurrent.TransferQueue;
61 import java.util.regex.Matcher;
62 import java.util.regex.Pattern;
63 import java.util.stream.Collectors;
64 import java.util.stream.Stream;
65
66 import static com.google.common.collect.ImmutableMap.builder;
67 import static org.openecomp.config.api.Hint.EXTERNAL_LOOKUP;
68 import static org.openecomp.config.api.Hint.LATEST_LOOKUP;
69 import static org.openecomp.config.api.Hint.NODE_SPECIFIC;
70
71 /**
72  * The type Configuration utils.
73  */
74 public class ConfigurationUtils {
75
76     private ConfigurationUtils() {
77     }
78
79     private static ImmutableMap<Class,Class> arrayClassMap;
80
81     static {
82         ImmutableMap.Builder<Class,Class> builder = builder();
83         builder.put(Byte.class,Byte[].class).put(Short.class, Short[].class)
84                 .put(Integer.class,Integer[].class).put(Long.class,Long[].class)
85                 .put(Float.class,Float[].class).put(Double.class,Double[].class)
86                 .put(Boolean.class,Boolean[].class).put(Character.class,Character[].class)
87                 .put(String.class,String[].class);
88         arrayClassMap = builder.build();
89     }
90
91     /**
92      * Gets thread factory.
93      *
94      * @return the thread factory
95      */
96     public static ThreadFactory getThreadFactory() {
97         return (r1) -> {
98             Thread thread = Executors.privilegedThreadFactory().newThread(r1);
99             thread.setDaemon(true);
100             return thread;
101         };
102     }
103
104     /**
105      * Gets all files.
106      *
107      * @param file          the file
108      * @param recursive     the recursive
109      * @param onlyDirectory the only directory
110      * @return the all files
111      */
112     public static Collection<File> getAllFiles(File file, boolean recursive, boolean onlyDirectory) {
113         ArrayList<File> collection = new ArrayList<>();
114         if (file.isDirectory() && file.exists()) {
115             File[] files = file.listFiles();
116             for (File innerFile : files) {
117                 if (innerFile.isFile() && !onlyDirectory) {
118                     collection.add(innerFile);
119                 } else if (innerFile.isDirectory()) {
120                     collection.add(innerFile);
121                     if (recursive) {
122                         collection.addAll(getAllFiles(innerFile, recursive, onlyDirectory));
123                     }
124                 }
125             }
126         }
127         return collection;
128     }
129
130     /**
131      * Gets comma saperated list.
132      *
133      * @param list the list
134      * @return the comma separated list
135      */
136     public static String getCommaSeparatedList(List list) {
137         return ((Stream<String>) list.stream().filter(o -> o != null && !o.toString().trim().isEmpty()).map(o -> o.toString().trim())).collect(Collectors.joining(","));
138     }
139
140     /**
141      * Gets comma saperated list.
142      *
143      * @param list the list
144      * @return the comma saperated list
145      */
146     public static String getCommaSeparatedList(String[] list) {
147         return getCommaSeparatedList(list == null ? Arrays.asList() : Arrays.asList(list));
148     }
149
150     /**
151      * Gets config type.
152      *
153      * @param url the url
154      * @return the config type
155      */
156     public static ConfigurationType getConfigType(URL url) {
157         return Enum.valueOf(ConfigurationType.class,
158                 url.getFile().substring(url.getFile().lastIndexOf('.') + 1).toUpperCase());
159     }
160
161     /**
162      * Gets config type.
163      *
164      * @param file the file
165      * @return the config type
166      */
167     public static ConfigurationType getConfigType(File file) {
168         return Enum.valueOf(ConfigurationType.class,
169                 file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf('.') + 1)
170                         .toUpperCase());
171     }
172
173     /**
174      * Is config boolean.
175      *
176      * @param url the url
177      * @return the boolean
178      */
179     public static boolean isConfig(URL url) {
180         return isConfig(url.getFile());
181     }
182
183     /**
184      * Is config boolean.
185      *
186      * @param file the file
187      * @return the boolean
188      */
189     public static boolean isConfig(File file) {
190         return file != null && file.exists() && isConfig(file.getName());
191     }
192
193     /**
194      * Is config boolean.
195      *
196      * @param file the file
197      * @return the boolean
198      */
199     public static boolean isConfig(String file) {
200         file = file.toUpperCase().substring(file.lastIndexOf('!') + 1);
201         file = file.substring(file.lastIndexOf('/') + 1);
202         return file.matches(
203                 "CONFIG(-\\w*){0,1}(-" + "(" + ConfigurationMode.OVERRIDE + "|" + ConfigurationMode.MERGE
204                         + "|" + ConfigurationMode.UNION + ")){0,1}" + "\\.("
205                         + ConfigurationType.PROPERTIES.name() + "|" + ConfigurationType.XML.name() + "|"
206                         + ConfigurationType.JSON.name() + "|" + ConfigurationType.YAML.name() + ")$")
207                 || file.matches("CONFIG(.)*\\.(" + ConfigurationType.PROPERTIES.name() + "|"
208                 + ConfigurationType.XML.name() + "|" + ConfigurationType.JSON.name() + "|"
209                 + ConfigurationType.YAML.name() + ")$");
210     }
211
212     /**
213      * Gets namespace.
214      *
215      * @param url the url
216      * @return the namespace
217      */
218     public static String getNamespace(URL url) {
219         String namespace = getNamespace(getConfiguration(url));
220         if (namespace != null) {
221             return namespace.toUpperCase();
222         }
223         return getNamespace(url.getFile().toUpperCase());
224     }
225
226     /**
227      * Gets namespace.
228      *
229      * @param file the file
230      * @return the namespace
231      */
232     public static String getNamespace(File file) {
233         String namespace = getNamespace(getConfiguration(file));
234         if (namespace != null) {
235             return namespace.toUpperCase();
236         }
237         return getNamespace(file.getName().toUpperCase());
238     }
239
240     private static String getNamespace(Configuration config) {
241         return config.getString(Constants.NAMESPACE_KEY) == null ? null
242                 : config.getString(Constants.NAMESPACE_KEY).toUpperCase();
243     }
244
245     /**
246      * Gets namespace.
247      *
248      * @param file the file
249      * @return the namespace
250      */
251     public static String getNamespace(String file) {
252         file = file.toUpperCase().substring(file.lastIndexOf('!') + 1);
253         file = file.substring(file.lastIndexOf('/') + 1);
254         Pattern pattern = Pattern.compile(
255                 "CONFIG(-\\w*){0,1}(-" + "(" + ConfigurationMode.OVERRIDE + "|" + ConfigurationMode.MERGE
256                         + "|" + ConfigurationMode.UNION + ")){0,1}" + "\\.("
257                         + ConfigurationType.PROPERTIES.name() + "|" + ConfigurationType.XML.name() + "|"
258                         + ConfigurationType.JSON.name() + "|" + ConfigurationType.YAML.name() + ")$");
259         Matcher matcher = pattern.matcher(file);
260         boolean b1 = matcher.matches();
261         if (b1) {
262             if (matcher.group(1) != null) {
263                 String moduleName = matcher.group(1).substring(1);
264                 return moduleName.equalsIgnoreCase(ConfigurationMode.OVERRIDE.name())
265                         || moduleName.equalsIgnoreCase(ConfigurationMode.UNION.name())
266                         || moduleName.equalsIgnoreCase(ConfigurationMode.MERGE.name())
267                         ? Constants.DEFAULT_NAMESPACE : moduleName;
268             } else {
269                 return Constants.DEFAULT_NAMESPACE;
270             }
271         } else if (isConfig(file)) {
272             return Constants.DEFAULT_NAMESPACE;
273         }
274
275         return null;
276     }
277
278     /**
279      * Gets merge strategy.
280      *
281      * @param url the url
282      * @return the merge strategy
283      */
284     public static ConfigurationMode getMergeStrategy(URL url) {
285         String configMode = getMergeStrategy(getConfiguration(url));
286         if (configMode != null) {
287             try {
288                 return Enum.valueOf(ConfigurationMode.class, configMode);
289             } catch (Exception exception) {
290                 //do nothing
291             }
292         }
293         return getMergeStrategy(url.getFile().toUpperCase());
294     }
295
296     private static String getMergeStrategy(Configuration config) {
297         return config.getString(Constants.MODE_KEY) == null ? null
298                 : config.getString(Constants.MODE_KEY).toUpperCase();
299     }
300
301     /**
302      * Gets merge strategy.
303      *
304      * @param file the file
305      * @return the merge strategy
306      */
307     public static ConfigurationMode getMergeStrategy(File file) {
308         String configMode = getMergeStrategy(getConfiguration(file));
309         if (configMode != null) {
310             try {
311                 return Enum.valueOf(ConfigurationMode.class, configMode);
312             } catch (Exception exception) {
313                 //do nothing
314             }
315         }
316         return getMergeStrategy(file.getName().toUpperCase());
317     }
318
319     /**
320      * Gets merge strategy.
321      *
322      * @param file the file
323      * @return the merge strategy
324      */
325     public static ConfigurationMode getMergeStrategy(String file) {
326         file = file.toUpperCase().substring(file.lastIndexOf('!') + 1);
327         file = file.substring(file.lastIndexOf('/') + 1);
328         Pattern pattern = Pattern.compile(
329                 "CONFIG(-\\w*){0,1}(-" + "(" + ConfigurationMode.OVERRIDE + "|" + ConfigurationMode.MERGE
330                         + "|" + ConfigurationMode.UNION + ")){0,1}" + "\\.("
331                         + ConfigurationType.PROPERTIES.name() + "|" + ConfigurationType.XML.name() + "|"
332                         + ConfigurationType.JSON.name() + "|" + ConfigurationType.YAML.name() + ")$");
333         Matcher matcher = pattern.matcher(file);
334         boolean b1 = matcher.matches();
335         if (b1) {
336             for (int i = 1; i <= matcher.groupCount(); i++) {
337                 String modeName = matcher.group(i);
338                 if (modeName != null) {
339                     modeName = modeName.substring(1);
340                 }
341                 try {
342                     return Enum.valueOf(ConfigurationMode.class, modeName);
343                 } catch (Exception exception) {
344                     //do nothing
345                 }
346             }
347         }
348
349         return null;
350     }
351
352     /**
353      * Gets configuration.
354      *
355      * @param url the url
356      * @return the configuration
357      */
358     public static FileBasedConfiguration getConfiguration(URL url) {
359         FileBasedConfiguration builder = null;
360         try {
361             ConfigurationType configType = ConfigurationUtils.getConfigType(url);
362             switch (configType) {
363                 case PROPERTIES:
364                     builder = new Configurations().fileBased(PropertiesConfiguration.class, url);
365                     break;
366                 case XML:
367                     builder = new Configurations().fileBased(XMLConfiguration.class, url);
368                     break;
369                 case JSON:
370                     builder = new Configurations().fileBased(JsonConfiguration.class, url);
371                     break;
372                 case YAML:
373                     builder = new Configurations().fileBased(YamlConfiguration.class, url);
374                     break;
375                 default:
376                     throw new ConfigurationException("Configuration type not supported:"+ configType);
377             }
378         } catch (ConfigurationException exception) {
379             exception.printStackTrace();
380         }
381         return builder;
382     }
383
384     /**
385      * Gets configuration.
386      *
387      * @param file the file
388      * @return the configuration
389      */
390     public static FileBasedConfiguration getConfiguration(File file) {
391         FileBasedConfiguration builder = null;
392         try {
393             ConfigurationType configType = ConfigurationUtils.getConfigType(file);
394             switch (configType) {
395                 case PROPERTIES:
396                     builder = new Configurations().fileBased(PropertiesConfiguration.class, file);
397                     break;
398                 case XML:
399                     builder = new Configurations().fileBased(XMLConfiguration.class, file);
400                     break;
401                 case JSON:
402                     builder = new Configurations().fileBased(JsonConfiguration.class, file);
403                     break;
404                 case YAML:
405                     builder = new Configurations().fileBased(YamlConfiguration.class, file);
406                     break;
407                 default:
408                     throw new ConfigurationException("Configuration type not supported:"+ configType);
409             }
410         } catch (ConfigurationException exception) {
411             exception.printStackTrace();
412         }
413         return builder;
414     }
415
416     /**
417      * Gets collection generic type.
418      *
419      * @param field the field
420      * @return the collection generic type
421      */
422     public static Class getCollectionGenericType(Field field) {
423         Type type = field.getGenericType();
424
425         if (type instanceof ParameterizedType) {
426
427             ParameterizedType paramType = (ParameterizedType) type;
428             Type[] arr = paramType.getActualTypeArguments();
429
430             for (Type tp : arr) {
431                 Class<?> clzz = (Class<?>) tp;
432                 if (isWrapperClass(clzz)) {
433                     return clzz;
434                 } else {
435                     throw new RuntimeException("Collection of type " + clzz.getName() + " not supported.");
436                 }
437             }
438         }
439         return String[].class;
440     }
441
442
443
444     /**
445      * Gets array class.
446      *
447      * @param clazz the clazz
448      * @return the array class
449      */
450     public static Class getArrayClass(Class clazz) {
451         return arrayClassMap.getOrDefault(clazz, null);
452     }
453
454     /**
455      * Gets all class path resources.
456      *
457      * @return the all class path resources
458      */
459     public static List<URL> getAllClassPathResources() {
460         return CPScanner.scanResources(new ResourceFilter());
461     }
462
463     /**
464      * Execute ddlsql boolean.
465      *
466      * @param sql the sql
467      * @return the boolean
468      * @throws Exception the exception
469      */
470     public static boolean executeDdlSql(String sql) throws Exception {
471         DataSource datasource = ConfigurationDataSource.lookup();
472         if (datasource == null) {
473             System.err.println("DB configuration not found. Configuration management will be using "
474                     + "in-memory persistence.");
475             return false;
476         }
477         try (Connection con = datasource.getConnection(); Statement stmt = con.createStatement()) {
478             stmt.executeQuery(sql);
479         } catch (Exception exception) {
480             System.err.println("Datasource initialization error. Configuration management will be using in-memory persistence.");
481             return false;
482         }
483         return true;
484     }
485
486     /**
487      * Gets configuration builder.
488      *
489      * @param url the url
490      * @return the configuration builder
491      */
492     public static BasicConfigurationBuilder<FileBasedConfiguration> getConfigurationBuilder(URL url) {
493         ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder = null;
494         ConfigurationType configType = ConfigurationUtils.getConfigType(url);
495         switch (configType) {
496             case PROPERTIES:
497                 builder = new ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration>(
498                         PropertiesConfiguration.class);
499                 break;
500             case XML:
501                 builder = new ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration>(
502                         XMLConfiguration.class);
503                 break;
504             case JSON:
505                 builder = new ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration>(
506                         JsonConfiguration.class);
507                 break;
508             case YAML:
509                 builder = new ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration>(
510                         YamlConfiguration.class);
511                 break;
512             default:
513                 throw new IllegalArgumentException("Configuration type not supported:"+ configType);
514         }
515         builder.configure(new Parameters().fileBased().setURL(url)
516                 .setListDelimiterHandler(new DefaultListDelimiterHandler(',')));
517         return builder;
518     }
519
520     /**
521      * Gets configuration builder.
522      *
523      * @param file     the file
524      * @param autoSave the auto save
525      * @return the configuration builder
526      */
527     public static BasicConfigurationBuilder<FileBasedConfiguration> getConfigurationBuilder(File file,
528                                                                                             boolean autoSave) {
529         ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder = null;
530         ConfigurationType configType = ConfigurationUtils.getConfigType(file);
531         switch (configType) {
532             case PROPERTIES:
533                 builder = new ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration>(
534                         PropertiesConfiguration.class);
535                 break;
536             case XML:
537                 builder = new ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration>(
538                         XMLConfiguration.class);
539                 break;
540             case JSON:
541                 builder = new ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration>(
542                         JsonConfiguration.class);
543                 break;
544             case YAML:
545                 builder = new ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration>(
546                         YamlConfiguration.class);
547                 break;
548             default:
549                 throw new IllegalArgumentException("Configuration type not supported:"+ configType);
550         }
551         builder.configure(new Parameters().fileBased().setFile(file)
552                 .setListDelimiterHandler(new DefaultListDelimiterHandler(',')));
553         builder.setAutoSave(autoSave);
554         return builder;
555     }
556
557
558     /**
559      * Execute select sql collection.
560      *
561      * @param sql    the sql
562      * @param params the params
563      * @return the collection
564      * @throws Exception the exception
565      */
566     public static Collection<String> executeSelectSql(String sql, String[] params) throws Exception {
567         Collection<String> coll = new ArrayList<>();
568         DataSource datasource = ConfigurationDataSource.lookup();
569         try (Connection con = datasource.getConnection();
570              PreparedStatement stmt = con.prepareStatement(sql)) {
571             if (params != null) {
572                 for (int i = 0; i < params.length; i++) {
573                     stmt.setString(i + 1, params[i]);
574                 }
575             }
576
577             try (ResultSet rs = stmt.executeQuery()) {
578
579                 while (rs.next()) {
580                     coll.add(rs.getString(1));
581                 }
582             }
583
584         } catch (Exception exception) {
585             //exception.printStackTrace();
586             return null;
587         }
588
589         return coll;
590     }
591
592     /**
593      * Execute insert sql boolean.
594      *
595      * @param sql    the sql
596      * @param params the params
597      * @return the boolean
598      * @throws Exception the exception
599      */
600     public static boolean executeInsertSql(String sql, Object[] params) throws Exception {
601         Collection<String> coll = new ArrayList<>();
602         DataSource datasource = ConfigurationDataSource.lookup();
603         try (Connection con = datasource.getConnection();
604              PreparedStatement stmt = con.prepareStatement(sql)) {
605             if (params != null) {
606                 int counter = 0;
607                 for (Object obj : params) {
608                     if (obj == null) {
609                         obj = "";
610                     }
611                     switch (obj.getClass().getName()) {
612                         case "java.lang.String":
613                             stmt.setString(++counter, obj.toString());
614                             break;
615                         case "java.lang.Integer":
616                             stmt.setInt(++counter, ((Integer) obj).intValue());
617                             break;
618                         case "java.lang.Long":
619                             stmt.setLong(++counter, ((Long) obj).longValue());
620                             break;
621                         default:
622                             stmt.setString(++counter, obj.toString());
623                             break;
624                     }
625                 }
626             }
627             stmt.executeUpdate();
628             return true;
629         } catch (Exception exception) {
630             exception.printStackTrace();
631         }
632         return false;
633     }
634
635     /**
636      * Read t.
637      *
638      * @param <T>       the type parameter
639      * @param config    the config
640      * @param clazz     the clazz
641      * @param keyPrefix the key prefix
642      * @return the t
643      * @throws Exception the exception
644      */
645     public static <T> T read(Configuration config, Class<T> clazz, String keyPrefix)
646             throws Exception {
647         org.openecomp.config.api.Config confAnnot =
648                 clazz.getAnnotation(org.openecomp.config.api.Config.class);
649         if (confAnnot != null) {
650             keyPrefix += (confAnnot.key() + ".");
651         }
652         T objToReturn = clazz.newInstance();
653         for (Field field : clazz.getDeclaredFields()) {
654             org.openecomp.config.api.Config fieldConfAnnot =
655                     field.getAnnotation(org.openecomp.config.api.Config.class);
656             if (fieldConfAnnot != null) {
657                 field.setAccessible(true);
658                 field.set(objToReturn, config.getProperty(keyPrefix + fieldConfAnnot.key()));
659             } else if (field.getType().getAnnotation(org.openecomp.config.api.Config.class) != null) {
660                 field.set(objToReturn, read(config, field.getType(), keyPrefix));
661             }
662         }
663         return objToReturn;
664     }
665
666     /**
667      * Gets db configuration builder.
668      *
669      * @param configName the config name
670      * @return the db configuration builder
671      * @throws Exception the exception
672      */
673     public static BasicConfigurationBuilder<AgglomerateConfiguration> getDbConfigurationBuilder(
674             String configName) throws Exception {
675         Configuration dbConfig = ConfigurationRepository.lookup()
676                 .getConfigurationFor(Constants.DEFAULT_TENANT, Constants.DB_NAMESPACE);
677         BasicConfigurationBuilder<AgglomerateConfiguration> builder =
678                 new BasicConfigurationBuilder<AgglomerateConfiguration>(AgglomerateConfiguration.class);
679         builder.configure(
680                 new Parameters().database()
681                         .setDataSource(ConfigurationDataSource.lookup())
682                         .setTable(dbConfig.getString("config.Table"))
683                         .setKeyColumn(dbConfig.getString("configKey"))
684                         .setValueColumn(dbConfig.getString("configValue"))
685                         .setConfigurationNameColumn(dbConfig.getString("configNameColumn"))
686                         .setConfigurationName(configName)
687                         .setAutoCommit(true)
688         );
689         return builder;
690     }
691
692     /**
693      * Gets property.
694      *
695      * @param config          the config
696      * @param key             the key
697      * @param processingHints the processing hints
698      * @return the property
699      */
700     public static Object getProperty(Configuration config, String key, int processingHints) {
701         if (!isDirectLookup(processingHints)) {
702             if (config instanceof AgglomerateConfiguration) {
703                 return ((AgglomerateConfiguration) config).getPropertyValue(key);
704             } else if (config instanceof CompositeConfiguration) {
705                 CompositeConfiguration conf = (CompositeConfiguration) config;
706                 for (int i = 0; i < conf.getNumberOfConfigurations(); i++) {
707                     if (conf.getConfiguration(i) instanceof AgglomerateConfiguration) {
708                         return ((AgglomerateConfiguration) conf.getConfiguration(i)).getPropertyValue(key);
709                     } else if (isNodeSpecific(processingHints)) {
710                         Object obj = conf.getConfiguration(i).getProperty(key);
711                         if (obj != null) {
712                             return obj;
713                         }
714                     }
715                 }
716             }
717         }
718         return config.getProperty(key);
719     }
720
721     /**
722      * Gets primitive array.
723      *
724      * @param collection the collection
725      * @param clazz      the clazz
726      * @return the primitive array
727      */
728     public static Object getPrimitiveArray(Collection collection, Class clazz) {
729         if (clazz == int.class) {
730             int[] array = new int[collection.size()];
731             Object[] objArray = collection.toArray();
732             for (int i = 0; i < collection.size(); i++) {
733                 array[i] = (int) objArray[i];
734             }
735             return array;
736         }
737         if (clazz == byte.class) {
738             byte[] array = new byte[collection.size()];
739             Object[] objArray = collection.toArray();
740             for (int i = 0; i < collection.size(); i++) {
741                 array[i] = (byte) objArray[i];
742             }
743             return array;
744         }
745         if (clazz == short.class) {
746             short[] array = new short[collection.size()];
747             Object[] objArray = collection.toArray();
748             for (int i = 0; i < collection.size(); i++) {
749                 array[i] = (short) objArray[i];
750             }
751             return array;
752         }
753         if (clazz == long.class) {
754             long[] array = new long[collection.size()];
755             Object[] objArray = collection.toArray();
756             for (int i = 0; i < collection.size(); i++) {
757                 array[i] = (long) objArray[i];
758             }
759             return array;
760         }
761         if (clazz == float.class) {
762             float[] array = new float[collection.size()];
763             Object[] objArray = collection.toArray();
764             for (int i = 0; i < collection.size(); i++) {
765                 array[i] = (float) objArray[i];
766             }
767             return array;
768         }
769         if (clazz == double.class) {
770             double[] array = new double[collection.size()];
771             Object[] objArray = collection.toArray();
772             for (int i = 0; i < collection.size(); i++) {
773                 array[i] = (double) objArray[i];
774             }
775             return array;
776         }
777         if (clazz == boolean.class) {
778             boolean[] array = new boolean[collection.size()];
779             Object[] objArray = collection.toArray();
780             for (int i = 0; i < collection.size(); i++) {
781                 array[i] = (boolean) objArray[i];
782             }
783             return array;
784         }
785         Object obj = null;
786         return obj;
787     }
788
789     /**
790      * Is wrapper class boolean.
791      *
792      * @param clazz the clazz
793      * @return the boolean
794      */
795     public static boolean isWrapperClass(Class clazz) {
796         return clazz == String.class || clazz == Boolean.class || clazz == Character.class
797                 || Number.class.isAssignableFrom(clazz);
798     }
799
800     /**
801      * Gets collection string.
802      *
803      * @param input the input
804      * @return the collection string
805      */
806     public static String getCollectionString(String input) {
807         Pattern pattern = Pattern.compile("^\\[(.*)\\]$");
808         Matcher matcher = pattern.matcher(input);
809         if (matcher.matches()) {
810             input = matcher.group(1);
811         }
812         return input;
813     }
814
815     /**
816      * Is collection boolean.
817      *
818      * @param input the input
819      * @return the boolean
820      */
821     public static boolean isCollection(String input) {
822         Pattern pattern = Pattern.compile("^\\[(.*)\\]$");
823         Matcher matcher = pattern.matcher(input);
824         return matcher.matches();
825     }
826
827     /**
828      * Process variables if present string.
829      *
830      * @param tenant    the tenant
831      * @param namespace the namespace
832      * @param data      the data
833      * @return the string
834      */
835     public static String processVariablesIfPresent(String tenant, String namespace, String data) {
836         Pattern pattern = Pattern.compile("^.*\\$\\{(.*)\\}.*");
837         Matcher matcher = pattern.matcher(data);
838         if (matcher.matches()) {
839             String key = matcher.group(1);
840             if (key.toUpperCase().startsWith("ENV:")) {
841                 String envValue = System.getenv(key.substring(4));
842                 return processVariablesIfPresent(tenant, namespace, data.replaceAll("\\$\\{" + key + "\\}",
843                         envValue == null ? "" : envValue.replace("\\", "\\\\")));
844             } else if (key.toUpperCase().startsWith("SYS:")) {
845                 String sysValue = System.getProperty(key.substring(4));
846                 return processVariablesIfPresent(tenant, namespace, data.replaceAll("\\$\\{" + key + "\\}",
847                         sysValue == null ? "" : sysValue.replace("\\", "\\\\")));
848             } else {
849                 String propertyValue = ConfigurationUtils.getCollectionString(
850                         ConfigurationManager.lookup().getAsStringValues(tenant, namespace, key).toString());
851                 return processVariablesIfPresent(tenant, namespace, data.replaceAll("\\$\\{" + key + "\\}",
852                         propertyValue == null ? "" : propertyValue.replace("\\", "\\\\")));
853             }
854         } else {
855             return data;
856         }
857     }
858
859     /**
860      * Gets file contents.
861      *
862      * @param path the path
863      * @return the file contents
864      */
865     public static String getFileContents(String path) {
866         try {
867             if (path != null) {
868                 return IOUtils.toString(new URL(path));
869             }
870         } catch (Exception exception) {
871             exception.printStackTrace();
872         }
873         return null;
874     }
875
876     /**
877      * Gets file contents.
878      *
879      * @param path the path
880      * @return the file contents
881      */
882     public static String getFileContents(Path path) {
883         try {
884             if (path != null) {
885                 return new String(Files.readAllBytes(path));
886             }
887         } catch (Exception exception) {
888             exception.printStackTrace();
889         }
890         return null;
891     }
892
893     /**
894      * Gets concrete collection.
895      *
896      * @param clazz the clazz
897      * @return the concrete collection
898      */
899     public static Collection getConcreteCollection(Class clazz) {
900         switch (clazz.getName()) {
901             case "java.util.Collection":
902             case "java.util.List":
903                 return new ArrayList<>();
904             case "java.util.Set":
905                 return new HashSet<>();
906             case "java.util.SortedSet":
907                 return new TreeSet<>();
908             case "java.util.Queue":
909                 return new ConcurrentLinkedQueue<>();
910             case "java.util.Deque":
911                 return new ArrayDeque<>();
912             case "java.util.concurrent.TransferQueue":
913                 return new LinkedTransferQueue<>();
914             case "java.util.concurrent.BlockingQueue":
915                 return new LinkedBlockingQueue<>();
916             default:
917                 return null;
918         }
919     }
920
921     /**
922      * Gets default for.
923      *
924      * @param clazz the clazz
925      * @return the default for
926      */
927     public static Object getDefaultFor(Class clazz) {
928         if (byte.class == clazz) {
929             return new Byte("0");
930         } else if (short.class == clazz) {
931             return new Short("0");
932         } else if (int.class == clazz) {
933             return new Integer("0");
934         } else if (float.class == clazz) {
935             return new Float("0");
936         } else if (long.class == clazz) {
937             return new Long("0");
938         } else if (double.class == clazz) {
939             return new Double("0");
940         } else if (boolean.class == clazz) {
941             return Boolean.FALSE;
942         }
943         return new Character((char) 0);
944     }
945
946     /**
947      * Gets compatible collection for abstract def.
948      *
949      * @param clazz the clazz
950      * @return the compatible collection for abstract def
951      */
952     public static Collection getCompatibleCollectionForAbstractDef(Class clazz) {
953         if (BlockingQueue.class.isAssignableFrom(clazz)) {
954             return getConcreteCollection(BlockingQueue.class);
955         }
956         if (TransferQueue.class.isAssignableFrom(clazz)) {
957             return getConcreteCollection(TransferQueue.class);
958         }
959         if (Deque.class.isAssignableFrom(clazz)) {
960             return getConcreteCollection(Deque.class);
961         }
962         if (Queue.class.isAssignableFrom(clazz)) {
963             return getConcreteCollection(Queue.class);
964         }
965         if (SortedSet.class.isAssignableFrom(clazz)) {
966             return getConcreteCollection(SortedSet.class);
967         }
968         if (Set.class.isAssignableFrom(clazz)) {
969             return getConcreteCollection(Set.class);
970         }
971         if (List.class.isAssignableFrom(clazz)) {
972             return getConcreteCollection(List.class);
973         }
974         return null;
975     }
976
977     /**
978      * Gets configuration repository key.
979      *
980      * @param array the array
981      * @return the configuration repository key
982      */
983     public static String getConfigurationRepositoryKey(String[] array) {
984         Deque<String> stack = new ArrayDeque<>();
985         stack.push(Constants.DEFAULT_TENANT);
986         for (String element : array) {
987             stack.push(element);
988         }
989         String toReturn = stack.pop();
990         return stack.pop() + Constants.KEY_ELEMENTS_DELEMETER + toReturn;
991     }
992
993     /**
994      * Gets configuration repository key.
995      *
996      * @param file the file
997      * @return the configuration repository key
998      */
999     public static String getConfigurationRepositoryKey(File file) {
1000         return getConfigurationRepositoryKey(
1001                 ConfigurationUtils.getNamespace(file).split(Constants.TENANT_NAMESPACE_SAPERATOR));
1002     }
1003
1004     /**
1005      * Gets configuration repository key.
1006      *
1007      * @param url the url
1008      * @return the configuration repository key
1009      */
1010     public static String getConfigurationRepositoryKey(URL url) {
1011         return getConfigurationRepositoryKey(
1012                 ConfigurationUtils.getNamespace(url).split(Constants.TENANT_NAMESPACE_SAPERATOR));
1013     }
1014
1015     /**
1016      * To map linked hash map.
1017      *
1018      * @param config the config
1019      * @return the linked hash map
1020      */
1021     public static LinkedHashMap toMap(Configuration config) {
1022         Iterator<String> iterator = config.getKeys();
1023         LinkedHashMap<String, String> map = new LinkedHashMap<>();
1024         while (iterator.hasNext()) {
1025             String key = iterator.next();
1026             if (!(key.equals(Constants.MODE_KEY) || key.equals(Constants.NAMESPACE_KEY)
1027                     || key.equals(Constants.LOAD_ORDER_KEY))) {
1028                 map.put(key, config.getProperty(key).toString());
1029             }
1030         }
1031
1032         return map;
1033     }
1034
1035     /**
1036      * Diff map.
1037      *
1038      * @param orig   the orig
1039      * @param latest the latest
1040      * @return the map
1041      */
1042     public static Map diff(LinkedHashMap orig, LinkedHashMap latest) {
1043         orig = new LinkedHashMap<>(orig);
1044         latest = new LinkedHashMap<>(latest);
1045         List<String> set = new ArrayList(orig.keySet());
1046         for (String key : set) {
1047             if (latest.remove(key, orig.get(key))) {
1048                 orig.remove(key);
1049             }
1050         }
1051         Set<String> keys = latest.keySet();
1052         for (String key : keys) {
1053             orig.remove(key);
1054         }
1055         set = new ArrayList(orig.keySet());
1056         for (String key : set) {
1057             latest.put(key, "");
1058         }
1059         return new HashMap<>(latest);
1060     }
1061
1062     /**
1063      * Is array boolean.
1064      *
1065      * @param tenant          the tenant
1066      * @param namespace       the namespace
1067      * @param key             the key
1068      * @param processingHints the processing hints
1069      * @return the boolean
1070      * @throws Exception the exception
1071      */
1072     public static boolean isArray(String tenant, String namespace, String key, int processingHints)
1073             throws Exception {
1074         Object obj = ConfigurationUtils
1075                 .getProperty(ConfigurationRepository.lookup().getConfigurationFor(tenant, namespace), key,
1076                         processingHints);
1077         return (obj == null) ? false : ConfigurationUtils.isCollection(obj.toString());
1078     }
1079
1080     /**
1081      * Is direct lookup boolean.
1082      *
1083      * @param hints the hints
1084      * @return the boolean
1085      */
1086     public static boolean isDirectLookup(int hints) {
1087         return (hints & LATEST_LOOKUP.value()) == LATEST_LOOKUP.value();
1088     }
1089
1090     /**
1091      * Is external lookup boolean.
1092      *
1093      * @param hints the hints
1094      * @return the boolean
1095      */
1096     public static boolean isExternalLookup(int hints) {
1097         return (hints & EXTERNAL_LOOKUP.value()) == EXTERNAL_LOOKUP.value();
1098     }
1099
1100     /**
1101      * Is node specific boolean.
1102      *
1103      * @param hints the hints
1104      * @return the boolean
1105      */
1106     public static boolean isNodeSpecific(int hints) {
1107         return (hints & NODE_SPECIFIC.value()) == NODE_SPECIFIC.value();
1108     }
1109
1110     public static boolean isZeroLengthArray(Class clazz, Object obj) {
1111         if (clazz.isArray() && clazz.getComponentType().isPrimitive()) {
1112             if (clazz.getComponentType() == int.class) {
1113                 return ((int[]) obj).length == 0;
1114             } else if (clazz.getComponentType() == byte.class) {
1115                 return ((byte[]) obj).length == 0;
1116             } else if (clazz.getComponentType() == short.class) {
1117                 return ((short[]) obj).length == 0;
1118             } else if (clazz.getComponentType() == float.class) {
1119                 return ((float[]) obj).length == 0;
1120             } else if (clazz.getComponentType() == boolean.class) {
1121                 return ((boolean[]) obj).length == 0;
1122             } else if (clazz.getComponentType() == double.class) {
1123                 return ((double[]) obj).length == 0;
1124             } else if (clazz.getComponentType() == long.class) {
1125                 return ((long[]) obj).length == 0;
1126             } else {
1127                 return ((Object[]) obj).length == 0;
1128             }
1129         }
1130
1131         return false;
1132     }
1133
1134     /**
1135      * Checks if value is blank
1136      *
1137      * @param value
1138      * @return
1139      */
1140     public static boolean isBlank(String value) {
1141         return value == null || value.trim().length() == 0;
1142     }
1143 }