1// Copyright (c) 2012 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 "dbus/property.h"
6
7#include "base/basictypes.h"
8#include "base/bind.h"
9#include "base/logging.h"
10
11#include "dbus/message.h"
12#include "dbus/object_path.h"
13#include "dbus/object_proxy.h"
14
15namespace dbus {
16
17//
18// PropertyBase implementation.
19//
20
21void PropertyBase::Init(PropertySet* property_set, const std::string& name) {
22  DCHECK(!property_set_);
23  property_set_ = property_set;
24  name_ = name;
25}
26
27
28//
29// PropertySet implementation.
30//
31
32PropertySet::PropertySet(
33    ObjectProxy* object_proxy,
34    const std::string& interface,
35    const PropertyChangedCallback& property_changed_callback)
36    : object_proxy_(object_proxy),
37      interface_(interface),
38      property_changed_callback_(property_changed_callback),
39      weak_ptr_factory_(this) {}
40
41PropertySet::~PropertySet() {
42}
43
44void PropertySet::RegisterProperty(const std::string& name,
45                                   PropertyBase* property) {
46  property->Init(this, name);
47  properties_map_[name] = property;
48}
49
50void PropertySet::ConnectSignals() {
51  DCHECK(object_proxy_);
52  object_proxy_->ConnectToSignal(
53      kPropertiesInterface,
54      kPropertiesChanged,
55      base::Bind(&PropertySet::ChangedReceived,
56                 weak_ptr_factory_.GetWeakPtr()),
57      base::Bind(&PropertySet::ChangedConnected,
58                 weak_ptr_factory_.GetWeakPtr()));
59}
60
61
62void PropertySet::ChangedReceived(Signal* signal) {
63  DCHECK(signal);
64  MessageReader reader(signal);
65
66  std::string interface;
67  if (!reader.PopString(&interface)) {
68    LOG(WARNING) << "Property changed signal has wrong parameters: "
69                 << "expected interface name: " << signal->ToString();
70    return;
71  }
72
73  if (interface != this->interface())
74    return;
75
76  if (!UpdatePropertiesFromReader(&reader)) {
77    LOG(WARNING) << "Property changed signal has wrong parameters: "
78                 << "expected dictionary: " << signal->ToString();
79  }
80
81  // TODO(keybuk): dbus properties api has invalidated properties array
82  // on the end, we don't handle this right now because I don't know of
83  // any service that sends it - or what they expect us to do with it.
84  // Add later when we need it.
85}
86
87void PropertySet::ChangedConnected(const std::string& interface_name,
88                                   const std::string& signal_name,
89                                   bool success) {
90  LOG_IF(WARNING, !success) << "Failed to connect to " << signal_name
91                            << "signal.";
92}
93
94
95void PropertySet::Get(PropertyBase* property, GetCallback callback) {
96  MethodCall method_call(kPropertiesInterface, kPropertiesGet);
97  MessageWriter writer(&method_call);
98  writer.AppendString(interface());
99  writer.AppendString(property->name());
100
101  DCHECK(object_proxy_);
102  object_proxy_->CallMethod(&method_call,
103                            ObjectProxy::TIMEOUT_USE_DEFAULT,
104                            base::Bind(&PropertySet::OnGet,
105                                       GetWeakPtr(),
106                                       property,
107                                       callback));
108}
109
110void PropertySet::OnGet(PropertyBase* property, GetCallback callback,
111                        Response* response) {
112  if (!response) {
113    LOG(WARNING) << property->name() << ": Get: failed.";
114    return;
115  }
116
117  MessageReader reader(response);
118  if (property->PopValueFromReader(&reader))
119    NotifyPropertyChanged(property->name());
120
121  if (!callback.is_null())
122    callback.Run(response);
123}
124
125void PropertySet::GetAll() {
126  MethodCall method_call(kPropertiesInterface, kPropertiesGetAll);
127  MessageWriter writer(&method_call);
128  writer.AppendString(interface());
129
130  DCHECK(object_proxy_);
131  object_proxy_->CallMethod(&method_call,
132                            ObjectProxy::TIMEOUT_USE_DEFAULT,
133                            base::Bind(&PropertySet::OnGetAll,
134                                       weak_ptr_factory_.GetWeakPtr()));
135}
136
137void PropertySet::OnGetAll(Response* response) {
138  if (!response) {
139    LOG(WARNING) << "GetAll request failed for: " << interface_;
140    return;
141  }
142
143  MessageReader reader(response);
144  if (!UpdatePropertiesFromReader(&reader)) {
145    LOG(WARNING) << "GetAll response has wrong parameters: "
146                 << "expected dictionary: " << response->ToString();
147  }
148}
149
150void PropertySet::Set(PropertyBase* property, SetCallback callback) {
151  MethodCall method_call(kPropertiesInterface, kPropertiesSet);
152  MessageWriter writer(&method_call);
153  writer.AppendString(interface());
154  writer.AppendString(property->name());
155  property->AppendSetValueToWriter(&writer);
156
157  DCHECK(object_proxy_);
158  object_proxy_->CallMethod(&method_call,
159                            ObjectProxy::TIMEOUT_USE_DEFAULT,
160                            base::Bind(&PropertySet::OnSet,
161                                       GetWeakPtr(),
162                                       property,
163                                       callback));
164}
165
166void PropertySet::OnSet(PropertyBase* property,
167                        SetCallback callback,
168                        Response* response) {
169  LOG_IF(WARNING, !response) << property->name() << ": Set: failed.";
170  if (!callback.is_null())
171    callback.Run(response);
172}
173
174bool PropertySet::UpdatePropertiesFromReader(MessageReader* reader) {
175  DCHECK(reader);
176  MessageReader array_reader(NULL);
177  if (!reader->PopArray(&array_reader))
178    return false;
179
180  while (array_reader.HasMoreData()) {
181    MessageReader dict_entry_reader(NULL);
182    if (array_reader.PopDictEntry(&dict_entry_reader))
183      UpdatePropertyFromReader(&dict_entry_reader);
184  }
185
186  return true;
187}
188
189bool PropertySet::UpdatePropertyFromReader(MessageReader* reader) {
190  DCHECK(reader);
191
192  std::string name;
193  if (!reader->PopString(&name))
194    return false;
195
196  PropertiesMap::iterator it = properties_map_.find(name);
197  if (it == properties_map_.end())
198    return false;
199
200  PropertyBase* property = it->second;
201  if (property->PopValueFromReader(reader)) {
202    NotifyPropertyChanged(name);
203    return true;
204  } else {
205    return false;
206  }
207}
208
209
210void PropertySet::NotifyPropertyChanged(const std::string& name) {
211  if (!property_changed_callback_.is_null())
212    property_changed_callback_.Run(name);
213}
214
215//
216// Property<Byte> specialization.
217//
218
219template <>
220Property<uint8>::Property() : value_(0) {
221}
222
223template <>
224bool Property<uint8>::PopValueFromReader(MessageReader* reader) {
225  return reader->PopVariantOfByte(&value_);
226}
227
228template <>
229void Property<uint8>::AppendSetValueToWriter(MessageWriter* writer) {
230  writer->AppendVariantOfByte(set_value_);
231}
232
233//
234// Property<bool> specialization.
235//
236
237template <>
238Property<bool>::Property() : value_(false) {
239}
240
241template <>
242bool Property<bool>::PopValueFromReader(MessageReader* reader) {
243  return reader->PopVariantOfBool(&value_);
244}
245
246template <>
247void Property<bool>::AppendSetValueToWriter(MessageWriter* writer) {
248  writer->AppendVariantOfBool(set_value_);
249}
250
251//
252// Property<int16> specialization.
253//
254
255template <>
256Property<int16>::Property() : value_(0) {
257}
258
259template <>
260bool Property<int16>::PopValueFromReader(MessageReader* reader) {
261  return reader->PopVariantOfInt16(&value_);
262}
263
264template <>
265void Property<int16>::AppendSetValueToWriter(MessageWriter* writer) {
266  writer->AppendVariantOfInt16(set_value_);
267}
268
269//
270// Property<uint16> specialization.
271//
272
273template <>
274Property<uint16>::Property() : value_(0) {
275}
276
277template <>
278bool Property<uint16>::PopValueFromReader(MessageReader* reader) {
279  return reader->PopVariantOfUint16(&value_);
280}
281
282template <>
283void Property<uint16>::AppendSetValueToWriter(MessageWriter* writer) {
284  writer->AppendVariantOfUint16(set_value_);
285}
286
287//
288// Property<int32> specialization.
289//
290
291template <>
292Property<int32>::Property() : value_(0) {
293}
294
295template <>
296bool Property<int32>::PopValueFromReader(MessageReader* reader) {
297  return reader->PopVariantOfInt32(&value_);
298}
299
300template <>
301void Property<int32>::AppendSetValueToWriter(MessageWriter* writer) {
302  writer->AppendVariantOfInt32(set_value_);
303}
304
305//
306// Property<uint32> specialization.
307//
308
309template <>
310Property<uint32>::Property() : value_(0) {
311}
312
313template <>
314bool Property<uint32>::PopValueFromReader(MessageReader* reader) {
315  return reader->PopVariantOfUint32(&value_);
316}
317
318template <>
319void Property<uint32>::AppendSetValueToWriter(MessageWriter* writer) {
320  writer->AppendVariantOfUint32(set_value_);
321}
322
323//
324// Property<int64> specialization.
325//
326
327template <>
328Property<int64>::Property() : value_(0), set_value_(0) {
329}
330
331template <>
332bool Property<int64>::PopValueFromReader(MessageReader* reader) {
333  return reader->PopVariantOfInt64(&value_);
334}
335
336template <>
337void Property<int64>::AppendSetValueToWriter(MessageWriter* writer) {
338  writer->AppendVariantOfInt64(set_value_);
339}
340
341//
342// Property<uint64> specialization.
343//
344
345template <>
346Property<uint64>::Property() : value_(0) {
347}
348
349template <>
350bool Property<uint64>::PopValueFromReader(MessageReader* reader) {
351  return reader->PopVariantOfUint64(&value_);
352}
353
354template <>
355void Property<uint64>::AppendSetValueToWriter(MessageWriter* writer) {
356  writer->AppendVariantOfUint64(set_value_);
357}
358
359//
360// Property<double> specialization.
361//
362
363template <>
364Property<double>::Property() : value_(0.0) {
365}
366
367template <>
368bool Property<double>::PopValueFromReader(MessageReader* reader) {
369  return reader->PopVariantOfDouble(&value_);
370}
371
372template <>
373void Property<double>::AppendSetValueToWriter(MessageWriter* writer) {
374  writer->AppendVariantOfDouble(set_value_);
375}
376
377//
378// Property<std::string> specialization.
379//
380
381template <>
382bool Property<std::string>::PopValueFromReader(MessageReader* reader) {
383  return reader->PopVariantOfString(&value_);
384}
385
386template <>
387void Property<std::string>::AppendSetValueToWriter(MessageWriter* writer) {
388  writer->AppendVariantOfString(set_value_);
389}
390
391//
392// Property<ObjectPath> specialization.
393//
394
395template <>
396bool Property<ObjectPath>::PopValueFromReader(MessageReader* reader) {
397  return reader->PopVariantOfObjectPath(&value_);
398}
399
400template <>
401void Property<ObjectPath>::AppendSetValueToWriter(MessageWriter* writer) {
402  writer->AppendVariantOfObjectPath(set_value_);
403}
404
405//
406// Property<std::vector<std::string> > specialization.
407//
408
409template <>
410bool Property<std::vector<std::string> >::PopValueFromReader(
411    MessageReader* reader) {
412  MessageReader variant_reader(NULL);
413  if (!reader->PopVariant(&variant_reader))
414    return false;
415
416  value_.clear();
417  return variant_reader.PopArrayOfStrings(&value_);
418}
419
420template <>
421void Property<std::vector<std::string> >::AppendSetValueToWriter(
422    MessageWriter* writer) {
423  MessageWriter variant_writer(NULL);
424  writer->OpenVariant("as", &variant_writer);
425  variant_writer.AppendArrayOfStrings(set_value_);
426  writer->CloseContainer(&variant_writer);
427}
428
429//
430// Property<std::vector<ObjectPath> > specialization.
431//
432
433template <>
434bool Property<std::vector<ObjectPath> >::PopValueFromReader(
435    MessageReader* reader) {
436  MessageReader variant_reader(NULL);
437  if (!reader->PopVariant(&variant_reader))
438    return false;
439
440  value_.clear();
441  return variant_reader.PopArrayOfObjectPaths(&value_);
442}
443
444template <>
445void Property<std::vector<ObjectPath> >::AppendSetValueToWriter(
446    MessageWriter* writer) {
447  MessageWriter variant_writer(NULL);
448  writer->OpenVariant("ao", &variant_writer);
449  variant_writer.AppendArrayOfObjectPaths(set_value_);
450  writer->CloseContainer(&variant_writer);
451}
452
453//
454// Property<std::vector<uint8> > specialization.
455//
456
457template <>
458bool Property<std::vector<uint8> >::PopValueFromReader(MessageReader* reader) {
459  MessageReader variant_reader(NULL);
460  if (!reader->PopVariant(&variant_reader))
461    return false;
462
463  value_.clear();
464  const uint8* bytes = NULL;
465  size_t length = 0;
466  if (!variant_reader.PopArrayOfBytes(&bytes, &length))
467    return false;
468  value_.assign(bytes, bytes + length);
469  return true;
470}
471
472template <>
473void Property<std::vector<uint8> >::AppendSetValueToWriter(
474    MessageWriter* writer) {
475  MessageWriter variant_writer(NULL);
476  writer->OpenVariant("ay", &variant_writer);
477  variant_writer.AppendArrayOfBytes(set_value_.data(), set_value_.size());
478  writer->CloseContainer(&variant_writer);
479}
480
481template class Property<uint8>;
482template class Property<bool>;
483template class Property<int16>;
484template class Property<uint16>;
485template class Property<int32>;
486template class Property<uint32>;
487template class Property<int64>;
488template class Property<uint64>;
489template class Property<double>;
490template class Property<std::string>;
491template class Property<ObjectPath>;
492template class Property<std::vector<std::string> >;
493template class Property<std::vector<ObjectPath> >;
494template class Property<std::vector<uint8> >;
495
496}  // namespace dbus
497