/* * (c) Copyright, Real-Time Innovations, 2017. * All rights reserved. * * No duplications, whole or partial, manual or electronic, may be made * without express written permission. Any such copies, or * revisions thereof, must display this notice unaltered. * This code contains trade secrets of Real-Time Innovations, Inc. */ #ifndef RTI_ROUTING_PROCESSOR_ROUTE_HPP_ #define RTI_ROUTING_PROCESSOR_ROUTE_HPP_ #include #include #include #include "routingservice/routingservice_processor.h" #include "routingservice/routingservice_processor_impl.h" #include #include #include #include #include #include #include namespace rti { namespace routing { namespace processor { namespace detail { class ProcessorForwarder; } class Route; template struct port_list; template <> struct port_list { static std::vector& get(Route& route); }; template <> struct port_list { static std::vector& get(Route& route); }; /** @ingroup RTI_RoutingServiceProcessorModule * * @class rti::routing::processor::Route * * @brief Representation of the Route object that owns a Processor. * * This class provides an interface to access the capabilities of a Route, such * as retrieving any of its inputs and outputs. Usage of this class * is restricted within the Processor context where the object is passed. * * An example of how to use this object is shown below. This example illustrates * a simple use case of reading from all inputs and writing to all outputs, * assuming that the sample data and info have the same representation and * type. * * \code{.c++} * using dds::core::xtypes::DynamicData; * using dds::sub::SampleInfo; * using namespace rti::routing::processor; * * ... * * for (auto input : route.inputs()) { * LoanedSamples samples = input->read(); * * for (auto output : route.outputs()) { * for(auto sample = samples) { * output.write(sample.data(), sample.info()); * } * } * } * \endcode */ class Route { public: template struct Inputs { typedef PortIterator iterator; Inputs(RTI_RoutingServiceRoute *native_route) : native_route_(native_route) { } iterator begin() { return iterator(native_route_); } iterator end() { return iterator(); } private: RTI_RoutingServiceRoute *native_route_; }; template struct Outputs { typedef PortIterator iterator; Outputs(RTI_RoutingServiceRoute *native_route) : native_route_(native_route) { } iterator begin() { return iterator(native_route_); } iterator end() { return iterator(); } private: RTI_RoutingServiceRoute *native_route_; }; /** * @brief Returns the total number of inputs in this Route. * */ int32_t input_count() const { return RTI_RoutingServiceRoute_get_input_count(native_route_); } /** * @brief Returns the total number of outputs in this Route. * */ int32_t output_count() const { return RTI_RoutingServiceRoute_get_output_count(native_route_); } /** *@brief Checks whether the Input at the specified index is enabled * */ bool input_enabled(int32_t index) const { return RTI_RoutingServiceRoute_is_input_enabled(native_route_, index) ? true : false; } /** *@brief Checks whether the Input at the specified index is enabled * */ bool output_enabled(int32_t index) const { return RTI_RoutingServiceRoute_is_output_enabled(native_route_, index) ? true : false; } /** * @brief Returns the Input object at the specified index. * * Input indexes are assigned in increasing creation order, starting at 0. * The creation order is the same order than the inputs are defined within * the Route configuration. * * The returned object can be used to construct the appropriate TypedInput, * which can be used for reading data. * * @param[in] index * The index of the Input to be retrieved. * * @return The Input at the specified index. * * @see TypedInput * */ Input& input(int32_t index) { return *(get_input_at_index(index)); } /** * @brief Returns the Input object with the specified name or throws an * exception if the input with the given name is not found or if it is * found but is not enabled. * * \b NOTE: The condition that the input must be enabled will be removed * in a future version. This is being tracked with issue ID ROUTING-1131. * * @param[in] name The input configuration name * * @see TypedInput::name * @throw std::logic_error */ Input& input(const std::string& name) { return *(lookup_input(name)); } /** * @brief Returns the TypedInput object at the specified index. * * The returned object is typed so it can read samples whose type is * \p DataRep for data, and \p InfoRep for info. These types must * match the expected type representations of the underlying * rti::routing::adapter::StreamReader. * * Typically, these template arguments are typed * dds::core::xtypes::DynamicData and dds::sub::SampleInfo, respectively. * * @warning This operation performs no type integrity check. It is * responsibility of the caller to ensure the provided template * arguments match with the expected types of the input. Otherwise * behavior accessing the input is undefined. * * @return The TypedInput object at the specified index. * * @see input(int32_t) * @see TypedInput */ template TypedInput input(int32_t index) { return &input(index); } /** * @brief Same as input(int32_t) with * InfoRep = dds::sub::SampleInfo. * */ template TypedInput input(int32_t index) { return input(index); } /** * @brief Same as input(int32_t) but using * the configuration name of the input. * */ template TypedInput input(const std::string& name) { return &input(name); } /** * @brief Same as input(std::string&) with * InfoRep = dds::sub::SampleInfo. */ template TypedInput input(const std::string& name) { return input(name); } /** * @brief Returns the Output object at the specified index. * * Output indexes are assigned in increasing creation order, starting at 0. * The creation order is the same order than the outputs are defined within * the Route configuration. * * The returned object can be used to construct the appropriate TypedOutput, * which can be used for writing data. * * @param[in] index * The index of the Output to be retrieved. * * @return The Output at the specified index. * * @see TypedOutput * */ Output& output(int32_t index) { return *(get_output_at_index(index)); } /** * @brief Returns the Output object with the specified name or throws an * exception if the output with the given name is not found or if it is * found but is not enabled. * * \b NOTE: The condition that the input must be enabled will be removed * in a future version. This is being tracked with issue ID ROUTING-1131. * * @param[in] name The output configuration name * * @see TypedOutput::name * @throw std::logic_error */ Output& output(const std::string& name) { return *(lookup_output(name)); } /** * @brief Returns the TypedOutput object at the specified index. * * The returned object is typed so it can write samples whose type is * \p DataRep for data, and \p InfoRep for info. These types must * match the expected type representations of the underlying * rti::routing::adapter::StreamWriter. * * Typically, these template arguments are typed * dds::core::xtypes::DynamicData and dds::sub::SampleInfo, respectively. * * @warning This operation performs no type integrity check. It is * responsibility of the caller to ensure the provided template * arguments match with the expected types of the output. Otherwise * behavior accessing the output is undefined. * * @return The TypedOutput object at the specified index. * * @see input(int32_t) */ template TypedOutput output(int32_t index) { return &output(index); } /** * @brief Same as output(int32_t) with * InfoRep = dds::sub::SampleInfo. * */ template TypedOutput output(int32_t index) { return output(index); } /** * @brief Same as output(int32_t) but using * the configuration name of the output. * */ template TypedOutput output(const std::string& name) { return &output(name); } /** * @brief Same as output(std::string&) with * InfoRep = dds::sub::SampleInfo. */ template TypedOutput output(const std::string& name) { return output(name); } /** * @brief Returns an accessor for the contained inputs. * * The returned object that allows iterating over the * contained inputs, treating them as TypedInput. * * @see Inputs * @see TypedInput input(int32_t index) */ template Inputs inputs() { return Inputs(native_route_); } /** * @brief Same as Inputs inputs() with * InfoRep = dds::sub::SampleInfo. */ template Inputs inputs() { return inputs(); } /** * @brief Returns an accessor for the contained outputs. * * The returned object that allows iterating over the * contained outputs, treating them as TypedOutput. * * @see Outputs * @see TypedOutput input(int32_t index) */ template Outputs outputs() { return Outputs(native_route_); } /** * @brief Same as Inputs outputs() with * InfoRep = dds::sub::SampleInfo. */ template Outputs outputs() { return outputs(); } /** * * @brief Changes the event period of this Route. * * This operation can be called many times within the same periodic event, * in which only the last call will have effect. * * The operation will enable the periodic event in this route if this * operation is called for the first time in a route with no period set * in the configuration. * * @param[in] period New session period */ void period(const dds::core::Duration& period) { struct DDS_Duration_t native_period = DDS_DURATION_ZERO; rti::core::native_conversions::to_native(native_period, period); RTI_RoutingServiceRoute_set_period( native_route_, &native_period); } dds::core::Duration period() const { struct DDS_Duration_t native_period = DDS_DURATION_ZERO; RTI_RoutingServiceRoute_get_period( native_route_, &native_period); return rti::core::native_conversions::from_native(native_period); } /** * * @brief Returns the fully qualified of this Route, derived from the configuration. * */ const std::string& full_name() const { return full_name_; } private: friend class detail::ProcessorForwarder; friend class Output; friend struct port_list; friend struct port_list; typedef std::vector::iterator private_input_it; typedef std::vector::iterator private_output_it; Route& operator= (const Route& other); Route(RTI_RoutingServiceRoute *native_route, RTI_RoutingServiceEnvironment *native_env) : native_route_(native_route), native_env_(native_env) { const char *native_full_name = RTI_RoutingServiceRoute_get_full_name(native_route); if (native_full_name == nullptr) { throw dds::core::InvalidArgumentError( "Native Route has invalid full name"); } full_name_ = native_full_name; } Input* get_input_at_index(int32_t index) { RTI_RoutingServiceInput *native_input = RTI_RoutingServiceRoute_get_input_at(native_route_, index); if (native_input == NULL) { throw dds::core::InvalidArgumentError( RTI_RoutingServiceEnvironment_get_error_message(native_env_)); } return static_cast(RTI_RoutingServiceInput_get_user_data(native_input)); } Output* get_output_at_index(int32_t index) { RTI_RoutingServiceOutput *native_output = RTI_RoutingServiceRoute_get_output_at(native_route_, index); if (native_output == NULL) { throw dds::core::InvalidArgumentError( RTI_RoutingServiceEnvironment_get_error_message(native_env_)); } return static_cast(RTI_RoutingServiceOutput_get_user_data(native_output)); } Input* lookup_input(const std::string& name) { RTI_RoutingServiceInput *native_input = RTI_RoutingServiceRoute_lookup_input_by_name( native_route_, name.c_str()); if (native_input == NULL) { throw dds::core::InvalidArgumentError( RTI_RoutingServiceEnvironment_get_error_message(native_env_)); } return static_cast(RTI_RoutingServiceInput_get_user_data(native_input)); } Output* lookup_output(const std::string& name) { RTI_RoutingServiceOutput *native_output = RTI_RoutingServiceRoute_lookup_output_by_name( native_route_, name.c_str()); if (native_output == NULL) { throw dds::core::InvalidArgumentError( RTI_RoutingServiceEnvironment_get_error_message(native_env_)); } return static_cast(RTI_RoutingServiceOutput_get_user_data(native_output)); } private: RTI_RoutingServiceRoute *native_route_; RTI_RoutingServiceEnvironment *native_env_; std::string full_name_; }; } } } #endif // RTI_ROUTING_PROCESSOR_ROUTE_HPP_