Adds immediate migration results

This commit is contained in:
torsten committed 2026-08-18 22:12:24 +02:00
1 parent ba4121728b
commit 6a2a0667ab
2395 files changed
+357322 -2524

No files matched your search

@@ -0,0 +1,703 @@
/*
* (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_INPUT_HPP_
#define RTI_ROUTING_PROCESSOR_INPUT_HPP_
#include <dds/core/Value.hpp>
#include <dds/core/SafeEnumeration.hpp>
#include <rti/core/NativeValueType.hpp>
#include <rti/core/Entity.hpp>
#include <dds/sub/DataReader.hpp>
#include <dds/core/xtypes/DynamicData.hpp>
#include "routingservice/routingservice_processor.h"
#include "routingservice/routingservice_adapter_new.h"
#include <rti/routing/StreamInfo.hpp>
#include <rti/routing/adapter/StreamReader.hpp>
#include <rti/routing/processor/LoanedSamples.hpp>
#include <rti/routing/processor/Query.hpp>
namespace rti { namespace routing { namespace processor {
class Route;
template <typename Data, typename Info> class TypedInput;
template <typename Data, typename Info = dds::sub::SampleInfo>
class TypedInput;
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::Input
*
* @brief Generic Representation of a Route's input.
*
*
* This class provides a base representation of the inputs contained in a Route.
* Since it is generic, this object does not allow you to perform any operation
* that requires dealing with the data provided by the underlying
* rti::routing::adapter::StreamReader.
*/
class Input {
public:
/*i
*/
Input(RTI_RoutingServiceInput *native,
int32_t index,
RTI_RoutingServiceRoute *native_route)
: native_(native),
index_(index),
native_route_(native_route),
stream_info_("", ""),
name_(RTI_RoutingServiceInput_get_name(native))
{
const RTI_RoutingServiceStreamInfo *native_stream_info =
RTI_RoutingServiceInput_get_stream_info(native);
if (native_stream_info == nullptr) {
throw dds::core::InvalidArgumentError(
"invalid argument: invalid StreamInfo for input");
}
stream_info_ = *native_stream_info;
}
/*i
*
*/
const rti::routing::StreamInfo& stream_info() const
{
return stream_info_;
}
/*i
*
*/
const std::string& name() const
{
return name_;
}
/*i
*
*/
int32_t index()
{
return index_;
}
/**
* @brief Returns a typed version of this Input.
*
* Note: This operation is not type-safe. It is the caller's responsibility
* to use the appropriate type.
*
*
* @see TypedInput
* @see <tt>TypedInput<DataRep, Info> Route<DataRep, InfoRep>::input(int32_t index)</tt>
*/
template <typename Data, typename Info>
TypedInput<Data, Info> get()
{
return this;
}
/**
* @brief Returns a typed version of this Input.
*
* Note: This operation is not type-safe. It is the caller's responsibility
* to use the appropriate type.
*
* @see TypedInput
* @see TypedInput<tt><DataRep, dds::sub::SampleInfo></tt> Route<DataRep>::input(int32_t index)
*/
template <typename Data>
TypedInput<Data, dds::sub::SampleInfo> get()
{
return this;
}
/*i
*
*/
RTI_RoutingServiceInput* native()
{
return native_;
}
// Implementation details
private:
template <typename Data, typename Info> friend class TypedInput;
friend class Route;
friend class std::allocator<Input>;
RTI_RoutingServiceInput *native_;
int32_t index_;
RTI_RoutingServiceRoute *native_route_;
rti::routing::StreamInfo stream_info_;
std::string name_;
};
template <typename Data, typename Info = dds::sub::SampleInfo>
class Selector;
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::TypedInput
*
* @brief Representation of an Input whose data representation is \p DataRep,
* whose info representation is \p InfoRep.
*
*/
template <typename Data, typename Info>
class TypedInput{
public:
typedef rti::routing::processor::Selector<Data, Info> Selector;
TypedInput(Input *input);
/**
* @brief Returns the StreamInfo associated with this object.
*
* The associated StreamInfo represents an equivalent object to the one
* used to create the underlying rti::routing::adapter::StreamReader.
*/
const rti::routing::StreamInfo& stream_info() const;
/**
* @brief Returns the name of this output.
*
* The name is given by the name of the corresponding XML configuration tag.
*/
const std::string& name() const;
/**
* @brief Returns all the available samples in this object.
*
* This operation will call rti::routing::adapter::StreamReader::take on
* the underlying rti::routing::adapter::StreamReader.
*
* The returned samples are interpreted to contain data represented
* as \c Data and info represented as \c Info.
*
* @see LoanedSamples
* @see rti::routing::adapter::StreamReader::take
*/
LoanedSamples<Data, Info> take();
/**
* @brief Same as take() but this calls
* rti::routing::adapter::StreamReader::read instead.
*
* @see LoanedSamples
* @see rti::routing::adapter::StreamReader::read
* @see take
*/
LoanedSamples<Data, Info> read();
/**
* @brief Gets a Selector to perform complex data selections, such as
* per-instance selection, content and status filtering.
*
* The selector can be used as follows:
* \code{.c++}
* LoanedSamples<DynamicData> samples = input.select()
* .instance(handle)
* .content(query)
* .state(state)
* .take();
* \endcode
*
* This shows how samples can be taken by selecting a specific instance,
* then filtering by state and content.
*
* Note that when the application wants to access all available samples,
* it can simply call read() or take().
*
* @return A Selector, typically used in-line to configure it and finally
* call Selector::read() or Selector::take().
*
* @see Selector for the different parameters that can be set to
* configure which samples to read or take. Selecting what samples to
* read.
*/
Selector select();
rti::routing::processor::Query query(
const dds::topic::Filter& filter);
/**
* @brief Indicates whether this input has received new data since the last
* time any variant of the read operations was called.
*
* @note Given the time decoupling between the notification of new data and
* when it the data is read, it is possible this function may return
* true and yet there is no data to be returned.
*
* @return True if this input has new data received since the last read
* access.
*/
bool active();
/**
* @brief Creates a new data sample from this input.
*
* The data constructor called in this operation depends on the data
* representation kind of the TypeInfo associated with this input.
* If the type representation is a dynamic type, then it will assume
* the following constructor:
* \code Data(const dds::core::xtypes::DynamicType&) \endcode
*
* and will use the type code object downcasted from the value
* returned by TypeInfo::type_representation.
*
* Otherwise:
* \code Data() \endcode
*
* @return A new data sample
*/
Data create_data();
/*i
*
*/
TypedInput<Data, Info>* operator->()
{
return this;
}
/**
* @brief Returns the underlying DDS DataReader that is part of this
* StreamReader implementation, assuming this input holds a DDS StreamReader.
*
* This operation will throw an exception if this input does not hold a
* DDS StreamReader.
*
* @note The access to the underlying DataReader is allowed only as long as
* this Input remains enabled. The object representing the DataReader
* must be invalidated before the input is disabled, otherwise the behavior
* is undefined.
*
* @throw std::exception
*
* @return dds::sub::DataReader<Data>
*/
dds::sub::DataReader<Data> dds_data_reader()
{
using rti::core::detail::create_from_native_entity;
DDS_DataReader *native_reader =
RTI_RoutingServiceInput_get_dds_reader(input_->native_);
if (native_reader == NULL) {
throw dds::core::InvalidArgumentError(
"invalid argument: input does not hold a DDS StreamReader");
}
typedef dds::sub::DataReader<Data> data_reader_type;
return rti::core::detail::create_from_native_entity<data_reader_type>(
native_reader);
}
private:
TypedInput();
friend class rti::routing::processor::Selector<Data, Info>;
LoanedSamples<Data, Info> take(
const rti::routing::adapter::SelectorState& selector_state);
LoanedSamples<Data, Info> read(
const rti::routing::adapter::SelectorState& selector_state);
friend class rti::routing::processor::Route;
Input *input_;
};
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::Selector
*
* @brief An element that allows reading data that meet a set of specified
* attributes.
*
* The Selector class is used by the TypedInput to compose read and take
* operations.
*
* A Selector has an associated TypedInput and configures the behavior of the
* read or take operation performed by that TypedInput.
*
* For example, to perform a read of at most 5 unread samples:
* \code
* LoanedSamples<Foo> samples = reader.select()
* .read()
* .max_samples(5)
* .state(dds::sub::status::DataState::new_data());
* \endcode
*
* @note It's very important to consider that the behavior of this class is
* tightly coupled and dependent on the underlying
* rti::routing::adapter::StreamReader of the attached TypedInput. In
* particular, the samples returned by a Selector depend on the behavior
* of the rti::routing::adapter::StreamReader::take(SelectorState) and
* rti::routing::adapter::StreamReader::read(SelectorState). If the
* implementation of these operations behave according to the requirements,
* then the behavior offered by this class will be consistent.
*
* @see rti::routing::adapter::SelectorState
* @see dds::sub::DataReader::Selector for equivalent semantics and behavior
* with DataReaders
*/
template <typename Data, typename Info>
class Selector {
public:
/**
* @brief Create a Selector for a TypedInput.
*
* Selectors are created with the default filter state of the TypedInput.
*
* @param[in] input
* The TypedInput that this Selector is attached to.
*/
Selector(const rti::routing::processor::TypedInput<Data, Info> input)
: typed_input_(input), query_(dds::core::null)
{
}
/**
* @brief Copy constructor
*/
Selector(const Selector& other)
: typed_input_(other.typed_input_),
state_(other.state_),
query_(other.query_)
{
}
/**
* @brief Select a specific dds::sub::status::DataState.
*
* By setting the DataState, you can specify the state of the samples that
* should be read or taken. The DataState of a sample encapsulates the
* SampleState, ViewState, and InstanceState of a sample.
*
* @param[in] the_state
* The selected DataState
*
*/
Selector& state(
const dds::sub::status::DataState& the_state)
{
state_.state(the_state);
return *this;
}
/**
* @brief Choose to only read/take up to a maximum number of samples.
*
* @param[in] count
* The maximum number of samples to read/take.
*/
Selector& max_samples(
const int32_t count)
{
state_.max_samples(count);
return *this;
}
/**
* @brief Select a specific instance to read/take.
*
* This operation causes the subsequent read or take operation to access
* only samples belonging the single specified instance whose handle is
* \p the_handle.
*
* Upon successful completion, the data collection will contain samples all
* belonging to the same instance.
*
* The subsequent read/take may operation may fail if the InstanceHandle
* does not correspond to an existing data-object known to the TypedInput.
*
* @param[in] the_handle
* The handle of the instance to select
*
* @see rti::routing::adapter::SelectorState
* @see dds::sub::DataReader::Selector::instance
*/
Selector& instance(
const dds::core::InstanceHandle& the_handle)
{
state_.instance(the_handle);
return *this;
}
/**
* @brief Select the instance after a specific instance.
*
* This operation causes the subsequent read or take operation to
* access only samples belonging a single instance whose handle is
* considered 'next' after the provided InstanceHandle, \p the_handle.
*
* The accessed samples will all belong to the 'next' instance with
* InstanceHandle 'greater' than the specified previous handle that has
* available samples.
*
* The special value dds::core::InstanceHandle::nil() is guaranteed to be
* 'less than' any valid instance_handle. So the use of the parameter value
* previous_handle == dds::core::InstanceHandle::nil() will return the
* samples for the instance that has the smallest instance_handle among all
* the instances that contain available samples.
*
* Note that it is possible to call the
* dds::sub::next_instance(const dds::core::InstanceHandle& h) operation
* with a previous_handle that does not correspond to an instance currently
* managed by the underlying rti::routing::adapter::StreamReader.
*
* @param[in] the_handle
* The reference instance. The instance after this one will be
* selected.
*
* @see rti::routing::adapter::SelectorState
* @see dds::sub::DataReader::Selector::next_instance
*/
Selector& next_instance(
const dds::core::InstanceHandle& the_handle)
{
state_.next_instance(the_handle);
return *this;
}
/**
* @brief Select samples based on a content filter parameters.
*
* The effect of using this manipulator is that the subsequent read/take
* will filter the samples based on the dds::topic::Filter. If the
* Input has no samples that meet the constraints, the read/take will not
* return any data.
*
* This selection is applied in combination with the other settings of
* this Selector.
*
* @param[in] the_filter
*/
Selector& filter(
const dds::topic::Filter& the_filter)
{
state_.filter(the_filter);
return *this;
}
/**
* @brief Select samples based on a rti::routing::processor::Query.
*
* When passing a Query, the effect of calling this method is that the
* underlying rti::routing::adapter::StreamReader shall filter the samples
* based only on the Query's settings.
*
* Using this manipulator will always override the selection specified
* with Selector::filter, no matter the order in which operations are
* called. To reset this selection, you can call this operation passing
* dds::core::null.
*
* @param[in] the_query
* The Query to read/take with.
*/
Selector& query(const rti::routing::processor::Query& the_query)
{
query_ = the_query;
state_.content(the_query.delegate().get()->query_data_);
return *this;
}
/**
* @brief Take samples based on the state associated with this Selector.
*
* @note This operation will call rti::routing::adapter::StreamReader::take(SelectorState)
* on the underlying rti::routing::adapter::StreamReader.
*
* @throw std::exception
*
* @return rti::routing::processor::LoanedSamples
*/
LoanedSamples<Data, Info> take()
{
return typed_input_.take(state_);
}
/**
* @brief Read samples based on the state associated with this Selector.
*
* @note This operation will call rti::routing::adapter::StreamReader::read(SelectorState)
* on the underlying rti::routing::adapter::StreamReader.
*
* @throw std::exception
*
* @return rti::routing::processor::LoanedSamples
*/
LoanedSamples<Data, Info> read()
{
return typed_input_.read(state_);
}
private:
rti::routing::processor::TypedInput<Data, Info> typed_input_;
rti::routing::adapter::SelectorState state_;
rti::routing::processor::Query query_;
};
template <typename Data, typename Info>
struct create_data_from_input {
static Data get(TypedInput<Data, Info>& )
{
return Data();
}
};
template <typename Info>
struct create_data_from_input<dds::core::xtypes::DynamicData, Info> {
static dds::core::xtypes::DynamicData get(
TypedInput<dds::core::xtypes::DynamicData, Info>& input)
{
if (input->stream_info().type_info().type_representation_kind()
!= TypeRepresentationKind::DYNAMIC_TYPE) {
throw dds::core::PreconditionNotMetError(
"inconsistent data representation kind");
}
dds::core::xtypes::DynamicType *type_code =
static_cast<dds::core::xtypes::DynamicType *> (
input->stream_info().type_info().type_representation());
return dds::core::xtypes::DynamicData(*type_code);
}
};
template <typename Data, typename Info>
TypedInput<Data, Info>::TypedInput(Input *input)
: input_(input)
{
}
template <typename Data, typename Info>
const rti::routing::StreamInfo& TypedInput<Data, Info>::stream_info() const
{
return input_->stream_info_;
}
template <typename Data, typename Info>
const std::string& TypedInput<Data, Info>::name() const
{
return input_->name_;
}
template <typename Data, typename Info>
LoanedSamples<Data, Info> TypedInput<Data, Info>::take()
{
RTI_RoutingServiceLoanedSamples native_samples =
RTI_RoutingServiceLoanedSamples_INITIALIZER;
if (!RTI_RoutingServiceInput_take(
input_->native_,
&native_samples)) {
throw dds::core::Error("error taking samples from native input");
}
return LoanedSamples<Data, Info>(input_->native_, native_samples);
}
template <typename Data, typename Info>
LoanedSamples<Data, Info> TypedInput<Data, Info>::read()
{
RTI_RoutingServiceLoanedSamples native_samples =
RTI_RoutingServiceLoanedSamples_INITIALIZER;
if (!RTI_RoutingServiceInput_read(
input_->native_,
&native_samples)) {
throw dds::core::Error("error reading samples from native input");
}
return LoanedSamples<Data, Info>(input_->native_, native_samples);
}
template <typename Data, typename Info>
rti::routing::processor::Selector<Data, Info>
TypedInput<Data, Info>::select()
{
return rti::routing::processor::Selector<Data, Info>(*this);
}
template <typename Data, typename Info>
rti::routing::processor::Query TypedInput<Data, Info>::query(
const dds::topic::Filter& filter)
{
return rti::routing::processor::Query(input_->native_, filter);
}
template <typename Data, typename Info>
LoanedSamples<Data, Info> TypedInput<Data, Info>::take(
const rti::routing::adapter::SelectorState& selector_state)
{
RTI_RoutingServiceLoanedSamples native_samples =
RTI_RoutingServiceLoanedSamples_INITIALIZER;
if (!RTI_RoutingServiceInput_take_w_selector(
input_->native_,
&native_samples,
&selector_state.native())) {
throw dds::core::Error("error taking samples with selector from native input");
}
return LoanedSamples<Data, Info>(input_->native_, native_samples);
}
template <typename Data, typename Info>
LoanedSamples<Data, Info> TypedInput<Data, Info>::read(
const rti::routing::adapter::SelectorState& selector_state)
{
RTI_RoutingServiceLoanedSamples native_samples =
RTI_RoutingServiceLoanedSamples_INITIALIZER;
if (!RTI_RoutingServiceInput_read_w_selector(
input_->native_,
&native_samples,
&selector_state.native())) {
throw dds::core::Error("error reading samples with selector from native input");
}
return LoanedSamples<Data, Info>(input_->native_, native_samples);
}
template <typename Data, typename Info>
bool TypedInput<Data, Info>::active()
{
return RTI_RoutingServiceInput_is_active(input_->native_) ? true : false;
}
template <typename Data, typename Info>
Data TypedInput<Data,Info>::create_data()
{
return create_data_from_input<Data, Info>::get(*this);
}
/**
* @brief Convenient definition of a TypedInput whose data representation
* is DynamicData and info representation is dds::sub::SampleInfo.
*
* These data and info representations are expected be used by most of the
* rti::routing::adapter::StreamReader implementations.
*/
typedef TypedInput<dds::core::xtypes::DynamicData> DynamicDataInput;
typedef dds::sub::DataReader<dds::core::xtypes::DynamicData> DynamicDataReader;
} } }
#endif // RTI_ROUTING_PROCESSOR_INPUT_HPP_
@@ -0,0 +1,130 @@
/* $Id$
(c) Copyright, Real-Time Innovations, 2015-2016.
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_LOANED_SAMPLE_HPP_
#define RTI_ROUTING_PROCESSOR_LOANED_SAMPLE_HPP_
#include <exception>
namespace rti { namespace routing { namespace processor {
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::LoanedSample
*
* @brief
*/
template <typename T, typename U>
class LoanedSample
{
public:
/**
* @brief The data type
*/
typedef T DataType;
/**
* @brief The info type
*/
typedef U InfoType;
LoanedSample()
: _data_ptr(NULL),
_info_ptr(NULL)
{}
LoanedSample(const DataType * the_data, const InfoType * the_info)
: _data_ptr(the_data),
_info_ptr(the_info)
{}
LoanedSample(const void * the_data, const void * the_info)
: _data_ptr(static_cast<const T*>(the_data)),
_info_ptr(static_cast<const U*>(the_info))
{}
const DataType & data() const
{
if (_info_ptr != NULL && !info().valid()) {
throw dds::core::PreconditionNotMetError("Invalid data");
}
return *_data_ptr;
}
/**
* @brief Gets the sample info
*/
const InfoType & info() const {
if (_info_ptr == NULL) {
throw dds::core::PreconditionNotMetError(
"Sample Info not available");
}
return *_info_ptr;
}
operator const DataType & () const
{
return data();
}
LoanedSample<DataType, InfoType> * operator ->() {
return this;
}
const LoanedSample<DataType, InfoType> * operator ->() const {
return this;
}
/**
* @brief Compares the data and info
*/
bool operator==(const LoanedSample& other) const
{
if (info() != other.info()) {
return false;
}
if (info().valid()) {
if (data() != other.data()) {
return false;
}
}
return true;
}
bool operator!=(const LoanedSample& other) const
{
return !(*this == other);
}
void swap(LoanedSample & other) throw()
{
using std::swap;
swap(_data_ptr, other._data_ptr);
swap(_info_ptr, other._info_ptr);
}
private:
const DataType * _data_ptr;
const InfoType * _info_ptr;
};
} } }
#endif // RTI_ROUTING_PROCESSOR_LOANED_SAMPLE_HPP_
@@ -0,0 +1,306 @@
/* $Id$
(c) Copyright, Real-Time Innovations, 2013-2016.
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_LOANED_SAMPLES_HPP_
#define RTI_ROUTING_PROCESSOR_LOANED_SAMPLES_HPP_
#include <utility> // std::move
#include <iterator>
#include "routingservice/routingservice_adapter_new.h"
#include <dds/core/types.hpp>
#include <rti/routing/processor/LoanedSample.hpp>
#include <rti/routing/adapter/StreamReader.hpp>
#include <rti/routing/processor/SampleIterator.hpp>
namespace rti { namespace routing { namespace processor {
template <typename T, typename U> class TypedInput;
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::LoanedSamples
*
* @brief Provides temporary access to a collection of samples (data and info)
* from a TypedInput.
*
* @tparam T The sample data type representation. It has to match the type of
* the underlying rti::routing::adapter::StreamReader of the TypedInput.
*
* @tparam U The sample info type representation. It has to match the type of
* the underlying rti::routing::adapter::StreamReader of the TypedInput.
*
* This STL-like container encapsulates a collection of loaned, read-only data
* samples rti::sub::LoanedSample::data() and
* rti::sub::LoanedSample::info() from a TypedInput.
*
* To obtain a LoanedSamples, you need to call one of the read/take operations
* from a TypedInput. The samples have to be eventually returned to the
* TypedInput by calling rti::routing::adapter::StreamReader::return_loan on
* the underlying rti::routing::adapter::StreamReader of the TypedInput. The
* destructor takes care of that, and the return_loan() function lets you do
* it explicitly if needed.
*
* As a move-only type, copying a LoanedSamples is not allowed. If you need
* to return a LoanedSamples from a function or assign it to another variable,
* use \p dds::core::move() (or \p std::move() for C++11).
*
* Iterators and overloaded subscript operators let you access the samples
* in this container, which are of the type rti::routing::processor::LoanedSample.
*
* This code demonstrates how to access the info and data of each sample in
* a DataReader:
*
* \code
* auto samples = reader.take();
* for (const auto& sample : samples) {
* if (sample.info().valid()) {
* std::cout << sample.data() << std::endl;
* }
* }
* \endcode
*
* @see dds::sub::LoanedSamples
*
*/
template <typename T, typename U = dds::sub::SampleInfo>
class LoanedSamples {
public:
typedef rti::routing::adapter::StreamReader StreamReader;
typedef typename std::vector<StreamReader::SamplePtr> SampleSeqType;
typedef typename std::vector<StreamReader::InfoPtr> InfoSeqType;
/**
* @brief The iterator type
*/
typedef SampleIterator<T, U> iterator;
typedef SampleIterator<T, U> const_iterator;
typedef typename SampleIterator<T, U>::value_type value_type;
typedef std::ptrdiff_t difference_type;
/**
* @brief Creates an empty LoanedSamples object.
*/
LoanedSamples() : input_(NULL)
{
native_samples_.data_array = NULL;
native_samples_.info_array = NULL;
native_samples_.length = 0;
}
public:
// Private c-tor only to be used by static method create_from_loans()
LoanedSamples(
RTI_RoutingServiceInput *native_input,
RTI_RoutingServiceLoanedSamples& native_samples)
: input_(native_input),
native_samples_(native_samples)
{
}
public:
/**
* @brief Automatically returns the loan to the TypedInput used
* to obtained these samples.
*
* @see return_loan
*/
~LoanedSamples() throw()
{
try {
return_loan();
} catch (const std::exception&) { // Do not throw in destructor
}
}
/**
* @brief Provides access to the underlying LoanedSample object in
* array-like syntax.
*
* @param[in] index
* The index of the Sample. Allowed values are from 0 to length()-1.
*
* @return A LoanedSample object that refers to data and info
* at the specified \p index.
*/
LoanedSample<T,U> operator [] (size_t index)
{
return native_samples_.info_array == NULL
? LoanedSample<T, U>(native_samples_.data_array[index], NULL)
: LoanedSample<T, U>(
native_samples_.data_array[index],
native_samples_.info_array[index]);
}
/**
* @brief Gets the number of samples in this collection
*/
int32_t length() const
{
return native_samples_.length;
}
/**
* @brief Returns the samples to the TypedInput used to get these
* samples.
*
* Thes operation returns the samples by calling the
* \link rti::routing::adapter::StreamReader::return_loan return_loan\endlink
* operation on the underlying rti::routing::stream::StreamReader of the
* TypedInput.
*
* @note Explicitly calling return_loan is optional, since the
* destructor does it implicitly.
*
* This operation tells the TypedInput that the application
* is done accessing the collection of samples.
*
* It is not necessary for an application to return the loans immediately
* after the call to read or take. However, as these buffers correspond to
* internal resources, the application should not retain them indefinitely.
*
* @throw std::exception
* If there was an error returning the loan to the TypedInput.
*/
void return_loan()
{
if (input_) {
if (!RTI_RoutingServiceInput_return_loan(
input_,
&native_samples_)) {
throw dds::core::Error("error returning loaned samples to native input");
}
input_ = NULL; // Indicate that this object doesn't hold a loan anymore
}
}
/**
* @brief Returns whether the Info part is available for each Data item of
* this set of loaned samples.
*/
bool has_infos()
{
return (native_samples_.info_array != NULL);
}
/**
* @brief Gets an iterator to the first sample
*/
iterator begin()
{
return iterator(
native_samples_.data_array,
native_samples_.info_array,
native_samples_.length);
}
/**
* @brief Gets an iterator to one past the last sample
*/
iterator end()
{
return iterator(
native_samples_.data_array,
native_samples_.info_array,
native_samples_.length,
native_samples_.length);
}
/**
* @brief Gets an iterator to the first sample
*/
const_iterator begin() const
{
return const_iterator(
native_samples_.data_array,
native_samples_.info_array,
native_samples_.length);
}
/**
* @brief Gets an iterator to one past the last sample
*/
const_iterator end() const
{
return const_iterator(
native_samples_.data_array,
native_samples_.info_array,
native_samples_.length,
native_samples_.length);
}
/**
* @brief Swaps two LoanedSamples containers
*/
void swap(LoanedSamples& other) throw()
{
std::swap(input_, other.input_);
std::swap(native_samples_, other.native_samples_);
}
LoanedSamples(LoanedSamples&& other)
:input_(NULL)
{
native_samples_.data_array = NULL;
native_samples_.info_array = NULL;
native_samples_.length = 0;
other.swap(*this);
}
LoanedSamples& operator= (LoanedSamples&& other) throw ()
{
// clean up existing values
LoanedSamples temp(std::move(other));
temp.swap(*this);
return *this;
}
private:
friend class TypedInput<T, U>;
void release()
{
input_ = NULL;
}
RTI_RoutingServiceLoanedSamples& native_samples()
{
return native_samples_;
}
private:
// reference to the reader that created this LoanedSamples object
RTI_RoutingServiceInput *input_;
RTI_RoutingServiceLoanedSamples native_samples_;
};
template <typename T, typename U>
LoanedSamples<T, U> move(LoanedSamples<T,U> & ls) OMG_NOEXCEPT
{
return std::move(ls);
}
} } }
#endif // RTI_ROUTING_PROCESSOR_LOANED_SAMPLES_HPP_
@@ -0,0 +1,326 @@
/*
* (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_OUTPUT_HPP_
#define RTI_ROUTING_PROCESSOR_OUTPUT_HPP_
#include <dds/core/Value.hpp>
#include <dds/core/SafeEnumeration.hpp>
#include <rti/core/NativeValueType.hpp>
#include <dds/pub/DataWriter.hpp>
#include <dds/core/xtypes/DynamicData.hpp>
#include "routingservice/routingservice_processor.h"
#include "routingservice/routingservice_adapter_new.h"
#include <rti/routing/adapter/StreamWriter.hpp>
namespace rti { namespace routing { namespace processor {
class Route;
template <typename Data, typename Info> class TypedOutput;
template <typename Data, typename Info = dds::sub::SampleInfo>
class TypedOutput;
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::Output
*
* @brief Generic Representation of a Route's output.
*
* This class provides a base representation of the outputs contained in a Route.
* Since it is generic, this object does not allow performing any operation
* that requires dealing with the data passed to the underlying
* rti::routing::adapter::StreamWriter.
*/
class Output {
public:
/*i
*/
Output(
RTI_RoutingServiceOutput *native,
int32_t index,
RTI_RoutingServiceRoute *native_route) :
native_(native),
index_(index),
native_route_(native_route),
stream_info_(*RTI_RoutingServiceOutput_get_stream_info(native)),
name_(RTI_RoutingServiceOutput_get_name(native))
{
}
/*i
*/
const rti::routing::StreamInfo& stream_info() const
{
return stream_info_;
}
/*i
*
*/
const std::string& name() const
{
return name_;
}
/*i
*
*/
int32_t index()
{
return index_;
}
/**
* @brief Returns a typed version of this Output.
*
* Note: This operation is not type-safe and it is the caller's
* responsibility to use the appropriate type.
*
* @see TypedOutput
* @see <tt>TypedOutput<DataRep, Info> Route<DataRep, InfoRep>::output(int32_t index)</tt>
*/
template <typename Data, typename Info>
TypedOutput<Data, Info> get()
{
return this;
}
/**
* @brief Returns a typed version of this Output.
*
* Note: This operation is not type-safe and it is the caller's
* responsibility to use the appropriate type.
*
* @see TypedOutput
* @see TypedOutput<tt><DataRep, dds::sub::SampleInfo></tt> Route<DataRep>::output(int32_t index)
*/
template <typename Data>
TypedOutput<Data, dds::sub::SampleInfo> get()
{
return this;
}
private:
template <typename Data, typename Info> friend class TypedOutput;
friend class Route;
RTI_RoutingServiceOutput *native_;
int32_t index_;
RTI_RoutingServiceRoute *native_route_;
rti::routing::StreamInfo stream_info_;
std::string name_;
};
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::TypedOutput
*
* @brief Representation of an Output whose data representation is \p DataRep,
* whose info representation is \p InfoRep.
*
*/
template <typename Data, typename Info>
class TypedOutput{
public:
TypedOutput(Output *output) ;
TypedOutput<Data, Info>* operator->();
/**
* @brief Returns the StreamInfo associated with this object.
*
* The associated StreamInfo represents an equivalent object to the one
* used to create the underlying rti::routing::adapter::StreamWriter.
*/
const rti::routing::StreamInfo& stream_info() const;
/**
* @brief Returns the name of this output.
*
* The name is given by the name of the corresponding XML configuration tag.
*/
const std::string& name() const;
/**
* @brief Writes the specified data and info sample in this output.
*
* This operation will call rti::routing::adapter::StreamWriter::write on
* the underlying rti::routing::adapter::StreamWriter.
*
* The provided sample is interpreted to contain data represented
* as \c Data and the info as \c Info.
*
* @see rti::routing::adapter::StreamWriter::write
*/
void write(const Data& sample, const Info& info);
/*
* @brief Writes a sample given its data only.
*
* This operation will call rti::routing::adapter::StreamWriter::write
* on the underlying rti::routing::adapter::StreamWriter, providing a null
* value for the info sample. The underlying adapter will compute any
* associated metadata from the data sample.
*/
void write(const Data& sample);
/**
* @brief Creates a new data sample that can be used to write in this
* output.
*
* The data constructor called in this operation depends on the data
* representation kind of the TypeInfo associated with this output.
* If the type representation is a dynamic type, then it will assume
* the following constructor:
* \code Data(const dds::core::xtypes::DynamicType&) \endcode
*
* and will use the type code object downcasted from the value
* returned by TypeInfo::type_representation.
*
* Otherwise:
* \code Data() \endcode
*
* @return A new data sample
*/
Data create_data();
/**
* @brief Returns the underlying DDS DataWriter that is part of this
* StreamWriter implementation, assuming this input holds a DDS StreamWriter.
*
* This operation will throw an exception if this output does not hold a
* DDS StreamWriter.
*
* @note The access to the underlying DataWriter is allowed only as long as
* this Output remains enabled. The object representing the DataWriter
* must be invalidated before the output is disabled, otherwise the behavior
* is undefined.
*
* @throw std::exception
*
* @return dds::pub::DataWriter<Data>
*/
dds::pub::DataWriter<Data> dds_data_writer()
{
DDS_DataWriter *native_writer =
RTI_RoutingServiceOutput_get_dds_writer(output_->native_);
if (native_writer == NULL) {
throw dds::core::InvalidArgumentError(
"invalid argument: input does not hold a DDS StreamWriter");
}
typedef dds::pub::DataWriter<Data> data_writer_type;
return rti::core::detail::create_from_native_entity<data_writer_type>(
native_writer);
}
private:
friend class rti::routing::processor::Route;
Output *output_;
};
template <typename Data, typename Info>
struct create_data_from_output {
static Data get(TypedOutput<Data, Info>& )
{
return Data();
}
};
template <typename Info>
struct create_data_from_output<dds::core::xtypes::DynamicData, Info> {
static dds::core::xtypes::DynamicData get(TypedOutput<dds::core::xtypes::DynamicData, Info>& output)
{
if (output->stream_info().type_info().type_representation_kind()
!= TypeRepresentationKind::DYNAMIC_TYPE) {
throw dds::core::PreconditionNotMetError(
"inconsistent data representation kind");
}
dds::core::xtypes::DynamicType *type_code =
static_cast<dds::core::xtypes::DynamicType *> (
output->stream_info().type_info().type_representation());
return dds::core::xtypes::DynamicData(*type_code);
}
};
template <typename Data, typename Info>
TypedOutput<Data,Info>::TypedOutput(Output* output) : output_(output)
{
}
template <typename Data, typename Info>
const rti::routing::StreamInfo& TypedOutput<Data, Info>::stream_info() const
{
return output_->stream_info_;
}
template <typename Data, typename Info>
const std::string& TypedOutput<Data, Info>::name() const
{
return output_->name_;
}
template <typename Data, typename Info>
TypedOutput<Data, Info>* TypedOutput<Data,Info>::operator->()
{
return this;
}
template <typename Data, typename Info>
void TypedOutput<Data, Info>::write(const Data& sample, const Info& info)
{
if (!RTI_RoutingServiceOutput_write_sample(
output_->native_,
const_cast<void *> (reinterpret_cast<const void*> (&sample)),
const_cast<void *> (reinterpret_cast<const void*> (&info)))) {
throw dds::core::Error("error writing sample to native output");
}
}
template <typename Data, typename Info>
void TypedOutput<Data,Info>::write(const Data& sample)
{
if (!RTI_RoutingServiceOutput_write_sample(
output_->native_,
const_cast<void *> (reinterpret_cast<const void*> (&sample)),
NULL)) {
throw dds::core::Error("error writing sample to native output");
}
}
template <typename Data, typename Info>
Data TypedOutput<Data,Info>::create_data()
{
return create_data_from_output<Data, Info>::get(*this);
}
/**
* @brief Convenient definition of a TypedOutput whose data representation
* is DynamicData and info representation is dds::sub::SampleInfo.
*
* These data and info representations are expected be used by most
* rti::routing::adapter::StreamWriter implementations.
*/
typedef TypedOutput<dds::core::xtypes::DynamicData> DynamicDataOutput;
typedef dds::pub::DataWriter<dds::core::xtypes::DynamicData> DynamicDataWriter;
} } }
#endif // RTI_ROUTING_PROCESSOR_OUTPUT_HPP_
@@ -0,0 +1,202 @@
/*
* (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_PORTS_ITERATOR_HPP_
#define RTI_ROUTING_PROCESSOR_PORTS_ITERATOR_HPP_
#include <dds/core/Value.hpp>
#include <dds/core/SafeEnumeration.hpp>
#include <rti/core/NativeValueType.hpp>
#include <dds/core/xtypes/DynamicData.hpp>
#include <dds/sub/SampleInfo.hpp>
#include <rti/routing/processor/Input.hpp>
#include <rti/routing/processor/Output.hpp>
namespace rti { namespace routing { namespace processor {
template <typename PORT, typename DataRep, typename InfoRep> struct TypedPortType;
template <typename DataRep, typename InfoRep>
struct TypedPortType<Input, DataRep, InfoRep>
{
typedef TypedInput<DataRep, InfoRep> type;
typedef RTI_RoutingServiceInput native_type;
static native_type * begin(RTI_RoutingServiceRoute *native_route)
{
return RTI_RoutingServiceRoute_get_first_input(native_route);
}
static native_type * next(
RTI_RoutingServiceRoute *native_route,
native_type *native)
{
return RTI_RoutingServiceRoute_get_next_input(native_route, native);
}
static Input* from_native(native_type *native)
{
return static_cast<Input*>(RTI_RoutingServiceInput_get_user_data(
native));
}
};
template <typename DataRep, typename InfoRep>
struct TypedPortType<Output, DataRep, InfoRep>
{
typedef TypedOutput<DataRep, InfoRep> type;
typedef RTI_RoutingServiceOutput native_type;
static native_type * begin(RTI_RoutingServiceRoute *native_route)
{
return RTI_RoutingServiceRoute_get_first_output(native_route);
}
static native_type * next(
RTI_RoutingServiceRoute *native_route,
native_type *native)
{
return RTI_RoutingServiceRoute_get_next_output(native_route, native);
}
static Output* from_native(native_type *native)
{
return static_cast<Output*>(RTI_RoutingServiceOutput_get_user_data(
native));
}
};
template <typename PORT,
typename DataRep,
typename InfoRep = dds::sub::SampleInfo>
class PortIterator {
public:
// iterator traits
typedef std::random_access_iterator_tag iterator_category;
typedef typename TypedPortType<PORT, DataRep, InfoRep>::type value_type;
typedef value_type reference;
typedef value_type pointer;
typedef std::ptrdiff_t difference_type;
explicit PortIterator(
RTI_RoutingServiceRoute *native_route)
: native_route_(native_route)
{
native_ = TypedPortType<PORT, DataRep, InfoRep>::begin(native_route);
}
explicit PortIterator()
: native_route_(NULL), native_(NULL)
{
}
PortIterator (const PortIterator<PORT, DataRep, InfoRep>& other)
: native_route_(other.native_route_),
native_(other.native_)
{}
PortIterator & operator = (const PortIterator<PORT, DataRep, InfoRep>& other)
{
native_route_ = other.native_route_;
native_ = other.native_;
return *this;
}
value_type operator*()
{
return TypedPortType<PORT, DataRep, InfoRep>::from_native(native_);
}
value_type operator->()
{
return *(*this);
}
PortIterator & operator++()
{
native_ = TypedPortType<PORT, DataRep, InfoRep>::next(
native_route_,
native_);
return *this;
}
PortIterator operator++(int)
{
PortIterator temp(*this);
++(*this);
return temp;
}
friend bool operator<(
const PortIterator & s1,
const PortIterator & s2)
{
return s1.index() < s2.index();
}
friend bool operator>(
const PortIterator & s1,
const PortIterator & s2)
{
return s1.index() > s2.index();
}
friend bool operator<=(
const PortIterator & s1,
const PortIterator & s2)
{
return s1.index() <= s2.index();
}
friend bool operator>=(
const PortIterator & s1,
const PortIterator & s2)
{
return s1.index() >= s2.index();
}
friend bool operator==(
const PortIterator & s1,
const PortIterator & s2)
{
return (s1.index() == s2.index());
}
friend bool operator!=(
const PortIterator & s1,
const PortIterator & s2)
{
return !(s1 == s2);
}
private:
int32_t index() const
{
return (native_ == NULL)
? RTI_INT32_MAX
: TypedPortType<PORT, DataRep, InfoRep>::from_native(native_)->index();
}
RTI_RoutingServiceRoute *native_route_;
typename TypedPortType<PORT, DataRep, InfoRep>::native_type *native_;
};
} } }
#endif // RTI_ROUTING_PROCESSOR_PORTS_ITERATOR_HPP_
@@ -0,0 +1,397 @@
/*
* (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_PROCESSOR_HPP_
#define RTI_ROUTING_PROCESSOR_PROCESSOR_HPP_
#include <dds/core/Value.hpp>
#include <dds/core/SafeEnumeration.hpp>
#include <rti/core/NativeValueType.hpp>
#include "routingservice/routingservice_processor.h"
#include <rti/routing/processor/Route.hpp>
#include <rti/routing/UpdatableEntity.hpp>
namespace rti { namespace routing { namespace processor {
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::Processor
*
* @brief Processor interface definition. Provides a way to process Route events
* and control the data forwarding process.
*
* A Processor receives event notifications from its Route owner in the form of
* operation callbacks. Each event occurrence will be dispatched to the Processor
* by calling the corresponding method.
*
* Each dispatching method has a signature according to the event kind and data
* it is associated with. Each event is associated with a Route state; hence
* limitations and constraints may apply individually to each method.
*
* Note that throwing an exception while processing any of the
* event notifications is allowed. In this situation, the Route owner will
* reject the events and none of the associated post conditions will be applied,
* including state transitions.
*
* @mtsafety Partially Safe
* All operations on a concrete Processor object are safe and
* always serialized on a given Session. Operations on different
* Processor objects may be called concurrently if they belong
* to different Routes.
*
* @see ProcessorPlugin
* @see Route
*/
class Processor : public rti::routing::UpdatableEntity {
public:
/**
* @brief Notification of the \c INPUT_ENABLED event.
*
* This operation is called when an Input enabled event occurs that
* affects any of the inputs contained in the owner Route.
*
* This operation is called right after the affected Input has been enabled.
*
* A running Routing Service instance will produce a log indicating the occurrence
* of the event. For example:
*
* \code
* [.../sessions/Session/routes/Route/inputs/Input1|ENABLE] stream=Example
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
* @param[in] input
* The just enabled Input.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p input
* to be automatically disabled right after.
*/
virtual void on_input_enabled(
Route& route,
rti::routing::processor::Input& input) = 0;
/**
* @brief Notification of the Input disabled event.
*
* This operation is called when an \c INPUT_DISABLED event occurs that
* affects any of the inputs contained in the owner Route.
*
* This operation is called right before the affected Input is disabled.
*
* A running Routing Service instance will produce a log indicating the occurrence
* of the event. For example:
*
* \code
* [.../sessions/Session/routes/Route/inputs/Input1|DISABLE] stream=Example
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
* @param[in] input
* The Input about to be disabled.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p input
* to remain enabled.
*/
virtual void on_input_disabled(
Route& route,
rti::routing::processor::Input& input) = 0;
/**
* @brief Notification of the Output enabled event.
*
* This operation is called when an \c OUTPUT_DISABLED event occurs that
* affects any of the outputs contained in the owner Route.
*
* This operation is called right after the affected Output has been enabled.
*
* A running Routing Service instance will produce a log indicating the occurrence
* of the event. For example:
*
* \code
* [.../sessions/Session/routes/Route/outputs/Output1|ENABLE] stream=Example
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
* @param[in] output
* The just enabled output.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p output
* to be automatically disabled right after.
*/
virtual void on_output_enabled(
Route& route,
rti::routing::processor::Output& output) = 0;
/**
* @brief Notification of the Output disabled event.
*
* This operation is called when an \c OUTPUT_DISABLED event occurs that
* affects any of the outputs contained in the owner Route.
*
* This operation is called right before the affected Output is disabled.
*
* A running Routing Service instance will produce a log indicating the occurrence
* of the event. For example:
*
* \code
* [.../sessions/Session/routes/Route/outputs/Output1|DISABLE] stream=Example
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
* @param[in] output
* The Output about to be disabled.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p output
* to remain enabled.
*/
virtual void on_output_disabled(
Route& route,
rti::routing::processor::Output& output) = 0;
/**
* @brief Notification of the Route started event.
*
* This operation is called right before the Route enters the \c STARTED
* state. At the time this operation is called, all the inputs and outputs
* within the Route are enabled.
*
* A running Routing Service instance will produce a log indicating the
* occurrence of the event. For example:
* \code
* [.../domain_routes/DomainRoute/sessions/Session/routes/Route|START]
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p route
* to remain \c STOPPED.
*/
virtual void on_start(Route& route) = 0;
/**
* @brief Notification of the Route stopped event.
*
* This operation is called right before the Route enters the \c STOPPED
* state. At the time this operation is called, all the inputs and outputs
* within the Route are still enabled.
*
* A running Routing Service instance will produce a log indicating the
* occurrence of the event. For example:
* \code
* [.../domain_routes/DomainRoute/sessions/Session/routes/Route|STOP]
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p route
* to remain \c STARTED.
*
*/
virtual void on_stop(Route& route) = 0;
/**
* @brief Notification of the Route \c RUN event.
*
* This operation is called right before the Route enters the \c RUNNING
* state. This operation is called after the Route went to \c STARTED after
* a successful notification to this Processor,
*
* \note
* If the Route was manually paused before via an Administration call, this
* operation will not be called until a manual run operation is performed.
*
* A Routing Service running instance will produce a log indicating the occurrence
* of the event. For example:
* \code
* [.../domain_routes/DomainRoute/sessions/Session/routes/Route|RUN]
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p route
* to remain \c PAUSED.
*
*/
virtual void on_run(Route& route) = 0;
/**
* @brief Notification of the Route stopped event.
*
* This operation is called right before the Route enters the \c PAUSED
* state. At the time this operation is called, all the inputs and outputs
* within the Route are still enabled.
*
* A Routing Service running instance will produce a log indicating the occurrence
* of the event. For example:
* \code
* [.../domain_routes/DomainRoute/sessions/Session/routes/Route|PAUSE]
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p route
* to remain \c RUNNING.
*
*/
virtual void on_pause(Route& route) = 0;
/**
* @brief Notification of the Route periodic action event.
*
* This operation is called periodically at the rate specified in the parent
* Session of the Route owner.
*
* Periodic notifications can occur only while the Route is in the \c RUNNING
* state.
*
* Implementations are allowed to access any of the Input and Output of the
* owner Route to read and write data, respectively.
*
* A Routing Service running instance will produce a log indicating the occurrence
* of the event. For example:
* \code
* [.../domain_routes/DomainRoute/sessions/Session/routes/Route] process event=PERODIC_ACTION
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
*
* @throw std::exception
* Throwing an error in this operation will produce a log message
* without affecting the Route state and notifications of this event
* to this Processor will keep occurring.
*/
virtual void on_periodic_action(Route& route) = 0;
/**
* @brief Notification of the Route \c DATA_AVAILABLE event
*
* This operation is called each time any of the inputs contained in the
* owner Route is notified about new data. Notifications of this event can
* occur only while the Route is in the \c RUNNING state.
*
* Implementations are allowed to access any of the Input and Output of the
* owner Route to read and write data, respectively.
*
* A running Routing Service instance will produce a log indicating the
* occurrence of the event. For example:
* \code
* [.../domain_routes/DomainRoute/sessions/Session/routes/Route] process event=DATA_ON_INPUTS
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
*
* @throw std::exception
* Throwing an error in this operation will produce a log message
* without affecting the Route state and notifications of this event
* to this Processor will keep occurring.
*
*/
virtual void on_data_available(Route& route) = 0;
/**
* @brief Virtual destructor
*/
virtual ~Processor() {}
};
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::NoOpProcessor
*
* @brief An empty implementation of the pure virtual interface
* rti::routing::processor::Processor.
*
* Your Processor implementation can inherit from this class and override
* just the methods that are of interest.
*/
class NoOpProcessor : public Processor {
virtual void on_input_enabled(Route&, rti::routing::processor::Input&)
{
}
virtual void on_input_disabled(Route&, rti::routing::processor::Input&)
{
}
virtual void on_output_enabled(Route&, rti::routing::processor::Output&)
{
}
virtual void on_output_disabled(Route&, rti::routing::processor::Output&)
{
}
virtual void on_start(Route&)
{
}
virtual void on_stop(Route&)
{
}
virtual void on_run(Route&)
{
}
virtual void on_pause(Route&)
{
}
virtual void on_data_available(Route&)
{
}
virtual void on_periodic_action(Route&)
{
}
};
} } }
#endif // RTI_ROUTING_PROCESSOR_PROCESSOR_HPP_
@@ -0,0 +1,389 @@
/*
* (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_PROCESSOR_PLUGIN_HPP_
#define RTI_ROUTING_PROCESSOR_PROCESSOR_PLUGIN_HPP_
#include "routingservice/routingservice_log.h"
#include <rti/config/Version.hpp>
#include <rti/routing/PropertySet.hpp>
#include <rti/routing/processor/Route.hpp>
#include <rti/routing/processor/Processor.hpp>
/** @file
* @brief \product C++ Processor API
*/
/** @defgroup RTI_RoutingServiceProcessorModule RTI Routing Service Processor API
* @ingroup ROUTER
* @brief This module describes the Processor API.
*
* @product rti::routing::processor::Processor are **event-oriented pluggable
* components** that allow you to control the forwarding process that occur within a Route.
*
* ## Development Requirements
*
* | | Linux/macOS Systems | Windows Systems |
* | --------------: | :----------------: | :-------------: |
* | Shared Libraries| librtiroutingservice.so | librtiroutingservice.lib |
* | ^ | librtirsinfrastructure.so | rtirsinfrastructure.lib |
* | ^ | libnddscpp2.so | nddscpp2.lib |
* | ^ | libnddsc.so | nddsc.lib |
* | ^ | libnddscore.so | nddscore.lib |
* | Headers | rti/routing/processor/ProcessorPlugin.hpp ||
*
* ## Architecture
*
* A rti::routing::processor::Processor represents a multiple-input,
* multiple-output component attached to a rti::routing::processor::Route,
* which dispatches events to the rti::routing::processor::Processor.
* The figure below shows the role of a rti::routing::processor::Processor within
* @product.
*
* \htmlonly <div style="margin:auto;width:700px;">\endhtmlonly
* \image html RouterProcessorComponent.svg "Overview of a Processor component in @product" width=700px
* \htmlonly </div>\endhtmlonly
*
* A Processor can access the *N* inputs and *M* outputs of the owner Route.
* Upon event notification, the Processor can read data from any input,
* perform any manipulation on the data, and write it on any of the outputs.
*
* Note in the figure above that any data a Processor writes on an output is
* first transformed with an rti::routing::transf::Transformation before passing
* it to the underlying rti::routing::adapter::StreamWriter.
*
* An example snippet is shown below. The example code is reading data from
* two inputs, merging it together in an intermediate data buffer and writing
* into a single output.
*
* \code{.cpp}
* on_data_available(Route& route)
* {
* auto output = route.output<DynamicData>(0);
* auto output_sample = output.create_data();
* for(const auto& status : route.input<DynamicData>(0).take()) {
* auto periodic = route.input<DynamicData>(1)
* .select().instance(status.info().instance_handle()).read();
* output_sample.value<int>(
* "id",
* status.data().get<int>("id"));
* output_sample.value<int>(
* "config",
* status.data().get<string>("config"));
* output_sample.value<int>(
* "latency",
* periodic[0].data().get<int>("latency"));
* output.write(output_sample);
* }
* }
* \endcode
*
* The Processor API component model is shown in figure below.
*
* \htmlonly <div style="margin:auto;width:800px;">\endhtmlonly
* \image html RouterProcessorClass.svg "Processor API component model" width=800px
* \htmlonly </div>\endhtmlonly
*
* * rti::routing::processor::Processor
* * rti::routing::processor::Route
* * rti::routing::processor::Input
* * rti::routing::processor::Output
* * rti::routing::processor::Selector
*
* ## Event dispatching
*
* A rti::routing::processor::Route will notify its contained
* rti::routing::processor::Processor about the events that affect the Route
* object. Each event kind maps to a virtual operation in the
* rti::routing::processor::Processor interface:
*
* * **Input Enabled**: Event that represents the transition from disables to
* enabled on any of the contained rti::routing::processor::Input. Enabling
* an Input results in the creation of the underlying
* rti::routing::adapter::StreamReader.
* This event is notified through rti::routing::processor::Processor::on_input_enabled.
*
* * **Input Disabled**: Event that represents the transition from enabled to
* disabled on any of the contained rti::routing::processor::Input. Disabling
* an Input results in the deletion of the underlying
* rti::routing::adapter::StreamReader.
* This event is notified through rti::routing::processor::Processor::on_input_disabled.
*
* * **Output Enabled**: Event that represents the transition from disabled to
* enabled on any of the contained rti::routing::processor::Output. Enabling
* an Output results in the creation of the underlying
* rti::routing::transf::Transformation and rti::routing::adapter::StreamWriter.
* This event is notified through rti::routing::processor::Processor::on_output_enabled.
*
* * **Output Disabled**: Event that represents the transition from enabled to
* disabled on any of the contained rti::routing::processor::Output. Disabling
* an Output results in the deletion of the underlying
* rti::routing::transf::Transformation and rti::routing::adapter::StreamWriter.
* This event is notified through rti::routing::processor::Processor::on_output_disabled.
*
* * **Route Started**: This event indicates that the owner
* rti::routing::processor::Route has enabled all inputs and outputs.
* This event is notified through rti::routing::processor::Processor::on_start.
*
* * **Route Stopped**: This event indicates that the owner
* rti::routing::processor::Route is about to disable at least one of its
* inputs or outputs.
* This event is notified through rti::routing::processor::Processor::on_stop.
*
* * **Route Running**: This event indicates that the owner
* rti::routing::processor::Route is ready to provide user event
* notifications.
* This event is notified through rti::routing::processor::Processor::on_run.
*
* * **Route Paused**: This event indicates that the owner
* rti::routing::processor::Route will temporarily stop providing user
* event notifications.
* This event is notified through rti::routing::processor::Processor::on_pause.
*
* * **Data Available**: This user event indicates at least one of the inputs
* within the owner rti::routing::processor::Route has received new data.
* This event is notified through rti::routing::processor::Processor::on_data_available.
*
* * **Periodic Action**: This user event represents a periodic notification,
* at a rate configured in the parent Session of the owner
* rti::routing::processor::Route.
* This event is notified through rti::routing::processor::Processor::on_periodic_action.
*
*
* ## Threading
*
* A rti::routing::processor::Route dispatches all the events to its contained
* processors **sequentially**, from within one of the parent Session's threads.
* For any given Route, and hence a Processor, it is guaranteed that only
* one event is dispatched at at time. That is, the operations on the Processor
* are never called concurrently for a given Route.
*
* A parent Session with *L* threads can only process one Route at
* a time but it can dispatch different Routes concurrently. Namely, it can
* dispatch up to *L* Routes concurrently. You should keep this behavior in mind
* for implementations that share state between Processor objects.
*
* ## Constraints
*
* There are several constraints that affect the behavior and relationship
* of the Processor API components:
*
* * A Route can have one and only one Processor. Alternatively, *semantically* a
* Processor can belong to one and only one Route. That is, each Route will
* call rti::routing::processor::ProcessorPlugin::create_processor and
* rti::routing::processor::ProcessorPlugin::delete_processor on the
* corresponding plug-in instance, if the implementation is returning the
* same physical object.
*
* * An Input/Output can belong to one and only one Route. Thus, they cannot
* be shared across different Routes. Alternatively, operations on an
* Input, Output and Route can be performed only from within the associated
* Processor. It is forbidden to pass Input, Output and Route objects between
* Processors
*/
namespace rti { namespace routing { namespace processor {
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::ProcessorPlugin
* @brief The top-level plug-in class.
*
* Represents a factory of Processor.
*/
class ProcessorPlugin {
public:
/**
* @brief Creates a Route Processor.
*
* This function is called when the Route containing the Processor
* is enabled.
*
* A Routing Service running instance will product a log indicating the
* occurrence of this event. For example:
* \code
* [.../domain_routes/DomainRoute|START|/sessions/Session|START|/routes/Route|ENABLE]
* \endcode
*
*
* <b>Required:</b> yes
*
* @param route
* @rs_st_in An object representation of the Route that owns
* the Processor.
* @param properties
* @rs_st_in Configuration properties for the Processor.
* These properties corresponds to the properties specified within
* the tag &lt;processor&gt;.
*
* @return New Processor if successful. Cannot return @null_value.
* @throw std::exception
* @mtsafety Safe
*/
virtual Processor * create_processor(
Route& route,
const rti::routing::PropertySet& properties) = 0;
/**
* @brief Deletes a Route Processor.
*
* This function is called when the Route containing the Processor
* is disabled.
*
* <b>Required:</b> yes
*
* @param route
* @rs_st_in An object representation of the Route that owns
* the Processor.
* @param processor
* @rs_st_in Processor object to be deleted.
*
* @throw std::exception
* @mtsafety Safe
*/
virtual void delete_processor(
Route& route,
Processor *processor) = 0;
/**
* @return The version of this TransformationPlugin.
*
* The version is used for logging purposes. It allows you to track which
* version of the TransformationPlugin the @product is using.
*
* Default implementation of this operation returns the version of the
* required Connext libraries.
*/
virtual rti::config::LibraryVersion get_version() const
{
return rti::config::LibraryVersion();
}
/**
* @brief Virtual destructor
*/
virtual ~ProcessorPlugin() {}
};
} } }
#include <rti/routing/processor/detail/ProcessorPluginForwarder.hpp>
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @brief Utility macro that declares a native extern function that can
* be used to load a ProcessorPlugin through a shared library.
*
* The prototype of the function is given by a native definition of the
* create operation.
*
* To register a ProcessorPlugin with @product, you must use the tag
* &lt;processor_plugin&gt; within &lt;plugin_library&gt;. For example:
*
* \code
* <dds>
* ...
* <plugin_library name="MyPluginLib">
* <processor_plugin name="MyProcessorPlugin">
* <dll>myprocessor</dll>
* <create_function>
* MyProcessorPlugin_create
* </create_function>
* </processor_plugin>
* ...
* </plugin_library>
* ...
* <routing_service>
* ...
* </routing_service>
* ...
* </dds>
* \endcode
*
* Once a ProcessorPlugin is registered, a Route can use it to create a
* Processor.
*
* For example:
*
* \code
* <topic_route name="SquareAndCircleToTriangle">
* ...
* <processor plugin_name="MyPluginLib::MyProcessorPlugin">
* <property>
* <value>
* <element>
* <name>my_property_name</name>
* <value>my_property_value</value>
* </element>
* </value>
* </property>
* </processor>
* <input participant="DomainIn">
* <topic_name>Square</topic_name>
* <registered_type_name>ShapeType</registered_type_name>
* </input>
* <input participant="DomainIn">
* <topic_name>Circle</topic_name>
* <registered_type_name>ShapeType</registered_type_name>
* </input>
* <output participant="DomainOut">
* <topic_name>Triangle</topic_name>
* <registered_type_name>ShapeType</registered_type_name>
* </output>
* </topic_route>
* \endcode
*
* For additional information on configuring Processors, see the
* \ref_url_routing_service_users_manual.
*
* @param PROCESSOR_CLASS
* Class name of a ProcessorPlugin implementation
*/
#define RTI_PROCESSOR_PLUGIN_CREATE_FUNCTION_DECL(PROCESSOR_CLASS) \
extern "C" RTI_USER_DLL_EXPORT struct RTI_RoutingServiceProcessorPlugin* \
PROCESSOR_CLASS ## _create_processor_plugin(\
const struct RTI_RoutingServiceProperties *, \
RTI_RoutingServiceEnvironment *); \
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @brief Utility macro that implements the ProcessorPlugin entry point
* declared with RTI_PROCESSOR_PLUGIN_CREATE_FUNCTION_DECL.
*/
#define RTI_PROCESSOR_PLUGIN_CREATE_FUNCTION_DEF(PROCESSOR_CLASS) \
struct RTI_RoutingServiceProcessorPlugin * PROCESSOR_CLASS ## _create_processor_plugin( \
const struct RTI_RoutingServiceProperties * native_properties, \
RTI_RoutingServiceEnvironment *environment) \
{ \
PropertySet properties; \
rti::routing::PropertyAdapter::add_properties_from_native(\
properties,\
native_properties); \
try { \
return rti::routing::processor::detail::ProcessorPluginForwarder::create_plugin(\
new PROCESSOR_CLASS(properties)); \
} catch (const std::exception& ex) {\
RTI_RoutingServiceEnvironment_set_error(\
environment,\
"%s",\
ex.what());\
} catch (...) {}\
\
return NULL; \
}
#endif // RTI_ROUTING_PROCESSOR_PROCESSOR_PLUGIN_HPP_
@@ -0,0 +1,138 @@
/* $Id$
(c) Copyright, Real-Time Innovations, 2015-2016.
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_QUERY_HPP_
#define RTI_ROUTING_PROCESSOR_QUERY_HPP_
#include "routingservice/routingservice_processor.h"
#include <dds/core/Reference.hpp>
#include <rti/core/detail/SelfReference.hpp>
namespace rti { namespace routing { namespace processor {
class Input;
class QueryHolder : public rti::core::detail::RetainableType<QueryHolder>{
public:
QueryHolder() : input_(NULL), query_data_(NULL)
{
}
QueryHolder(RTI_RoutingServiceInput *input, const dds::topic::Filter& the_filter)
: input_(input),
query_data_(NULL)
{
filter(the_filter);
}
~QueryHolder()
{
if (query_data_ != NULL) {
/*
* Ignore the error. We can't throw in the destructor and this
* layer does not log anything
*/
(void) RTI_RoutingServiceInput_delete_content_query(
input_,
query_data_);
}
}
void filter(const dds::topic::Filter& filter)
{
RTI_RoutingServiceSelectorContent content =
RTI_RoutingServiceSelectorContent_INITIALIZER;
content.expression = (char *) filter.expression().c_str();
rti::core::native_conversions::to_native(
content.expression_parameters,
filter->parameters());
query_data_ = RTI_RoutingServiceInput_create_content_query(
input_,
query_data_,
&content);
DDS_StringSeq_finalize(&content.expression_parameters);
if (query_data_ == NULL) {
throw dds::core::Error("error creating content query from native input");
}
}
RTI_RoutingServiceInput *input_;
void* query_data_;
};
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::Query
*
* @brief Encapsulates a content query to select data from a
* rti::routing::adapter::StreamReader.
*
* Note that syntax for the query filter is StreamReader implementation
* dependent. For the DDS Adapter case, the syntax corresponds to that
* of the SQL filter.
*
* A Query object holds a custom query obtained by calling
* rti::routing::adapter::StreamReader::create_content_query. Likewise,
* the deletion of a Query object will call
* rti::routing::adapter::StreamReader::delete_content_query.
*/
class Query : public dds::core::Reference<rti::routing::processor::QueryHolder> {
public:
typedef dds::core::Reference<QueryHolder> Base;
OMG_DDS_REF_TYPE_NOTYPENAME(
Query,
dds::core::Reference,
rti::routing::processor::QueryHolder);
explicit Query(Base::DELEGATE_REF_T reference) : Base(reference)
{
if (this->delegate()) {
this->delegate()->remember_reference(this->delegate());
}
}
/**
* @brief Creates a Query described by a filter on an input.
*
* @param[in] input The native Input to query the data from.
* @param[in] filter Description of the content query based on an expression
* and parameters.
*
* @see dds::topic::Filter
*/
Query(RTI_RoutingServiceInput *input, const dds::topic::Filter& filter)
: Base(new QueryHolder(input, filter))
{
this->delegate()->remember_reference(this->delegate());
}
/**
* @brief Updates the current Query content filter.
*
* This operation will call
* rti::routing::adapter::StreamReader::create_content_query providing
* the current query content data this Query holds.
*/
void filter(const dds::topic::Filter& filter)
{
this->delegate()->filter(filter);
}
};
} } }
#endif // RTI_ROUTING_PROCESSOR_QUERY_HPP_
@@ -0,0 +1,555 @@
/*
* (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 <dds/core/Value.hpp>
#include <dds/core/SafeEnumeration.hpp>
#include <rti/core/NativeValueType.hpp>
#include "routingservice/routingservice_processor.h"
#include "routingservice/routingservice_processor_impl.h"
#include <dds/core/xtypes/DynamicData.hpp>
#include <dds/sub/SampleInfo.hpp>
#include <rti/routing/adapter/AdapterPlugin.hpp>
#include <rti/routing/processor/Input.hpp>
#include <rti/routing/processor/Output.hpp>
#include <rti/routing/processor/LoanedSamples.hpp>
#include <rti/routing/processor/PortIterator.hpp>
namespace rti { namespace routing { namespace processor {
namespace detail {
class ProcessorForwarder;
}
class Route;
template <typename PORT> struct port_list;
template <> struct port_list<Input>
{
static std::vector<Input>& get(Route& route);
};
template <> struct port_list<Output>
{
static std::vector<Output>& 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<DynamicData>()) {
* LoanedSamples<DynamicData> samples = input->read();
*
* for (auto output : route.outputs<DynamicData>()) {
* for(auto sample = samples) {
* output.write(sample.data(), sample.info());
* }
* }
* }
* \endcode
*/
class Route {
public:
template <typename DataRep, typename InfoRep = dds::sub::SampleInfo>
struct Inputs {
typedef PortIterator<Input, DataRep, InfoRep> 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 <typename DataRep, typename InfoRep = dds::sub::SampleInfo>
struct Outputs {
typedef PortIterator<Output, DataRep, InfoRep> 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 <typename DataRep, typename InfoRep>
TypedInput<DataRep, InfoRep> input(int32_t index)
{
return &input(index);
}
/**
* @brief Same as <tt>input<DataRep, InfoRep>(int32_t)</tt> with
* InfoRep = dds::sub::SampleInfo.
*
*/
template <typename DataRep>
TypedInput<DataRep> input(int32_t index)
{
return input<DataRep, dds::sub::SampleInfo>(index);
}
/**
* @brief Same as <tt>input<DataRep, InfoRep>(int32_t)</tt> but using
* the configuration name of the input.
*
*/
template <typename DataRep, typename InfoRep>
TypedInput<DataRep, InfoRep> input(const std::string& name)
{
return &input(name);
}
/**
* @brief Same as <tt>input<DataRep, InfoRep>(std::string&)</tt> with
* InfoRep = dds::sub::SampleInfo.
*/
template <typename DataRep>
TypedInput<DataRep> input(const std::string& name)
{
return input<DataRep, dds::sub::SampleInfo>(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 <typename DataRep, typename InfoRep>
TypedOutput<DataRep, InfoRep> output(int32_t index)
{
return &output(index);
}
/**
* @brief Same as <tt>output<DataRep, InfoRep>(int32_t)</tt> with
* InfoRep = dds::sub::SampleInfo.
*
*/
template <typename DataRep>
TypedOutput<DataRep> output(int32_t index)
{
return output<DataRep, dds::sub::SampleInfo>(index);
}
/**
* @brief Same as <tt>output<DataRep, InfoRep>(int32_t)</tt> but using
* the configuration name of the output.
*
*/
template <typename DataRep, typename InfoRep>
TypedOutput<DataRep, InfoRep> output(const std::string& name)
{
return &output(name);
}
/**
* @brief Same as <tt>output<DataRep, InfoRep>(std::string&)</tt> with
* InfoRep = dds::sub::SampleInfo.
*/
template <typename DataRep>
TypedOutput<DataRep> output(const std::string& name)
{
return output<DataRep, dds::sub::SampleInfo>(name);
}
/**
* @brief Returns an accessor for the contained inputs.
*
* The returned object that allows iterating over the
* contained inputs, treating them as <tt>TypedInput<DataRep, InfoRep></tt>.
*
* @see <tt>Inputs<DataRep, InfoRep></tt>
* @see <tt>TypedInput<DataRep, InfoRep> input(int32_t index)</tt>
*/
template <typename DataRep, typename InfoRep>
Inputs<DataRep, InfoRep> inputs()
{
return Inputs<DataRep, InfoRep>(native_route_);
}
/**
* @brief Same as <tt>Inputs<DataRep, InfoRep> inputs()</tt> with
* InfoRep = dds::sub::SampleInfo.
*/
template <typename DataRep>
Inputs<DataRep> inputs()
{
return inputs<DataRep, dds::sub::SampleInfo>();
}
/**
* @brief Returns an accessor for the contained outputs.
*
* The returned object that allows iterating over the
* contained outputs, treating them as <tt>TypedOutput<DataRep, InfoRep></tt>.
*
* @see <tt>Outputs<DataRep, InfoRep></tt>
* @see <tt>TypedOutput<DataRep, InfoRep> input(int32_t index)</tt>
*/
template <typename DataRep, typename InfoRep>
Outputs<DataRep, InfoRep> outputs()
{
return Outputs<DataRep, InfoRep>(native_route_);
}
/**
* @brief Same as <tt>Inputs<DataRep, InfoRep> outputs()</tt> with
* InfoRep = dds::sub::SampleInfo.
*/
template <typename DataRep>
Outputs<DataRep> outputs()
{
return outputs<DataRep, dds::sub::SampleInfo>();
}
/**
*
* @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<Input>;
friend struct port_list<Output>;
typedef std::vector<Input>::iterator private_input_it;
typedef std::vector<Output>::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<Input*>(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<Output*>(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<Input*>(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<Output*>(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_
@@ -0,0 +1,275 @@
/* $Id$
(c) Copyright, Real-Time Innovations, 2014-2016.
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.
modification history
--------------------
1.0a,05may14,acr Added ValidSampleIterator and valid_samples helper
1.0a,20mar13,acr Created
============================================================================= */
#ifndef RTI_ROUTING_PROCESSOR_SAMPLE_ITERATOR_HPP_
#define RTI_ROUTING_PROCESSOR_SAMPLE_ITERATOR_HPP_
#include <rti/routing/processor/LoanedSample.hpp>
#include <exception>
namespace rti {
namespace routing {
namespace processor {
/*i
* @brief Tag type to emulate/indicate that sample infos are not available
*/
struct no_sample_info_t {
};
/**
* @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::SampleIterator
* @brief A random-access iterator of LoanedSample
*
* @see rti::routing::processor::LoanedSamples
*/
template <typename T, typename U>
class SampleIterator {
public:
// iterator traits
using iterator_category = std::random_access_iterator_tag;
using value_type = const LoanedSample<T, U>;
using reference = value_type;
using pointer = value_type;
using difference_type = std::size_t;
using SampleSeqType = RTI_RoutingServiceSample*;
using InfoSeqType = RTI_RoutingServiceSampleInfo*;
private:
static no_sample_info_t *_null_info_scrachtpad[1];
static InfoSeqType _null_info_seq;
static difference_type _null_info_pos;
public:
SampleIterator()
: _sample_seq(0),
_info_seq(0),
_length(0),
_pos(0),
_info_pos(_pos)
{
}
SampleIterator(
const SampleSeqType sample_seq,
const InfoSeqType info_seq,
int length,
int position = 0)
: _sample_seq(sample_seq),
_info_seq(info_seq == NULL ? _null_info_seq : info_seq),
_length(length),
_info_pos(info_seq == NULL ? _null_info_pos : _pos)
{
if (position < 0) {
throw dds::core::IllegalOperationError("SampleIterator out of range");
}
_pos = static_cast<difference_type>(position);
}
SampleIterator(const SampleIterator<T, U> & other)
: _sample_seq(other._sample_seq),
_info_seq(other._info_seq),
_length(other._length),
_pos(other._pos),
_info_pos(other._info_pos)
{
}
SampleIterator & operator=(const SampleIterator<T, U> & other)
{
_sample_seq = other._sample_seq;
_info_seq = other._info_seq;
_length = other._length;
_pos = other._pos;
_info_pos = other._info_pos;
return *this;
}
value_type operator*() const
{
return value_type(_sample_seq[_pos], _info_seq[_info_pos]);
}
value_type operator->() const
{
return value_type(_sample_seq[_pos], _info_seq[_info_pos]);
}
value_type operator[](difference_type offset) const
{
return (_info_seq == _null_info_seq)
? value_type(_sample_seq[_pos], NULL)
: value_type(_sample_seq[_pos + offset], _info_seq[_info_pos + offset]);
}
/*
* Windows defines min and max in one of the Windows headers, and they
* collide with the max() definition we use below
*/
#ifdef RTI_WIN32
#undef max
#undef min
#endif
SampleIterator & operator++()
{
if (_pos == std::numeric_limits<difference_type>::max()) {
throw dds::core::IllegalOperationError("SampleIterator out of range");
}
++_pos;
return *this;
}
SampleIterator operator++(int)
{
SampleIterator temp(*this);
++(*this);
return temp;
}
SampleIterator & operator--()
{
if (_pos == std::numeric_limits<difference_type>::min()) {
throw dds::core::IllegalOperationError("SampleIterator out of range");
}
--_pos;
return *this;
}
SampleIterator operator--(int)
{
SampleIterator temp(*this);
--(*this);
return temp;
}
SampleIterator & operator-=(difference_type i)
{
if (i > _pos) {
throw dds::core::IllegalOperationError("SampleIterator out of range");
}
_pos -= i;
return *this;
}
SampleIterator & operator+=(difference_type i)
{
if ((std::numeric_limits<difference_type>::max() - _pos) < i) {
throw dds::core::IllegalOperationError("SampleIterator out of range");
}
_pos += i;
return *this;
}
friend SampleIterator operator-(
const SampleIterator& si,
difference_type i)
{
SampleIterator temp(si);
temp -= i;
return temp;
}
friend SampleIterator operator+(
const SampleIterator& si,
difference_type i)
{
SampleIterator temp(si);
temp += i;
return temp;
}
friend difference_type operator-(
const SampleIterator& s1,
const SampleIterator& s2)
{
return s1._pos - s2._pos;
}
friend bool operator<(const SampleIterator & s1,
const SampleIterator & s2)
{
return s1._pos < s2._pos;
}
friend bool operator>(const SampleIterator & s1,
const SampleIterator & s2)
{
return s1._pos > s2._pos;
}
friend bool operator<=(const SampleIterator & s1,
const SampleIterator & s2)
{
return s1._pos <= s2._pos;
}
friend bool operator>=(const SampleIterator & s1,
const SampleIterator & s2)
{
return s1._pos >= s2._pos;
}
friend bool operator==(const SampleIterator & s1,
const SampleIterator & s2)
{
return (s1._sample_seq == s2._sample_seq) && (s1._pos == s2._pos);
}
friend bool operator!=(const SampleIterator & s1,
const SampleIterator & s2)
{
return !(s1 == s2);
}
bool is_end() const
{
return (_length == _pos);
}
// Keep these members public otherwise some of the
// converting constructors will not compile.
public:
SampleSeqType _sample_seq;
InfoSeqType _info_seq;
int _length;
difference_type _pos;
difference_type& _info_pos;
};
template <typename T, typename U>
std::size_t SampleIterator<T, U>::_null_info_pos = 0;
template <typename T, typename U>
no_sample_info_t * SampleIterator<T, U>::_null_info_scrachtpad[1] = {NULL};
template <typename T, typename U>
typename SampleIterator<T, U>::InfoSeqType SampleIterator<T, U>::_null_info_seq =
reinterpret_cast<InfoSeqType> (SampleIterator<T, U>::_null_info_scrachtpad);
} } }
#endif // RTI_ROUTING_PROCESSOR_SAMPLE_ITERATOR_HPP_
@@ -0,0 +1,353 @@
/*
* (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_DETAIL_PROCESSOR_FORWARDER_HPP_
#define RTI_ROUTING_PROCESSOR_DETAIL_PROCESSOR_FORWARDER_HPP_
#include <rti/core/Exception.hpp>
#include "rti/apputils/ServiceException.hpp"
#include "routingservice/routingservice_processor_impl.h"
#include <rti/routing/detail/ForwarderUtils.hpp>
#include <rti/routing/detail/UpdatableEntityForwarder.hpp>
#include <rti/routing/processor/Route.hpp>
#include <rti/routing/processor/Input.hpp>
#include <rti/routing/processor/Output.hpp>
namespace rti { namespace routing { namespace processor { namespace detail {
class ProcessorForwarder {
private:
template <typename PORT, typename NATIVE>
class ScopedPort {
public:
ScopedPort(Route& route, int32_t index, NATIVE *native)
: route_(route),
port_(new PORT(native, index, route.native_route_))
{
}
PORT* get()
{
return port_;
}
void clear()
{
port_ = NULL;
}
~ScopedPort()
{
if (port_ != NULL) {
delete port_;
port_ = NULL;
}
}
private:
Route& route_;
PORT *port_;
};
public:
static RTI_RoutingServiceProcessor * create_native(
ProcessorPlugin *plugin,
RTI_RoutingServiceRoute *native_route,
const struct RTI_RoutingServiceProperties *native_properties,
RTI_RoutingServiceEnvironment *environment)
{
try {
using rti::routing::detail::ScopedForwarder;
std::map<std::string, std::string> properties;
rti::routing::PropertyAdapter::add_properties_from_native(
properties,
native_properties);
ProcessorForwarder *forwarder = new ProcessorForwarder(
native_route,
environment);
ScopedForwarder<ProcessorPlugin, ProcessorForwarder> scoped(
plugin,
forwarder,
environment);
forwarder->processor_ = plugin->create_processor(
forwarder->route(),
properties);
RTI_ROUTING_THROW_ON_NULL(forwarder->processor_);
scoped.release();
// TRUST-134: the forwarder is not leaked here. It might be leaked
// if delete_native() were not to be called, but Routing Service
// will make sure that is not the case
/* coverity[leaked_storage : FALSE] */
return forwarder->native();
} catch(const rti::apputils::FatalServiceException& ex) {
RTI_RoutingServiceEnvironment_fatal_error(
environment,
ex.what());
return NULL;
} catch(const std::exception& ex) {
RTI_RoutingServiceEnvironment_set_error(
environment,
ex.what());
return NULL;
} catch (...) {
RTI_RoutingServiceEnvironment_set_error(
environment,
"unexpected exception");
return NULL;
}
}
static void delete_native(
ProcessorPlugin *plugin,
RTI_RoutingServiceProcessor *native_processor,
RTI_RoutingServiceEnvironment *environment)
{
ProcessorForwarder *processor_forwarder =
static_cast<ProcessorForwarder*>(native_processor->processor_data);
try {
if (processor_forwarder->processor_ != NULL) {
plugin->delete_processor(
processor_forwarder->route_,
processor_forwarder->processor_);
processor_forwarder->processor_ = NULL;
}
} catch(const rti::apputils::FatalServiceException& ex) {
RTI_RoutingServiceEnvironment_fatal_error(
environment,
ex.what());
} catch(const std::exception& ex) {
RTI_RoutingServiceEnvironment_set_error(
environment,
ex.what());
} catch (...) {
RTI_RoutingServiceEnvironment_set_error(
environment,
"unexpected exception");
}
delete processor_forwarder;
}
static void forward_on_route_event(
void *native_processor_data,
RTI_RoutingServiceRouteEvent *native_route_event,
RTI_RoutingServiceEnvironment *environment)
{
ProcessorForwarder *forwarder =
static_cast<ProcessorForwarder*>(native_processor_data);
try {
// build up wrapper objects based on the event
switch (RTI_RoutingServiceRouteEvent_get_kind(native_route_event)) {
case RTI_ROUTING_SERVICE_ROUTE_EVENT_DATA_ON_INPUTS:
forwarder->processor_->on_data_available(forwarder->route());
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_PERIODIC_ACTION:
forwarder->processor_->on_periodic_action(forwarder->route());
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_INPUT_ENABLED:
{
void *affected_entity =
RTI_RoutingServiceRouteEvent_get_affected_entity(native_route_event);
void *index =
RTI_RoutingServiceRouteEvent_get_event_data(native_route_event);
/* ScopedPort helps to delete the Input if an exception occurs */
ScopedPort<Input, RTI_RoutingServiceInput> port(
forwarder->route_,
*(static_cast<int32_t*>(index)),
static_cast<RTI_RoutingServiceInput *>(affected_entity));
forwarder->processor_->on_input_enabled(
forwarder->route(),
*port.get());
RTI_RoutingServiceInput_set_user_data(
static_cast<RTI_RoutingServiceInput *>(affected_entity),
port.get());
/*
* Input successfully enabled, so clear the ScopedPort so it
* doesn't delete it
*/
port.clear();
}
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_INPUT_DISABLED:
{
void *affected_entity =
RTI_RoutingServiceRouteEvent_get_affected_entity(native_route_event);
RTI_RoutingServiceInput *native_input =
static_cast<RTI_RoutingServiceInput *>(affected_entity);
Input *input = reinterpret_cast<Input*>(
RTI_RoutingServiceInput_get_user_data(native_input));
forwarder->processor_->on_input_disabled(
forwarder->route(),
*input);
RTI_RoutingServiceInput_set_user_data(native_input, NULL);
delete input;
}
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_OUTPUT_ENABLED:
{
void *affected_entity =
RTI_RoutingServiceRouteEvent_get_affected_entity(native_route_event);
void *index =
RTI_RoutingServiceRouteEvent_get_event_data(native_route_event);
/* ScopedPort helps to delete the Output if an exception occurs */
ScopedPort<Output, RTI_RoutingServiceOutput> port(
forwarder->route_,
*(static_cast<int32_t*>(index)),
static_cast<RTI_RoutingServiceOutput *>(affected_entity));
forwarder->processor_->on_output_enabled(
forwarder->route(),
*port.get());
RTI_RoutingServiceOutput_set_user_data(
static_cast<RTI_RoutingServiceOutput *>(affected_entity),
port.get());
/*
* Output successfully enabled, so clear the ScopedPort so it
* doesn't delete it
*/
port.clear();
}
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_OUTPUT_DISABLED:
{
void *affected_entity =
RTI_RoutingServiceRouteEvent_get_affected_entity(native_route_event);
RTI_RoutingServiceOutput *native_output =
static_cast<RTI_RoutingServiceOutput *>(affected_entity);
Output *output = reinterpret_cast<Output*>(
RTI_RoutingServiceOutput_get_user_data(native_output));
forwarder->processor_->on_output_disabled(
forwarder->route(),
*output);
RTI_RoutingServiceOutput_set_user_data(native_output, NULL);
delete output;
}
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_ROUTE_STARTED:
forwarder->processor_->on_start(forwarder->route());
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_ROUTE_STOPPED:
forwarder->processor_->on_stop(forwarder->route());
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_ROUTE_RUNNING:
forwarder->processor_->on_run(forwarder->route());
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_ROUTE_PAUSED:
forwarder->processor_->on_pause(forwarder->route());
break;
default:
break;
};
} catch (const rti::apputils::FatalServiceException& ex) {
RTI_RoutingServiceEnvironment_fatal_error(
environment,
ex.what());
} catch (const std::exception& ex) {
RTI_RoutingServiceEnvironment_set_error(
environment,
ex.what());
} catch (...) {
RTI_RoutingServiceEnvironment_set_error(
environment,
"%s",
"unexpected exception");
}
}
static void forward_update(
void *native_processor_data,
const struct RTI_RoutingServiceProperties *native_properties,
RTI_RoutingServiceEnvironment *environment)
{
ProcessorForwarder *processorForwarder =
static_cast<ProcessorForwarder*> (native_processor_data);
rti::routing::detail::UpdatableEntityForwarder::update(
processorForwarder->processor_,
native_properties,
environment);
}
RTI_RoutingServiceProcessor* native()
{
return &native_;
}
private:
ProcessorForwarder(
RTI_RoutingServiceRoute *native_route,
RTI_RoutingServiceEnvironment *native_env) :
processor_(NULL),
route_(native_route, native_env)
{
RTIOsapiMemory_zero(&native_, sizeof(native_));
/* initialize native implementation */
native_.processor_data = static_cast<void *>(this);
native_.on_route_event = ProcessorForwarder::forward_on_route_event;
native_.update = ProcessorForwarder::forward_update;
}
rti::routing::processor::Route& route()
{
return route_;
}
~ProcessorForwarder()
{
}
private:
RTI_RoutingServiceProcessor native_;
Processor *processor_;
rti::routing::processor::Route route_;
};
}}}}
#endif // RTI_ROUTING_PROCESSOR_DETAIL_PROCESSOR_FORWARDER_HPP_
@@ -0,0 +1,99 @@
/*
* (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_PLUGIN_DETAIL_PROCESSOR_PLUGIN_FORWARDER_HPP_
#define RTI_ROUTING_PROCESSOR_PLUGIN_DETAIL_PROCESSOR_PLUGIN_FORWARDER_HPP_
#include <rti/core/Exception.hpp>
#include <rti/routing/processor/detail/ProcessorForwarder.hpp>
#include <rti/routing/detail/ForwarderUtils.hpp>
namespace rti { namespace routing { namespace processor { namespace detail {
class ProcessorPluginForwarder {
public:
static RTI_RoutingServiceProcessorPlugin * create_plugin(
ProcessorPlugin *plugin)
{
RTI_RoutingServiceProcessorPlugin *native_plugin = NULL;
RTIOsapiHeap_allocateStructure(
&native_plugin,
struct RTI_RoutingServiceProcessorPlugin);
rti::core::check_create_entity(
native_plugin,
"RTI_RoutingServiceProcessorPlugin");
RTI_RoutingServiceProcessorPlugin_initialize(native_plugin);
// Set adapter version
rti::config::LibraryVersion version = plugin->get_version();
native_plugin->plugin_version.major = version.major_version();
native_plugin->plugin_version.minor = version.minor_version();
native_plugin->plugin_version.release = version.release_version();
// Initialize native implementation
native_plugin->processor_plugin_data =
static_cast<void *>(plugin);
native_plugin->plugin_delete =
ProcessorPluginForwarder::delete_plugin;
native_plugin->create_processor =
ProcessorPluginForwarder::forward_create_processor;
native_plugin->delete_processor =
ProcessorPluginForwarder::forward_delete_processor;
return native_plugin;
}
static void delete_plugin(
RTI_RoutingServiceProcessorPlugin *native_plugin,
RTI_RoutingServiceEnvironment *)
{
ProcessorPlugin *plugin = static_cast<ProcessorPlugin*>(
native_plugin->processor_plugin_data);
// Plug-in is destructor not allowed to throw
delete plugin;
RTIOsapiHeap_freeStructure(native_plugin);
}
static RTI_RoutingServiceProcessor * forward_create_processor(
void *native_plugin_data,
RTI_RoutingServiceRoute *native_route,
const struct RTI_RoutingServiceProperties *native_properties,
RTI_RoutingServiceEnvironment *environment)
{
return ProcessorForwarder::create_native(
static_cast<ProcessorPlugin *>(native_plugin_data),
native_route,
native_properties,
environment);
}
static void forward_delete_processor(
void *native_plugin_data,
struct RTI_RoutingServiceProcessor *native_processor,
RTI_RoutingServiceRoute *,
RTI_RoutingServiceEnvironment *environment)
{
ProcessorForwarder::delete_native(
static_cast<ProcessorPlugin *>(native_plugin_data),
native_processor,
environment);
}
};
}}}}
#endif // RTI_ROUTING_PROCESSOR_PLUGIN_DETAIL_PROCESSOR_PLUGIN_FORWARDER_HPP_