15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/dbus/introspectable_client.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/bus.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/message.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/object_path.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/object_proxy.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/libxml/chromium/libxml_utils.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// D-Bus specification constants.
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kIntrospectableInterface[] = "org.freedesktop.DBus.Introspectable";
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kIntrospect[] = "Introspect";
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// String constants used for parsing D-Bus Introspection XML data.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInterfaceNode[] = "interface";
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInterfaceNameAttribute[] = "name";
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The IntrospectableClient implementation used in production.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class IntrospectableClientImpl : public IntrospectableClient {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
35424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  IntrospectableClientImpl() : bus_(NULL), weak_ptr_factory_(this) {}
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~IntrospectableClientImpl() {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IntrospectableClient override.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Introspect(const std::string& service_name,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const dbus::ObjectPath& object_path,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const IntrospectCallback& callback) OVERRIDE {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dbus::MethodCall method_call(kIntrospectableInterface, kIntrospect);
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dbus::ObjectProxy* object_proxy = bus_->GetObjectProxy(service_name,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                           object_path);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    object_proxy->CallMethod(
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &method_call,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&IntrospectableClientImpl::OnIntrospect,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr(),
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   service_name, object_path, callback));
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) protected:
58424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  virtual void Init(dbus::Bus* bus) OVERRIDE { bus_ = bus; }
59424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called by dbus:: when a response for Introspect() is recieved.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnIntrospect(const std::string& service_name,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const dbus::ObjectPath& object_path,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const IntrospectCallback& callback,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    dbus::Response* response) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Parse response.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool success = false;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string xml_data;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (response != NULL) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dbus::MessageReader reader(response);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!reader.PopString(&xml_data)) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(WARNING) << "Introspect response has incorrect paramters: "
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     << response->ToString();
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        success = true;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Notify client.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(service_name, object_path, xml_data, success);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dbus::Bus* bus_;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Weak pointer factory for generating 'this' pointers that might live longer
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // than we do.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: This should remain the last member so it'll be destroyed and
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // invalidate its weak pointers before any other members are destroyed.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::WeakPtrFactory<IntrospectableClientImpl> weak_ptr_factory_;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(IntrospectableClientImpl);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IntrospectableClient::IntrospectableClient() {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IntrospectableClient::~IntrospectableClient() {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<std::string>
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IntrospectableClient::GetInterfacesFromIntrospectResult(
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& xml_data) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> interfaces;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XmlReader reader;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!reader.Load(xml_data))
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return interfaces;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip to the next open tag, exit when done.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (!reader.SkipToElement()) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!reader.Read()) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return interfaces;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only look at interface nodes.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (reader.NodeName() != kInterfaceNode)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip if missing the interface name.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string interface_name;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!reader.NodeAttribute(kInterfaceNameAttribute, &interface_name))
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    interfaces.push_back(interface_name);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (reader.Read());
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return interfaces;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)IntrospectableClient* IntrospectableClient::Create() {
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return new IntrospectableClientImpl();
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromeos
139