RTC Toolkit  2.0.0
measurable.hpp
Go to the documentation of this file.
1 
12 #ifndef RTCTK_COMPONENTFRAMEWORK_MEASURABLE_HPP
13 #define RTCTK_COMPONENTFRAMEWORK_MEASURABLE_HPP
14 
15 #include <optional>
16 
22 
23 namespace rtctk::componentFramework {
24 namespace detail {
35 public:
42  MeasureContext(rad::cii::Request<std::string, std::string> const& request)
43  : m_request(request), m_arg() {
44  m_arg = JsonPayload::parse(m_request.GetRequestPayload());
45  }
47 
48  JsonPayload const& GetArg() const noexcept {
49  return m_arg;
50  }
51 
58  void SetResult(JsonPayload const& result) {
59  m_result = result.dump();
60  }
61 
67  void SendReply() noexcept {
68  try {
69  m_request.SetReplyValue(m_result);
70  } catch (std::exception const& exception) {
71  LOG4CPLUS_ERROR(
72  GetLogger(),
73  "MeasureContext::SendReply: Failed to send reply: " << exception.what());
74  } catch (...) {
75  LOG4CPLUS_ERROR(
76  GetLogger(),
77  "MeasureContext::SendReply: Failed to send reply with unknown exception.");
78  }
79  }
80 
84  void SendErrorReply(std::exception_ptr eptr) noexcept {
85  try {
86  m_request.SetException(
87  RequestFailed(NestedExceptionPrinter(std::move(eptr)).Str()));
88  } catch (RtctkException const& exception) {
89  LOG4CPLUS_ERROR(
90  GetLogger(),
91  "MeasureContext::SendErrorReply: Failed to send reply: " << exception.what());
92  } catch (...) {
93  LOG4CPLUS_ERROR(
94  GetLogger(),
95  "MeasureContext::SendErrorReply: Failed to send reply with unknown exception.");
96  }
97  }
98 
99 private:
100  rad::cii::Request<std::string, std::string> m_request;
104  JsonPayload m_arg;
108  std::string m_result;
109 };
110 } // namespace detail
111 
145 template <typename Super>
146 struct Measurable : Super {
147  static_assert(std::is_base_of_v<RtcComponent, Super>, "'Measurable' requires 'RtcComponent'");
148 
152  class BizLogicIf : public Super::BizLogicIf {
153  public:
166  virtual JsonPayload ActivityMeasuring(StopToken stop_token, JsonPayload const& arg) {
167  (void)stop_token;
168  return JsonPayload("42");
169  }
170 
180  virtual bool GuardMeasuringAllowed(JsonPayload const& arg) {
181  return true;
182  }
183  };
184 
185  class InputStage : public Super::InputStage {
186  public:
187  using Super::InputStage::InputStage;
188 
189  void Start() override {
190  Super::InputStage::Start();
191 
192  MeasCmdsImpl::Register(this->m_replier, this->m_engine);
193  }
194  };
195 
196  class OutputStage : public Super::OutputStage {
197  public:
199  // Handlers ###################################################################
200 
201  engine.RegisterRejectHandler<events::Measure, RequestRejected>();
202 
203  m_measure_success_handler = [this] {
204  this->m_engine.PostEvent(std::make_unique<events::MeasureDone>());
205  };
206 
207  m_measure_error_handler = [this](std::exception_ptr eptr) {
208  this->m_engine.PostEvent(std::make_unique<events::MeasureError>(eptr));
209  };
210 
211  // No Disable in states ###############################################################
212 
213  this->m_no_disable_in_states.push_back("On:Operational:MeasureBusy");
214 
215  // No Update in states ################################################################
216 
217  this->m_no_update_in_states.push_back("On:Operational:MeasureBusy");
218 
219  // No Measure in states ###############################################################
220 
221  this->m_no_measure_in_states.push_back("On:Operational:UpdateBusy");
222 
223  // Guards #####################################################################
224 
225  engine.RegisterGuardStatic<events::Measure>(
226  "GuardMeasuringAllowed", [this](events::Measure const& ev) {
235  auto act_state = this->m_engine.GetState();
236  for (auto& s : m_no_measure_in_states) {
237  if (act_state.find(s) != std::string::npos) {
238  return false;
239  }
240  }
241  detail::MeasureContext ctx(ev.GetPayload());
242  if (static_cast<BizLogicIf&>(this->m_logic)
243  .GuardMeasuringAllowed(ctx.GetArg())) {
244  // Measure is allowed so context is stored.
245  assert(!m_measure_ctx);
246  m_measure_ctx.emplace(std::move(ctx));
247  return true;
248  }
249  return false;
250  });
251 
252  // Activities #####################################################################
253  engine.RegisterActivity(
254  "ActivityMeasuring",
255  [this](StopToken stop_token) {
256  assert(m_measure_ctx);
257  JsonPayload result =
258  static_cast<BizLogicIf&>(this->m_logic)
259  .ActivityMeasuring(std::move(stop_token), m_measure_ctx->GetArg());
260  // note: SetResult may throw
261  m_measure_ctx->SetResult(result);
262  },
265 
266  // Actions #####################################################################
267  engine.RegisterAction("ActionMeasuringDone", [this](auto c) {
268  assert(m_measure_ctx);
269  m_measure_ctx->SendReply();
270  m_measure_ctx.reset();
271  });
272 
273  engine.RegisterActionStatic<events::MeasureError>(
274  "ActionMeasuringFailed", [this](events::MeasureError const& ev) {
275  assert(m_measure_ctx);
276  m_measure_ctx->SendErrorReply(ev.GetPayload());
277  m_measure_ctx.reset();
278  });
279  }
280 
281  protected:
283  std::optional<detail::MeasureContext> m_measure_ctx;
284  std::function<void()> m_measure_success_handler;
285  std::function<void(std::exception_ptr)> m_measure_error_handler;
286  std::list<std::string> m_no_measure_in_states;
287  };
288 
289  class ModelBuilder : public Super::ModelBuilder {
290  public:
292  this->RegisterLayer({"Measurable", {}});
293 
294  this->mm.AddState(Composite, "On:Operational:RegionMeasure", "On:Operational");
295  this->mm.AddState(Initial, "On:Operational:MeasureInitial", "On:Operational:RegionMeasure");
296  this->mm.AddState(Simple, "On:Operational:MeasureIdle", "On:Operational:RegionMeasure");
297  this->mm.AddState(Simple, "On:Operational:MeasureBusy", "On:Operational:RegionMeasure", "ActivityMeasuring");
298 
299  this->mm.AddTrans("On:Operational:MeasureInitial" , "On:Operational:MeasureIdle" );
300  this->mm.AddTrans("On:Operational:MeasureIdle",
301  "On:Operational:MeasureBusy",
302  events::Measure::ID,
303  "GuardMeasuringAllowed");
304  this->mm.AddTrans("On:Operational:MeasureBusy",
305  "On:Operational:MeasureIdle",
306  events::MeasureDone::ID,
307  "",
308  "ActionMeasuringDone");
309  this->mm.AddTrans("On:Operational:MeasureBusy",
310  "On:Operational:MeasureIdle",
311  events::MeasureError::ID,
312  "",
313  "ActionMeasuringFailed");
314  }
315  };
316 };
317 
318 } // namespace rtctk::componentFramework
319 
320 #endif
rtctk::componentFramework::Simple
@ Simple
Definition: model.hpp:23
rtctk::componentFramework::RequestRejected
Definition: rtcComponent.hpp:34
rtctk::componentFramework::Measurable::ModelBuilder::ModelBuilder
ModelBuilder(StateMachineEngine &engine)
Definition: measurable.hpp:291
exceptions.hpp
Provides macros and utilities for exception handling.
rtctk::componentFramework::Measurable
Life cycle extension to make RtcComponent Measurable.
Definition: measurable.hpp:146
rtctk::componentFramework::detail::MeasureContext::SendReply
void SendReply() noexcept
Send reply using result set with SetResult().
Definition: measurable.hpp:67
rtctk::componentFramework::Measurable::OutputStage::OutputStage
OutputStage(StateMachineEngine &engine, BizLogicIf &bl)
Definition: measurable.hpp:198
rtctk::componentFramework
Definition: commandReplier.cpp:20
rtctk::componentFramework::StateMachineEngine::RegisterGuardStatic
void RegisterGuardStatic(std::string const &id, std::function< bool(Event const &)> guard)
Register guard for statically known event type.
Definition: stateMachineEngine.hpp:112
rtctk::componentFramework::Measurable::BizLogicIf
Business logic interface for Measurable mixin.
Definition: measurable.hpp:152
rtctk::rtcSupervisor::Super
Runnable< RtcComponent > Super
Definition: rtcSupervisor.hpp:33
rtctk::componentFramework::RtctkException
The RtctkException class is the base class for all Rtctk exceptions.
Definition: exceptions.hpp:207
rtctk::componentFramework::Measurable::OutputStage
Definition: measurable.hpp:196
rtctk::componentFramework::Measurable::OutputStage::m_measure_error_handler
std::function< void(std::exception_ptr)> m_measure_error_handler
Definition: measurable.hpp:285
rtctk::componentFramework::StopToken
rad::StopToken StopToken
Definition: stopToken.hpp:19
rtctk::componentFramework::StateMachineEngine::RegisterActionStatic
void RegisterActionStatic(std::string const &id, std::function< void(Event const &)> action)
Register action for statically known event type.
Definition: stateMachineEngine.hpp:79
measCmdsImpl.hpp
Implementation of MAL commands for layer 'Measurable'.
rtctk::componentFramework::StateMachineEngine
Definition: stateMachineEngine.hpp:31
rtctk::componentFramework::NestedExceptionPrinter
Adapter object intended to be used in contexts without direct access to the output-stream object.
Definition: exceptions.hpp:157
rtctk::componentFramework::detail::MeasureContext::MeasureContext
MeasureContext(rad::cii::Request< std::string, std::string > const &request)
Construct context with provided request.
Definition: measurable.hpp:42
rtctk::componentFramework::StateMachineEngine::RegisterAction
void RegisterAction(std::string const &id, ActionMethod action)
Register action.
Definition: stateMachineEngine.cpp:65
rtctk::componentFramework::Measurable::InputStage
Definition: measurable.hpp:185
rtctk::componentFramework::GetLogger
log4cplus::Logger & GetLogger(const std::string &name="")
Get handle to a specific logger (used with logging macros)
rtctk::componentFramework::MeasCmdsImpl::Register
static void Register(CommandReplier &replier, StateMachineEngine &engine)
Definition: measCmdsImpl.hpp:34
rtctk::componentFramework::Measurable::BizLogicIf::ActivityMeasuring
virtual JsonPayload ActivityMeasuring(StopToken stop_token, JsonPayload const &arg)
Activity executed in its own thread that peforms the requested measurement specified by JSON argument...
Definition: measurable.hpp:166
rtctk::componentFramework::detail::MeasureContext::GetArg
JsonPayload const & GetArg() const noexcept
Definition: measurable.hpp:48
rtctk::componentFramework::detail::MeasureContext::MeasureContext
MeasureContext(MeasureContext &&) noexcept=default
rtctk::componentFramework::detail::MeasureContext::SetResult
void SetResult(JsonPayload const &result)
Sets serialized reply from JSON payload, but does not send it.
Definition: measurable.hpp:58
jsonPayload.hpp
Defines the JSON payload type JsonPayload.
rtctk::componentFramework::StateMachineEngine::RegisterRejectHandler
void RegisterRejectHandler(std::string const &id, RejectMethod reject)
Register reject handler.
Definition: stateMachineEngine.cpp:98
rtctk::componentFramework::Measurable::OutputStage::m_no_measure_in_states
std::list< std::string > m_no_measure_in_states
Definition: measurable.hpp:286
rtctk::componentFramework::detail::MeasureContext::SendErrorReply
void SendErrorReply(std::exception_ptr eptr) noexcept
If reply is pending, set exception to the provided value.
Definition: measurable.hpp:84
stopToken.hpp
A simple Stop Token.
rtctk::componentFramework::Initial
@ Initial
Definition: model.hpp:26
rtctk::componentFramework::Measurable::ModelBuilder
Definition: measurable.hpp:289
rtctk::componentFramework::Measurable::BizLogicIf::GuardMeasuringAllowed
virtual bool GuardMeasuringAllowed(JsonPayload const &arg)
Determines if measurement is possible at this time with the provided argument.
Definition: measurable.hpp:180
rtcComponent.hpp
Lifecycle of a basic 'RtcComponent'.
rtctk::componentFramework::RequestFailed
Definition: rtcComponent.hpp:44
rtctk::componentFramework::detail::MeasureContext
Holds context necessary for processing a measure request to completion.
Definition: measurable.hpp:34
rtctk::componentFramework::Measurable::InputStage::Start
void Start() override
Definition: measurable.hpp:189
rtctk::componentFramework::Measurable::OutputStage::m_measure_success_handler
std::function< void()> m_measure_success_handler
Definition: measurable.hpp:284
rtctk::componentFramework::Composite
@ Composite
Definition: model.hpp:25
rtctk_config_tool.default
default
Enter an interactive shell.
Definition: rtctk_config_tool.py:119
rtctk::componentFramework::StateMachineEngine::RegisterActivity
void RegisterActivity(std::string const &id, ActivityMethod activity, SuccessMethod on_success, FailureMethod on_failure)
Register activity.
Definition: stateMachineEngine.cpp:90
rtctk::componentFramework::JsonPayload
nlohmann::json JsonPayload
Type requirements:
Definition: jsonPayload.hpp:24
rtctk::componentFramework::Measurable::OutputStage::m_measure_ctx
std::optional< detail::MeasureContext > m_measure_ctx
Context storage used for each accepted Measure request.
Definition: measurable.hpp:283