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 #ifndef META_EXT_BEHAVIOR_H
17 #define META_EXT_BEHAVIOR_H
18
19 #include <meta/ext/attachment/attachment.h>
20 #include <meta/interface/intf_startable.h>
21
META_BEGIN_NAMESPACE()22 META_BEGIN_NAMESPACE()
23
24 namespace Internal {
25
26 /**
27 * @brief The Behavior class is an helper class which takes care of common steps needed
28 * to implement the IStartable interface.
29 *
30 * Startable objects (i.e. attachments which implement IStartable) are commonly referred to as behaviors. The
31 * runtime environment is usually implemented in such a way that the framework starts and stops any beheviors
32 * automatically as they become part of the hierarchy.
33 */
34 class BehaviorBase : public IntroduceInterfaces<AttachmentFwd, IStartable> {
35 META_OBJECT_NO_CLASSINFO(BehaviorBase, IntroduceInterfaces)
36
37 META_BEGIN_STATIC_DATA()
38 META_STATIC_PROPERTY_DATA(
39 META_NS::IStartable, META_NS::StartBehavior, StartableMode, META_NS::StartBehavior::AUTOMATIC)
40 META_STATIC_PROPERTY_DATA(META_NS::IStartable, META_NS::StartableState, StartableState,
41 META_NS::StartableState::DETACHED, DEFAULT_PROPERTY_FLAGS_NO_SER)
42 META_END_STATIC_DATA()
43
44 META_IMPLEMENT_PROPERTY(META_NS::StartBehavior, StartableMode)
45 META_IMPLEMENT_READONLY_PROPERTY(META_NS::StartableState, StartableState)
46 protected:
47 /**
48 * @brief Returns the state of the startable.
49 */
50 META_NS::StartableState GetState() const
51 {
52 return META_ACCESS_PROPERTY_VALUE(StartableState);
53 }
54 /**
55 * @brief Called when the behavior has been attached to a target.
56 * If the behavior needs to do some initialization steps, it should override this
57 * function and do them here.
58 * @return True if the operation completed successfully, false otherwise.
59 */
60 virtual bool OnAttach()
61 {
62 return true;
63 };
64 /**
65 * @brief Called when the behavior is being detached from a target.
66 */
67 virtual void OnDetach() {};
68 /**
69 * @brief Called after the behavior has been successfully attached, and the runtime state of the framework is such
70 * that the behavior should start any processing.
71 * @note Usually it is enough to override OnStart/OnStop, OnAttach/OnDetach are not needed.
72 * @return True if start was successful, false otherwise.
73 */
74 virtual bool OnStart()
75 {
76 return true;
77 }
78 /**
79 * @brief Called when the behavior should stop any ongoing tasks.
80 */
81 virtual void OnStop() {}
82 /**
83 * @brief Returns a strong reference to the target object.
84 */
85 META_NS::IObject::Ptr GetObject() const
86 {
87 return object_.lock();
88 }
89 /**
90 * @brief Returns a strong reference to the data context object.
91 */
92 META_NS::IObject::Ptr GetContext() const
93 {
94 return context_.lock();
95 }
96 /**
97 * @brief Templated helper for GetObject, returning the target object casted to given type.
98 */
99 template<class T>
100 typename T::Ptr GetObject() const
101 {
102 return interface_pointer_cast<T>(object_);
103 }
104 /**
105 * @brief Templated helper for GetObject, returning the context object casted to given type.
106 */
107 template<class T>
108 typename T::Ptr GetContext() const
109 {
110 return interface_pointer_cast<T>(context_);
111 }
112
113 private: // META_NS::AttachmentFwd
114 /** Private implementation of AttachmentFwd::AttachTo, handle properties and call the Attach of derived
115 * implementation */
116 bool AttachTo(const META_NS::IAttach::Ptr& target, const META_NS::IObject::Ptr& dataContext) override
117 {
118 auto object = interface_pointer_cast<META_NS::IObject>(target);
119 if (!object) {
120 CORE_LOG_E("Behavior target must implement IObject interface");
121 return false;
122 }
123 object_ = object;
124 context_ = dataContext;
125 if (OnAttach()) {
126 SetValue(META_ACCESS_PROPERTY(StartableState), META_NS::StartableState::ATTACHED);
127 return true;
128 }
129 // Attach failed
130 object_.reset();
131 context_.reset();
132 return false;
133 }
134 /** Private implementation of AttachmentFwd::DetachFrom, handle properties and call the Detach method of derived
135 * implementation. */
136 bool DetachFrom(const META_NS::IAttach::Ptr& /*target*/) override
137 {
138 OnDetach();
139 SetValue(META_ACCESS_PROPERTY(StartableState), META_NS::StartableState::DETACHED);
140 object_.reset();
141 context_.reset();
142 return true;
143 }
144
145 bool Start() override final
146 {
147 const auto state = META_ACCESS_PROPERTY_VALUE(StartableState);
148 switch (state) {
149 case StartableState::DETACHED: {
150 CORE_LOG_E("Tried to start a detached behavior");
151 break;
152 }
153 case StartableState::ATTACHED: {
154 CORE_LOG_V("Calling OnStart");
155 if (OnStart()) {
156 SetValue(META_ACCESS_PROPERTY(StartableState), StartableState::STARTED);
157 return true;
158 }
159 break;
160 }
161 case StartableState::STARTED: {
162 CORE_LOG_V("Behavior already started");
163 return true;
164 }
165 }
166 return false;
167 }
168 bool Stop() override
169 {
170 const auto state = META_ACCESS_PROPERTY_VALUE(StartableState);
171 if (state == StartableState::STARTED) {
172 OnStop();
173 SetValue(META_ACCESS_PROPERTY(StartableState), StartableState::ATTACHED);
174 return true;
175 }
176 return false;
177 }
178
179 private:
180 META_NS::IObject::WeakPtr object_;
181 META_NS::IObject::WeakPtr context_;
182 };
183
184 } // namespace Internal
185
186 /**
187 * @brief The Behavior class is a helper class for implementing custom behaviors.
188 *
189 * @code
190 * META_REGISTER_CLASS(
191 * MyBehavior, "...", META_NS::ObjectCategoryBits::NO_CATEGORY, "My behavior")
192 *
193 * class MyCustomBehavior : public META_NS::Behavior<IMyCustonInterface> {
194 * META_OBJECT(MyCustomBehavior, ClassId::MyBehavior, Behavior)
195 * ...
196 * };
197 * @endcode
198 */
199 template<class... Interfaces>
200 class Behavior : public IntroduceInterfaces<Internal::BehaviorBase, Interfaces...> {};
201
202 META_END_NAMESPACE()
203
204 #endif // META_EXT_BEHAVIOR_H
205