1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef META_SRC_OBJECT_HIERARCHY_OBSERVER_H
16 #define META_SRC_OBJECT_HIERARCHY_OBSERVER_H
17 
18 #include <shared_mutex>
19 
20 #include <base/containers/unordered_map.h>
21 
22 #include <meta/api/event_handler.h>
23 #include <meta/ext/event_impl.h>
24 #include <meta/interface/builtin_objects.h>
25 #include <meta/interface/intf_attachment.h>
26 #include <meta/interface/intf_object_hierarchy_observer.h>
27 
28 #include "object.h"
29 
30 META_BEGIN_NAMESPACE()
31 
32 class ObjectHierarchyObserver;
33 
34 class ObjectChangeListener final {
35 public:
36     META_NO_COPY_MOVE(ObjectChangeListener)
37     ObjectChangeListener() = delete;
38     ~ObjectChangeListener();
39 
40     ObjectChangeListener(const IObject::Ptr& object, HierarchyChangeObjectType myType, const IObject::WeakPtr& parent,
41         ObjectHierarchyObserver* observer, HierarchyChangeModeValue mode);
42 
GetType()43     HierarchyChangeObjectType GetType() const
44     {
45         return type_;
46     }
47 
48 private:
49     bool Subscribe(HierarchyChangeModeValue mode);
50     void Unsubscribe();
51 
52     void SubscribeContainer(const IObject::Ptr& object);
53     void SubscribeAttachment(const IObject::Ptr& object);
54 
55     IObject::WeakPtr object_;
56     HierarchyChangeObjectType type_;
57     IObject::WeakPtr parent_;
58 
59     // Currently IContent does not support "OnChanging" and so the content might be destroyed already
60     // which would make it impossible to notify about
61     IObject::Ptr content_;
62 
63     ObjectHierarchyObserver* observer_ {};
64     BASE_NS::vector<EventHandler> handlers_;
65     bool containerPreTransaction_ { false };
66     bool attachmentPreTransaction_ { false };
67 
68     void NotifyObjectChangedOp();
69     void NotifyContainerChangeOp(
70         const ChildChangedInfo& info, HierarchyChangeType operation, HierarchyChangeObjectType objectType);
71     void NotifyContainerMoveOp(
72         const ChildMovedInfo& info, HierarchyChangeType operation, HierarchyChangeObjectType objectType);
73     void NotifyContentChangeOp();
74 };
75 
76 class ObjectHierarchyObserver final : public Internal::MetaObjectFwd<ObjectHierarchyObserver,
77                                           ClassId::ObjectHierarchyObserver, IObjectHierarchyObserver, IAttachment> {
78     using Super = Internal::MetaObjectFwd<ObjectHierarchyObserver, ClassId::ObjectHierarchyObserver,
79         IObjectHierarchyObserver, IAttachment>;
80 
81 public:
82     void HierarchyChanged(const HierarchyChangedInfo& info, ObjectChangeListener* listener);
83 
84 protected: // LifeCycle
85     bool Build(const IMetadata::Ptr&) override;
86     void Destroy() override;
87 
88 protected: // IObjectHierarchyObserver
89     void SetTarget(const IObject::Ptr& root, HierarchyChangeModeValue mode) override;
90     IObject::Ptr GetTarget() const override;
91     BASE_NS::vector<IObject::Ptr> GetAllObserved() const override;
92     META_IMPLEMENT_INTERFACE_EVENT(IObjectHierarchyObserver, IOnHierarchyChanged, OnHierarchyChanged)
93 
94 protected: // IAttachment
95     bool Attaching(const META_NS::IAttach::Ptr& target, const META_NS::IObject::Ptr& dataContext) override;
96     bool Detaching(const META_NS::IAttach::Ptr& target) override;
97 
98     META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAttachment, IObject::WeakPtr, DataContext);
99     META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAttachment, IAttach::WeakPtr, AttachedTo, {});
100 
101 private:
102     void Subscribe(const IObject::Ptr& root, HierarchyChangeObjectType type, const IObject::WeakPtr& parent = nullptr);
103     void Unsubscribe(const IObject::Ptr& root);
104     void ClearSubscriptions();
105     void NotifyOnDetach();
106 
107     HierarchyChangeModeValue mode_ {};
108     IObject::WeakPtr root_;
109 
110     struct Subscription final {
111         META_NO_COPY(Subscription)
Subscriptionfinal112         Subscription(IObject::WeakPtr object, BASE_NS::unique_ptr<ObjectChangeListener>&& listener)
113             : object_(BASE_NS::move(object)), listener_(BASE_NS::move(listener))
114         {}
115         ~Subscription() = default;
116         Subscription(Subscription&& other) noexcept = default;
117         Subscription& operator=(Subscription&& other) = default;
118         IObject::WeakPtr object_;
119         BASE_NS::unique_ptr<ObjectChangeListener> listener_;
120     };
121 
122     void AddSubscription(const IObject::Ptr& object, HierarchyChangeObjectType type, const IObject::WeakPtr& parent);
123     void RemoveSubscription(const IObject::Ptr& object);
124 
125     void AddImmediateChild(const HierarchyChangedInfo& info);
126     void RemoveImmediateChild(const HierarchyChangedInfo& info);
127 
128     BASE_NS::unordered_map<ObjectChangeListener*, Subscription> subscriptions_;
129     struct ImmediateChild {
130         BASE_NS::weak_ptr<IObject> object;
131         HierarchyChangeObjectType type {};
132     };
133     bool keepTrackOfImmediate_ {};
134     BASE_NS::vector<ImmediateChild> immediateChildren_;
135     mutable std::shared_mutex mutex_;
136 };
137 
138 META_END_NAMESPACE()
139 
140 #endif // META_SRC_OBJECT_HIERARCHY_OBSERVER_H
141