[ambctl] - fixed get, set, listen, getHistory
[profile/ivi/automotive-message-broker.git] / ambd / pluginloader.cpp
1 /*
2 Copyright (C) 2012 Intel Corporation
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19
20 #include "pluginloader.h"
21 #include "glibmainloop.h"
22 #include "core.h"
23
24 #include <gio/gio.h>
25 #include <picojson.h>
26
27 #include <iostream>
28 #include <fstream>
29 #include <stdexcept>
30 #include <boost/concept_check.hpp>
31
32 std::string get_file_contents(const char *filename)
33 {
34     std::ifstream in(filename, std::ios::in);
35     if(in.fail())
36     {
37         DebugOut(DebugOut::Error) << "Failed to open file '" << filename << "':' " << strerror(errno) << endl;
38         return "";
39     }
40
41     std::string output;
42     std::string line;
43     while(in.good())
44     {
45         getline(in,line);
46         output.append(line);
47     }
48     return output;
49 }
50
51 PluginLoader::PluginLoader(string configFile, int argc, char** argv): f_create(NULL), routingEngine(nullptr), mMainLoop(nullptr)
52 {
53     DebugOut()<<"Loading config file: "<<configFile<<endl;
54     std::string configBuffer = get_file_contents(configFile.c_str());
55
56     std::string picojsonerr = "";
57     picojson::value v;
58     picojson::parse(v, configBuffer.begin(), configBuffer.end(), &picojsonerr);
59
60     if(!picojsonerr.empty())
61     {
62         DebugOut(DebugOut::Error) << "Failed to parse main config! " << picojsonerr << endl;
63         throw std::runtime_error("Error parsing config");
64     }
65
66     if(v.contains("routingEngine"))
67     {
68         string restr = v.get("routingEngine").to_str();
69
70         routingEngine = loadRoutingEngine(restr);
71
72         if(!routingEngine)
73         {
74             DebugOut(DebugOut::Warning)<<"Failed to load routing engine plugin: "<<restr<<endl;
75         }
76     }
77
78     if(!routingEngine)
79     {
80         /// there is no mainloop entry, use default glib
81         DebugOut()<<"No routing engine specified in config.  Using built-in 'core' routing engine by default."<<endl;
82
83         /// core wants some specific configuration settings:
84         std::map<std::string,std::string> settings;
85
86
87         for (auto q : {"lowPriorityQueueSize", "normalPriorityQueueSize", "highPriorityQueueSize"})
88         {
89             if (v.contains(q))
90             {
91                 string restr = v.get(q).to_str();
92                 settings[q] = restr;
93             }
94         }
95
96         routingEngine = new Core(settings);
97     }
98
99
100     if(v.contains("plugins"))
101     {
102         std::string pluginsPath = v.get("plugins").to_str();
103         scanPluginDir(pluginsPath);
104     }
105
106     if(v.contains("mainloop"))
107     {
108         /// there is a mainloop entry.  Load the plugin:
109
110         string mainloopstr = v.get("mainloop").to_str();
111
112         mMainLoop = loadMainLoop(mainloopstr, argc, argv);
113
114         if(!mMainLoop)
115         {
116             DebugOut(DebugOut::Warning)<<"Failed to load main loop plugin."<<endl;
117         }
118     }
119     else if(!mMainLoop)
120     {
121         /// there is no mainloop entry, use default glib
122         DebugOut()<<"No mainloop specified in config.  Using glib by default."<<endl;
123         mMainLoop = new GlibMainLoop(argc, argv);
124     }
125
126
127     for (auto q : {"sources", "sinks"})
128     {
129         if(v.contains("sources"))
130         {
131             picojson::array list = v.get(q).get<picojson::array>();
132             if (!list.size())
133             {
134                 DebugOut() << "Error getting list for " << q << endl;
135             }
136
137             for(auto src : list)
138             {
139                 std::map<std::string, std::string> configurationMap;
140                 for( auto obj : src.get<picojson::object>())
141                 {
142                     string valstr = obj.second.to_str();
143                     string key = obj.first;
144
145                     DebugOut() << "plugin config key: " << key << "value:" << valstr << endl;
146
147                     configurationMap[key] = valstr;
148                 }
149
150                 string path = configurationMap["path"];
151
152                 if(!loadPlugin(path, configurationMap))
153                     DebugOut(DebugOut::Warning) << "Failed to load plugin: " << path <<endl;
154             }
155
156         }
157     }
158
159     Core* core = static_cast<Core*>(routingEngine);
160     if( core != nullptr )
161     {
162         core->inspectSupported();
163     }
164 }
165
166 PluginLoader::~PluginLoader()
167 {
168     for(auto handle : openHandles)
169         dlclose(handle);
170 }
171
172 IMainLoop *PluginLoader::mainloop()
173 {
174     return mMainLoop;
175 }
176
177 std::string PluginLoader::errorString()
178 {
179     return mErrorString;
180 }
181
182 void PluginLoader::scanPluginDir(const std::string & dir)
183 {
184     DebugOut() << "Scanning plugin directory: " << dir << endl;
185
186     auto pluginsDirectory = amb::make_gobject(g_file_new_for_path(dir.c_str()));
187
188     GError* enumerateError = nullptr;
189
190     auto enumerator = amb::make_gobject(g_file_enumerate_children(pluginsDirectory.get(), G_FILE_ATTRIBUTE_ID_FILE,
191                                                                   G_FILE_QUERY_INFO_NONE, nullptr,
192                                                                   &enumerateError));
193     auto enumerateErrorPtr = amb::make_super(enumerateError);
194
195     if(enumerateErrorPtr)
196     {
197         DebugOut(DebugOut::Error) << "Scanning plugin directory: " << enumerateErrorPtr->message << endl;
198         return;
199     }
200
201     GError* errorGetFile = nullptr;
202     while(auto pluginConfig = amb::make_gobject(g_file_enumerator_next_file(enumerator.get(), nullptr, &errorGetFile)))
203     {
204         std::string name = g_file_info_get_name(pluginConfig.get());
205
206         DebugOut() << "Found file: " << name << endl;
207         std::string fullpath = dir + (boost::algorithm::ends_with(dir, "/") ? "":"/") + name;
208         std::string data = get_file_contents(fullpath.c_str());
209
210         DebugOut() << "data: " << data << endl;
211
212         if(!readPluginConfig(data))
213         {
214             DebugOut(DebugOut::Error) << "Reading contentds of file: " << name << endl;
215         }
216     }
217
218     auto errorGetFilePtr = amb::make_super(errorGetFile);
219
220     if(errorGetFilePtr)
221     {
222         DebugOut(DebugOut::Error) << "enumerating file: " << errorGetFilePtr->message << endl;
223         return;
224     }
225 }
226
227 bool PluginLoader::readPluginConfig(const string &configData)
228 {
229     picojson::value v;
230     std::string err;
231
232     picojson::parse(v, configData.begin(), configData.end(), &err);
233
234     if (!err.empty())
235     {
236         DebugOut(DebugOut::Error) << err << endl;
237         return false;
238     }
239
240     std::string pluginName;
241     if(v.contains("name"))
242     {
243         pluginName = v.get("name").to_str();
244     }
245
246     std::string pluginPath;
247     if(v.contains("path"))
248     {
249         pluginPath = v.get("path").to_str();
250     }
251     else
252     {
253         DebugOut(DebugOut::Error) << "config missing 'path'." << endl;
254         return false;
255     }
256
257     bool enabled = false;
258     if(v.contains("enabled"))
259     {
260         enabled = v.get("enabled").get<bool>();
261     }
262     else
263     {
264         DebugOut(DebugOut::Error) << "config missing 'enabled'." << endl;
265         return false;
266     }
267
268     DebugOut() << "Plugin: " << pluginName << endl;
269     DebugOut() << "Path: " << pluginPath << endl;
270     DebugOut() << "Enabled: " << enabled << endl;
271
272     if(enabled)
273     {
274         std::map<std::string, std::string> otherConfig;
275
276         picojson::object obj = v.get<picojson::object>();
277         for(auto itr : obj)
278         {
279             if(!itr.second.is<std::string>())
280                 otherConfig[itr.first] = itr.second.serialize();
281             else
282                 otherConfig[itr.first] = itr.second.to_str();
283         }
284
285         loadPlugin(pluginPath, otherConfig);
286     }
287
288     return true;
289 }
290