9771a344e8808d9c406ae852881ca54246a757af
[platform/framework/web/crosswalk.git] / src / xwalk / dbus / property_exporter.cc
1 // Copyright (c) 2013 Intel Corporation. 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 "xwalk/dbus/property_exporter.h"
6
7 #include <string>
8 #include "base/bind.h"
9 #include "base/stl_util.h"
10 #include "base/values.h"
11 #include "dbus/message.h"
12 #include "dbus/property.h"
13
14 namespace {
15
16 const char kErrorName[] = "org.freedesktop.DBus.Properties.Error";
17
18 }  // namespace
19
20 namespace dbus {
21
22 PropertyExporter::PropertyExporter(ExportedObject* object,
23                                    const ObjectPath& path)
24     : path_(path),
25       weak_factory_(this) {
26   CHECK(object);
27   object->ExportMethod(
28       kPropertiesInterface, kPropertiesGet,
29       base::Bind(&PropertyExporter::OnGet, weak_factory_.GetWeakPtr()),
30       base::Bind(&PropertyExporter::OnExported, weak_factory_.GetWeakPtr()));
31   object->ExportMethod(
32       kPropertiesInterface, kPropertiesGetAll,
33       base::Bind(&PropertyExporter::OnGetAll, weak_factory_.GetWeakPtr()),
34       base::Bind(&PropertyExporter::OnExported, weak_factory_.GetWeakPtr()));
35 }
36
37 PropertyExporter::~PropertyExporter() {
38   STLDeleteValues(&interfaces_);
39 }
40
41 void PropertyExporter::Set(const std::string& interface,
42                            const std::string& property,
43                            scoped_ptr<base::Value> value) {
44   // TODO(cmarcelo): Support more types as we need to use them.
45   if (!value->IsType(base::Value::TYPE_STRING)
46       && !value->IsType(base::Value::TYPE_INTEGER)) {
47     LOG(ERROR) << "PropertyExporter can only can "
48                << "export String and Integer properties";
49     return;
50   }
51
52   InterfacesMap::iterator it = interfaces_.find(interface);
53   base::DictionaryValue* dict;
54   if (it != interfaces_.end()) {
55     dict = it->second;
56   } else {
57     dict = new base::DictionaryValue;
58     interfaces_[interface] = dict;
59   }
60
61   dict->Set(property, value.release());
62
63   // TODO(cmarcelo): Emit PropertyChanged signal.
64 }
65
66 namespace {
67
68 void AppendVariantOfValue(MessageWriter* writer, const base::Value& value) {
69   switch (value.GetType()) {
70     case base::Value::TYPE_STRING: {
71       std::string s;
72       value.GetAsString(&s);
73       writer->AppendVariantOfString(s);
74       break;
75     }
76     case base::Value::TYPE_INTEGER: {
77       int n;
78       value.GetAsInteger(&n);
79       writer->AppendVariantOfInt32(n);
80       break;
81     }
82     default:
83       LOG(ERROR) << "Unsupported base::Value when converting to DBus VARIANT.";
84   }
85 }
86
87 scoped_ptr<Response> CreateParseError(MethodCall* method_call) {
88   scoped_ptr<ErrorResponse> error_response = ErrorResponse::FromMethodCall(
89       method_call, kErrorName, "Error parsing arguments.");
90   return error_response.PassAs<Response>();
91 }
92
93 scoped_ptr<Response> CreateInterfaceNotFoundError(
94     MethodCall* method_call, const std::string& interface,
95     const dbus::ObjectPath& path) {
96   scoped_ptr<ErrorResponse> error_response = ErrorResponse::FromMethodCall(
97       method_call, kErrorName,
98       "Interface '" + interface + "' not found for object '"
99       + path.value() + "'.");
100   return error_response.PassAs<Response>();
101 }
102
103 }  // namespace
104
105 void PropertyExporter::AppendPropertiesToWriter(const std::string& interface,
106                                                 MessageWriter* writer) const {
107   InterfacesMap::const_iterator it = interfaces_.find(interface);
108   if (it == interfaces_.end())
109     return;
110
111   MessageWriter dict_writer(NULL);
112   writer->OpenArray("{sv}", &dict_writer);
113
114   for (base::DictionaryValue::Iterator dict_it(*it->second);
115        !dict_it.IsAtEnd();
116        dict_it.Advance()) {
117     MessageWriter entry_writer(NULL);
118     dict_writer.OpenDictEntry(&entry_writer);
119     entry_writer.AppendString(dict_it.key());
120     AppendVariantOfValue(&entry_writer, dict_it.value());
121     dict_writer.CloseContainer(&entry_writer);
122   }
123
124   writer->CloseContainer(&dict_writer);
125 }
126
127 std::vector<std::string> PropertyExporter::interfaces() const {
128   std::vector<std::string> interfaces;
129
130   InterfacesMap::const_iterator it = interfaces_.begin();
131   for (; it != interfaces_.end(); ++it) {
132     interfaces.push_back(it->first);
133   }
134
135   return interfaces;
136 }
137
138 void PropertyExporter::OnGet(
139     MethodCall* method_call, ExportedObject::ResponseSender response_sender) {
140   MessageReader reader(method_call);
141   std::string interface;
142   std::string property;
143   if (!reader.PopString(&interface) || !reader.PopString(&property)) {
144     scoped_ptr<Response> error_response = CreateParseError(method_call);
145     response_sender.Run(error_response.Pass());
146     return;
147   }
148
149   InterfacesMap::const_iterator it = interfaces_.find(interface);
150   if (it == interfaces_.end()) {
151     scoped_ptr<Response> error_response =
152         CreateInterfaceNotFoundError(method_call, interface, path_);
153     response_sender.Run(error_response.Pass());
154     return;
155   }
156
157   const base::DictionaryValue* dict = it->second;
158   const base::Value* value = NULL;
159   if (!dict->Get(property, &value)) {
160     scoped_ptr<ErrorResponse> error_response = ErrorResponse::FromMethodCall(
161         method_call, kErrorName,
162         "Property '" + property + "' of interface '" + interface
163         + "' not found for object '" + path_.value() + "'.");
164     response_sender.Run(error_response.PassAs<Response>());
165     return;
166   }
167
168   scoped_ptr<Response> response = Response::FromMethodCall(method_call);
169   MessageWriter writer(response.get());
170   AppendVariantOfValue(&writer, *value);
171   response_sender.Run(response.Pass());
172 }
173
174 void PropertyExporter::OnGetAll(
175     MethodCall* method_call, ExportedObject::ResponseSender response_sender) {
176   MessageReader reader(method_call);
177   std::string interface;
178   if (!reader.PopString(&interface)) {
179     scoped_ptr<Response> error_response = CreateParseError(method_call);
180     response_sender.Run(error_response.Pass());
181     return;
182   }
183
184   InterfacesMap::const_iterator it = interfaces_.find(interface);
185   if (it == interfaces_.end()) {
186     scoped_ptr<Response> error_response =
187         CreateInterfaceNotFoundError(method_call, interface, path_);
188     response_sender.Run(error_response.Pass());
189     return;
190   }
191
192   scoped_ptr<Response> response = Response::FromMethodCall(method_call);
193   MessageWriter writer(response.get());
194   AppendPropertiesToWriter(interface, &writer);
195   response_sender.Run(response.Pass());
196 }
197
198 void PropertyExporter::OnExported(const std::string& interface_name,
199                                   const std::string& method_name,
200                                   bool success) {
201   if (!success) {
202     LOG(WARNING) << "Error exporting method '" << interface_name
203                  << "." << method_name << "' in object '"
204                  << path_.value() << "'.";
205   }
206 }
207
208 }  // namespace dbus