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