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.sql.Timestamp;
 
  21 import java.util.ArrayList;
 
  22 import java.util.Arrays;
 
  23 import java.util.Collection;
 
  24 import java.util.Collections;
 
  25 import java.util.HashSet;
 
  26 import java.util.LinkedHashMap;
 
  29 import org.apache.commons.configuration2.CombinedConfiguration;
 
  30 import org.apache.commons.configuration2.CompositeConfiguration;
 
  31 import org.apache.commons.configuration2.Configuration;
 
  32 import org.apache.commons.configuration2.FileBasedConfiguration;
 
  33 import org.apache.commons.configuration2.builder.BasicConfigurationBuilder;
 
  34 import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
 
  35 import org.apache.commons.configuration2.ex.ConfigurationException;
 
  36 import org.onap.config.ConfigurationUtils;
 
  37 import org.onap.config.Constants;
 
  39 public final class ConfigurationRepository {
 
  41     private static final ConfigurationRepository repo;
 
  43     private static final Set<String> validCallers = Collections.unmodifiableSet(new HashSet<>(
 
  44             Arrays.asList(ConfigurationChangeNotifier.NotificationData.class.getName(),
 
  45                     ConfigurationUtils.class.getName(), CliConfigurationImpl.class.getName(),
 
  46                     ConfigurationChangeNotifier.class.getName(), ConfigurationImpl.class.getName())));
 
  49         repo = new ConfigurationRepository();
 
  52     private final Set<String> tenants = new HashSet<>();
 
  53     private final Set<String> namespaces = new HashSet<>();
 
  54     private final LinkedHashMap<String, ConfigurationHolder> store =
 
  55             new LinkedHashMap<String, ConfigurationHolder>(16, 0.75f, true) {
 
  57                 protected boolean removeEldestEntry(Map.Entry eldest) {
 
  59                         return size() > getConfigurationFor(Constants.DEFAULT_TENANT, Constants.DB_NAMESPACE)
 
  60                                                 .getInt("config.size.max");
 
  61                     } catch (Exception exception) {
 
  67     private ConfigurationRepository() {
 
  69             throw new RuntimeException("Illegal access to configuration.");
 
  71         tenants.add(Constants.DEFAULT_TENANT);
 
  72         namespaces.add(Constants.DEFAULT_NAMESPACE);
 
  75     public static ConfigurationRepository lookup() {
 
  76         if (validCallers.contains(Thread.currentThread().getStackTrace()[2].getClassName())) {
 
  82     public Set<String> getTenants() {
 
  86     public Set<String> getNamespaces() {
 
  91     public boolean isValidTenant(String tenant) {
 
  92         return tenant != null && tenants.contains(tenant.toUpperCase());
 
  95     public boolean isValidNamespace(String namespace) {
 
  96         return namespace != null && namespaces.contains(namespace.toUpperCase());
 
  99     public Configuration getConfigurationFor(String tenant, String namespace) throws Exception {
 
 100         ConfigurationHolder config;
 
 101         String module = tenant + Constants.KEY_ELEMENTS_DELIMETER + namespace;
 
 102         config = store.get(module);
 
 103         if (config == null) {
 
 104             config = new ConfigurationHolder(new BasicConfigurationBuilder<>(AgglomerateConfiguration.class));
 
 105             store.put(module, config);
 
 107         return config.getConfiguration(tenant + Constants.KEY_ELEMENTS_DELIMETER + namespace);
 
 110     public void populateConfiguration(String key, Configuration builder) {
 
 111         store.put(key, new ConfigurationHolder(builder));
 
 112         populateTenantsNamespace(key, false);
 
 115     private void populateTenantsNamespace(String key, boolean sourcedFromDb) {
 
 116         String[] array = key.split(Constants.KEY_ELEMENTS_DELIMETER);
 
 117         if (!array[1].equalsIgnoreCase(Constants.DB_NAMESPACE)) {
 
 118             tenants.add(array[0]);
 
 119             namespaces.add(array[1]);
 
 123     public void populateOverrideConfiguration(String key, File file) {
 
 124         ConfigurationHolder holder = store.get(key);
 
 125         if (holder == null) {
 
 126             holder = new ConfigurationHolder(new CombinedConfiguration());
 
 127             store.put(key, holder);
 
 129         holder.addOverrideConfiguration(file.getAbsolutePath(), ConfigurationUtils.getConfigurationBuilder(file, true));
 
 130         populateTenantsNamespace(key, true);
 
 133     public void refreshOverrideConfigurationFor(String key, int index) {
 
 134         ConfigurationHolder holder = store.get(key);
 
 135         if (holder != null) {
 
 136             holder.refreshOverrideConfiguration(index);
 
 140     public void removeOverrideConfiguration(File file) {
 
 141         for (String s : (Iterable<String>) new ArrayList(store.keySet())) {
 
 142             ConfigurationHolder holder = store.get(s);
 
 143             if (holder.containsOverrideConfiguration(file.getAbsolutePath())) {
 
 144                 holder.removeOverrideConfiguration(file.getAbsolutePath());
 
 149     private class ConfigurationHolder {
 
 151         private final Map<String, FileBasedConfigurationBuilder<FileBasedConfiguration>> overrideConfiguration =
 
 152                 new LinkedHashMap<>();
 
 153         BasicConfigurationBuilder<Configuration> builder;
 
 154         Timestamp lastConfigurationBuildTime;
 
 155         Configuration config;
 
 156         Configuration composite;
 
 158         public ConfigurationHolder(BasicConfigurationBuilder builder) {
 
 159             this.builder = builder;
 
 162         public ConfigurationHolder(Configuration builder) {
 
 163             this.config = builder;
 
 166         public void refreshOverrideConfiguration(int index) {
 
 168             for (FileBasedConfigurationBuilder overrides : overrideConfiguration.values()) {
 
 170                     if (++count == index) {
 
 172                         overrides.resetResult();
 
 174                 } catch (ConfigurationException exception) {
 
 180         public void addOverrideConfiguration(String path, BasicConfigurationBuilder<FileBasedConfiguration> builder) {
 
 181             overrideConfiguration.put(path.toUpperCase(), (FileBasedConfigurationBuilder) builder);
 
 182             getEffectiveConfiguration(config, overrideConfiguration.values());
 
 185         private Configuration getEffectiveConfiguration(Configuration configuration,
 
 186                 Collection<FileBasedConfigurationBuilder<FileBasedConfiguration>> list) {
 
 188                 CompositeConfiguration cc = new CompositeConfiguration();
 
 189                 for (FileBasedConfigurationBuilder<FileBasedConfiguration> b : list) {
 
 190                     cc.addConfiguration(b.getConfiguration());
 
 192                 cc.addConfiguration(configuration);
 
 195             } catch (Exception exception) {
 
 200         public void removeOverrideConfiguration(String path) {
 
 201             overrideConfiguration.remove(path.toUpperCase());
 
 202             getEffectiveConfiguration(config, overrideConfiguration.values());
 
 205         public boolean containsOverrideConfiguration(String path) {
 
 206             return overrideConfiguration.containsKey(path.toUpperCase());
 
 209         public Configuration getConfiguration(String namespace) throws Exception {
 
 210             if (config == null) {
 
 211                 config = builder.getConfiguration();
 
 212                 lastConfigurationBuildTime = new Timestamp(System.currentTimeMillis());
 
 213             } else if (lastConfigurationBuildTime != null
 
 214                                && System.currentTimeMillis() - lastConfigurationBuildTime.getTime()
 
 215                                           > getConfigurationFor(Constants.DEFAULT_TENANT, Constants.DB_NAMESPACE)
 
 216                                                     .getInt("config.refresh.interval")) {
 
 217                 lastConfigurationBuildTime = new Timestamp(System.currentTimeMillis());
 
 219             if (composite == null && overrideConfiguration.size() != 0) {
 
 220                 composite = getEffectiveConfiguration(config, overrideConfiguration.values());
 
 222             return overrideConfiguration.size() == 0 ? config : composite;