// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIBBRILLO_BRILLO_DBUS_EXPORTED_OBJECT_MANAGER_H_
#define LIBBRILLO_BRILLO_DBUS_EXPORTED_OBJECT_MANAGER_H_
#include <map>
#include <string>
#include <vector>
#include <base/callback.h>
#include <base/memory/weak_ptr.h>
#include <brillo/brillo_export.h>
#include <brillo/dbus/dbus_object.h>
#include <brillo/dbus/exported_property_set.h>
#include <brillo/variant_dictionary.h>
#include <dbus/bus.h>
#include <dbus/exported_object.h>
#include <dbus/message.h>
#include <dbus/object_path.h>
namespace brillo {
namespace dbus_utils {
// ExportedObjectManager is a delegate that implements the
// org.freedesktop.DBus.ObjectManager interface on behalf of another
// object. It handles sending signals when new interfaces are added.
//
// This class is very similar to the ExportedPropertySet class, except that
// it allows objects to expose an object manager interface rather than the
// properties interface.
//
// Example usage:
//
// class ExampleObjectManager {
// public:
// ExampleObjectManager(dbus::Bus* bus)
// : object_manager_(bus, "/my/objects/path") { }
//
// void RegisterAsync(const CompletionAction& cb) {
// object_manager_.RegisterAsync(cb);
// }
// void ClaimInterface(const dbus::ObjectPath& path,
// const std::string& interface_name,
// const ExportedPropertySet::PropertyWriter& writer) {
// object_manager_->ClaimInterface(...);
// }
// void ReleaseInterface(const dbus::ObjectPath& path,
// const std::string& interface_name) {
// object_manager_->ReleaseInterface(...);
// }
//
// private:
// ExportedObjectManager object_manager_;
// };
//
// class MyObjectClaimingAnInterface {
// public:
// MyObjectClaimingAnInterface(ExampleObjectManager* object_manager)
// : object_manager_(object_manager) {}
//
// void OnInitFinish(bool success) {
// if (!success) { /* handle that */ }
// object_manager_->ClaimInterface(
// my_path_, my_interface_, my_properties_.GetWriter());
// }
//
// private:
// struct Properties : public ExportedPropertySet {
// public:
// /* Lots of interesting properties. */
// };
//
// Properties my_properties_;
// ExampleObjectManager* object_manager_;
// };
class BRILLO_EXPORT ExportedObjectManager
: public base::SupportsWeakPtr<ExportedObjectManager> {
public:
using ObjectMap =
std::map<dbus::ObjectPath, std::map<std::string, VariantDictionary>>;
using InterfaceProperties =
std::map<std::string, ExportedPropertySet::PropertyWriter>;
ExportedObjectManager(scoped_refptr<dbus::Bus> bus,
const dbus::ObjectPath& path);
virtual ~ExportedObjectManager() = default;
// Registers methods implementing the ObjectManager interface on the object
// exported on the path given in the constructor. Must be called on the
// origin thread.
virtual void RegisterAsync(
const brillo::dbus_utils::AsyncEventSequencer::CompletionAction&
completion_callback);
// Trigger a signal that |path| has added an interface |interface_name|
// with properties as given by |writer|.
virtual void ClaimInterface(
const dbus::ObjectPath& path,
const std::string& interface_name,
const ExportedPropertySet::PropertyWriter& writer);
// Trigger a signal that |path| has removed an interface |interface_name|.
virtual void ReleaseInterface(const dbus::ObjectPath& path,
const std::string& interface_name);
const scoped_refptr<dbus::Bus>& GetBus() const { return bus_; }
// Due to D-Bus forwarding, clients may need to access the underlying
// DBusObject to handle signals/methods.
// TODO(sonnysasaka): Refactor this accessor into a stricter API once we know
// what D-Bus forwarding needs when it's completed, without exposing
// DBusObject directly.
brillo::dbus_utils::DBusObject* dbus_object() { return &dbus_object_; };
private:
BRILLO_PRIVATE ObjectMap HandleGetManagedObjects();
scoped_refptr<dbus::Bus> bus_;
brillo::dbus_utils::DBusObject dbus_object_;
// Tracks all objects currently known to the ExportedObjectManager.
std::map<dbus::ObjectPath, InterfaceProperties> registered_objects_;
using SignalInterfacesAdded =
DBusSignal<dbus::ObjectPath, std::map<std::string, VariantDictionary>>;
using SignalInterfacesRemoved =
DBusSignal<dbus::ObjectPath, std::vector<std::string>>;
std::weak_ptr<SignalInterfacesAdded> signal_itf_added_;
std::weak_ptr<SignalInterfacesRemoved> signal_itf_removed_;
friend class ExportedObjectManagerTest;
DISALLOW_COPY_AND_ASSIGN(ExportedObjectManager);
};
} // namespace dbus_utils
} // namespace brillo
#endif // LIBBRILLO_BRILLO_DBUS_EXPORTED_OBJECT_MANAGER_H_