/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "importer.h"
#include
#include
#include
#include "ser_nodes.h"
META_BEGIN_NAMESPACE()
namespace Serialization {
static bool IsBuiltinAny(const ObjectId& oid)
{
static constexpr BASE_NS::Uid uid = MakeUidImpl(0, BUILTIN_ANY_TAG);
return oid.ToUid().data[1] == uid.data[1];
}
static bool IsBuiltinArrayAny(const ObjectId& oid)
{
static constexpr BASE_NS::Uid uid = MakeUidImpl(0, BUILTIN_ARRAY_ANY_TAG);
return oid.ToUid().data[1] == uid.data[1];
}
InstanceId Importer::ConvertInstanceId(const InstanceId& id) const
{
auto it = mapInstanceIds_.find(id);
return it != mapInstanceIds_.end() ? it->second : id;
}
bool Importer::IsRegisteredObjectType(const ObjectId& oid) const
{
return registry_.GetObjectFactory(oid) != nullptr;
}
IObject::Ptr Importer::Import(const ISerNode::ConstPtr& tree)
{
IObject::Ptr object;
if (auto root = interface_cast(tree)) {
importVersion_ = root->GetSerializerVersion();
object = ImportObject(root->GetObject());
if (object) {
// resolve deferred ref uris
for (auto&& d : deferred_) {
if (auto obj = interface_pointer_cast(ImportRef(d.uri))) {
d.target->SetValue(obj);
} else {
CORE_LOG_W("Failed to resolve deferred ref uri");
}
}
// execute finalizes
for (auto&& f : finalizes_) {
if (!f->Finalize(*this)) {
CORE_LOG_W("Failed to finalize imported object");
}
}
}
} else {
CORE_LOG_W("Invalid serialisation tree, expected root node");
}
return object;
}
IObject::Ptr Importer::GetReferencedObject(const InstanceId& uid) const
{
// first check for globals
if (auto obj = globalData_.GetGlobalObject(uid)) {
return obj;
}
// then see the object registry.
return registry_.GetObjectInstanceByInstanceId(ConvertInstanceId(uid));
}
IObject::Ptr Importer::ImportRef(const RefUri& ref)
{
if (ref.BaseObjectUid() == BASE_NS::Uid {}) {
// for now we only support anchored references, relative references requires to know the current object
CORE_LOG_W("Missing base object for ref uri [%s]", ref.ToString().c_str());
return nullptr;
}
if (auto obj = interface_pointer_cast(GetReferencedObject(ref.BaseObjectUid()))) {
auto uri = ref.RelativeUri();
// interpret all uris as absolute, pointing to the exact thing they say
uri.SetAbsoluteInterpretation(true);
if (auto ret = obj->Resolve(uri)) {
return ret;
}
}
CORE_LOG_W("Failed to find object for ref uri [%s]", ref.ToString().c_str());
return nullptr;
}
IObject::Ptr Importer::ImportObject(const IObjectNode::ConstPtr& node, IObject::Ptr object)
{
IObject::Ptr result;
if (object) {
if (auto instance = interface_cast(object)) {
if (auto iid = node->GetInstanceId(); iid.IsValid()) {
CORE_LOG_D("importing object [%s] -> [%s]", iid.ToString().c_str(),
instance->GetInstanceId().ToString().c_str());
mapInstanceIds_[iid] = instance->GetInstanceId();
}
}
if (auto ser = interface_cast(object)) {
ImportContext context(*this, object, interface_pointer_cast(node->GetMembers()));
if (ser->Import(context)) {
result = object;
} else {
CORE_LOG_W("Failed to import object [type=%s]", node->GetObjectId().ToString().c_str());
}
} else if (AutoImportObject(node->GetMembers(), object)) {
result = object;
}
}
if (auto fin = interface_pointer_cast(result)) {
finalizes_.push_back(fin);
}
return result;
}
IObject::Ptr Importer::ImportObject(const ISerNode::ConstPtr& n)
{
IObject::Ptr result;
if (auto node = interface_cast(n)) {
result = ImportRef(node->GetValue());
}
if (auto node = interface_pointer_cast(n)) {
if (!node->GetObjectId().IsValid()) {
return nullptr;
}
IObject::Ptr object;
if (IsRegisteredObjectType(node->GetObjectId())) {
object = registry_.Create(node->GetObjectId());
} else {
// check if it is property?
auto name = node->GetObjectName();
if (!name.empty()) {
object =
interface_pointer_cast(registry_.GetPropertyRegister().Create(node->GetObjectId(), name));
}
}
if (object) {
result = ImportObject(node, object);
} else {
CORE_LOG_W("Failed to create requested object type [%s]", node->GetObjectId().ToString().c_str());
}
}
return result;
}
ReturnError Importer::AutoImportObject(const ISerNode::ConstPtr& node, IObject::Ptr object)
{
if (auto members = interface_cast(node)) {
return AutoImportObject(*members, object);
}
return GenericError::SUCCESS;
}
ReturnError Importer::AutoImportObject(const IMapNode& members, IObject::Ptr object)
{
if (auto flags = interface_cast(object)) {
if (auto fn = members.FindNode("__flags")) {
ImportIObjectFlags(fn, *flags);
}
}
if (auto meta = interface_cast(object)) {
ImportIMetadata(members, object, *meta);
}
if (auto attach = interface_cast(object)) {
if (auto fn = members.FindNode("__attachments")) {
ImportIAttach(fn, object, *attach);
}
}
if (auto cont = interface_cast(object)) {
if (auto fn = members.FindNode("__children")) {
ImportIContainer(fn, *cont);
}
}
return GenericError::SUCCESS;
}
ReturnError Importer::ImportIObjectFlags(const ISerNode::ConstPtr& node, IObjectFlags& flags)
{
Any any;
if (ImportValue(node, any)) {
uint64_t v {};
if (any.GetValue(v)) {
flags.SetObjectFlags(v);
return GenericError::SUCCESS;
}
}
return GenericError::FAIL;
}
ReturnError Importer::ImportIMetadata(const IMapNode& members, const IObject::Ptr& owner, IMetadata& data)
{
if (auto fn = members.FindNode("__properties")) {
if (auto cont = data.GetPropertyContainer()) {
if (auto array = interface_cast(fn)) {
for (auto&& m : array->GetMembers()) {
IObject::Ptr mobj;
if (auto onode = interface_pointer_cast(m)) {
mobj = interface_pointer_cast(data.GetPropertyByName(onode->GetObjectName()));
if (mobj) {
mobj = ImportObject(onode, mobj);
}
}
if (!mobj) {
mobj = ImportObject(m);
if (auto p = interface_pointer_cast(mobj)) {
data.AddProperty(p);
}
}
}
}
}
}
return GenericError::SUCCESS;
}
ReturnError Importer::ImportIAttach(const ISerNode::ConstPtr& node, const IObject::Ptr& owner, IAttach& cont)
{
if (auto array = interface_cast(node)) {
auto attachments = cont.GetAttachmentContainer();
for (auto&& m : array->GetMembers()) {
if (auto att = ImportObject(m)) {
if (attachments) {
cont.Detach(attachments->FindByName(att->GetName()));
}
if (auto attachment = interface_pointer_cast(att)) {
auto context = attachment->DataContext()->GetValue().lock();
if (!context) {
context = owner;
}
// Re-attach
cont.Attach(attachment, context);
}
}
}
}
return GenericError::SUCCESS;
}
ReturnError Importer::ImportIContainer(const ISerNode::ConstPtr& node, IContainer& cont)
{
if (auto array = interface_cast(node)) {
cont.RemoveAll();
for (auto&& m : array->GetMembers()) {
if (auto object = ImportObject(m)) {
cont.Insert(-1, object);
}
}
}
return GenericError::SUCCESS;
}
template
static ReturnError ImportSingleBuiltinValue(TypeList, const ISerNode::ConstPtr& n, IAny& value)
{
AnyReturnValue res = AnyReturn::FAIL;
[[maybe_unused]] bool r =
((Builtins::ID == value.GetTypeId() ? (res = Builtins::ExtractValue(n, value), true) : false) || ...);
return res ? GenericError::SUCCESS : GenericError::FAIL;
}
ReturnError Importer::ImportArray(const ISerNode::ConstPtr& n, IArrayAny& array)
{
if (auto node = interface_cast(n)) {
array.RemoveAll();
for (auto&& m : node->GetMembers()) {
if (auto any = array.Clone(AnyCloneOptions { CloneValueType::DEFAULT_VALUE, TypeIdRole::ITEM })) {
if (!ImportValue(m, *any) || !array.InsertAnyAt(-1, *any)) {
return GenericError::FAIL;
}
} else {
return GenericError::FAIL;
}
}
return GenericError::SUCCESS;
}
return GenericError::FAIL;
}
ReturnError Importer::ImportBuiltinValue(const ISerNode::ConstPtr& n, IAny& entity)
{
if (auto arr = interface_cast(&entity)) {
return ImportArray(n, *arr);
}
if (entity.GetTypeId() == UidFromType()) {
// handle as double
Any d;
auto ret = ImportSingleBuiltinValue(SupportedBuiltins {}, n, d);
if (ret) {
entity.SetValue(static_cast(d.InternalGetValue()));
}
return ret;
}
return ImportSingleBuiltinValue(SupportedBuiltins {}, n, entity);
}
ReturnError Importer::ImportPointer(const ISerNode::ConstPtr& n, IAny& entity)
{
if (auto nil = interface_cast(n)) {
entity.SetValue(SharedPtrIInterface {});
return GenericError::SUCCESS;
}
if (auto intf = GetPointer(entity)) {
if (auto node = interface_pointer_cast(n)) {
if (auto object = interface_pointer_cast(intf)) {
if (ImportObject(node, object)) {
return GenericError::SUCCESS;
}
} else if (auto any = interface_pointer_cast(intf)) {
return ImportAny(node, any);
}
}
} else {
if (auto node = interface_pointer_cast(n);
(node && IsRegisteredObjectType(node->GetObjectId())) || interface_cast>(n)) {
if (auto obj = ImportObject(n)) {
if (entity.SetValue(interface_pointer_cast(obj))) {
return GenericError::SUCCESS;
}
}
} else if (auto any = ImportAny(n)) {
if (entity.SetValue(interface_pointer_cast(any))) {
return GenericError::SUCCESS;
}
}
}
return GenericError::FAIL;
}
ReturnError Importer::ImportValue(const ISerNode::ConstPtr& n, IAny& entity)
{
if (auto imp = globalData_.GetValueSerializer(entity.GetTypeId())) {
if (auto any = imp->Import(*this, n)) {
if (entity.CopyFrom(*any)) {
return GenericError::SUCCESS;
}
} else {
CORE_LOG_W("Value import registered for type [%s] but it failed", entity.GetTypeId().ToString().c_str());
}
}
if (ImportBuiltinValue(n, entity)) {
return GenericError::SUCCESS;
}
if (IsGetCompatibleWith(entity)) {
return ImportPointer(n, entity);
}
CORE_LOG_F("Failed to import type [%s]", entity.GetTypeId().ToString().c_str());
return GenericError::FAIL;
}
ReturnError Importer::ImportWeakPtrInAny(const ISerNode::ConstPtr& node, const IAny::Ptr& any)
{
if (auto nil = interface_cast(node)) {
any->SetValue(SharedPtrIInterface {});
return GenericError::SUCCESS;
}
if (auto n = interface_cast(node)) {
// defer resolving the ref uri, might point to object that has not been imported yet.
deferred_.push_back(DeferredUriResolve { any, n->GetValue() });
return GenericError::SUCCESS;
}
CORE_LOG_F("Cannot import something else than ref uri to weak ptr");
return GenericError::FAIL;
}
ReturnError Importer::ImportAny(const IObjectNode::ConstPtr& node, const IAny::Ptr& any)
{
if (auto ser = interface_cast(any)) {
ImportContext context(
*this, interface_pointer_cast(any), interface_pointer_cast(node->GetMembers()));
if (ser->Import(context)) {
return GenericError::SUCCESS;
}
CORE_LOG_W("Failed to import object [type=%s]", node->GetObjectId().ToString().c_str());
} else {
if (auto members = interface_cast(node->GetMembers())) {
if (auto value = members->FindNode("value")) {
if (IsGetCompatibleWith(*any)) {
if (ImportWeakPtrInAny(value, any)) {
return GenericError::SUCCESS;
}
} else if (ImportValue(value, *any)) {
return GenericError::SUCCESS;
}
}
}
}
CORE_LOG_F("Failed to import any [%s]", any->GetClassId().ToString().c_str());
return GenericError::FAIL;
}
IAny::Ptr Importer::ImportAny(const ISerNode::ConstPtr& n)
{
IAny::Ptr any;
if (auto node = interface_pointer_cast(n)) {
if (!node->GetObjectId().IsValid()) {
return nullptr;
}
any = registry_.GetPropertyRegister().ConstructAny(node->GetObjectId());
if (any) {
if (!ImportAny(node, any)) {
any.reset();
}
} else {
CORE_LOG_F("No such any-type registered [%s, classname=%s]", node->GetObjectId().ToString().c_str(),
node->GetObjectClassName().c_str());
}
}
return any;
}
IObject::Ptr Importer::ResolveRefUri(const RefUri& uri)
{
return ImportRef(uri);
}
ReturnError Importer::ImportFromNode(const ISerNode::ConstPtr& node, IAny& entity)
{
return ImportValue(node, entity);
}
bool ImportContext::HasMember(BASE_NS::string_view name) const
{
return node_ && node_->FindNode(name);
}
ReturnError ImportContext::Import(BASE_NS::string_view name, IAny& entity)
{
if (node_) {
if (auto n = node_->FindNode(name)) {
return importer_.ImportValue(n, entity);
}
}
CORE_LOG_W("Failed to import member with name '%s'", BASE_NS::string(name).c_str());
return GenericError::FAIL;
}
ReturnError ImportContext::ImportAny(BASE_NS::string_view name, IAny::Ptr& any)
{
if (node_) {
if (auto n = node_->FindNode(name)) {
any = importer_.ImportAny(n);
return GenericError::SUCCESS;
}
}
CORE_LOG_W("Failed to import member with name '%s'", BASE_NS::string(name).c_str());
return GenericError::FAIL;
}
ReturnError ImportContext::ImportWeakPtr(BASE_NS::string_view name, IObject::WeakPtr& ptr)
{
if (node_) {
if (auto n = node_->FindNode(name)) {
if (auto node = interface_cast(n)) {
ptr = importer_.ImportRef(node->GetValue());
return GenericError::SUCCESS;
}
CORE_LOG_W("Failed to import weak ptr from non ref uri node");
}
}
CORE_LOG_W("Failed to import member with name '%s'", BASE_NS::string(name).c_str());
return GenericError::FAIL;
}
ReturnError ImportContext::AutoImport()
{
if (!object_) {
CORE_LOG_W("Failed to auto import, imported type is not IObject");
return GenericError::FAIL;
}
if (node_) {
return importer_.AutoImportObject(*node_, object_);
}
CORE_LOG_W("Failed to auto import, invalid node");
return GenericError::FAIL;
}
IObject::Ptr ImportContext::ResolveRefUri(const RefUri& uri)
{
return importer_.ImportRef(uri);
}
ReturnError ImportContext::ImportFromNode(const ISerNode::ConstPtr& node, IAny& entity)
{
return importer_.ImportFromNode(node, entity);
}
} // namespace Serialization
META_END_NAMESPACE()