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