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