RTC Toolkit  1.0.0
rtcComponentMain.hpp
Go to the documentation of this file.
1 
12 #ifndef RTCTK_COMPONENTFRAMEWORK_RTCCOMPONENTMAIN_HPP
13 #define RTCTK_COMPONENTFRAMEWORK_RTCCOMPONENTMAIN_HPP
14 
15 #include <mal/Cii.hpp>
16 #include <memory>
17 #include <string>
18 
20 
29 
30 #include <rtctk/componentFramework/events.rad.hpp> // TODO: should not be needed
31 
32 namespace rtctk::componentFramework {
34 }
35 
46 
47 
48 namespace rtctk::componentFramework {
49 
66 template <class BL, class BLF>
67 void RunAsRtcComponent(Args const& args, BLF factory) {
68  using namespace std;
69 
70  auto component_name = args.GetComponentName();
71  LOG4CPLUS_INFO(GetLogger(), "RtcComponent '" << component_name << "' started.");
72  LOG4CPLUS_DEBUG(GetLogger(), "BusinessLogic is '" << detail::GetTypeName(typeid(BL)) << "'");
73 
74  ServiceContainer services;
75 
76  auto svc_disc_endpoint = args.GetServiceDiscEndpoint();
77  services.Add<ServiceDiscovery>(
78  make_unique<ServiceDiscovery>(svc_disc_endpoint, component_name));
79 
80  ServiceDiscovery& svc_disc = services.Get<ServiceDiscovery>();
81 
82  auto rtr_endpoint = svc_disc.Get(ServiceDiscovery::RUNTIME_REPO_ENDPOINT);
83  services.Add<RuntimeRepoIf>(RuntimeRepoIf::CreateAdapter(rtr_endpoint));
84 
85  auto oldb_endpoint = svc_disc.Get(ServiceDiscovery::OLDB_ENDPOINT);
86  services.Add<OldbIf>(OldbIf::CreateAdapter(oldb_endpoint));
87 
88  auto rr_endpoint = svc_disc.Get(ServiceDiscovery::REQ_REP_ENDPOINT);
89  CommandReplier replier(rr_endpoint);
90 
91  auto ps_endpoint = svc_disc.Get(ServiceDiscovery::PUB_SUB_ENDPOINT);
92  StatePublisher publisher(ps_endpoint, component_name);
93 
94  StateMachineEngine engine(make_unique<events::Exit>());
95 
96  engine.RegisterStateChangeHandler([&](string const& state) {
97  publisher.PublishState(state);
98  OldbIf& oldb = services.Get<OldbIf>();
99  DataPointPath dp_name = DataPointPath("/" + component_name + "/state");
100  if (not oldb.DataPointExists(dp_name)) {
101  oldb.CreateDataPoint<std::string>(dp_name);
102  }
103  oldb.SetDataPoint(dp_name, state);
104  });
105 
106  static_assert(is_base_of_v<typename BL::ComponentType::BizLogicIf, BL>,
107  "BusinessLogic must implement BusinessLogicInterface");
108 
109  static_assert(is_invocable_v<BLF, string const&, ServiceContainer&>,
110  "Factory must be invocable with 'std::string const&' and 'ServiceContainer&'");
111 
112  static_assert(is_same_v<invoke_result_t<BLF, string const&, ServiceContainer&>, unique_ptr<BL>>,
113  "Factory must return type 'std::unique_ptr<BusinessLogic>'");
114 
115  // Invoking user factory here -> catch and rethrow RtctkException
116  unique_ptr<BL> biz_logic;
117  try {
118  biz_logic = invoke(factory, component_name, services);
119  if (!biz_logic) {
120  throw std::runtime_error("BusinessLogic factory did not return a valid object");
121  }
122  } catch (...) {
123  std::throw_with_nested(RtctkException("BusinessLogic factory failed"));
124  }
125 
126 
127  typename BL::ComponentType::InputStage input_stage(replier, engine);
128 
129  typename BL::ComponentType::OutputStage output_stage(engine, *biz_logic);
130 
131  typename BL::ComponentType::ModelBuilder model_builder(engine);
132 
133  if (auto emf = args.GetModelExportFile(); emf) {
134  model_builder.ExportModel(emf->path().to_string());
135  }
136 
137  model_builder.RegisterModel();
138  input_stage.Start();
139  engine.Work();
140 
141  LOG4CPLUS_INFO(GetLogger(), "RtcComponent '" << component_name << "' terminated.");
142 }
143 
155 template <class BL>
156 void RunAsRtcComponent(Args const& args) {
157  using namespace std;
158 
159  static_assert(
160  is_constructible_v<BL, string const&, ServiceContainer&>,
161  "BusinessLogic must be constructible with 'std::string const&' and 'ServiceContainer&'");
162 
163  RunAsRtcComponent<BL>(args, make_unique<BL, string const&, ServiceContainer&>);
164 }
165 
166 } // namespace rtctk::componentFramework
167 
168 #ifndef RTCTK_NOMAIN
169 namespace rtctk::componentFramework {
170 
177 int Main(int argc, char* argv[]) {
178  LogInitializer initializer;
179 
180  try {
181  Args args{argc, argv};
182 
183  auto component_name = args.GetComponentName();
184  auto log_props_file = args.GetLogPropsFile();
185 
186  if (log_props_file.has_value()) {
187  auto props_file = log_props_file.value().path().to_string();
188  LogConfigure(props_file);
189  SetDefaultLogger(component_name);
190  LOG4CPLUS_INFO(GetLogger(), "Custom log properties file loaded: " << props_file);
191  } else {
192  LogConfigure();
193  MakeLogger(component_name, log4cplus::INFO_LOG_LEVEL);
194  SetDefaultLogger(component_name);
195  }
196 
197  // Call user implementation of RtcComponentMain
198  ::RtcComponentMain(args);
199 
200  return EXIT_SUCCESS;
201 
202  } catch (detail::HelpOnly const & e) {
203  std::cout << e.what() << std::endl;
204  return EXIT_SUCCESS;
205  } catch (detail::ArgNotSet const& e) {
206  std::cout << e.what() << std::endl;
207  } catch (std::exception const& e) {
208  LOG4CPLUS_FATAL(GetLogger(), NestedExceptionPrinter(e));
209  } catch (...) {
210  LOG4CPLUS_FATAL(GetLogger(), NestedExceptionPrinter(std::current_exception()));
211  }
212  return EXIT_FAILURE;
213 }
214 
215 } // namespace rtctk::componentFramework
216 
217 
221 int main(int argc, char* argv[]) {
222  try {
223  return rtctk::componentFramework::Main(argc, argv);
224  } catch (...) {
225  // Note: Use minimal formatting to avoid further exception leaks.
226  // This handler is only here to avoid std::terminate due to exception-leaks.
227  constexpr std::string_view msg =
228  "Caught exception leaked from rtctk::componentFramework::Main\n";
229  std::cerr.write(msg.data(), msg.size());
230  }
231 }
232 #endif // RTCTK_NOMAIN
233 
234 #endif // RTCTK_COMPONENTFRAMEWORK_RTCCOMPONENTMAIN_HPP
serviceContainer.hpp
A container that can hold any type of service.
rtctk::componentFramework::detail::GetTypeName
std::string GetTypeName(const std::type_info &tid)
Definition: rtcComponent.hpp:114
commandReplier.hpp
Receive commands via MAL.
rtctk::componentFramework::RepositoryIf::SetDataPoint
void SetDataPoint(const DataPointPath &path, const T value)
Sets a datapoint in the repository.
Definition: repositoryIf.hpp:489
rtctk::componentFramework::detail::HelpOnly
Definition: rtcComponent.hpp:24
rtctk::componentFramework::StateMachineEngine::Work
void Work()
Runs the event loop of the state machine.
Definition: stateMachineEngine.cpp:130
stateMachineEngine.hpp
Wrapper around the SCXML State Machine Engine.
rtctk::componentFramework::MakeLogger
void MakeLogger(const std::string &name, log4cplus::LogLevel ll, bool log_to_file=true, bool additive=false)
Retrieve new logger programmatically.
rtctk::componentFramework::ServiceContainer::Get
Service & Get(const std::string &name="")
Get a handle to a service.
Definition: serviceContainer.hpp:85
rtctk::componentFramework::detail::ArgNotSet
Definition: rtcComponent.hpp:30
rtctk::componentFramework::LogConfigure
void LogConfigure(const std::string &cfg_file_name="")
Initial logging system configuration.
rtctk::componentFramework::ServiceContainer::Add
void Add(Service &&service, const std::string &name="")
Insert new service into the container.
Definition: serviceContainer.hpp:48
statePublisher.hpp
Publishes the stdif state topic via MAL.
rtctk::componentFramework::Args
detail::Args Args
Definition: rtcComponentMain.hpp:33
rtctk::componentFramework
Definition: commandReplier.cpp:20
serviceDiscovery.hpp
Class that implements a very basic service discover mechanism.
RtcComponentMain
void RtcComponentMain(rtctk::componentFramework::Args const &args)
Main entry point for user code, method must be implemented by component developers.
Definition: main.cpp:22
rtctk::componentFramework::ServiceDiscovery::RUNTIME_REPO_ENDPOINT
static const DataPointPath RUNTIME_REPO_ENDPOINT
Definition: serviceDiscovery.hpp:36
rtctk::componentFramework::RepositoryIf::DataPointExists
virtual bool DataPointExists(const DataPointPath &path) const =0
Checks for the existence of a datapoint in the repository.
rtctk::componentFramework::StatePublisher
Class used to publish state-changed-topic using MAL.
Definition: statePublisher.hpp:33
rtctk::componentFramework::ServiceDiscovery
Class that implements a very basic service discovery mechanism.
Definition: serviceDiscovery.hpp:29
rtctk::componentFramework::detail::Args
Definition: rtcComponent.hpp:38
rtctk::componentFramework::RtctkException
The RtctkException class is the base class for all Rtctk exceptions.
Definition: exceptions.hpp:207
rtcComponent.hpp
Provides details for core functionality of an RTC Component.
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::RuntimeRepoIf::CreateAdapter
static std::unique_ptr< RuntimeRepoIf > CreateAdapter(const elt::mal::Uri &uri)
Factory method used to create the appropriate Runtime Configuration Repository adapter depending on t...
Definition: runtimeRepoIf.cpp:18
rtctk::componentFramework::LogInitializer
RAII class to clean-up logging without leaking memory.
Definition: logger.hpp:23
rtctk::componentFramework::GetLogger
log4cplus::Logger & GetLogger(const std::string &name="")
Get handle to a specific logger (used with logging macros)
rtctk::componentFramework::ServiceDiscovery::REQ_REP_ENDPOINT
static const DataPointPath REQ_REP_ENDPOINT
There is a fixed set of supported service types.
Definition: serviceDiscovery.hpp:34
rtctk::componentFramework::StatePublisher::PublishState
void PublishState(const std::string &state)
Definition: statePublisher.cpp:36
rtctk::componentFramework::ServiceContainer
Container class that holds services of any type.
Definition: serviceContainer.hpp:35
rtctk::componentFramework::Main
int Main(int argc, char *argv[])
Main function implementation.
Definition: rtcComponentMain.hpp:177
rtctk::componentFramework::detail::Args::GetComponentName
std::string GetComponentName() const
Definition: rtcComponent.hpp:44
main
int main(int argc, char *argv[])
Main function, this is private to the RTC Tk and shall NOT be used by component developers.
Definition: rtcComponentMain.hpp:221
rtctk::componentFramework::detail::Args::GetServiceDiscEndpoint
elt::mal::Uri GetServiceDiscEndpoint() const
Definition: rtcComponent.hpp:48
rtctk::componentFramework::OldbIf
Definition: oldbIf.hpp:20
rtctk::componentFramework::CommandReplier
Class that handles reception of commands using MAL.
Definition: commandReplier.hpp:26
rtctk::componentFramework::RunAsRtcComponent
void RunAsRtcComponent(Args const &args, BLF factory)
RTC Component runner function, needed to run custom BusinessLogic as RTC Component.
Definition: rtcComponentMain.hpp:67
rtctk::componentFramework::ServiceDiscovery::Get
elt::mal::Uri Get(const std::string &service_name)
Get endpoint of specific service.
rtctk::componentFramework::RuntimeRepoIf
Definition: runtimeRepoIf.hpp:20
std
Definition: mudpiProcessingError.hpp:119
rtctk::componentFramework::OldbIf::CreateAdapter
static std::unique_ptr< OldbIf > CreateAdapter(const elt::mal::Uri &uri)
Factory method used to create the appropriate OLDB adapter depending on the URI scheme.
Definition: oldbIf.cpp:18
logger.hpp
Logging Support Library based on log4cplus.
rtctk::componentFramework::StateMachineEngine::RegisterStateChangeHandler
void RegisterStateChangeHandler(StateMethod on_statechange)
Register state changed handler.
Definition: stateMachineEngine.cpp:108
rtctk::componentFramework::SetDefaultLogger
void SetDefaultLogger(const std::string &name)
Set the default logger.
Definition: logger.cpp:62
rtctk::componentFramework::RepositoryIf::CreateDataPoint
virtual void CreateDataPoint(const DataPointPath &path, const std::type_info &type)=0
Creates a new datapoint in the repository with a specified type.
rtctk::componentFramework::detail::Args::GetModelExportFile
std::optional< elt::mal::Uri > GetModelExportFile() const
Definition: rtcComponent.hpp:60
rtctk::componentFramework::DataPointPath
This class provides a wraper for DataPoint paths which ensures that they only contain valid character...
Definition: dataPointPath.hpp:34
runtimeRepoIf.hpp
Header file for RuntimeRepoIf, which defines the API for RuntimeRepoAdapters.
rtctk::componentFramework::ServiceDiscovery::PUB_SUB_ENDPOINT
static const DataPointPath PUB_SUB_ENDPOINT
Definition: serviceDiscovery.hpp:35
rtctk::componentFramework::ServiceDiscovery::OLDB_ENDPOINT
static const DataPointPath OLDB_ENDPOINT
Definition: serviceDiscovery.hpp:38
oldbIf.hpp
Header file for OldbIf, which defines the API for OldbAdapters.