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