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.Iterator;
27 import java.util.LinkedHashMap;
30 import org.apache.commons.configuration2.CombinedConfiguration;
31 import org.apache.commons.configuration2.CompositeConfiguration;
32 import org.apache.commons.configuration2.Configuration;
33 import org.apache.commons.configuration2.FileBasedConfiguration;
34 import org.apache.commons.configuration2.builder.BasicConfigurationBuilder;
35 import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
36 import org.apache.commons.configuration2.ex.ConfigurationException;
37 import org.onap.config.ConfigurationUtils;
38 import org.onap.config.Constants;
41 * The type Configuration repository.
43 public final class ConfigurationRepository {
48 static ConfigurationRepository repo;
49 private static Set<String> validCallers = Collections.unmodifiableSet(new HashSet<>(Arrays
50 .asList(ConfigurationChangeNotifier.NotificationData.class.getName(),
51 ConfigurationUtils.class.getName(), CliConfigurationImpl.class.getName(),
52 ConfigurationChangeNotifier.class.getName(),
53 ConfigurationImpl.class.getName())));
56 repo = new ConfigurationRepository();
59 private boolean dbAccessible = true;
60 private Set<String> tenants = new HashSet<>();
61 private Set<String> namespaces = new HashSet<>();
62 private LinkedHashMap<String, ConfigurationHolder> store =
63 new LinkedHashMap<String, ConfigurationHolder>(16, 0.75f, true) {
65 protected boolean removeEldestEntry(Map.Entry eldest) {
67 return size() > getConfigurationFor(Constants.DEFAULT_TENANT, Constants.DB_NAMESPACE)
68 .getInt("config.size.max");
69 } catch (Exception exception) {
75 private ConfigurationRepository() {
77 throw new RuntimeException("Illegal access to configuration.");
79 tenants.add(Constants.DEFAULT_TENANT);
80 namespaces.add(Constants.DEFAULT_NAMESPACE);
84 * Lookup configuration repository.
86 * @return the configuration repository
88 public static ConfigurationRepository lookup() {
89 if (validCallers.contains(Thread.currentThread().getStackTrace()[2].getClassName())) {
100 public Set<String> getTenants() {
107 * @return the namespaces
109 public Set<String> getNamespaces() {
113 private void populateTenantsNamespace(String key, boolean sourcedFromDb) {
114 String[] array = key.split(Constants.KEY_ELEMENTS_DELEMETER);
115 if (!array[1].equalsIgnoreCase(Constants.DB_NAMESPACE)) {
116 if (!sourcedFromDb) {
117 dbAccessible = false;
119 tenants.add(array[0]);
120 namespaces.add(array[1]);
125 * Init tenants and namespaces.
127 public void initTenantsAndNamespaces() {
128 // nothing to do here, left for backward compatibility
132 * Is valid tenant boolean.
134 * @param tenant the tenant
135 * @return the boolean
137 public boolean isValidTenant(String tenant) {
138 return tenant != null && tenants.contains(tenant.toUpperCase());
142 * Is valid namespace boolean.
144 * @param namespace the namespace
145 * @return the boolean
147 public boolean isValidNamespace(String namespace) {
148 return namespace != null && namespaces.contains(namespace.toUpperCase());
152 * Gets configuration for.
154 * @param tenant the tenant
155 * @param namespace the namespace
156 * @return the configuration for
157 * @throws Exception the exception
159 public Configuration getConfigurationFor(String tenant, String namespace) throws Exception {
160 ConfigurationHolder config;
161 String module = tenant + Constants.KEY_ELEMENTS_DELEMETER + namespace;
162 config = store.get(module);
163 if (config == null) {
164 config = new ConfigurationHolder(new BasicConfigurationBuilder<>(AgglomerateConfiguration.class));
165 store.put(module, config);
167 return config.getConfiguration(tenant + Constants.KEY_ELEMENTS_DELEMETER + namespace);
171 * Populate configurtaion.
174 * @param builder the builder
176 public void populateConfigurtaion(String key, Configuration builder) {
177 store.put(key, new ConfigurationHolder(builder));
178 populateTenantsNamespace(key, false);
182 * Populate override configurtaion.
185 * @param file the file
186 * @throws Exception the exception
188 public void populateOverrideConfigurtaion(String key, File file) {
189 ConfigurationHolder holder = store.get(key);
190 if (holder == null) {
191 holder = new ConfigurationHolder(new CombinedConfiguration());
192 store.put(key, holder);
194 holder.addOverrideConfiguration(file.getAbsolutePath(),
195 ConfigurationUtils.getConfigurationBuilder(file, true));
196 populateTenantsNamespace(key, true);
200 * Refresh override configurtaion for.
203 * @param index the index
204 * @throws Exception the exception
206 public void refreshOverrideConfigurtaionFor(String key, int index) {
207 ConfigurationHolder holder = store.get(key);
208 if (holder != null) {
209 holder.refreshOverrideConfiguration(index);
214 * Remove override configurtaion.
216 * @param file the file
217 * @throws Exception the exception
219 public void removeOverrideConfigurtaion(File file) throws Exception {
220 Iterator<String> iterator = new ArrayList(store.keySet()).iterator();
221 while (iterator.hasNext()) {
222 ConfigurationHolder holder = store.get(iterator.next());
223 if (holder.containsOverrideConfiguration(file.getAbsolutePath())) {
224 holder.removeOverrideConfiguration(file.getAbsolutePath());
230 private class ConfigurationHolder {
235 BasicConfigurationBuilder<Configuration> builder;
237 * The Last configuration build time.
239 Timestamp lastConfigurationBuildTime;
243 Configuration config;
247 Configuration composite;
249 * The Last config change timestamp.
251 Timestamp lastConfigChangeTimestamp;
252 private Map<String, FileBasedConfigurationBuilder<FileBasedConfiguration>>
253 overrideConfiguration = new LinkedHashMap<>();
257 * Instantiates a new Configuration holder.
259 * @param builder the builder
261 public ConfigurationHolder(BasicConfigurationBuilder builder) {
262 this.builder = builder;
266 * Instantiates a new Configuration holder.
268 * @param builder the builder
270 public ConfigurationHolder(Configuration builder) {
271 this.config = builder;
275 * Refresh override configuration.
277 * @param index the index
279 public void refreshOverrideConfiguration(int index) {
281 for (FileBasedConfigurationBuilder overrides : overrideConfiguration.values()) {
283 if (++count == index) {
285 overrides.resetResult();
287 } catch (ConfigurationException exception) {
294 * Add override configuration.
296 * @param path the path
297 * @param builder the builder
299 public void addOverrideConfiguration(String path,
300 BasicConfigurationBuilder<FileBasedConfiguration> builder) {
301 overrideConfiguration.put(path.toUpperCase(), (FileBasedConfigurationBuilder) builder);
302 getEffectiveConfiguration(config, overrideConfiguration.values());
306 * Remove override configuration.
308 * @param path the path
310 public void removeOverrideConfiguration(String path) {
311 overrideConfiguration.remove(path.toUpperCase());
312 getEffectiveConfiguration(config, overrideConfiguration.values());
316 * Contains override configuration boolean.
318 * @param path the path
319 * @return the boolean
321 public boolean containsOverrideConfiguration(String path) {
322 return overrideConfiguration.containsKey(path.toUpperCase());
326 * Gets configuration.
328 * @param namespace the namespace
329 * @return the configuration
330 * @throws Exception the exception
332 public Configuration getConfiguration(String namespace) throws Exception {
333 if (config == null) {
334 config = builder.getConfiguration();
335 lastConfigurationBuildTime = new Timestamp(System.currentTimeMillis());
336 } else if (lastConfigurationBuildTime != null
337 && System.currentTimeMillis() - lastConfigurationBuildTime.getTime()
338 > getConfigurationFor(Constants.DEFAULT_TENANT, Constants.DB_NAMESPACE)
339 .getInt("config.refresh.interval")) {
340 Timestamp temp = getLastUpdateTimestampFor(namespace);
342 && (lastConfigChangeTimestamp == null
343 || temp.getTime() > lastConfigChangeTimestamp.getTime())) {
344 builder.resetResult();
345 config = builder.getConfiguration();
346 lastConfigChangeTimestamp = temp;
347 getEffectiveConfiguration(config, overrideConfiguration.values());
349 lastConfigurationBuildTime = new Timestamp(System.currentTimeMillis());
351 if (composite == null && overrideConfiguration.size() != 0) {
352 composite = getEffectiveConfiguration(config, overrideConfiguration.values());
354 return overrideConfiguration.size() == 0 ? config : composite;
357 private Configuration getEffectiveConfiguration(Configuration configuration,
358 Collection<FileBasedConfigurationBuilder<FileBasedConfiguration>> list) {
360 CompositeConfiguration cc = new CompositeConfiguration();
361 for (FileBasedConfigurationBuilder<FileBasedConfiguration> b : list) {
362 cc.addConfiguration(b.getConfiguration());
364 cc.addConfiguration(configuration);
367 } catch (Exception exception) {
373 * Gets last update timestamp for.
375 * @param namespace the namespace
376 * @return the last update timestamp for
378 public Timestamp getLastUpdateTimestampFor(String namespace) {
385 public boolean isDBAccessible(){