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 "proxy_object.h"
17
18 #include <algorithm>
19
20 #include <meta/api/make_callback.h>
21 #include <meta/api/property/property_event_handler.h>
22 #include <meta/api/util.h>
23
24 META_BEGIN_NAMESPACE()
25
26 namespace Internal {
27
~ProxyObject()28 ProxyObject::~ProxyObject()
29 {
30 if (meta_) {
31 ResetTargetListener();
32 for (auto&& p : meta_->GetProperties()) {
33 p->OnChanged()->RemoveHandler(uintptr_t(this));
34 }
35 }
36 }
37
Build(const IMetadata::Ptr & data)38 bool ProxyObject::Build(const IMetadata::Ptr& data)
39 {
40 bool ret = Super::Build(data);
41 if (ret) {
42 meta_ = interface_cast<META_NS::IMetadata>(Super::GetAttachmentContainer(true));
43 if (!meta_) {
44 return false;
45 }
46 Dynamic()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this]() {
47 if (Dynamic()->GetValue()) {
48 ListenTargetChanges();
49 RefreshProperties();
50 } else {
51 ResetTargetListener();
52 }
53 }));
54
55 for (auto&& p : meta_->GetProperties()) {
56 p->OnChanged()->AddHandler(MakeCallback<IOnChanged>(
57 [this](auto p) {
58 if (p) {
59 OnPropertyChanged(p);
60 }
61 },
62 p),
63 uintptr_t(this));
64 }
65
66 if (auto meta = GetSelf<IAttach>()) {
67 metaAdded_.Subscribe<IOnChildChanged>(
68 meta->GetAttachmentContainer(true)->OnContainerChanged(), [this](const auto& i) {
69 if (interface_cast<IProperty>(i.object)) {
70 if (i.type == ContainerChangeType::ADDED) {
71 OnPropertyAdded(i);
72 } else if (i.type == ContainerChangeType::REMOVED) {
73 OnPropertyRemoved(i);
74 }
75 }
76 });
77 }
78 UpdateSerializeState();
79 }
80 return ret;
81 }
82
SerializeEmbeddedProxy(IProperty::Ptr p)83 static bool SerializeEmbeddedProxy(IProperty::Ptr p)
84 {
85 // Check for embedded proxy objects
86 if (auto proxy = GetPointer<IProxyObject>(p)) {
87 if (auto f = interface_cast<IObjectFlags>(proxy)) {
88 return static_cast<bool>(f->GetObjectFlags() & ObjectFlagBits::SERIALIZE);
89 }
90 }
91 return false;
92 }
93
OnPropertyAdded(const ChildChangedInfo & info)94 void ProxyObject::OnPropertyAdded(const ChildChangedInfo& info)
95 {
96 if (auto p = interface_pointer_cast<IProperty>(info.object)) {
97 auto f = GetSelf<IObjectFlags>();
98 if (!updating_ && f && !(f->GetObjectFlags() & ObjectFlagBits::SERIALIZE)) {
99 META_NS::SetObjectFlags(f, ObjectFlagBits::SERIALIZE, ShouldSerialise(p));
100 }
101 p->OnChanged()->AddHandler(MakeCallback<IOnChanged>(
102 [this](auto p) {
103 if (p) {
104 OnPropertyChanged(p);
105 }
106 },
107 p),
108 uintptr_t(this));
109 }
110 }
111
OnPropertyRemoved(const ChildChangedInfo & info)112 void ProxyObject::OnPropertyRemoved(const ChildChangedInfo& info)
113 {
114 if (auto p = interface_cast<IProperty>(info.object)) {
115 p->OnChanged()->RemoveHandler(uintptr_t(this));
116 }
117 auto f = GetSelf<IObjectFlags>();
118 if (!updating_ && f && f->GetObjectFlags() & ObjectFlagBits::SERIALIZE) {
119 UpdateSerializeState();
120 }
121 }
122
OnPropertyChanged(const IProperty::Ptr & p)123 void ProxyObject::OnPropertyChanged(const IProperty::Ptr& p)
124 {
125 auto f = GetSelf<IObjectFlags>();
126 if (!updating_ && f) {
127 if (f->GetObjectFlags() & ObjectFlagBits::SERIALIZE) {
128 UpdateSerializeState();
129 } else {
130 META_NS::SetObjectFlags(f, ObjectFlagBits::SERIALIZE, ShouldSerialise(p));
131 }
132 }
133 }
134
ListenTargetChanges()135 void ProxyObject::ListenTargetChanges()
136 {
137 if (auto target = interface_pointer_cast<IAttach>(GetTarget())) {
138 targetAddedListener_.Subscribe<IOnChildChanged>(
139 target->GetAttachmentContainer(true)->OnContainerChanged(), [&](auto i) {
140 if (interface_cast<IProperty>(i.object)) {
141 RefreshProperties();
142 }
143 });
144 }
145 }
146
ResetTargetListener()147 void ProxyObject::ResetTargetListener()
148 {
149 targetAddedListener_.Unsubscribe();
150 targetRemovedListener_.Unsubscribe();
151 }
152
RefreshProperties()153 void ProxyObject::RefreshProperties()
154 {
155 if (!GetTarget()) {
156 RemoveAllProxyProperties();
157 return;
158 }
159 updating_ = true;
160
161 auto propertiesToRemove = BASE_NS::vector<BASE_NS::string>();
162 auto propertiesToAdd = BASE_NS::vector<BASE_NS::string>();
163 for (auto&& property : proxyProperties_) {
164 const auto& name = property.first;
165 META_NS::IProperty::Ptr sourceProperty;
166 if (auto internalSourceName = internalBindings_.find(name); internalSourceName != internalBindings_.end()) {
167 auto targetSourceProperty = interface_cast<IMetadata>(GetTarget())->GetProperty(internalSourceName->second);
168 if (targetSourceProperty) {
169 propertiesToAdd.push_back(name);
170 continue;
171 }
172 internalBindings_.erase(internalSourceName);
173 sourceProperty = interface_cast<IMetadata>(GetTarget())->GetProperty(name);
174 if (!sourceProperty) {
175 propertiesToRemove.push_back(name);
176 propertiesToAdd.push_back(name);
177 continue;
178 }
179 } else {
180 sourceProperty = interface_cast<IMetadata>(GetTarget())->GetProperty(name);
181 if (!sourceProperty) {
182 propertiesToRemove.push_back(name);
183 continue;
184 }
185 }
186 auto& valueBind = proxyProperties_.find(name)->second;
187 const auto bindingResult = valueBind.Bind(sourceProperty);
188 if (!bindingResult) {
189 propertiesToRemove.push_back(name);
190 propertiesToAdd.push_back(name);
191 }
192 }
193 for (const auto& remove : propertiesToRemove) {
194 RemoveProxyProperty(remove);
195 }
196 for (const auto& name : propertiesToAdd) {
197 AddProxyProperty(name);
198 }
199 updating_ = false;
200 UpdateSerializeState();
201 }
202
GetTarget() const203 const IObject::Ptr ProxyObject::GetTarget() const
204 {
205 return target_.lock();
206 }
207
SetTarget(const IObject::Ptr & target)208 bool ProxyObject::SetTarget(const IObject::Ptr& target)
209 {
210 ResetTargetListener();
211 target_ = target;
212 if (Dynamic()->GetValue()) {
213 ListenTargetChanges();
214 }
215 RefreshProperties();
216 if (META_ACCESS_PROPERTY_VALUE(Mode) & ProxyMode::REFLECT_PROXY_HIERARCHY) {
217 ReflectHierarchy(target);
218 }
219 return true;
220 }
221
ReflectHierarchy(const IObject::Ptr & target)222 void ProxyObject::ReflectHierarchy(const IObject::Ptr& target)
223 {
224 auto m = interface_pointer_cast<IMetadata>(target);
225 if (!m) {
226 return;
227 }
228 for (auto&& p : meta_->GetProperties()) {
229 // reflect only non-proxyable properties
230 if (!proxyProperties_.count(p->GetName())) {
231 if (auto proxy = GetPointer<IProxyObject>(p)) {
232 ReflectTargetForProperty(m, p->GetName(), proxy);
233 }
234 }
235 }
236 }
237
ReflectTargetForProperty(const IMetadata::Ptr & m,BASE_NS::string_view name,const IProxyObject::Ptr & proxy)238 void ProxyObject::ReflectTargetForProperty(
239 const IMetadata::Ptr& m, BASE_NS::string_view name, const IProxyObject::Ptr& proxy)
240 {
241 if (auto p = m->GetProperty(name)) {
242 if (auto tp = GetPointer<IObject>(p)) {
243 proxy->SetTarget(tp);
244 }
245 }
246 }
247
GetOverrides() const248 BASE_NS::vector<IProperty::ConstPtr> ProxyObject::GetOverrides() const
249 {
250 BASE_NS::vector<IProperty::ConstPtr> res;
251 for (auto&& p : proxyProperties_) {
252 if (!p.second.IsDefaultValue()) {
253 res.push_back(p.second.GetProperty());
254 }
255 }
256 return res;
257 }
258
GetOverride(BASE_NS::string_view name) const259 IProperty::ConstPtr ProxyObject::GetOverride(BASE_NS::string_view name) const
260 {
261 auto it = proxyProperties_.find(name);
262 return it != proxyProperties_.end() && !it->second.IsDefaultValue() ? it->second.GetProperty() : nullptr;
263 }
264
GetProxyProperty(BASE_NS::string_view name) const265 IProperty::ConstPtr ProxyObject::GetProxyProperty(BASE_NS::string_view name) const
266 {
267 auto it = proxyProperties_.find(name);
268 return it != proxyProperties_.end() ? it->second.GetProperty() : nullptr;
269 }
270
SetPropertyTarget(const IProperty::Ptr & property)271 IProperty::Ptr ProxyObject::SetPropertyTarget(const IProperty::Ptr& property)
272 {
273 if (!property) {
274 return nullptr;
275 }
276 IProperty::Ptr res;
277 bool add = true;
278 auto it = proxyProperties_.find(property->GetName());
279 if (it != proxyProperties_.end()) {
280 auto bprop = it->second.GetProperty();
281 add = !bprop || bprop->GetTypeId() != property->GetTypeId();
282 if (add) {
283 proxyProperties_.erase(it);
284 } else {
285 it->second.Bind(property);
286 res = it->second.GetProperty();
287 }
288 }
289 if (add && property) {
290 if (auto p = meta_->GetProperty(property->GetName())) {
291 proxyProperties_.insert_or_assign(p->GetName(), DefaultValueBind(p, property));
292 res = p;
293 } else {
294 res = AddProxyProperty(property->GetName(), property);
295 }
296 }
297 return res;
298 }
299
AddProxyProperty(BASE_NS::string_view name,const IProperty::ConstPtr & tp)300 IProperty::Ptr ProxyObject::AddProxyProperty(BASE_NS::string_view name, const IProperty::ConstPtr& tp)
301 {
302 auto p = meta_->GetProperty(name);
303 if (!p) {
304 p = DuplicatePropertyType(META_NS::GetObjectRegistry(), tp, name);
305 }
306 if (p) {
307 proxyProperties_.insert_or_assign(p->GetName(), DefaultValueBind(p, tp));
308 AddProperty(p);
309 }
310 return p;
311 }
312
AddProxyProperty(BASE_NS::string_view name)313 IProperty::Ptr ProxyObject::AddProxyProperty(BASE_NS::string_view name)
314 {
315 IProperty::Ptr p;
316 if (internalBindings_.contains(name)) {
317 auto source = GetProperty(internalBindings_[name]);
318 if (!source) {
319 return {};
320 }
321 p = AddProxyProperty(name, source);
322 } else if (auto target = interface_pointer_cast<IMetadata>(GetTarget())) {
323 if (auto tp = target->GetProperty(name)) {
324 p = AddProxyProperty(name, tp);
325 }
326 }
327 return p;
328 }
329
PopulateAllProperties()330 void ProxyObject::PopulateAllProperties()
331 {
332 if (auto target = interface_pointer_cast<IMetadata>(GetTarget())) {
333 for (auto&& p : target->GetProperties()) {
334 auto it = proxyProperties_.find(p->GetName());
335 if (it == proxyProperties_.end()) {
336 AddProxyProperty(p->GetName(), p);
337 }
338 }
339 }
340 }
341
GetProperty(BASE_NS::string_view name,MetadataQuery q)342 IProperty::Ptr ProxyObject::GetProperty(BASE_NS::string_view name, MetadataQuery q)
343 {
344 auto p = meta_->GetProperty(name, q);
345 if (!p) {
346 p = AddProxyProperty(name);
347 }
348 return p;
349 }
350
GetProperty(BASE_NS::string_view name,MetadataQuery q) const351 IProperty::ConstPtr ProxyObject::GetProperty(BASE_NS::string_view name, MetadataQuery q) const
352 {
353 return const_cast<ProxyObject*>(this)->GetProperty(name, q);
354 }
355
RemoveProperty(const IProperty::Ptr & p)356 bool ProxyObject::RemoveProperty(const IProperty::Ptr& p)
357 {
358 bool res = meta_->RemoveProperty(p);
359 proxyProperties_.erase(p->GetName());
360 return res;
361 }
362
GetProperties()363 BASE_NS::vector<IProperty::Ptr> ProxyObject::GetProperties()
364 {
365 PopulateAllProperties();
366 return meta_->GetProperties();
367 }
368
GetProperties() const369 BASE_NS::vector<IProperty::ConstPtr> ProxyObject::GetProperties() const
370 {
371 const_cast<ProxyObject*>(this)->PopulateAllProperties();
372 return const_cast<const IMetadata*>(meta_)->GetProperties();
373 }
374
ShouldSerialise(const IProperty::Ptr & p) const375 bool ProxyObject::ShouldSerialise(const IProperty::Ptr& p) const
376 {
377 auto s = interface_cast<IStackProperty>(p);
378 return (s && !s->GetValues({}, false).empty()) ||
379 (!IsFlagSet(p, ObjectFlagBits::NATIVE) && !proxyProperties_.count(p->GetName())) ||
380 SerializeEmbeddedProxy(p);
381 }
382
UpdateSerializeState()383 void ProxyObject::UpdateSerializeState()
384 {
385 if (!updating_) {
386 bool serialise = !GetOverrides().empty();
387 if (!serialise) {
388 for (auto&& p : meta_->GetProperties()) {
389 serialise = ShouldSerialise(p);
390 if (serialise) {
391 break;
392 }
393 }
394 }
395 META_NS::SetObjectFlags(GetSelf(), ObjectFlagBits::SERIALIZE, serialise);
396 }
397 }
398
RemoveProxyProperty(const BASE_NS::string & name)399 void ProxyObject::RemoveProxyProperty(const BASE_NS::string& name)
400 {
401 meta_->RemoveProperty(GetProperty(name));
402 proxyProperties_.erase(name);
403 internalBindings_.erase(name);
404 }
RemoveAllProxyProperties()405 void ProxyObject::RemoveAllProxyProperties()
406 {
407 for (const auto& p : meta_->GetProperties()) {
408 RemoveProxyProperty(p->GetName());
409 }
410 }
AddInternalProxy(BASE_NS::string_view propertyPropertyName,BASE_NS::string_view sourcePropertyName)411 void ProxyObject::AddInternalProxy(BASE_NS::string_view propertyPropertyName, BASE_NS::string_view sourcePropertyName)
412 {
413 auto internalSourceProperty = GetProperty(sourcePropertyName);
414 if (!internalSourceProperty) {
415 return;
416 }
417 if (internalBindings_.contains(propertyPropertyName)) {
418 if (internalBindings_[propertyPropertyName] == sourcePropertyName) {
419 return;
420 }
421 internalBindings_.erase(propertyPropertyName);
422 }
423 internalBindings_.insert({ BASE_NS::string(propertyPropertyName), BASE_NS::string(sourcePropertyName) });
424 if (proxyProperties_.contains(propertyPropertyName)) {
425 proxyProperties_.erase(propertyPropertyName);
426 }
427 auto bindProperty = meta_->GetProperty(propertyPropertyName);
428 if (!bindProperty) {
429 return;
430 }
431 proxyProperties_.insert({ propertyPropertyName, DefaultValueBind(bindProperty, internalSourceProperty) });
432 }
433 } // namespace Internal
434
435 META_END_NAMESPACE()
436