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;
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Field;
22 import java.lang.reflect.Modifier;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
32 import java.util.function.Predicate;
33 import org.onap.config.ConfigurationUtils;
34 import org.onap.config.Constants;
35 import org.onap.config.NonConfigResource;
36 import org.onap.config.api.Config;
37 import org.onap.config.api.Hint;
39 public class ConfigurationImpl implements org.onap.config.api.Configuration {
41 private static final String KEY_CANNOT_BE_NULL = "Key can't be null.";
43 private static final ThreadLocal<String> TENANT = ThreadLocal.withInitial(() -> Constants.DEFAULT_TENANT);
45 private static final Object LOCK = new Object();
47 private static boolean instantiated = false;
49 public ConfigurationImpl() throws Exception {
56 private void init() throws Exception {
58 if (instantiated || !CliConfigurationImpl.class.isAssignableFrom(this.getClass())) {
59 throw new RuntimeException("Illegal access to configuration.");
62 Map<String, AggregateConfiguration> moduleConfigStore = new HashMap<>();
63 List<URL> classpathResources = ConfigurationUtils.getAllClassPathResources();
64 Predicate<URL> predicate = ConfigurationUtils::isConfig;
65 for (URL url : classpathResources) {
66 if (predicate.test(url)) {
67 String moduleName = ConfigurationUtils.getConfigurationRepositoryKey(url);
68 AggregateConfiguration moduleConfig = moduleConfigStore.get(moduleName);
69 if (moduleConfig == null) {
70 moduleConfig = new AggregateConfiguration();
71 moduleConfigStore.put(moduleName, moduleConfig);
73 moduleConfig.addConfig(url);
75 NonConfigResource.add(url);
78 String configLocation = System.getProperty("config.location");
79 if (configLocation != null && configLocation.trim().length() > 0) {
80 File root = new File(configLocation);
81 Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
82 Predicate<File> filePredicate = ConfigurationUtils::isConfig;
83 for (File file : filesystemResources) {
84 if (filePredicate.test(file)) {
85 String moduleName = ConfigurationUtils.getConfigurationRepositoryKey(file);
86 AggregateConfiguration moduleConfig = moduleConfigStore.get(moduleName);
87 if (moduleConfig == null) {
88 moduleConfig = new AggregateConfiguration();
89 moduleConfigStore.put(moduleName, moduleConfig);
91 moduleConfig.addConfig(file);
93 NonConfigResource.add(file);
97 String tenantConfigLocation = System.getProperty("tenant.config.location");
98 if (tenantConfigLocation != null && tenantConfigLocation.trim().length() > 0) {
99 File root = new File(tenantConfigLocation);
100 Collection<File> tenantsRoot = ConfigurationUtils.getAllFiles(root, false, true);
101 Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
102 Predicate<File> filePredicate = ConfigurationUtils::isConfig;
103 for (File file : filesystemResources) {
104 if (filePredicate.test(file)) {
105 String moduleName = ConfigurationUtils.getNamespace(file);
106 for (File tenantFileRoot : tenantsRoot) {
107 if (file.getAbsolutePath().startsWith(tenantFileRoot.getAbsolutePath())) {
108 moduleName = ConfigurationUtils.getConfigurationRepositoryKey(
109 (tenantFileRoot.getName().toUpperCase() + Constants.TENANT_NAMESPACE_SEPARATOR
110 + moduleName).split(Constants.TENANT_NAMESPACE_SEPARATOR));
113 AggregateConfiguration moduleConfig = moduleConfigStore.get(moduleName);
114 if (moduleConfig == null) {
115 moduleConfig = new AggregateConfiguration();
116 moduleConfigStore.put(moduleName, moduleConfig);
118 moduleConfig.addConfig(file);
123 populateFinalConfigurationIncrementally(moduleConfigStore);
124 String nodeConfigLocation = System.getProperty("node.config.location");
125 if (nodeConfigLocation != null && nodeConfigLocation.trim().length() > 0) {
126 File root = new File(nodeConfigLocation);
127 Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
128 Predicate<File> filePredicate = ConfigurationUtils::isConfig;
129 for (File file : filesystemResources) {
130 if (filePredicate.test(file)) {
131 ConfigurationRepository.lookup().populateOverrideConfiguration(
132 ConfigurationUtils.getConfigurationRepositoryKey(
133 ConfigurationUtils.getNamespace(file).split(Constants.TENANT_NAMESPACE_SEPARATOR)),
142 private 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 if (tenantId == null || tenantId.trim().length() == 0) {
205 tenantId = TENANT.get();
207 tenantId = tenantId.toUpperCase();
209 if (namespace == null || namespace.trim().length() == 0) {
210 namespace = Constants.DEFAULT_NAMESPACE;
212 namespace = namespace.toUpperCase();
214 Map<String, T> map = new HashMap<>();
215 Iterator<String> keys;
217 keys = ConfigurationRepository.lookup().getConfigurationFor(tenantId, namespace).getKeys(key);
218 while (keys.hasNext()) {
219 String k = keys.next();
220 if (k.startsWith(key + ".")) {
221 k = k.substring(key.length() + 1);
222 String subkey = k.substring(0, k.indexOf("."));
223 if (!map.containsKey(subkey)) {
224 map.put(subkey, get(tenantId, namespace, key + "." + subkey, clazz));
228 } catch (Exception e) {
235 public Map generateMap(String tenantId, String namespace, String key) {
237 if (tenantId == null || tenantId.trim().length() == 0) {
238 tenantId = TENANT.get();
240 tenantId = tenantId.toUpperCase();
242 if (namespace == null || namespace.trim().length() == 0) {
243 namespace = Constants.DEFAULT_NAMESPACE;
245 namespace = namespace.toUpperCase();
248 Map parentMap = new HashMap<>();
249 Iterator<String> keys;
251 if (key == null || key.trim().length() == 0) {
252 keys = ConfigurationRepository.lookup().getConfigurationFor(tenantId, namespace).getKeys();
254 keys = ConfigurationRepository.lookup().getConfigurationFor(tenantId, namespace).getKeys(key);
256 while (keys.hasNext()) {
258 String k = keys.next();
260 if (key != null && key.trim().length() != 0 && !k.startsWith(key + ".")) {
263 String value = getAsString(tenantId, namespace, k);
264 if (key != null && key.trim().length() != 0 && k.startsWith(key + ".")) {
265 k = k.substring(key.trim().length() + 1);
268 while (k.contains(".")) {
269 if (k.contains(".")) {
270 String subkey = k.substring(0, k.indexOf("."));
271 k = k.substring(k.indexOf(".") + 1);
272 if (!map.containsKey(subkey)) {
273 map.put(subkey, map = new HashMap<>());
275 map = (Map) map.get(subkey);
281 } catch (Exception e) {
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 if (tenant == null || tenant.trim().length() == 0) {
296 tenant = TENANT.get();
298 tenant = tenant.toUpperCase();
300 if (namespace == null || namespace.trim().length() == 0) {
301 namespace = Constants.DEFAULT_NAMESPACE;
303 namespace = namespace.toUpperCase();
305 if ((key == null || key.trim().length() == 0) && !clazz.isAnnotationPresent(Config.class)) {
306 throw new IllegalArgumentException(KEY_CANNOT_BE_NULL);
309 throw new IllegalArgumentException("clazz is null.");
311 if (clazz.isPrimitive()) {
312 clazz = getWrapperClass(clazz);
315 if (ConfigurationUtils.isWrapperClass(clazz) || clazz.isPrimitive()) {
316 Object obj = ConfigurationUtils.getProperty(
317 ConfigurationRepository.lookup().getConfigurationFor(tenant, namespace), key, processingHints);
319 if (ConfigurationUtils.isCollection(obj.toString())) {
320 obj = ConfigurationUtils.getCollectionString(obj.toString());
322 String value = obj.toString().split(",")[0];
323 value = ConfigurationUtils.processVariablesIfPresent(tenant, namespace, value);
324 return (T) getValue(value, clazz.isPrimitive() ? getWrapperClass(clazz) : clazz, processingHints);
328 } else if (clazz.isArray() && (clazz.getComponentType().isPrimitive() || ConfigurationUtils.isWrapperClass(
329 clazz.getComponentType()))) {
330 Object obj = ConfigurationUtils.getProperty(
331 ConfigurationRepository.lookup().getConfigurationFor(tenant, namespace), key, processingHints);
333 Class componentClass = clazz.getComponentType();
334 if (clazz.getComponentType().isPrimitive()) {
335 componentClass = getWrapperClass(clazz.getComponentType());
337 String collString = ConfigurationUtils.getCollectionString(obj.toString());
338 ArrayList<String> tempCollection = new ArrayList<>();
339 for (String itemValue : collString.split(",")) {
340 tempCollection.add(ConfigurationUtils.processVariablesIfPresent(tenant, namespace, itemValue));
342 Collection<T> collection =
343 convert(ConfigurationUtils.getCollectionString(Arrays.toString(tempCollection.toArray())),
344 componentClass, processingHints);
345 if (clazz.getComponentType().isPrimitive()) {
346 return (T) ConfigurationUtils.getPrimitiveArray(collection, clazz.getComponentType());
348 return (T) collection.toArray(getZeroLengthArrayFor(getWrapperClass(clazz.getComponentType())));
353 } else if (clazz.isAnnotationPresent(Config.class)) {
354 return read(tenant, namespace, clazz, (key == null || key.trim().length() == 0) ? "" : (key + "."),
357 throw new IllegalArgumentException(
358 "Only primitive classes, wrapper classes, corresponding array classes and any "
359 + "class decorated with @org.openecomp.config.api.Config are allowed as argument.");
361 } catch (Exception exception) {
362 exception.printStackTrace();
367 private <T> T read(String tenant, String namespace, Class<T> clazz, String keyPrefix, Hint... hints)
369 Config confAnnotation = clazz.getAnnotation(Config.class);
370 if (confAnnotation != null && confAnnotation.key().length() > 0 && !keyPrefix.endsWith(".")) {
371 keyPrefix += (confAnnotation.key() + ".");
373 Constructor<T> constructor = clazz.getDeclaredConstructor();
374 constructor.setAccessible(true);
375 T objToReturn = constructor.newInstance();
376 for (Field field : clazz.getDeclaredFields()) {
377 field.setAccessible(true);
378 Config fieldConfAnnotation = field.getAnnotation(Config.class);
379 if (fieldConfAnnotation != null) {
380 if (field.getType().isPrimitive() || ConfigurationUtils.isWrapperClass(field.getType()) || (
381 field.getType().isArray() && (field.getType().getComponentType().isPrimitive()
382 || ConfigurationUtils.isWrapperClass(
383 field.getType().getComponentType())))
384 || field.getType().getAnnotation(Config.class) != null) {
385 field.set(objToReturn,
386 get(tenant, namespace, keyPrefix + fieldConfAnnotation.key(), field.getType(), hints));
387 } else if (Collection.class.isAssignableFrom(field.getType())) {
388 Object obj = get(tenant, namespace, keyPrefix + fieldConfAnnotation.key(),
389 ConfigurationUtils.getArrayClass(ConfigurationUtils.getCollectionGenericType(field)),
392 List list = Arrays.asList((Object[]) obj);
393 Class clazzToInstantiate;
394 if (field.getType().isInterface()) {
395 clazzToInstantiate = ConfigurationUtils.getConcreteCollection(field.getType()).getClass();
396 } else if (Modifier.isAbstract(field.getType().getModifiers())) {
398 ConfigurationUtils.getCompatibleCollectionForAbstractDef(field.getType())
401 clazzToInstantiate = field.getType();
403 Constructor construct = getConstructorWithArguments(clazzToInstantiate, Collection.class);
404 if (construct != null) {
405 construct.setAccessible(true);
406 field.set(objToReturn, construct.newInstance(list));
407 } else if ((construct = getConstructorWithArguments(clazzToInstantiate, Integer.class,
408 Boolean.class, Collection.class)) != null) {
409 construct.setAccessible(true);
410 field.set(objToReturn, construct.newInstance(list.size(), true, list));
413 } else if (Map.class.isAssignableFrom(field.getType())) {
414 field.set(objToReturn, generateMap(tenant, namespace, keyPrefix + fieldConfAnnotation.key()));
421 private Constructor getConstructorWithArguments(Class clazz, Class... classes) {
423 return clazz.getDeclaredConstructor(classes);
424 } catch (Exception exception) {
429 private Class getWrapperClass(Class clazz) {
430 if (byte.class == clazz) {
432 } else if (short.class == clazz) {
434 } else if (int.class == clazz) {
435 return Integer.class;
436 } else if (long.class == clazz) {
438 } else if (float.class == clazz) {
440 } else if (double.class == clazz) {
442 } else if (char.class == clazz) {
443 return Character.class;
444 } else if (boolean.class == clazz) {
445 return Boolean.class;
450 private <T> T getValue(Object obj, Class<T> clazz, int processingHint) {
451 if (obj == null || obj.toString().trim().length() == 0) {
454 obj = obj.toString().trim();
456 if (String.class.equals(clazz)) {
457 if (obj.toString().startsWith("@") && ConfigurationUtils.isExternalLookup(processingHint)) {
458 String contents = ConfigurationUtils.getFileContents(
459 NonConfigResource.locate(obj.toString().substring(1).trim()));
460 if (contents == null) {
461 contents = ConfigurationUtils.getFileContents(obj.toString().substring(1).trim());
463 if (contents != null) {
467 return (T) obj.toString();
468 } else if (Number.class.isAssignableFrom(clazz)) {
469 Double doubleValue = Double.valueOf(obj.toString());
470 switch (clazz.getName()) {
471 case "java.lang.Byte":
472 Byte byteVal = doubleValue.byteValue();
474 case "java.lang.Short":
475 Short shortVal = doubleValue.shortValue();
477 case "java.lang.Integer":
478 Integer intVal = doubleValue.intValue();
480 case "java.lang.Long":
481 Long longVal = doubleValue.longValue();
483 case "java.lang.Float":
484 Float floatVal = doubleValue.floatValue();
486 case "java.lang.Double":
487 return (T) doubleValue;
490 } else if (Boolean.class.equals(clazz)) {
491 return (T) Boolean.valueOf(obj.toString());
492 } else if (Character.class.equals(clazz)) {
493 return (T) Character.valueOf(obj.toString().charAt(0));
498 private <T> T[] getZeroLengthArrayFor(Class<T> clazz) {
500 if (clazz == int.class) {
502 } else if (clazz == byte.class) {
504 } else if (clazz == short.class) {
505 obj = new short[] {};
506 } else if (clazz == long.class) {
508 } else if (clazz == float.class) {
509 obj = new float[] {};
510 } else if (clazz == double.class) {
511 obj = new double[] {};
512 } else if (clazz == boolean.class) {
513 obj = new boolean[] {};
514 } else if (clazz == char.class) {
516 } else if (clazz == Byte.class) {
518 } else if (clazz == Short.class) {
519 obj = new Short[] {};
520 } else if (clazz == Integer.class) {
521 obj = new Integer[] {};
522 } else if (clazz == Long.class) {
524 } else if (clazz == Float.class) {
525 obj = new Float[] {};
526 } else if (clazz == Double.class) {
527 obj = new Double[] {};
528 } else if (clazz == Boolean.class) {
529 obj = new Boolean[] {};
530 } else if (clazz == Character.class) {
531 obj = new Character[] {};
532 } else if (clazz == String.class) {
533 obj = new String[] {};
538 private <T> Collection<T> convert(String commaSaperatedValues, Class<T> clazz, int processingHints) {
539 ArrayList<T> collection = new ArrayList<>();
540 for (String value : commaSaperatedValues.split(",")) {
542 T type1 = getValue(value, clazz, processingHints);
544 collection.add(type1);
546 } catch (RuntimeException re) {