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