18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "object_hierarchy_observer.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <algorithm>
198bf80f4bSopenharmony_ci
208bf80f4bSopenharmony_ci#include <meta/api/iteration.h>
218bf80f4bSopenharmony_ci#include <meta/api/make_callback.h>
228bf80f4bSopenharmony_ci#include <meta/api/property/property_event_handler.h>
238bf80f4bSopenharmony_ci#include <meta/api/util.h>
248bf80f4bSopenharmony_ci#include <meta/base/interface_utils.h>
258bf80f4bSopenharmony_ci#include <meta/interface/intf_containable.h>
268bf80f4bSopenharmony_ci#include <meta/interface/intf_content.h>
278bf80f4bSopenharmony_ci
288bf80f4bSopenharmony_ciMETA_BEGIN_NAMESPACE()
298bf80f4bSopenharmony_ci
308bf80f4bSopenharmony_ci// ContainerChangeListener
318bf80f4bSopenharmony_ci
328bf80f4bSopenharmony_ciObjectChangeListener::ObjectChangeListener(const IObject::Ptr& object, HierarchyChangeObjectType myType,
338bf80f4bSopenharmony_ci    const IObject::WeakPtr& parent, ObjectHierarchyObserver* observer, HierarchyChangeModeValue mode)
348bf80f4bSopenharmony_ci    : object_(object), type_(myType), parent_(parent), observer_(observer)
358bf80f4bSopenharmony_ci{
368bf80f4bSopenharmony_ci    CORE_ASSERT(observer_ && object);
378bf80f4bSopenharmony_ci    Subscribe(mode);
388bf80f4bSopenharmony_ci}
398bf80f4bSopenharmony_ci
408bf80f4bSopenharmony_ciObjectChangeListener::~ObjectChangeListener()
418bf80f4bSopenharmony_ci{
428bf80f4bSopenharmony_ci    Unsubscribe();
438bf80f4bSopenharmony_ci}
448bf80f4bSopenharmony_ci
458bf80f4bSopenharmony_civoid ObjectChangeListener::SubscribeContainer(const IObject::Ptr& object)
468bf80f4bSopenharmony_ci{
478bf80f4bSopenharmony_ci    if (const auto container = interface_cast<IContainer>(object)) {
488bf80f4bSopenharmony_ci        if (auto trans = interface_cast<IContainerPreTransaction>(container)) {
498bf80f4bSopenharmony_ci            handlers_.emplace_back(trans->OnAdding(), [this](const ChildChangedInfo& info, bool&) {
508bf80f4bSopenharmony_ci                NotifyContainerChangeOp(info, HierarchyChangeType::ADDING, HierarchyChangeObjectType::CHILD);
518bf80f4bSopenharmony_ci            });
528bf80f4bSopenharmony_ci            handlers_.emplace_back(trans->OnRemoving(), [this](const ChildChangedInfo& info, bool&) {
538bf80f4bSopenharmony_ci                NotifyContainerChangeOp(info, HierarchyChangeType::REMOVING, HierarchyChangeObjectType::CHILD);
548bf80f4bSopenharmony_ci            });
558bf80f4bSopenharmony_ci            containerPreTransaction_ = true;
568bf80f4bSopenharmony_ci        }
578bf80f4bSopenharmony_ci
588bf80f4bSopenharmony_ci        handlers_.emplace_back(container->OnAdded(), [this](const ChildChangedInfo& info) {
598bf80f4bSopenharmony_ci            NotifyContainerChangeOp(info, HierarchyChangeType::ADDED, HierarchyChangeObjectType::CHILD);
608bf80f4bSopenharmony_ci        });
618bf80f4bSopenharmony_ci        handlers_.emplace_back(container->OnRemoved(), [this](const ChildChangedInfo& info) {
628bf80f4bSopenharmony_ci            NotifyContainerChangeOp(info, HierarchyChangeType::REMOVED, HierarchyChangeObjectType::CHILD);
638bf80f4bSopenharmony_ci        });
648bf80f4bSopenharmony_ci        handlers_.emplace_back(container->OnMoved(), [this](const ChildMovedInfo& info) {
658bf80f4bSopenharmony_ci            NotifyContainerMoveOp(info, HierarchyChangeType::MOVED, HierarchyChangeObjectType::CHILD);
668bf80f4bSopenharmony_ci        });
678bf80f4bSopenharmony_ci    }
688bf80f4bSopenharmony_ci}
698bf80f4bSopenharmony_ci
708bf80f4bSopenharmony_civoid ObjectChangeListener::SubscribeAttachment(const IObject::Ptr& object)
718bf80f4bSopenharmony_ci{
728bf80f4bSopenharmony_ci    if (const auto attach = interface_cast<IAttach>(object)) {
738bf80f4bSopenharmony_ci        if (const auto container = attach->GetAttachmentContainer(true)) {
748bf80f4bSopenharmony_ci            if (const auto trans = interface_cast<IContainerPreTransaction>(container)) {
758bf80f4bSopenharmony_ci                handlers_.emplace_back(trans->OnAdding(), [this](const ChildChangedInfo& info, bool&) {
768bf80f4bSopenharmony_ci                    NotifyContainerChangeOp(info, HierarchyChangeType::ADDING, HierarchyChangeObjectType::ATTACHMENT);
778bf80f4bSopenharmony_ci                });
788bf80f4bSopenharmony_ci                handlers_.emplace_back(trans->OnRemoving(), [this](const ChildChangedInfo& info, bool&) {
798bf80f4bSopenharmony_ci                    NotifyContainerChangeOp(info, HierarchyChangeType::REMOVING, HierarchyChangeObjectType::ATTACHMENT);
808bf80f4bSopenharmony_ci                });
818bf80f4bSopenharmony_ci                attachmentPreTransaction_ = true;
828bf80f4bSopenharmony_ci            }
838bf80f4bSopenharmony_ci            handlers_.emplace_back(container->OnAdded(), [this](const ChildChangedInfo& info) {
848bf80f4bSopenharmony_ci                NotifyContainerChangeOp(info, HierarchyChangeType::ADDED, HierarchyChangeObjectType::ATTACHMENT);
858bf80f4bSopenharmony_ci            });
868bf80f4bSopenharmony_ci            handlers_.emplace_back(container->OnRemoved(), [this](const ChildChangedInfo& info) {
878bf80f4bSopenharmony_ci                NotifyContainerChangeOp(info, HierarchyChangeType::REMOVED, HierarchyChangeObjectType::ATTACHMENT);
888bf80f4bSopenharmony_ci            });
898bf80f4bSopenharmony_ci            handlers_.emplace_back(container->OnMoved(), [this](const ChildMovedInfo& info) {
908bf80f4bSopenharmony_ci                NotifyContainerMoveOp(info, HierarchyChangeType::MOVED, HierarchyChangeObjectType::ATTACHMENT);
918bf80f4bSopenharmony_ci            });
928bf80f4bSopenharmony_ci        }
938bf80f4bSopenharmony_ci    }
948bf80f4bSopenharmony_ci}
958bf80f4bSopenharmony_ci
968bf80f4bSopenharmony_cibool ObjectChangeListener::Subscribe(HierarchyChangeModeValue mode)
978bf80f4bSopenharmony_ci{
988bf80f4bSopenharmony_ci    if (const auto object = object_.lock()) {
998bf80f4bSopenharmony_ci        // Figure out which hierarchical interfaces our target object implements and add listeners based on that
1008bf80f4bSopenharmony_ci        if (mode & HierarchyChangeMode::NOTIFY_CONTAINER) {
1018bf80f4bSopenharmony_ci            SubscribeContainer(object);
1028bf80f4bSopenharmony_ci        }
1038bf80f4bSopenharmony_ci        if (mode & HierarchyChangeMode::NOTIFY_CONTENT) {
1048bf80f4bSopenharmony_ci            if (const auto content = interface_cast<IContent>(object)) {
1058bf80f4bSopenharmony_ci                content_ = META_NS::GetValue(content->Content());
1068bf80f4bSopenharmony_ci                handlers_.emplace_back(
1078bf80f4bSopenharmony_ci                    content->Content()->OnChanged(), MakeCallback<IOnChanged>([this]() { NotifyContentChangeOp(); }));
1088bf80f4bSopenharmony_ci            }
1098bf80f4bSopenharmony_ci        }
1108bf80f4bSopenharmony_ci        if (mode & HierarchyChangeMode::NOTIFY_ATTACHMENT) {
1118bf80f4bSopenharmony_ci            SubscribeAttachment(object);
1128bf80f4bSopenharmony_ci        }
1138bf80f4bSopenharmony_ci        if (mode & HierarchyChangeMode::NOTIFY_OBJECT) {
1148bf80f4bSopenharmony_ci            if (auto i = interface_pointer_cast<INotifyOnChange>(object)) {
1158bf80f4bSopenharmony_ci                handlers_.emplace_back(i->OnChanged(), MakeCallback<IOnChanged>([this]() { NotifyObjectChangedOp(); }));
1168bf80f4bSopenharmony_ci            }
1178bf80f4bSopenharmony_ci        }
1188bf80f4bSopenharmony_ci        return true;
1198bf80f4bSopenharmony_ci    }
1208bf80f4bSopenharmony_ci    return false;
1218bf80f4bSopenharmony_ci}
1228bf80f4bSopenharmony_ci
1238bf80f4bSopenharmony_civoid ObjectChangeListener::Unsubscribe()
1248bf80f4bSopenharmony_ci{
1258bf80f4bSopenharmony_ci    handlers_.clear();
1268bf80f4bSopenharmony_ci    content_.reset();
1278bf80f4bSopenharmony_ci}
1288bf80f4bSopenharmony_ci
1298bf80f4bSopenharmony_civoid ObjectChangeListener::NotifyObjectChangedOp()
1308bf80f4bSopenharmony_ci{
1318bf80f4bSopenharmony_ci    if (auto object = object_.lock()) {
1328bf80f4bSopenharmony_ci        HierarchyChangedInfo change;
1338bf80f4bSopenharmony_ci        change.object = object;
1348bf80f4bSopenharmony_ci        change.change = HierarchyChangeType::CHANGED;
1358bf80f4bSopenharmony_ci        change.objectType = type_;
1368bf80f4bSopenharmony_ci        change.parent = parent_;
1378bf80f4bSopenharmony_ci        observer_->HierarchyChanged(change, this);
1388bf80f4bSopenharmony_ci    }
1398bf80f4bSopenharmony_ci}
1408bf80f4bSopenharmony_ci
1418bf80f4bSopenharmony_civoid ObjectChangeListener::NotifyContainerChangeOp(
1428bf80f4bSopenharmony_ci    const ChildChangedInfo& info, HierarchyChangeType operation, HierarchyChangeObjectType objectType)
1438bf80f4bSopenharmony_ci{
1448bf80f4bSopenharmony_ci    HierarchyChangedInfo change;
1458bf80f4bSopenharmony_ci    change.object = info.object;
1468bf80f4bSopenharmony_ci    change.change = operation;
1478bf80f4bSopenharmony_ci    change.objectType = objectType;
1488bf80f4bSopenharmony_ci    change.index = info.index;
1498bf80f4bSopenharmony_ci    change.parent = object_;
1508bf80f4bSopenharmony_ci    if ((objectType == HierarchyChangeObjectType::CHILD && !containerPreTransaction_) ||
1518bf80f4bSopenharmony_ci        (objectType == HierarchyChangeObjectType::ATTACHMENT && !attachmentPreTransaction_)) {
1528bf80f4bSopenharmony_ci        // Our target does not support pre transaction notifications, generate ones.
1538bf80f4bSopenharmony_ci        if (operation == HierarchyChangeType::ADDED) {
1548bf80f4bSopenharmony_ci            change.change = HierarchyChangeType::ADDING;
1558bf80f4bSopenharmony_ci            observer_->HierarchyChanged(change, this);
1568bf80f4bSopenharmony_ci            change.change = operation;
1578bf80f4bSopenharmony_ci        } else if (operation == HierarchyChangeType::REMOVED) {
1588bf80f4bSopenharmony_ci            change.change = HierarchyChangeType::REMOVING;
1598bf80f4bSopenharmony_ci            observer_->HierarchyChanged(change, this);
1608bf80f4bSopenharmony_ci            change.change = operation;
1618bf80f4bSopenharmony_ci        }
1628bf80f4bSopenharmony_ci    }
1638bf80f4bSopenharmony_ci    observer_->HierarchyChanged(change, this);
1648bf80f4bSopenharmony_ci}
1658bf80f4bSopenharmony_ci
1668bf80f4bSopenharmony_civoid ObjectChangeListener::NotifyContainerMoveOp(
1678bf80f4bSopenharmony_ci    const ChildMovedInfo& info, HierarchyChangeType operation, HierarchyChangeObjectType objectType)
1688bf80f4bSopenharmony_ci{
1698bf80f4bSopenharmony_ci    HierarchyChangedInfo change;
1708bf80f4bSopenharmony_ci    change.object = info.object;
1718bf80f4bSopenharmony_ci    change.change = operation;
1728bf80f4bSopenharmony_ci    change.objectType = objectType;
1738bf80f4bSopenharmony_ci    change.parent = object_;
1748bf80f4bSopenharmony_ci    observer_->HierarchyChanged(change, this);
1758bf80f4bSopenharmony_ci}
1768bf80f4bSopenharmony_ci
1778bf80f4bSopenharmony_civoid ObjectChangeListener::NotifyContentChangeOp()
1788bf80f4bSopenharmony_ci{
1798bf80f4bSopenharmony_ci    if (const auto content = interface_pointer_cast<IContent>(object_)) {
1808bf80f4bSopenharmony_ci        const auto newContent = GetValue(content->Content());
1818bf80f4bSopenharmony_ci        const auto oldContent = content_;
1828bf80f4bSopenharmony_ci
1838bf80f4bSopenharmony_ci        HierarchyChangedInfo change;
1848bf80f4bSopenharmony_ci        change.objectType = HierarchyChangeObjectType::CONTENT;
1858bf80f4bSopenharmony_ci        change.parent = object_;
1868bf80f4bSopenharmony_ci
1878bf80f4bSopenharmony_ci        if (oldContent != newContent) {
1888bf80f4bSopenharmony_ci            if (oldContent) {
1898bf80f4bSopenharmony_ci                change.object = oldContent;
1908bf80f4bSopenharmony_ci                change.change = HierarchyChangeType::REMOVING;
1918bf80f4bSopenharmony_ci                observer_->HierarchyChanged(change, this);
1928bf80f4bSopenharmony_ci                change.change = HierarchyChangeType::REMOVED;
1938bf80f4bSopenharmony_ci                observer_->HierarchyChanged(change, this);
1948bf80f4bSopenharmony_ci            }
1958bf80f4bSopenharmony_ci            content_ = newContent;
1968bf80f4bSopenharmony_ci            if (newContent) {
1978bf80f4bSopenharmony_ci                change.object = newContent;
1988bf80f4bSopenharmony_ci                change.change = HierarchyChangeType::ADDING;
1998bf80f4bSopenharmony_ci                observer_->HierarchyChanged(change, this);
2008bf80f4bSopenharmony_ci                change.change = HierarchyChangeType::ADDED;
2018bf80f4bSopenharmony_ci                observer_->HierarchyChanged(change, this);
2028bf80f4bSopenharmony_ci            }
2038bf80f4bSopenharmony_ci        }
2048bf80f4bSopenharmony_ci    }
2058bf80f4bSopenharmony_ci}
2068bf80f4bSopenharmony_ci
2078bf80f4bSopenharmony_ci// ContainerObserver
2088bf80f4bSopenharmony_ci
2098bf80f4bSopenharmony_cibool ObjectHierarchyObserver::Build(const IMetadata::Ptr& p)
2108bf80f4bSopenharmony_ci{
2118bf80f4bSopenharmony_ci    bool ret = Super::Build(p);
2128bf80f4bSopenharmony_ci    if (ret) {
2138bf80f4bSopenharmony_ci        // we don't want to serialise observers
2148bf80f4bSopenharmony_ci        META_NS::SetObjectFlags(GetSelf(), ObjectFlagBits::SERIALIZE, false);
2158bf80f4bSopenharmony_ci    }
2168bf80f4bSopenharmony_ci    return ret;
2178bf80f4bSopenharmony_ci}
2188bf80f4bSopenharmony_ci
2198bf80f4bSopenharmony_civoid ObjectHierarchyObserver::Destroy()
2208bf80f4bSopenharmony_ci{
2218bf80f4bSopenharmony_ci    ClearSubscriptions();
2228bf80f4bSopenharmony_ci}
2238bf80f4bSopenharmony_ci
2248bf80f4bSopenharmony_civoid ObjectHierarchyObserver::SetTarget(const IObject::Ptr& root, HierarchyChangeModeValue mode)
2258bf80f4bSopenharmony_ci{
2268bf80f4bSopenharmony_ci    ClearSubscriptions();
2278bf80f4bSopenharmony_ci    mode_ = mode;
2288bf80f4bSopenharmony_ci    root_ = root;
2298bf80f4bSopenharmony_ci
2308bf80f4bSopenharmony_ci    if (auto i = interface_cast<IAttach>(root)) {
2318bf80f4bSopenharmony_ci        i->Attach(GetSelf<IAttachment>());
2328bf80f4bSopenharmony_ci    }
2338bf80f4bSopenharmony_ci
2348bf80f4bSopenharmony_ci    Subscribe(root, HierarchyChangeObjectType::ROOT);
2358bf80f4bSopenharmony_ci}
2368bf80f4bSopenharmony_ci
2378bf80f4bSopenharmony_civoid ObjectHierarchyObserver::ClearSubscriptions()
2388bf80f4bSopenharmony_ci{
2398bf80f4bSopenharmony_ci    // Delay subscription removal until outside lock
2408bf80f4bSopenharmony_ci    decltype(subscriptions_) subs;
2418bf80f4bSopenharmony_ci    decltype(immediateChildren_) immes;
2428bf80f4bSopenharmony_ci    {
2438bf80f4bSopenharmony_ci        std::unique_lock lock(mutex_);
2448bf80f4bSopenharmony_ci        subs = BASE_NS::move(subscriptions_);
2458bf80f4bSopenharmony_ci        immes = BASE_NS::move(immediateChildren_);
2468bf80f4bSopenharmony_ci    }
2478bf80f4bSopenharmony_ci    subs.clear();
2488bf80f4bSopenharmony_ci    immes.clear();
2498bf80f4bSopenharmony_ci}
2508bf80f4bSopenharmony_ci
2518bf80f4bSopenharmony_ciIObject::Ptr ObjectHierarchyObserver::GetTarget() const
2528bf80f4bSopenharmony_ci{
2538bf80f4bSopenharmony_ci    return root_.lock();
2548bf80f4bSopenharmony_ci}
2558bf80f4bSopenharmony_ci
2568bf80f4bSopenharmony_ciBASE_NS::vector<IObject::Ptr> ObjectHierarchyObserver::GetAllObserved() const
2578bf80f4bSopenharmony_ci{
2588bf80f4bSopenharmony_ci    std::shared_lock lock(mutex_);
2598bf80f4bSopenharmony_ci    BASE_NS::vector<IObject::Ptr> observed;
2608bf80f4bSopenharmony_ci    observed.reserve(subscriptions_.size());
2618bf80f4bSopenharmony_ci    for (auto&& sub : subscriptions_) {
2628bf80f4bSopenharmony_ci        if (auto object = sub.second.object_.lock()) {
2638bf80f4bSopenharmony_ci            observed.emplace_back(BASE_NS::move(object));
2648bf80f4bSopenharmony_ci        }
2658bf80f4bSopenharmony_ci    }
2668bf80f4bSopenharmony_ci    return observed;
2678bf80f4bSopenharmony_ci}
2688bf80f4bSopenharmony_ci
2698bf80f4bSopenharmony_civoid ObjectHierarchyObserver::AddImmediateChild(const HierarchyChangedInfo& info)
2708bf80f4bSopenharmony_ci{
2718bf80f4bSopenharmony_ci    std::unique_lock lock(mutex_);
2728bf80f4bSopenharmony_ci    if (info.index < immediateChildren_.size()) {
2738bf80f4bSopenharmony_ci        immediateChildren_.insert(
2748bf80f4bSopenharmony_ci            immediateChildren_.begin() + info.index, ImmediateChild { info.object, info.objectType });
2758bf80f4bSopenharmony_ci    } else {
2768bf80f4bSopenharmony_ci        immediateChildren_.push_back(ImmediateChild { info.object, info.objectType });
2778bf80f4bSopenharmony_ci    }
2788bf80f4bSopenharmony_ci}
2798bf80f4bSopenharmony_ci
2808bf80f4bSopenharmony_civoid ObjectHierarchyObserver::RemoveImmediateChild(const HierarchyChangedInfo& info)
2818bf80f4bSopenharmony_ci{
2828bf80f4bSopenharmony_ci    std::unique_lock lock(mutex_);
2838bf80f4bSopenharmony_ci    auto it = immediateChildren_.begin();
2848bf80f4bSopenharmony_ci    for (; it != immediateChildren_.end() && it->object.lock() != info.object; ++it) {
2858bf80f4bSopenharmony_ci    }
2868bf80f4bSopenharmony_ci    if (it != immediateChildren_.end()) {
2878bf80f4bSopenharmony_ci        immediateChildren_.erase(it);
2888bf80f4bSopenharmony_ci    }
2898bf80f4bSopenharmony_ci}
2908bf80f4bSopenharmony_ci
2918bf80f4bSopenharmony_civoid ObjectHierarchyObserver::HierarchyChanged(const HierarchyChangedInfo& info, ObjectChangeListener* listener)
2928bf80f4bSopenharmony_ci{
2938bf80f4bSopenharmony_ci    if (info.object != GetSelf()) {
2948bf80f4bSopenharmony_ci        META_ACCESS_EVENT(OnHierarchyChanged)->Invoke(info);
2958bf80f4bSopenharmony_ci        if (info.objectType == HierarchyChangeObjectType::CHILD ||
2968bf80f4bSopenharmony_ci            info.objectType == HierarchyChangeObjectType::CONTENT) {
2978bf80f4bSopenharmony_ci            // We do not listen to attachments (other than monitoring for changes in an object's attachment list)
2988bf80f4bSopenharmony_ci            if (info.change == HierarchyChangeType::ADDING) {
2998bf80f4bSopenharmony_ci                Subscribe(info.object, info.objectType, info.parent);
3008bf80f4bSopenharmony_ci                if (keepTrackOfImmediate_ && listener->GetType() == HierarchyChangeObjectType::ROOT) {
3018bf80f4bSopenharmony_ci                    AddImmediateChild(info);
3028bf80f4bSopenharmony_ci                }
3038bf80f4bSopenharmony_ci            } else if (info.change == HierarchyChangeType::REMOVED) {
3048bf80f4bSopenharmony_ci                Unsubscribe(info.object);
3058bf80f4bSopenharmony_ci                if (keepTrackOfImmediate_ && listener->GetType() == HierarchyChangeObjectType::ROOT) {
3068bf80f4bSopenharmony_ci                    RemoveImmediateChild(info);
3078bf80f4bSopenharmony_ci                }
3088bf80f4bSopenharmony_ci            }
3098bf80f4bSopenharmony_ci        }
3108bf80f4bSopenharmony_ci    }
3118bf80f4bSopenharmony_ci}
3128bf80f4bSopenharmony_ci
3138bf80f4bSopenharmony_civoid ObjectHierarchyObserver::Subscribe(
3148bf80f4bSopenharmony_ci    const IObject::Ptr& root, HierarchyChangeObjectType type, const IObject::WeakPtr& parent)
3158bf80f4bSopenharmony_ci{
3168bf80f4bSopenharmony_ci    if (!root) {
3178bf80f4bSopenharmony_ci        return;
3188bf80f4bSopenharmony_ci    }
3198bf80f4bSopenharmony_ci
3208bf80f4bSopenharmony_ci    AddSubscription(root, type, parent);
3218bf80f4bSopenharmony_ci
3228bf80f4bSopenharmony_ci    if (const auto container = interface_cast<IContainer>(root)) {
3238bf80f4bSopenharmony_ci        for (auto&& child : container->GetAll()) {
3248bf80f4bSopenharmony_ci            if (keepTrackOfImmediate_ && type == HierarchyChangeObjectType::ROOT) {
3258bf80f4bSopenharmony_ci                std::unique_lock lock(mutex_);
3268bf80f4bSopenharmony_ci                immediateChildren_.push_back(ImmediateChild { child, HierarchyChangeObjectType::CHILD });
3278bf80f4bSopenharmony_ci            }
3288bf80f4bSopenharmony_ci            Subscribe(child, HierarchyChangeObjectType::CHILD, root);
3298bf80f4bSopenharmony_ci        }
3308bf80f4bSopenharmony_ci    }
3318bf80f4bSopenharmony_ci    if (const auto content = interface_cast<IContent>(root)) {
3328bf80f4bSopenharmony_ci        if (auto object = GetValue(content->Content())) {
3338bf80f4bSopenharmony_ci            if (keepTrackOfImmediate_ && type == HierarchyChangeObjectType::ROOT) {
3348bf80f4bSopenharmony_ci                std::unique_lock lock(mutex_);
3358bf80f4bSopenharmony_ci                immediateChildren_.push_back(ImmediateChild { object, HierarchyChangeObjectType::CONTENT });
3368bf80f4bSopenharmony_ci            }
3378bf80f4bSopenharmony_ci            Subscribe(object, HierarchyChangeObjectType::CONTENT, root);
3388bf80f4bSopenharmony_ci        }
3398bf80f4bSopenharmony_ci    }
3408bf80f4bSopenharmony_ci}
3418bf80f4bSopenharmony_ci
3428bf80f4bSopenharmony_civoid ObjectHierarchyObserver::AddSubscription(
3438bf80f4bSopenharmony_ci    const IObject::Ptr& object, HierarchyChangeObjectType type, const IObject::WeakPtr& parent)
3448bf80f4bSopenharmony_ci{
3458bf80f4bSopenharmony_ci    auto listener = BASE_NS::make_unique<ObjectChangeListener>(object, type, parent, this, mode_);
3468bf80f4bSopenharmony_ci
3478bf80f4bSopenharmony_ci    {
3488bf80f4bSopenharmony_ci        std::unique_lock lock(mutex_);
3498bf80f4bSopenharmony_ci        if (subscriptions_.find(listener.get()) != subscriptions_.end()) {
3508bf80f4bSopenharmony_ci            CORE_LOG_E(
3518bf80f4bSopenharmony_ci                "Duplicate event subscription for %s:%s", object->GetClassName().data(), object->GetName().data());
3528bf80f4bSopenharmony_ci        }
3538bf80f4bSopenharmony_ci        subscriptions_.insert({ listener.get(), Subscription(object, BASE_NS::move(listener)) });
3548bf80f4bSopenharmony_ci    }
3558bf80f4bSopenharmony_ci}
3568bf80f4bSopenharmony_ci
3578bf80f4bSopenharmony_civoid ObjectHierarchyObserver::Unsubscribe(const IObject::Ptr& root)
3588bf80f4bSopenharmony_ci{
3598bf80f4bSopenharmony_ci    if (!root) {
3608bf80f4bSopenharmony_ci        return;
3618bf80f4bSopenharmony_ci    }
3628bf80f4bSopenharmony_ci
3638bf80f4bSopenharmony_ci    RemoveSubscription(root);
3648bf80f4bSopenharmony_ci
3658bf80f4bSopenharmony_ci    if (root->GetInterface(IIterable::UID)) {
3668bf80f4bSopenharmony_ci        ForEachShared(
3678bf80f4bSopenharmony_ci            root, [this](const IObject::Ptr& object) { RemoveSubscription(object); },
3688bf80f4bSopenharmony_ci            TraversalType::DEPTH_FIRST_PRE_ORDER);
3698bf80f4bSopenharmony_ci    } else {
3708bf80f4bSopenharmony_ci        if (const auto container = interface_cast<IContainer>(root)) {
3718bf80f4bSopenharmony_ci            for (auto&& child : container->GetAll()) {
3728bf80f4bSopenharmony_ci                Unsubscribe(child);
3738bf80f4bSopenharmony_ci            }
3748bf80f4bSopenharmony_ci        }
3758bf80f4bSopenharmony_ci        if (const auto content = interface_cast<IContent>(root)) {
3768bf80f4bSopenharmony_ci            if (auto object = GetValue(content->Content())) {
3778bf80f4bSopenharmony_ci                Unsubscribe(object);
3788bf80f4bSopenharmony_ci            }
3798bf80f4bSopenharmony_ci        }
3808bf80f4bSopenharmony_ci    }
3818bf80f4bSopenharmony_ci}
3828bf80f4bSopenharmony_ci
3838bf80f4bSopenharmony_civoid ObjectHierarchyObserver::RemoveSubscription(const IObject::Ptr& object)
3848bf80f4bSopenharmony_ci{
3858bf80f4bSopenharmony_ci    // Delay subscription destruction until we're out of the lock
3868bf80f4bSopenharmony_ci    BASE_NS::vector<Subscription> subs;
3878bf80f4bSopenharmony_ci    {
3888bf80f4bSopenharmony_ci        std::unique_lock lock(mutex_);
3898bf80f4bSopenharmony_ci        auto it = subscriptions_.begin();
3908bf80f4bSopenharmony_ci        while (it != subscriptions_.end()) {
3918bf80f4bSopenharmony_ci            const auto o = it->second.object_.lock();
3928bf80f4bSopenharmony_ci            if (!o || o == object) {
3938bf80f4bSopenharmony_ci                subs.emplace_back(BASE_NS::move(it->second));
3948bf80f4bSopenharmony_ci                it = subscriptions_.erase(it);
3958bf80f4bSopenharmony_ci            } else {
3968bf80f4bSopenharmony_ci                ++it;
3978bf80f4bSopenharmony_ci            }
3988bf80f4bSopenharmony_ci        }
3998bf80f4bSopenharmony_ci    }
4008bf80f4bSopenharmony_ci    subs.clear();
4018bf80f4bSopenharmony_ci}
4028bf80f4bSopenharmony_ci
4038bf80f4bSopenharmony_civoid ObjectHierarchyObserver::NotifyOnDetach()
4048bf80f4bSopenharmony_ci{
4058bf80f4bSopenharmony_ci    // If we were attached to the target and we are getting detached when the target already died, lets
4068bf80f4bSopenharmony_ci    // notify about the removing the immediate children as those are not otherwise notified when destroying
4078bf80f4bSopenharmony_ci    // container
4088bf80f4bSopenharmony_ci    decltype(immediateChildren_) ic;
4098bf80f4bSopenharmony_ci    {
4108bf80f4bSopenharmony_ci        std::unique_lock lock(mutex_);
4118bf80f4bSopenharmony_ci        ic = BASE_NS::move(immediateChildren_);
4128bf80f4bSopenharmony_ci    }
4138bf80f4bSopenharmony_ci    if (root_.expired()) {
4148bf80f4bSopenharmony_ci        for (auto&& c : ic) {
4158bf80f4bSopenharmony_ci            if (auto o = c.object.lock()) {
4168bf80f4bSopenharmony_ci                // Generate pre transaction notifications (even if coming in wrong time).
4178bf80f4bSopenharmony_ci                HierarchyChangedInfo info { o, HierarchyChangeType::REMOVING, c.type, size_t(-1), nullptr };
4188bf80f4bSopenharmony_ci                META_ACCESS_EVENT(OnHierarchyChanged)->Invoke(info);
4198bf80f4bSopenharmony_ci                info.change = HierarchyChangeType::REMOVED;
4208bf80f4bSopenharmony_ci                META_ACCESS_EVENT(OnHierarchyChanged)->Invoke(info);
4218bf80f4bSopenharmony_ci            }
4228bf80f4bSopenharmony_ci        }
4238bf80f4bSopenharmony_ci    }
4248bf80f4bSopenharmony_ci}
4258bf80f4bSopenharmony_ci
4268bf80f4bSopenharmony_cibool ObjectHierarchyObserver::Attaching(const META_NS::IAttach::Ptr& target, const META_NS::IObject::Ptr& dataContext)
4278bf80f4bSopenharmony_ci{
4288bf80f4bSopenharmony_ci    META_ACCESS_PROPERTY(AttachedTo)->SetValue(target);
4298bf80f4bSopenharmony_ci    META_ACCESS_PROPERTY(DataContext)->SetValue(dataContext);
4308bf80f4bSopenharmony_ci    {
4318bf80f4bSopenharmony_ci        std::unique_lock lock(mutex_);
4328bf80f4bSopenharmony_ci        keepTrackOfImmediate_ = true;
4338bf80f4bSopenharmony_ci    }
4348bf80f4bSopenharmony_ci    return true;
4358bf80f4bSopenharmony_ci}
4368bf80f4bSopenharmony_cibool ObjectHierarchyObserver::Detaching(const META_NS::IAttach::Ptr& target)
4378bf80f4bSopenharmony_ci{
4388bf80f4bSopenharmony_ci    NotifyOnDetach();
4398bf80f4bSopenharmony_ci    {
4408bf80f4bSopenharmony_ci        std::unique_lock lock(mutex_);
4418bf80f4bSopenharmony_ci        keepTrackOfImmediate_ = false;
4428bf80f4bSopenharmony_ci    }
4438bf80f4bSopenharmony_ci    META_ACCESS_PROPERTY(AttachedTo)->SetValue({});
4448bf80f4bSopenharmony_ci    META_ACCESS_PROPERTY(DataContext)->SetValue({});
4458bf80f4bSopenharmony_ci    return true;
4468bf80f4bSopenharmony_ci}
4478bf80f4bSopenharmony_ci
4488bf80f4bSopenharmony_ciMETA_END_NAMESPACE()
449