Home | History | Annotate | Download | only in dbus
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chromeos/dbus/nfc_client_helpers.h"
      6 
      7 #include "base/stl_util.h"
      8 #include "dbus/values_util.h"
      9 
     10 namespace chromeos {
     11 namespace nfc_client_helpers {
     12 
     13 const char kNoResponseError[] = "org.chromium.Error.NoResponse";
     14 const char kUnknownObjectError[] = "org.chromium.Error.UnknownObject";
     15 
     16 void OnSuccess(const base::Closure& callback, dbus::Response* response) {
     17   DCHECK(response);
     18   callback.Run();
     19 }
     20 
     21 void OnError(const ErrorCallback& error_callback,
     22              dbus::ErrorResponse* response) {
     23   // Error response has optional error message argument.
     24   std::string error_name;
     25   std::string error_message;
     26   if (response) {
     27     dbus::MessageReader reader(response);
     28     error_name = response->GetErrorName();
     29     reader.PopString(&error_message);
     30   } else {
     31     error_name = kNoResponseError;
     32     error_message = "";
     33   }
     34   error_callback.Run(error_name, error_message);
     35 }
     36 
     37 void AppendValueDataAsVariant(dbus::MessageWriter* writer,
     38                               const base::Value& value) {
     39   switch (value.GetType()) {
     40     case base::Value::TYPE_DICTIONARY: {
     41       const base::DictionaryValue* dictionary = NULL;
     42       value.GetAsDictionary(&dictionary);
     43       dbus::MessageWriter variant_writer(NULL);
     44       dbus::MessageWriter array_writer(NULL);
     45       writer->OpenVariant("a{sv}", &variant_writer);
     46       variant_writer.OpenArray("{sv}", &array_writer);
     47       for (base::DictionaryValue::Iterator iter(*dictionary);
     48            !iter.IsAtEnd(); iter.Advance()) {
     49         dbus::MessageWriter entry_writer(NULL);
     50         array_writer.OpenDictEntry(&entry_writer);
     51         entry_writer.AppendString(iter.key());
     52         AppendValueDataAsVariant(&entry_writer, iter.value());
     53         array_writer.CloseContainer(&entry_writer);
     54       }
     55       variant_writer.CloseContainer(&array_writer);
     56       writer->CloseContainer(&variant_writer);
     57       break;
     58     }
     59     case base::Value::TYPE_LIST: {
     60       const base::ListValue* list = NULL;
     61       value.GetAsList(&list);
     62       dbus::MessageWriter variant_writer(NULL);
     63       dbus::MessageWriter array_writer(NULL);
     64       writer->OpenVariant("av", &variant_writer);
     65       variant_writer.OpenArray("v", &array_writer);
     66       for (base::ListValue::const_iterator iter = list->begin();
     67            iter != list->end(); ++iter) {
     68         const base::Value* value = *iter;
     69         AppendValueDataAsVariant(&array_writer, *value);
     70       }
     71       variant_writer.CloseContainer(&array_writer);
     72       writer->CloseContainer(&variant_writer);
     73       break;
     74     }
     75     case base::Value::TYPE_BOOLEAN:
     76     case base::Value::TYPE_INTEGER:
     77     case base::Value::TYPE_DOUBLE:
     78     case base::Value::TYPE_STRING:
     79       dbus::AppendBasicTypeValueDataAsVariant(writer, value);
     80       break;
     81     default:
     82       DLOG(ERROR) << "Unexpected type: " << value.GetType();
     83   }
     84 }
     85 
     86 DBusObjectMap::DBusObjectMap(const std::string& service_name,
     87                              Delegate* delegate,
     88                              dbus::Bus* bus)
     89     : bus_(bus),
     90       service_name_(service_name),
     91       delegate_(delegate) {
     92   DCHECK(bus_);
     93   DCHECK(delegate_);
     94 }
     95 
     96 DBusObjectMap::~DBusObjectMap() {
     97   // Clean up the Properties structures. We don't explicitly delete the object
     98   // proxies, as they are owned by dbus::Bus.
     99   for (ObjectMap::iterator iter = object_map_.begin();
    100        iter != object_map_.end(); ++iter) {
    101     const dbus::ObjectPath& object_path = iter->first;
    102     ObjectPropertyPair pair = iter->second;
    103     delegate_->ObjectRemoved(object_path);
    104     CleanUpObjectPropertyPair(pair);
    105   }
    106 }
    107 
    108 dbus::ObjectProxy* DBusObjectMap::GetObjectProxy(
    109     const dbus::ObjectPath& object_path) {
    110   return GetObjectPropertyPair(object_path).first;
    111 }
    112 
    113 NfcPropertySet* DBusObjectMap::GetObjectProperties(
    114     const dbus::ObjectPath& object_path) {
    115   return GetObjectPropertyPair(object_path).second;
    116 }
    117 
    118 void DBusObjectMap::UpdateObjects(const ObjectPathVector& object_paths) {
    119   // This set is used to query if an object path was removed, while updating
    120   // the removed paths below. The iterator is used as a hint to accelerate
    121   // insertion.
    122   std::set<dbus::ObjectPath> object_path_set;
    123   std::set<dbus::ObjectPath>::iterator object_path_set_iter =
    124       object_path_set.begin();
    125 
    126   // Add all objects.
    127   for (ObjectPathVector::const_iterator iter = object_paths.begin();
    128        iter != object_paths.end(); ++iter) {
    129     const dbus::ObjectPath &object_path = *iter;
    130     AddObject(object_path);
    131     // Neard usually returns object paths in ascending order. Give a hint here
    132     // to make insertion amortized constant.
    133     object_path_set_iter =
    134         object_path_set.insert(object_path_set_iter, object_path);
    135   }
    136 
    137   // Remove all objects that are not in |object_paths|.
    138   ObjectMap::const_iterator iter = object_map_.begin();
    139   while (iter != object_map_.end()) {
    140     // It is safe to use a const reference here, as DBusObjectMap::RemoveObject
    141     // won't access it after the iterator becomes invalidated.
    142     const dbus::ObjectPath &object_path = iter->first;
    143     ++iter;
    144     if (!ContainsKey(object_path_set, object_path))
    145       RemoveObject(object_path);
    146   }
    147 }
    148 
    149 bool DBusObjectMap::AddObject(const dbus::ObjectPath& object_path) {
    150   ObjectMap::iterator iter = object_map_.find(object_path);
    151   if (iter != object_map_.end())
    152     return false;
    153 
    154   DCHECK(bus_);
    155   DCHECK(delegate_);
    156   dbus::ObjectProxy* object_proxy = bus_->GetObjectProxy(service_name_,
    157                                                          object_path);
    158 
    159   // Create the properties structure.
    160   NfcPropertySet* properties = delegate_->CreateProperties(object_proxy);
    161   properties->ConnectSignals();
    162   properties->GetAll();
    163   ObjectPropertyPair object = std::make_pair(object_proxy, properties);
    164   object_map_[object_path] = object;
    165   VLOG(1) << "Created proxy for object with Path: " << object_path.value()
    166           << ", Service: " << service_name_;
    167   delegate_->ObjectAdded(object_path);
    168   return true;
    169 }
    170 
    171 void DBusObjectMap::RemoveObject(const dbus::ObjectPath& object_path) {
    172   DCHECK(bus_);
    173   DCHECK(delegate_);
    174   ObjectMap::iterator iter = object_map_.find(object_path);
    175   if (iter == object_map_.end())
    176     return;
    177 
    178   // Notify the delegate, so that it can perform any clean up that is
    179   // necessary.
    180   delegate_->ObjectRemoved(object_path);
    181 
    182   // Clean up the object proxy and the properties structure.
    183   ObjectPropertyPair pair = iter->second;
    184   CleanUpObjectPropertyPair(pair);
    185   object_map_.erase(iter);
    186   VLOG(1) << "Object proxy removed for object path: "
    187           << object_path.value();
    188 }
    189 
    190 void DBusObjectMap::RefreshProperties(const dbus::ObjectPath& object_path) {
    191   NfcPropertySet* properties = GetObjectProperties(object_path);
    192   if (properties)
    193     properties->GetAll();
    194 }
    195 
    196 void DBusObjectMap::RefreshAllProperties() {
    197   for (ObjectMap::const_iterator iter = object_map_.begin();
    198        iter != object_map_.end(); ++iter) {
    199     const dbus::ObjectPath& object_path = iter->first;
    200     RefreshProperties(object_path);
    201   }
    202 }
    203 
    204 ObjectPathVector DBusObjectMap::GetObjectPaths() {
    205   std::vector<dbus::ObjectPath> object_paths;
    206   for (ObjectMap::const_iterator iter = object_map_.begin();
    207        iter != object_map_.end(); ++iter) {
    208     const dbus::ObjectPath& object_path = iter->first;
    209     object_paths.push_back(object_path);
    210   }
    211   return object_paths;
    212 }
    213 
    214 DBusObjectMap::ObjectPropertyPair DBusObjectMap::GetObjectPropertyPair(
    215     const dbus::ObjectPath& object_path) {
    216   ObjectMap::iterator iter = object_map_.find(object_path);
    217   if (iter != object_map_.end())
    218     return iter->second;
    219   return std::make_pair(static_cast<dbus::ObjectProxy*>(NULL),
    220                         static_cast<NfcPropertySet*>(NULL));
    221 }
    222 
    223 void DBusObjectMap::CleanUpObjectPropertyPair(const ObjectPropertyPair& pair) {
    224   dbus::ObjectProxy* object_proxy = pair.first;
    225   NfcPropertySet* properties = pair.second;
    226   bus_->RemoveObjectProxy(service_name_,
    227                           object_proxy->object_path(),
    228                           base::Bind(&base::DoNothing));
    229   delete properties;
    230 }
    231 
    232 ObjectProxyTree::ObjectProxyTree() {
    233 }
    234 
    235 ObjectProxyTree::~ObjectProxyTree() {
    236   for (PathsToObjectMapsType::iterator iter = paths_to_object_maps_.begin();
    237        iter != paths_to_object_maps_.end(); ++iter) {
    238     DBusObjectMap* object_map = iter->second;
    239     delete object_map;
    240   }
    241 }
    242 
    243 bool ObjectProxyTree::CreateObjectMap(const dbus::ObjectPath& object_path,
    244                                       const std::string& service_name,
    245                                       DBusObjectMap::Delegate* delegate,
    246                                       dbus::Bus* bus) {
    247   if (ContainsKey(paths_to_object_maps_, object_path)) {
    248     LOG(ERROR) << "Mapping already exists for object path: "
    249                << object_path.value();
    250     return false;
    251   }
    252   paths_to_object_maps_[object_path] =
    253       new DBusObjectMap(service_name, delegate, bus);
    254   return true;
    255 }
    256 
    257 void ObjectProxyTree::RemoveObjectMap(const dbus::ObjectPath& object_path) {
    258   PathsToObjectMapsType::iterator iter =
    259       paths_to_object_maps_.find(object_path);
    260   if (iter == paths_to_object_maps_.end())
    261     return;
    262   DBusObjectMap* object_map = iter->second;
    263   delete object_map;
    264   paths_to_object_maps_.erase(iter);
    265 }
    266 
    267 DBusObjectMap* ObjectProxyTree::GetObjectMap(
    268     const dbus::ObjectPath& object_path) {
    269   PathsToObjectMapsType::iterator iter =
    270       paths_to_object_maps_.find(object_path);
    271   if (iter == paths_to_object_maps_.end())
    272     return NULL;
    273   return iter->second;
    274 }
    275 
    276 dbus::ObjectProxy* ObjectProxyTree::FindObjectProxy(
    277     const dbus::ObjectPath& object_proxy_path) {
    278   for (PathsToObjectMapsType::iterator iter = paths_to_object_maps_.begin();
    279        iter != paths_to_object_maps_.end(); ++iter) {
    280     DBusObjectMap* object_map = iter->second;
    281     dbus::ObjectProxy* object_proxy =
    282         object_map->GetObjectProxy(object_proxy_path);
    283     if (object_proxy)
    284       return object_proxy;
    285   }
    286   return NULL;
    287 }
    288 
    289 NfcPropertySet* ObjectProxyTree::FindObjectProperties(
    290     const dbus::ObjectPath& object_proxy_path) {
    291   for (PathsToObjectMapsType::iterator iter = paths_to_object_maps_.begin();
    292        iter != paths_to_object_maps_.end(); ++iter) {
    293     DBusObjectMap* object_map = iter->second;
    294     NfcPropertySet* properties =
    295         object_map->GetObjectProperties(object_proxy_path);
    296     if (properties)
    297       return properties;
    298   }
    299   return NULL;
    300 }
    301 
    302 }  // namespace nfc_client_helpers
    303 }  // namespace chromeos
    304