RTC Toolkit 4.0.1
Loading...
Searching...
No Matches
rtcComponentMain.hpp
Go to the documentation of this file.
1
13#ifndef RTCTK_COMPONENTFRAMEWORK_RTCCOMPONENTMAIN_HPP
14#define RTCTK_COMPONENTFRAMEWORK_RTCCOMPONENTMAIN_HPP
15
30
31#include <mal/Cii.hpp>
32
33#include <boost/core/demangle.hpp>
34
35#include <iostream>
36#include <memory>
37#include <string>
38
49
51
68template <class BL, class BLF>
69void RunAsRtcComponent(Args const& args, BLF factory) {
70 try {
71 auto& logger = GetLogger("rtctk");
72
73 auto component_name = args.GetComponentName();
74 LOG4CPLUS_INFO(logger, "RtcComponent '" << component_name << "' started.");
75 using boost::core::demangle;
76 LOG4CPLUS_DEBUG(logger, "BusinessLogic '" << demangle(typeid(BL).name()) << "'");
77
78 {
79 ServiceContainer services;
80
81 // Service Discovery
82 auto svc_disc_endpoint = args.GetServiceDiscEndpoint();
83 services.Add<ServiceDiscovery>(
84 std::make_unique<ServiceDiscovery>(svc_disc_endpoint, component_name));
85 ServiceDiscovery& svc_disc = services.Get<ServiceDiscovery>();
86
87 // Runtime repository
88 auto rtr_endpoint = svc_disc.GetRuntimeRepoEndpoint();
89 auto rtr_adapter = std::shared_ptr(RuntimeRepoIf::CreateAdapter(rtr_endpoint));
90 services.Add<RuntimeRepoIf>(rtr_adapter);
91
92 // OLDB
93 auto oldb_endpoint = svc_disc.GetOldbEndpoint();
94 auto oldb_adapter = std::shared_ptr(OldbIf::CreateAdapter(oldb_endpoint));
95 services.Add<OldbIf>(oldb_adapter);
96
97 // Telemetry service
98 auto component_metrics = std::make_shared<ComponentMetrics>(
99 oldb_adapter,
100 DataPointPath("/") / DataPointPath(component_name) /
101 DataPointPath("metrics/default"),
102 logger);
103 services.Add<ComponentMetricsIf>(component_metrics);
104 ComponentMetricsConfigurator component_metrics_configurator(
105 component_metrics,
106 rtr_adapter,
107 DataPointPath("/") / DataPointPath(component_name) /
108 DataPointPath("dynamic/metrics/default"),
109 logger);
110
111 // Event Service
112 auto event_service = std::make_shared<MalDdsEventService>();
113 services.Add<EventServiceIf>(event_service);
114
115 // Alert service and standard observers
116 auto alert_service = std::make_shared<AlertService>(logger);
117 AlertLogger alert_logger(logger, *alert_service);
118 AlertEventPublisher alert_publisher(
119 component_name, *alert_service, *event_service, logger);
120 services.Add<AlertServiceIf>(alert_service);
121
122 // for RR endpoint we do not want to be checked if the process is there or not (as we
123 // are just starting it up)
124 auto rr_endpoint = svc_disc.GetReqRepEndpoint("", false);
125 CommandReplier replier(rr_endpoint);
126
127 // ... and sam for PubSub endpoint we do not want to be checked if the process is there
128 // or not (as we are just starting it up)
129 auto ps_endpoint = svc_disc.GetPubSubEndpoint("", false);
130 StatePublisher publisher(ps_endpoint, component_name);
131
132 StateMachineEngine engine;
133
134 engine.RegisterStateChangeHandler([&](std::string const& state) {
135 try {
136 LOG4CPLUS_DEBUG(logger, "Entering State: " << state);
137 publisher.PublishState(state);
138 OldbIf& oldb = services.Get<OldbIf>();
139 DataPointPath dp_name = DataPointPath("/" + component_name + "/state");
140 if (not oldb.DataPointExists(dp_name)) {
141 oldb.CreateDataPoint<std::string>(dp_name);
142 }
143 oldb.SetDataPoint(dp_name, state);
144 } catch (...) {
145 LOG4CPLUS_ERROR(logger,
147 RtctkException("StateChangeHandler failed"))));
148 }
149 });
150
151 static_assert(std::is_base_of_v<typename BL::ComponentType::BizLogicIf, BL>,
152 "BusinessLogic must implement BusinessLogicInterface");
153
154 static_assert(
155 std::is_invocable_v<BLF, std::string const&, ServiceContainer&>,
156 "Factory must be invocable with 'std::string const&' and 'ServiceContainer&'");
157
158 static_assert(
159 std::is_same_v<std::invoke_result_t<BLF, std::string const&, ServiceContainer&>,
160 std::unique_ptr<BL>>,
161 "Factory must return type 'std::unique_ptr<BusinessLogic>'");
162
163 // Invoking user factory here -> catch and rethrow RtctkException
164 std::unique_ptr<BL> biz_logic;
165 try {
166 biz_logic = invoke(factory, component_name, services);
167 if (!biz_logic) {
168 CII_THROW(RtctkException,
169 "BusinessLogic factory did not return a valid object");
170 }
171 } catch (std::exception const& ex) {
172 CII_THROW_WITH_NESTED(RtctkException, ex, "BusinessLogic factory failed");
173 }
174
175 typename BL::ComponentType::InputStage input_stage(replier, engine);
176
177 typename BL::ComponentType::OutputStage output_stage(engine, *biz_logic);
178
179 typename BL::ComponentType::ModelBuilder model_builder(engine);
180
181 if (auto emf = args.GetModelExportFile(); emf) {
182 model_builder.ExportModel(emf->path().to_string());
183 }
184
185 model_builder.RegisterModel();
186 input_stage.Start();
187 component_metrics->StartMonitoring();
188 engine.Work();
189 }
190
191 LOG4CPLUS_INFO(logger, "RtcComponent '" << component_name << "' terminated.");
192
193 } catch (std::exception const& ex) {
194 CII_THROW_WITH_NESTED(RtctkException, ex, "RunAsRtcComponent() failed");
195 }
196}
197
209template <class BL>
210void RunAsRtcComponent(Args const& args) {
211 static_assert(
212 std::is_constructible_v<BL, std::string const&, ServiceContainer&>,
213 "BusinessLogic must be constructible with 'std::string const&' and 'ServiceContainer&'");
214
215 RunAsRtcComponent<BL>(args, std::make_unique<BL, std::string const&, ServiceContainer&>);
216}
217
218} // namespace rtctk::componentFramework
219
220#ifndef RTCTK_NOMAIN
222
229int Main(int argc, char* argv[]) {
230 LogInitializer initializer;
231
232 try {
233 Args args{argc, argv};
234
235 auto name = args.GetComponentName();
236 auto log_props_file = args.GetLogPropsFile();
237 auto debug_mode = args.GetDebugMode();
238
239 if (log_props_file.has_value()) {
240 auto props_file = log_props_file.value().path().to_string();
241 LogConfigure(name, props_file);
242 } else {
243 auto level = debug_mode ? log4cplus::DEBUG_LOG_LEVEL : log4cplus::INFO_LOG_LEVEL;
244 LogConfigure(name, level);
245 }
246
247 // Call user implementation of RtcComponentMain
248 ::RtcComponentMain(args);
249
250 return EXIT_SUCCESS;
251
252 } catch (Args::HelpOnly const& e) {
253 std::cout << e.what() << std::endl;
254 return EXIT_SUCCESS;
255 } catch (Args::ArgNotSet const& e) {
256 std::cerr << e.what() << std::endl;
257 } catch (boost::program_options::error const& e) {
258 std::cerr << "Command line arguments parsing ERROR: " << e.what();
259 std::cerr << ", use -h for help." << std::endl;
260 } catch (std::exception const& e) {
261 LOG4CPLUS_FATAL(GetLogger("rtctk"), NestedExceptionPrinter(e));
262 } catch (...) {
263 LOG4CPLUS_FATAL(GetLogger("rtctk"), NestedExceptionPrinter(std::current_exception()));
264 }
265 return EXIT_FAILURE;
266}
267
268} // namespace rtctk::componentFramework
269
273int main(int argc, char* argv[]) {
274 try {
275 return rtctk::componentFramework::Main(argc, argv);
276 } catch (...) {
277 // Note: Use minimal formatting to avoid further exception leaks.
278 // This handler is only here to avoid std::terminate due to exception-leaks.
279 constexpr std::string_view msg =
280 "Caught exception leaked from rtctk::componentFramework::Main\n";
281 std::cerr.write(msg.data(), msg.size());
282 }
283}
284#endif // RTCTK_NOMAIN
285
286#endif // RTCTK_COMPONENTFRAMEWORK_RTCCOMPONENTMAIN_HPP
Declares AlertService.
Alert observer that publishes alerts to event service using the typed event AlertStatusEvent.
Definition: alertService.hpp:106
Simple alert observer that writes alerts to log.
Definition: alertService.hpp:89
Alert Service interface.
Definition: alertServiceIf.hpp:315
Exception class used by the command line argument parser.
Definition: rtcComponentArgs.hpp:51
Exception class used by the command line argument parser.
Definition: rtcComponentArgs.hpp:41
Class used to parse default command line arguments.
Definition: rtcComponentArgs.hpp:34
std::optional< elt::mal::Uri > GetModelExportFile() const
Get name of optionally provided state machine model export file.
Definition: rtcComponentArgs.cpp:48
std::string GetComponentName() const
Get component name or identifier.
Definition: rtcComponentArgs.cpp:28
elt::mal::Uri GetServiceDiscEndpoint() const
Get service discovery endpoint.
Definition: rtcComponentArgs.cpp:32
Class that handles reception of commands using MAL.
Definition: commandReplier.hpp:29
Configures ComponentMetrics from a runtime repository.
Definition: componentMetrics.hpp:43
Component metrics interface.
Definition: componentMetricsIf.hpp:184
This class provides a wrapper for a data point path.
Definition: dataPointPath.hpp:73
Interface class for providing pub/sub facilities for JSON events.
Definition: eventServiceIf.hpp:29
RAII class to clean-up logging without leaking memory.
Definition: logger.hpp:28
Adapter object intended to be used in contexts without direct access to the output-stream object.
Definition: exceptions.hpp:185
Base interface for all OLDB adapters.
Definition: oldbIf.hpp:26
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
virtual void CreateDataPoint(const DataPointPath &path, const std::type_info &type)=0
Creates a new datapoint in the repository with a specified type.
void SetDataPoint(const DataPointPath &path, const T value)
Sets a datapoint in the repository.
Definition: repositoryIf.hpp:595
virtual bool DataPointExists(const DataPointPath &path) const =0
Checks for the existence of a datapoint in the repository.
The RtctkException class is the base class for all Rtctk exceptions.
Definition: exceptions.hpp:237
Base interface for all Runtime Configuration Repository adapters.
Definition: runtimeRepoIf.hpp:28
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
Container class that holds services of any type.
Definition: serviceContainer.hpp:39
Class that implements a very basic service discovery mechanism.
Definition: serviceDiscovery.hpp:33
ServiceEndpoint GetRuntimeRepoEndpoint()
Get the Runtime Repository Endpoint from the ServiceDiscovery.
Definition: serviceDiscovery.cpp:59
Definition: stateMachineEngine.hpp:35
void RegisterStateChangeHandler(StateMethod on_statechange)
Register state changed handler.
Definition: stateMachineEngine.cpp:144
void Work()
Runs the event loop of the state machine.
Definition: stateMachineEngine.cpp:157
Class used to publish state-changed-topic using MAL.
Definition: statePublisher.hpp:36
void PublishState(const std::string &state)
Definition: statePublisher.cpp:41
Receive commands via MAL.
Declares ComponentMetrics.
Provides macros and utilities for exception handling.
void RunAsRtcComponent(Args const &args, BLF factory)
RTC Component runner function, needed to run custom BusinessLogic as RTC Component.
Definition: rtcComponentMain.hpp:69
void RtcComponentMain(rtctk::componentFramework::Args const &args)
Main entry point for user code, this method must be implemented by component developers.
Definition: main.cpp:25
auto WrapWithNested(E &&exception) noexcept(std::is_nothrow_constructible_v< detail::UnspecifiedNested< typename std::decay_t< E > >, E && >)
Constructs an unspecified exception that derives from both the provided object and std::nested_except...
Definition: exceptions.hpp:121
log4cplus::Logger & GetLogger(const std::string &name="app")
Get handle to a specific logger.
Definition: logger.cpp:180
void LogConfigure(const std::string &app_name, const std::string &props_file_name)
Performs custom logging configuration for any application.
Definition: logger.cpp:69
Logging Support Library based on log4cplus.
Implementation of the event service.
Definition: commandReplier.cpp:22
int Main(int argc, char *argv[])
Main function implementation.
Definition: rtcComponentMain.hpp:229
Header file for OldbIf, which defines the API for OldbAdapters.
Provides argument parsing functionality of an RTC Component.
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:273
Header file for RuntimeRepoIf, which defines the API for RuntimeRepoAdapters.
A container that can hold any type of service.
Class that implements a very basic service discover mechanism.
Class that implements the service registry interface.
Wrapper around the SCXML State Machine Engine.
Publishes the stdif state topic via MAL.