2 Copyright (C) 2012 Intel Corporation
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.
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.
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
19 #include "abstractdbusinterface.h"
21 #include <abstractroutingengine.h>
23 #include <boost/algorithm/string.hpp>
24 #include <boost/algorithm/string/predicate.hpp>
26 #include <listplusplus.h>
28 #include "abstractproperty.h"
30 #include "dbussignaller.h"
32 static DBusSignaller* signaller = nullptr;
34 unordered_map<string, AbstractDBusInterface*> AbstractDBusInterface::objectMap;
35 list<string> AbstractDBusInterface::mimplementedProperties;
37 const uint getPid(const char *owner)
39 GError* error = nullptr;
40 GDBusProxy* dbus = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL,
41 "org.freedesktop.DBus",
43 "org.freedesktop.DBus",
49 throw std::runtime_error(error->message);
54 GVariant* pid = g_dbus_proxy_call_sync(dbus, "GetConnectionUnixProcessID", g_variant_new("(s)", owner), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
58 throw std::runtime_error(error->message);
63 g_variant_get(pid,"(u)",&thePid);
70 static void handleMyMethodCall(GDBusConnection *connection,
72 const gchar *object_path,
73 const gchar *interface_name,
74 const gchar *method_name,
76 GDBusMethodInvocation *invocation,
80 std::string method = method_name;
81 AbstractDBusInterface* iface = static_cast<AbstractDBusInterface*>(user_data);
83 if(DebugOut::getDebugThreshhold() >= 6)
85 DebugOut(6)<<"DBus method call from: "<<sender<< " pid: " <<getPid(sender)<< " interface: "<<interface_name<<" method: "<<method<<endl;
86 DebugOut(6)<<"DBus method call path: "<<object_path<<endl;
91 if(method == "GetHistory")
96 g_variant_get(parameters, "(dd)", &beginTime, &endTime);
98 auto propertyMap = iface->getProperties();
100 std::list<std::string> propertyList;
102 for(auto itr = propertyMap.begin(); itr != propertyMap.end(); itr++)
104 AbstractProperty* prop = (*itr).second;
106 propertyList.push_back(prop->ambPropertyName());
109 std::string ifaceName = iface->interfaceName();
111 AsyncRangePropertyRequest request;
113 request.properties = propertyList;
114 request.timeBegin = beginTime;
115 request.timeEnd = endTime;
116 request.zone = iface->zone();
117 request.sourceUuid = iface->source();
119 request.completed = [&invocation,&ifaceName](AsyncRangePropertyReply* reply)
124 str<<"Error during request: "<<reply->error;
125 ifaceName += ".Error";
126 g_dbus_method_invocation_return_dbus_error(invocation, ifaceName.c_str(), str.str().c_str());
130 if(!reply->values.size())
132 ifaceName += ".Error";
133 g_dbus_method_invocation_return_dbus_error(invocation, ifaceName.c_str(), "No results");
137 GVariantBuilder builder;
138 g_variant_builder_init(&builder, G_VARIANT_TYPE("a(svd)"));
141 for(auto itr = reply->values.begin(); itr != reply->values.end(); itr++)
143 AbstractPropertyType* value = *itr;
145 g_variant_builder_add(&builder, "(svd)", value->name.c_str(), g_variant_ref(value->toVariant()),value->timestamp);
148 g_dbus_method_invocation_return_value(invocation,g_variant_new("(a(svd))",&builder));
151 iface->re->getRangePropertyAsync(request);
154 else if(boost::algorithm::starts_with(method,"Get"))
156 std::string propertyName = method.substr(3);
157 auto propertyMap = iface->getProperties();
158 if(propertyMap.find(propertyName) == propertyMap.end())
160 g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method.");
164 AbstractProperty* property = propertyMap[propertyName];
166 GError *error = NULL;
168 GVariant **params = g_new(GVariant*,4);
169 GVariant *val = g_variant_ref(property->value()->toVariant());
170 params[0] = g_variant_new("v",val);
171 params[1] = g_variant_new("d",property->timestamp());
172 params[2] = g_variant_new("i",property->value()->sequence);
173 params[3] = g_variant_new("i",property->updateFrequency());
175 GVariant *tuple_variant = g_variant_new_tuple(params,4);
177 g_dbus_method_invocation_return_value(invocation, tuple_variant);
180 g_variant_unref(val);
184 DebugOut(DebugOut::Error)<<error->message<<endl;
190 g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method.");
193 AbstractDBusInterface::AbstractDBusInterface(string interfaceName, string objectName,
194 GDBusConnection* connection)
195 : mInterfaceName(interfaceName), mConnection(connection), mPropertyName(objectName), supported(false), zoneFilter(Zone::None), mTime(0), regId(0)
199 mObjectPath = "/" + objectName;
202 AbstractDBusInterface::~AbstractDBusInterface()
206 list<std::string> impl = implementedProperties();
208 for(auto itr = impl.begin(); itr != impl.end(); itr++)
210 if(properties.find(*itr) != properties.end())
212 // Deleted in ~DBusSink()
213 //delete properties[*itr];
214 properties.erase(*itr);
218 objectMap.erase(mObjectPath);
222 void AbstractDBusInterface::addProperty(AbstractProperty* property)
224 string nameToLower = property->name();
225 boost::algorithm::to_lower<string>(nameToLower);
229 if(property->access() == AbstractProperty::Read)
231 else if(property->access() == AbstractProperty::Write)
233 else if(property->access() == AbstractProperty::ReadWrite)
234 access = "readwrite";
235 else throw -1; //FIXME: don't throw
237 std::string pn = property->name();
239 ///see which properties are supported:
241 "<property type='"+ string(property->signature()) + "' name='"+ pn +"' access='"+access+"' />"
242 "<method name='Get" + pn + "'>"
243 " <arg type='v' direction='out' name='value' />"
244 " <arg type='d' direction='out' name='timestamp' />"
245 " <arg type='i' direction='out' name='sequence' />"
246 " <arg type='i' direction='out' name='updateFrequency' />"
248 "<signal name='" + pn + "Changed' >"
249 " <arg type='v' name='" + nameToLower + "' direction='out' />"
250 " <arg type='d' name='timestamp' direction='out' />"
252 "<property type='i' name='" + property->name() + "Sequence' access='read' />";
254 properties[property->name()] = property;
256 if(!ListPlusPlus<string>(&mimplementedProperties).contains(property->ambPropertyName()))
258 std::string pname = property->ambPropertyName();
259 mimplementedProperties.push_back(pname);
263 void AbstractDBusInterface::registerObject()
267 throw std::runtime_error("forgot to call setDBusConnection on AbstractDBusInterface");
270 if(introspectionXml.empty())
272 cerr<<"no interface to export: "<<mInterfaceName<<endl;
276 if(!boost::algorithm::ends_with(introspectionXml,"</node>"))
278 introspectionXml += "</interface>"
284 GDBusNodeInfo* introspection = g_dbus_node_info_new_for_xml(introspectionXml.c_str(), &error);
286 if(!introspection || error)
289 DebugOut(DebugOut::Error)<<"Error in "<<__FILE__<<" - "<<__FUNCTION__<<":"<<__LINE__<<endl;
290 DebugOut(DebugOut::Error)<<error->message<<endl;
291 DebugOut(DebugOut::Error)<<"probably bad xml:"<<endl;
292 DebugOut(DebugOut::Error)<<introspectionXml<<endl;
299 GDBusInterfaceInfo* mInterfaceInfo = g_dbus_node_info_lookup_interface(introspection, mInterfaceName.c_str());
302 const GDBusInterfaceVTable vtable = { handleMyMethodCall, AbstractDBusInterface::getProperty, AbstractDBusInterface::setProperty };
306 DebugOut()<<"registering DBus path: "<<mObjectPath<<endl;
308 regId = g_dbus_connection_register_object(mConnection, mObjectPath.c_str(), mInterfaceInfo, &vtable, this, NULL, &error2);
309 g_dbus_node_info_unref(introspection);
312 DebugOut(DebugOut::Error)<<error2->message<<endl;
313 g_error_free(error2);
318 DebugOut(DebugOut::Error)<<"We failed to register on DBus"<<endl;
322 void AbstractDBusInterface::unregisterObject()
325 g_dbus_connection_unregister_object(mConnection, regId);
330 void AbstractDBusInterface::updateValue(AbstractProperty *property)
332 if(mConnection == nullptr)
338 signaller->fireSignal(mConnection, mObjectPath, mInterfaceName, "PropertiesChanged", property);
341 std::list<AbstractDBusInterface *> AbstractDBusInterface::getObjectsForProperty(string object)
343 std::list<AbstractDBusInterface *> l;
344 for(auto itr = objectMap.begin(); itr != objectMap.end(); itr++)
346 AbstractDBusInterface * interface = (*itr).second;
347 if(interface->objectName() == object)
348 l.push_back(interface);
353 list<AbstractDBusInterface *> AbstractDBusInterface::interfaces()
355 std::list<AbstractDBusInterface*> ifaces;
357 for(auto itr = objectMap.begin(); itr != objectMap.end(); itr++)
359 ifaces.push_back((*itr).second);
365 bool AbstractDBusInterface::implementsProperty(string property)
367 for(auto itr = properties.begin(); itr != properties.end(); itr++)
369 if((*itr).first == property)
378 void AbstractDBusInterface::startRegistration()
381 introspectionXml ="<node>" ;
383 "<interface name='"+ mInterfaceName + "' >"
384 "<property type='i' name='Zone' access='read' />"
385 "<property type='d' name='Time' access='read' />"
386 "<method name='GetHistory'>"
387 " <arg type='d' direction='in' name='beginTimestamp' />"
388 " <arg type='d' direction='in' name='endTimestamp' />"
389 " <arg type='a(svd)' direction='out' name='result' />"
393 GVariant* AbstractDBusInterface::getProperty(GDBusConnection* connection, const gchar* sender, const gchar* objectPath, const gchar* interfaceName, const gchar* propertyName, GError** error, gpointer userData)
395 if(DebugOut::getDebugThreshhold() >= 6)
397 DebugOut(6)<<"DBus GetProperty call from: "<<sender<< " pid: " <<getPid(sender)<< " interface: "<<interfaceName<<" property: "<<propertyName<<endl;
398 DebugOut(6)<<"DBus GetProperty call path: "<<objectPath<<endl;
401 std::string pn = propertyName;
404 if(objectMap.find(objectPath) == objectMap.end())
406 DebugOut(DebugOut::Error)<<objectPath<<" is not a valid object path."<<endl;
409 double time = objectMap[objectPath]->time();
411 GVariant* value = g_variant_new("d", time);
415 if(boost::ends_with(pn, "Sequence"))
417 AbstractDBusInterface* t = static_cast<AbstractDBusInterface*>(userData);
419 int pos = pn.find("Sequence");
421 std::string p = pn.substr(0,pos);
423 AbstractProperty* theProperty = t->property(p);
427 DebugOut(DebugOut::Error)<<"Invalid Sequence property: "<<p<<endl;
431 int sequence = theProperty->sequence();
433 GVariant* value = g_variant_new("i", sequence);
439 if(objectMap.find(objectPath) == objectMap.end())
441 DebugOut(DebugOut::Error)<<objectPath<<" is not a valid object path."<<endl;
445 Zone::Type zone = objectMap[objectPath]->zone();
447 GVariant* value = g_variant_new("i",(int)zone);
451 if(objectMap.count(objectPath))
453 GVariant* value = objectMap[objectPath]->getProperty(propertyName);
458 DebugOut(DebugOut::Error)<<"No interface for" << interfaceName <<endl;
462 gboolean AbstractDBusInterface::setProperty(GDBusConnection* connection, const gchar* sender, const gchar* objectPath, const gchar* interfaceName, const gchar* propertyName, GVariant* value, GError** error, gpointer userData)
464 if(DebugOut::getDebugThreshhold() >= 6)
466 DebugOut(6)<<"DBus SetProperty call from: "<<sender<< " pid: " <<getPid(sender)<< " interface: "<<interfaceName<<" property: "<<propertyName<<endl;
467 DebugOut(6)<<"DBus SetProperty call path: "<<objectPath<<endl;
470 if(objectMap.count(objectPath))
472 objectMap[objectPath]->setProperty(propertyName, value);
479 void AbstractDBusInterface::setProperty(string propertyName, GVariant *value)
481 if(properties.count(propertyName))
483 properties[propertyName]->fromGVariant(value);
491 GVariant *AbstractDBusInterface::getProperty(string propertyName)
493 if(properties.count(propertyName))
494 return properties[propertyName]->toGVariant();
499 void AbstractDBusInterface::setTimeout(int timeout)
502 signaller = DBusSignaller::factory(timeout);