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