Adds immediate migration results
This commit is contained in:
2395 files changed
+357322
-2524
No files matched your search
@@ -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_ADAPTER_ADAPTER_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_ADAPTER_HPP_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "routingservice/routingservice_infrastructure.h"
|
||||
#include <rti/config/Version.hpp>
|
||||
#include <rti/routing/adapter/StreamReaderListener.hpp>
|
||||
#include <rti/routing/adapter/Connection.hpp>
|
||||
|
||||
/** @file
|
||||
* @brief \product C++ Adapter API
|
||||
*/
|
||||
|
||||
namespace rti { namespace routing { namespace adapter {
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @class rti::routing::adapter::AdapterPlugin
|
||||
* @brief The top-level plug-in class.
|
||||
*
|
||||
* Represents a factory of Connection.
|
||||
*/
|
||||
class AdapterPlugin {
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a Connection.
|
||||
*
|
||||
* Connection objects are created when the domain routes that contain them
|
||||
* are enabled.
|
||||
*
|
||||
* @param input_stream_discovery_listener
|
||||
* @rs_st_in The listener of the built-in @ref DiscoveryStreamReader
|
||||
* that notifies the discovery of new input streams.
|
||||
* @param output_stream_discovery_listener
|
||||
* @rs_st_in The listener of the built-in @ref DiscoveryStreamReader
|
||||
* that notifies the discovery of new output streams.
|
||||
* @param properties
|
||||
* @rs_st_in Configuration properties for the Connection.
|
||||
* These properties corresponds to the properties specified within
|
||||
* the tag <connection>.
|
||||
*
|
||||
* @return New Connection if successful. Cannot return @null_value.
|
||||
*
|
||||
* @throw std::exception
|
||||
*
|
||||
* @mtsafety Safe
|
||||
*/
|
||||
virtual Connection * create_connection(
|
||||
StreamReaderListener *input_stream_discovery_listener,
|
||||
StreamReaderListener *output_stream_discovery_listener,
|
||||
const PropertySet& properties) = 0;
|
||||
|
||||
/**
|
||||
* @brief Deletes a Connection.
|
||||
*
|
||||
* Connection objects are deleted when the domain routes that contain them
|
||||
* are disabled or @product is stopped.
|
||||
*
|
||||
* @param connection @rs_st_in Connection to be deleted
|
||||
*
|
||||
* @throw std::exception
|
||||
*
|
||||
* @mtsafety Safe
|
||||
*/
|
||||
virtual void delete_connection(Connection *connection) = 0;
|
||||
|
||||
/**
|
||||
* @return The version of this AdapterPlugin.
|
||||
*
|
||||
* Version is used for logging purposes and allows you to track which
|
||||
* version of the AdapterPlugin @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 ~AdapterPlugin() {}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#include <rti/routing/adapter/detail/AdapterForwarder.hpp>
|
||||
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @brief Utility macro that declares a native extern function that can
|
||||
* be used to load an AdapterPlugin through a shared library.
|
||||
*
|
||||
* The prototype of the function is given by
|
||||
* RTI_RoutingServiceAdapterPlugin_CreateFcn.
|
||||
*
|
||||
* To register an AdapterPlugin plugin with @product, you must use the tag
|
||||
* <adapter_plugin> within <plugin_library>. For example:
|
||||
*
|
||||
* \code
|
||||
* <dds>
|
||||
* ...
|
||||
* <plugin_library name="MyPluginLib">
|
||||
<adapter_plugin name="MyAdapterPlugin">
|
||||
<dll>mycadapter</dll>
|
||||
<create_function>
|
||||
MyAdapterPlugin_create
|
||||
</create_function>
|
||||
</adapter_plugin>
|
||||
* ...
|
||||
* </plugin_library>
|
||||
* ...
|
||||
* <routing_service>
|
||||
* ...
|
||||
* </routing_service>
|
||||
* ...
|
||||
* </dds>
|
||||
* \endcode
|
||||
*
|
||||
* Once an AdapterPlugin is registered, a Connection can refer to it as
|
||||
* follows:
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* \code
|
||||
* <dds>
|
||||
* <routing_service name="example">
|
||||
* <domain_route name="myadapter_to_dds">
|
||||
*
|
||||
* <connection name="MyConnection" plugin_name="MyAdapter">
|
||||
* <property>
|
||||
* <value>
|
||||
* <element>
|
||||
* <name>my_property_name</name>
|
||||
* <value>my_property_value</value>
|
||||
* </element>
|
||||
* </value>
|
||||
* </property>
|
||||
* </connection>
|
||||
*
|
||||
* ...
|
||||
* </domain_route>
|
||||
* </routing_service>
|
||||
* </dds>
|
||||
* \endcode
|
||||
*
|
||||
* For additional information on configuring adapters, see the
|
||||
* \ref_url_routing_service_users_manual.
|
||||
*
|
||||
* @param ADAPTER_CLASS
|
||||
* Class name of an AdapterPlugin implementation
|
||||
*/
|
||||
#define RTI_ADAPTER_PLUGIN_CREATE_FUNCTION_DECL(ADAPTER_CLASS) \
|
||||
extern "C" RTI_USER_DLL_EXPORT struct RTI_RoutingServiceAdapterPluginExt * \
|
||||
ADAPTER_CLASS ## _create_adapter_plugin(\
|
||||
const struct RTI_RoutingServiceProperties *, \
|
||||
RTI_RoutingServiceEnvironment *); \
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @brief Utility macro that implements the AdapterPlugin entry point declared
|
||||
* with RTI_ADAPTER_PLUGIN_CREATE_FUNCTION_DECL.
|
||||
*/
|
||||
#define RTI_ADAPTER_PLUGIN_CREATE_FUNCTION_DEF(ADAPTER_CLASS) \
|
||||
struct RTI_RoutingServiceAdapterPluginExt * ADAPTER_CLASS ## _create_adapter_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::adapter::detail::AdapterForwarder::create_plugin(new ADAPTER_CLASS(properties)); \
|
||||
} catch (const std::exception& ex) {\
|
||||
RTI_RoutingServiceEnvironment_set_error(\
|
||||
environment,\
|
||||
"%s",\
|
||||
ex.what());\
|
||||
} catch (...) {}\
|
||||
\
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_ADAPTER_HPP_
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* (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_ADAPTER_CONNECTION_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_CONNECTION_HPP_
|
||||
|
||||
#include <rti/routing/PropertySet.hpp>
|
||||
#include <rti/routing/UpdatableEntity.hpp>
|
||||
#include <rti/routing/adapter/Session.hpp>
|
||||
#include <rti/routing/adapter/StreamWriter.hpp>
|
||||
#include <rti/routing/adapter/StreamReader.hpp>
|
||||
#include <rti/routing/StreamInfo.hpp>
|
||||
#include <rti/routing/adapter/DiscoveryStreamReader.hpp>
|
||||
#include <rti/routing/adapter/StreamReaderListener.hpp>
|
||||
|
||||
namespace rti { namespace routing { namespace adapter {
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @class rti::routing::adapter::Connection
|
||||
*
|
||||
* @brief A Connection provides access to a data domain (such as a DDS domain
|
||||
* or a JMS network provider).
|
||||
*
|
||||
* In the XML configuration file, Connections are associated with the tag
|
||||
* <connection> within a domain route.
|
||||
*/
|
||||
class Connection : public UpdatableEntity {
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a Session
|
||||
*
|
||||
* Session objects are created when the associated @product Sessions are
|
||||
* enabled. This operation is called once for each service Session and
|
||||
* for each Connection within the DomainRoute.
|
||||
*
|
||||
* @param properties
|
||||
* @rs_st_in Configuration properties for the Session.
|
||||
*
|
||||
* @return New Session if successful. Can return @null_value if sessions
|
||||
* are not required by this AdapterPlugin.
|
||||
*
|
||||
* @throw std::exception
|
||||
*
|
||||
*
|
||||
* @mtsafety Safe
|
||||
*
|
||||
*/
|
||||
virtual Session * create_session(
|
||||
const PropertySet& properties)
|
||||
{
|
||||
(void) properties;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deletes a Session
|
||||
*
|
||||
* Session objects are deleted when the @product Sessions that contain them
|
||||
* are disabled.
|
||||
*
|
||||
* @param session
|
||||
* @rs_st_in Session to be deleted.
|
||||
*
|
||||
* @throw std::exception
|
||||
* @mtsafety Safe
|
||||
*/
|
||||
virtual void delete_session(Session *session)
|
||||
{
|
||||
(void) session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a StreamWriter.
|
||||
*
|
||||
* This @method is called for each Route's output when the associated
|
||||
* 'creation mode' condition is met. The operation is called on the output
|
||||
* Connection as a specified through the 'connection' attribute in the
|
||||
* <output> tag.
|
||||
*
|
||||
* @param session
|
||||
* @rs_st_in Session associated with the StreamWriter. This
|
||||
* parameter is \null_value if Sessions are not used by the adapter.
|
||||
* @param stream_info
|
||||
* @rs_st_in Information related to the stream where the StreamWriter
|
||||
* sends data.
|
||||
* @param properties
|
||||
* @rs_st_in Configuration properties for the StreamWriter.
|
||||
*
|
||||
* @return New StreamWriter if successful. Cannot return @null_value
|
||||
*
|
||||
* @throw std::exception
|
||||
* @mtsafety Partially Safe.
|
||||
* This operation is never called concurrently for the same
|
||||
* Connection, even if multiple outputs are configured in different
|
||||
* Sessions. It can only be called concurrently for different
|
||||
* Connections.
|
||||
*
|
||||
*/
|
||||
virtual StreamWriter * create_stream_writer(
|
||||
Session *session,
|
||||
const StreamInfo& stream_info,
|
||||
const PropertySet& properties)
|
||||
{
|
||||
(void) session;
|
||||
(void) stream_info;
|
||||
(void) properties;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deletes a StreamWriter.
|
||||
*
|
||||
* A StreamWriter object is deleted when:
|
||||
* - The route that contains it is disabled
|
||||
* - The 'creation mode' condition associated with the route's output
|
||||
* becomes false
|
||||
* - \product is shutdown.
|
||||
*
|
||||
* @param stream_writer
|
||||
* @rs_st_in StreamWriter to be deleted.
|
||||
*
|
||||
* @throw std::exception
|
||||
*/
|
||||
virtual void delete_stream_writer(
|
||||
StreamWriter *stream_writer)
|
||||
{
|
||||
(void) stream_writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a StreamReader.
|
||||
*
|
||||
* This @method is called for each Route's input when the associated
|
||||
* 'creation mode' condition is met. The operation is called on the input
|
||||
* Connection as a specified through the 'connection' attribute in the
|
||||
* <output> tag.
|
||||
*
|
||||
* @param session
|
||||
* @rs_st_in Session associated with the StreamReader. This
|
||||
* parameter is \null_value if Sessions are not used by the adapter.
|
||||
* @param stream_info
|
||||
* @rs_st_in Information related to the stream where the StreamReader
|
||||
* read data.
|
||||
* @param properties
|
||||
* @rs_st_in Configuration properties for the StreamReader.
|
||||
* @param listener
|
||||
* @rs_st_in The listener for the StreamReader implementation used
|
||||
* to notify \product when new data is available.
|
||||
*
|
||||
* @return New StreamReader if successful. Cannot return @null_value.
|
||||
*
|
||||
* @throw std::exception
|
||||
*
|
||||
* @mtsafety Partially Safe.
|
||||
* This operation is never called concurrently for the same
|
||||
* Connection, even if multiple outputs are configured in different
|
||||
* Sessions. It can only be called concurrently for different
|
||||
* Connections.
|
||||
*
|
||||
*/
|
||||
virtual StreamReader * create_stream_reader(
|
||||
Session *session,
|
||||
const StreamInfo& stream_info,
|
||||
const PropertySet& properties,
|
||||
StreamReaderListener *listener)
|
||||
{
|
||||
(void) session;
|
||||
(void) stream_info;
|
||||
(void) properties;
|
||||
(void) listener;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deletes a StreamReader.
|
||||
*
|
||||
* A StreamReader object is deleted when:
|
||||
* - The route that contains it is disabled
|
||||
* - The 'creation mode' condition associated with the route's input
|
||||
* becomes false
|
||||
* - \product is shutdown.
|
||||
*
|
||||
* @param stream_reader
|
||||
* @rs_st_in StreamReader to be deleted.
|
||||
*
|
||||
* @throw std::exception
|
||||
*/
|
||||
virtual void delete_stream_reader(
|
||||
StreamReader *stream_reader)
|
||||
{
|
||||
(void) stream_reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the input stream discovery StreamReader.
|
||||
*
|
||||
* Returns a DiscoveryStreamReader that is used by \product to discover
|
||||
* input streams.
|
||||
*
|
||||
* An input stream is a stream from which a StreamReader can read data.
|
||||
* Disposed scenarios, where an input stream disappears, are also notified
|
||||
* using this DiscoveryStreamReader.
|
||||
*
|
||||
* The StreamReaderListener associated with this DiscoveryStreamReader is
|
||||
* provided as a parameter to the method AdapterPlugin::create_connection
|
||||
*
|
||||
* Implementations may return @null_value if they do not support stream
|
||||
* discovery.
|
||||
*
|
||||
* @throw std::exception
|
||||
*/
|
||||
virtual DiscoveryStreamReader * input_stream_discovery_reader()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the output stream discovery StreamReader.
|
||||
*
|
||||
* Returns a DiscoveryStreamReader that is used by \product to discover
|
||||
* output streams.
|
||||
*
|
||||
* An output stream is a stream from which a StreamWrite can write data.
|
||||
* Disposed scenarios, where an output stream disappears, are also notified
|
||||
* using this DiscoveryStreamReader.
|
||||
*
|
||||
* The StreamReaderListener associated with this DiscoveryStreamReader is
|
||||
* provided as a parameter to the method AdapterPlugin::create_connection.
|
||||
*
|
||||
* Implementations may return @null_value if they do not support stream
|
||||
* discovery.
|
||||
*
|
||||
* @throw std::exception
|
||||
*/
|
||||
virtual DiscoveryStreamReader * output_stream_discovery_reader()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Virtual destructor
|
||||
*/
|
||||
virtual ~Connection()
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_CONNECTION_HPP_
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* (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_ADAPTER_DISCOVERY_STREAM_READER_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_DISCOVERY_STREAM_READER_HPP_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <rti/routing/UpdatableEntity.hpp>
|
||||
#include <rti/routing/StreamInfo.hpp>
|
||||
#include <rti/routing/detail/ForwarderUtils.hpp>
|
||||
|
||||
|
||||
namespace rti { namespace routing { namespace adapter {
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @class rti::routing::adapter::DiscoveryStreamReader
|
||||
*
|
||||
* @brief Definition of a special StreamReader to read information about
|
||||
* data streams.
|
||||
*
|
||||
* @mtsafety Safe
|
||||
* All the operations on a DiscoveryStreamReader always serialized,
|
||||
* no matter from which Connection it belongs.
|
||||
*/
|
||||
class DiscoveryStreamReader : public StreamReader{
|
||||
|
||||
using StreamReader::take;
|
||||
using StreamReader::return_loan;
|
||||
/**
|
||||
* @brief Performs the conversion between the vector of data
|
||||
* pointers to strongly-type pointers.
|
||||
*/
|
||||
void take(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>&) RTI_FINAL
|
||||
{
|
||||
take(sample_seq_);
|
||||
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(sample_seq, sample_seq_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs the conversion between the vector of data
|
||||
* pointers to strongly-type pointers.
|
||||
*/
|
||||
void return_loan(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>&) RTI_FINAL
|
||||
{
|
||||
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(sample_seq_, sample_seq);
|
||||
return_loan(sample_seq_);
|
||||
sample_seq_.clear();
|
||||
}
|
||||
|
||||
void read(
|
||||
std::vector<SamplePtr>&,
|
||||
std::vector<InfoPtr>&) RTI_FINAL
|
||||
{
|
||||
}
|
||||
|
||||
void take(
|
||||
std::vector<SamplePtr>&,
|
||||
std::vector<InfoPtr>&,
|
||||
const SelectorState&) RTI_FINAL
|
||||
{
|
||||
}
|
||||
|
||||
void read(
|
||||
std::vector<SamplePtr>&,
|
||||
std::vector<InfoPtr>&,
|
||||
const SelectorState&) RTI_FINAL
|
||||
{
|
||||
}
|
||||
|
||||
virtual void* create_content_query(
|
||||
void *,
|
||||
const dds::topic::Filter&) RTI_FINAL
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
virtual void delete_content_query(void*) RTI_FINAL
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Takes a collection of all available StreamInfo samples.
|
||||
*
|
||||
* When \product is done using the samples, it will 'return the loan' to the
|
||||
* DiscoveryStreamReader by calling DiscoveryStreamReader::return_loan.
|
||||
* It is guaranteed \product takes one outstanding loan at time.
|
||||
*
|
||||
* The samples provided with this operation are considered 'removed'
|
||||
* from the DiscoveryStreamReader's cache, and they shall no longer be
|
||||
* returned by subsequent DiscoveryStreamReader::take.
|
||||
*
|
||||
* @param sample_seq
|
||||
* @rs_st_inout Vector that will hold the StreamInfo samples. \product
|
||||
* provides this vector to the StreamReader to fill. For each call,
|
||||
* the size of the vector is zero.
|
||||
* @throw std::exception
|
||||
*/
|
||||
virtual void take(
|
||||
std::vector<rti::routing::StreamInfo*>& sample_seq) = 0;
|
||||
|
||||
/** @brief Returns a loan on the read or taken StreamInfo samples.
|
||||
*
|
||||
* \product calls this method to indicate that it is done accessing
|
||||
* the collection of StreamInfo samples obtained by an earlier
|
||||
* invocation of DiscoveryStreamReader::take.
|
||||
*
|
||||
* @param sample_seq
|
||||
* @rs_st_in Vector of loaned data samples.
|
||||
*
|
||||
* @throw std::exception
|
||||
*/
|
||||
virtual void return_loan(
|
||||
std::vector<rti::routing::StreamInfo*>& sample_seq) = 0;
|
||||
|
||||
/*
|
||||
* @brief Virtual destructor
|
||||
*/
|
||||
virtual ~DiscoveryStreamReader()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<StreamInfo*> sample_seq_;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_DISCOVERY_STREAM_READER_HPP_
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* (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_ADAPTER_SESSION_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_SESSION_HPP_
|
||||
|
||||
#include <rti/routing/UpdatableEntity.hpp>
|
||||
|
||||
namespace rti { namespace routing { namespace adapter {
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @class rti::routing::adapter::Session
|
||||
*
|
||||
* A Session is a concurrency unit within a Connection that has an associated
|
||||
* set of StreamReaders and StreamWriter. Access to the StreamReader and
|
||||
* StreamWriters in the same Session is serialized by @product.
|
||||
*
|
||||
* In the XML configuration file, Sessions are associated with the tag
|
||||
* <session> within a DomainRoute.
|
||||
*/
|
||||
class Session : public UpdatableEntity {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Virtual destructor
|
||||
*/
|
||||
virtual ~Session()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_SESSION_HPP_
|
||||
@@ -0,0 +1,666 @@
|
||||
/*
|
||||
* (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_ADAPTER_STREAM_READER_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_STREAM_READER_HPP_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <dds/core/SafeEnumeration.hpp>
|
||||
#include <dds/sub/status/DataState.hpp>
|
||||
#include <dds/core/InstanceHandle.hpp>
|
||||
#include <dds/core/types.hpp>
|
||||
#include <dds/topic/Filter.hpp>
|
||||
#include <dds/core/xtypes/DynamicData.hpp>
|
||||
#include <dds/sub/SampleInfo.hpp>
|
||||
#include <rti/core/NativeValueType.hpp>
|
||||
#include <rti/routing/UpdatableEntity.hpp>
|
||||
#include <rti/routing/detail/ForwarderUtils.hpp>
|
||||
|
||||
namespace rti { namespace routing { namespace adapter {
|
||||
|
||||
class SelectorState;
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @class rti::routing::adapter::StreamReader
|
||||
*
|
||||
* @brief Provides a way to read samples of a specific type from a data domain.
|
||||
* In the XML configuration file, StreamReaders are associated with the tag
|
||||
* <input> within <route> and <auto_route>.
|
||||
*
|
||||
* @mtsafety Partially Safe
|
||||
* All operations on a concrete StreamReader objects are safe and
|
||||
* always serialized on a given Session. Operations on different
|
||||
* StreamReader objects can be called concurrently if the
|
||||
* StreamReader objects belong to different Sessions.
|
||||
*/
|
||||
class StreamReader : public UpdatableEntity{
|
||||
|
||||
public:
|
||||
typedef void* SamplePtr;
|
||||
typedef void* InfoPtr;
|
||||
|
||||
/**
|
||||
* @brief Takes a collection of all data samples and info samples available
|
||||
* from an input stream.
|
||||
*
|
||||
* When \product is done using the samples, it will 'return the loan' to the
|
||||
* StreamReader by calling StreamReader::return_loan. Note that multiple
|
||||
* calls to this operation can be made before returning the loans.
|
||||
*
|
||||
* The samples provided with this operation are considered 'removed'
|
||||
* from the StreamReader cache, and they shall no longer be returned by
|
||||
* subsequent StreamReader::take or StreamReader::read operations.
|
||||
*
|
||||
* This operation represents the minimum required behavior by \product
|
||||
* in order to forward data.
|
||||
*
|
||||
* @param sample_seq
|
||||
* @rs_st_inout Vector that will hold the output samples. \product
|
||||
* provides this vector to the StreamReader to fill. For each call,
|
||||
* the size of the vector is zero.
|
||||
* The data representation associated with the samples will be given
|
||||
* by the value of TypeInfo::data_representation_kind that is
|
||||
* part of the StreamInfo object passed at StreamWriter creation
|
||||
* time.
|
||||
* Usually the data representation is dynamic type, which corresponds
|
||||
* to dds::core::xtypes::DynamicData.
|
||||
* @param info_seq
|
||||
* @rs_st_inout Vector that will hold the output info samples. \product
|
||||
* provides this vector to the StreamReader to fill. For each call,
|
||||
* the size of the vector is zero.
|
||||
* The implementation may leave the vector untouched if it does not
|
||||
* support the concept of sample info.
|
||||
* The info representation is dependent of the StreamWriter
|
||||
* implementation.
|
||||
* Usually when data representation is dynamic type, the sample
|
||||
* info is dds::sub::SampleInfo.
|
||||
*
|
||||
* @throw std::exception
|
||||
*/
|
||||
virtual void take(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>& info_seq) = 0;
|
||||
|
||||
/**
|
||||
* @brief Variation of StreamReader::take where the returned samples will
|
||||
* remain in the StreamReader's cache, so they can be read again by
|
||||
* subsequence StreamReader::take or StreamReader::read operations.
|
||||
*
|
||||
* @see StreamReader::take
|
||||
*/
|
||||
virtual void read(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>& info_seq) = 0;
|
||||
|
||||
/**
|
||||
* @brief Variation of StreamReader::take where the returned samples shall
|
||||
* represent the subset specified by the SelectorState.
|
||||
*
|
||||
* SelectorState is configured accordingly from the values set on
|
||||
* rti::routing::processor::Selector. This operation will be called only
|
||||
* by custom rti::routing::processor::Processor implementations.
|
||||
*
|
||||
* @param sample_seq
|
||||
* @param info_seq
|
||||
* @param selector_state
|
||||
* @rs_st_in A description of the subset of samples that shall
|
||||
* be returned.
|
||||
*
|
||||
* @see SelectorState.
|
||||
*/
|
||||
virtual void take(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>& info_seq,
|
||||
const SelectorState& selector_state) = 0;
|
||||
|
||||
/**
|
||||
* @brief Variation of StreamReader::read where the returned samples shall
|
||||
* represent the subset specified by the SelectorState.
|
||||
*
|
||||
* SelectorState is configured accordingly from the values set on
|
||||
* rti::routing::processor::Selector. This operation will be called only
|
||||
* by custom rti::routing::processor::Processor implementations.
|
||||
*
|
||||
* @param sample_seq
|
||||
* @param info_seq
|
||||
* @param selector_state
|
||||
* @rs_st_in A description of the subset of samples that shall
|
||||
* be returned.
|
||||
*
|
||||
* @see SelectorState.
|
||||
*/
|
||||
virtual void read(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>& info_seq,
|
||||
const SelectorState& selector_state) = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns a loan on the read or taken data samples and info samples.
|
||||
*
|
||||
* \product calls this method to indicate that it is done accessing
|
||||
* the collection of data samples and info samples obtained by an earlier
|
||||
* invocation of any variation of StreamReader::take.
|
||||
*
|
||||
* @param sample_seq
|
||||
* @rs_st_in Vector of loaned data samples.
|
||||
* @param info_seq
|
||||
* @rs_st_in Vector of loaned info samples.
|
||||
*
|
||||
* @throw std::exception
|
||||
*
|
||||
*/
|
||||
virtual void return_loan(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>& info_seq) = 0;
|
||||
|
||||
/**
|
||||
* @brief Creates a query object that selects the data with the specified
|
||||
* filter.
|
||||
*
|
||||
* This operation allows to read data with a SelectorState that contains
|
||||
* a query object returned by this operation.
|
||||
*
|
||||
* A query object type is implementation dependent and it's guaranteed to
|
||||
* to be used only within the same StreamReader that created it. Because
|
||||
* a query object may be a expensive resource, this operation allows to
|
||||
* receive a previously created query for a potential reuse and update of
|
||||
* its filter.
|
||||
*
|
||||
* @param[in] old_query_data A previously created query object that
|
||||
* that is provided for potential reuse and update of its filter.
|
||||
* @param[in] filter The query content filter
|
||||
*
|
||||
* @return The new or updated query object.
|
||||
*
|
||||
* @throw std::exception
|
||||
*
|
||||
*/
|
||||
virtual void* create_content_query(
|
||||
void *old_query_data,
|
||||
const dds::topic::Filter& filter) = 0;
|
||||
|
||||
/**
|
||||
* @brief Deletes a content query created from this StreamReader.
|
||||
*
|
||||
* @param[in] query_data the query object to be deleted.
|
||||
*/
|
||||
virtual void delete_content_query(void* query_data) = 0;
|
||||
|
||||
/**
|
||||
* @brief Virtual destructor.
|
||||
*/
|
||||
virtual ~StreamReader()
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @class rti::routing::adapter::TStreamReader
|
||||
*
|
||||
* @brief A wrapper implementation of a StreamReader that provides a
|
||||
* strongly-typed interface through template parameters for data and info
|
||||
* representation.
|
||||
*
|
||||
* You can implement this interface as a convenience to manipulate the data
|
||||
* and info representation without dealing with opaque pointers.
|
||||
*/
|
||||
template <typename Data, typename Info>
|
||||
class TStreamReader : public StreamReader {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief The data type
|
||||
*/
|
||||
typedef Data DataRep;
|
||||
/**
|
||||
* @brief The info type
|
||||
*/
|
||||
typedef Info InfoRep;
|
||||
|
||||
using StreamReader::take;
|
||||
using StreamReader::read;
|
||||
using StreamReader::return_loan;
|
||||
|
||||
/**
|
||||
* @brief Performs the conversion between the vector of data and info
|
||||
* pointers to strongly-type pointers.
|
||||
*/
|
||||
void take(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>& info_seq) RTI_FINAL
|
||||
{
|
||||
take(sample_seq_, info_seq_);
|
||||
convert_samples(sample_seq, info_seq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs the conversion between the vector of data and info
|
||||
* pointers to strongly-type pointers.
|
||||
*/
|
||||
void read(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>& info_seq) RTI_FINAL
|
||||
{
|
||||
read(sample_seq_, info_seq_);
|
||||
convert_samples(sample_seq, info_seq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs the conversion between the vector of data and info
|
||||
* pointers to strongly-type pointers.
|
||||
*/
|
||||
void take(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>& info_seq,
|
||||
const SelectorState& selector_state) RTI_FINAL
|
||||
{
|
||||
take(sample_seq_, info_seq_, selector_state);
|
||||
convert_samples(sample_seq, info_seq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs the conversion between the vector of data and info
|
||||
* pointers to strongly-type pointers.
|
||||
*/
|
||||
void read(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>& info_seq,
|
||||
const SelectorState& selector_state) RTI_FINAL
|
||||
{
|
||||
read(sample_seq_, info_seq_, selector_state);
|
||||
convert_samples(sample_seq, info_seq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs the conversion between the vector of data and info
|
||||
* pointers to strongly-type pointers.
|
||||
*/
|
||||
void return_loan(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>& info_seq) RTI_FINAL
|
||||
{
|
||||
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(sample_seq_, sample_seq);
|
||||
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(info_seq_, info_seq);
|
||||
return_loan(sample_seq_, info_seq_);
|
||||
sample_seq_.clear();
|
||||
info_seq_.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Interface redefinition
|
||||
*
|
||||
* @see StreamReader::take
|
||||
*/
|
||||
virtual void take(
|
||||
std::vector<Data*>& sample_seq,
|
||||
std::vector<Info*>& info_seq) = 0;
|
||||
|
||||
/**
|
||||
* @brief Interface redefinition
|
||||
*
|
||||
* @see StreamReader::read
|
||||
*/
|
||||
virtual void read(
|
||||
std::vector<Data*>& sample_seq,
|
||||
std::vector<Info*>& info_seq) = 0;
|
||||
|
||||
/**
|
||||
* @brief Interface redefinition
|
||||
*
|
||||
* @see StreamReader::take(std::vector&, std::vector&,const SelectorState&);
|
||||
*/
|
||||
virtual void take(
|
||||
std::vector<Data*>& sample_seq,
|
||||
std::vector<Info*>& info_seq,
|
||||
const SelectorState& selector_state) = 0;
|
||||
|
||||
/**
|
||||
* @brief Interface redefinition
|
||||
*
|
||||
* @see StreamReader::read(std::vector&, std::vector&,const SelectorState&);
|
||||
*/
|
||||
virtual void read(
|
||||
std::vector<Data*>& sample_seq,
|
||||
std::vector<Info*>& info_seq,
|
||||
const SelectorState& selector_state) = 0;
|
||||
|
||||
/**
|
||||
* @brief Interface redefinition
|
||||
*
|
||||
* @see StreamReader::return_loan
|
||||
*/
|
||||
virtual void return_loan(
|
||||
std::vector<Data*>& sample_seq,
|
||||
std::vector<Info*>& info_seq) = 0;
|
||||
|
||||
/*
|
||||
* @brief Virtual destructor
|
||||
*/
|
||||
virtual ~TStreamReader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
void convert_samples(
|
||||
std::vector<SamplePtr>& sample_seq,
|
||||
std::vector<InfoPtr>& info_seq)
|
||||
{
|
||||
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(sample_seq, sample_seq_);
|
||||
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(info_seq, info_seq_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Data*> sample_seq_;
|
||||
std::vector<Info*> info_seq_;
|
||||
|
||||
};
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @class rti::routing::adapter::NoOpStreamReader
|
||||
*
|
||||
* @brief An empty implementation of the TStreamReader interface.
|
||||
*
|
||||
* Each implemented operation performs as a no-op.
|
||||
*/
|
||||
template <typename Data, typename Info>
|
||||
class NoOpStreamReader : public TStreamReader<Data, Info> {
|
||||
|
||||
public:
|
||||
virtual void take(
|
||||
std::vector<Data*>&,
|
||||
std::vector<Info*>&) RTI_OVERRIDE
|
||||
{
|
||||
}
|
||||
|
||||
virtual void read(
|
||||
std::vector<Data*>&,
|
||||
std::vector<Info*>&) RTI_OVERRIDE
|
||||
{
|
||||
}
|
||||
|
||||
virtual void take(
|
||||
std::vector<Data*>&,
|
||||
std::vector<Info*>&,
|
||||
const SelectorState&) RTI_OVERRIDE
|
||||
{
|
||||
}
|
||||
|
||||
virtual void read(
|
||||
std::vector<Data*>&,
|
||||
std::vector<Info*>&,
|
||||
const SelectorState&) RTI_OVERRIDE
|
||||
{
|
||||
}
|
||||
|
||||
virtual void return_loan(
|
||||
std::vector<Data*>&,
|
||||
std::vector<Info*>&) RTI_OVERRIDE
|
||||
{
|
||||
}
|
||||
|
||||
virtual void* create_content_query(
|
||||
void *,
|
||||
const dds::topic::Filter&) RTI_OVERRIDE
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
virtual void delete_content_query(void*) RTI_OVERRIDE
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual ~NoOpStreamReader()
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @brief Convenient definition of typed StreamReader that requires
|
||||
* dds::core::xtypes::DynamicData for data samples and dds::sub::SampleInfo
|
||||
* for info samples.
|
||||
*
|
||||
*/
|
||||
typedef NoOpStreamReader<dds::core::xtypes::DynamicData, dds::sub::SampleInfo>
|
||||
DynamicDataStreamReader;
|
||||
|
||||
|
||||
|
||||
class SelectorStateAdapter {
|
||||
public:
|
||||
typedef RTI_RoutingServiceSelectorState native_type;
|
||||
|
||||
static void initialize(native_type& native_value)
|
||||
{
|
||||
RTI_RoutingServiceSelectorState native_state =
|
||||
RTI_RoutingServiceSelectorState_INITIALIZER;
|
||||
memcpy(&native_value, &native_state, sizeof(native_state));
|
||||
}
|
||||
|
||||
static void finalize(native_type& native_value)
|
||||
{
|
||||
if (native_value.content.expression != NULL) {
|
||||
DDS_String_free(native_value.content.expression);
|
||||
}
|
||||
DDS_StringSeq_finalize(&native_value.content.expression_parameters);
|
||||
}
|
||||
|
||||
static void copy(native_type& destination, const native_type& source)
|
||||
{
|
||||
destination.sample_state = source.sample_state;
|
||||
destination.view_state = source.view_state;
|
||||
destination.instance_state = source.instance_state;
|
||||
destination.instance_handle = source.instance_handle;
|
||||
destination.instance_selection = source.instance_selection;
|
||||
destination.sample_count_max = source.sample_count_max;
|
||||
destination.query_data = source.query_data;
|
||||
char *result = DDS_String_replace(
|
||||
&destination.content.expression,
|
||||
source.content.expression);
|
||||
if (source.content.expression != NULL && result == NULL) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
if (DDS_StringSeq_copy(
|
||||
&destination.content.expression_parameters,
|
||||
&source.content.expression_parameters) == NULL) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
static bool equals(const native_type& first, const native_type& second)
|
||||
{
|
||||
if (first.sample_state != second.sample_state) {
|
||||
return false;
|
||||
}
|
||||
if (first.view_state != second.view_state) {
|
||||
return false;
|
||||
}
|
||||
if (first.instance_state != second.instance_state) {
|
||||
return false;
|
||||
}
|
||||
if (first.instance_selection != second.instance_selection) {
|
||||
return false;
|
||||
}
|
||||
if (first.sample_count_max != second.sample_count_max) {
|
||||
return false;
|
||||
}
|
||||
if (first.query_data != second.query_data) {
|
||||
return false;
|
||||
}
|
||||
if (first.content.expression != NULL
|
||||
&& second.content.expression != NULL
|
||||
&& strcmp(first.content.expression, second.content.expression) != 0) {
|
||||
return false;
|
||||
}
|
||||
return DDS_StringSeq_equals(
|
||||
&first.content.expression_parameters,
|
||||
&second.content.expression_parameters);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
// native_type_traits needs to be defined in rti::core
|
||||
namespace core {
|
||||
|
||||
template <>
|
||||
struct native_type_traits<rti::routing::adapter::SelectorState> {
|
||||
typedef rti::routing::adapter::SelectorStateAdapter adapter_type;
|
||||
typedef RTI_RoutingServiceSelectorState native_type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace routing { namespace adapter {
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @class rti::routing::adapter::SelectorState
|
||||
*
|
||||
* @brief Defines a set of attributes that can be used to read a subset of
|
||||
* data from StreamReader.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
class SelectorState : public rti::core::NativeValueType<SelectorState> {
|
||||
public:
|
||||
RTI_NATIVE_VALUE_TYPE_DEFINE_DEFAULT_MOVE_OPERATIONS(SelectorState)
|
||||
|
||||
typedef rti::core::NativeValueType<SelectorState> Base;
|
||||
public:
|
||||
SelectorState()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SelectorState(const RTI_RoutingServiceSelectorState &native)
|
||||
: Base(native)
|
||||
{
|
||||
}
|
||||
|
||||
dds::sub::status::DataState state() const
|
||||
{
|
||||
return dds::sub::status::DataState(
|
||||
dds::sub::status::SampleState(native().sample_state),
|
||||
dds::sub::status::ViewState(native().view_state),
|
||||
dds::sub::status::InstanceState(native().instance_state));
|
||||
}
|
||||
|
||||
SelectorState& state(const dds::sub::status::DataState& state)
|
||||
{
|
||||
native().sample_state = static_cast<DDS_SampleStateMask>(
|
||||
state.sample_state().to_ulong());
|
||||
native().view_state = static_cast<DDS_ViewStateMask>(
|
||||
state.view_state().to_ulong());
|
||||
native().instance_state = static_cast<DDS_InstanceStateMask>(
|
||||
state.instance_state().to_ulong());
|
||||
return *this;
|
||||
}
|
||||
|
||||
int32_t max_samples() const
|
||||
{
|
||||
return native().sample_count_max;
|
||||
}
|
||||
|
||||
SelectorState& max_samples(const int32_t count)
|
||||
{
|
||||
native().sample_count_max = count;
|
||||
return *this;
|
||||
}
|
||||
|
||||
dds::core::InstanceHandle instance() const
|
||||
{
|
||||
if (native().instance_selection
|
||||
== RTI_ROUTING_SERVICE_THIS_INSTANCE_SELECTION) {
|
||||
return rti::core::native_conversions::from_native_handle(
|
||||
native().instance_handle);
|
||||
}
|
||||
|
||||
return dds::core::InstanceHandle::nil();
|
||||
}
|
||||
|
||||
SelectorState& instance(const dds::core::InstanceHandle& handle)
|
||||
{
|
||||
native().instance_handle =
|
||||
static_cast<DDS_InstanceHandle_t>(handle->native());
|
||||
native().instance_selection = RTI_ROUTING_SERVICE_THIS_INSTANCE_SELECTION;
|
||||
return *this;
|
||||
}
|
||||
|
||||
dds::core::InstanceHandle next_instance() const
|
||||
{
|
||||
if (native().instance_selection
|
||||
== RTI_ROUTING_SERVICE_NEXT_INSTANCE_SELECTION) {
|
||||
return rti::core::native_conversions::from_native_handle(
|
||||
native().instance_handle);
|
||||
}
|
||||
|
||||
return dds::core::InstanceHandle::nil();
|
||||
}
|
||||
|
||||
SelectorState& next_instance(
|
||||
const dds::core::InstanceHandle& handle)
|
||||
{
|
||||
native().instance_handle =
|
||||
static_cast<DDS_InstanceHandle_t>(handle->native());
|
||||
native().instance_selection = RTI_ROUTING_SERVICE_NEXT_INSTANCE_SELECTION;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void* content()
|
||||
{
|
||||
return native().query_data;
|
||||
}
|
||||
|
||||
SelectorState& content(void *query_data)
|
||||
{
|
||||
native().query_data = query_data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
dds::topic::Filter filter() const
|
||||
{
|
||||
return dds::topic::Filter(
|
||||
native().content.expression == NULL ? "" : native().content.expression,
|
||||
rti::core::native_conversions::from_native<std::string>(
|
||||
native().content.expression_parameters));
|
||||
}
|
||||
|
||||
SelectorState& filter(const dds::topic::Filter& filter)
|
||||
{
|
||||
DDS_String_replace(
|
||||
&native().content.expression,
|
||||
filter.expression().c_str());
|
||||
rti::core::native_conversions::to_native(
|
||||
native().content.expression_parameters,
|
||||
filter->parameters());
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_STREAM_READER_HPP_
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* (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_ADAPTER_STREAM_READER_LISTENER_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_STREAM_READER_LISTENER_HPP_
|
||||
|
||||
#include <rti/routing/adapter/detail/StreamReaderListenerForwarder.hpp>
|
||||
|
||||
namespace rti { namespace routing { namespace adapter {
|
||||
|
||||
using detail::StreamReaderListener;
|
||||
|
||||
}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_STREAM_READER_LISTENER_HPP_
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* (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_ADAPTER_STREAM_WRITER_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_STREAM_WRITER_HPP_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <rti/routing/UpdatableEntity.hpp>
|
||||
#include <rti/routing/detail/ForwarderUtils.hpp>
|
||||
|
||||
namespace rti { namespace routing { namespace adapter {
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @class rti::routing::adapter::StreamWriter
|
||||
*
|
||||
* @brief Provides a way to write samples of a specific type in a data domain.
|
||||
*
|
||||
* In the XML configuration file, A StreamWriter is associated with the tag
|
||||
* <output> within <route> or <auto_route>.
|
||||
*
|
||||
* @mtsafety Partially Safe
|
||||
* All operations on a concrete StreamWriter objects are safe and
|
||||
* always serialized on a given Session. Operations on different
|
||||
* StreamWriter objects can be called concurrently if the
|
||||
* StreamWriter objects belong to different Sessions.
|
||||
*/
|
||||
class StreamWriter : public UpdatableEntity {
|
||||
|
||||
public:
|
||||
|
||||
typedef void* SamplePtr;
|
||||
typedef void* InfoPtr;
|
||||
|
||||
/**
|
||||
* @brief Writes a collection of data samples to the output stream
|
||||
* associated with this StreamWriter.
|
||||
*
|
||||
* @param sample_seq
|
||||
* @rs_st_in Vector of sample pointers.
|
||||
* The data representation associated with the samples will be given
|
||||
* by the value of TypeInfo::data_representation_kind that is
|
||||
* part of the StreamInfo object passed at StreamWriter creation
|
||||
* time.
|
||||
* Usually the data representation is dynamic type, which corresponds
|
||||
* to dds::core::xtypes::DynamicData.
|
||||
* @param info_seq
|
||||
* @rs_st_in Vector of sample info pointers.
|
||||
* The info representation is dependent of the StreamWriter
|
||||
* implementation.
|
||||
* Usually when data representation is dynamic type, the sample
|
||||
* info is dds::sub::SampleInfo.
|
||||
* @return Number of samples written.
|
||||
* @throw std::exception
|
||||
*/
|
||||
virtual int write(
|
||||
const std::vector<SamplePtr>& sample_seq,
|
||||
const std::vector<InfoPtr>& info_seq) = 0;
|
||||
|
||||
/**
|
||||
* @brief Virtual destructor
|
||||
*/
|
||||
virtual ~StreamWriter()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @class rti::routing::adapter::TStreamWriter
|
||||
*
|
||||
* @brief A wrapper implementation of a StreamWriter that provides a
|
||||
* strongly-typed interface through template parameters for data and info
|
||||
* representation.
|
||||
*
|
||||
* You can implement this interface as a convenience to manipulate the data
|
||||
* and info representation without dealing with opaque pointers.
|
||||
*/
|
||||
template <typename Data, typename Info>
|
||||
class TStreamWriter : public StreamWriter {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief The data type
|
||||
*/
|
||||
typedef Data DataRep;
|
||||
typedef DataRep* DataRepPtr;
|
||||
/**
|
||||
* @brief The info type
|
||||
*/
|
||||
typedef Info InfoRep;
|
||||
typedef InfoRep* InfoRepPtr;
|
||||
|
||||
/**
|
||||
* @brief Performs the conversion between the vector of data and info
|
||||
* pointers to strongly-type pointers.
|
||||
*/
|
||||
int write(
|
||||
const std::vector<SamplePtr>& sample_seq,
|
||||
const std::vector<InfoPtr>& info_seq) RTI_FINAL
|
||||
{
|
||||
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(sample_seq_, sample_seq);
|
||||
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(info_seq_, info_seq);
|
||||
|
||||
return write(sample_seq_, info_seq_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Interface redefinition
|
||||
*
|
||||
* @see StreamWriter::write
|
||||
*/
|
||||
virtual int write(
|
||||
const std::vector<Data*>& sample_seq,
|
||||
const std::vector<Info*>& info_seq) = 0;
|
||||
|
||||
/**
|
||||
* @brief Virtual destructor
|
||||
*/
|
||||
virtual ~TStreamWriter()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Data*> sample_seq_;
|
||||
std::vector<Info*> info_seq_;
|
||||
};
|
||||
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @brief Convenient definition of typed StreamWriter that requires
|
||||
* dds::core::xtypes::DynamicData for data samples and dds::sub::SampleInfo
|
||||
* for info samples.
|
||||
*
|
||||
*/
|
||||
typedef TStreamWriter<dds::core::xtypes::DynamicData, dds::sub::SampleInfo>
|
||||
DynamicDataStreamWriter;
|
||||
|
||||
}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_STREAM_WRITER_HPP_
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* (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_ADAPTER_DETAIL_ADAPTER_FORWARDER_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_DETAIL_ADAPTER_FORWARDER_HPP_
|
||||
|
||||
#include <rti/core/Exception.hpp>
|
||||
|
||||
#include <routingservice/routingservice_adapter_new.h>
|
||||
|
||||
#include <rti/routing/adapter/detail/ConnectionForwarder.hpp>
|
||||
|
||||
namespace rti { namespace routing { namespace adapter { namespace detail {
|
||||
|
||||
|
||||
class AdapterForwarder {
|
||||
public:
|
||||
static RTI_RoutingServiceAdapterPluginExt * create_plugin(
|
||||
AdapterPlugin *adapter_plugin)
|
||||
{
|
||||
RTI_RoutingServiceAdapterPluginExt *native_adapter = NULL;
|
||||
RTIOsapiHeap_allocateStructure(
|
||||
&native_adapter,
|
||||
struct RTI_RoutingServiceAdapterPluginExt);
|
||||
rti::core::check_create_entity(
|
||||
native_adapter,
|
||||
"RTI_RoutingServiceAdapterPluginExt");
|
||||
RTI_RoutingServiceAdapterPluginExt_initialize(native_adapter);
|
||||
|
||||
// Set adapter version
|
||||
rti::config::LibraryVersion version = adapter_plugin->get_version();
|
||||
native_adapter->plugin_version.major = version.major_version();
|
||||
native_adapter->plugin_version.minor = version.minor_version();
|
||||
native_adapter->plugin_version.release = version.release_version();
|
||||
|
||||
// Initialize adapter methods
|
||||
native_adapter->adapter_plugin_data =
|
||||
static_cast<void *>(adapter_plugin);
|
||||
native_adapter->plugin_delete =
|
||||
AdapterForwarder::delete_plugin;
|
||||
native_adapter->create_connection =
|
||||
AdapterForwarder::create_connection;
|
||||
native_adapter->delete_connection =
|
||||
AdapterForwarder::delete_connection;
|
||||
|
||||
|
||||
return native_adapter;
|
||||
}
|
||||
|
||||
static void delete_plugin(
|
||||
void *native_adapter_data,
|
||||
RTI_RoutingServiceEnvironment *)
|
||||
{
|
||||
RTI_RoutingServiceAdapterPluginExt *native_adapter =
|
||||
static_cast<RTI_RoutingServiceAdapterPluginExt *>(
|
||||
native_adapter_data);
|
||||
AdapterPlugin *adapter = static_cast<AdapterPlugin *>(
|
||||
native_adapter->adapter_plugin_data);
|
||||
// Plug-in is destructor not allowed to throw
|
||||
delete adapter;
|
||||
RTIOsapiHeap_freeStructure(native_adapter);
|
||||
}
|
||||
|
||||
static RTI_RoutingServiceConnectionExt* create_connection(
|
||||
void *native_adapter_data,
|
||||
const char *routing_service_name,
|
||||
const char *routing_service_group_name,
|
||||
const RTI_RoutingServiceStreamReaderListenerExt *native_output_stream_listener,
|
||||
const RTI_RoutingServiceStreamReaderListenerExt *native_input_stream_listener,
|
||||
const RTI_RoutingServiceTypeInfo **registered_types,
|
||||
int registered_type_count,
|
||||
const RTI_RoutingServiceProperties *native_properties,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
return ConnectionForwarder::create_native(
|
||||
static_cast<AdapterPlugin *>(native_adapter_data),
|
||||
routing_service_name,
|
||||
routing_service_group_name,
|
||||
native_output_stream_listener,
|
||||
native_input_stream_listener,
|
||||
registered_types,
|
||||
registered_type_count,
|
||||
native_properties,
|
||||
environment);
|
||||
}
|
||||
|
||||
static void delete_connection(
|
||||
void *native_adapter_data,
|
||||
RTI_RoutingServiceConnectionExt *native_connection,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
ConnectionForwarder::delete_native(
|
||||
static_cast<AdapterPlugin *>(native_adapter_data),
|
||||
native_connection,
|
||||
environment);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_DETAIL_ADAPTER_FORWARDER_HPP_
|
||||
+335
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* (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_ADAPTER_DETAIL_CONNECTION_FORWARDER_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_DETAIL_CONNECTION_FORWARDER_HPP_
|
||||
|
||||
#include <rti/core/Exception.hpp>
|
||||
|
||||
#include <rti/apputils/ServiceException.hpp>
|
||||
|
||||
#include <osapi/osapi_heap.h>
|
||||
#include <routingservice/routingservice_adapter_new.h>
|
||||
|
||||
#include <rti/routing/adapter/detail/SessionForwarder.hpp>
|
||||
#include <rti/routing/adapter/detail/StreamReaderForwarder.hpp>
|
||||
#include <rti/routing/adapter/detail/StreamWriterForwarder.hpp>
|
||||
#include <rti/routing/adapter/detail/DiscoveryStreamReaderForwarder.hpp>
|
||||
#include <rti/routing/detail/UpdatableEntityForwarder.hpp>
|
||||
#include <rti/routing/detail/ForwarderUtils.hpp>
|
||||
|
||||
namespace rti { namespace routing { namespace adapter { namespace detail {
|
||||
|
||||
class ConnectionForwarder {
|
||||
public:
|
||||
static RTI_RoutingServiceConnectionExt * create_native(
|
||||
AdapterPlugin *adapter,
|
||||
const char *,
|
||||
const char *,
|
||||
const RTI_RoutingServiceStreamReaderListenerExt *native_output_stream_listener,
|
||||
const RTI_RoutingServiceStreamReaderListenerExt *native_input_stream_listener,
|
||||
const RTI_RoutingServiceTypeInfo **,
|
||||
int,
|
||||
const RTI_RoutingServiceProperties *native_properties,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
try {
|
||||
using rti::routing::detail::ScopedForwarder;
|
||||
|
||||
// Set properties
|
||||
std::map<std::string, std::string> properties;
|
||||
rti::routing::PropertyAdapter::add_properties_from_native(
|
||||
properties,
|
||||
native_properties);
|
||||
|
||||
ConnectionForwarder *forwarder = new ConnectionForwarder(
|
||||
native_output_stream_listener,
|
||||
native_input_stream_listener);
|
||||
ScopedForwarder<AdapterPlugin, ConnectionForwarder> scoped(
|
||||
adapter,
|
||||
forwarder,
|
||||
environment);
|
||||
// Create connection
|
||||
forwarder->connection_ = adapter->create_connection(
|
||||
&forwarder->input_discovery_listener_,
|
||||
&forwarder->output_discovery_listener_,
|
||||
properties);
|
||||
RTI_ROUTING_THROW_ON_NULL(forwarder->connection_);
|
||||
|
||||
// Create built-in SRs
|
||||
forwarder->input_stream_discovery_forwarder_ =
|
||||
new DiscoveryStreamReaderForwarder(
|
||||
forwarder->connection_
|
||||
->input_stream_discovery_reader());
|
||||
|
||||
forwarder->output_stream_discovery_forwarder_ =
|
||||
new DiscoveryStreamReaderForwarder(
|
||||
forwarder->connection_
|
||||
->output_stream_discovery_reader());
|
||||
|
||||
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(
|
||||
AdapterPlugin *adapter,
|
||||
RTI_RoutingServiceConnectionExt *native_connection,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
ConnectionForwarder *forwarder = static_cast<ConnectionForwarder*>(
|
||||
native_connection->connection_data);
|
||||
try {
|
||||
// delete built-in SRs
|
||||
delete forwarder->input_stream_discovery_forwarder_;
|
||||
delete forwarder->output_stream_discovery_forwarder_;
|
||||
|
||||
// delete connection
|
||||
if (forwarder->connection_ != NULL) {
|
||||
adapter->delete_connection(forwarder->connection_);
|
||||
forwarder->connection_ = 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 (...) {
|
||||
}
|
||||
|
||||
delete forwarder;
|
||||
}
|
||||
|
||||
|
||||
static RTI_RoutingServiceStreamReaderExt *
|
||||
get_input_stream_discovery_reader(
|
||||
void *native_connection_data,
|
||||
RTI_RoutingServiceEnvironment *)
|
||||
{
|
||||
ConnectionForwarder *forwarder = static_cast<ConnectionForwarder*>(
|
||||
native_connection_data);
|
||||
return forwarder->input_stream_discovery_forwarder_->native();
|
||||
}
|
||||
|
||||
static RTI_RoutingServiceStreamReaderExt *
|
||||
get_output_stream_discovery_reader(
|
||||
void *native_connection_data,
|
||||
RTI_RoutingServiceEnvironment *)
|
||||
{
|
||||
ConnectionForwarder *forwarder = static_cast<ConnectionForwarder*>(
|
||||
native_connection_data);
|
||||
return forwarder->output_stream_discovery_forwarder_->native();
|
||||
}
|
||||
|
||||
static RTI_RoutingServiceSessionExt * create_session(
|
||||
void *native_connection_data,
|
||||
const struct RTI_RoutingServiceProperties * native_properties,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
|
||||
ConnectionForwarder *forwarder = static_cast<ConnectionForwarder*>(
|
||||
native_connection_data);
|
||||
|
||||
return SessionForwarder::create_native(
|
||||
forwarder->connection_,
|
||||
native_properties,
|
||||
environment);
|
||||
}
|
||||
|
||||
static void delete_session(
|
||||
void *native_connection_data,
|
||||
RTI_RoutingServiceSessionExt *native_session,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
ConnectionForwarder *forwarder = static_cast<ConnectionForwarder*> (
|
||||
native_connection_data);
|
||||
|
||||
SessionForwarder::delete_native(
|
||||
forwarder->connection_,
|
||||
native_session,
|
||||
environment);
|
||||
}
|
||||
|
||||
static RTI_RoutingServiceStreamReaderExt* create_stream_reader(
|
||||
void *native_connection_data,
|
||||
void *native_session_data,
|
||||
const struct RTI_RoutingServiceStreamInfo *native_stream_info,
|
||||
const struct RTI_RoutingServiceProperties *native_properties,
|
||||
const struct RTI_RoutingServiceStreamReaderListenerExt *native_listener,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
ConnectionForwarder *forwarder = static_cast<ConnectionForwarder*>(
|
||||
native_connection_data);
|
||||
SessionForwarder *session_forwarder = static_cast<SessionForwarder*>(
|
||||
native_session_data);
|
||||
|
||||
return StreamReaderForwarder::create_native(
|
||||
forwarder->connection_,
|
||||
session_forwarder->session(),
|
||||
native_stream_info,
|
||||
native_properties,
|
||||
native_listener,
|
||||
environment);
|
||||
}
|
||||
|
||||
static void delete_stream_reader(
|
||||
void *native_connection_data,
|
||||
RTI_RoutingServiceStreamReaderExt *native_reader,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
ConnectionForwarder *forwarder = static_cast<ConnectionForwarder*>(
|
||||
native_connection_data);
|
||||
StreamReaderForwarder::delete_native(
|
||||
forwarder->connection_,
|
||||
native_reader,
|
||||
environment);
|
||||
}
|
||||
|
||||
static RTI_RoutingServiceStreamWriterExt* create_stream_writer(
|
||||
void *native_connection_data,
|
||||
void *native_session_data,
|
||||
const struct RTI_RoutingServiceStreamInfo *native_stream_info,
|
||||
const struct RTI_RoutingServiceProperties *native_properties,
|
||||
const struct RTI_RoutingServiceStreamWriterListenerExt *,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
ConnectionForwarder *forwarder = static_cast<ConnectionForwarder*>(
|
||||
native_connection_data);
|
||||
SessionForwarder *session_forwarder = static_cast<SessionForwarder*>(
|
||||
native_session_data);
|
||||
|
||||
return StreamWriterForwarder::create_native(
|
||||
forwarder->connection_,
|
||||
session_forwarder->session(),
|
||||
native_stream_info,
|
||||
native_properties,
|
||||
environment);
|
||||
}
|
||||
|
||||
static void delete_stream_writer(
|
||||
void *native_connection_data,
|
||||
RTI_RoutingServiceStreamWriterExt *native_writer,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
ConnectionForwarder *forwarder = static_cast<ConnectionForwarder*>(
|
||||
native_connection_data);
|
||||
StreamWriterForwarder::delete_native(
|
||||
forwarder->connection_,
|
||||
native_writer,
|
||||
environment);
|
||||
}
|
||||
|
||||
static void update(
|
||||
void *native_connection_data,
|
||||
const struct RTI_RoutingServiceProperties *native_properties,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
ConnectionForwarder *forwarder =
|
||||
static_cast<ConnectionForwarder*> (native_connection_data);
|
||||
|
||||
rti::routing::detail::UpdatableEntityForwarder::update(
|
||||
forwarder->connection_,
|
||||
native_properties,
|
||||
environment);
|
||||
}
|
||||
|
||||
|
||||
Connection * connection()
|
||||
{
|
||||
return connection_;
|
||||
}
|
||||
|
||||
RTI_RoutingServiceConnectionExt* native()
|
||||
{
|
||||
return &this->native_;
|
||||
}
|
||||
|
||||
RTI_RoutingServiceStreamReaderExt* native_input_discovery_reader()
|
||||
{
|
||||
return input_stream_discovery_forwarder_->native();
|
||||
}
|
||||
|
||||
RTI_RoutingServiceStreamReaderExt* native_output_discovery_reader()
|
||||
{
|
||||
return output_stream_discovery_forwarder_->native();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
ConnectionForwarder(
|
||||
const RTI_RoutingServiceStreamReaderListenerExt *native_output_stream_listener,
|
||||
const RTI_RoutingServiceStreamReaderListenerExt *native_input_stream_listener) :
|
||||
connection_(NULL),
|
||||
output_stream_discovery_forwarder_(NULL),
|
||||
output_discovery_listener_(native_output_stream_listener),
|
||||
input_stream_discovery_forwarder_(NULL),
|
||||
input_discovery_listener_(native_input_stream_listener)
|
||||
{
|
||||
RTIOsapiMemory_zero(&native_, sizeof(native_));
|
||||
|
||||
native_.connection_data = static_cast<void*>(this);
|
||||
native_.create_session = ConnectionForwarder::create_session;
|
||||
native_.delete_session = ConnectionForwarder::delete_session;
|
||||
native_.create_stream_reader =
|
||||
ConnectionForwarder::create_stream_reader;
|
||||
native_.delete_stream_reader =
|
||||
ConnectionForwarder::delete_stream_reader;
|
||||
native_.create_stream_writer =
|
||||
ConnectionForwarder::create_stream_writer;
|
||||
native_.delete_stream_writer =
|
||||
ConnectionForwarder::delete_stream_writer;
|
||||
native_.get_input_stream_discovery_reader =
|
||||
ConnectionForwarder::get_input_stream_discovery_reader;
|
||||
native_.get_output_stream_discovery_reader =
|
||||
ConnectionForwarder::get_output_stream_discovery_reader;
|
||||
native_.update = ConnectionForwarder::update;
|
||||
}
|
||||
|
||||
~ConnectionForwarder()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
RTI_RoutingServiceConnectionExt native_;
|
||||
Connection *connection_;
|
||||
DiscoveryStreamReaderForwarder *output_stream_discovery_forwarder_;
|
||||
StreamReaderListener output_discovery_listener_;
|
||||
DiscoveryStreamReaderForwarder *input_stream_discovery_forwarder_;
|
||||
StreamReaderListener input_discovery_listener_;
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_DETAIL_CONNECTION_FORWARDER_HPP_
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* (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_ADAPTER_DETAIL_DISCOVERY_STREAM_READER_FORWARDER_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_DETAIL_DISCOVERY_STREAM_READER_FORWARDER_HPP_
|
||||
|
||||
#include <rti/core/Exception.hpp>
|
||||
|
||||
#include <rti/apputils/ServiceException.hpp>
|
||||
|
||||
#include <routingservice/routingservice_adapter_new.h>
|
||||
|
||||
#include <rti/routing/adapter/DiscoveryStreamReader.hpp>
|
||||
#include <rti/routing/detail/ForwarderUtils.hpp>
|
||||
|
||||
namespace rti { namespace routing { namespace adapter { namespace detail {
|
||||
|
||||
|
||||
class DiscoveryStreamReaderForwarder {
|
||||
public:
|
||||
static void take(
|
||||
void *native_stream_reader_data,
|
||||
RTI_RoutingServiceSample **sample_array,
|
||||
RTI_RoutingServiceSampleInfo **sample_info_array,
|
||||
int *array_length,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
DiscoveryStreamReaderForwarder *forwarder =
|
||||
static_cast<DiscoveryStreamReaderForwarder*>(
|
||||
native_stream_reader_data);
|
||||
|
||||
*sample_info_array = NULL;
|
||||
*array_length = 0;
|
||||
try {
|
||||
forwarder->stream_reader_->take(forwarder->sample_seq_);
|
||||
*array_length = static_cast<int>(forwarder->sample_seq_.size());
|
||||
if (*array_length > 0) {
|
||||
*sample_array = reinterpret_cast<RTI_RoutingServiceSample*> (
|
||||
&forwarder->sample_seq_[0]);
|
||||
}
|
||||
} 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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void return_loan(
|
||||
void *native_stream_reader_data,
|
||||
RTI_RoutingServiceSample *,
|
||||
RTI_RoutingServiceSampleInfo *,
|
||||
int,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
DiscoveryStreamReaderForwarder *forwarder =
|
||||
static_cast<DiscoveryStreamReaderForwarder*>(
|
||||
native_stream_reader_data);
|
||||
|
||||
try {
|
||||
forwarder->stream_reader_->return_loan(forwarder->sample_seq_);
|
||||
} 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");
|
||||
return;
|
||||
}
|
||||
forwarder->sample_seq_.clear();
|
||||
}
|
||||
|
||||
|
||||
DiscoveryStreamReaderForwarder(
|
||||
DiscoveryStreamReader *stream_reader) :
|
||||
stream_reader_(stream_reader)
|
||||
{
|
||||
RTIOsapiMemory_zero(&native_, sizeof(native_));
|
||||
native_.stream_reader_data =
|
||||
static_cast<void *>(this);
|
||||
native_.take =
|
||||
DiscoveryStreamReaderForwarder::take;
|
||||
native_.return_loan =
|
||||
DiscoveryStreamReaderForwarder::return_loan;
|
||||
}
|
||||
|
||||
|
||||
~DiscoveryStreamReaderForwarder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static DiscoveryStreamReaderForwarder* from_native(
|
||||
RTI_RoutingServiceStreamReaderExt *native)
|
||||
{
|
||||
return static_cast<DiscoveryStreamReaderForwarder*>(
|
||||
native->stream_reader_data);
|
||||
}
|
||||
|
||||
RTI_RoutingServiceStreamReaderExt * native()
|
||||
{
|
||||
return &native_;
|
||||
}
|
||||
|
||||
private:
|
||||
RTI_RoutingServiceStreamReaderExt native_;
|
||||
DiscoveryStreamReader *stream_reader_;
|
||||
std::vector<StreamInfo*> sample_seq_;
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_DETAIL_DISCOVERY_STREAM_READER_FORWARDER_HPP_
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* (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_ADAPTER_DETAIL_READ_PROXY_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_DETAIL_READ_PROXY_HPP_
|
||||
|
||||
#include <rti/routing/adapter/StreamReader.hpp>
|
||||
|
||||
namespace rti { namespace routing { namespace adapter { namespace detail {
|
||||
|
||||
|
||||
struct TakeProxy {
|
||||
|
||||
TakeProxy (StreamReader& stream_reader)
|
||||
: stream_reader_(stream_reader)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void operator() (
|
||||
std::vector<rti::routing::adapter::StreamReader::SamplePtr>& sample_seq,
|
||||
std::vector<rti::routing::adapter::StreamReader::InfoPtr>& info_seq)
|
||||
{
|
||||
stream_reader_.take(sample_seq, info_seq);
|
||||
}
|
||||
|
||||
private:
|
||||
StreamReader& stream_reader_;
|
||||
};
|
||||
|
||||
struct ReadProxy {
|
||||
|
||||
ReadProxy (StreamReader& stream_reader)
|
||||
: stream_reader_(stream_reader)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void operator() (
|
||||
std::vector<rti::routing::adapter::StreamReader::SamplePtr>& sample_seq,
|
||||
std::vector<rti::routing::adapter::StreamReader::InfoPtr>& info_seq)
|
||||
{
|
||||
stream_reader_.read(sample_seq, info_seq);
|
||||
}
|
||||
|
||||
private:
|
||||
StreamReader& stream_reader_;
|
||||
};
|
||||
|
||||
struct TakeSelectorProxy {
|
||||
|
||||
TakeSelectorProxy(
|
||||
StreamReader& stream_reader,
|
||||
const rti::routing::adapter::SelectorState& state)
|
||||
: stream_reader_(stream_reader), state_(state)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void operator() (
|
||||
std::vector<rti::routing::adapter::StreamReader::SamplePtr>& sample_seq,
|
||||
std::vector<rti::routing::adapter::StreamReader::InfoPtr>& info_seq)
|
||||
{
|
||||
stream_reader_.take(sample_seq, info_seq, state_);
|
||||
}
|
||||
|
||||
private:
|
||||
StreamReader& stream_reader_;
|
||||
const rti::routing::adapter::SelectorState& state_;
|
||||
};
|
||||
|
||||
struct ReadSelectorProxy {
|
||||
|
||||
ReadSelectorProxy (
|
||||
StreamReader& stream_reader,
|
||||
const rti::routing::adapter::SelectorState& state)
|
||||
: stream_reader_(stream_reader), state_(state)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void operator() (
|
||||
std::vector<rti::routing::adapter::StreamReader::SamplePtr>& sample_seq,
|
||||
std::vector<rti::routing::adapter::StreamReader::InfoPtr>& info_seq)
|
||||
{
|
||||
stream_reader_.read(sample_seq, info_seq, state_);
|
||||
}
|
||||
|
||||
private:
|
||||
StreamReader& stream_reader_;
|
||||
const rti::routing::adapter::SelectorState& state_;
|
||||
};
|
||||
|
||||
|
||||
} } } }
|
||||
|
||||
|
||||
#endif /* RTI_ROUTING_ADAPTER_DETAIL_READ_PROXY_HPP_ */
|
||||
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* (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_ADAPTER_DETAIL_SESSION_FORWARDER_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_DETAIL_SESSION_FORWARDER_HPP_
|
||||
|
||||
#include <rti/core/Exception.hpp>
|
||||
|
||||
#include <rti/apputils/ServiceException.hpp>
|
||||
|
||||
#include <rti/routing/adapter/Connection.hpp>
|
||||
#include <rti/routing/detail/UpdatableEntityForwarder.hpp>
|
||||
#include <rti/routing/detail/ForwarderUtils.hpp>
|
||||
|
||||
namespace rti { namespace routing { namespace adapter { namespace detail {
|
||||
|
||||
|
||||
class SessionForwarder {
|
||||
public:
|
||||
static RTI_RoutingServiceSessionExt* create_native(
|
||||
Connection *connection,
|
||||
const RTI_RoutingServiceProperties *native_properties,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
|
||||
try {
|
||||
using rti::routing::detail::ScopedForwarder;
|
||||
|
||||
// Set properties
|
||||
std::map<std::string, std::string> properties;
|
||||
rti::routing::PropertyAdapter::add_properties_from_native(
|
||||
properties,
|
||||
native_properties);
|
||||
|
||||
SessionForwarder *forwarder = new SessionForwarder();
|
||||
ScopedForwarder<Connection, SessionForwarder> scoped(
|
||||
connection,
|
||||
forwarder,
|
||||
environment);
|
||||
// Create session: Note we don't check for NULL because a Session
|
||||
// is not required
|
||||
forwarder->session_ = connection->create_session(properties);
|
||||
|
||||
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(
|
||||
Connection *connection,
|
||||
RTI_RoutingServiceSessionExt *native_session,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
SessionForwarder *forwarder = static_cast<SessionForwarder*>(
|
||||
native_session->session_data);
|
||||
try {
|
||||
// delete session
|
||||
if (forwarder->session_ != NULL) {
|
||||
connection->delete_session(forwarder->session_);
|
||||
forwarder->session_ = 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 (...) {
|
||||
}
|
||||
|
||||
delete forwarder;
|
||||
}
|
||||
|
||||
Session * session()
|
||||
{
|
||||
return session_;
|
||||
}
|
||||
|
||||
RTI_RoutingServiceSessionExt* native()
|
||||
{
|
||||
return &this->native_;
|
||||
}
|
||||
|
||||
static void update(
|
||||
void *native_session_data,
|
||||
const struct RTI_RoutingServiceProperties * native_properties,
|
||||
RTI_RoutingServiceEnvironment * environment)
|
||||
{
|
||||
SessionForwarder *forwarder =
|
||||
static_cast<SessionForwarder*> (native_session_data);
|
||||
|
||||
rti::routing::detail::UpdatableEntityForwarder::update(
|
||||
forwarder->session_,
|
||||
native_properties,
|
||||
environment);
|
||||
}
|
||||
|
||||
private:
|
||||
SessionForwarder() : session_(NULL)
|
||||
{
|
||||
RTIOsapiMemory_zero(&native_, sizeof(native_));
|
||||
native_.session_data =
|
||||
static_cast<void*>(this);
|
||||
native_.update =
|
||||
SessionForwarder::update;
|
||||
}
|
||||
|
||||
~SessionForwarder()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
RTI_RoutingServiceSessionExt native_;
|
||||
Session *session_;
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_DETAIL_SESSION_FORWARDER_HPP_
|
||||
+524
@@ -0,0 +1,524 @@
|
||||
/*
|
||||
* (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_ADAPTER_DETAIL_STREAM_READER_FORWARDER_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_DETAIL_STREAM_READER_FORWARDER_HPP_
|
||||
|
||||
#include <assert.h>
|
||||
#include <list>
|
||||
#include <rti/core/Exception.hpp>
|
||||
|
||||
#include <rti/apputils/ServiceException.hpp>
|
||||
|
||||
#include <rti/routing/adapter/StreamReader.hpp>
|
||||
#include <rti/routing/StreamInfo.hpp>
|
||||
#include <rti/routing/detail/UpdatableEntityForwarder.hpp>
|
||||
#include <rti/routing/detail/ForwarderUtils.hpp>
|
||||
#include <rti/routing/adapter/detail/DiscoveryStreamReaderForwarder.hpp>
|
||||
|
||||
|
||||
namespace rti { namespace routing { namespace adapter { namespace detail {
|
||||
|
||||
template <bool ReadOrTake, bool HasSelector> struct read_or_take;
|
||||
|
||||
|
||||
template<>
|
||||
struct read_or_take<false, false> {
|
||||
|
||||
static void read(
|
||||
rti::routing::adapter::StreamReader& stream_reader,
|
||||
std::vector<StreamReader::SamplePtr>& sample_seq,
|
||||
std::vector<StreamReader::InfoPtr>& info_seq,
|
||||
const struct RTI_RoutingServiceSelectorState *)
|
||||
{
|
||||
stream_reader.take(sample_seq, info_seq);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct read_or_take<true, false> {
|
||||
|
||||
static void read(
|
||||
rti::routing::adapter::StreamReader& stream_reader,
|
||||
std::vector<StreamReader::SamplePtr>& sample_seq,
|
||||
std::vector<StreamReader::InfoPtr>& info_seq,
|
||||
const struct RTI_RoutingServiceSelectorState *)
|
||||
{
|
||||
stream_reader.read(sample_seq, info_seq);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct read_or_take<false, true> {
|
||||
|
||||
static void read(
|
||||
rti::routing::adapter::StreamReader& stream_reader,
|
||||
std::vector<StreamReader::SamplePtr>& sample_seq,
|
||||
std::vector<StreamReader::InfoPtr>& info_seq,
|
||||
const struct RTI_RoutingServiceSelectorState *native_selector)
|
||||
{
|
||||
stream_reader.take(
|
||||
sample_seq,
|
||||
info_seq,
|
||||
SelectorState(*native_selector));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct read_or_take<true, true> {
|
||||
|
||||
static void read(
|
||||
rti::routing::adapter::StreamReader& stream_reader,
|
||||
std::vector<StreamReader::SamplePtr>& sample_seq,
|
||||
std::vector<StreamReader::InfoPtr>& info_seq,
|
||||
const struct RTI_RoutingServiceSelectorState *native_selector)
|
||||
{
|
||||
stream_reader.read(
|
||||
sample_seq,
|
||||
info_seq,
|
||||
SelectorState(*native_selector));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct SamplesHolder {
|
||||
public:
|
||||
|
||||
SamplesHolder()
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<StreamReader::SamplePtr> sample_seq_;
|
||||
std::vector<StreamReader::InfoPtr> info_seq_;
|
||||
};
|
||||
|
||||
class StreamReaderForwarder {
|
||||
public:
|
||||
static RTI_RoutingServiceStreamReaderExt* create_native(
|
||||
Connection *connection,
|
||||
Session *session,
|
||||
const struct RTI_RoutingServiceStreamInfo *native_stream_info,
|
||||
const struct RTI_RoutingServiceProperties *native_properties,
|
||||
const struct RTI_RoutingServiceStreamReaderListenerExt *native_listener,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
|
||||
try {
|
||||
using rti::routing::detail::ScopedForwarder;
|
||||
|
||||
StreamInfo stream_info(*native_stream_info);
|
||||
|
||||
std::map<std::string, std::string> properties;
|
||||
rti::routing::PropertyAdapter::add_properties_from_native(
|
||||
properties,
|
||||
native_properties);
|
||||
|
||||
StreamReaderForwarder *forwarder = new StreamReaderForwarder(
|
||||
native_listener);
|
||||
ScopedForwarder<Connection, StreamReaderForwarder> scoped(
|
||||
connection,
|
||||
forwarder,
|
||||
environment);
|
||||
forwarder->stream_reader_ = connection->create_stream_reader(
|
||||
session,
|
||||
stream_info,
|
||||
properties,
|
||||
&forwarder->listener_);
|
||||
RTI_ROUTING_THROW_ON_NULL(forwarder->stream_reader_);
|
||||
|
||||
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(
|
||||
Connection *connection,
|
||||
RTI_RoutingServiceStreamReaderExt *native_stream_reader,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
StreamReaderForwarder *stream_reader_forwarder =
|
||||
from_native(native_stream_reader);
|
||||
try {
|
||||
if (stream_reader_forwarder->stream_reader_ != NULL) {
|
||||
connection->delete_stream_reader(
|
||||
stream_reader_forwarder->stream_reader_);
|
||||
stream_reader_forwarder->stream_reader_ = 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 stream_reader_forwarder;
|
||||
}
|
||||
|
||||
|
||||
RTI_RoutingServiceStreamReaderExt* native()
|
||||
{
|
||||
return &this->native_;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
StreamReaderForwarder(
|
||||
const RTI_RoutingServiceStreamReaderListenerExt *native_listener) :
|
||||
stream_reader_(NULL),
|
||||
listener_(native_listener)
|
||||
{
|
||||
RTIOsapiMemory_zero(&native_, sizeof(native_));
|
||||
native_.stream_reader_data =
|
||||
static_cast<void *>(this);
|
||||
native_.take =
|
||||
StreamReaderForwarder::take;
|
||||
native_.read =
|
||||
StreamReaderForwarder::read;
|
||||
native_.take_w_selector =
|
||||
StreamReaderForwarder::take_with_selector;
|
||||
native_.read_w_selector =
|
||||
StreamReaderForwarder::read_with_selector;
|
||||
native_.return_loan =
|
||||
StreamReaderForwarder::return_loan;
|
||||
native_.create_content_query =
|
||||
StreamReaderForwarder::create_content_query;
|
||||
native_.delete_content_query =
|
||||
StreamReaderForwarder::delete_content_query;
|
||||
native_.update =
|
||||
StreamReaderForwarder::update;
|
||||
}
|
||||
|
||||
~StreamReaderForwarder()
|
||||
{
|
||||
// delete holders
|
||||
for (std::list<SamplesHolder*>::iterator it = holder_pool_.begin();
|
||||
it != holder_pool_.end();
|
||||
++it) {
|
||||
delete (*it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void take(
|
||||
void *native_stream_reader_data,
|
||||
RTI_RoutingServiceSample **sample_array,
|
||||
RTI_RoutingServiceSampleInfo **sample_info_array,
|
||||
int *array_length,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
proxy_read<false, false>(
|
||||
native_stream_reader_data,
|
||||
sample_array,
|
||||
sample_info_array,
|
||||
array_length,
|
||||
NULL,
|
||||
environment);
|
||||
}
|
||||
|
||||
static void read(
|
||||
void *native_stream_reader_data,
|
||||
RTI_RoutingServiceSample **sample_array,
|
||||
RTI_RoutingServiceSampleInfo **sample_info_array,
|
||||
int *array_length,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
proxy_read<true, false>(
|
||||
native_stream_reader_data,
|
||||
sample_array,
|
||||
sample_info_array,
|
||||
array_length,
|
||||
NULL,
|
||||
environment);
|
||||
}
|
||||
|
||||
static void take_with_selector(
|
||||
void *native_stream_reader_data,
|
||||
RTI_RoutingServiceSample **sample_array,
|
||||
RTI_RoutingServiceSampleInfo **sample_info_array,
|
||||
int *array_length,
|
||||
const struct RTI_RoutingServiceSelectorState *native_selector,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
proxy_read<false, true>(
|
||||
native_stream_reader_data,
|
||||
sample_array,
|
||||
sample_info_array,
|
||||
array_length,
|
||||
native_selector,
|
||||
environment);
|
||||
}
|
||||
|
||||
static void read_with_selector(
|
||||
void *native_stream_reader_data,
|
||||
RTI_RoutingServiceSample **sample_array,
|
||||
RTI_RoutingServiceSampleInfo **sample_info_array,
|
||||
int *array_length,
|
||||
const struct RTI_RoutingServiceSelectorState *native_selector,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
proxy_read<true, true>(
|
||||
native_stream_reader_data,
|
||||
sample_array,
|
||||
sample_info_array,
|
||||
array_length,
|
||||
native_selector,
|
||||
environment);
|
||||
}
|
||||
|
||||
static void return_loan(
|
||||
void *native_stream_reader_data,
|
||||
RTI_RoutingServiceSample *native_samples,
|
||||
RTI_RoutingServiceSampleInfo *,
|
||||
int count,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
StreamReaderForwarder *forwarder =
|
||||
static_cast<StreamReaderForwarder*>(native_stream_reader_data);
|
||||
assert(forwarder != NULL);
|
||||
|
||||
SamplesHolder *holder = static_cast<SamplesHolder*>(
|
||||
native_samples[count]);
|
||||
assert(holder != NULL);
|
||||
|
||||
|
||||
try {
|
||||
forwarder->stream_reader_->return_loan(
|
||||
holder->sample_seq_,
|
||||
holder->info_seq_);
|
||||
} 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");
|
||||
}
|
||||
|
||||
forwarder->return_holder(holder);
|
||||
}
|
||||
|
||||
static void update(
|
||||
void *native_stream_reader_data,
|
||||
const struct RTI_RoutingServiceProperties * native_properties,
|
||||
RTI_RoutingServiceEnvironment * environment)
|
||||
{
|
||||
|
||||
StreamReaderForwarder *stream_reader_forwarder =
|
||||
static_cast<StreamReaderForwarder*>(native_stream_reader_data);
|
||||
|
||||
rti::routing::detail::UpdatableEntityForwarder::update(
|
||||
stream_reader_forwarder->stream_reader_,
|
||||
native_properties,
|
||||
environment);
|
||||
}
|
||||
|
||||
static void* create_content_query(
|
||||
void *native_stream_reader_data,
|
||||
RTI_RoutingServiceSelectorStateQueryData old_query_data,
|
||||
const struct RTI_RoutingServiceSelectorContent *content,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
StreamReaderForwarder *forwarder =
|
||||
static_cast<StreamReaderForwarder*>(native_stream_reader_data);
|
||||
|
||||
void *query_data = NULL;
|
||||
try {
|
||||
dds::topic::Filter filter(
|
||||
content->expression == NULL ? "" : content->expression,
|
||||
rti::core::native_conversions::from_native<std::string>(
|
||||
content->expression_parameters));
|
||||
query_data = forwarder->stream_reader_->create_content_query(
|
||||
old_query_data,
|
||||
filter);
|
||||
} 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");
|
||||
}
|
||||
|
||||
return query_data;
|
||||
}
|
||||
|
||||
static void delete_content_query(
|
||||
void *native_stream_reader_data,
|
||||
RTI_RoutingServiceSelectorStateQueryData query_data,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
StreamReaderForwarder *forwarder =
|
||||
static_cast<StreamReaderForwarder*>(native_stream_reader_data);
|
||||
try {
|
||||
forwarder->stream_reader_->delete_content_query(query_data);
|
||||
} catch (const std::exception& ex) {
|
||||
RTI_RoutingServiceEnvironment_set_error(
|
||||
environment,
|
||||
"%s",
|
||||
ex.what());
|
||||
} catch (...) {
|
||||
RTI_RoutingServiceEnvironment_set_error(
|
||||
environment,
|
||||
"unexpected exception");
|
||||
}
|
||||
}
|
||||
|
||||
static StreamReaderForwarder* from_native(
|
||||
RTI_RoutingServiceStreamReaderExt *native)
|
||||
{
|
||||
return static_cast<StreamReaderForwarder*>(native->stream_reader_data);
|
||||
}
|
||||
|
||||
template <bool ReadOrTake, bool HasSelector>
|
||||
static void proxy_read(
|
||||
void *native_stream_reader_data,
|
||||
RTI_RoutingServiceSample **sample_array,
|
||||
RTI_RoutingServiceSampleInfo **sample_info_array,
|
||||
int *array_length,
|
||||
const struct RTI_RoutingServiceSelectorState *native_selector,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
StreamReaderForwarder *forwarder =
|
||||
static_cast<StreamReaderForwarder*>(native_stream_reader_data);
|
||||
assert(forwarder != NULL);
|
||||
|
||||
SamplesHolder *holder = forwarder->get_holder();
|
||||
|
||||
*array_length = 0;
|
||||
try {
|
||||
read_or_take<ReadOrTake, HasSelector>::read(
|
||||
*forwarder->stream_reader_,
|
||||
holder->sample_seq_,
|
||||
holder->info_seq_,
|
||||
native_selector);
|
||||
if (!holder->info_seq_.empty()
|
||||
&& (holder->info_seq_.size() != holder->sample_seq_.size())) {
|
||||
throw dds::core::PreconditionNotMetError(
|
||||
"sample and info sequences length mismatch");
|
||||
}
|
||||
/*
|
||||
* We reserve a hidden slot in the sample_seq to keep the original
|
||||
* loaned returned from the native StreamReader. This allows us
|
||||
* to quickly access it on return_loan(), instead of having to search
|
||||
* in a list.
|
||||
*
|
||||
* TRUST-1466: reserving just 1 more memory spot can be inefficient,
|
||||
* and we're doing this for every read/take operation called in C++.
|
||||
*/
|
||||
if (holder->sample_seq_.size() + 1
|
||||
>= holder->sample_seq_.capacity()) {
|
||||
holder->sample_seq_.reserve(
|
||||
holder->sample_seq_.capacity() == 0
|
||||
? 1
|
||||
: 2 * holder->sample_seq_.capacity());
|
||||
}
|
||||
*(holder->sample_seq_.data() + holder->sample_seq_.size()) = holder;
|
||||
} catch (const rti::apputils::FatalServiceException& ex) {
|
||||
RTI_RoutingServiceEnvironment_fatal_error(
|
||||
environment,
|
||||
ex.what());
|
||||
forwarder->return_holder(holder);
|
||||
return;
|
||||
} catch (const std::exception& ex) {
|
||||
RTI_RoutingServiceEnvironment_set_error(
|
||||
environment,
|
||||
ex.what());
|
||||
forwarder->return_holder(holder);
|
||||
return;
|
||||
} catch (...) {
|
||||
RTI_RoutingServiceEnvironment_set_error(
|
||||
environment,
|
||||
"unexpected exception");
|
||||
forwarder->return_holder(holder);
|
||||
return;
|
||||
}
|
||||
|
||||
// direct mapping
|
||||
*array_length = static_cast<int>(holder->sample_seq_.size());
|
||||
*sample_array = holder->sample_seq_.data();
|
||||
if (holder->info_seq_.empty()) {
|
||||
*sample_info_array = NULL;
|
||||
} else {
|
||||
*sample_info_array = &holder->info_seq_[0];
|
||||
}
|
||||
}
|
||||
|
||||
SamplesHolder* get_holder()
|
||||
{
|
||||
if (holder_pool_.size() == 0) {
|
||||
return new SamplesHolder();
|
||||
}
|
||||
|
||||
SamplesHolder *holder = holder_pool_.front();
|
||||
holder_pool_.pop_front();
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
void return_holder(SamplesHolder *holder)
|
||||
{
|
||||
holder->sample_seq_.clear();
|
||||
holder->info_seq_.clear();
|
||||
holder_pool_.push_front(holder);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
RTI_RoutingServiceStreamReaderExt native_;
|
||||
StreamReader *stream_reader_;
|
||||
StreamReaderListener listener_;
|
||||
std::list<SamplesHolder*> holder_pool_;
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_DETAIL_STREAM_READER_FORWARDER_HPP_
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* (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_ADAPTER_DETAIL_STREAM_READER_LISTENER_FORWARDER_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_DETAIL_STREAM_READER_LISTENER_FORWARDER_HPP_
|
||||
|
||||
#include <rti/core/Exception.hpp>
|
||||
|
||||
#include <routingservice/routingservice_adapter_new.h>
|
||||
|
||||
#include <rti/routing/adapter/StreamReader.hpp>
|
||||
#include <rti/routing/adapter/DiscoveryStreamReader.hpp>
|
||||
|
||||
namespace rti { namespace routing { namespace adapter { namespace detail {
|
||||
|
||||
/** @ingroup RTI_RoutingServiceAdapterModule
|
||||
*
|
||||
* @class rti::routing::adapter::StreamReaderListener
|
||||
*
|
||||
* @brief Listener representation used by StreamReader to notify @product
|
||||
* when new data is available.
|
||||
*
|
||||
* When a StreamReader receives new data, it shall call
|
||||
* StreamReaderListener::on_data_available to wake up the associated Session.
|
||||
* After that, the Session will invoke any of the StreamReader operations to
|
||||
* read the new data.
|
||||
*
|
||||
*/
|
||||
class StreamReaderListener {
|
||||
public:
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Operation to notify @product about data available on the
|
||||
* a StreamReader.
|
||||
*
|
||||
* @param stream_reader
|
||||
* @rs_st_in Stream reader for which new data is available.
|
||||
*
|
||||
*/
|
||||
void on_data_available(
|
||||
rti::routing::adapter::StreamReader *stream_reader)
|
||||
{
|
||||
native_listener_.on_data_available(
|
||||
static_cast<void*>(stream_reader),
|
||||
native_listener_.listener_data);
|
||||
}
|
||||
|
||||
|
||||
StreamReaderListener(
|
||||
const RTI_RoutingServiceStreamReaderListenerExt *native_listener) :
|
||||
native_listener_(*native_listener)
|
||||
{
|
||||
}
|
||||
|
||||
~StreamReaderListener()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
RTI_RoutingServiceStreamReaderListenerExt native_listener_;
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_DETAIL_STREAM_READER_LISTENER_FORWARDER_HPP_
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* (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_ADAPTER_DETAIL_STREAM_WRITER_FORWARDER_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_DETAIL_STREAM_WRITER_FORWARDER_HPP_
|
||||
|
||||
#include <rti/core/Exception.hpp>
|
||||
|
||||
#include <rti/apputils/ServiceException.hpp>
|
||||
|
||||
#include <rti/routing/adapter/StreamWriter.hpp>
|
||||
#include <rti/routing/detail/UpdatableEntityForwarder.hpp>
|
||||
#include <rti/routing/detail/ForwarderUtils.hpp>
|
||||
|
||||
namespace rti { namespace routing { namespace adapter { namespace detail {
|
||||
|
||||
|
||||
class StreamWriterForwarder {
|
||||
public:
|
||||
|
||||
static RTI_RoutingServiceStreamWriterExt* create_native(
|
||||
Connection *connection,
|
||||
Session *session,
|
||||
const struct RTI_RoutingServiceStreamInfo *native_stream_info,
|
||||
const struct RTI_RoutingServiceProperties *native_properties,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
try {
|
||||
using rti::routing::detail::ScopedForwarder;
|
||||
|
||||
StreamInfo stream_info(*native_stream_info);
|
||||
|
||||
std::map<std::string, std::string> properties;
|
||||
rti::routing::PropertyAdapter::add_properties_from_native(
|
||||
properties,
|
||||
native_properties);
|
||||
|
||||
StreamWriterForwarder *forwarder = new StreamWriterForwarder(
|
||||
NULL);
|
||||
ScopedForwarder<Connection, StreamWriterForwarder> scoped(
|
||||
connection,
|
||||
forwarder,
|
||||
environment);
|
||||
forwarder->stream_writer_ = connection->create_stream_writer(
|
||||
session,
|
||||
stream_info,
|
||||
properties);
|
||||
RTI_ROUTING_THROW_ON_NULL(forwarder->stream_writer_);
|
||||
|
||||
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(
|
||||
Connection *connection,
|
||||
RTI_RoutingServiceStreamWriterExt *native_stream_writer,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
StreamWriterForwarder *stream_writer_forwarder =
|
||||
static_cast<StreamWriterForwarder*>(
|
||||
native_stream_writer->stream_writer_data);
|
||||
try {
|
||||
if (stream_writer_forwarder->stream_writer_ != NULL) {
|
||||
connection->delete_stream_writer(
|
||||
stream_writer_forwarder->stream_writer_);
|
||||
stream_writer_forwarder->stream_writer_ = 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 (...) {
|
||||
}
|
||||
|
||||
delete stream_writer_forwarder;
|
||||
}
|
||||
|
||||
|
||||
static int write(
|
||||
void *native_stream_writer_data,
|
||||
const RTI_RoutingServiceSample *sample_array,
|
||||
const RTI_RoutingServiceSampleInfo *sample_info_array,
|
||||
int array_length,
|
||||
RTI_RoutingServiceEnvironment *environment)
|
||||
{
|
||||
|
||||
StreamWriterForwarder *forwarder =
|
||||
static_cast<StreamWriterForwarder*>(native_stream_writer_data);
|
||||
|
||||
try {
|
||||
RTI_ROUTING_SAMPLE_VECTOR_COPY_FROM_NATIVE(
|
||||
forwarder->sample_seq_,
|
||||
sample_array,
|
||||
array_length);
|
||||
if (sample_info_array != NULL) {
|
||||
RTI_ROUTING_SAMPLE_VECTOR_COPY_FROM_NATIVE(
|
||||
forwarder->info_seq_,
|
||||
sample_info_array,
|
||||
array_length);
|
||||
} else {
|
||||
forwarder->info_seq_.clear();
|
||||
}
|
||||
return forwarder->stream_writer_->write(
|
||||
forwarder->sample_seq_,
|
||||
forwarder->info_seq_);
|
||||
} 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");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update(
|
||||
void *native_stream_writer_data,
|
||||
const struct RTI_RoutingServiceProperties * native_properties,
|
||||
RTI_RoutingServiceEnvironment * environment)
|
||||
{
|
||||
|
||||
StreamWriterForwarder *stream_writer_forwarder =
|
||||
static_cast<StreamWriterForwarder*> (native_stream_writer_data);
|
||||
|
||||
rti::routing::detail::UpdatableEntityForwarder::update(
|
||||
stream_writer_forwarder->stream_writer_,
|
||||
native_properties,
|
||||
environment);
|
||||
}
|
||||
|
||||
RTI_RoutingServiceStreamWriterExt* native()
|
||||
{
|
||||
return &this->native_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
StreamWriterForwarder(
|
||||
StreamWriter *stream_writer) :
|
||||
stream_writer_(stream_writer)
|
||||
{
|
||||
RTIOsapiMemory_zero(&native_, sizeof(native_));
|
||||
native_.stream_writer_data =
|
||||
static_cast<void*>(this);
|
||||
native_.write =
|
||||
StreamWriterForwarder::write;
|
||||
native_.update =
|
||||
StreamWriterForwarder::update;
|
||||
|
||||
}
|
||||
|
||||
~StreamWriterForwarder()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
RTI_RoutingServiceStreamWriterExt native_;
|
||||
StreamWriter *stream_writer_;
|
||||
std::vector<StreamWriter::SamplePtr> sample_seq_;
|
||||
std::vector<StreamWriter::InfoPtr> info_seq_;
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_DETAIL_STREAM_WRITER_FORWARDER_HPP_
|
||||
Reference in new issue
Block a user