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