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.impl;
19 import static org.onap.config.ConfigurationUtils.isBlank;
22 import java.lang.reflect.Constructor;
23 import java.lang.reflect.Field;
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Modifier;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.List;
35 import java.util.function.Predicate;
36 import org.apache.commons.configuration2.ex.ConfigurationException;
37 import org.onap.config.ConfigurationUtils;
38 import org.onap.config.Constants;
39 import org.onap.config.NonConfigResource;
40 import org.onap.config.api.Config;
41 import org.onap.config.api.Hint;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
45 public class ConfigurationImpl implements org.onap.config.api.Configuration {
47 private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationImpl.class);
49 private static final String KEY_CANNOT_BE_NULL = "Key can't be null.";
51 private static final NonConfigResource NON_CONFIG_RESOURCE = new NonConfigResource();
57 } catch (ConfigurationException e) {
58 throw new IllegalStateException("Failed to initialize configuration", e);
62 private static void init() throws ConfigurationException {
64 Map<String, AggregateConfiguration> moduleConfigStore = new HashMap<>();
65 List<URL> classpathResources = ConfigurationUtils.getAllClassPathResources();
66 Predicate<URL> predicate = ConfigurationUtils::isConfig;
67 for (URL url : classpathResources) {
68 if (predicate.test(url)) {
69 String moduleName = ConfigurationUtils.getConfigurationRepositoryKey(url);
70 AggregateConfiguration moduleConfig = moduleConfigStore.get(moduleName);
71 if (moduleConfig == null) {
72 moduleConfig = new AggregateConfiguration();
73 moduleConfigStore.put(moduleName, moduleConfig);
75 moduleConfig.addConfig(url);
77 NON_CONFIG_RESOURCE.add(url);
80 String configLocation = System.getProperty("config.location");
81 if (!isBlank(configLocation)) {
82 File root = new File(configLocation);
83 Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
84 Predicate<File> filePredicate = ConfigurationUtils::isConfig;
85 for (File file : filesystemResources) {
86 if (filePredicate.test(file)) {
87 String moduleName = ConfigurationUtils.getConfigurationRepositoryKey(file);
88 AggregateConfiguration moduleConfig = moduleConfigStore.get(moduleName);
89 if (moduleConfig == null) {
90 moduleConfig = new AggregateConfiguration();
91 moduleConfigStore.put(moduleName, moduleConfig);
93 moduleConfig.addConfig(file);
95 NON_CONFIG_RESOURCE.add(file);
99 String tenantConfigLocation = System.getProperty("tenant.config.location");
100 if (!isBlank(tenantConfigLocation)) {
101 File root = new File(tenantConfigLocation);
102 Collection<File> tenantsRoot = ConfigurationUtils.getAllFiles(root, false, true);
103 Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
104 Predicate<File> filePredicate = ConfigurationUtils::isConfig;
105 for (File file : filesystemResources) {
106 if (filePredicate.test(file)) {
107 String moduleName = ConfigurationUtils.getNamespace(file);
108 for (File tenantFileRoot : tenantsRoot) {
109 if (file.getAbsolutePath().startsWith(tenantFileRoot.getAbsolutePath())) {
110 moduleName = ConfigurationUtils.getConfigurationRepositoryKey(
111 (tenantFileRoot.getName().toUpperCase() + Constants.TENANT_NAMESPACE_SEPARATOR
112 + moduleName).split(Constants.TENANT_NAMESPACE_SEPARATOR));
115 AggregateConfiguration moduleConfig = moduleConfigStore.get(moduleName);
116 if (moduleConfig == null) {
117 moduleConfig = new AggregateConfiguration();
118 moduleConfigStore.put(moduleName, moduleConfig);
120 moduleConfig.addConfig(file);
125 populateFinalConfigurationIncrementally(moduleConfigStore);
126 String nodeConfigLocation = System.getProperty("node.config.location");
127 if (!isBlank(nodeConfigLocation)) {
128 File root = new File(nodeConfigLocation);
129 Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
130 Predicate<File> filePredicate = ConfigurationUtils::isConfig;
131 for (File file : filesystemResources) {
132 if (filePredicate.test(file)) {
133 ConfigurationRepository.lookup().populateOverrideConfiguration(
134 ConfigurationUtils.getConfigurationRepositoryKey(
135 ConfigurationUtils.getNamespace(file).split(Constants.TENANT_NAMESPACE_SEPARATOR)),
142 private static void populateFinalConfigurationIncrementally(Map<String, AggregateConfiguration> configs) {
144 if (configs.get(Constants.DEFAULT_TENANT + Constants.KEY_ELEMENTS_DELIMITER + Constants.DB_NAMESPACE) != null) {
145 ConfigurationRepository.lookup().populateConfiguration(
146 Constants.DEFAULT_TENANT + Constants.KEY_ELEMENTS_DELIMITER + Constants.DB_NAMESPACE,
147 configs.remove(Constants.DEFAULT_TENANT + Constants.KEY_ELEMENTS_DELIMITER + Constants.DB_NAMESPACE)
148 .getFinalConfiguration());
151 Set<String> modules = configs.keySet();
152 for (String module : modules) {
153 ConfigurationRepository.lookup().populateConfiguration(module, configs.get(module).getFinalConfiguration());
158 public <T> T get(String tenant, String namespace, String key, Class<T> clazz, Hint... hints) {
160 String[] tenantNamespaceArray;
161 if (tenant == null && namespace != null) {
162 tenantNamespaceArray = namespace.split(Constants.TENANT_NAMESPACE_SEPARATOR);
163 if (tenantNamespaceArray.length > 1) {
164 tenant = tenantNamespaceArray[0];
165 namespace = tenantNamespaceArray[1];
169 tenant = ConfigurationRepository.lookup().isValidTenant(tenant) ? tenant.toUpperCase()
170 : Constants.DEFAULT_TENANT;
171 namespace = ConfigurationRepository.lookup().isValidNamespace(namespace) ? namespace.toUpperCase()
172 : Constants.DEFAULT_NAMESPACE;
174 returnValue = (T) getInternal(tenant, namespace, key, clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
175 hints == null || hints.length == 0 ? new Hint[] {Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC} : hints);
176 if ((returnValue == null || ConfigurationUtils.isZeroLengthArray(clazz, returnValue))
177 && !Constants.DEFAULT_TENANT.equals(tenant)) {
178 returnValue = (T) getInternal(Constants.DEFAULT_TENANT, namespace, key,
179 clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
180 hints == null || hints.length == 0 ? new Hint[] {Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC} : hints);
182 if ((returnValue == null || ConfigurationUtils.isZeroLengthArray(clazz, returnValue))
183 && !Constants.DEFAULT_NAMESPACE.equals(namespace)) {
184 returnValue = (T) getInternal(tenant, Constants.DEFAULT_NAMESPACE, key,
185 clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
186 hints == null || hints.length == 0 ? new Hint[] {Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC} : hints);
188 if ((returnValue == null || ConfigurationUtils.isZeroLengthArray(clazz, returnValue))
189 && !Constants.DEFAULT_NAMESPACE.equals(namespace) && !Constants.DEFAULT_TENANT.equals(tenant)) {
190 returnValue = (T) getInternal(Constants.DEFAULT_TENANT, Constants.DEFAULT_NAMESPACE, key,
191 clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
192 hints == null || hints.length == 0 ? new Hint[] {Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC} : hints);
194 if (returnValue == null && clazz.isPrimitive()) {
195 return (T) ConfigurationUtils.getDefaultFor(clazz);
202 public <T> Map<String, T> populateMap(String tenantId, String namespace, String key, Class<T> clazz) {
204 tenantId = calculateTenant(tenantId);
205 namespace = calculateNamespace(namespace);
206 Map<String, T> map = new HashMap<>();
207 Iterator<String> keys;
209 keys = ConfigurationRepository.lookup().getConfigurationFor(tenantId, namespace).getKeys(key);
210 while (keys.hasNext()) {
211 String k = keys.next();
212 if (k.startsWith(key + ".")) {
213 k = k.substring(key.length() + 1);
214 String subkey = k.substring(0, k.indexOf('.'));
215 if (!map.containsKey(subkey)) {
216 map.put(subkey, get(tenantId, namespace, key + "." + subkey, clazz));
220 } catch (Exception e) {
222 "Couldn't populate map fot tenant: {}, namespace: {}, key: {}, type: {}",
226 clazz.getSimpleName(),
234 public Map generateMap(String tenantId, String namespace, String key) {
236 tenantId = calculateTenant(tenantId);
237 namespace = calculateNamespace(namespace);
240 Map parentMap = new HashMap<>();
241 Iterator<String> keys;
244 keys = ConfigurationRepository.lookup().getConfigurationFor(tenantId, namespace).getKeys();
246 keys = ConfigurationRepository.lookup().getConfigurationFor(tenantId, namespace).getKeys(key);
248 while (keys.hasNext()) {
250 String k = keys.next();
252 if (!isBlank(key) && !k.startsWith(key + ".")) {
255 String value = getAsString(tenantId, namespace, k);
256 if (!isBlank(key) && k.startsWith(key + ".")) {
257 k = k.substring(key.trim().length() + 1);
260 while (k.contains(".")) {
261 if (k.contains(".")) {
262 String subkey = k.substring(0, k.indexOf('.'));
263 k = k.substring(k.indexOf('.') + 1);
264 if (!map.containsKey(subkey)) {
265 Map tmp = new HashMap();
266 map.put(subkey, tmp);
269 map = (Map) map.get(subkey);
275 } catch (Exception e) {
277 "Couldn't generate map fot tenant: {}, namespace: {}, key: {}",
287 protected <T> T getInternal(String tenant, String namespace, String key, Class<T> clazz, Hint... hints) {
288 int processingHints = Hint.DEFAULT.value();
290 for (Hint hint : hints) {
291 processingHints = processingHints | hint.value();
295 tenant = calculateTenant(tenant);
296 namespace = calculateNamespace(namespace);
298 if (isBlank(key) && !clazz.isAnnotationPresent(Config.class)) {
299 throw new IllegalArgumentException(KEY_CANNOT_BE_NULL);
303 throw new IllegalArgumentException("clazz is null.");
306 if (clazz.isPrimitive()) {
307 clazz = getWrapperClass(clazz);
310 if (ConfigurationUtils.isWrapperClass(clazz) || clazz.isPrimitive()) {
311 Object obj = ConfigurationUtils.getProperty(
312 ConfigurationRepository.lookup().getConfigurationFor(tenant, namespace), key, processingHints);
314 if (ConfigurationUtils.isCollection(obj.toString())) {
315 obj = ConfigurationUtils.getCollectionString(obj.toString());
317 String value = obj.toString().split(",")[0];
318 value = ConfigurationUtils.processVariablesIfPresent(tenant, namespace, value);
319 return (T) getValue(value, clazz.isPrimitive() ? getWrapperClass(clazz) : clazz, processingHints);
323 } else if (clazz.isArray() && (clazz.getComponentType().isPrimitive() || ConfigurationUtils.isWrapperClass(
324 clazz.getComponentType()))) {
325 Object obj = ConfigurationUtils.getProperty(
326 ConfigurationRepository.lookup().getConfigurationFor(tenant, namespace), key, processingHints);
328 Class componentClass = clazz.getComponentType();
329 if (clazz.getComponentType().isPrimitive()) {
330 componentClass = getWrapperClass(clazz.getComponentType());
332 String collString = ConfigurationUtils.getCollectionString(obj.toString());
333 ArrayList<String> tempCollection = new ArrayList<>();
334 for (String itemValue : collString.split(",")) {
335 tempCollection.add(ConfigurationUtils.processVariablesIfPresent(tenant, namespace, itemValue));
337 Collection<T> collection =
338 convert(ConfigurationUtils.getCollectionString(Arrays.toString(tempCollection.toArray())),
339 componentClass, processingHints);
340 if (clazz.getComponentType().isPrimitive()) {
341 return (T) ConfigurationUtils.getPrimitiveArray(collection, clazz.getComponentType());
343 return (T) collection.toArray(getZeroLengthArrayFor(getWrapperClass(clazz.getComponentType())));
348 } else if (clazz.isAnnotationPresent(Config.class)) {
349 return read(tenant, namespace, clazz, isBlank(key) ? "" : (key + "."), hints);
351 throw new IllegalArgumentException(
352 "Only primitive classes, wrapper classes, corresponding array classes and any "
353 + "class decorated with @org.openecomp.config.api.Config are allowed as argument.");
355 } catch (Exception exception) {
357 "Failed to get internal value fot tenant: {}, namespace: {}, key: {}, type: {}",
361 clazz.getSimpleName(),
368 private static String calculateNamespace(String namespace) {
370 if (isBlank(namespace)) {
371 return Constants.DEFAULT_NAMESPACE;
374 return namespace.toUpperCase();
377 private static String calculateTenant(String tenant) {
379 if (isBlank(tenant)) {
380 return Constants.DEFAULT_TENANT;
383 return tenant.toUpperCase();
386 private <T> T read(String tenant, String namespace, Class<T> clazz, String keyPrefix, Hint... hints)
387 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
389 Config confAnnotation = clazz.getAnnotation(Config.class);
390 if (confAnnotation != null && confAnnotation.key().length() > 0 && !keyPrefix.endsWith(".")) {
391 keyPrefix += (confAnnotation.key() + ".");
393 Constructor<T> constructor = clazz.getDeclaredConstructor();
394 constructor.setAccessible(true);
395 T objToReturn = constructor.newInstance();
396 for (Field field : clazz.getDeclaredFields()) {
397 field.setAccessible(true);
398 Config fieldConfAnnotation = field.getAnnotation(Config.class);
399 if (fieldConfAnnotation != null) {
400 if (field.getType().isPrimitive() || ConfigurationUtils.isWrapperClass(field.getType()) || (
401 field.getType().isArray() && (field.getType().getComponentType().isPrimitive()
402 || ConfigurationUtils.isWrapperClass(
403 field.getType().getComponentType())))
404 || field.getType().getAnnotation(Config.class) != null) {
405 field.set(objToReturn,
406 get(tenant, namespace, keyPrefix + fieldConfAnnotation.key(), field.getType(), hints));
407 } else if (Collection.class.isAssignableFrom(field.getType())) {
408 Object obj = get(tenant, namespace, keyPrefix + fieldConfAnnotation.key(),
409 ConfigurationUtils.getArrayClass(ConfigurationUtils.getCollectionGenericType(field)),
412 List list = Arrays.asList((Object[]) obj);
413 Class clazzToInstantiate;
414 if (field.getType().isInterface()) {
415 clazzToInstantiate = ConfigurationUtils.getConcreteCollection(field.getType()).getClass();
416 } else if (Modifier.isAbstract(field.getType().getModifiers())) {
418 ConfigurationUtils.getCompatibleCollectionForAbstractDef(field.getType())
421 clazzToInstantiate = field.getType();
423 Constructor construct = getConstructorWithArguments(clazzToInstantiate, Collection.class);
425 if (construct != null) {
426 construct.setAccessible(true);
427 field.set(objToReturn, construct.newInstance(list));
429 construct = getConstructorWithArguments(clazzToInstantiate, Integer.class,
430 Boolean.class, Collection.class);
431 if (construct != null) {
432 construct.setAccessible(true);
433 field.set(objToReturn, construct.newInstance(list.size(), true, list));
437 } else if (Map.class.isAssignableFrom(field.getType())) {
438 field.set(objToReturn, generateMap(tenant, namespace, keyPrefix + fieldConfAnnotation.key()));
445 private Constructor getConstructorWithArguments(Class clazz, Class... classes) {
447 return clazz.getDeclaredConstructor(classes);
448 } catch (Exception exception) {
449 LOGGER.warn("Failed to get {} constructor.", clazz.getSimpleName(), exception);
454 private Class getWrapperClass(Class clazz) {
455 if (byte.class == clazz) {
457 } else if (short.class == clazz) {
459 } else if (int.class == clazz) {
460 return Integer.class;
461 } else if (long.class == clazz) {
463 } else if (float.class == clazz) {
465 } else if (double.class == clazz) {
467 } else if (char.class == clazz) {
468 return Character.class;
469 } else if (boolean.class == clazz) {
470 return Boolean.class;
475 private <T> T getValue(Object obj, Class<T> clazz, int processingHint) {
477 if (obj == null || obj.toString().trim().length() == 0) {
480 obj = obj.toString().trim();
483 if (String.class.equals(clazz)) {
484 if (obj.toString().startsWith("@") && ConfigurationUtils.isExternalLookup(processingHint)) {
485 String contents = ConfigurationUtils.getFileContents(
486 NON_CONFIG_RESOURCE.locate(obj.toString().substring(1).trim()));
487 if (contents == null) {
488 contents = ConfigurationUtils.getFileContents(obj.toString().substring(1).trim());
490 if (contents != null) {
494 return (T) obj.toString();
495 } else if (Number.class.isAssignableFrom(clazz)) {
496 Double doubleValue = Double.valueOf(obj.toString());
497 switch (clazz.getName()) {
498 case "java.lang.Byte":
499 Byte byteVal = doubleValue.byteValue();
501 case "java.lang.Short":
502 Short shortVal = doubleValue.shortValue();
504 case "java.lang.Integer":
505 Integer intVal = doubleValue.intValue();
507 case "java.lang.Long":
508 Long longVal = doubleValue.longValue();
510 case "java.lang.Float":
511 Float floatVal = doubleValue.floatValue();
513 case "java.lang.Double":
514 return (T) doubleValue;
517 } else if (Boolean.class.equals(clazz)) {
518 return (T) Boolean.valueOf(obj.toString());
519 } else if (Character.class.equals(clazz)) {
520 return (T) Character.valueOf(obj.toString().charAt(0));
525 private <T> T[] getZeroLengthArrayFor(Class<T> clazz) {
527 if (clazz == int.class) {
529 } else if (clazz == byte.class) {
531 } else if (clazz == short.class) {
532 obj = new short[] {};
533 } else if (clazz == long.class) {
535 } else if (clazz == float.class) {
536 obj = new float[] {};
537 } else if (clazz == double.class) {
538 obj = new double[] {};
539 } else if (clazz == boolean.class) {
540 obj = new boolean[] {};
541 } else if (clazz == char.class) {
543 } else if (clazz == Byte.class) {
545 } else if (clazz == Short.class) {
546 obj = new Short[] {};
547 } else if (clazz == Integer.class) {
548 obj = new Integer[] {};
549 } else if (clazz == Long.class) {
551 } else if (clazz == Float.class) {
552 obj = new Float[] {};
553 } else if (clazz == Double.class) {
554 obj = new Double[] {};
555 } else if (clazz == Boolean.class) {
556 obj = new Boolean[] {};
557 } else if (clazz == Character.class) {
558 obj = new Character[] {};
559 } else if (clazz == String.class) {
560 obj = new String[] {};
565 private <T> Collection<T> convert(String commaSeparatedValues, Class<T> clazz, int processingHints) {
566 ArrayList<T> collection = new ArrayList<>();
567 for (String value : commaSeparatedValues.split(",")) {
569 T type1 = getValue(value, clazz, processingHints);
571 collection.add(type1);
573 } catch (RuntimeException re) {
574 LOGGER.warn("Failed to convert {}", commaSeparatedValues, re);