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 <shared_mutex>
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <meta/api/event_handler.h>
198bf80f4bSopenharmony_ci#include <meta/api/property/property_event_handler.h>
208bf80f4bSopenharmony_ci#include <meta/api/threading/mutex.h>
218bf80f4bSopenharmony_ci#include <meta/ext/implementation_macros.h>
228bf80f4bSopenharmony_ci#include <meta/interface/intf_content.h>
238bf80f4bSopenharmony_ci#include <meta/interface/intf_iterable.h>
248bf80f4bSopenharmony_ci#include <meta/interface/intf_required_interfaces.h>
258bf80f4bSopenharmony_ci#include <meta/interface/loaders/intf_dynamic_content_loader.h>
268bf80f4bSopenharmony_ci
278bf80f4bSopenharmony_ci#include "object.h"
288bf80f4bSopenharmony_ci
298bf80f4bSopenharmony_ciMETA_BEGIN_NAMESPACE()
308bf80f4bSopenharmony_ci
318bf80f4bSopenharmony_ciclass ContentObject
328bf80f4bSopenharmony_ci    : public Internal::ObjectFwd<ContentObject, ClassId::ContentObject, IContent, IRequiredInterfaces, IIterable> {
338bf80f4bSopenharmony_ci    using Super = Internal::ObjectFwd<ContentObject, ClassId::ContentObject, IContent, IRequiredInterfaces, IIterable>;
348bf80f4bSopenharmony_ci
358bf80f4bSopenharmony_cipublic:
368bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IContent, IObject::Ptr, Content)
378bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(IContent, bool, ContentSearchable, true)
388bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(IContent, IContentLoader::Ptr, ContentLoader)
398bf80f4bSopenharmony_ci
408bf80f4bSopenharmony_ci    bool SetContent(const IObject::Ptr& content) override
418bf80f4bSopenharmony_ci    {
428bf80f4bSopenharmony_ci        META_ACCESS_PROPERTY(ContentLoader)->SetValue(nullptr);
438bf80f4bSopenharmony_ci        return SetContentInternal(content);
448bf80f4bSopenharmony_ci    }
458bf80f4bSopenharmony_ci
468bf80f4bSopenharmony_ci    bool Build(const IMetadata::Ptr& data) override
478bf80f4bSopenharmony_ci    {
488bf80f4bSopenharmony_ci        bool ret = Super::Build(data);
498bf80f4bSopenharmony_ci        if (ret) {
508bf80f4bSopenharmony_ci            loaderChanged_.Subscribe(META_ACCESS_PROPERTY(ContentLoader), [this] { OnLoaderChanged(); });
518bf80f4bSopenharmony_ci            OnSerializeChanged();
528bf80f4bSopenharmony_ci        }
538bf80f4bSopenharmony_ci        return ret;
548bf80f4bSopenharmony_ci    }
558bf80f4bSopenharmony_ci
568bf80f4bSopenharmony_ci    void Destroy() override
578bf80f4bSopenharmony_ci    {
588bf80f4bSopenharmony_ci        if (auto c = META_ACCESS_PROPERTY(Content)) {
598bf80f4bSopenharmony_ci            c->OnChanged()->Reset();
608bf80f4bSopenharmony_ci            c->SetValue(nullptr);
618bf80f4bSopenharmony_ci        }
628bf80f4bSopenharmony_ci        Super::Destroy();
638bf80f4bSopenharmony_ci    }
648bf80f4bSopenharmony_ci
658bf80f4bSopenharmony_ci    void OnSerializeChanged()
668bf80f4bSopenharmony_ci    {
678bf80f4bSopenharmony_ci        if (auto cont = META_ACCESS_PROPERTY(Content)) {
688bf80f4bSopenharmony_ci            META_NS::SetObjectFlags(cont.GetProperty(), ObjectFlagBits::SERIALIZE,
698bf80f4bSopenharmony_ci                GetObjectFlags().IsSet(ObjectFlagBits::SERIALIZE_HIERARCHY));
708bf80f4bSopenharmony_ci        }
718bf80f4bSopenharmony_ci    }
728bf80f4bSopenharmony_ci
738bf80f4bSopenharmony_ci    void OnLoaderChanged()
748bf80f4bSopenharmony_ci    {
758bf80f4bSopenharmony_ci        contentChanged_.Unsubscribe();
768bf80f4bSopenharmony_ci        if (auto dynamic = interface_pointer_cast<IDynamicContentLoader>(META_ACCESS_PROPERTY_VALUE(ContentLoader))) {
778bf80f4bSopenharmony_ci            // If our loader is dynamic (i.e. the content can change), subscribe to change events
788bf80f4bSopenharmony_ci            contentChanged_.Subscribe<IOnChanged>(dynamic->ContentChanged(), [&] { OnContentChanged(); });
798bf80f4bSopenharmony_ci        }
808bf80f4bSopenharmony_ci        OnContentChanged();
818bf80f4bSopenharmony_ci    }
828bf80f4bSopenharmony_ci
838bf80f4bSopenharmony_ci    void OnContentChanged()
848bf80f4bSopenharmony_ci    {
858bf80f4bSopenharmony_ci        const auto loader = META_ACCESS_PROPERTY_VALUE(ContentLoader);
868bf80f4bSopenharmony_ci        SetContentInternal(loader ? loader->Create({}) : nullptr);
878bf80f4bSopenharmony_ci    }
888bf80f4bSopenharmony_ci
898bf80f4bSopenharmony_ci    void SetObjectFlags(const ObjectFlagBitsValue& flags) override
908bf80f4bSopenharmony_ci    {
918bf80f4bSopenharmony_ci        Super::SetObjectFlags(flags);
928bf80f4bSopenharmony_ci        OnSerializeChanged();
938bf80f4bSopenharmony_ci    }
948bf80f4bSopenharmony_ci
958bf80f4bSopenharmony_ci    ObjectFlagBitsValue GetObjectDefaultFlags() const override
968bf80f4bSopenharmony_ci    {
978bf80f4bSopenharmony_ci        auto flags = Super::GetObjectDefaultFlags();
988bf80f4bSopenharmony_ci        flags &= ~ObjectFlagBitsValue(ObjectFlagBits::SERIALIZE_HIERARCHY);
998bf80f4bSopenharmony_ci        return flags;
1008bf80f4bSopenharmony_ci    }
1018bf80f4bSopenharmony_ci
1028bf80f4bSopenharmony_ci    bool SetRequiredInterfaces(const BASE_NS::vector<TypeId>& interfaces) override
1038bf80f4bSopenharmony_ci    {
1048bf80f4bSopenharmony_ci        {
1058bf80f4bSopenharmony_ci            std::unique_lock lock(mutex_);
1068bf80f4bSopenharmony_ci            requiredInterfaces_ = interfaces;
1078bf80f4bSopenharmony_ci        }
1088bf80f4bSopenharmony_ci        bool valid = false;
1098bf80f4bSopenharmony_ci        if (const auto content = META_ACCESS_PROPERTY_VALUE(Content)) {
1108bf80f4bSopenharmony_ci            valid = CheckContentRequirements(content);
1118bf80f4bSopenharmony_ci        }
1128bf80f4bSopenharmony_ci        if (!valid) {
1138bf80f4bSopenharmony_ci            // We don't have valid content, check if we could create one with our loader
1148bf80f4bSopenharmony_ci            OnContentChanged();
1158bf80f4bSopenharmony_ci        }
1168bf80f4bSopenharmony_ci        return true;
1178bf80f4bSopenharmony_ci    }
1188bf80f4bSopenharmony_ci    BASE_NS::vector<TypeId> GetRequiredInterfaces() const override
1198bf80f4bSopenharmony_ci    {
1208bf80f4bSopenharmony_ci        std::shared_lock lock(mutex_);
1218bf80f4bSopenharmony_ci        return requiredInterfaces_;
1228bf80f4bSopenharmony_ci    }
1238bf80f4bSopenharmony_ci
1248bf80f4bSopenharmony_ci    bool SetContentInternal(const IObject::Ptr& content)
1258bf80f4bSopenharmony_ci    {
1268bf80f4bSopenharmony_ci        bool valid = CheckContentRequirements(content);
1278bf80f4bSopenharmony_ci        META_ACCESS_PROPERTY(Content)->SetValue(valid ? content : nullptr);
1288bf80f4bSopenharmony_ci        if (!valid) {
1298bf80f4bSopenharmony_ci            CORE_LOG_W("Content does not fulfil interface requirements");
1308bf80f4bSopenharmony_ci        }
1318bf80f4bSopenharmony_ci        return valid;
1328bf80f4bSopenharmony_ci    }
1338bf80f4bSopenharmony_ci
1348bf80f4bSopenharmony_ci    bool CheckContentRequirements(const IObject::Ptr& object)
1358bf80f4bSopenharmony_ci    {
1368bf80f4bSopenharmony_ci        std::shared_lock lock(mutex_);
1378bf80f4bSopenharmony_ci        // Null object always passes content requirements
1388bf80f4bSopenharmony_ci        return !object || CheckInterfaces(object, requiredInterfaces_, true);
1398bf80f4bSopenharmony_ci    }
1408bf80f4bSopenharmony_ci
1418bf80f4bSopenharmony_ci    template<typename Func>
1428bf80f4bSopenharmony_ci    IterationResult IterateImpl(const Func& f) const
1438bf80f4bSopenharmony_ci    {
1448bf80f4bSopenharmony_ci        if (!f) {
1458bf80f4bSopenharmony_ci            CORE_LOG_W("Incompatible function with Iterate");
1468bf80f4bSopenharmony_ci            return IterationResult::FAILED;
1478bf80f4bSopenharmony_ci        }
1488bf80f4bSopenharmony_ci        if (META_ACCESS_PROPERTY_VALUE(ContentSearchable)) {
1498bf80f4bSopenharmony_ci            if (auto c = META_ACCESS_PROPERTY_VALUE(Content)) {
1508bf80f4bSopenharmony_ci                return f->Invoke(c);
1518bf80f4bSopenharmony_ci            }
1528bf80f4bSopenharmony_ci        }
1538bf80f4bSopenharmony_ci        return IterationResult::CONTINUE;
1548bf80f4bSopenharmony_ci    }
1558bf80f4bSopenharmony_ci
1568bf80f4bSopenharmony_ci    IterationResult Iterate(const IterationParameters& params) override
1578bf80f4bSopenharmony_ci    {
1588bf80f4bSopenharmony_ci        return IterateImpl(params.function.GetInterface<IIterableCallable<IObject::Ptr>>());
1598bf80f4bSopenharmony_ci    }
1608bf80f4bSopenharmony_ci
1618bf80f4bSopenharmony_ci    IterationResult Iterate(const IterationParameters& params) const override
1628bf80f4bSopenharmony_ci    {
1638bf80f4bSopenharmony_ci        return IterateImpl(params.function.GetInterface<IIterableConstCallable<IObject::Ptr>>());
1648bf80f4bSopenharmony_ci    }
1658bf80f4bSopenharmony_ci
1668bf80f4bSopenharmony_ciprivate:
1678bf80f4bSopenharmony_ci    PropertyChangedEventHandler loaderChanged_;
1688bf80f4bSopenharmony_ci    EventHandler contentChanged_;
1698bf80f4bSopenharmony_ci    BASE_NS::vector<TypeId> requiredInterfaces_;
1708bf80f4bSopenharmony_ci    mutable std::shared_mutex mutex_;
1718bf80f4bSopenharmony_ci};
1728bf80f4bSopenharmony_ci
1738bf80f4bSopenharmony_cinamespace Internal {
1748bf80f4bSopenharmony_ci
1758bf80f4bSopenharmony_ciIObjectFactory::Ptr GetContentObjectFactory()
1768bf80f4bSopenharmony_ci{
1778bf80f4bSopenharmony_ci    return ContentObject::GetFactory();
1788bf80f4bSopenharmony_ci}
1798bf80f4bSopenharmony_ci
1808bf80f4bSopenharmony_ci} // namespace Internal
1818bf80f4bSopenharmony_ci
1828bf80f4bSopenharmony_ciMETA_END_NAMESPACE()
183