RDK Documentation (Open Sourced RDK Components)
hostPersistence.cpp
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2016 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 
21 
22 /**
23 * @defgroup devicesettings
24 * @{
25 * @defgroup rpc
26 * @{
27 **/
28 
29 
30 #include <iostream>
31 #include <fstream>
32 #include <map>
33 #include <exception>
34 #include <dirent.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 
40 
41 #include "hostPersistence.hpp"
42 #include "exception.hpp"
43 #include "illegalArgumentException.hpp"
44 
45 
46 #include "dsserverlogger.h"
47 
48 #define HOSTPERSIST_ERROR -1
49 #define HOSTPERSIST_SUCCESS 0
50 
51 
52 using namespace std;
53 
54 namespace device {
55 
56 /**
57  * <code>HostPersistence</code> is an simple class that provides
58  * for robust serialization of (key,value) values stored in a Hashmap.
59  *
60  * The local file system is used as the database, with different sets
61  * of persistent objects may occupy individual files in the file system.
62  *
63  * <p>
64  * In order to provide for more robust updates, we never overwrite a file
65  * directly. Instead we write to a secondary file, then delete the original, and
66  * finally rename the secondary file. When reading files in we look for the
67  * secondary file first. If no secondary file is found or it is corrupt, we fall
68  * back to the original filename.
69  * <p>
70  *
71  * <p>
72  * For this implementation, where the <i>key</i> is a string constant and <i>value</i> is
73  * either a string constant or a primitive data type, we use a HashMap to store the properties.
74  * <p>
75  *
76  * @TODO: If necessary, we will later add capability to configure the file path where the persistent data
77  * is to be stored.
78  *
79  */
80 
81 HostPersistence::HostPersistence() {
82  /*
83  * TBD This need to be removed and
84  * Persistent path shall be set from startup script
85  * To do this Host Persistent need to be part of DS Manager
86  * TBD
87  */
88 
89  #if defined(HAS_HDD_PERSISTENT)
90  /*Product having HDD Persistent*/
91  filePath = "/tmp/mnt/diska3/persistent/ds/hostData";
92  {
93  }
94  #elif defined(HAS_FLASH_PERSISTENT)
95  /*Product having Flash Persistent*/
96  filePath = "/opt/persistent/ds/hostData";
97  {
98  }
99  #else
100  filePath = "/opt/ds/hostData";
101  {
102  }
103  /*Default case*/
104  #endif
105  defaultFilePath = "/etc/hostDataDefault";
106 
107 
108 }
109 
110 HostPersistence::HostPersistence( const std::string &storeFileName) {
111  // TODO Auto-generated constructor stub
112  filePath = storeFileName;
113 }
114 HostPersistence::~HostPersistence() {
115  // TODO Auto-generated destructor stub
116 }
117 
118 /**
119  * Provides a Host Persistenc Instance.
120  *
121  */
122  HostPersistence& HostPersistence::getInstance()
123  {
124  static HostPersistence instance;
125  return instance;
126  }
127 
128 /**
129  * Provides a simple utility method for load host persisted values.
130  * from file system. Exception is thrown if the persisted file is
131  * not readable, and property map is loaded with default values.
132  */
133 void HostPersistence::load() {
134  try
135  {
136  loadFromFile(filePath, _properties);
137  }
138  catch (exception& e)
139  {
140  cout << "Backup file is currupt or not available.." << endl;
141  try {
142  loadFromFile(filePath + "tmpDB", _properties);
143  }
144  catch (...) {
145  /* Remove all properties, and start with default values */
146  }
147  }
148 
149  try
150  {
151  loadFromFile(defaultFilePath, _defaultProperties);
152  }
153  catch (exception& e)
154  {
155  cout << "System file "<< defaultFilePath <<" is currupt or not available.." << endl;
156  }
157 
158  return;
159 }
160 
161 /**
162  * Provides a simple utility method for accessing host persisted values.
163  * Exception is thrown if the asked property is not available.
164  *
165  * @param key
166  * property key
167  * @param defValue
168  * default value
169  * @return {@link Integer#getInteger(String)} for the given <i>key</i>,
170  * <i>defValue</i>
171  */
172 std::string HostPersistence::getProperty(const string &key)
173 {
174  /* Check the validness of the key */
175  if( key.empty())
176  {
177  cout << "The KEY is empty..." << endl;
178  throw IllegalArgumentException();
179  }
180 
181  std::map <std::string, std::string> :: const_iterator eFound = _properties.find (key);
182  if (eFound == _properties.end())
183  {
184  cout << "The Item IS NOT FOUND " << endl;
185 
186  throw IllegalArgumentException();
187  }
188  else
189  {
190  /*cout << "The Item " << eFound->first << " is found & the value is " << eFound->second << endl;*/
191  return eFound->second;
192  }
193 }
194 
195 /**
196  * Provides a simple utility method for accessing host persisted values
197  * Default value is returned if the asked property is not available.
198  *
199  * @param key
200  * property key
201  * @param defValue
202  * default value
203  * @return {@link Integer#getInteger(String)} for the given <i>key</i>,
204  * <i>defValue</i>
205  */
206 std::string HostPersistence::getProperty(const std::string &key, const std::string &defValue)
207 {
208  /* Check the validness of the key */
209  if( key.empty())
210  {
211  cout << "The KEY is empty..." << endl;
212  throw IllegalArgumentException();
213  }
214 
215  /*cout << "Looking for " << key << " and " << defValue << endl;*/
216 
217  std::map <std::string, std::string> :: const_iterator eFound = _properties.find (key);
218 
219  if (eFound == _properties.end())
220  {
221  return defValue;
222  }
223  else
224  {
225  /*cout << "The Item " << eFound->first << " is found & the value is " << eFound->second << endl;*/
226  return eFound->second;
227  }
228 }
229 
230 /**
231  * Provides a simple utility method for accessing host persisted values.
232  * Exception is thrown if the asked property is not available.
233  *
234  * @param key
235  * property key
236  * @return {@link Integer#getInteger(String)} for the given <i>key</i>,
237  * <i>defValue</i>
238  */
239 std::string HostPersistence::getDefaultProperty(const string &key)
240 {
241  /* Check the validness of the key */
242  if( key.empty())
243  {
244  cout << "The KEY is empty..." << endl;
245  throw IllegalArgumentException();
246  }
247 
248  std::map <std::string, std::string> :: const_iterator eFound = _defaultProperties.find (key);
249  if (eFound == _defaultProperties.end())
250  {
251  cout << "The Item IS NOT FOUND " << endl;
252 
253  throw IllegalArgumentException();
254  }
255  else
256  {
257  cout << "The Item " << eFound->first << " is found & the value is " << eFound->second << endl;
258  return eFound->second;
259  }
260 }
261 
262 /**
263  * Provides a simple utility method for persist host values to a file.
264  * Default value is returned if the asked property is not available.
265  *
266  * @param key
267  * property key
268  * @param defValue
269  * default value
270  * @return {@link Integer#getInteger(String)} for the given <i>key</i>,
271  * <i>defValue</i>
272  */
273 void HostPersistence::persistHostProperty(const std::string &key, const std::string &value)
274 {
275  if( key.empty() || value.empty())
276  {
277  cout << "Given KEY or VALUE is empty..." << endl;
278  throw IllegalArgumentException();
279  }
280 
281 
282  try {
283  string eRet = getProperty (key);
284 
285 
286 
287  if (eRet.compare(value) == 0) {
288  /* Same value. No need to do anything */
289  return;
290  }
291 
292  /* Save a current copy before modifying */
293  writeToFile(filePath + "tmpDB");
294 
295  /* First of all check whether the entry is already present in the hashtable */
296  /*cout << "Entry Already present. Erase it before Writting..!\n";*/
297  _properties.erase (key);
298 
299  }
300  catch (const IllegalArgumentException &e) {
301  cout << "Entry Not found..!\n";
302  }
303  catch (...) {
304 
305  }
306 
307  _properties.insert ({key, value });
308 
309  writeToFile(filePath);
310 
311  return;
312 }
313 
314 /**
315  * Provides a simple utility method for loading the key and defvalue from the backup file.
316  *
317  * @param filename
318  * property file name
319  *
320  * @param std::map <std::string, std::string> map
321  * properties map
322  * @return {@link Integer#getInteger(String)} 0 for Success and -1 for Failure
323  */
324 void HostPersistence::loadFromFile (const string &fileName, std::map <std::string, std::string> &map)
325 {
326  char keyValue[1024] = "";
327  char key[1024] = "";
328  FILE *filePtr = NULL;
329 
330  filePtr = fopen (fileName.c_str(), "r");
331  if (filePtr != NULL) {
332  while (!feof(filePtr))
333  {
334  /* RDKSEC-811 Coverity fix - CHECKED_RETURN */
335  if (fscanf (filePtr, "%s\t%s\n", key, keyValue) <= 0 )
336  {
337  cout << "fscanf failed !\n";
338  }
339  else
340  {
341  /* Check the TypeOfInput variable and then call the appropriate insert function */
342  map.insert ({key, keyValue });
343  }
344  }
345  fclose (filePtr);
346  }
347  else {
348  throw Exception(-1);
349  }
350 }
351 
352 /**
353  * Provides a simple utility method for dumping all the data that are in hash to tmp file.
354  *
355  * @return {@link Integer#getInteger(String)} 0 for Success and -1 for Failure
356  */
357 void HostPersistence::writeToFile (const string &fileName)
358 {
359  unlink(fileName.c_str());
360 
361  if(_properties.size() > 0)
362  {
363  /*
364  * Replacing the ofstream to fwrite
365  * Because the ofstream.close or ofstream.flush or ofstream.rdbuf->sync
366  * does not sync the data onto disk.
367  * TBD - This need to be changed to C++ APIs in future.
368  */
369 
370  FILE *file = fopen (fileName.c_str(),"w");
371  if (file != NULL)
372  {
373  for ( auto it = _properties.begin(); it != _properties.end(); ++it ) {
374  string dataToWrite = it->first + "\t" + it->second + "\n";
375  unsigned int size = dataToWrite.length();
376  fwrite(dataToWrite.c_str(),1,size,file);
377  /*cout << "Size " << size << endl;*/
378  /*cout << "Item " << it->first << " Value" << it->second << endl;*/
379  }
380 
381  fflush (file); //Flush buffers to FS
382  fsync(fileno(file)); // Flush file to HDD
383  fclose (file);
384  }
385  }
386 }
387 
388 }
389 
390 
391 
392 /** @} */
393 /** @} */
device::Exception
This class handles exceptions occurring in DS module.
Definition: exception.hpp:52
device::IllegalArgumentException
This class extends Exception class to manage the expections caused due to illegal arguments.
Definition: illegalArgumentException.hpp:51
device::HostPersistence
Definition: hostPersistence.hpp:38