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