summaryrefslogtreecommitdiff
path: root/src/CommonAPI/DBus/DBusObjectManagerStub.h
blob: 42db8e324a4ac41f387b325c30e61c8d95c3921d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* Copyright (C) 2013 BMW Group
 * Author: Manfred Bathelt (manfred.bathelt@bmw.de)
 * Author: Juergen Gehring (juergen.gehring@bmw.de)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef COMMONAPI_DBUS_DBUS_FREEDESKTOP_OBJECT_MANAGER_STUB_H_
#define COMMONAPI_DBUS_DBUS_FREEDESKTOP_OBJECT_MANAGER_STUB_H_

// TODO rename DBusObjectManager to DBusStubManager

// TODO proxy/client logic simply instantiates DBusObjectManagerProxy
//      with the object path of the currently instantiated proxy. That
//      way asking about available instances is a matter of calling
//      getManagedObjects(). Maybe we'll also have to cache within the
//      proxy like the service registry is doing.

// TODO Service Discovery
//      - first detect all objects of a service via the Introspectible interface (like d-feet does).
//      - Introspectible is less efficient than a global ObjectManager but a global ObjectManager
//        conflicts with local ones, so we can't intentionally have one. The tradeoff is efficiency for correctness
//      - Register for all InterfaceAdded and InterfaceRemoved signals on the bus.
//      - Handle double InterfaceAdded and InterfaceRemoved signals properly (ignore them!).

#include "DBusInterfaceHandler.h"

#include <memory>
#include <mutex>
#include <string>

namespace CommonAPI {
namespace DBus {

class DBusStubAdapter;

/**
 * Stub for standard <a href="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager">org.freedesktop.dbus.ObjectManager</a> interface.
 *
 * Instantiated within a manager stub and it must hold reference to all registered objects.
 * Whenever the manager gets destroyed all references to registered objects are lost too.
 * This duplicates the semantic of the CommonAPI::ServicePublisher class.
 *
 * Only one DBusStubAdapter instance could be registered per DBusObjectManagerStub instance.
 *
 * The owner of the DBusObjectManagerStub instance must take care of registering and unregistering it.
 *
 * Example stub life cycle:
 *  - create CommonAPI::ServicePublisher
 *  - create stub A
 *  - register stub A to CommonAPI::ServicePublisher
 *  - create stub B
 *  - register stub B with stub A as object manager
 *  - drop all references to stub B, stub A keeps a reference to stub B
 *  - drop all references to stub A, CommonAPI::ServicePublisher keeps a reference to stub A
 *  - reference overview: Application > CommonAPI::ServicePublisher > Stub A > Stub B
 *  - drop all references to CommonAPI::ServicePublisher causes all object references to be dropped
 */
class DBusObjectManagerStub: public DBusInterfaceHandler {
 public:
    // XXX serialization trick: use bool instead of variant since we never serialize it
    typedef std::unordered_map<std::string, bool> DBusPropertiesChangedDict;
    typedef std::unordered_map<std::string, DBusPropertiesChangedDict> DBusInterfacesAndPropertiesDict;
    typedef std::unordered_map<std::string, DBusInterfacesAndPropertiesDict> DBusObjectPathAndInterfacesDict;

 public:
	DBusObjectManagerStub(const std::string& dbusObjectPath, const std::shared_ptr<DBusProxyConnection>&);

	/**
	 * Unregisters all currently registered DBusStubAdapter instances from the DBusServicePublisher
	 */
	virtual ~DBusObjectManagerStub();

    /**
     * Export DBusStubAdapter instance with the current DBusObjectManagerStub instance.
     *
     * The DBusStubAdapter must be registered with the DBusServicePublisher!
     *
     * On registering a
     * <a href="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager">InsterfaceAdded</a>
     * signal will be emitted with the DBusObjectManagerStub instance's current D-Bus object path.
     *
     * @param dbusStubAdapter a refernce to DBusStubAdapter instance
     *
     * @return false if the @a dbusStubAdapter instance was already registered
     * @return false if sending the InterfaceAdded signal fails
     *
     * @see ~DBusObjectManagerStub()
     * @see CommonAPI::ServicePublisher
     * @see DBusObjectManager
     */
    bool exportDBusStubAdapter(DBusStubAdapter* dbusStubAdapter);

    /**
     * Unexport DBusStubAdapter instance from this DBusObjectManagerStub instance.
     *
     * On unregistering a
     * <a href="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager">InsterfaceRemoved</a>
     * signal will be emitted with the DBusObjectManagerStub instance's current D-Bus object path.
     *
     * @param dbusStubAdapter
     *
     * @return false if @a dbusStubAdapter wasn't registered
     * @return true even if sending the InterfaceRemoved signal fails
     *
     * @see exportDBusStubAdapter()
     */
    bool unexportDBusStubAdapter(DBusStubAdapter* dbusStubAdapter);

    bool isDBusStubAdapterExported(DBusStubAdapter* dbusStubAdapter);

    inline const std::string& getDBusObjectPath() const;
    inline static const char* getInterfaceName();

    virtual const char* getMethodsDBusIntrospectionXmlData() const;
    virtual bool onInterfaceDBusMessage(const DBusMessage& dbusMessage);

 private:
    bool registerDBusStubAdapter(DBusStubAdapter* dbusStubAdapter);
    bool unregisterDBusStubAdapter(DBusStubAdapter* dbusStubAdapter);

    bool emitInterfacesAddedSignal(DBusStubAdapter* dbusStubAdapter,
                                   const std::shared_ptr<DBusProxyConnection>& dbusConnection) const;

    bool emitInterfacesRemovedSignal(DBusStubAdapter* dbusStubAdapter,
                                     const std::shared_ptr<DBusProxyConnection>& dbusConnection) const;

    std::string dbusObjectPath_;
    std::weak_ptr<DBusProxyConnection> dbusConnectionWeakPtr_;

    typedef std::unordered_map<std::string, DBusStubAdapter*> DBusInterfacesMap;
    typedef std::unordered_map<std::string, DBusInterfacesMap> DBusObjectPathsMap;
    DBusObjectPathsMap registeredDBusObjectPathsMap_;

    std::mutex dbusObjectManagerStubLock_;
};


inline const std::string& DBusObjectManagerStub::getDBusObjectPath() const {
    return dbusObjectPath_;
}

const char* DBusObjectManagerStub::getInterfaceName() {
    return "org.freedesktop.DBus.ObjectManager";
}

} // namespace DBus
} // namespace CommonAPI

#endif // COMMONAPI_DBUS_DBUS_FREEDESKTOP_OBJECT_MANAGER_STUB_H_