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 "object.h"
16 
17 #include <algorithm>
18 #include <limits>
19 
20 #include <base/util/uid_util.h>
21 #include <core/plugin/intf_class_factory.h>
22 
23 #include <meta/api/iteration.h>
24 #include <meta/interface/builtin_objects.h>
25 #include <meta/interface/intf_object_registry.h>
26 #include <meta/interface/intf_proxy_object.h>
27 #include <meta/interface/intf_required_interfaces.h>
28 #include <meta/interface/property/intf_property_internal.h>
29 
30 #include "ref_uri_util.h"
31 
32 META_BEGIN_NAMESPACE()
33 namespace Internal {
34 
35 // ILifecycle
Build(const IMetadata::Ptr & data)36 bool Object::Build(const IMetadata::Ptr& data)
37 {
38     return Super::Build(data);
39 }
40 
Destroy()41 void Object::Destroy()
42 {
43     if (attachments_) {
44         attachments_->RemoveAllAttachments();
45         attachments_.reset();
46     }
47     Super::Destroy();
48 }
49 
50 // IAttach
Attach(const IObject::Ptr & attachment,const IObject::Ptr & dataContext)51 bool Object::Attach(const IObject::Ptr& attachment, const IObject::Ptr& dataContext)
52 {
53     ValidateAttachmentContainer();
54     if (attachments_) {
55         return attachments_->Attach(attachment, dataContext);
56     }
57     return false;
58 }
59 
Detach(const IObject::Ptr & attachment)60 bool Object::Detach(const IObject::Ptr& attachment)
61 {
62     if (attachments_) {
63         return attachments_->Detach(attachment);
64     }
65     return false;
66 }
67 
GetAttachments(const BASE_NS::vector<TypeId> & uids,bool strict) const68 BASE_NS::vector<IObject::Ptr> Object::GetAttachments(const BASE_NS::vector<TypeId>& uids, bool strict) const
69 {
70     if (attachments_) {
71         return attachments_->GetAttachments(uids, strict);
72     }
73     return {};
74 }
HasAttachments() const75 bool Object::HasAttachments() const
76 {
77     if (const auto container = interface_cast<IContainer>(attachments_)) {
78         return container->GetSize() > 0;
79     }
80     return false;
81 }
GetAttachmentContainer(bool initializeAlways) const82 IContainer::Ptr Object::GetAttachmentContainer(bool initializeAlways) const
83 {
84     if (initializeAlways) {
85         ValidateAttachmentContainer();
86     }
87     return interface_pointer_cast<IContainer>(attachments_);
88 }
89 
ValidateAttachmentContainer() const90 void Object::ValidateAttachmentContainer() const
91 {
92     if (!attachments_) {
93         if (attachments_ =
94                 META_NS::GetObjectRegistry().Create<META_NS::IAttachmentContainer>(ClassId::AttachmentContainer);
95             attachments_) {
96             attachments_->Initialize(GetSelf<META_NS::IAttach>());
97         } else {
98             CORE_LOG_E("Failed to create container for attachments");
99         }
100     }
101 }
102 
CheckRequiredInterfaces(const IContainer::Ptr & container,const BASE_NS::vector<BASE_NS::Uid> & uids)103 bool CheckRequiredInterfaces(const IContainer::Ptr& container, const BASE_NS::vector<BASE_NS::Uid>& uids)
104 {
105     if (uids.empty()) {
106         return true;
107     }
108     if (auto req = interface_cast<IRequiredInterfaces>(container)) {
109         const auto reqs = req->GetRequiredInterfaces();
110         if (reqs.empty()) {
111             return true; // Container has no requirements related to the interfaces it accepts
112         }
113         size_t matches = 0;
114         for (const auto& uid : uids) {
115             if (std::find(reqs.begin(), reqs.end(), uid) != reqs.end()) {
116                 matches++;
117             }
118         }
119         return matches == uids.size();
120     }
121 
122     // If container is valid but it does not implement IRequiredInterfaces, anything goes
123     return container.operator bool();
124 }
125 
FindAllContainers(const ContainerFindOptions & options) const126 BASE_NS::vector<IContainer::Ptr> Object::FindAllContainers(const ContainerFindOptions& options) const
127 {
128     BASE_NS::vector<IContainer::Ptr> containers;
129     const auto maxCount = options.maxCount ? options.maxCount : std::numeric_limits<size_t>::max();
130     const auto& uids = options.uids;
131     const auto addIfMatches = [&containers, &uids](const IContainer::Ptr& container) {
132         if (container) {
133             if (CheckRequiredInterfaces(container, uids)) {
134                 containers.push_back(container);
135             }
136         }
137     };
138     if (const auto me = GetSelf<IContainer>()) {
139         // This object is itself a container
140         addIfMatches(me);
141     }
142     if (containers.size() < maxCount) {
143         if (HasAttachments()) {
144             // Check the attachment container
145             addIfMatches(interface_pointer_cast<IContainer>(attachments_));
146             // Check the attachments themselves
147             if (containers.size() < maxCount) {
148                 IterateShared(attachments_, [&addIfMatches, &containers, &maxCount](const IObject::Ptr& object) {
149                     addIfMatches(interface_pointer_cast<IContainer>(object));
150                     return containers.size() < maxCount;
151                 });
152             }
153         } else {
154             // No attachments, but the user has requested IAttachment so we need to create the container
155             if (uids.empty() || std::find(uids.begin(), uids.end(), IAttachment::UID) != uids.end()) {
156                 ValidateAttachmentContainer();
157                 addIfMatches(interface_pointer_cast<IContainer>(attachments_));
158             }
159         }
160     }
161     return containers;
162 }
163 
GetStaticMetadata() const164 const StaticObjectMetadata& Object::GetStaticMetadata() const
165 {
166     return GetStaticObjectMetadata();
167 }
168 
169 } // namespace Internal
170 
171 META_END_NAMESPACE()
172