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