953f793b9d1673fcf17778e9f3f34e04b5cf83d1
[sdc.git] / common / onap-common-configuration-management / onap-configuration-management-core / src / main / java / org / onap / config / impl / ConfigurationRepository.java
1 package org.onap.config.impl;
2
3 import org.apache.commons.configuration2.CombinedConfiguration;
4 import org.apache.commons.configuration2.CompositeConfiguration;
5 import org.apache.commons.configuration2.Configuration;
6 import org.apache.commons.configuration2.FileBasedConfiguration;
7 import org.apache.commons.configuration2.builder.BasicConfigurationBuilder;
8 import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
9 import org.apache.commons.configuration2.ex.ConfigurationException;
10 import org.onap.config.ConfigurationUtils;
11 import org.onap.config.Constants;
12
13 import java.io.File;
14 import java.sql.Timestamp;
15 import java.util.*;
16
17 /**
18  * The type Configuration repository.
19  */
20 public final class ConfigurationRepository {
21
22   /**
23    * The Repo.
24    */
25   static ConfigurationRepository repo;
26   private static Set<String> validCallers = Collections.unmodifiableSet(new HashSet<>(Arrays
27       .asList(ConfigurationChangeNotifier.NotificationData.class.getName(),
28           ConfigurationUtils.class.getName(), CliConfigurationImpl.class.getName(),
29           ConfigurationChangeNotifier.class.getName(), ConfigurationDataSource.class.getName(),
30           ConfigurationImpl.class.getName())));
31
32   static {
33     repo = new ConfigurationRepository();
34   }
35
36   private boolean dbAccessible = true;
37   private Set<String> tenants = new HashSet<>();
38   private Set<String> namespaces = new HashSet<>();
39   private LinkedHashMap<String, ConfigurationHolder> store =
40       new LinkedHashMap<String, ConfigurationHolder>(16, 0.75f, true) {
41         @Override
42         protected boolean removeEldestEntry(Map.Entry eldest) {
43           try {
44             return size() > getConfigurationFor(Constants.DEFAULT_TENANT, Constants.DB_NAMESPACE)
45                 .getInt("config.size.max");
46           } catch (Exception exception) {
47             return false;
48           }
49         }
50       };
51
52   private ConfigurationRepository() {
53     if (repo != null) {
54       throw new RuntimeException("Illegal access to configuration.");
55     }
56     tenants.add(Constants.DEFAULT_TENANT);
57     namespaces.add(Constants.DEFAULT_NAMESPACE);
58   }
59
60   /**
61    * Lookup configuration repository.
62    *
63    * @return the configuration repository
64    */
65   public static ConfigurationRepository lookup() {
66     if (validCallers.contains(Thread.currentThread().getStackTrace()[2].getClassName())) {
67       return repo;
68     }
69     return null;
70   }
71
72   /**
73    * Gets tenants.
74    *
75    * @return the tenants
76    */
77   public Set<String> getTenants() {
78     return tenants;
79   }
80
81   /**
82    * Gets namespaces.
83    *
84    * @return the namespaces
85    */
86   public Set<String> getNamespaces() {
87     return namespaces;
88   }
89
90   private void populateTenantsNamespace(String key, boolean sourcedFromDb) {
91     String[] array = key.split(Constants.KEY_ELEMENTS_DELEMETER);
92     if (!array[1].equalsIgnoreCase(Constants.DB_NAMESPACE)) {
93       if (!sourcedFromDb) {
94         dbAccessible = false;
95       }
96       tenants.add(array[0]);
97       namespaces.add(array[1]);
98     }
99   }
100
101   /**
102    * Init tenants and namespaces.
103    */
104   public void initTenantsAndNamespaces() {
105     try {
106       Collection<String> collection = ConfigurationUtils.executeSelectSql(
107           getConfigurationFor(Constants.DEFAULT_TENANT, Constants.DB_NAMESPACE)
108               .getString("fetchnamescql"), new String[]{});
109       Iterator<String> iterator = collection.iterator();
110       while (iterator.hasNext()) {
111         populateTenantsNamespace(iterator.next(), true);
112       }
113     } catch (Exception exception) {
114       //Log this later
115     }
116   }
117
118   /**
119    * Is valid tenant boolean.
120    *
121    * @param tenant the tenant
122    * @return the boolean
123    */
124   public boolean isValidTenant(String tenant) {
125     return tenant == null ? false : tenants.contains(tenant.toUpperCase());
126   }
127
128   /**
129    * Is valid namespace boolean.
130    *
131    * @param namespace the namespace
132    * @return the boolean
133    */
134   public boolean isValidNamespace(String namespace) {
135     return namespace == null ? false : namespaces.contains(namespace.toUpperCase());
136   }
137
138   /**
139    * Gets configuration for.
140    *
141    * @param tenant    the tenant
142    * @param namespace the namespace
143    * @return the configuration for
144    * @throws Exception the exception
145    */
146   public Configuration getConfigurationFor(String tenant, String namespace) throws Exception {
147     ConfigurationHolder config;
148     String module = tenant + Constants.KEY_ELEMENTS_DELEMETER + namespace;
149     config = store.get(module);
150     if (config == null) {
151       config = new ConfigurationHolder(ConfigurationUtils
152           .getDbConfigurationBuilder(tenant + Constants.KEY_ELEMENTS_DELEMETER + namespace));
153       store.put(module, config);
154     }
155     return config.getConfiguration(tenant + Constants.KEY_ELEMENTS_DELEMETER + namespace);
156   }
157
158   /**
159    * Populate configurtaion.
160    *
161    * @param key     the key
162    * @param builder the builder
163    */
164   public void populateConfigurtaion(String key, Configuration builder) {
165     store.put(key, new ConfigurationHolder(builder));
166     populateTenantsNamespace(key, false);
167   }
168
169   /**
170    * Populate configurtaion.
171    *
172    * @param key     the key
173    * @param builder the builder
174    * @throws Exception the exception
175    */
176   public void populateConfigurtaion(String key, BasicConfigurationBuilder builder)
177       throws Exception {
178     store.put(key, new ConfigurationHolder(builder));
179   }
180
181   /**
182    * Populate override configurtaion.
183    *
184    * @param key  the key
185    * @param file the file
186    * @throws Exception the exception
187    */
188   public void populateOverrideConfigurtaion(String key, File file) throws Exception {
189     ConfigurationHolder holder = store.get(key);
190     if (holder == null) {
191       if (dbAccessible) {
192         holder = new ConfigurationHolder(ConfigurationUtils.getDbConfigurationBuilder(key));
193       } else {
194         holder = new ConfigurationHolder(new CombinedConfiguration());
195       }
196       store.put(key, holder);
197     }
198     holder.addOverrideConfiguration(file.getAbsolutePath(),
199         ConfigurationUtils.getConfigurationBuilder(file, true));
200     populateTenantsNamespace(key, true);
201   }
202
203   /**
204    * Refresh override configurtaion for.
205    *
206    * @param key   the key
207    * @param index the index
208    * @throws Exception the exception
209    */
210   public void refreshOverrideConfigurtaionFor(String key, int index) throws Exception {
211     ConfigurationHolder holder = store.get(key);
212     if (holder != null) {
213       holder.refreshOverrideConfiguration(index);
214     }
215   }
216
217   /**
218    * Remove override configurtaion.
219    *
220    * @param file the file
221    * @throws Exception the exception
222    */
223   public void removeOverrideConfigurtaion(File file) throws Exception {
224     Iterator<String> iterator = new ArrayList(store.keySet()).iterator();
225     while (iterator.hasNext()) {
226       ConfigurationHolder holder = store.get(iterator.next());
227       if (holder.containsOverrideConfiguration(file.getAbsolutePath())) {
228         holder.removeOverrideConfiguration(file.getAbsolutePath());
229       }
230     }
231
232   }
233
234   private class ConfigurationHolder {
235
236     /**
237      * The Builder.
238      */
239     BasicConfigurationBuilder<Configuration> builder;
240     /**
241      * The Last configuration build time.
242      */
243     Timestamp lastConfigurationBuildTime;
244     /**
245      * The Config.
246      */
247     Configuration config;
248     /**
249      * The Composite.
250      */
251     Configuration composite;
252     /**
253      * The Last config change timestamp.
254      */
255     Timestamp lastConfigChangeTimestamp;
256     private Map<String, FileBasedConfigurationBuilder<FileBasedConfiguration>>
257         overrideConfiguration = new LinkedHashMap<>();
258
259
260     /**
261      * Instantiates a new Configuration holder.
262      *
263      * @param builder the builder
264      */
265     public ConfigurationHolder(BasicConfigurationBuilder builder) {
266       this.builder = builder;
267     }
268
269     /**
270      * Instantiates a new Configuration holder.
271      *
272      * @param builder the builder
273      */
274     public ConfigurationHolder(Configuration builder) {
275       this.config = builder;
276     }
277
278     /**
279      * Refresh override configuration.
280      *
281      * @param index the index
282      */
283     public void refreshOverrideConfiguration(int index) {
284       int count = -1;
285       for (FileBasedConfigurationBuilder overrides : overrideConfiguration.values()) {
286         try {
287           if (++count == index) {
288             overrides.save();
289             overrides.resetResult();
290           }
291         } catch (ConfigurationException exception) {
292           //do nothing
293         }
294       }
295     }
296
297     /**
298      * Add override configuration.
299      *
300      * @param path    the path
301      * @param builder the builder
302      */
303     public void addOverrideConfiguration(String path,
304                                      BasicConfigurationBuilder<FileBasedConfiguration> builder) {
305       overrideConfiguration.put(path.toUpperCase(), (FileBasedConfigurationBuilder) builder);
306       getEffectiveConfiguration(config, overrideConfiguration.values());
307     }
308
309     /**
310      * Remove override configuration.
311      *
312      * @param path the path
313      */
314     public void removeOverrideConfiguration(String path) {
315       overrideConfiguration.remove(path.toUpperCase());
316       getEffectiveConfiguration(config, overrideConfiguration.values());
317     }
318
319     /**
320      * Contains override configuration boolean.
321      *
322      * @param path the path
323      * @return the boolean
324      */
325     public boolean containsOverrideConfiguration(String path) {
326       return overrideConfiguration.containsKey(path.toUpperCase());
327     }
328
329     /**
330      * Gets configuration.
331      *
332      * @param namespace the namespace
333      * @return the configuration
334      * @throws Exception the exception
335      */
336     public Configuration getConfiguration(String namespace) throws Exception {
337       if (config == null) {
338         config = builder.getConfiguration();
339         lastConfigurationBuildTime = new Timestamp(System.currentTimeMillis());
340       } else if (lastConfigurationBuildTime != null
341           && System.currentTimeMillis() - lastConfigurationBuildTime.getTime()
342           > getConfigurationFor(Constants.DEFAULT_TENANT, Constants.DB_NAMESPACE)
343                   .getInt("config.refresh.interval")) {
344         Timestamp temp = getLastUpdateTimestampFor(namespace);
345         if ((temp != null)
346             && (lastConfigChangeTimestamp == null
347             || temp.getTime() > lastConfigChangeTimestamp.getTime())) {
348           builder.resetResult();
349           config = builder.getConfiguration();
350           lastConfigChangeTimestamp = temp;
351           getEffectiveConfiguration(config, overrideConfiguration.values());
352         }
353         lastConfigurationBuildTime = new Timestamp(System.currentTimeMillis());
354       }
355       if (composite == null && overrideConfiguration.size() != 0) {
356         composite = getEffectiveConfiguration(config, overrideConfiguration.values());
357       }
358       return overrideConfiguration.size() == 0 ? config : composite;
359     }
360
361     private Configuration getEffectiveConfiguration(Configuration configuration,
362                     Collection<FileBasedConfigurationBuilder<FileBasedConfiguration>> list) {
363       try {
364         CompositeConfiguration cc = new CompositeConfiguration();
365         for (FileBasedConfigurationBuilder<FileBasedConfiguration> b : list) {
366           cc.addConfiguration(b.getConfiguration());
367         }
368         cc.addConfiguration(configuration);
369         composite = cc;
370         return composite;
371       } catch (Exception exception) {
372         return null;
373       }
374     }
375
376     /**
377      * Gets last update timestamp for.
378      *
379      * @param namespace the namespace
380      * @return the last update timestamp for
381      */
382     public Timestamp getLastUpdateTimestampFor(String namespace) {
383       Timestamp timestamp = null;
384
385       try {
386         Collection<String> collection = ConfigurationUtils.executeSelectSql(
387             getConfigurationFor(Constants.DEFAULT_TENANT, Constants.DB_NAMESPACE)
388                 .getString("fetchlastchangecql"), new String[]{namespace});
389         if (!collection.isEmpty()) {
390           timestamp = new Timestamp(Long.valueOf(((ArrayList) collection).get(0).toString()));
391         }
392       } catch (Exception exception) {
393         //Log this later
394       }
395
396       return timestamp;
397     }
398
399
400   }
401
402   public boolean isDBAccessible(){
403     return dbAccessible;
404   }
405
406
407 }