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 "chromeos/dbus/introspectable_client.h"
6
7#include <string>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/logging.h"
12#include "dbus/bus.h"
13#include "dbus/message.h"
14#include "dbus/object_path.h"
15#include "dbus/object_proxy.h"
16#include "third_party/libxml/chromium/libxml_utils.h"
17
18namespace {
19
20// D-Bus specification constants.
21const char kIntrospectableInterface[] = "org.freedesktop.DBus.Introspectable";
22const char kIntrospect[] = "Introspect";
23
24// String constants used for parsing D-Bus Introspection XML data.
25const char kInterfaceNode[] = "interface";
26const char kInterfaceNameAttribute[] = "name";
27
28}  // namespace
29
30namespace chromeos {
31
32// The IntrospectableClient implementation used in production.
33class IntrospectableClientImpl : public IntrospectableClient {
34 public:
35  IntrospectableClientImpl() : bus_(NULL), weak_ptr_factory_(this) {}
36
37  virtual ~IntrospectableClientImpl() {
38  }
39
40  // IntrospectableClient override.
41  virtual void Introspect(const std::string& service_name,
42                          const dbus::ObjectPath& object_path,
43                          const IntrospectCallback& callback) OVERRIDE {
44    dbus::MethodCall method_call(kIntrospectableInterface, kIntrospect);
45
46    dbus::ObjectProxy* object_proxy = bus_->GetObjectProxy(service_name,
47                                                           object_path);
48
49    object_proxy->CallMethod(
50        &method_call,
51        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
52        base::Bind(&IntrospectableClientImpl::OnIntrospect,
53                   weak_ptr_factory_.GetWeakPtr(),
54                   service_name, object_path, callback));
55  }
56
57 protected:
58  virtual void Init(dbus::Bus* bus) OVERRIDE { bus_ = bus; }
59
60 private:
61  // Called by dbus:: when a response for Introspect() is recieved.
62  void OnIntrospect(const std::string& service_name,
63                    const dbus::ObjectPath& object_path,
64                    const IntrospectCallback& callback,
65                    dbus::Response* response) {
66    // Parse response.
67    bool success = false;
68    std::string xml_data;
69    if (response != NULL) {
70      dbus::MessageReader reader(response);
71      if (!reader.PopString(&xml_data)) {
72        LOG(WARNING) << "Introspect response has incorrect paramters: "
73                     << response->ToString();
74      } else {
75        success = true;
76      }
77    }
78
79    // Notify client.
80    callback.Run(service_name, object_path, xml_data, success);
81  }
82
83  dbus::Bus* bus_;
84
85  // Weak pointer factory for generating 'this' pointers that might live longer
86  // than we do.
87  // Note: This should remain the last member so it'll be destroyed and
88  // invalidate its weak pointers before any other members are destroyed.
89  base::WeakPtrFactory<IntrospectableClientImpl> weak_ptr_factory_;
90
91  DISALLOW_COPY_AND_ASSIGN(IntrospectableClientImpl);
92};
93
94IntrospectableClient::IntrospectableClient() {
95}
96
97IntrospectableClient::~IntrospectableClient() {
98}
99
100// static
101std::vector<std::string>
102IntrospectableClient::GetInterfacesFromIntrospectResult(
103    const std::string& xml_data) {
104  std::vector<std::string> interfaces;
105
106  XmlReader reader;
107  if (!reader.Load(xml_data))
108    return interfaces;
109
110  do {
111    // Skip to the next open tag, exit when done.
112    while (!reader.SkipToElement()) {
113      if (!reader.Read()) {
114        return interfaces;
115      }
116    }
117
118    // Only look at interface nodes.
119    if (reader.NodeName() != kInterfaceNode)
120      continue;
121
122    // Skip if missing the interface name.
123    std::string interface_name;
124    if (!reader.NodeAttribute(kInterfaceNameAttribute, &interface_name))
125      continue;
126
127    interfaces.push_back(interface_name);
128  } while (reader.Read());
129
130  return interfaces;
131}
132
133// static
134IntrospectableClient* IntrospectableClient::Create() {
135  return new IntrospectableClientImpl();
136}
137
138}  // namespace chromeos
139