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 
16 #include <shared_mutex>
17 
18 #include <meta/api/event_handler.h>
19 #include <meta/api/property/property_event_handler.h>
20 #include <meta/api/threading/mutex.h>
21 #include <meta/ext/implementation_macros.h>
22 #include <meta/interface/intf_content.h>
23 #include <meta/interface/intf_iterable.h>
24 #include <meta/interface/intf_required_interfaces.h>
25 #include <meta/interface/loaders/intf_dynamic_content_loader.h>
26 
27 #include "object.h"
28 
29 META_BEGIN_NAMESPACE()
30 
31 class ContentObject
32     : public Internal::ObjectFwd<ContentObject, ClassId::ContentObject, IContent, IRequiredInterfaces, IIterable> {
33     using Super = Internal::ObjectFwd<ContentObject, ClassId::ContentObject, IContent, IRequiredInterfaces, IIterable>;
34 
35 public:
META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IContent,IObject::Ptr,Content)36     META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IContent, IObject::Ptr, Content)
37     META_IMPLEMENT_INTERFACE_PROPERTY(IContent, bool, ContentSearchable, true)
38     META_IMPLEMENT_INTERFACE_PROPERTY(IContent, IContentLoader::Ptr, ContentLoader)
39 
40     bool SetContent(const IObject::Ptr& content) override
41     {
42         META_ACCESS_PROPERTY(ContentLoader)->SetValue(nullptr);
43         return SetContentInternal(content);
44     }
45 
Build(const IMetadata::Ptr & data)46     bool Build(const IMetadata::Ptr& data) override
47     {
48         bool ret = Super::Build(data);
49         if (ret) {
50             loaderChanged_.Subscribe(META_ACCESS_PROPERTY(ContentLoader), [this] { OnLoaderChanged(); });
51             OnSerializeChanged();
52         }
53         return ret;
54     }
55 
Destroy()56     void Destroy() override
57     {
58         if (auto c = META_ACCESS_PROPERTY(Content)) {
59             c->OnChanged()->Reset();
60             c->SetValue(nullptr);
61         }
62         Super::Destroy();
63     }
64 
OnSerializeChanged()65     void OnSerializeChanged()
66     {
67         if (auto cont = META_ACCESS_PROPERTY(Content)) {
68             META_NS::SetObjectFlags(cont.GetProperty(), ObjectFlagBits::SERIALIZE,
69                 GetObjectFlags().IsSet(ObjectFlagBits::SERIALIZE_HIERARCHY));
70         }
71     }
72 
OnLoaderChanged()73     void OnLoaderChanged()
74     {
75         contentChanged_.Unsubscribe();
76         if (auto dynamic = interface_pointer_cast<IDynamicContentLoader>(META_ACCESS_PROPERTY_VALUE(ContentLoader))) {
77             // If our loader is dynamic (i.e. the content can change), subscribe to change events
78             contentChanged_.Subscribe<IOnChanged>(dynamic->ContentChanged(), [&] { OnContentChanged(); });
79         }
80         OnContentChanged();
81     }
82 
OnContentChanged()83     void OnContentChanged()
84     {
85         const auto loader = META_ACCESS_PROPERTY_VALUE(ContentLoader);
86         SetContentInternal(loader ? loader->Create({}) : nullptr);
87     }
88 
SetObjectFlags(const ObjectFlagBitsValue & flags)89     void SetObjectFlags(const ObjectFlagBitsValue& flags) override
90     {
91         Super::SetObjectFlags(flags);
92         OnSerializeChanged();
93     }
94 
GetObjectDefaultFlags() const95     ObjectFlagBitsValue GetObjectDefaultFlags() const override
96     {
97         auto flags = Super::GetObjectDefaultFlags();
98         flags &= ~ObjectFlagBitsValue(ObjectFlagBits::SERIALIZE_HIERARCHY);
99         return flags;
100     }
101 
SetRequiredInterfaces(const BASE_NS::vector<TypeId> & interfaces)102     bool SetRequiredInterfaces(const BASE_NS::vector<TypeId>& interfaces) override
103     {
104         {
105             std::unique_lock lock(mutex_);
106             requiredInterfaces_ = interfaces;
107         }
108         bool valid = false;
109         if (const auto content = META_ACCESS_PROPERTY_VALUE(Content)) {
110             valid = CheckContentRequirements(content);
111         }
112         if (!valid) {
113             // We don't have valid content, check if we could create one with our loader
114             OnContentChanged();
115         }
116         return true;
117     }
GetRequiredInterfaces() const118     BASE_NS::vector<TypeId> GetRequiredInterfaces() const override
119     {
120         std::shared_lock lock(mutex_);
121         return requiredInterfaces_;
122     }
123 
SetContentInternal(const IObject::Ptr & content)124     bool SetContentInternal(const IObject::Ptr& content)
125     {
126         bool valid = CheckContentRequirements(content);
127         META_ACCESS_PROPERTY(Content)->SetValue(valid ? content : nullptr);
128         if (!valid) {
129             CORE_LOG_W("Content does not fulfil interface requirements");
130         }
131         return valid;
132     }
133 
CheckContentRequirements(const IObject::Ptr & object)134     bool CheckContentRequirements(const IObject::Ptr& object)
135     {
136         std::shared_lock lock(mutex_);
137         // Null object always passes content requirements
138         return !object || CheckInterfaces(object, requiredInterfaces_, true);
139     }
140 
141     template<typename Func>
IterateImpl(const Func & f) const142     IterationResult IterateImpl(const Func& f) const
143     {
144         if (!f) {
145             CORE_LOG_W("Incompatible function with Iterate");
146             return IterationResult::FAILED;
147         }
148         if (META_ACCESS_PROPERTY_VALUE(ContentSearchable)) {
149             if (auto c = META_ACCESS_PROPERTY_VALUE(Content)) {
150                 return f->Invoke(c);
151             }
152         }
153         return IterationResult::CONTINUE;
154     }
155 
Iterate(const IterationParameters & params)156     IterationResult Iterate(const IterationParameters& params) override
157     {
158         return IterateImpl(params.function.GetInterface<IIterableCallable<IObject::Ptr>>());
159     }
160 
Iterate(const IterationParameters & params) const161     IterationResult Iterate(const IterationParameters& params) const override
162     {
163         return IterateImpl(params.function.GetInterface<IIterableConstCallable<IObject::Ptr>>());
164     }
165 
166 private:
167     PropertyChangedEventHandler loaderChanged_;
168     EventHandler contentChanged_;
169     BASE_NS::vector<TypeId> requiredInterfaces_;
170     mutable std::shared_mutex mutex_;
171 };
172 
173 namespace Internal {
174 
GetContentObjectFactory()175 IObjectFactory::Ptr GetContentObjectFactory()
176 {
177     return ContentObject::GetFactory();
178 }
179 
180 } // namespace Internal
181 
182 META_END_NAMESPACE()
183