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.";
42 private static final ThreadLocal<String> tenant = ThreadLocal.withInitial(() -> Constants.DEFAULT_TENANT);
44 private static boolean instantiated = false;
46 public ConfigurationImpl() throws Exception {
47 if (instantiated || !CliConfigurationImpl.class.isAssignableFrom(this.getClass())) {
48 throw new RuntimeException("Illegal access to configuration.");
50 Map<String, AggregateConfiguration> moduleConfigStore = new HashMap<>();
51 List<URL> classpathResources = ConfigurationUtils.getAllClassPathResources();
52 Predicate<URL> predicate = ConfigurationUtils::isConfig;
53 for (URL url : classpathResources) {
54 if (predicate.test(url)) {
55 String moduleName = ConfigurationUtils.getConfigurationRepositoryKey(url);
56 AggregateConfiguration moduleConfig = moduleConfigStore.get(moduleName);
57 if (moduleConfig == null) {
58 moduleConfig = new AggregateConfiguration();
59 moduleConfigStore.put(moduleName, moduleConfig);
61 moduleConfig.addConfig(url);
63 NonConfigResource.add(url);
66 String configLocation = System.getProperty("config.location");
67 if (configLocation != null && configLocation.trim().length() > 0) {
68 File root = new File(configLocation);
69 Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
70 Predicate<File> filePredicate = ConfigurationUtils::isConfig;
71 for (File file : filesystemResources) {
72 if (filePredicate.test(file)) {
73 String moduleName = ConfigurationUtils.getConfigurationRepositoryKey(file);
74 AggregateConfiguration moduleConfig = moduleConfigStore.get(moduleName);
75 if (moduleConfig == null) {
76 moduleConfig = new AggregateConfiguration();
77 moduleConfigStore.put(moduleName, moduleConfig);
79 moduleConfig.addConfig(file);
81 NonConfigResource.add(file);
85 String tenantConfigLocation = System.getProperty("tenant.config.location");
86 if (tenantConfigLocation != null && tenantConfigLocation.trim().length() > 0) {
87 File root = new File(tenantConfigLocation);
88 Collection<File> tenantsRoot = ConfigurationUtils.getAllFiles(root, false, true);
89 Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
90 Predicate<File> filePredicate = ConfigurationUtils::isConfig;
91 for (File file : filesystemResources) {
92 if (filePredicate.test(file)) {
93 String moduleName = ConfigurationUtils.getNamespace(file);
94 for (File tenantFileRoot : tenantsRoot) {
95 if (file.getAbsolutePath().startsWith(tenantFileRoot.getAbsolutePath())) {
96 moduleName = ConfigurationUtils.getConfigurationRepositoryKey(
97 (tenantFileRoot.getName().toUpperCase() + Constants.TENANT_NAMESPACE_SEPARATOR
98 + moduleName).split(Constants.TENANT_NAMESPACE_SEPARATOR));
101 AggregateConfiguration moduleConfig = moduleConfigStore.get(moduleName);
102 if (moduleConfig == null) {
103 moduleConfig = new AggregateConfiguration();
104 moduleConfigStore.put(moduleName, moduleConfig);
106 moduleConfig.addConfig(file);
110 populateFinalConfigurationIncrementally(moduleConfigStore);
111 String nodeConfigLocation = System.getProperty("node.config.location");
112 if (nodeConfigLocation != null && nodeConfigLocation.trim().length() > 0) {
113 File root = new File(nodeConfigLocation);
114 Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
115 Predicate<File> filePredicate = ConfigurationUtils::isConfig;
116 for (File file : filesystemResources) {
117 if (filePredicate.test(file)) {
118 ConfigurationRepository.lookup().populateOverrideConfiguration(
119 ConfigurationUtils.getConfigurationRepositoryKey(
120 ConfigurationUtils.getNamespace(file).split(Constants.TENANT_NAMESPACE_SEPARATOR)),
128 private void populateFinalConfigurationIncrementally(Map<String, AggregateConfiguration> configs) {
130 if (configs.get(Constants.DEFAULT_TENANT + Constants.KEY_ELEMENTS_DELIMITER + Constants.DB_NAMESPACE) != null) {
131 ConfigurationRepository.lookup().populateConfiguration(
132 Constants.DEFAULT_TENANT + Constants.KEY_ELEMENTS_DELIMITER + Constants.DB_NAMESPACE,
133 configs.remove(Constants.DEFAULT_TENANT + Constants.KEY_ELEMENTS_DELIMITER + Constants.DB_NAMESPACE)
134 .getFinalConfiguration());
137 Set<String> modules = configs.keySet();
138 for (String module : modules) {
139 ConfigurationRepository.lookup().populateConfiguration(module, configs.get(module).getFinalConfiguration());
144 public <T> T get(String tenant, String namespace, String key, Class<T> clazz, Hint... hints) {
146 String[] tenantNamespaceArray;
147 if (tenant == null && namespace != null) {
148 tenantNamespaceArray = namespace.split(Constants.TENANT_NAMESPACE_SEPARATOR);
149 if (tenantNamespaceArray.length > 1) {
150 tenant = tenantNamespaceArray[0];
151 namespace = tenantNamespaceArray[1];
155 tenant = ConfigurationRepository.lookup().isValidTenant(tenant) ? tenant.toUpperCase()
156 : Constants.DEFAULT_TENANT;
157 namespace = ConfigurationRepository.lookup().isValidNamespace(namespace) ? namespace.toUpperCase()
158 : Constants.DEFAULT_NAMESPACE;
160 returnValue = (T) getInternal(tenant, namespace, key, clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
161 hints == null || hints.length == 0 ? new Hint[] {Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC} : hints);
162 if ((returnValue == null || ConfigurationUtils.isZeroLengthArray(clazz, returnValue))
163 && !Constants.DEFAULT_TENANT.equals(tenant)) {
164 returnValue = (T) getInternal(Constants.DEFAULT_TENANT, namespace, key,
165 clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
166 hints == null || hints.length == 0 ? new Hint[] {Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC} : hints);
168 if ((returnValue == null || ConfigurationUtils.isZeroLengthArray(clazz, returnValue))
169 && !Constants.DEFAULT_NAMESPACE.equals(namespace)) {
170 returnValue = (T) getInternal(tenant, Constants.DEFAULT_NAMESPACE, key,
171 clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
172 hints == null || hints.length == 0 ? new Hint[] {Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC} : hints);
174 if ((returnValue == null || ConfigurationUtils.isZeroLengthArray(clazz, returnValue))
175 && !Constants.DEFAULT_NAMESPACE.equals(namespace) && !Constants.DEFAULT_TENANT.equals(tenant)) {
176 returnValue = (T) getInternal(Constants.DEFAULT_TENANT, Constants.DEFAULT_NAMESPACE, key,
177 clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
178 hints == null || hints.length == 0 ? new Hint[] {Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC} : hints);
180 if (returnValue == null && clazz.isPrimitive()) {
181 return (T) ConfigurationUtils.getDefaultFor(clazz);
188 public <T> Map<String, T> populateMap(String tenantId, String namespace, String key, Class<T> clazz) {
189 if (tenantId == null || tenantId.trim().length() == 0) {
190 tenantId = tenant.get();
192 tenantId = tenantId.toUpperCase();
194 if (namespace == null || namespace.trim().length() == 0) {
195 namespace = Constants.DEFAULT_NAMESPACE;
197 namespace = namespace.toUpperCase();
199 Map<String, T> map = new HashMap<>();
200 Iterator<String> keys;
202 keys = ConfigurationRepository.lookup().getConfigurationFor(tenantId, namespace).getKeys(key);
203 while (keys.hasNext()) {
204 String k = keys.next();
205 if (k.startsWith(key + ".")) {
206 k = k.substring(key.length() + 1);
207 String subkey = k.substring(0, k.indexOf("."));
208 if (!map.containsKey(subkey)) {
209 map.put(subkey, get(tenantId, namespace, key + "." + subkey, clazz));
213 } catch (Exception e) {
220 public Map generateMap(String tenantId, String namespace, String key) {
221 if (tenantId == null || tenantId.trim().length() == 0) {
222 tenantId = tenant.get();
224 tenantId = tenantId.toUpperCase();
226 if (namespace == null || namespace.trim().length() == 0) {
227 namespace = Constants.DEFAULT_NAMESPACE;
229 namespace = namespace.toUpperCase();
232 Map parentMap = new HashMap<>();
233 Iterator<String> keys;
235 if (key == null || key.trim().length() == 0) {
236 keys = ConfigurationRepository.lookup().getConfigurationFor(tenantId, namespace).getKeys();
238 keys = ConfigurationRepository.lookup().getConfigurationFor(tenantId, namespace).getKeys(key);
240 while (keys.hasNext()) {
242 String k = keys.next();
244 if (key != null && key.trim().length() != 0 && !k.startsWith(key + ".")) {
247 String value = getAsString(tenantId, namespace, k);
248 if (key != null && key.trim().length() != 0 && k.startsWith(key + ".")) {
249 k = k.substring(key.trim().length() + 1);
252 while (k.contains(".")) {
253 if (k.contains(".")) {
254 String subkey = k.substring(0, k.indexOf("."));
255 k = k.substring(k.indexOf(".") + 1);
256 if (!map.containsKey(subkey)) {
257 map.put(subkey, map = new HashMap<>());
259 map = (Map) map.get(subkey);
265 } catch (Exception e) {
271 protected <T> T getInternal(String tenant, String namespace, String key, Class<T> clazz, Hint... hints) {
272 int processingHints = Hint.DEFAULT.value();
274 for (Hint hint : hints) {
275 processingHints = processingHints | hint.value();
279 if (tenant == null || tenant.trim().length() == 0) {
280 tenant = ConfigurationImpl.tenant.get();
282 tenant = tenant.toUpperCase();
284 if (namespace == null || namespace.trim().length() == 0) {
285 namespace = Constants.DEFAULT_NAMESPACE;
287 namespace = namespace.toUpperCase();
289 if ((key == null || key.trim().length() == 0) && !clazz.isAnnotationPresent(Config.class)) {
290 throw new IllegalArgumentException(KEY_CANNOT_BE_NULL);
293 throw new IllegalArgumentException("clazz is null.");
295 if (clazz.isPrimitive()) {
296 clazz = getWrapperClass(clazz);
299 if (ConfigurationUtils.isWrapperClass(clazz) || clazz.isPrimitive()) {
300 Object obj = ConfigurationUtils.getProperty(
301 ConfigurationRepository.lookup().getConfigurationFor(tenant, namespace), key, processingHints);
303 if (ConfigurationUtils.isCollection(obj.toString())) {
304 obj = ConfigurationUtils.getCollectionString(obj.toString());
306 String value = obj.toString().split(",")[0];
307 value = ConfigurationUtils.processVariablesIfPresent(tenant, namespace, value);
308 return (T) getValue(value, clazz.isPrimitive() ? getWrapperClass(clazz) : clazz, processingHints);
312 } else if (clazz.isArray() && (clazz.getComponentType().isPrimitive() || ConfigurationUtils.isWrapperClass(
313 clazz.getComponentType()))) {
314 Object obj = ConfigurationUtils.getProperty(
315 ConfigurationRepository.lookup().getConfigurationFor(tenant, namespace), key, processingHints);
317 Class componentClass = clazz.getComponentType();
318 if (clazz.getComponentType().isPrimitive()) {
319 componentClass = getWrapperClass(clazz.getComponentType());
321 String collString = ConfigurationUtils.getCollectionString(obj.toString());
322 ArrayList<String> tempCollection = new ArrayList<>();
323 for (String itemValue : collString.split(",")) {
324 tempCollection.add(ConfigurationUtils.processVariablesIfPresent(tenant, namespace, itemValue));
326 Collection<T> collection =
327 convert(ConfigurationUtils.getCollectionString(Arrays.toString(tempCollection.toArray())),
328 componentClass, processingHints);
329 if (clazz.getComponentType().isPrimitive()) {
330 return (T) ConfigurationUtils.getPrimitiveArray(collection, clazz.getComponentType());
332 return (T) collection.toArray(getZeroLengthArrayFor(getWrapperClass(clazz.getComponentType())));
337 } else if (clazz.isAnnotationPresent(Config.class)) {
338 return read(tenant, namespace, clazz, (key == null || key.trim().length() == 0) ? "" : (key + "."),
341 throw new IllegalArgumentException(
342 "Only primitive classes, wrapper classes, corresponding array classes and any "
343 + "class decorated with @org.openecomp.config.api.Config are allowed as argument.");
345 } catch (Exception exception) {
346 exception.printStackTrace();
351 private <T> T read(String tenant, String namespace, Class<T> clazz, String keyPrefix, Hint... hints)
353 Config confAnnotation = clazz.getAnnotation(Config.class);
354 if (confAnnotation != null && confAnnotation.key().length() > 0 && !keyPrefix.endsWith(".")) {
355 keyPrefix += (confAnnotation.key() + ".");
357 Constructor<T> constructor = clazz.getDeclaredConstructor();
358 constructor.setAccessible(true);
359 T objToReturn = constructor.newInstance();
360 for (Field field : clazz.getDeclaredFields()) {
361 field.setAccessible(true);
362 Config fieldConfAnnotation = field.getAnnotation(Config.class);
363 if (fieldConfAnnotation != null) {
364 if (field.getType().isPrimitive() || ConfigurationUtils.isWrapperClass(field.getType()) || (
365 field.getType().isArray() && (field.getType().getComponentType().isPrimitive()
366 || ConfigurationUtils.isWrapperClass(
367 field.getType().getComponentType())))
368 || field.getType().getAnnotation(Config.class) != null) {
369 field.set(objToReturn,
370 get(tenant, namespace, keyPrefix + fieldConfAnnotation.key(), field.getType(), hints));
371 } else if (Collection.class.isAssignableFrom(field.getType())) {
372 Object obj = get(tenant, namespace, keyPrefix + fieldConfAnnotation.key(),
373 ConfigurationUtils.getArrayClass(ConfigurationUtils.getCollectionGenericType(field)),
376 List list = Arrays.asList((Object[]) obj);
377 Class clazzToInstantiate;
378 if (field.getType().isInterface()) {
379 clazzToInstantiate = ConfigurationUtils.getConcreteCollection(field.getType()).getClass();
380 } else if (Modifier.isAbstract(field.getType().getModifiers())) {
382 ConfigurationUtils.getCompatibleCollectionForAbstractDef(field.getType())
385 clazzToInstantiate = field.getType();
387 Constructor construct = getConstructorWithArguments(clazzToInstantiate, Collection.class);
388 if (construct != null) {
389 construct.setAccessible(true);
390 field.set(objToReturn, construct.newInstance(list));
391 } else if ((construct = getConstructorWithArguments(clazzToInstantiate, Integer.class,
392 Boolean.class, Collection.class)) != null) {
393 construct.setAccessible(true);
394 field.set(objToReturn, construct.newInstance(list.size(), true, list));
397 } else if (Map.class.isAssignableFrom(field.getType())) {
398 field.set(objToReturn, generateMap(tenant, namespace, keyPrefix + fieldConfAnnotation.key()));
405 private Constructor getConstructorWithArguments(Class clazz, Class... classes) {
407 return clazz.getDeclaredConstructor(classes);
408 } catch (Exception exception) {
413 private Class getWrapperClass(Class clazz) {
414 if (byte.class == clazz) {
416 } else if (short.class == clazz) {
418 } else if (int.class == clazz) {
419 return Integer.class;
420 } else if (long.class == clazz) {
422 } else if (float.class == clazz) {
424 } else if (double.class == clazz) {
426 } else if (char.class == clazz) {
427 return Character.class;
428 } else if (boolean.class == clazz) {
429 return Boolean.class;
434 private <T> T getValue(Object obj, Class<T> clazz, int processingHint) {
435 if (obj == null || obj.toString().trim().length() == 0) {
438 obj = obj.toString().trim();
440 if (String.class.equals(clazz)) {
441 if (obj.toString().startsWith("@") && ConfigurationUtils.isExternalLookup(processingHint)) {
442 String contents = ConfigurationUtils.getFileContents(
443 NonConfigResource.locate(obj.toString().substring(1).trim()));
444 if (contents == null) {
445 contents = ConfigurationUtils.getFileContents(obj.toString().substring(1).trim());
447 if (contents != null) {
451 return (T) obj.toString();
452 } else if (Number.class.isAssignableFrom(clazz)) {
453 Double doubleValue = Double.valueOf(obj.toString());
454 switch (clazz.getName()) {
455 case "java.lang.Byte":
456 Byte byteVal = doubleValue.byteValue();
458 case "java.lang.Short":
459 Short shortVal = doubleValue.shortValue();
461 case "java.lang.Integer":
462 Integer intVal = doubleValue.intValue();
464 case "java.lang.Long":
465 Long longVal = doubleValue.longValue();
467 case "java.lang.Float":
468 Float floatVal = doubleValue.floatValue();
470 case "java.lang.Double":
471 return (T) doubleValue;
474 } else if (Boolean.class.equals(clazz)) {
475 return (T) Boolean.valueOf(obj.toString());
476 } else if (Character.class.equals(clazz)) {
477 return (T) Character.valueOf(obj.toString().charAt(0));
482 private <T> T[] getZeroLengthArrayFor(Class<T> clazz) {
484 if (clazz == int.class) {
486 } else if (clazz == byte.class) {
488 } else if (clazz == short.class) {
489 obj = new short[] {};
490 } else if (clazz == long.class) {
492 } else if (clazz == float.class) {
493 obj = new float[] {};
494 } else if (clazz == double.class) {
495 obj = new double[] {};
496 } else if (clazz == boolean.class) {
497 obj = new boolean[] {};
498 } else if (clazz == char.class) {
500 } else if (clazz == Byte.class) {
502 } else if (clazz == Short.class) {
503 obj = new Short[] {};
504 } else if (clazz == Integer.class) {
505 obj = new Integer[] {};
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 == Character.class) {
515 obj = new Character[] {};
516 } else if (clazz == String.class) {
517 obj = new String[] {};
522 private <T> Collection<T> convert(String commaSaperatedValues, Class<T> clazz, int processingHints) {
523 ArrayList<T> collection = new ArrayList<>();
524 for (String value : commaSaperatedValues.split(",")) {
526 T type1 = getValue(value, clazz, processingHints);
528 collection.add(type1);
530 } catch (RuntimeException re) {