54a5172a3edfcb570358a653998a16406b66fec5
[ccsdk/features.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP : ccsdk features
4  * ================================================================================
5  * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
6  * All rights reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  *
21  */
22 package org.onap.ccsdk.features.sdnr.wt.common.configuration;
23
24 import java.io.BufferedReader;
25 import java.io.BufferedWriter;
26 import java.io.File;
27 import java.io.FileReader;
28 import java.io.FileWriter;
29 import java.io.IOException;
30 import java.util.HashMap;
31 import java.util.Optional;
32 import org.onap.ccsdk.features.sdnr.wt.common.configuration.filechange.ConfigFileObserver;
33 import org.onap.ccsdk.features.sdnr.wt.common.configuration.filechange.IConfigChangedListener;
34 import org.onap.ccsdk.features.sdnr.wt.common.configuration.subtypes.Section;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 /**
39  * Representation of configuration file with section.<br>
40  * A root section is used for parameters, not assigned to a specific section.<br>
41  * The definitions of the configuration are attributes of a java class<br>
42  */
43 public class ConfigurationFileRepresentation implements IConfigChangedListener {
44
45     // constants
46     private static final Logger LOG = LoggerFactory.getLogger(ConfigurationFileRepresentation.class);
47
48     private static final long FILE_POLL_INTERVAL_MS = 1000;
49     public static final String SECTIONNAME_ROOT = "";
50     private static final String LR = "\n";
51     private static final String EMPTY = "";
52     // end of constants
53
54     // variables
55     /** Related configuration file **/
56     private final File mFile;
57     /** Monitor changes of file **/
58     private final ConfigFileObserver fileObserver;
59     /** List of sections **/
60     private final HashMap<String, Section> sections;
61     // end of variables
62
63     // constructors
64     public ConfigurationFileRepresentation(File f) {
65
66         this.mFile = f;
67         this.sections = new HashMap<String, Section>();
68         try {
69             if (!this.mFile.exists()) {
70                 if (!this.mFile.createNewFile()) {
71                     LOG.error("Can not create file {}", f.getAbsolutePath());
72                 }
73                 this.mFile.setReadable(true, false);
74                 this.mFile.setWritable(true, false);
75             }
76             reLoad();
77
78         } catch (IOException e) {
79             LOG.error("Problem loading config file {} : {}", f.getAbsolutePath(), e.getMessage());
80         }
81         this.fileObserver = new ConfigFileObserver(f.getAbsolutePath(), FILE_POLL_INTERVAL_MS);
82         this.fileObserver.start();
83         this.fileObserver.registerConfigChangedListener(this);
84     }
85
86     public ConfigurationFileRepresentation(String configurationfile) {
87         this(new File(configurationfile));
88     }
89     // end of constructors
90
91     // getters and setters
92     public synchronized Optional<Section> getSection(String name) {
93         return Optional.ofNullable(sections.get(name));
94     }
95     // end of getters and setters
96
97     // private methods
98     private synchronized void reLoad() {
99         sections.clear();
100         addSection(SECTIONNAME_ROOT);
101         load();
102     }
103
104     private synchronized void load() {
105         LOG.debug("loading file {}", getMFileName());
106         String curSectionName = SECTIONNAME_ROOT;
107         Optional<Section> sectionOptional = this.getSection(curSectionName);
108         Section curSection = sectionOptional.isPresent() ? sectionOptional.get() : this.addSection(curSectionName);
109         BufferedReader br = null;
110         try {
111             br = new BufferedReader(new FileReader(this.mFile));
112             for (String line; (line = br.readLine()) != null;) {
113                 line = line.trim();
114                 if (line.isEmpty()) {
115                     continue;
116                 }
117                 if (line.startsWith("[") && line.endsWith("]")) {
118                     curSectionName = line.substring(1, line.length() - 1);
119                     curSection = this.addSection(curSectionName);
120                 } else {
121                     curSection.addLine(line);
122                 }
123             }
124
125         } catch (Exception e) {
126             LOG.info("Problem loading configuration file. {} {}", getMFileName(), e);
127         } finally {
128             try {
129                 if (br != null) {
130                     br.close();
131                 }
132             } catch (IOException e) {
133             }
134         }
135         LOG.debug("finished loading file");
136         LOG.debug("start parsing sections");
137         for (Section section : this.sections.values()) {
138             section.parseLines();
139         }
140         LOG.debug("finished parsing " + this.sections.size() + " sections");
141     }
142
143     private String getMFileName() {
144         return mFile.getAbsolutePath();
145     }
146
147     // end of private methods
148
149     // public methods
150     public synchronized Section addSection(String name) {
151         if (this.sections.containsKey(name)) {
152             return this.sections.get(name);
153         }
154         Section s = new Section(name);
155         this.sections.put(name, s);
156         return s;
157     }
158
159     public synchronized void save() {
160         LOG.debug("Write configuration to {}", getMFileName());
161         try (BufferedWriter bw = new BufferedWriter(new FileWriter(this.mFile, false))) {
162             for (Section section : this.sections.values()) {
163                 if (section.hasValues()) {
164                     bw.write(String.join(LR, section.toLines()) + LR + LR);
165                 }
166             }
167             bw.close();
168         } catch (Exception e) {
169             LOG.warn("problem saving value: " + e.getMessage());
170         }
171     }
172
173     public void registerConfigChangedListener(IConfigChangedListener l) {
174         this.fileObserver.registerConfigChangedListener(l);
175     }
176
177     public void unregisterConfigChangedListener(IConfigChangedListener l) {
178         this.fileObserver.unregisterConfigChangedListener(l);
179     }
180
181     @Override
182     public void onConfigChanged() {
183         LOG.debug("Reload on change {}", getMFileName());
184         reLoad();
185     }
186
187     @Override
188     public String toString() {
189         return "ConfigurationFileRepresentation [mFile=" + mFile + ", sections=" + sections + "]";
190     }
191
192     @Override
193     protected void finalize() throws Throwable {
194         if (this.fileObserver != null) {
195             this.fileObserver.interrupt();
196         }
197         super.finalize();
198     }
199
200     /*
201      * Property access set/get
202      */
203     public synchronized void setProperty(String section, String key, Object value) {
204         Optional<Section> os = this.getSection(section);
205         if (os.isPresent()) {
206             os.get().setProperty(key, value == null ? "null" : value.toString());
207             save();
208         } else {
209             LOG.info("Unknown configuration section {}", section);
210         }
211     }
212
213     public synchronized String getProperty(String section, String propertyKey) {
214         Optional<Section> os = this.getSection(section);
215         if (os.isPresent()) {
216             return os.get().getProperty(propertyKey);
217         } else {
218             LOG.debug("Unknown configuration section {}", section);
219             return EMPTY;
220         }
221     }
222
223     public synchronized Optional<Long> getPropertyLong(String section, String propertyKey) {
224         Optional<Section> os = this.getSection(section);
225         if (os.isPresent()) {
226             return os.get().getLong(propertyKey);
227         } else {
228             LOG.debug("Unknown configuration section {}", section);
229             return Optional.empty();
230         }
231     }
232
233     public synchronized boolean isPropertyAvailable(String section, String propertyKey) {
234         Optional<Section> s = this.getSection(section);
235         return s.isPresent() && s.get().hasKey(propertyKey);
236     }
237
238     public synchronized void setPropertyIfNotAvailable(String section, String propertyKey, Object propertyValue) {
239         if (!isPropertyAvailable(section, propertyKey)) {
240             setProperty(section, propertyKey, propertyValue.toString());
241         }
242     }
243
244     public synchronized boolean getPropertyBoolean(String section, String propertyKey) {
245         return getProperty(section, propertyKey).equalsIgnoreCase("true");
246     }
247     // end of public methods
248
249 }