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