Code formatting of configuration framework
[sdc.git] / common / onap-common-configuration-management / onap-configuration-management-core / src / main / java / org / onap / config / impl / ConfigurationRepository.java
1 /*
2  * Copyright © 2016-2018 European Support Limited
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package org.onap.config.impl;
18
19 import java.io.File;
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;
27 import java.util.Map;
28 import java.util.Set;
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;
38
39 public final class ConfigurationRepository {
40
41     private static final ConfigurationRepository repo;
42
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())));
47
48     static {
49         repo = new ConfigurationRepository();
50     }
51
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) {
56                 @Override
57                 protected boolean removeEldestEntry(Map.Entry eldest) {
58                     try {
59                         return size() > getConfigurationFor(Constants.DEFAULT_TENANT, Constants.DB_NAMESPACE)
60                                                 .getInt("config.size.max");
61                     } catch (Exception exception) {
62                         return false;
63                     }
64                 }
65             };
66
67     private ConfigurationRepository() {
68         if (repo != null) {
69             throw new RuntimeException("Illegal access to configuration.");
70         }
71         tenants.add(Constants.DEFAULT_TENANT);
72         namespaces.add(Constants.DEFAULT_NAMESPACE);
73     }
74
75     public static ConfigurationRepository lookup() {
76         if (validCallers.contains(Thread.currentThread().getStackTrace()[2].getClassName())) {
77             return repo;
78         }
79         return null;
80     }
81
82     public Set<String> getTenants() {
83         return tenants;
84     }
85
86     public Set<String> getNamespaces() {
87         return namespaces;
88     }
89
90
91     public boolean isValidTenant(String tenant) {
92         return tenant != null && tenants.contains(tenant.toUpperCase());
93     }
94
95     public boolean isValidNamespace(String namespace) {
96         return namespace != null && namespaces.contains(namespace.toUpperCase());
97     }
98
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);
106         }
107         return config.getConfiguration(tenant + Constants.KEY_ELEMENTS_DELIMETER + namespace);
108     }
109
110     public void populateConfiguration(String key, Configuration builder) {
111         store.put(key, new ConfigurationHolder(builder));
112         populateTenantsNamespace(key, false);
113     }
114
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]);
120         }
121     }
122
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);
128         }
129         holder.addOverrideConfiguration(file.getAbsolutePath(), ConfigurationUtils.getConfigurationBuilder(file, true));
130         populateTenantsNamespace(key, true);
131     }
132
133     public void refreshOverrideConfigurationFor(String key, int index) {
134         ConfigurationHolder holder = store.get(key);
135         if (holder != null) {
136             holder.refreshOverrideConfiguration(index);
137         }
138     }
139
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());
145             }
146         }
147     }
148
149     private class ConfigurationHolder {
150
151         private final Map<String, FileBasedConfigurationBuilder<FileBasedConfiguration>> overrideConfiguration =
152                 new LinkedHashMap<>();
153         BasicConfigurationBuilder<Configuration> builder;
154         Timestamp lastConfigurationBuildTime;
155         Configuration config;
156         Configuration composite;
157
158         public ConfigurationHolder(BasicConfigurationBuilder builder) {
159             this.builder = builder;
160         }
161
162         public ConfigurationHolder(Configuration builder) {
163             this.config = builder;
164         }
165
166         public void refreshOverrideConfiguration(int index) {
167             int count = -1;
168             for (FileBasedConfigurationBuilder overrides : overrideConfiguration.values()) {
169                 try {
170                     if (++count == index) {
171                         overrides.save();
172                         overrides.resetResult();
173                     }
174                 } catch (ConfigurationException exception) {
175                     //do nothing
176                 }
177             }
178         }
179
180         public void addOverrideConfiguration(String path, BasicConfigurationBuilder<FileBasedConfiguration> builder) {
181             overrideConfiguration.put(path.toUpperCase(), (FileBasedConfigurationBuilder) builder);
182             getEffectiveConfiguration(config, overrideConfiguration.values());
183         }
184
185         private Configuration getEffectiveConfiguration(Configuration configuration,
186                 Collection<FileBasedConfigurationBuilder<FileBasedConfiguration>> list) {
187             try {
188                 CompositeConfiguration cc = new CompositeConfiguration();
189                 for (FileBasedConfigurationBuilder<FileBasedConfiguration> b : list) {
190                     cc.addConfiguration(b.getConfiguration());
191                 }
192                 cc.addConfiguration(configuration);
193                 composite = cc;
194                 return composite;
195             } catch (Exception exception) {
196                 return null;
197             }
198         }
199
200         public void removeOverrideConfiguration(String path) {
201             overrideConfiguration.remove(path.toUpperCase());
202             getEffectiveConfiguration(config, overrideConfiguration.values());
203         }
204
205         public boolean containsOverrideConfiguration(String path) {
206             return overrideConfiguration.containsKey(path.toUpperCase());
207         }
208
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());
218             }
219             if (composite == null && overrideConfiguration.size() != 0) {
220                 composite = getEffectiveConfiguration(config, overrideConfiguration.values());
221             }
222             return overrideConfiguration.size() == 0 ? config : composite;
223         }
224     }
225 }