Fawkes API  Fawkes Development Version
yaml.cpp
1 
2 /***************************************************************************
3  * yaml.cpp - Fawkes configuration stored in one or more YAML files
4  *
5  * Created: Wed Aug 01 16:46:13 2012
6  * Copyright 2006-2012 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include "yaml.h"
25 
26 #include "yaml_node.h"
27 
28 #include <core/exceptions/software.h>
29 #include <core/threading/mutex.h>
30 #include <core/threading/mutex_locker.h>
31 #include <logging/liblogger.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <utils/misc/string_split.h>
35 #include <utils/system/fam_thread.h>
36 #include <yaml-cpp/exceptions.h>
37 
38 #include <cerrno>
39 #include <cstdio>
40 #include <cstdlib>
41 #include <cstring>
42 #include <dirent.h>
43 #include <fstream>
44 #include <queue>
45 #include <regex>
46 
47 namespace fawkes {
48 
49 #define YAML_FILE_REGEX "^[a-zA-Z0-9_-]+\\.yaml$"
50 
51 /** @class YamlConfiguration::YamlValueIterator <config/yaml.h>
52  * Iterator for YAML config trees.
53  * This iterator is used by YamlConfiguration as a result value
54  * for queries. Its use is opaque and knowledge of
55  * Configuration::ValueIterator will suffice for interaction.
56  * @author Tim Niemueller
57  */
58 
59 /** Constructor.
60  * Creates an iterator representing the invalid iterator.
61  */
63 {
64  current_ = nodes_.end();
65 }
66 
67 /** Initializing constructor.
68  * @param nodes nodes to iterate over
69  */
71  std::map<std::string, std::shared_ptr<YamlConfigurationNode>> &nodes)
72 : first_(true), nodes_(nodes)
73 {
74  current_ = nodes_.begin();
75 }
76 
77 bool
79 {
80  if (first_) {
81  first_ = false;
82  } else {
83  ++current_;
84  }
85  return (current_ != nodes_.end());
86 }
87 
88 bool
90 {
91  return (current_ != nodes_.end());
92 }
93 
94 const char *
96 {
97  if (current_ == nodes_.end()) {
98  throw Exception("YamlValueIterator: cannot get path of invalid iterator");
99  }
100  return current_->first.c_str();
101 }
102 
103 const char *
105 {
106  if (current_ == nodes_.end()) {
107  throw Exception("YamlValueIterator: cannot get type of invalid iterator");
108  }
109  return YamlConfigurationNode::Type::to_string(current_->second->get_type());
110 }
111 
112 bool
114 {
115  if (current_ == nodes_.end()) {
116  throw Exception("YamlValueIterator: cannot check type on invalid iterator");
117  }
118  return (current_->second->is_type<float>());
119 }
120 
121 bool
123 {
124  if (current_ == nodes_.end()) {
125  throw Exception("YamlValueIterator: cannot check type on invalid iterator");
126  }
127  return (current_->second->is_type<unsigned int>());
128 }
129 
130 bool
132 {
133  if (current_ == nodes_.end()) {
134  throw Exception("YamlValueIterator: cannot check type on invalid iterator");
135  }
136  return (current_->second->is_type<int>());
137 }
138 
139 bool
141 {
142  if (current_ == nodes_.end()) {
143  throw Exception("YamlValueIterator: cannot check type on invalid iterator");
144  }
145  return (current_->second->is_type<bool>());
146 }
147 
148 bool
150 {
151  if (current_ == nodes_.end()) {
152  throw Exception("YamlValueIterator: cannot check type on invalid iterator");
153  }
154  return (current_->second->is_type<std::string>());
155 }
156 
157 bool
159 {
160  if (current_ == nodes_.end()) {
161  throw Exception("YamlValueIterator: cannot check type on invalid iterator");
162  }
163  return current_->second->get_type() == YamlConfigurationNode::Type::SEQUENCE;
164 }
165 
166 size_t
168 {
169  if (current_ == nodes_.end()) {
170  throw Exception("YamlValueIterator: cannot check type on invalid iterator");
171  }
172  if (current_->second->get_type() != YamlConfigurationNode::Type::SEQUENCE) {
173  throw Exception("YamlValueIterator: cannot get list size of non-list value");
174  }
175  return current_->second->get_list_size();
176 }
177 
178 float
180 {
181  if (current_ == nodes_.end()) {
182  throw Exception("YamlValueIterator: cannot get value of invalid iterator");
183  }
184  return current_->second->get_value<float>();
185 }
186 
187 unsigned int
189 {
190  if (current_ == nodes_.end()) {
191  throw Exception("YamlValueIterator: cannot get value of invalid iterator");
192  }
193  return current_->second->get_value<unsigned int>();
194 }
195 
196 int
198 {
199  if (current_ == nodes_.end()) {
200  throw Exception("YamlValueIterator: cannot get value of invalid iterator");
201  }
202  return current_->second->get_value<int>();
203 }
204 
205 bool
207 {
208  if (current_ == nodes_.end()) {
209  throw Exception("YamlValueIterator: cannot get value of invalid iterator");
210  }
211  return current_->second->get_value<bool>();
212 }
213 
214 std::string
216 {
217  if (current_ == nodes_.end()) {
218  throw Exception("YamlValueIterator: cannot get value of invalid iterator");
219  }
220  return current_->second->get_value<std::string>();
221 }
222 
223 std::string
225 {
226  if (current_ == nodes_.end()) {
227  throw Exception("YamlValueIterator: cannot get value of invalid iterator");
228  }
229  if (current_->second->get_type() == YamlConfigurationNode::Type::SEQUENCE) {
230  return current_->second->get_list_as_string();
231  } else {
232  return current_->second->get_value<std::string>();
233  }
234 }
235 
236 std::vector<float>
238 {
239  if (current_ == nodes_.end()) {
240  throw Exception("YamlValueIterator: cannot get value of invalid iterator");
241  }
242  return current_->second->get_list<float>();
243 }
244 
245 std::vector<unsigned int>
247 {
248  if (current_ == nodes_.end()) {
249  throw Exception("YamlValueIterator: cannot get value of invalid iterator");
250  }
251  return current_->second->get_list<unsigned int>();
252 }
253 
254 std::vector<int>
256 {
257  if (current_ == nodes_.end()) {
258  throw Exception("YamlValueIterator: cannot get value of invalid iterator");
259  }
260  return current_->second->get_list<int>();
261 }
262 
263 std::vector<bool>
265 {
266  if (current_ == nodes_.end()) {
267  throw Exception("YamlValueIterator: cannot get value of invalid iterator");
268  }
269  return current_->second->get_list<bool>();
270 }
271 
272 std::vector<std::string>
274 {
275  if (current_ == nodes_.end()) {
276  throw Exception("YamlValueIterator: cannot get value of invalid iterator");
277  }
278  return current_->second->get_list<std::string>();
279 }
280 
281 std::string
283 {
284  throw NotImplementedException("YamlConfig: comments are not available");
285 }
286 
287 bool
289 {
290  if (current_ == nodes_.end()) {
291  throw Exception("YamlValueIterator: cannot get value of invalid iterator");
292  }
293  return current_->second->is_default();
294 }
295 
296 /** @class YamlConfiguration <config/yaml.h>
297  * Configuration store using YAML documents.
298  * @author Tim Niemueller
299  */
300 
301 /** Constructor. */
303 {
304  fam_thread_ = NULL;
305  mutex = new Mutex();
306  write_pending_ = false;
307  write_pending_mutex_ = new Mutex();
308 
309  sysconfdir_ = NULL;
310  userconfdir_ = NULL;
311 }
312 
313 /** Constructor.
314  * @param sysconfdir system configuration directory, will be searched for
315  * default configuration file, and system will try to create host-specific
316  * database if writable
317  * @param userconfdir user configuration directory, will be searched preferably
318  * for default configuration file, and will be used to create host-specific
319  * database if sysconfdir is not writable. This directory will be created
320  * if it does not exist during load().
321  */
322 YamlConfiguration::YamlConfiguration(const char *sysconfdir, const char *userconfdir)
323 {
324  fam_thread_ = NULL;
325  mutex = new Mutex();
326  write_pending_ = false;
327  write_pending_mutex_ = new Mutex();
328 
329  sysconfdir_ = strdup(sysconfdir);
330 
331  if (userconfdir != NULL) {
332  userconfdir_ = strdup(userconfdir);
333  } else {
334  const char *homedir = getenv("HOME");
335  if (homedir == NULL) {
336  userconfdir_ = strdup(sysconfdir);
337  } else {
338  if (asprintf(&userconfdir_, "%s/%s", homedir, USERDIR) == -1) {
339  userconfdir_ = strdup(sysconfdir);
340  }
341  }
342  }
343 }
344 
345 /** Destructor. */
347 {
348  if (write_pending_) {
349  write_host_file();
350  }
351 
352  if (fam_thread_) {
353  fam_thread_->cancel();
354  fam_thread_->join();
355  delete fam_thread_;
356  }
357 
358  if (sysconfdir_)
359  free(sysconfdir_);
360  if (userconfdir_)
361  free(userconfdir_);
362  delete mutex;
363  delete write_pending_mutex_;
364 }
365 
366 void
367 YamlConfiguration::load(const char *file_path)
368 {
369  if (file_path == NULL) {
370  file_path = "config.yaml";
371  }
372 
373  std::string filename;
374  if (file_path[0] == '/') {
375  filename = file_path;
376  } else {
377  const char *try_paths[] = {userconfdir_, sysconfdir_};
378  int try_paths_len = 2;
379 
380  for (int i = 0; i < try_paths_len; ++i) {
381  char *path;
382  if (asprintf(&path, "%s/%s", try_paths[i], file_path) != -1) {
383  if (access(path, R_OK) == 0) {
384  filename = path;
385  free(path);
386  break;
387  }
388  free(path);
389  }
390  }
391  if (filename == "") {
392  throw Exception("YamlConfig: cannot find configuration file %s/%s or %s/%s",
393  userconfdir_,
394  file_path,
395  sysconfdir_,
396  file_path);
397  }
398  }
399 
400  config_file_ = filename;
401 
402  host_file_ = "";
403  std::list<std::string> files, dirs;
404  read_yaml_config(filename, host_file_, root_, host_root_, files, dirs);
405 
406 #ifdef HAVE_INOTIFY
407  fam_thread_ = new FamThread();
408  RefPtr<FileAlterationMonitor> fam = fam_thread_->get_fam();
409  fam->add_filter("^[^.].*\\.yaml$");
410  std::list<std::string>::iterator f;
411  for (f = files.begin(); f != files.end(); ++f) {
412  //LibLogger::log_info("YC", "Watching %s", f->c_str());
413  fam->watch_file(f->c_str());
414  }
415  for (f = dirs.begin(); f != dirs.end(); ++f) {
416  //LibLogger::log_info("YC", "Watching DIR %s", f->c_str());
417  fam->watch_dir(f->c_str());
418  }
419  fam->add_listener(this);
420  fam_thread_->start();
421 #endif
422 
423  //root_->print();
424 }
425 
426 std::shared_ptr<YamlConfigurationNode>
427 YamlConfiguration::read_yaml_file(std::string filename,
428  bool ignore_missing,
429  std::queue<LoadQueueEntry> &load_queue,
430  std::string & host_file)
431 {
432  if (access(filename.c_str(), R_OK) == -1) {
433  if (ignore_missing) {
434  return NULL;
435  }
436  throw Exception(errno, "YamlConfig: cannot access file %s", filename.c_str());
437  }
438 
439  std::vector<YAML::Node> docs;
440  bool have_doc1 = false, have_doc2 = false;
441 
442  try {
443  docs = YAML::LoadAllFromFile(filename);
444  have_doc1 = docs.size() > 0;
445  have_doc2 = docs.size() > 1;
446  } catch (YAML::ParserException &e) {
447  throw CouldNotOpenConfigException("Failed to parse %s line %i column %i: %s",
448  filename.c_str(),
449  e.mark.line,
450  e.mark.column,
451  e.msg.c_str());
452  }
453 
454  std::shared_ptr<YamlConfigurationNode> sub_root;
455 
456  if (!have_doc1) {
457  //throw Exception("YamlConfig: file %s contains no document", filename.c_str());
458  // empty -> ignore
459  } else if (have_doc1 && have_doc2) {
460  // we have a meta info and a config document
461  read_meta_doc(docs[0], load_queue, host_file);
462  sub_root = read_config_doc(docs[1]);
463 
464  } else {
465  // only one, assume this to be the config document
466  sub_root = read_config_doc(docs[0]);
467  }
468 
469  return sub_root;
470 }
471 
472 void
473 YamlConfiguration::read_yaml_config(std::string filename,
474  std::string & host_file,
475  std::shared_ptr<YamlConfigurationNode> &root,
476  std::shared_ptr<YamlConfigurationNode> &host_root,
477  std::list<std::string> & files,
478  std::list<std::string> & dirs)
479 {
480  root = std::make_shared<YamlConfigurationNode>();
481 
482  std::queue<LoadQueueEntry> load_queue;
483  load_queue.push(LoadQueueEntry(filename, false));
484 
485  while (!load_queue.empty()) {
486  LoadQueueEntry &qe = load_queue.front();
487 
488  if (qe.is_dir) {
489  dirs.push_back(qe.filename);
490  } else {
491  //LibLogger::log_debug("YamlConfiguration",
492  // "Reading YAML file '%s' (ignore missing: %s)",
493  // qe.filename.c_str(), qe.ignore_missing ? "yes" : "no");
494 
495  std::shared_ptr<YamlConfigurationNode> sub_root =
496  read_yaml_file(qe.filename, qe.ignore_missing, load_queue, host_file);
497 
498  if (sub_root) {
499  files.push_back(qe.filename);
500  *root += sub_root;
501  }
502  }
503 
504  load_queue.pop();
505  }
506 
507  if (host_file != "") {
508  //LibLogger::log_debug("YamlConfiguration",
509  // "Reading Host YAML file '%s'", host_file.c_str());
510  std::queue<LoadQueueEntry> host_load_queue;
511  host_root = read_yaml_file(host_file, true, host_load_queue, host_file);
512  if (!host_load_queue.empty()) {
513  throw CouldNotOpenConfigException("YamlConfig: includes are not allowed "
514  "in host document");
515  }
516  if (host_root) {
517  *root += host_root;
518  files.push_back(host_file);
519  } else {
520  host_root = std::make_shared<YamlConfigurationNode>();
521  }
522  } else {
523  host_root = std::make_shared<YamlConfigurationNode>();
524  }
525 }
526 
527 void
528 YamlConfiguration::fam_event(const char *filename, unsigned int mask)
529 {
530  MutexLocker lock(mutex);
531  try {
532  std::string host_file = "";
533  std::list<std::string> files, dirs;
534  std::shared_ptr<YamlConfigurationNode> root, host_root;
535  read_yaml_config(config_file_, host_file, root, host_root, files, dirs);
536 
537  std::list<std::string> changes = YamlConfigurationNode::diff(root_, root);
538 
539  if (!changes.empty()) {
540  root_ = root;
541  host_root_ = host_root;
542  host_file_ = host_file;
543 
544  std::list<std::string>::iterator c;
545  for (c = changes.begin(); c != changes.end(); ++c) {
546  notify_handlers(c->c_str());
547  }
548  }
549 
550  // includes might have changed to include a new empty file
551  // so even though no value changes were seen, we might very
552  // well have new files we need to watch (or files we do no
553  // longer have to watch, so always reset and re-add.
554  RefPtr<FileAlterationMonitor> fam = fam_thread_->get_fam();
555  fam->reset();
556  std::list<std::string>::iterator f;
557  for (f = files.begin(); f != files.end(); ++f) {
558  fam->watch_file(f->c_str());
559  }
560  for (f = dirs.begin(); f != dirs.end(); ++f) {
561  fam->watch_dir(f->c_str());
562  }
563 
564  } catch (Exception &e) {
565  LibLogger::log_warn("YamlConfiguration", "Failed to reload changed config, exception follows");
566  LibLogger::log_warn("YamlConfiguration", e);
567  }
568 }
569 
570 /** Create absolute config path.
571  * If the @p path starts with / it is considered to be absolute. Otherwise
572  * it is prefixed with the config directory.
573  * @param path path
574  * @return absolute path
575  */
576 static std::string
577 abs_cfg_path(const std::string &path)
578 {
579  if (path[0] == '/') {
580  return path;
581  } else {
582  return std::string(CONFDIR) + "/" + path;
583  }
584 }
585 
586 void
587 YamlConfiguration::read_meta_doc(YAML::Node & doc,
588  std::queue<LoadQueueEntry> &load_queue,
589  std::string & host_file)
590 {
591  try {
592  const YAML::Node &includes = doc["include"];
593  for (YAML::const_iterator it = includes.begin(); it != includes.end(); ++it) {
594  std::string include = it->as<std::string>();
595  bool ignore_missing = false;
596  if (it->Tag() == "tag:fawkesrobotics.org,cfg/ignore-missing") {
597  ignore_missing = true;
598  }
599 
600  if (it->Tag() == "tag:fawkesrobotics.org,cfg/host-specific") {
601  if (host_file != "") {
602  throw Exception("YamlConfig: Only one host-specific file can be specified");
603  }
604  host_file = abs_cfg_path(it->Scalar());
605  continue;
606  }
607 
608  if (include.empty()) {
609  throw Exception("YamlConfig: invalid empty include");
610  }
611 
612  if (include[include.size() - 1] == '/') {
613  // this should be a directory
614  std::string dirname = abs_cfg_path(include);
615  struct stat dir_stat;
616  if ((stat(dirname.c_str(), &dir_stat) != 0)) {
617  if (ignore_missing)
618  continue;
619  throw Exception(errno, "YamlConfig: Failed to stat directory %s", dirname.c_str());
620  }
621 
622  if (!S_ISDIR(dir_stat.st_mode)) {
623  throw Exception("YamlConfig: %s is not a directory", dirname.c_str());
624  }
625 
626  DIR *d = opendir(dirname.c_str());
627  if (!d) {
628  throw Exception(errno, "YamlConfig: failed to open directory %s", dirname.c_str());
629  }
630 
631  load_queue.push(LoadQueueEntry(dirname, ignore_missing, true));
632 
633  std::list<std::string> files;
634 
635  std::regex yaml_regex{YAML_REGEX, std::regex_constants::extended};
636 
637  struct dirent *dent;
638  while ((dent = readdir(d)) != NULL) {
639  if (regex_search(dent->d_name, yaml_regex)) {
640  std::string dn = dent->d_name;
641  files.push_back(dirname + dn);
642  }
643  }
644  closedir(d);
645 
646  files.sort();
647  for (std::list<std::string>::iterator f = files.begin(); f != files.end(); ++f) {
648  load_queue.push(LoadQueueEntry(*f, ignore_missing));
649  }
650 
651  } else {
652  load_queue.push(LoadQueueEntry(abs_cfg_path(include), ignore_missing));
653  }
654  }
655  } catch (YAML::KeyNotFound &e) {
656  //ignored, no includes
657  }
658 }
659 
660 std::shared_ptr<YamlConfigurationNode>
661 YamlConfiguration::read_config_doc(const YAML::Node &doc)
662 {
663  return YamlConfigurationNode::create(doc);
664 }
665 
666 void
667 YamlConfiguration::write_host_file()
668 {
669  if (host_file_ == "") {
670  throw Exception("YamlConfig: no host config file specified");
671  }
672  if (mutex->try_lock()) {
673  try {
674  host_root_->emit(host_file_);
675  mutex->unlock();
676  } catch (...) {
677  write_pending_mutex_->unlock();
678  mutex->unlock();
679  throw;
680  }
681  } else {
682  write_pending_mutex_->lock();
683  write_pending_ = true;
684  write_pending_mutex_->unlock();
685  }
686 }
687 
688 void
690 {
691  throw NotImplementedException("YamlConfig does not support copying of a configuration");
692 }
693 
694 bool
695 YamlConfiguration::exists(const char *path)
696 {
697  try {
698  std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
699  return !n->has_children();
700  } catch (Exception &e) {
701  return false;
702  }
703 }
704 
705 std::string
707 {
708  std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
709  if (n->has_children()) {
710  throw ConfigEntryNotFoundException(path);
711  }
712 
713  return YamlConfigurationNode::Type::to_string(n->get_type());
714 }
715 
716 std::string
718 {
719  return "";
720 }
721 
722 /** Retrieve value casted to given type T.
723  * @param root root node of the tree to search
724  * @param path path to query
725  * @return value casted as desired
726  * @throw YAML::ScalarInvalid thrown if value does not exist or is of
727  * a different type.
728  */
729 template <typename T>
730 static inline T
731 get_value_as(std::shared_ptr<YamlConfigurationNode> root, const char *path)
732 {
733  std::shared_ptr<YamlConfigurationNode> n = root->find(path);
734  if (n->has_children()) {
735  throw ConfigEntryNotFoundException(path);
736  }
737  return n->get_value<T>();
738 }
739 
740 /** Retrieve value casted to given type T.
741  * @param root root node of the tree to search
742  * @param path path to query
743  * @return value casted as desired
744  * @throw YAML::ScalarInvalid thrown if value does not exist or is of
745  * a different type.
746  */
747 template <typename T>
748 static inline std::vector<T>
749 get_list(std::shared_ptr<YamlConfigurationNode> root, const char *path)
750 {
751  std::shared_ptr<YamlConfigurationNode> n = root->find(path);
752  if (n->has_children()) {
753  throw ConfigEntryNotFoundException(path);
754  }
755  return n->get_list<T>();
756 }
757 
758 float
760 {
761  return get_value_as<float>(root_, path);
762 }
763 
764 unsigned int
766 {
767  return get_value_as<unsigned int>(root_, path);
768 }
769 
770 int
771 YamlConfiguration::get_int(const char *path)
772 {
773  return get_value_as<int>(root_, path);
774 }
775 
776 bool
778 {
779  return get_value_as<bool>(root_, path);
780 }
781 
782 std::string
784 {
785  return get_value_as<std::string>(root_, path);
786 }
787 
788 std::vector<float>
790 {
791  return get_list<float>(root_, path);
792 }
793 
794 std::vector<unsigned int>
796 {
797  return get_list<unsigned int>(root_, path);
798 }
799 
800 std::vector<int>
802 {
803  return get_list<int>(root_, path);
804 }
805 
806 std::vector<bool>
808 {
809  return get_list<bool>(root_, path);
810 }
811 
812 std::vector<std::string>
814 {
815  return get_list<std::string>(root_, path);
816 }
817 
818 /** Check if value is of given type T.
819  * @param root root node of the tree to search
820  * @param path path to query
821  * @return true if value is of desired type, false otherwise
822  */
823 template <typename T>
824 static inline bool
825 is_type(std::shared_ptr<YamlConfigurationNode> root, const char *path)
826 {
827  std::shared_ptr<YamlConfigurationNode> n = root->find(path);
828  if (n->has_children()) {
829  throw ConfigEntryNotFoundException(path);
830  }
831  return n->is_type<T>();
832 }
833 
834 bool
836 {
837  return is_type<float>(root_, path);
838 }
839 
840 bool
841 YamlConfiguration::is_uint(const char *path)
842 {
843  std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
844  if (n->has_children()) {
845  throw ConfigEntryNotFoundException(path);
846  }
847 
848  if (!n->is_type<unsigned int>())
849  return false;
850 
851  int v = n->get_value<int>();
852  return (v >= 0);
853 }
854 
855 bool
856 YamlConfiguration::is_int(const char *path)
857 {
858  return is_type<int>(root_, path);
859 }
860 
861 bool
862 YamlConfiguration::is_bool(const char *path)
863 {
864  return is_type<bool>(root_, path);
865 }
866 
867 bool
869 {
870  return is_type<std::string>(root_, path);
871 }
872 
873 bool
874 YamlConfiguration::is_list(const char *path)
875 {
876  std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
877  if (n->has_children()) {
878  throw ConfigEntryNotFoundException(path);
879  }
880  return (n->get_type() == YamlConfigurationNode::Type::SEQUENCE);
881 }
882 
883 std::string
885 {
886  return "";
887 }
888 
889 bool
891 {
892  return false;
893 }
894 
897 {
898  try {
899  std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
900  if (n->has_children()) {
901  return new YamlValueIterator();
902  }
903  std::map<std::string, std::shared_ptr<YamlConfigurationNode>> nodes;
904  nodes[path] = n;
905  return new YamlValueIterator(nodes);
906  } catch (ConfigEntryNotFoundException &e) {
907  return new YamlValueIterator();
908  }
909 }
910 
911 void
912 YamlConfiguration::set_float(const char *path, float f)
913 {
914  root_->set_value(path, f);
915  host_root_->set_value(path, f);
916  write_host_file();
917  notify_handlers(path, false);
918 }
919 
920 void
921 YamlConfiguration::set_uint(const char *path, unsigned int uint)
922 {
923  root_->set_value(path, uint);
924  host_root_->set_value(path, uint);
925  write_host_file();
926  notify_handlers(path, false);
927 }
928 
929 void
930 YamlConfiguration::set_int(const char *path, int i)
931 {
932  root_->set_value(path, i);
933  host_root_->set_value(path, i);
934  write_host_file();
935  notify_handlers(path, false);
936 }
937 
938 void
939 YamlConfiguration::set_bool(const char *path, bool b)
940 {
941  root_->set_value(path, b);
942  host_root_->set_value(path, b);
943  write_host_file();
944  notify_handlers(path, false);
945 }
946 
947 void
948 YamlConfiguration::set_string(const char *path, const char *s)
949 {
950  root_->set_value(path, std::string(s));
951  host_root_->set_value(path, std::string(s));
952  write_host_file();
953  notify_handlers(path, false);
954 }
955 
956 void
957 YamlConfiguration::set_string(const char *path, std::string &s)
958 {
959  set_string(path, s.c_str());
960 }
961 
962 void
963 YamlConfiguration::set_floats(const char *path, std::vector<float> &f)
964 {
965  root_->set_list(path, f);
966  host_root_->set_list(path, f);
967  write_host_file();
968  notify_handlers(path, false);
969 }
970 
971 void
972 YamlConfiguration::set_uints(const char *path, std::vector<unsigned int> &u)
973 {
974  root_->set_list(path, u);
975  host_root_->set_list(path, u);
976  write_host_file();
977  notify_handlers(path, false);
978 }
979 
980 void
981 YamlConfiguration::set_ints(const char *path, std::vector<int> &i)
982 {
983  root_->set_list(path, i);
984  host_root_->set_list(path, i);
985  write_host_file();
986  notify_handlers(path, false);
987 }
988 
989 void
990 YamlConfiguration::set_bools(const char *path, std::vector<bool> &b)
991 {
992  root_->set_list(path, b);
993  host_root_->set_list(path, b);
994  write_host_file();
995  notify_handlers(path, false);
996 }
997 
998 void
999 YamlConfiguration::set_strings(const char *path, std::vector<std::string> &s)
1000 {
1001  root_->set_list(path, s);
1002  host_root_->set_list(path, s);
1003  write_host_file();
1004  notify_handlers(path, false);
1005 }
1006 
1007 void
1008 YamlConfiguration::set_strings(const char *path, std::vector<const char *> &s)
1009 {
1010  root_->set_list(path, s);
1011  host_root_->set_list(path, s);
1012  write_host_file();
1013  notify_handlers(path, false);
1014 }
1015 
1016 void
1017 YamlConfiguration::set_comment(const char *path, const char *comment)
1018 {
1019 }
1020 
1021 void
1022 YamlConfiguration::set_comment(const char *path, std::string &comment)
1023 {
1024 }
1025 
1026 void
1027 YamlConfiguration::erase(const char *path)
1028 {
1029  host_root_->erase(path);
1030  root_->erase(path);
1031  write_host_file();
1032 }
1033 
1034 void
1035 YamlConfiguration::set_default_float(const char *path, float f)
1036 {
1037  throw NotImplementedException("YamlConfiguration does not support default values");
1038 }
1039 
1040 void
1041 YamlConfiguration::set_default_uint(const char *path, unsigned int uint)
1042 {
1043  throw NotImplementedException("YamlConfiguration does not support default values");
1044 }
1045 
1046 void
1047 YamlConfiguration::set_default_int(const char *path, int i)
1048 {
1049  throw NotImplementedException("YamlConfiguration does not support default values");
1050 }
1051 
1052 void
1053 YamlConfiguration::set_default_bool(const char *path, bool b)
1054 {
1055  throw NotImplementedException("YamlConfiguration does not support default values");
1056 }
1057 
1058 void
1059 YamlConfiguration::set_default_string(const char *path, const char *s)
1060 {
1061  throw NotImplementedException("YamlConfiguration does not support default values");
1062 }
1063 
1064 void
1065 YamlConfiguration::set_default_string(const char *path, std::string &s)
1066 {
1067  set_default_string(path, s.c_str());
1068 }
1069 
1070 void
1071 YamlConfiguration::set_default_comment(const char *path, const char *comment)
1072 {
1073  throw NotImplementedException("YamlConfiguration does not support default values");
1074 }
1075 
1076 void
1077 YamlConfiguration::set_default_comment(const char *path, std::string &comment)
1078 {
1079  set_default_comment(path, comment.c_str());
1080 }
1081 
1082 void
1084 {
1085  throw NotImplementedException("YamlConfiguration does not support default values");
1086 }
1087 
1088 /** Lock the config.
1089  * No further changes or queries can be executed on the configuration and will block until
1090  * the config is unlocked.
1091  */
1092 void
1094 {
1095  mutex->lock();
1096 }
1097 
1098 /** Try to lock the config.
1099  * @see Configuration::lock()
1100  * @return true, if the lock has been aquired, false otherwise
1101  */
1102 bool
1104 {
1105  return mutex->try_lock();
1106 }
1107 
1108 /** Unlock the config.
1109  * Modifications and queries are possible again.
1110  */
1111 void
1113 {
1114  write_pending_mutex_->lock();
1115  if (write_pending_) {
1116  host_root_->emit(host_file_);
1117  write_pending_ = false;
1118  }
1119  write_pending_mutex_->unlock();
1120  mutex->unlock();
1121 }
1122 
1123 void
1125 {
1126 }
1127 
1130 {
1131  std::map<std::string, std::shared_ptr<YamlConfigurationNode>> nodes;
1132  root_->enum_leafs(nodes);
1133  return new YamlValueIterator(nodes);
1134 }
1135 
1137 YamlConfiguration::search(const char *path)
1138 {
1139  std::string tmp_path = path;
1140  std::string::size_type tl = tmp_path.length();
1141  if ((tl > 0) && (tmp_path[tl - 1] == '/')) {
1142  tmp_path.resize(tl - 1);
1143  }
1144  try {
1145  std::shared_ptr<YamlConfigurationNode> n = root_->find(tmp_path.c_str());
1146  std::map<std::string, std::shared_ptr<YamlConfigurationNode>> nodes;
1147  n->enum_leafs(nodes, tmp_path);
1148  return new YamlValueIterator(nodes);
1149  } catch (Exception &e) {
1150  return new YamlValueIterator();
1151  }
1152 }
1153 
1154 /** Query node for a specific path.
1155  * @param path path to retrieve node for
1156  * @return node representing requested path query result, if the path only
1157  * consists of collection and path name returns the whole document.
1158  */
1159 std::shared_ptr<YamlConfigurationNode>
1160 YamlConfiguration::query(const char *path) const
1161 {
1162  std::queue<std::string> pel_q = str_split_to_queue(path);
1163  return root_->find(pel_q);
1164 }
1165 
1166 } // end namespace fawkes
virtual void set_int(const char *path, int i)
Set new value in configuration of type int.
Definition: yaml.cpp:930
virtual std::vector< int > get_ints() const
Get list of values from configuration which is of type int.
Definition: yaml.cpp:255
virtual bool is_float() const
Check if current value is a float.
Definition: yaml.cpp:113
virtual bool is_list() const
Check if a value is a list.
Definition: yaml.cpp:158
virtual std::string get_string() const
Get string value.
Definition: yaml.cpp:215
ValueIterator * search(const char *path)
Iterator with search results.
Definition: yaml.cpp:1137
virtual bool is_uint(const char *path)
Check if a value is of type unsigned int.
Definition: yaml.cpp:841
virtual int get_int() const
Get int value.
Definition: yaml.cpp:197
virtual float get_float() const
Get float value.
Definition: yaml.cpp:179
ValueIterator * iterator()
Iterator for all values.
Definition: yaml.cpp:1129
virtual void set_comment(const char *path, std::string &comment)
Set new comment for existing value.
Definition: yaml.cpp:1022
virtual std::vector< float > get_floats() const
Get list of values from configuration which is of type float.
Definition: yaml.cpp:237
YamlConfiguration()
Constructor.
Definition: yaml.cpp:302
virtual void erase_default(const char *path)
Erase the given default value from the configuration.
Definition: yaml.cpp:1083
virtual void set_uint(const char *path, unsigned int uint)
Set new value in configuration of type unsigned int.
Definition: yaml.cpp:921
virtual bool is_list(const char *path)
Check if a value is a list.
Definition: yaml.cpp:874
static std::vector< T > get_list(std::shared_ptr< YamlConfigurationNode > root, const char *path)
Retrieve value casted to given type T.
Definition: memory.cpp:119
virtual std::vector< unsigned int > get_uints(const char *path)
Get list of values from configuration which is of type unsigned int.
Definition: yaml.cpp:795
Fawkes library namespace.
void unlock()
Unlock the mutex.
Definition: mutex.cpp:131
virtual void set_strings(const char *path, std::vector< std::string > &s)
Set new value in configuration of type string.
Definition: yaml.cpp:999
Called method has not been implemented.
Definition: software.h:104
Mutex locking helper.
Definition: mutex_locker.h:33
Thrown if a config entry could not be found.
Definition: config.h:46
virtual bool valid() const
Check if the current element is valid.
Definition: yaml.cpp:89
virtual void set_string(const char *path, std::string &s)
Set new value in configuration of type string.
Definition: yaml.cpp:957
void lock()
Lock the config.
Definition: yaml.cpp:1093
virtual bool is_bool(const char *path)
Check if a value is of type bool.
Definition: yaml.cpp:862
virtual bool is_uint() const
Check if current value is a unsigned int.
Definition: yaml.cpp:122
virtual void set_default_comment(const char *path, const char *comment)
Set new default comment for existing default configuration value.
Definition: yaml.cpp:1071
static bool is_type(std::shared_ptr< YamlConfigurationNode > root, const char *path)
Check if value is of given type T.
Definition: memory.cpp:195
virtual bool is_int(const char *path)
Check if a value is of type int.
Definition: yaml.cpp:856
RefPtr< FileAlterationMonitor > get_fam()
Get FileAlterationMonitor.
Definition: fam_thread.cpp:55
virtual std::vector< std::string > get_strings(const char *path)
Get list of values from configuration which is of type string.
Definition: yaml.cpp:813
virtual bool is_default(const char *path)
Check if a value was read from the default config.
Definition: yaml.cpp:890
virtual bool is_float(const char *path)
Check if a value is of type float.
Definition: yaml.cpp:835
virtual bool is_bool() const
Check if current value is a bool.
Definition: yaml.cpp:140
virtual std::vector< unsigned int > get_uints() const
Get list of values from configuration which is of type unsigned int.
Definition: yaml.cpp:246
static std::queue< std::string > str_split_to_queue(const std::string &s, char delim='/')
Split string by delimiter.
Definition: string_split.h:202
static T get_value_as(std::shared_ptr< YamlConfigurationNode > root, const char *path)
Retrieve value casted to given type T.
Definition: memory.cpp:101
virtual std::string get_comment() const
Get comment of value.
Definition: yaml.cpp:282
virtual ValueIterator * get_value(const char *path)
Get value from configuration.
Definition: yaml.cpp:896
Iterator for YAML config trees.
Definition: yaml.h:118
virtual int get_int(const char *path)
Get value from configuration which is of type int.
Definition: yaml.cpp:771
virtual void load(const char *file_path)
Load configuration.
Definition: yaml.cpp:367
virtual std::vector< int > get_ints(const char *path)
Get list of values from configuration which is of type int.
Definition: yaml.cpp:801
static std::string abs_cfg_path(const std::string &path)
Create absolute config path.
Definition: yaml.cpp:577
void reset()
Reset pointer.
Definition: refptr.h:453
virtual std::vector< bool > get_bools() const
Get list of values from configuration which is of type bool.
Definition: yaml.cpp:264
virtual std::string get_string(const char *path)
Get value from configuration which is of type string.
Definition: yaml.cpp:783
virtual unsigned int get_uint(const char *path)
Get value from configuration which is of type unsigned int.
Definition: yaml.cpp:765
virtual const char * path() const
Path of value.
Definition: yaml.cpp:95
virtual std::string get_type(const char *path)
Get type of value at given path.
Definition: yaml.cpp:706
Base class for exceptions in Fawkes.
Definition: exception.h:35
virtual std::string get_as_string() const
Get value as string.
Definition: yaml.cpp:224
virtual size_t get_list_size() const
Get number of elements in list value.
Definition: yaml.cpp:167
virtual void set_bool(const char *path, bool b)
Set new value in configuration of type bool.
Definition: yaml.cpp:939
virtual void set_default_uint(const char *path, unsigned int uint)
Set new default value in configuration of type unsigned int.
Definition: yaml.cpp:1041
void unlock()
Unlock the config.
Definition: yaml.cpp:1112
virtual bool get_bool() const
Get bool value.
Definition: yaml.cpp:206
virtual void set_bools(const char *path, std::vector< bool > &b)
Set new value in configuration of type bool.
Definition: yaml.cpp:990
virtual ~YamlConfiguration()
Destructor.
Definition: yaml.cpp:346
static void log_warn(const char *component, const char *format,...)
Log warning message.
Definition: liblogger.cpp:156
bool try_lock()
Tries to lock the mutex.
Definition: mutex.cpp:117
virtual void set_float(const char *path, float f)
Set new value in configuration of type float.
Definition: yaml.cpp:912
virtual unsigned int get_uint() const
Get unsigned int value.
Definition: yaml.cpp:188
void cancel()
Cancel a thread.
Definition: thread.cpp:646
virtual void try_dump()
Try to dump configuration.
Definition: yaml.cpp:1124
bool try_lock()
Try to lock the config.
Definition: yaml.cpp:1103
virtual void set_floats(const char *path, std::vector< float > &f)
Set new value in configuration of type float.
Definition: yaml.cpp:963
virtual bool next()
Check if there is another element and advance to this if possible.
Definition: yaml.cpp:78
void notify_handlers(const char *path, bool comment_changed=false)
Notify handlers for given path.
Definition: config.cpp:674
RefPtr<> is a reference-counting shared smartpointer.
Definition: refptr.h:49
virtual std::string get_comment(const char *path)
Get comment of value at given path.
Definition: yaml.cpp:717
virtual bool is_string(const char *path)
Check if a value is of type string.
Definition: yaml.cpp:868
virtual bool is_default() const
Check if current value was read from the default config.
Definition: yaml.cpp:288
virtual bool exists(const char *path)
Check if a given value exists.
Definition: yaml.cpp:695
virtual void set_default_string(const char *path, std::string &s)
Set new default value in configuration of type string.
Definition: yaml.cpp:1065
virtual void set_ints(const char *path, std::vector< int > &i)
Set new value in configuration of type int.
Definition: yaml.cpp:981
Iterator interface to iterate over config values.
Definition: config.h:71
virtual std::vector< std::string > get_strings() const
Get list of values from configuration which is of type string.
Definition: yaml.cpp:273
virtual bool get_bool(const char *path)
Get value from configuration which is of type bool.
Definition: yaml.cpp:777
virtual void set_uints(const char *path, std::vector< unsigned int > &uint)
Set new value in configuration of type unsigned int.
Definition: yaml.cpp:972
virtual void erase(const char *path)
Erase the given value from the configuration.
Definition: yaml.cpp:1027
virtual void set_default_bool(const char *path, bool b)
Set new default value in configuration of type bool.
Definition: yaml.cpp:1053
virtual void set_default_float(const char *path, float f)
Set new default value in configuration of type float.
Definition: yaml.cpp:1035
void join()
Join the thread.
Definition: thread.cpp:597
virtual void set_default_int(const char *path, int i)
Set new default value in configuration of type int.
Definition: yaml.cpp:1047
virtual std::string get_default_comment(const char *path)
Get comment of value at given path.
Definition: yaml.cpp:884
virtual std::vector< float > get_floats(const char *path)
Get list of values from configuration which is of type float.
Definition: yaml.cpp:789
FileAlterationMonitor thread wrapper.
Definition: fam_thread.h:32
void lock()
Lock this mutex.
Definition: mutex.cpp:87
virtual bool is_string() const
Check if current value is a string.
Definition: yaml.cpp:149
virtual void fam_event(const char *filename, unsigned int mask)
Event has been raised.
Definition: yaml.cpp:528
virtual float get_float(const char *path)
Get value from configuration which is of type float.
Definition: yaml.cpp:759
virtual bool is_int() const
Check if current value is a int.
Definition: yaml.cpp:131
Mutex mutual exclusion lock.
Definition: mutex.h:32
virtual void copy(Configuration *copyconf)
Copies all values from the given configuration.
Definition: yaml.cpp:689
virtual std::vector< bool > get_bools(const char *path)
Get list of values from configuration which is of type bool.
Definition: yaml.cpp:807
Interface for configuration handling.
Definition: config.h:64
virtual const char * type() const
Type of value.
Definition: yaml.cpp:104
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:499