0b497c9812b4e2f6a87e7d81745b14088ba23721
[profile/ivi/settings-daemon.git] / lib / manager.cpp
1 /**
2  * @file manager.cpp
3  *
4  * @brief Settings manager implementation.
5  *
6  * @author Ossama Othman @<ossama.othman@@intel.com@>
7  *
8  * @copyright @par
9  * Copyright 2012, 2013 Intel Corporation All Rights Reserved.
10  * @par
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation;
14  * version 2.1 of the License.
15  * @par
16  * This library 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 GNU
19  * Lesser General Public License for more details.
20  * @par
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA  02110-1301  USA
25  */
26
27
28 #include "config.hpp"
29 #include "manager.hpp"
30 #include <settingsd/plugin.hpp>
31 #include <settingsd/response_callback.hpp>
32 #include <settingsd/json_glib_traits.hpp>
33 #include <settingsd/smart_ptr.hpp>
34
35 #include <gmodule.h>
36
37 #include <boost/filesystem.hpp>
38
39
40 ivi::settings::manager::manager(std::string const & dir)
41   : loaders_()
42   , settings_()
43 {
44   load_settings(dir);
45 }
46
47 ivi::settings::manager::~manager()
48 {
49 }
50
51 bool
52 ivi::settings::manager::register_setting(std::unique_ptr<plugin> p)
53 {
54   std::string const & id = p->id();
55
56   auto const result =
57     settings_.insert(std::make_pair(id, std::move(p)));
58
59   if (!result.second)
60     std::cerr << "Settings plugin registration for \""
61               << id << "\" failed." << std::endl;
62
63   return result.second;
64 }
65
66 void
67 ivi::settings::manager::load_settings(std::string const & dir)
68 {
69   if (dir.length() == 0)
70     throw std::logic_error("Zero length settings plugin directory path.");
71
72   namespace fs = boost::filesystem;
73
74   // Find all settings plugins in the plugin directory.
75   fs::path settings_dir(dir);
76
77   if (fs::is_directory(settings_dir)) {
78     // Iterate over directory entries, create settings instances
79     // for each settings plugin, and store in settings map.
80
81     fs::directory_iterator const end;
82     for (fs::directory_iterator i(settings_dir); i != end; ++i) {
83       try {
84         fs::path const & plugin_path = (*i).path();
85
86         // Verify that the plugin is actually a file with the
87         // appropriate extension (e.g. ".so").
88         //
89         // Note that the .extension() method returns a string like
90         // ".so" whereas G_MODULE_SUFFIX is preprocessor symbol/string
91         // like "so".  We prepend a period to G_MODULE_SUFFIX using
92         // standard string literal concatenation.
93         if (!fs::is_regular_file(plugin_path)
94             || plugin_path.extension() != "." G_MODULE_SUFFIX)
95           continue;
96
97         std::string const & plugin_name = plugin_path.string();
98
99         std::unique_ptr<loader> plugin(new loader(plugin_name, *this));
100
101         loaders_.push_back(std::move(plugin));
102       }
103       catch (std::logic_error & e) {
104         /**
105          * @todo I really hate catching an exception like this, but I
106          *       really don't want to resort to a construct/init()
107          *       style of object initialization.  Fix.
108          */std::cerr << "Error loading plugin: " << e.what() << "\n";
109       }
110     }
111
112     if (settings_.size() == 0) {
113       std::cerr << "Settings plugin directory \""
114                 << dir << "\" has no plugins.\n";
115     } else {
116       std::cerr << "Registered settings plugins: \n";
117       for (auto const & i : settings_)
118         std::cerr << "\t" << i.first << '\n';
119     }
120   } else {
121     std::cerr << "Settings plugin directory \""
122               << dir << "\" does not exist.\n";
123   }
124 }
125
126 void
127 ivi::settings::manager::dispatch(std::string request,
128                                  struct libwebsocket * wsi)
129 {
130   if (request.empty()) {
131     response_callback response(wsi, std::string(), std::string());
132     response.send_error("Empty settings request.");
133   }
134
135   smart_ptr<JsonParser> const parser(json_parser_new());
136   json_parser_load_from_data(parser.get(), request.c_str(), -1, nullptr);
137
138   JsonReader * const reader = json_reader_new(json_parser_get_root(parser.get()));
139   smart_ptr<JsonReader> const safe_reader(reader);
140
141   // Retrieve setting name and transcation ID from the JSON request
142   // string.
143   char const * type = nullptr;
144   if (json_reader_read_member(reader, "type")) {
145     type = json_reader_get_string_value(reader);
146   }
147   json_reader_end_member(reader);
148
149   /**
150    * @todo Allow transaction ID to be null?
151    */
152   char const * transaction_id = "";
153   if (json_reader_read_member(reader, "transactionid")) {
154     transaction_id = json_reader_get_string_value(reader);
155   }
156   json_reader_end_member(reader);
157
158   response_callback response(wsi,
159                              type == nullptr ? "" : type,
160                              transaction_id);
161
162   std::string error;
163   if (type != nullptr) {
164     // Dispatch the request to the corresponding settings plugin.
165     auto i = settings_.find(type);
166     if (i != settings_.end())
167       (*i).second->handle_request(request, response);
168     else {
169       error =
170         std::string("Settings type \"")
171         + type + "\" not supported.";
172
173       response.send_error(error);
174     }
175   } else {
176     error =
177       "Settings type not specified in request.\n"
178       "Supported plugins:\n";
179
180     for (auto const & i : settings_)
181       error += "\t" + i.first + "\n";
182
183     response.send_error(error);
184   }
185 }
186
187
188 // Local Variables:
189 // mode:c++
190 // c-basic-offset:2
191 // indent-tabs-mode: nil
192 // End: