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 "varianttype.h"
29 #include "dbussignaller.h"
31 static DBusSignaller* signaller = nullptr;
33 unordered_map<string, AbstractDBusInterface*> AbstractDBusInterface::objectMap;
34 PropertyList AbstractDBusInterface::mimplementedProperties;
36 const uint getPid(const char *owner)
38 GError* error = nullptr;
39 GDBusProxy* dbus = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL,
40 "org.freedesktop.DBus",
42 "org.freedesktop.DBus",
48 throw std::runtime_error(error->message);
53 GVariant* pid = g_dbus_proxy_call_sync(dbus, "GetConnectionUnixProcessID", g_variant_new("(s)", owner), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
57 throw std::runtime_error(error->message);
62 g_variant_get(pid,"(u)",&thePid);
69 static void handleMyMethodCall(GDBusConnection *connection,
71 const gchar *object_path,
72 const gchar *interface_name,
73 const gchar *method_name,
75 GDBusMethodInvocation *invocation,
79 std::string method = method_name;
80 AbstractDBusInterface* iface = static_cast<AbstractDBusInterface*>(user_data);
82 if(DebugOut::getDebugThreshhold() >= 6)
84 DebugOut(6)<<"DBus method call from: "<<sender<< " pid: " <<getPid(sender)<< " interface: "<<interface_name<<" method: "<<method<<endl;
85 DebugOut(6)<<"DBus method call path: "<<object_path<<endl;
90 if(method == "GetHistory")
95 g_variant_get(parameters, "(dd)", &beginTime, &endTime);
97 auto propertyMap = iface->getProperties();
99 PropertyList propertyList;
101 for(auto itr = propertyMap.begin(); itr != propertyMap.end(); itr++)
103 VariantType* prop = (*itr).second;
105 if(!contains(propertyList, prop->ambPropertyName()))
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* r)
121 auto reply = amb::make_unique(r);
125 str<<"Error during request: "<<AsyncPropertyReply::errorToStr(reply->error);
126 ifaceName += ".Error";
127 g_dbus_method_invocation_return_dbus_error(invocation, ifaceName.c_str(), str.str().c_str());
131 if(!reply->values.size())
133 ifaceName += ".Error";
134 g_dbus_method_invocation_return_dbus_error(invocation, ifaceName.c_str(), "No results");
138 GVariantBuilder builder;
139 g_variant_builder_init(&builder, G_VARIANT_TYPE("a(svd)"));
142 for(auto itr = reply->values.begin(); itr != reply->values.end(); itr++)
144 AbstractPropertyType* value = *itr;
146 g_variant_builder_add(&builder, "(svd)", value->name.c_str(), g_variant_ref(value->toVariant()),value->timestamp);
149 g_dbus_method_invocation_return_value(invocation,g_variant_new("(a(svd))",&builder));
152 iface->re->getRangePropertyAsync(request);
157 else if(boost::algorithm::starts_with(method, "Get"))
159 std::string propertyName = method.substr(3);
160 auto propertyMap = iface->getProperties();
161 if(propertyMap.find(propertyName) == propertyMap.end())
163 g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method.");
167 VariantType * property = propertyMap[propertyName];
169 GError *error = NULL;
171 GVariant **params = g_new(GVariant*,4);
172 GVariant *val = g_variant_ref(property->value()->toVariant());
173 params[0] = g_variant_new("v", val);
174 params[1] = g_variant_new("d",property->timestamp());
175 params[2] = g_variant_new("i",property->value()->sequence);
176 params[3] = g_variant_new("i",property->updateFrequency());
178 GVariant *tuple_variant = g_variant_new_tuple(params,4);
180 g_dbus_method_invocation_return_value(invocation, tuple_variant);
183 g_variant_unref(val);
187 DebugOut(DebugOut::Error)<<error->message<<endl;
193 g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method.");
196 AbstractDBusInterface::AbstractDBusInterface(string interfaceName, string objectName,
197 GDBusConnection* connection)
198 : mInterfaceName(interfaceName), mConnection(connection), mPropertyName(objectName), supported(false), zoneFilter(Zone::None), mTime(0), regId(0)
202 mObjectPath = "/" + objectName;
205 AbstractDBusInterface::~AbstractDBusInterface()
209 PropertyList impl = implementedProperties();
211 for(auto itr = impl.begin(); itr != impl.end(); itr++)
213 if(properties.find(*itr) != properties.end())
215 // Deleted in ~DBusSink()
216 //delete properties[*itr];
217 properties.erase(*itr);
221 objectMap.erase(mObjectPath);
225 void AbstractDBusInterface::addProperty(VariantType * property)
227 string nameToLower = property->name();
228 boost::algorithm::to_lower<string>(nameToLower);
232 if(property->access() == VariantType::Read)
234 else if(property->access() == VariantType::Write)
236 else if(property->access() == VariantType::ReadWrite)
237 access = "readwrite";
238 else throw -1; //FIXME: don't throw
240 std::string pn = property->name();
242 ///see which properties are supported:
244 "<property type='"+ string(property->signature()) + "' name='"+ pn +"' access='"+access+"' />"
245 "<method name='Get" + pn + "'>"
246 " <arg type='v' direction='out' name='value' />"
247 " <arg type='d' direction='out' name='timestamp' />"
248 " <arg type='i' direction='out' name='sequence' />"
249 " <arg type='i' direction='out' name='updateFrequency' />"
251 "<signal name='" + pn + "Changed' >"
252 " <arg type='v' name='" + nameToLower + "' direction='out' />"
253 " <arg type='d' name='imestamp' direction='out' />"
255 "<property type='i' name='" + pn + "Sequence' access='read' />";
257 properties[pn] = property;
259 if(!contains(mimplementedProperties, property->ambPropertyName()))
261 std::string pname = property->ambPropertyName();
262 mimplementedProperties.push_back(pname);
266 void AbstractDBusInterface::registerObject()
270 throw std::runtime_error("forgot to call setDBusConnection on AbstractDBusInterface");
273 if(introspectionXml.empty())
275 cerr<<"no interface to export: "<<mInterfaceName<<endl;
279 if(!boost::algorithm::ends_with(introspectionXml,"</node>"))
281 introspectionXml += "</interface>"
287 GDBusNodeInfo* introspection = g_dbus_node_info_new_for_xml(introspectionXml.c_str(), &error);
289 if(!introspection || error)
292 DebugOut(DebugOut::Error)<<"Error in "<<__FILE__<<" - "<<__FUNCTION__<<":"<<__LINE__<<endl;
293 DebugOut(DebugOut::Error)<<error->message<<endl;
294 DebugOut(DebugOut::Error)<<"probably bad xml:"<<endl;
295 DebugOut(DebugOut::Error)<<introspectionXml<<endl;
302 GDBusInterfaceInfo* mInterfaceInfo = g_dbus_node_info_lookup_interface(introspection, mInterfaceName.c_str());
305 const GDBusInterfaceVTable vtable = { handleMyMethodCall, AbstractDBusInterface::getProperty, AbstractDBusInterface::setProperty };
309 DebugOut()<<"registering DBus path: "<<mObjectPath<<endl;
311 regId = g_dbus_connection_register_object(mConnection, mObjectPath.c_str(), mInterfaceInfo, &vtable, this, NULL, &error2);
312 g_dbus_node_info_unref(introspection);
315 DebugOut(DebugOut::Error)<<error2->message<<endl;
316 g_error_free(error2);
321 DebugOut(DebugOut::Error)<<"We failed to register on DBus"<<endl;
325 void AbstractDBusInterface::unregisterObject()
329 DebugOut()<<__FUNCTION__<<endl;
330 g_dbus_connection_unregister_object(mConnection, regId);
336 void AbstractDBusInterface::updateValue(VariantType *property)
338 if(mConnection == nullptr)
344 signaller->fireSignal(mConnection, mObjectPath, mInterfaceName, "PropertiesChanged", property);
347 std::list<AbstractDBusInterface *> AbstractDBusInterface::getObjectsForProperty(string object)
349 std::list<AbstractDBusInterface *> l;
350 for(auto itr = objectMap.begin(); itr != objectMap.end(); itr++)
352 AbstractDBusInterface * interface = (*itr).second;
353 if(interface->objectName() == object)
354 l.push_back(interface);
359 list<AbstractDBusInterface *> AbstractDBusInterface::interfaces()
361 std::list<AbstractDBusInterface*> ifaces;
363 for(auto itr = objectMap.begin(); itr != objectMap.end(); itr++)
365 ifaces.push_back((*itr).second);
371 std::vector<std::string> AbstractDBusInterface::supportedInterfaces()
373 std::vector<std::string> ifaces;
375 for(auto itr : objectMap)
377 if(itr.second->isSupported())
378 ifaces.push_back(itr.second->objectName());
384 bool AbstractDBusInterface::implementsProperty(string property)
386 for(auto itr = properties.begin(); itr != properties.end(); itr++)
388 if((*itr).first == property)
397 void AbstractDBusInterface::startRegistration()
399 //unregisterObject();
400 introspectionXml ="<node>" ;
402 "<interface name='"+ mInterfaceName + "' >"
403 "<property type='i' name='Zone' access='read' />"
404 "<property type='d' name='Time' access='read' />"
405 "<method name='GetHistory'>"
406 " <arg type='d' direction='in' name='beginTimestamp' />"
407 " <arg type='d' direction='in' name='endTimestamp' />"
408 " <arg type='a(svd)' direction='out' name='result' />"
412 GVariant* AbstractDBusInterface::getProperty(GDBusConnection* connection, const gchar* sender, const gchar* objectPath, const gchar* interfaceName, const gchar* propertyName, GError** error, gpointer userData)
414 if(DebugOut::getDebugThreshhold() >= 6)
416 DebugOut(6)<<"DBus GetProperty call from: "<<sender<< " pid: " <<getPid(sender)<< " interface: "<<interfaceName<<" property: "<<propertyName<<endl;
417 DebugOut(6)<<"DBus GetProperty call path: "<<objectPath<<endl;
420 std::string pn = propertyName;
423 if(objectMap.find(objectPath) == objectMap.end())
425 DebugOut(DebugOut::Error)<<objectPath<<" is not a valid object path."<<endl;
428 double time = objectMap[objectPath]->time();
430 GVariant* value = g_variant_new("d", time);
434 if(boost::ends_with(pn, "Sequence"))
436 AbstractDBusInterface* t = static_cast<AbstractDBusInterface*>(userData);
438 int pos = pn.find("Sequence");
440 std::string p = pn.substr(0,pos);
442 VariantType * theProperty = t->property(p);
446 DebugOut(DebugOut::Error)<<"Invalid Sequence property: "<<p<<endl;
450 int sequence = theProperty->sequence();
452 GVariant* value = g_variant_new("i", sequence);
458 if(objectMap.find(objectPath) == objectMap.end())
460 DebugOut(DebugOut::Error)<<objectPath<<" is not a valid object path."<<endl;
464 Zone::Type zone = objectMap[objectPath]->zone();
466 GVariant* value = g_variant_new("i",(int)zone);
470 if(objectMap.count(objectPath))
472 GVariant* value = objectMap[objectPath]->getProperty(propertyName);
477 DebugOut(DebugOut::Error)<<"No interface for" << interfaceName <<endl;
481 gboolean AbstractDBusInterface::setProperty(GDBusConnection* connection, const gchar* sender, const gchar* objectPath, const gchar* interfaceName, const gchar* propertyName, GVariant* value, GError** error, gpointer userData)
483 if(DebugOut::getDebugThreshhold() >= 6)
485 DebugOut(6)<<"DBus SetProperty call from: "<<sender<< " pid: " <<getPid(sender)<< " interface: "<<interfaceName<<" property: "<<propertyName<<endl;
486 DebugOut(6)<<"DBus SetProperty call path: "<<objectPath<<endl;
489 if(objectMap.count(objectPath))
491 objectMap[objectPath]->setProperty(propertyName, value);
498 void AbstractDBusInterface::setProperty(string propertyName, GVariant *value)
500 if(properties.count(propertyName))
502 properties[propertyName]->fromVariant(value);
510 GVariant *AbstractDBusInterface::getProperty(string propertyName)
512 if(properties.count(propertyName))
513 return properties[propertyName]->toVariant();
518 void AbstractDBusInterface::setTimeout(int timeout)
521 signaller = DBusSignaller::factory(timeout);