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