• 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         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