• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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