2 * Copyright © 2016-2018 European Support Limited
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.onap.config;
19 import static java.util.Optional.ofNullable;
20 import static org.onap.config.api.Hint.EXTERNAL_LOOKUP;
21 import static org.onap.config.api.Hint.LATEST_LOOKUP;
22 import static org.onap.config.api.Hint.NODE_SPECIFIC;
24 import com.virtlink.commons.configuration2.jackson.JsonConfiguration;
26 import java.lang.reflect.Field;
27 import java.lang.reflect.ParameterizedType;
28 import java.lang.reflect.Type;
29 import java.net.MalformedURLException;
31 import java.nio.file.Files;
32 import java.nio.file.Path;
33 import java.util.ArrayDeque;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.Deque;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.List;
43 import java.util.Objects;
44 import java.util.Optional;
45 import java.util.Queue;
47 import java.util.SortedSet;
48 import java.util.TreeSet;
49 import java.util.concurrent.BlockingQueue;
50 import java.util.concurrent.ConcurrentLinkedQueue;
51 import java.util.concurrent.LinkedBlockingQueue;
52 import java.util.concurrent.LinkedTransferQueue;
53 import java.util.concurrent.TransferQueue;
54 import java.util.regex.Matcher;
55 import java.util.regex.Pattern;
56 import java.util.stream.Collectors;
57 import net.sf.corn.cps.CPScanner;
58 import net.sf.corn.cps.ResourceFilter;
59 import org.apache.commons.configuration2.CompositeConfiguration;
60 import org.apache.commons.configuration2.Configuration;
61 import org.apache.commons.configuration2.FileBasedConfiguration;
62 import org.apache.commons.configuration2.PropertiesConfiguration;
63 import org.apache.commons.configuration2.XMLConfiguration;
64 import org.apache.commons.configuration2.builder.BasicConfigurationBuilder;
65 import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
66 import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
67 import org.apache.commons.configuration2.builder.fluent.Configurations;
68 import org.apache.commons.configuration2.builder.fluent.Parameters;
69 import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
70 import org.apache.commons.configuration2.ex.ConfigurationException;
71 import org.apache.commons.io.IOUtils;
72 import org.onap.config.api.Config;
73 import org.onap.config.api.ConfigurationManager;
74 import org.onap.config.impl.YamlConfiguration;
75 import org.onap.config.type.ConfigurationMode;
76 import org.onap.config.type.ConfigurationType;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
80 public class ConfigurationUtils {
82 private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationUtils.class);
84 private static final String CONFIGURATION_TYPE_NOT_SUPPORTED = "Configuration type not supported:";
86 private static final Map<Class, Class> ARRAY_CLASS_MAP;
89 Map<Class, Class> arrayTypes = new HashMap<>();
90 arrayTypes.put(Byte.class, Byte[].class);
91 arrayTypes.put(Short.class, Short[].class);
92 arrayTypes.put(Integer.class, Integer[].class);
93 arrayTypes.put(Long.class, Long[].class);
94 arrayTypes.put(Float.class, Float[].class);
95 arrayTypes.put(Double.class, Double[].class);
96 arrayTypes.put(Boolean.class, Boolean[].class);
97 arrayTypes.put(Character.class, Character[].class);
98 arrayTypes.put(String.class, String[].class);
99 ARRAY_CLASS_MAP = Collections.unmodifiableMap(arrayTypes);
102 private ConfigurationUtils() {
103 // prevent instantiation
106 public static Collection<File> getAllFiles(File file, boolean recursive, boolean onlyDirectory) {
108 ArrayList<File> collection = new ArrayList<>();
109 if (file.isDirectory() && file.exists()) {
110 File[] files = file.listFiles();
111 for (File innerFile : files) {
112 if (innerFile.isFile() && !onlyDirectory) {
113 collection.add(innerFile);
114 } else if (innerFile.isDirectory()) {
115 collection.add(innerFile);
117 collection.addAll(getAllFiles(innerFile, true, onlyDirectory));
125 public static String getCommaSeparatedList(String[] list) {
126 return (list == null) || (list.length == 0) ? "" : getCommaSeparatedList(Arrays.asList(list));
129 public static String getCommaSeparatedList(List<?> list) {
131 if ((list == null) || list.isEmpty()) {
135 return list.stream().filter(o -> o != null && !o.toString().trim().isEmpty())
136 .map(o -> o.toString().trim()).collect(Collectors.joining(","));
139 public static boolean isConfig(URL url) {
140 return isConfig(url.getFile());
143 public static boolean isConfig(String file) {
144 file = file.toUpperCase().substring(file.lastIndexOf('!') + 1);
145 file = file.substring(file.lastIndexOf('/') + 1);
147 "CONFIG(-\\w*){0,1}(-" + "(" + ConfigurationMode.OVERRIDE + "|" + ConfigurationMode.MERGE + "|"
148 + ConfigurationMode.UNION + ")){0,1}" + "\\.(" + ConfigurationType.PROPERTIES.name() + "|"
149 + ConfigurationType.XML.name() + "|" + ConfigurationType.JSON.name() + "|"
150 + ConfigurationType.YAML.name() + ")$") || file.matches(
151 "CONFIG(.)*\\.(" + ConfigurationType.PROPERTIES.name() + "|" + ConfigurationType.XML.name() + "|"
152 + ConfigurationType.JSON.name() + "|" + ConfigurationType.YAML.name() + ")$");
155 public static boolean isConfig(File file) {
156 return file != null && file.exists() && isConfig(file.getName());
159 private static Optional<String> readNamespace(Configuration config) {
160 return ofNullable(config).flatMap(configuration -> ofNullable(configuration.getString(Constants.NAMESPACE_KEY)))
161 .map(String::toUpperCase);
164 private static Optional<String> readMergeStrategy(Configuration config) {
165 return ofNullable(config).flatMap(configuration -> ofNullable(configuration.getString(Constants.MODE_KEY)))
166 .map(String::toUpperCase);
169 public static ConfigurationMode getMergeStrategy(File file) {
170 Optional<ConfigurationMode> configurationMode =
171 getConfiguration(file).flatMap(ConfigurationUtils::readMergeStrategy)
172 .flatMap(ConfigurationUtils::convertConfigurationMode);
173 return configurationMode.orElseGet(() -> getMergeStrategy(file.getName().toUpperCase()));
176 public static ConfigurationMode getMergeStrategy(URL url) {
177 Optional<ConfigurationMode> configurationMode =
178 getConfiguration(url).flatMap(ConfigurationUtils::readMergeStrategy)
179 .flatMap(ConfigurationUtils::convertConfigurationMode);
180 return configurationMode.orElseGet(() -> getMergeStrategy(url.getFile().toUpperCase()));
183 public static ConfigurationMode getMergeStrategy(String file) {
185 file = file.toUpperCase().substring(file.lastIndexOf('!') + 1);
186 file = file.substring(file.lastIndexOf('/') + 1);
188 Pattern pattern = Pattern.compile(
189 "CONFIG(-\\w*){0,1}(-" + "(" + ConfigurationMode.OVERRIDE + "|" + ConfigurationMode.MERGE + "|"
190 + ConfigurationMode.UNION + ")){0,1}" + "\\.(" + ConfigurationType.PROPERTIES.name() + "|"
191 + ConfigurationType.XML.name() + "|" + ConfigurationType.JSON.name() + "|"
192 + ConfigurationType.YAML.name() + ")$");
193 Matcher matcher = pattern.matcher(file);
194 boolean b1 = matcher.matches();
196 for (int i = 1; i <= matcher.groupCount(); i++) {
197 String modeName = matcher.group(i);
198 if (modeName != null) {
199 modeName = modeName.substring(1);
202 return Enum.valueOf(ConfigurationMode.class, modeName);
203 } catch (Exception exception) {
212 public static Optional<FileBasedConfiguration> getConfiguration(URL url) {
216 ConfigurationType configType = ConfigurationUtils.getConfigType(url);
217 switch (configType) {
219 return Optional.of(new Configurations().fileBased(PropertiesConfiguration.class, url));
221 return Optional.of(new Configurations().fileBased(XMLConfiguration.class, url));
223 return Optional.of(new Configurations().fileBased(JsonConfiguration.class, url));
225 return Optional.of(new Configurations().fileBased(YamlConfiguration.class, url));
227 throw new ConfigurationException(CONFIGURATION_TYPE_NOT_SUPPORTED + configType);
229 } catch (ConfigurationException exception) {
230 exception.printStackTrace();
233 return Optional.empty();
236 public static Optional<FileBasedConfiguration> getConfiguration(File file) {
239 return getConfiguration(file.getAbsoluteFile().toURI().toURL());
240 } catch (MalformedURLException e) {
241 throw new IllegalStateException("Malformed URL: " + file.getAbsolutePath());
245 public static ConfigurationType getConfigType(File file) {
246 Objects.requireNonNull(file, "File cannot be null");
247 return Enum.valueOf(ConfigurationType.class,
248 file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf('.') + 1).toUpperCase());
251 public static ConfigurationType getConfigType(URL url) {
252 Objects.requireNonNull(url, "URL cannot be null");
253 return Enum.valueOf(ConfigurationType.class,
254 url.getFile().substring(url.getFile().lastIndexOf('.') + 1).toUpperCase());
257 private static Optional<ConfigurationMode> convertConfigurationMode(String configMode) {
258 ConfigurationMode configurationMode = null;
260 configurationMode = ConfigurationMode.valueOf(configMode);
261 } catch (Exception exception) {
262 LOGGER.error("Could not find convert {} into configuration mode", configMode);
264 return Optional.ofNullable(configurationMode);
267 public static Class getCollectionGenericType(Field field) {
268 Type type = field.getGenericType();
270 if (type instanceof ParameterizedType) {
272 ParameterizedType paramType = (ParameterizedType) type;
273 Type[] arr = paramType.getActualTypeArguments();
274 if (arr.length > 0) {
275 Class<?> clazz = (Class<?>) arr[0];
276 if (isWrapperClass(clazz)) {
279 throw new IllegalArgumentException("Collection of type " + clazz.getName() + " not supported.");
284 return String[].class;
287 public static boolean isWrapperClass(Class clazz) {
288 return clazz == String.class || clazz == Boolean.class || clazz == Character.class
289 || Number.class.isAssignableFrom(clazz);
292 public static Class getArrayClass(Class clazz) {
293 return ARRAY_CLASS_MAP.getOrDefault(clazz, null);
296 public static List<URL> getAllClassPathResources() {
297 return CPScanner.scanResources(new ResourceFilter());
300 public static BasicConfigurationBuilder<FileBasedConfiguration> getConfigurationBuilder(File file) {
301 FileBasedConfigurationBuilder<FileBasedConfiguration> builder;
302 ConfigurationType configType = ConfigurationUtils.getConfigType(file);
303 builder = getFileBasedConfigurationBuilder(configType);
304 builder.configure(new Parameters().fileBased().setFile(file)
305 .setListDelimiterHandler(new DefaultListDelimiterHandler(',')));
309 public static BasicConfigurationBuilder<FileBasedConfiguration> getConfigurationBuilder(URL url) {
310 ConfigurationType configType = ConfigurationUtils.getConfigType(url);
311 ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder =
312 getFileBasedConfigurationBuilder(configType);
314 new Parameters().fileBased().setURL(url).setListDelimiterHandler(new DefaultListDelimiterHandler(',')));
318 private static ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> getFileBasedConfigurationBuilder(
319 ConfigurationType configType) {
321 ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder;
322 switch (configType) {
324 builder = new ReloadingFileBasedConfigurationBuilder<>(PropertiesConfiguration.class);
327 builder = new ReloadingFileBasedConfigurationBuilder<>(XMLConfiguration.class);
330 builder = new ReloadingFileBasedConfigurationBuilder<>(JsonConfiguration.class);
333 builder = new ReloadingFileBasedConfigurationBuilder<>(YamlConfiguration.class);
336 throw new IllegalArgumentException(CONFIGURATION_TYPE_NOT_SUPPORTED + configType);
341 public static <T> T read(Configuration config, Class<T> clazz, String keyPrefix) throws Exception {
342 Config confAnnotation = clazz.getAnnotation(Config.class);
343 if (confAnnotation != null) {
344 keyPrefix += (confAnnotation.key() + ".");
346 T objToReturn = clazz.newInstance();
347 for (Field field : clazz.getDeclaredFields()) {
348 Config fieldAnnotation = field.getAnnotation(Config.class);
349 if (fieldAnnotation != null) {
350 field.setAccessible(true);
351 field.set(objToReturn, config.getProperty(keyPrefix + fieldAnnotation.key()));
352 } else if (field.getType().getAnnotation(Config.class) != null) {
353 field.set(objToReturn, read(config, field.getType(), keyPrefix));
359 public static Object getPrimitiveArray(Collection collection, Class clazz) {
360 if (clazz == int.class) {
361 int[] array = new int[collection.size()];
362 Object[] objArray = collection.toArray();
363 for (int i = 0; i < collection.size(); i++) {
364 array[i] = (int) objArray[i];
368 if (clazz == byte.class) {
369 byte[] array = new byte[collection.size()];
370 Object[] objArray = collection.toArray();
371 for (int i = 0; i < collection.size(); i++) {
372 array[i] = (byte) objArray[i];
376 if (clazz == short.class) {
377 short[] array = new short[collection.size()];
378 Object[] objArray = collection.toArray();
379 for (int i = 0; i < collection.size(); i++) {
380 array[i] = (short) objArray[i];
384 if (clazz == long.class) {
385 long[] array = new long[collection.size()];
386 Object[] objArray = collection.toArray();
387 for (int i = 0; i < collection.size(); i++) {
388 array[i] = (long) objArray[i];
392 if (clazz == float.class) {
393 float[] array = new float[collection.size()];
394 Object[] objArray = collection.toArray();
395 for (int i = 0; i < collection.size(); i++) {
396 array[i] = (float) objArray[i];
400 if (clazz == double.class) {
401 double[] array = new double[collection.size()];
402 Object[] objArray = collection.toArray();
403 for (int i = 0; i < collection.size(); i++) {
404 array[i] = (double) objArray[i];
408 if (clazz == boolean.class) {
409 boolean[] array = new boolean[collection.size()];
410 Object[] objArray = collection.toArray();
411 for (int i = 0; i < collection.size(); i++) {
412 array[i] = (boolean) objArray[i];
419 public static String getCollectionString(String input) {
420 Pattern pattern = Pattern.compile("^\\[(.*)\\]$");
421 Matcher matcher = pattern.matcher(input);
422 if (matcher.matches()) {
423 input = matcher.group(1);
428 public static String processVariablesIfPresent(String tenant, String namespace, String data) {
429 Pattern pattern = Pattern.compile("^.*\\$\\{(.*)\\}.*");
430 Matcher matcher = pattern.matcher(data);
431 if (matcher.matches()) {
432 String key = matcher.group(1);
433 if (key.toUpperCase().startsWith("ENV:")) {
434 String envValue = System.getenv(key.substring(4));
435 return processVariablesIfPresent(tenant, namespace, data.replaceAll("\\$\\{" + key + "\\}",
436 envValue == null ? "" : envValue.replace("\\", "\\\\")));
437 } else if (key.toUpperCase().startsWith("SYS:")) {
438 String sysValue = System.getProperty(key.substring(4));
439 return processVariablesIfPresent(tenant, namespace, data.replaceAll("\\$\\{" + key + "\\}",
440 sysValue == null ? "" : sysValue.replace("\\", "\\\\")));
442 String propertyValue = ConfigurationUtils.getCollectionString(
443 ConfigurationManager.lookup().getAsStringValues(tenant, namespace, key).toString());
444 return processVariablesIfPresent(tenant, namespace, data.replaceAll("\\$\\{" + key + "\\}",
445 propertyValue == null ? "" : propertyValue.replace("\\", "\\\\")));
452 public static String getFileContents(String path) {
455 return IOUtils.toString(new URL(path));
457 } catch (Exception exception) {
458 exception.printStackTrace();
463 public static String getFileContents(Path path) {
466 return new String(Files.readAllBytes(path));
468 } catch (Exception exception) {
469 exception.printStackTrace();
474 public static Object getDefaultFor(Class clazz) {
475 if (byte.class == clazz) {
476 return new Byte("0");
477 } else if (short.class == clazz) {
478 return new Short("0");
479 } else if (int.class == clazz) {
480 return new Integer("0");
481 } else if (float.class == clazz) {
482 return new Float("0");
483 } else if (long.class == clazz) {
484 return new Long("0");
485 } else if (double.class == clazz) {
486 return new Double("0");
487 } else if (boolean.class == clazz) {
488 return Boolean.FALSE;
493 public static Collection getCompatibleCollectionForAbstractDef(Class clazz) {
494 if (BlockingQueue.class.isAssignableFrom(clazz)) {
495 return getConcreteCollection(BlockingQueue.class);
497 if (TransferQueue.class.isAssignableFrom(clazz)) {
498 return getConcreteCollection(TransferQueue.class);
500 if (Deque.class.isAssignableFrom(clazz)) {
501 return getConcreteCollection(Deque.class);
503 if (Queue.class.isAssignableFrom(clazz)) {
504 return getConcreteCollection(Queue.class);
506 if (SortedSet.class.isAssignableFrom(clazz)) {
507 return getConcreteCollection(SortedSet.class);
509 if (Set.class.isAssignableFrom(clazz)) {
510 return getConcreteCollection(Set.class);
512 if (List.class.isAssignableFrom(clazz)) {
513 return getConcreteCollection(List.class);
518 public static Collection getConcreteCollection(Class clazz) {
519 switch (clazz.getName()) {
520 case "java.util.Collection":
521 case "java.util.List":
522 return new ArrayList<>();
523 case "java.util.Set":
524 return new HashSet<>();
525 case "java.util.SortedSet":
526 return new TreeSet<>();
527 case "java.util.Queue":
528 return new ConcurrentLinkedQueue<>();
529 case "java.util.Deque":
530 return new ArrayDeque<>();
531 case "java.util.concurrent.TransferQueue":
532 return new LinkedTransferQueue<>();
533 case "java.util.concurrent.BlockingQueue":
534 return new LinkedBlockingQueue<>();
540 public static String getConfigurationRepositoryKey(File file) {
541 return getConfigurationRepositoryKey(
542 ConfigurationUtils.getNamespace(file).split(Constants.TENANT_NAMESPACE_SEPARATOR));
545 public static String getConfigurationRepositoryKey(URL url) {
546 return getConfigurationRepositoryKey(
547 ConfigurationUtils.getNamespace(url).split(Constants.TENANT_NAMESPACE_SEPARATOR));
550 public static String getConfigurationRepositoryKey(String[] array) {
551 Deque<String> stack = new ArrayDeque<>();
552 stack.push(Constants.DEFAULT_TENANT);
553 for (String element : array) {
556 String toReturn = stack.pop();
557 return stack.pop() + Constants.KEY_ELEMENTS_DELIMITER + toReturn;
560 public static String getNamespace(File file) {
561 Optional<String> namespace =
562 getConfiguration(file).flatMap(ConfigurationUtils::readNamespace).map(String::toUpperCase);
563 return namespace.orElseGet(() -> getNamespace(file.getName().toUpperCase()));
566 public static String getNamespace(String file) {
567 file = file.toUpperCase().substring(file.lastIndexOf('!') + 1);
568 file = file.substring(file.lastIndexOf('/') + 1);
569 Pattern pattern = Pattern.compile(
570 "CONFIG(-\\w*){0,1}(-" + "(" + ConfigurationMode.OVERRIDE + "|" + ConfigurationMode.MERGE + "|"
571 + ConfigurationMode.UNION + ")){0,1}" + "\\.(" + ConfigurationType.PROPERTIES.name() + "|"
572 + ConfigurationType.XML.name() + "|" + ConfigurationType.JSON.name() + "|"
573 + ConfigurationType.YAML.name() + ")$");
574 Matcher matcher = pattern.matcher(file);
575 boolean b1 = matcher.matches();
577 if (matcher.group(1) != null) {
578 String moduleName = matcher.group(1).substring(1);
579 return moduleName.equalsIgnoreCase(ConfigurationMode.OVERRIDE.name()) || moduleName.equalsIgnoreCase(
580 ConfigurationMode.UNION.name()) || moduleName.equalsIgnoreCase(ConfigurationMode.MERGE.name())
581 ? Constants.DEFAULT_NAMESPACE : moduleName;
583 return Constants.DEFAULT_NAMESPACE;
585 } else if (isConfig(file)) {
586 return Constants.DEFAULT_NAMESPACE;
592 public static String getNamespace(URL url) {
594 Optional<String> namespace =
595 getConfiguration(url).flatMap(ConfigurationUtils::readNamespace).map(String::toUpperCase);
597 return namespace.orElseGet(() -> getNamespace(url.getFile().toUpperCase()));
600 public static Object getProperty(Configuration config, String key, int processingHints) {
602 if (!isDirectLookup(processingHints) && (config instanceof CompositeConfiguration)) {
604 CompositeConfiguration conf = (CompositeConfiguration) config;
605 for (int i = 0; i < conf.getNumberOfConfigurations(); i++) {
607 if (isNodeSpecific(processingHints)) {
608 Object obj = conf.getConfiguration(i).getProperty(key);
616 return config.getProperty(key);
619 public static boolean isCollection(String input) {
620 Pattern pattern = Pattern.compile("^\\[(.*)\\]$");
621 Matcher matcher = pattern.matcher(input);
622 return matcher.matches();
625 public static boolean isDirectLookup(int hints) {
626 return (hints & LATEST_LOOKUP.value()) == LATEST_LOOKUP.value();
629 public static boolean isNodeSpecific(int hints) {
630 return (hints & NODE_SPECIFIC.value()) == NODE_SPECIFIC.value();
633 public static boolean isExternalLookup(int hints) {
634 return (hints & EXTERNAL_LOOKUP.value()) == EXTERNAL_LOOKUP.value();
637 public static boolean isZeroLengthArray(Class clazz, Object obj) {
638 if (clazz.isArray() && clazz.getComponentType().isPrimitive()) {
639 if (clazz.getComponentType() == int.class) {
640 return ((int[]) obj).length == 0;
641 } else if (clazz.getComponentType() == byte.class) {
642 return ((byte[]) obj).length == 0;
643 } else if (clazz.getComponentType() == short.class) {
644 return ((short[]) obj).length == 0;
645 } else if (clazz.getComponentType() == float.class) {
646 return ((float[]) obj).length == 0;
647 } else if (clazz.getComponentType() == boolean.class) {
648 return ((boolean[]) obj).length == 0;
649 } else if (clazz.getComponentType() == double.class) {
650 return ((double[]) obj).length == 0;
651 } else if (clazz.getComponentType() == long.class) {
652 return ((long[]) obj).length == 0;
654 return ((Object[]) obj).length == 0;
661 public static boolean isBlank(String value) {
662 return value == null || value.trim().isEmpty();