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