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 #include "exporter.h"
16 
17 #include <meta/api/util.h>
18 #include <meta/interface/intf_attach.h>
19 #include <meta/interface/intf_object_context.h>
20 #include <meta/interface/serialization/intf_serializable.h>
21 
22 #include "ser_nodes.h"
23 
24 META_BEGIN_NAMESPACE()
25 namespace Serialization {
26 
ShouldSerialize(const IObject::ConstPtr & object) const27 bool Exporter::ShouldSerialize(const IObject::ConstPtr& object) const
28 {
29     return IsFlagSet(object, ObjectFlagBits::SERIALIZE);
30 }
ShouldSerialize(const IAny & any) const31 bool Exporter::ShouldSerialize(const IAny& any) const
32 {
33     SharedPtrConstIInterface p;
34     if (any.GetValue(p)) {
35         if (auto flags = interface_cast<IObjectFlags>(p)) {
36             return flags->GetObjectFlags().IsSet(ObjectFlagBits::SERIALIZE);
37         }
38     }
39     return true;
40 }
41 
ConvertInstanceId(const InstanceId & id) const42 InstanceId Exporter::ConvertInstanceId(const InstanceId& id) const
43 {
44     auto it = mapInstanceIds_.find(id);
45     return it != mapInstanceIds_.end() ? it->second : id;
46 }
47 
MarkExported(const IObject::ConstPtr & object)48 bool Exporter::MarkExported(const IObject::ConstPtr& object)
49 {
50     bool res = false;
51     if (auto i = interface_cast<IObjectInstance>(object)) {
52         auto id = i->GetInstanceId();
53         auto it = exported_.find(id);
54         res = it != exported_.end();
55         if (!res) {
56             exported_[id] = object;
57         }
58     }
59     return res;
60 }
61 
HasBeenExported(const InstanceId & id) const62 bool Exporter::HasBeenExported(const InstanceId& id) const
63 {
64     return exported_.find(id) != exported_.end();
65 }
66 
Export(const IObject::ConstPtr & object)67 ISerNode::Ptr Exporter::Export(const IObject::ConstPtr& object)
68 {
69     BASE_NS::shared_ptr<RootNode> res;
70     if (object) {
71         ISerNode::Ptr node;
72         auto r = ExportObject(object, node);
73         if (r) {
74             res.reset(new RootNode { EXPORTER_VERSION, BASE_NS::move(node) });
75         }
76     }
77     return res;
78 }
79 
CreateObjectNode(const IObject::ConstPtr & object,BASE_NS::shared_ptr<MapNode> node)80 ISerNode::Ptr Exporter::CreateObjectNode(const IObject::ConstPtr& object, BASE_NS::shared_ptr<MapNode> node)
81 {
82     ISerNode::Ptr res;
83     InstanceId iid;
84     if (auto i = interface_cast<IObjectInstance>(object)) {
85         iid = ConvertInstanceId(i->GetInstanceId());
86     }
87     return ISerNode::Ptr(new ObjectNode(BASE_NS::string(object->GetClassName()), BASE_NS::string(object->GetName()),
88         object->GetClassId(), iid, BASE_NS::move(node)));
89 }
90 
CreateObjectRefNode(const RefUri & ref)91 ISerNode::Ptr Exporter::CreateObjectRefNode(const RefUri& ref)
92 {
93     RefUri uri(ref);
94     uri.SetBaseObjectUid(ConvertInstanceId(uri.BaseObjectUid()).ToUid());
95     return ISerNode::Ptr(new RefNode { uri });
96 }
97 
CreateObjectRefNode(const IObject::ConstPtr & object)98 ISerNode::Ptr Exporter::CreateObjectRefNode(const IObject::ConstPtr& object)
99 {
100     ISerNode::Ptr res;
101     if (auto i = interface_cast<IObjectInstance>(object)) {
102         RefUri ref(i->GetInstanceId().ToUid());
103         res = CreateObjectRefNode(ref);
104     }
105     return res;
106 }
107 
ExportObject(const IObject::ConstPtr & object,ISerNode::Ptr & res)108 ReturnError Exporter::ExportObject(const IObject::ConstPtr& object, ISerNode::Ptr& res)
109 {
110     ReturnError err = GenericError::SUCCESS;
111     if (ShouldSerialize(object)) {
112         if (MarkExported(object)) {
113             res = CreateObjectRefNode(object);
114         } else if (auto ser = interface_cast<ISerializable>(object)) {
115             ExportContext context(*this, object);
116             err = ser->Export(context);
117             if (err) {
118                 res = CreateObjectNode(object, context.ExtractNode());
119             }
120         } else {
121             res = AutoExportObject(object);
122         }
123     }
124     return err;
125 }
126 
AutoExportObject(const IObject::ConstPtr & object)127 ISerNode::Ptr Exporter::AutoExportObject(const IObject::ConstPtr& object)
128 {
129     BASE_NS::vector<NamedNode> members;
130     AutoExportObjectMembers(object, members);
131     return CreateObjectNode(object, BASE_NS::shared_ptr<MapNode>(new MapNode(members)));
132 }
133 
AutoExportObjectMembers(const IObject::ConstPtr & object,BASE_NS::vector<NamedNode> & members)134 ReturnError Exporter::AutoExportObjectMembers(const IObject::ConstPtr& object, BASE_NS::vector<NamedNode>& members)
135 {
136     if (auto flags = interface_cast<IObjectFlags>(object)) {
137         if (flags->GetObjectDefaultFlags() != flags->GetObjectFlags()) {
138             ISerNode::Ptr node;
139             auto res = ExportValue(Any<uint64_t>(flags->GetObjectFlags().GetValue()), node);
140             if (res && node) {
141                 members.push_back(NamedNode { "__flags", node });
142             }
143         }
144     }
145     if (auto meta = interface_cast<IMetadata>(object)) {
146         auto res = ExportIMetadata(*meta);
147         members.insert(members.end(), res.begin(), res.end());
148     }
149     if (auto attach = interface_cast<IAttach>(object)) {
150         if (IsFlagSet(object, ObjectFlagBits::SERIALIZE_ATTACHMENTS)) {
151             if (auto cont = attach->GetAttachmentContainer()) {
152                 if (auto node = ExportIContainer(*cont)) {
153                     members.push_back(NamedNode { "__attachments", node });
154                 }
155             }
156         }
157     }
158     if (auto cont = interface_cast<IContainer>(object)) {
159         if (IsFlagSet(object, ObjectFlagBits::SERIALIZE_HIERARCHY)) {
160             if (auto node = ExportIContainer(*cont)) {
161                 members.push_back(NamedNode { "__children", node });
162             }
163         }
164     }
165     return GenericError::SUCCESS;
166 }
167 
ExportIMetadata(const IMetadata & data)168 BASE_NS::vector<NamedNode> Exporter::ExportIMetadata(const IMetadata& data)
169 {
170     // for now only properties
171     BASE_NS::vector<NamedNode> res;
172     if (auto cont = data.GetPropertyContainer()) {
173         if (cont->GetSize() > 0) {
174             if (auto node = ExportIContainer(*cont)) {
175                 res.push_back(NamedNode { "__properties", BASE_NS::move(node) });
176             }
177         }
178     }
179     return res;
180 }
181 
ExportIContainer(const IContainer & cont)182 ISerNode::Ptr Exporter::ExportIContainer(const IContainer& cont)
183 {
184     BASE_NS::vector<ISerNode::Ptr> elements;
185     for (size_t i = 0; i != cont.GetSize(); ++i) {
186         ISerNode::Ptr node;
187         if (ExportObject(cont.GetAt(i), node) && node) {
188             elements.push_back(BASE_NS::move(node));
189         }
190     }
191     return ISerNode::Ptr(new ArrayNode(BASE_NS::move(elements)));
192 }
193 
194 template<typename... Builtins>
ExportSingleBuiltinValue(TypeList<Builtins...>,const IAny & value)195 static ISerNode::Ptr ExportSingleBuiltinValue(TypeList<Builtins...>, const IAny& value)
196 {
197     ISerNode::Ptr res;
198     [[maybe_unused]] bool r =
199         ((Builtins::ID == value.GetTypeId() ? (res = Builtins::CreateNode(value), true) : false) || ...);
200     return res;
201 }
202 
ExportArray(const IArrayAny & array)203 ISerNode::Ptr Exporter::ExportArray(const IArrayAny& array)
204 {
205     ISerNode::Ptr res;
206     auto any = array.Clone(AnyCloneOptions { CloneValueType::DEFAULT_VALUE, TypeIdRole::ITEM });
207     if (any) {
208         BASE_NS::vector<ISerNode::Ptr> elements;
209         for (size_t i = 0; i != array.GetSize(); ++i) {
210             if (!array.GetAnyAt(i, *any)) {
211                 return nullptr;
212             }
213             ISerNode::Ptr node;
214             if (ExportValue(*any, node) && node) {
215                 elements.push_back(BASE_NS::move(node));
216             }
217         }
218         res.reset(new ArrayNode(BASE_NS::move(elements)));
219     }
220     return res;
221 }
222 
ExportBuiltinValue(const IAny & value)223 ISerNode::Ptr Exporter::ExportBuiltinValue(const IAny& value)
224 {
225     ISerNode::Ptr res;
226     if (auto arr = interface_cast<IArrayAny>(&value)) {
227         res = ExportArray(*arr);
228     } else {
229         if (value.GetTypeId() == UidFromType<float>()) {
230             // handle as double
231             res = ExportSingleBuiltinValue(SupportedBuiltins {}, Any<double>(GetValue<float>(value)));
232         } else {
233             res = ExportSingleBuiltinValue(SupportedBuiltins {}, value);
234         }
235     }
236     return res;
237 }
238 
ExportPointer(const IAny & entity,ISerNode::Ptr & res)239 ReturnError Exporter::ExportPointer(const IAny& entity, ISerNode::Ptr& res)
240 {
241     // first see if it is a weak pointer
242     BASE_NS::weak_ptr<const CORE_NS::IInterface> weak;
243     bool isWeak = entity.GetValue(weak);
244     if (isWeak) {
245         if (auto obj = interface_pointer_cast<IObject>(weak)) {
246             return ExportWeakPtr(obj, res);
247         }
248     }
249 
250     BASE_NS::shared_ptr<const CORE_NS::IInterface> intf;
251     if (entity.GetValue(intf)) {
252         // see if it is null pointer
253         if (!intf) {
254             res = ISerNode::Ptr(new NilNode);
255             return GenericError::SUCCESS;
256         }
257         // finally handle normal pointer case
258         if (!isWeak) {
259             if (auto obj = interface_pointer_cast<IObject>(intf)) {
260                 return ExportObject(obj, res);
261             }
262             if (auto any = interface_pointer_cast<IAny>(intf)) {
263                 return ExportAny(any, res);
264             }
265         }
266     }
267     return GenericError::FAIL;
268 }
269 
ExportValue(const IAny & entity,ISerNode::Ptr & res)270 ReturnError Exporter::ExportValue(const IAny& entity, ISerNode::Ptr& res)
271 {
272     if (!ShouldSerialize(entity)) {
273         return GenericError::SUCCESS;
274     }
275     if (auto exp = globalData_.GetValueSerializer(entity.GetTypeId())) {
276         res = exp->Export(*this, entity);
277         if (res) {
278             return GenericError::SUCCESS;
279         }
280         CORE_LOG_W("Value export registered for type [%s, %s] but it failed", entity.GetTypeIdString().c_str(),
281             entity.GetTypeId().ToString().c_str());
282     }
283     res = ExportBuiltinValue(entity);
284     if (!res) {
285         ExportPointer(entity, res);
286     }
287     if (!res) {
288         CORE_LOG_F(
289             "Failed to export type [%s, %s]", entity.GetTypeIdString().c_str(), entity.GetTypeId().ToString().c_str());
290         return GenericError::FAIL;
291     }
292     return GenericError::SUCCESS;
293 }
294 
ExportAny(const IAny::ConstPtr & any,ISerNode::Ptr & res)295 ReturnError Exporter::ExportAny(const IAny::ConstPtr& any, ISerNode::Ptr& res)
296 {
297     ReturnError err = GenericError::SUCCESS;
298     if (!registry_.GetPropertyRegister().IsAnyRegistered(any->GetClassId())) {
299         CORE_LOG_W("Exporting any that is not registered [class id=%s, type=%s, type id=%s]",
300             any->GetClassId().ToString().c_str(), any->GetTypeIdString().c_str(), any->GetTypeId().ToString().c_str());
301     }
302     if (!any) {
303         res = ISerNode::Ptr(new NilNode);
304     } else if (auto ser = interface_cast<ISerializable>(any)) {
305         ExportContext context(*this, interface_pointer_cast<IObject>(any));
306         err = ser->Export(context);
307         if (err) {
308             res =
309                 ISerNode::Ptr(new ObjectNode(BASE_NS::string("Any"), {}, any->GetClassId(), {}, context.ExtractNode()));
310         }
311     } else {
312         ISerNode::Ptr node;
313         err = ExportValue(*any, node);
314         if (err && node) {
315             auto members = CreateShared<MapNode>(BASE_NS::vector<NamedNode> { NamedNode { "value", node } });
316             res = ISerNode::Ptr(
317                 new ObjectNode(BASE_NS::string("Any"), {}, any->GetClassId(), {}, BASE_NS::move(members)));
318         }
319     }
320     return err;
321 }
322 
ResolveUriSegment(const IObject::ConstPtr & ptr,RefUri & uri) const323 IObject::Ptr Exporter::ResolveUriSegment(const IObject::ConstPtr& ptr, RefUri& uri) const
324 {
325     if (auto instance = interface_cast<IObjectInstance>(ptr)) {
326         if (auto context = interface_cast<IObjectContext>(ptr)) {
327             uri.PushObjectContextSegment();
328         } else {
329             uri.PushObjectSegment(instance->GetName());
330         }
331         return ptr->Resolve(RefUri::ParentUri());
332     }
333     if (auto property = interface_cast<IProperty>(ptr)) {
334         uri.PushPropertySegment(property->GetName());
335         auto owner = property->GetOwner().lock();
336         if (!owner) {
337             CORE_LOG_E("No Owner for property '%s' when exporting weak ptr", property->GetName().c_str());
338         }
339         return owner;
340     }
341     return nullptr;
342 }
343 
ExportWeakPtr(const IObject::ConstWeakPtr & ptr,ISerNode::Ptr & res)344 ReturnError Exporter::ExportWeakPtr(const IObject::ConstWeakPtr& ptr, ISerNode::Ptr& res)
345 {
346     if (auto p = ptr.lock()) {
347         auto original = p;
348         RefUri uri;
349         while (p) {
350             if (auto obj = interface_cast<IObjectInstance>(p)) {
351                 auto iid = ConvertInstanceId(obj->GetInstanceId());
352                 if (HasBeenExported(iid) || globalData_.GetGlobalObject(obj->GetInstanceId())) {
353                     uri.SetBaseObjectUid(iid.ToUid());
354                     res = ISerNode::Ptr(new RefNode(uri));
355                     return GenericError::SUCCESS;
356                 }
357             }
358             p = ResolveUriSegment(p, uri);
359         }
360         CORE_LOG_E("Could not find suitable anchor object when exporting weak ptr [%s, %s, %s]",
361             BASE_NS::string(original->GetClassName()).c_str(), original->GetName().c_str(),
362             original->GetClassId().ToString().c_str());
363         return GenericError::FAIL;
364     }
365     res = ISerNode::Ptr(new NilNode);
366     return GenericError::SUCCESS;
367 }
368 
ExportToNode(const IAny & entity,ISerNode::Ptr & res)369 ReturnError Exporter::ExportToNode(const IAny& entity, ISerNode::Ptr& res)
370 {
371     return ExportValue(entity, res);
372 }
373 
Export(BASE_NS::string_view name,const IAny & entity)374 ReturnError ExportContext::Export(BASE_NS::string_view name, const IAny& entity)
375 {
376     ISerNode::Ptr node;
377     auto res = exporter_.ExportValue(entity, node);
378     if (res && node) {
379         elements_.push_back(NamedNode { BASE_NS::string(name), BASE_NS::move(node) });
380     }
381     if (!res) {
382         CORE_LOG_W("Failed to export member with name '%s'", BASE_NS::string(name).c_str());
383     }
384     return res;
385 }
386 
ExportAny(BASE_NS::string_view name,const IAny::Ptr & any)387 ReturnError ExportContext::ExportAny(BASE_NS::string_view name, const IAny::Ptr& any)
388 {
389     ISerNode::Ptr node;
390     auto res = exporter_.ExportAny(any, node);
391     if (res && node) {
392         elements_.push_back(NamedNode { BASE_NS::string(name), BASE_NS::move(node) });
393     }
394     if (!res) {
395         CORE_LOG_W("Failed to export member with name '%s'", BASE_NS::string(name).c_str());
396     }
397     return res;
398 }
399 
ExportWeakPtr(BASE_NS::string_view name,const IObject::ConstWeakPtr & ptr)400 ReturnError ExportContext::ExportWeakPtr(BASE_NS::string_view name, const IObject::ConstWeakPtr& ptr)
401 {
402     ISerNode::Ptr node;
403     auto res = exporter_.ExportWeakPtr(ptr, node);
404     if (res && node) {
405         elements_.push_back(NamedNode { BASE_NS::string(name), BASE_NS::move(node) });
406     }
407     if (!res) {
408         CORE_LOG_W("Failed to export member with name '%s'", BASE_NS::string(name).c_str());
409     }
410     return res;
411 }
412 
AutoExport()413 ReturnError ExportContext::AutoExport()
414 {
415     if (object_) {
416         BASE_NS::vector<NamedNode> vec;
417         auto res = exporter_.AutoExportObjectMembers(object_, vec);
418         if (res) {
419             elements_.insert(elements_.end(), vec.begin(), vec.end());
420         }
421         return res;
422     }
423     CORE_LOG_W("Failed to auto export, exported type is not IObject");
424     return GenericError::FAIL;
425 }
426 
ExtractNode()427 BASE_NS::shared_ptr<MapNode> ExportContext::ExtractNode()
428 {
429     return BASE_NS::shared_ptr<MapNode>(new MapNode { BASE_NS::move(elements_) });
430 }
431 
ExportToNode(const IAny & entity,ISerNode::Ptr & res)432 ReturnError ExportContext::ExportToNode(const IAny& entity, ISerNode::Ptr& res)
433 {
434     return exporter_.ExportToNode(entity, res);
435 }
436 
437 } // namespace Serialization
438 META_END_NAMESPACE()
439