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.ConfigurationChangeListener;
38 import org.onap.config.api.Hint;
41 * The type Configuration.
43 public class ConfigurationImpl implements org.onap.config.api.Configuration {
45 private static final String KEY_CANNOT_BE_NULL = "Key can't be null.";
46 private static ThreadLocal<String> tenant = new ThreadLocal<String>() {
49 protected String initialValue() {
50 return Constants.DEFAULT_TENANT;
55 private static boolean instantiated = false;
57 * The Change notifier.
59 ConfigurationChangeNotifier changeNotifier;
62 * Instantiates a new Configuration.
64 * @throws Exception the exception
66 public ConfigurationImpl() throws Exception {
67 if (instantiated || !CliConfigurationImpl.class.isAssignableFrom(this.getClass())) {
68 throw new RuntimeException("Illegal access to configuration.");
70 Map<String, AggregateConfiguration> moduleConfigStore = new HashMap<>();
71 List<URL> classpathResources = ConfigurationUtils.getAllClassPathResources();
72 Predicate<URL> predicate = ConfigurationUtils::isConfig;
73 for (URL url : classpathResources) {
74 if (predicate.test(url)) {
75 String moduleName = ConfigurationUtils.getConfigurationRepositoryKey(url);
76 AggregateConfiguration moduleConfig = moduleConfigStore.get(moduleName);
77 if (moduleConfig == null) {
78 moduleConfig = new AggregateConfiguration();
79 moduleConfigStore.put(moduleName, moduleConfig);
81 moduleConfig.addConfig(url);
83 NonConfigResource.add(url);
86 String configLocation = System.getProperty("config.location");
87 if (configLocation != null && configLocation.trim().length() > 0) {
88 File root = new File(configLocation);
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.getConfigurationRepositoryKey(file);
94 AggregateConfiguration moduleConfig = moduleConfigStore.get(moduleName);
95 if (moduleConfig == null) {
96 moduleConfig = new AggregateConfiguration();
97 moduleConfigStore.put(moduleName, moduleConfig);
99 moduleConfig.addConfig(file);
101 NonConfigResource.add(file);
105 String tenantConfigLocation = System.getProperty("tenant.config.location");
106 if (tenantConfigLocation != null && tenantConfigLocation.trim().length() > 0) {
107 File root = new File(tenantConfigLocation);
108 Collection<File> tenantsRoot = ConfigurationUtils.getAllFiles(root, false, true);
109 Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
110 Predicate<File> filePredicate = ConfigurationUtils::isConfig;
111 for (File file : filesystemResources) {
112 if (filePredicate.test(file)) {
113 String moduleName = ConfigurationUtils.getNamespace(file);
114 for (File tenanatFileRoot : tenantsRoot) {
115 if (file.getAbsolutePath().startsWith(tenanatFileRoot.getAbsolutePath())) {
116 moduleName = ConfigurationUtils.getConfigurationRepositoryKey(
117 (tenanatFileRoot.getName().toUpperCase() + Constants.TENANT_NAMESPACE_SAPERATOR
118 + moduleName).split(Constants.TENANT_NAMESPACE_SAPERATOR));
121 AggregateConfiguration moduleConfig = moduleConfigStore.get(moduleName);
122 if (moduleConfig == null) {
123 moduleConfig = new AggregateConfiguration();
124 moduleConfigStore.put(moduleName, moduleConfig);
126 moduleConfig.addConfig(file);
130 populateFinalConfigurationIncrementally(moduleConfigStore);
131 ConfigurationRepository.lookup().initTenantsAndNamespaces();
132 String nodeConfigLocation = System.getProperty("node.config.location");
133 if (nodeConfigLocation != null && nodeConfigLocation.trim().length() > 0) {
134 File root = new File(nodeConfigLocation);
135 Collection<File> filesystemResources = ConfigurationUtils.getAllFiles(root, true, false);
136 Predicate<File> filePredicate = ConfigurationUtils::isConfig;
137 for (File file : filesystemResources) {
138 if (filePredicate.test(file)) {
139 ConfigurationRepository.lookup().populateOverrideConfigurtaion(
140 ConfigurationUtils.getConfigurationRepositoryKey(ConfigurationUtils.getNamespace(file)
141 .split(Constants.TENANT_NAMESPACE_SAPERATOR)), file);
146 changeNotifier = new ConfigurationChangeNotifier(moduleConfigStore);
150 public void addConfigurationChangeListener(String tenant, String namespace, String key,
151 ConfigurationChangeListener myself) {
152 tenant = ConfigurationRepository.lookup().isValidTenant(tenant) ? tenant.toUpperCase()
153 : Constants.DEFAULT_TENANT;
155 ConfigurationRepository.lookup().isValidNamespace(namespace) ? namespace.toUpperCase()
156 : Constants.DEFAULT_NAMESPACE;
157 if (key == null || key.trim().length() == 0) {
158 throw new IllegalArgumentException(KEY_CANNOT_BE_NULL);
160 if (myself == null) {
161 throw new IllegalArgumentException("ConfigurationChangeListener instance is null.");
164 changeNotifier.notifyChangesTowards(tenant, namespace, key, myself);
165 } catch (Exception exception) {
166 exception.printStackTrace();
170 private void populateFinalConfigurationIncrementally(Map<String, AggregateConfiguration> configs) {
173 Constants.DEFAULT_TENANT + Constants.KEY_ELEMENTS_DELEMETER + Constants.DB_NAMESPACE)
175 ConfigurationRepository.lookup().populateConfigurtaion(
176 Constants.DEFAULT_TENANT + Constants.KEY_ELEMENTS_DELEMETER + Constants.DB_NAMESPACE,
178 Constants.DEFAULT_TENANT + Constants.KEY_ELEMENTS_DELEMETER + Constants.DB_NAMESPACE)
179 .getFinalConfiguration());
182 Set<String> modules = configs.keySet();
183 for (String module : modules) {
184 ConfigurationRepository.lookup()
185 .populateConfigurtaion(module, configs.get(module).getFinalConfiguration());
190 public <T> T get(String tenant, String namespace, String key, Class<T> clazz, Hint... hints) {
192 String[] tenantNamespaceArrayy;
193 if (tenant == null && namespace != null) {
194 tenantNamespaceArrayy = namespace.split(Constants.TENANT_NAMESPACE_SAPERATOR);
195 if (tenantNamespaceArrayy.length > 1) {
196 tenant = tenantNamespaceArrayy[0];
197 namespace = tenantNamespaceArrayy[1];
201 tenant = ConfigurationRepository.lookup().isValidTenant(tenant) ? tenant.toUpperCase()
202 : Constants.DEFAULT_TENANT;
204 ConfigurationRepository.lookup().isValidNamespace(namespace) ? namespace.toUpperCase()
205 : Constants.DEFAULT_NAMESPACE;
206 T returnValue = null;
207 returnValue = (T) getInternal(tenant, namespace, key,
208 clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
209 hints == null || hints.length == 0 ? new Hint[]{Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC}
211 if ((returnValue == null || ConfigurationUtils.isZeroLengthArray(clazz, returnValue))
212 && !Constants.DEFAULT_TENANT.equals(tenant)) {
213 returnValue = (T) getInternal(Constants.DEFAULT_TENANT, namespace, key,
214 clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
215 hints == null || hints.length == 0 ? new Hint[]{Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC}
218 if ((returnValue == null || ConfigurationUtils.isZeroLengthArray(clazz, returnValue))
219 && !Constants.DEFAULT_NAMESPACE.equals(namespace)) {
220 returnValue = (T) getInternal(tenant, Constants.DEFAULT_NAMESPACE, key,
221 clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
222 hints == null || hints.length == 0 ? new Hint[]{Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC}
225 if ((returnValue == null || ConfigurationUtils.isZeroLengthArray(clazz, returnValue))
226 && !Constants.DEFAULT_NAMESPACE.equals(namespace)
227 && !Constants.DEFAULT_TENANT.equals(tenant)) {
228 returnValue = (T) getInternal(Constants.DEFAULT_TENANT, Constants.DEFAULT_NAMESPACE, key,
229 clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
230 hints == null || hints.length == 0 ? new Hint[]{Hint.EXTERNAL_LOOKUP, Hint.NODE_SPECIFIC}
233 if (returnValue == null && clazz.isPrimitive()) {
234 return (T) ConfigurationUtils.getDefaultFor(clazz);
244 * @param <T> the type parameter
245 * @param tenant the tenant
246 * @param namespace the namespace
248 * @param clazz the clazz
249 * @param hints the hints
250 * @return the internal
252 protected <T> T getInternal(String tenant, String namespace, String key, Class<T> clazz,
254 int processingHints = Hint.DEFAULT.value();
256 for (Hint hint : hints) {
257 processingHints = processingHints | hint.value();
261 if (tenant == null || tenant.trim().length() == 0) {
262 tenant = ConfigurationImpl.tenant.get();
264 tenant = tenant.toUpperCase();
266 if (namespace == null || namespace.trim().length() == 0) {
267 namespace = Constants.DEFAULT_NAMESPACE;
269 namespace = namespace.toUpperCase();
271 if ((key == null || key.trim().length() == 0) && !clazz.isAnnotationPresent(Config.class)) {
272 throw new IllegalArgumentException(KEY_CANNOT_BE_NULL);
275 throw new IllegalArgumentException("clazz is null.");
277 if (clazz.isPrimitive()) {
278 clazz = getWrapperClass(clazz);
281 if (ConfigurationUtils.isWrapperClass(clazz) || clazz.isPrimitive()) {
284 .getProperty(ConfigurationRepository.lookup().getConfigurationFor(tenant, namespace),
285 key, processingHints);
287 if (ConfigurationUtils.isCollection(obj.toString())) {
288 obj = ConfigurationUtils.getCollectionString(obj.toString());
290 String value = obj.toString().split(",")[0];
291 value = ConfigurationUtils.processVariablesIfPresent(tenant, namespace, value);
292 return (T) getValue(value, clazz.isPrimitive() ? getWrapperClass(clazz) : clazz,
297 } else if (clazz.isArray()
298 && (clazz.getComponentType().isPrimitive() || ConfigurationUtils.isWrapperClass(clazz.getComponentType()))) {
301 .getProperty(ConfigurationRepository.lookup().getConfigurationFor(tenant, namespace),
302 key, processingHints);
304 Class componentClass = clazz.getComponentType();
305 if (clazz.getComponentType().isPrimitive()) {
306 componentClass = getWrapperClass(clazz.getComponentType());
308 String collString = ConfigurationUtils.getCollectionString(obj.toString());
309 ArrayList<String> tempCollection = new ArrayList<>();
310 for (String itemValue : collString.split(",")) {
312 .add(ConfigurationUtils.processVariablesIfPresent(tenant, namespace, itemValue));
314 Collection<T> collection = convert(
315 ConfigurationUtils.getCollectionString(Arrays.toString(tempCollection.toArray())),
316 componentClass, processingHints);
317 if (clazz.getComponentType().isPrimitive()) {
318 return (T) ConfigurationUtils.getPrimitiveArray(collection, clazz.getComponentType());
320 return (T) collection
321 .toArray(getZeroLengthArrayFor(getWrapperClass(clazz.getComponentType())));
326 } else if (clazz.isAnnotationPresent(Config.class)) {
327 return read(tenant, namespace, clazz,
328 (key == null || key.trim().length() == 0) ? "" : (key + "."), hints);
330 throw new IllegalArgumentException(
331 "Only pimitive classes, wrapper classes, corresponding array classes and any "
332 + "class decorated with @org.openecomp.config.api.Config are allowed as argument.");
334 } catch (Exception exception) {
335 exception.printStackTrace();
341 private <T> T read(String tenant, String namespace, Class<T> clazz, String keyPrefix,
342 Hint... hints) throws Exception {
344 clazz.getAnnotation(Config.class);
345 if (confAnnot != null && confAnnot.key().length()>0 && !keyPrefix.endsWith(".")) {
346 keyPrefix += (confAnnot.key() + ".");
348 Constructor<T> constructor = clazz.getDeclaredConstructor();
349 constructor.setAccessible(true);
350 T objToReturn = constructor.newInstance();
351 for (Field field : clazz.getDeclaredFields()) {
352 field.setAccessible(true);
353 Config fieldConfAnnot =
354 field.getAnnotation(Config.class);
355 if (fieldConfAnnot != null) {
356 if (field.getType().isPrimitive() || ConfigurationUtils.isWrapperClass(field.getType())
357 || (field.getType().isArray() && (field.getType().getComponentType().isPrimitive()
358 || ConfigurationUtils.isWrapperClass(field.getType().getComponentType())))
359 || field.getType().getAnnotation(Config.class) != null) {
360 field.set(objToReturn,
361 get(tenant, namespace, keyPrefix + fieldConfAnnot.key(), field.getType(), hints));
362 } else if (Collection.class.isAssignableFrom(field.getType())) {
363 Object obj = get(tenant, namespace, keyPrefix + fieldConfAnnot.key(),
364 ConfigurationUtils.getArrayClass(ConfigurationUtils.getCollectionGenericType(field)),
367 List list = Arrays.asList((Object[]) obj);
368 Class clazzToInstantiate = null;
369 if (field.getType().isInterface()) {
371 ConfigurationUtils.getConcreteCollection(field.getType()).getClass();
372 } else if (Modifier.isAbstract(field.getType().getModifiers())) {
374 ConfigurationUtils.getCompatibleCollectionForAbstractDef(field.getType())
377 clazzToInstantiate = field.getType();
379 Constructor construct =
380 getConstructorWithArguments(clazzToInstantiate, Collection.class);
381 if (construct != null) {
382 construct.setAccessible(true);
383 field.set(objToReturn, construct.newInstance(list));
384 } else if ((construct =
385 getConstructorWithArguments(clazzToInstantiate, Integer.class, Boolean.class,
386 Collection.class)) != null) {
387 construct.setAccessible(true);
388 field.set(objToReturn, construct.newInstance(list.size(), true, list));
391 }else if (Map.class.isAssignableFrom(field.getType())){
392 field.set(objToReturn, generateMap(tenant, namespace, keyPrefix+fieldConfAnnot.key()));
399 private Constructor getConstructorWithArguments(Class clazz, Class... classes) {
401 return clazz.getDeclaredConstructor(classes);
402 } catch (Exception exception) {
407 private Class getWrapperClass(Class clazz) {
408 if (byte.class == clazz) {
410 } else if (short.class == clazz) {
412 } else if (int.class == clazz) {
413 return Integer.class;
414 } else if (long.class == clazz) {
416 } else if (float.class == clazz) {
418 } else if (double.class == clazz) {
420 } else if (char.class == clazz) {
421 return Character.class;
422 } else if (boolean.class == clazz) {
423 return Boolean.class;
428 private <T> T getValue(Object obj, Class<T> clazz, int processingHint) {
429 if (obj == null || obj.toString().trim().length() == 0) {
432 obj = obj.toString().trim();
434 if (String.class.equals(clazz)) {
435 if (obj.toString().startsWith("@") && ConfigurationUtils.isExternalLookup(processingHint)) {
436 String contents = ConfigurationUtils
437 .getFileContents(NonConfigResource.locate(obj.toString().substring(1).trim()));
438 if (contents == null) {
439 contents = ConfigurationUtils.getFileContents(obj.toString().substring(1).trim());
441 if (contents != null) {
445 return (T) obj.toString();
446 } else if (Number.class.isAssignableFrom(clazz)) {
447 Double doubleValue = Double.valueOf(obj.toString());
448 switch (clazz.getName()) {
449 case "java.lang.Byte":
450 Byte byteVal = doubleValue.byteValue();
452 case "java.lang.Short":
453 Short shortVal = doubleValue.shortValue();
455 case "java.lang.Integer":
456 Integer intVal = doubleValue.intValue();
458 case "java.lang.Long":
459 Long longVal = doubleValue.longValue();
461 case "java.lang.Float":
462 Float floatVal = doubleValue.floatValue();
464 case "java.lang.Double":
465 Double doubleVal = doubleValue;
466 return (T) doubleVal;
469 } else if (Boolean.class.equals(clazz)) {
470 return (T) Boolean.valueOf(obj.toString());
471 } else if (Character.class.equals(clazz)) {
472 return (T) Character.valueOf(obj.toString().charAt(0));
477 private <T> T[] getZeroLengthArrayFor(Class<T> clazz) {
479 if (clazz == int.class) {
481 } else if (clazz == byte.class) {
483 } else if (clazz == short.class) {
485 } else if (clazz == long.class) {
487 } else if (clazz == float.class) {
489 } else if (clazz == double.class) {
490 obj = new double[]{};
491 } else if (clazz == boolean.class) {
492 obj = new boolean[]{};
493 } else if (clazz == char.class) {
495 } else if (clazz == Byte.class) {
497 } else if (clazz == Short.class) {
499 } else if (clazz == Integer.class) {
500 obj = new Integer[]{};
501 } else if (clazz == Long.class) {
503 } else if (clazz == Float.class) {
505 } else if (clazz == Double.class) {
506 obj = new Double[]{};
507 } else if (clazz == Boolean.class) {
508 obj = new Boolean[]{};
509 } else if (clazz == Character.class) {
510 obj = new Character[]{};
511 } else if (clazz == String.class) {
512 obj = new String[]{};
517 private <T> Collection<T> convert(String commaSaperatedValues, Class<T> clazz,
518 int processingHints) {
519 ArrayList<T> collection = new ArrayList<>();
520 for (String value : commaSaperatedValues.split(",")) {
522 T type1 = getValue(value, clazz, processingHints);
524 collection.add(type1);
526 } catch (RuntimeException re) {
536 public void shutdown() {
537 if (changeNotifier != null) {
539 changeNotifier.shutdown();
540 } catch (Exception exception) {
541 exception.printStackTrace();
547 public void removeConfigurationChangeListener(String tenant, String namespace, String key,
548 ConfigurationChangeListener myself) {
549 tenant = ConfigurationRepository.lookup().isValidTenant(tenant) ? tenant.toUpperCase()
550 : Constants.DEFAULT_TENANT;
552 ConfigurationRepository.lookup().isValidNamespace(namespace) ? namespace.toUpperCase()
553 : Constants.DEFAULT_NAMESPACE;
554 if (key == null || key.trim().length() == 0) {
555 throw new IllegalArgumentException(KEY_CANNOT_BE_NULL);
558 changeNotifier.stopNotificationTowards(tenant, namespace, key, myself);
559 } catch (Exception exception) {
560 exception.printStackTrace();
565 public <T> Map<String, T> populateMap(String tenantId, String namespace, String key, Class<T> clazz){
566 if (tenantId==null || tenantId.trim().length()==0){
567 tenantId = tenant.get();
569 tenantId = tenantId.toUpperCase();
571 if (namespace==null || namespace.trim().length()==0){
572 namespace = Constants.DEFAULT_NAMESPACE;
574 namespace = namespace.toUpperCase();
576 Map<String, T> map = new HashMap<>();
577 Iterator<String> keys ;
579 keys = ConfigurationRepository.lookup().getConfigurationFor(tenantId, namespace).getKeys(key);
580 while(keys.hasNext()){
581 String k = keys.next();
582 if (k.startsWith(key+".")){
583 k = k.substring(key.length()+1);
584 String subkey = k.substring(0, k.indexOf("."));
585 if (!map.containsKey(subkey)){
586 map.put(subkey, get(tenantId, namespace, key+"."+subkey, clazz));
590 }catch (Exception e){
597 public Map generateMap(String tenantId, String namespace, String key){
598 if (tenantId==null || tenantId.trim().length()==0){
599 tenantId = tenant.get();
601 tenantId = tenantId.toUpperCase();
603 if (namespace==null || namespace.trim().length()==0){
604 namespace = Constants.DEFAULT_NAMESPACE;
606 namespace = namespace.toUpperCase();
608 Map map, parentMap = new HashMap<>();
609 Iterator<String> keys ;
611 if (key==null || key.trim().length()==0){
612 keys = ConfigurationRepository.lookup().getConfigurationFor(tenantId, namespace).getKeys();
614 keys = ConfigurationRepository.lookup().getConfigurationFor(tenantId, namespace).getKeys(key);
616 while(keys.hasNext()){
618 String k = keys.next();
620 if (key!=null && key.trim().length()!=0 && !k.startsWith(key+".")){
623 String value = getAsString(tenantId, namespace, k);
624 if (key!=null && key.trim().length()!=0 && k.startsWith(key+".")){
625 k = k.substring(key.trim().length()+1);
628 while(k.contains(".")){
629 if (k.contains(".")){
630 String subkey = k.substring(0, k.indexOf("."));
631 k = k.substring(k.indexOf(".")+1);
632 if (!map.containsKey(subkey)){
633 map.put(subkey, map=new HashMap<>());
635 map = (Map)map.get(subkey);
641 }catch (Exception e){