Adds immediate migration results

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

No files matched your search

@@ -0,0 +1,426 @@
/*
* (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_ENTITY_LISTENER_HPP_
#define RTI_ROUTING_ENTITY_LISTENER_HPP_
#include "routingservice/routingservice_service_impl.h"
#include <rti/apputils/ServiceException.hpp>
#include <rti/apputils/log/LogConfig.hpp>
#include <rti/routing/StreamInfo.hpp>
namespace rti { namespace routing {
/**
*/
struct EntityKind_def {
/**
* @brief The underlying \p enum type
*/
enum type {
SERVICE = RTI_ROUTING_SERVICE_SERVICE_ENTITY,
DOMAIN_ROUTE = RTI_ROUTING_SERVICE_DOMAIN_ROUTE_ENTITY,
CONNECTION = RTI_ROUTING_SERVICE_CONNECTION_ENTITY,
SESSION = RTI_ROUTING_SERVICE_SESSION_ENTITY,
AUTO_TOPIC_ROUTE = RTI_ROUTING_SERVICE_AUTO_TOPIC_ROUTE_ENTITY,
TOPIC_ROUTE = RTI_ROUTING_SERVICE_TOPIC_ROUTE_ENTITY,
INPUT = RTI_ROUTING_SERVICE_INPUT_ENTITY,
OUTPUT = RTI_ROUTING_SERVICE_OUTPUT_ENTITY,
count_
};
};
/**
*/
typedef dds::core::safe_enum<EntityKind_def> EntityKind;
/**
*/
struct EntityStateKind_def {
/**
* @brief The underlying \p enum type
*/
enum type {
INVALID = RTI_SERVICE_INVALID_ENTITY_STATE,
ENABLED = RTI_SERVICE_ENABLED_ENTITY_STATE,
DISABLED = RTI_SERVICE_DISABLED_ENTITY_STATE,
STARTED = RTI_SERVICE_STARTED_ENTITY_STATE,
STOPPED = RTI_SERVICE_STOPPED_ENTITY_STATE,
RUNNING = RTI_SERVICE_RUNNING_ENTITY_STATE,
PAUSED = RTI_SERVICE_PAUSED_ENTITY_STATE
};
};
typedef dds::core::safe_enum<EntityStateKind_def> EntityStateKind;
/*
* @brief string representation of EntityStateKind
*/
inline
const std::string to_string(const rti::routing::EntityStateKind& kind)
{
static const char * ENTITY_STATE_KIND_AS_STRING[] = {
"INVALID",
"ENABLED",
"DISABLED",
"STARTED",
"STOPPED",
"RUNNING",
"PAUSED"
};
return ENTITY_STATE_KIND_AS_STRING[kind.underlying()];
}
inline
const char* to_action_native_string(const rti::routing::EntityStateKind& kind)
{
static const char * ENTITY_STATE_ACTION_AS_STRING[] = {
"INVALID",
"ENABLE",
"DISABLE",
"START",
"STOP",
"RUN",
"PAUSE"
""
};
return ENTITY_STATE_ACTION_AS_STRING[kind.underlying()];
}
inline
const std::string to_action_string(const rti::routing::EntityStateKind& kind)
{
return to_action_native_string(kind);
}
class EntityListener {
public:
class Context {
public:
friend EntityListener::Context from_native(
RTI_RoutingServiceEntityListenerContext*);
const rti::routing::EntityKind& entity_kind() const
{
return entity_kind_;
}
const std::string& entity_name() const
{
return entity_name_;
}
const rti::routing::EntityStateKind& entity_state_kind() const
{
return entity_state_kind_;
}
bool ok()
{
return ok_;
}
rti::advlog::Entries logging_context_entries()
{
return logging_context_entries_;
}
private:
rti::routing::EntityKind entity_kind_;
std::string entity_name_;
rti::routing::EntityStateKind entity_state_kind_;
bool ok_;
/*
* We need to keep the entries of the context because they are entered
* in a function and left in another function.
* The number of entries is two:
* - An entry for the resource.
* - An entry for the activity.
*
* Recorder:
* - The entries are entered into the context using the macro
* RTI_ENTITY_LISTENER_CONTEXT_ENTER_ON_BEFORE in a function.
* - The entries are left using the macro
* RTI_ENTITY_LISTENER_CONTEXT_LEAVE_ON_AFTER in another function.
*
* For example:
* - Enter in EntityListener::on_before_create
* - Leave in EntityListener::on_after_create
*/
rti::advlog::Entries logging_context_entries_;
};
virtual void on_before_create( EntityListener::Context&)
{
}
virtual void on_after_create(EntityListener::Context&)
{
}
virtual void on_before_state_change(EntityListener::Context&)
{
}
virtual void on_after_state_change(EntityListener::Context&)
{
}
virtual void on_before_delete(EntityListener::Context&)
{
}
virtual void on_after_delete(EntityListener::Context&)
{
}
virtual void on_before_stream_event(
EntityListener::Context&,
const rti::routing::StreamInfo&)
{
}
virtual void on_after_stream_event(
EntityListener::Context&,
const rti::routing::StreamInfo&)
{
}
virtual ~EntityListener() {}
};
inline
EntityListener::Context from_native(
RTI_RoutingServiceEntityListenerContext *native)
{
EntityListener::Context context;
context.entity_kind_ = static_cast<EntityKind::type> (
native->entity_kind);
context.entity_name_ = native->entity_name;
context.entity_state_kind_ = static_cast<EntityStateKind::type> (
native->entity_state_kind);
context.ok_ = native->ok ? true : false;
context.logging_context_entries_.from_native(
native->logging_context_entries,
native->logging_context_params);
return context;
}
class EntityListenerForwarder {
public:
typedef RTI_RoutingServiceEntityListener native;
static native create(
EntityListener *listener)
{
native native_listener = RTI_RoutingServiceEntityListener_INITIALIZER;
native_listener.on_before_create =
on_before_create_forwarder;
native_listener.on_after_create =
on_after_create_forwarder;
native_listener.on_before_state_change =
on_before_state_change_forwarder;
native_listener.on_after_state_change =
on_after_state_change_forwarder;
native_listener.on_before_delete =
on_before_delete_forwarder;
native_listener.on_after_delete =
on_after_delete_forwarder;
native_listener.on_before_stream_event =
on_before_stream_event_forwarder;
native_listener.on_after_stream_event =
on_after_stream_event_forwarder;
native_listener.listener_data = static_cast<void*>(listener);
return native_listener;
}
private:
static void on_before_create_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_before_create(context);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_after_create_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_after_create(context);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_before_state_change_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_before_state_change(context);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_after_state_change_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_after_state_change(context);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_before_delete_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_before_delete(context);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_after_delete_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_after_delete(context);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_before_stream_event_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native,
const RTI_RoutingServiceStreamInfo *stream_info)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_before_stream_event(
context,
*stream_info);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_after_stream_event_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native,
const RTI_RoutingServiceStreamInfo *stream_info)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_after_stream_event(
context,
*stream_info);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
};
}}
#endif // RTI_ROUTING_ENTITY_LISTENER_HPP_
@@ -0,0 +1,219 @@
/*
* (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_LOGGER_HPP_
#define RTI_ROUTING_LOGGER_HPP_
#include <dds/core/Reference.hpp>
#include <rti/config/Logger.hpp>
#include "routingservice/routingservice_log.h"
#include "routingservice/routingservice_service.h"
namespace rti { namespace routing {
/** \ingroup RTI_RoutingServiceLibModule
*
* @brief The singleton type used to configure @product verbosity
*
* For configuring other aspects such as output file, print format or
* RTI Connext specific logging, use rti::config::Logger.
*/
class Logger
{
public:
typedef rti::config::Verbosity Verbosity;
typedef rti::config::LogCategory LogCategory;
typedef rti::config::PrintFormat PrintFormat;
static Logger& instance()
{
static Logger singleton;
return singleton;
}
/**
* @brief Sets the verbosity for the log messages generated at the
* @product level.
*
* @param verbosity
* @rs_st_in The verbosity of the service logs
*/
void service_verbosity(rti::config::Verbosity verbosity)
{
NDDS_Config_Logger_set_verbosity_by_service(
NDDS_Config_Logger_get_instance(),
NDDS_CONFIG_LOG_SERVICE_ROUTING,
static_cast<NDDS_Config_LogVerbosity>(verbosity.underlying()));
}
/**
* @brief Getter for the same attribute
*
* @see service_verbosity(rti::config::Verbosity)
*/
rti::config::Verbosity service_verbosity()
{
RTILogBitmap instrumentation_mask =
NDDS_Config_Logger_get_verbosity_by_service(
NDDS_Config_Logger_get_instance(),
NDDS_CONFIG_LOG_SERVICE_ROUTING);
return static_cast<rti::config::Verbosity::type>(instrumentation_mask);
}
/**
* @brief Logs as message with EXCEPTION level
*
* The generated log will be part of logging stream of the running service
* if the service verbosity contains EXCEPTION messages. The result log
* message may include additional information according to the
* Connext logging configuration, such as Advlog Context, thread ID,
* line number, etc. Additionally, the result log message will contain a
* newline character at the end, so the format does not need to contain it.
*
* @param[in] msg Message to be logged
*/
void error(const std::string& msg)
{
this->error(msg.c_str());
}
/**
* @brief overload of error(const std::string& msg)
*/
void error(const char *msg)
{
this->message(rti::config::LogLevel::EXCEPTION, msg);
}
/**
* @brief Logs as message with WARNING level
*
* This operation behaves similar to error() except the log level is
* WARNING.
*
* @param[in] msg Message to be logged
*
* @see rti::routing::Logger::error
*
*/
void warn(const std::string& msg)
{
this->warn(msg.c_str());
}
/**
* @brief overload of warn(const std::string& msg)
*/
void warn(const char *msg)
{
this->message(rti::config::LogLevel::WARNING, msg);
}
/**
* @brief Logs as message with WARNING level
*
* This operation behaves similar to error() except the log level is
* STATUS_LOCAL.
*
* @param[in] msg Message to be logged
*
* @see rti::routing::Logger::error
*
*/
void local(const std::string& msg)
{
this->local(msg.c_str());
}
/**
* @brief overload of local(const std::string& msg)
*/
void local(const char *msg)
{
this->message(rti::config::LogLevel::STATUS_LOCAL, msg);
}
/**
* @brief Logs as message with WARNING level
*
* This operation behaves similar to error() except the log level is
* STATUS_REMOTE.
*
* @param[in] msg Message to be logged
*
* @see rti::routing::Logger::error
*
*/
void remote(const std::string& msg)
{
this->remote(msg.c_str());
}
/**
* @brief overload of remote(const std::string& msg)
*/
void remote(const char *msg)
{
this->message(rti::config::LogLevel::STATUS_REMOTE, msg);
}
/**
* @brief Logs as message with WARNING level
*
* This operation behaves similar to error() except the log level is
* STATUS_DEBUG.
*
* @param[in] msg Message to be logged
*
* @see rti::routing::Logger::error
*
*/
void debug(const std::string& msg)
{
this->debug(msg.c_str());
}
/**
* @brief overload of debug(const std::string& msg)
*/
void debug(const char *msg)
{
this->message(rti::config::LogLevel::STATUS_ALL, msg);
}
virtual ~Logger()
{
}
private:
void message(const rti::config::LogLevel& level, const char* msg)
{
RTI_RoutingServiceLogger_log(
static_cast<NDDS_Config_LogLevel> (level.underlying()),
"%s",
msg);
}
Logger()
{
}
// Disable copy
Logger(const Logger&);
Logger& operator=(const Logger&);
};
}}
#endif // RTI_ROUTING_LOGGER_HPP_
@@ -0,0 +1,64 @@
/*
* (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_PROPERTY_SET_HPP_
#define RTI_ROUTING_PROPERTY_SET_HPP_
#include <map>
#include "routingservice/routingservice_infrastructure.h"
#include <rti/config/Version.hpp>
namespace rti { namespace routing {
inline
std::string app_name_property_name()
{
return RTI_ROUTING_SERVICE_APP_NAME_PROPERTY_NAME;
}
inline
std::string group_name_property_name()
{
return RTI_ROUTING_SERVICE_GROUP_PROPERTY_NAME;
}
inline
std::string version_property_name()
{
return RTI_ROUTING_SERVICE_VERSION_PROPERTY_NAME;
}
inline
std::string verbosity_property_name()
{
return RTI_ROUTING_SERVICE_VERBOSITY_PROPERTY_NAME;
}
inline
std::string entity_resource_name_property_name()
{
return RTI_ROUTING_SERVICE_ENTITY_RESOURCE_NAME_PROPERTY_NAME;
}
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
* @brief The definition of a pluggable entity’s configuration properties.
*
* Configuration properties for an entity are obtained as a result of parsing
* the &lt;property&gt; corresponding to each pluggable entity. The result is a
* map keyed by property name, represented as std::string, whose values are
* the property values, also represented as std::string. Hence, a property name
* shall be unique for each set of entity properties.
*/
typedef std::map<std::string,std::string> PropertySet;
}}
#endif // RTI_ROUTING_PROPERTY_SET_HPP_
@@ -0,0 +1,17 @@
/*
* (c) Copyright, Real-Time Innovations, 2021.
* 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_ROUTING_SERVICE_HPP_
#define RTI_ROUTING_ROUTING_SERVICE_HPP_
#include <rti/routing/Service.hpp>
#endif // RTI_ROUTING_ROUTING_SERVICE_HPP_
@@ -0,0 +1,404 @@
/*
* (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_SERVICE_HPP_
#define RTI_ROUTING_SERVICE_HPP_
#include <dds/core/Reference.hpp>
#include <rti/config/Logger.hpp>
#include "routingservice/routingservice_adapter_new.h"
#include <rti/routing/Logger.hpp>
#include <rti/routing/ServiceProperty.hpp>
#include <rti/routing/detail/RoutingServiceImpl.hpp>
#include <rti/routing/adapter/AdapterPlugin.hpp>
#include <rti/routing/processor/ProcessorPlugin.hpp>
namespace rti { namespace routing {
/*e \defgroup RTI_RoutingServiceLibModule RTI Routing Library API
* \ingroup ROUTER
*
* @brief @product can be deployed as a native library linked into your
* application in select architectures.
*
* This API allows you to create, configure and start @product instances from
* your application.
*
* The following code shows the typical use of the API:
*
* \code
*
* int main ()
* {
* rti::routing::Service service(
* rti::routing::ServiceProperty()
* .cfg_file("MyRouter.xml")
* .cfg_name("MyRouter"));
* ...
*
* service.start();
*
* while(keep_running) {
* sleep();
* ...
* }
*
* return 0;
* }
*
* \endcode
*
* Instead of a file, you can use XML strings to configure @product.
* See ServiceProperty for more information.
* <p>
* To build your application you need to link with the @product native library
* in <b> &lt;@ndds home&gt;/bin/&lt;architecture&gt;/ </b>.
*
* ### Development Requirements
*
* | | Linux/macOS Systems | Windows Systems |
* | --------------: | :----------------: | :-------------: |
* | Shared Libraries| libnddscpp2.so | nddscpp2.dll |
* | ^ | librtirsinfrastructure.so | rtirsinfrastructure.dll |
* | ^ | librtiserviceadmincpp.so | rtiserviceadmincpp.dll |
* | ^ | librtidlc.so | rtidlc.dll |
* | ^ | librtiapputilsc.so | rtiapputilsc.dll |
* | ^ | libnddsmetp.so | nddsmetp.dll |
* | ^ | librticonnextmsgc.so | rticonnextmsgc.dll |
* | ^ | libnddsc.so | nddsc.dll |
* | ^ | librtixml2.so | rtixml2.dll |
* | ^ | libnddscore.so | nddscore.dll |
* | Headers | rti/routing/RoutingService.hpp ||
*
*/
/** \ingroup RTI_RoutingServiceLibModule
*
* @brief The @product.
*
*/
class Service : public dds::core::Reference<RoutingServiceImpl> {
public:
typedef RTI::Service::Admin::CommandRequest CommandRequest;
typedef RTI::Service::Admin::CommandReply CommandReply;
typedef dds::core::Reference<RoutingServiceImpl> Base;
OMG_DDS_REF_TYPE_NOTYPENAME(
Service,
dds::core::Reference,
RoutingServiceImpl);
/**
* @brief Creates a @product instance
*
* @param property
* @rs_st_in The property to configure @product instance.
*
* @mtsafety On non-Linux, non-Windows systems (i.e. VxWorks):
* UNSAFE for multiple threads to simultaneously make the FIRST
* call to any of the Service constructors. Subsequent calls are
* thread safe.
* On Windows and Linux systems, these calls are thread-safe.
*/
explicit Service(const ServiceProperty& property)
: Base(new RoutingServiceImpl(property))
{
this->delegate()->remember_reference(this->delegate());
}
/**
* @brief Creates a @product instance
*
* A callable shutdown hook can optionally be provided to handle the
* shutdown command received through remote administration. Upon reception
* of this command, @product will notify the installed hook.
*
* The following example shows simple implementation of a shutdown hook
* that sets a boolean flag to true when invoked:
*
* \code
*
* // Hook implementation
* struct FlagShutdownHook {
* public:
* FlagShutdownHook(bool& the_flag) : flag(the_flag) {
* flag = false;
* }
* void operator()() {
* flag = true;
* }
*
* bool& flag;
* };
*
* // Instantiate service with hook
* bool my_flag;
* FlagShutdownHook my_hook(my_flag)
* rti::routing::Service routing_service(
* property,
* my_hook);
* ...
*
*
* \endcode
*
*
* @param[in] property
* The property to configure @product instance.
*
* @param[in] shutdown_hook
* Callable object to handle the shutdown command. The expected
* type is a void operator()() (C++11 equivalent is
* std::function<void()>)
*
* @mtsafety On non-Linux, non-Windows systems (i.e. VxWorks):
* UNSAFE for multiple threads to simultaneously make the FIRST
* call to any of the Service constructors. Subsequent calls are
* thread safe.
* On Windows and Linux systems, these calls are thread-safe.
*/
template <typename HookFunc>
Service(
const ServiceProperty& property,
HookFunc& shutdown_hook)
: Base(new RoutingServiceImpl(property, shutdown_hook))
{
this->delegate()->remember_reference(this->delegate());
}
Service(const RTI_RoutingServiceProperty& property)
: Base(new RoutingServiceImpl(property))
{
this->delegate()->remember_reference(this->delegate());
}
explicit Service(Base::DELEGATE_REF_T reference) : Base(reference)
{
if (this->delegate()) {
this->delegate()->remember_reference(this->delegate());
}
}
/**
* @brief Starts @product.
*
* This is a non-blocking operation. @product will create its own set of
* threads to perform its tasks.
*/
void start()
{
this->delegate()->start();
}
/**
* @brief Stops @product.
*
* This operation will bloc the instance is fully stopped.
*/
void stop()
{
this->delegate()->stop();
}
/**
* @brief Attaches an Adapter plugin to be used by @product when it is
* started.
*
* By using this function an adapter can be statically compiled, created
* in your application and have the service load it, instead of registering
* a shared library and a create function in the configuration.
*
* The name passed in this function is the name that has to be used in the
* configuration to instantiate connections from the plugin.
*
* Example:
*
* \code
*
* rti::routing::RoutingService service(property);
*
* service.attach_adapter_plugin(myAdapter, "MyAdapter");
*
* service.start();
* ...
*
* \endcode
*
* And our configuration would look like this:
*
* \code
* <dds>
* <!-- No need to register the plugin in
* <plugin_library><adapter_plugin>
* -->
* <routing_service name="example">
* <domain_route name="myadapter_to_dds">
*
* <connection name="MyConnection" plugin_name="MyAdapter">
* ...
* </connection>
*
* ...
* </domain_route>
* </routing_service>
* </dds>
*
* \endcode
*
* This function can be called as many times as desired to attach
* several plugins.
*
* @pre Routing Service must not be started
*
* @param adapter_plugin
* @rs_st_in The adapter plugin object to be attached. The object
* shall remain alive during the execution of the service. Once the
* plugin is attached, the memory is owned by @product and will delete
* it upon service stop.
*
* @param plugin_name
* @rs_st_in
* The name used for this plugin in the &lt;connection&gt;
* tag in the configuration.
*
*/
void attach_adapter_plugin(
rti::routing::adapter::AdapterPlugin *adapter_plugin,
const std::string& plugin_name)
{
this->delegate()->attach_adapter_plugin(
adapter_plugin,
plugin_name);
}
/**
* @brief Attaches a Processor plugin to be used by @product when it is
* started.
*
* @see attach_adapter_plugin
*/
void attach_processor_plugin(
rti::routing::processor::ProcessorPlugin *processor_plugin,
const std::string& plugin_name)
{
this->delegate()->attach_processor_plugin(
processor_plugin,
plugin_name);
}
/**
* @brief Attaches a Transformation plugin to be used by @product when it
* is started.
*
* @see attach_adapter_plugin
*/
void attach_transformation_plugin(
rti::routing::transf::TransformationPlugin *transformation_plugin,
const std::string& plugin_name)
{
this->delegate()->attach_transformation_plugin(
transformation_plugin,
plugin_name);
}
/**
* @brief Executes an Administration command on this service.
*
* This operation directly executes the specified \p request in this
* service as if it was directly received from an administration requester.
*
* The request can represent any of the available administration operations
* as documented in the Administration chapter in the user's manual. This
* operation gives you an alternative way to control the service using
* the same remote administration interface but allowing you to call
* the operation directly.
*
* This operation can also throw an exception if an internal error
* occurs.
*
* Example:
*
* \code
*
* using namespace rti::routing;
* using namespace RTI::Service;
* using namespace RTI::Service::Admin;
*
* // Instantiate a RoutingServicee
* RoutingService service(...);
*
* // Prepare a request for any command, for example stop the service
* CommandRequest request;
* request.action(CommandActionKind::UPDATE_ACTION);
* request.resource_identifier("/routing_services/MyRouter");
* dds::topic::topic_type_support<EntityState>::to_cdr_buffer(
* reinterpret_cast<std::vector<char> &>(request.octet_body()),
* EntityState(EntityStateKind::DISABLED));
* // Execute and check result
* CommandReply reply = service.execute_command(request);
* if (reply.retcode().underlying() != CommandReplyRetcode::OK_RETCODE) {
* Logger.instance().error(
* std::string("Command returned: ") + reply.string_body());
* //handle
* ...
* }
*
* \endcode
*
* @param[in] request Representation of the command to be executed
* @return The reply with the result of the command execution.
*
*/
CommandReply execute_command(const CommandRequest& request)
{
return this->delegate()->execute_command(request);
}
/**
* @brief Executes an Administration command on this service.
*
* Similar to execute_command(const CommandRequest& request) except
* the caller provides the CommandReply object.
*
* @param[out] reply Representation of the reply containing the result of
* the operation
* @param[in] request Representation of the command to be executed
*
* @return A reference to the same reply object provided as a parameter
*/
CommandReply& execute_command(
CommandReply& reply,
const CommandRequest& request)
{
return this->delegate()->execute_command(reply, request);
}
/**
* @deprecated Calling this function at the end of the application is no
* longer necessary. It will be removed in future versions.
*/
static void finalize_globals()
{
rti::routing::Logger::instance().warn(
"Calling 'rti::routing::Service::finalize_globals()' is no "
"longer necessary and the function will be removed in future "
"versions");
}
};
typedef Service RoutingService;
}}
#endif // RTI_ROUTING_SERVICE_HPP_
@@ -0,0 +1,563 @@
/*
* (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_ROUTING_SERVICE_PROPERTY_HPP_
#define RTI_ROUTING_ROUTING_SERVICE_PROPERTY_HPP_
// IMPORTANT: macros.hpp must be the first RTI header included in every header
// file so that symbols are exported correctly on Windows
#include <dds/core/macros.hpp>
#include <rti/core/NativeValueType.hpp>
#include "routingservice/routingservice_service.h"
#include <rti/routing/detail/ForwarderUtils.hpp>
namespace rti { namespace routing {
class PropertyAdapter {
public:
typedef RTI_RoutingServiceProperty native_type;
static void initialize(native_type& native_value)
{
static const native_type DEFAULT
= RTI_RoutingServiceProperty_INITIALIZER;
native_value = DEFAULT;
native_value.service_verbosity = -1;
native_value.dds_verbosity = -1;
}
static void finalize(native_type& native_value)
{
if (native_value.cfg_strings != NULL) {
RTIOsapiHeap_freeArray(native_value.cfg_strings);
native_value.cfg_strings = NULL;
}
RTI_RoutingServiceProperty_finalize(&native_value);
}
static void copy(native_type& destination, const native_type& source)
{
RTIOsapiUtility_unusedParameter(destination);
RTIOsapiUtility_unusedParameter(source);
throw dds::core::UnsupportedError("Unsupported operation: copy");
}
static bool equals(const native_type& first, const native_type& second)
{
RTIOsapiUtility_unusedParameter(first);
RTIOsapiUtility_unusedParameter(second);
throw dds::core::UnsupportedError("Unsupported operation: equals");
}
static void add_properties_from_native(
std::map<std::string, std::string>& properties,
const RTI_RoutingServiceProperties *native_properties)
{
for (int i = 0; i < native_properties->count; i++) {
properties[native_properties->properties[i].name] =
(const char *) native_properties->properties[i].value;
}
}
static void add_properties_to_native(
RTI_RoutingServiceProperties *native_properties,
const std::map<std::string, std::string>& properties)
{
RTI_RoutingServiceProperties_finalize(native_properties);
RTI_RoutingServiceProperties_initialize(native_properties);
std::map<std::string, std::string>::const_iterator it = properties.begin();
for (; it != properties.end(); ++it) {
if (!RTI_RoutingServiceProperties_add(
native_properties,
it->first.c_str(),
it->second.c_str())) {
throw dds::core::Error("failed to add native property");
}
}
}
};
class ServiceProperty;
}
namespace core {
template<>
struct native_type_traits<rti::routing::ServiceProperty> {
typedef rti::routing::PropertyAdapter adapter_type;
typedef RTI_RoutingServiceProperty native_type;
};
}
namespace routing {
/** \ingroup RTI_RoutingServiceLibModule
*
* @brief Configuration for a @product object.
*
*/
class ServiceProperty : public rti::core::NativeValueType<ServiceProperty> {
public:
RTI_NATIVE_VALUE_TYPE_DEFINE_DEFAULT_MOVE_OPERATIONS(ServiceProperty)
typedef rti::core::NativeValueType<ServiceProperty> Base;
/**
* @brief Creates a property object with default settings.
*/
ServiceProperty(): Base()
{
}
ServiceProperty(const struct RTI_RoutingServiceProperty &native_property)
: Base(native_property)
{
}
/**
* @brief Getter (see setter with the same name)
*/
std::string cfg_file() const
{
return native().cfg_file == NULL ? "" : native().cfg_file;
}
/**
* @brief Path to an @product configuration file
*
* @default empty string.
*/
ServiceProperty& cfg_file(const std::string& filename)
{
DDS_String_replace(
&native().cfg_file,
filename.c_str());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
const std::vector<std::string>& cfg_strings() const
{
return cfg_strings_;
}
/**
* @brief XML configuration represented as strings
*
* An array of strings that altogether make up an
* XML document to configure @product. This parameter is used
* only if ServiceProperty::cfg_file is empty.
*
* The reason for using an array instead of one single string is to
* get around the limited size of literal strings.
* In general, if you create the XML string dynamically
* the vector needs only one element.
*
* @default empty.
*/
ServiceProperty& cfg_strings(
const std::vector<std::string>& the_cfg_strings)
{
cfg_strings_ = the_cfg_strings;
if (cfg_strings_.size() > 0) {
if (!RTIOsapiHeap_reallocateArray(
(char ***) &native().cfg_strings,
cfg_strings_.size(),
char *)) {
throw dds::core::OutOfResourcesError("cfg_strings native array");
}
for (uint32_t i = 0; i < cfg_strings_.size(); i++) {
native().cfg_strings[i] = cfg_strings_[i].c_str();
}
}
native().cfg_strings_count = static_cast<int>(cfg_strings_.size());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string service_name() const
{
return native().service_name == NULL ? "" : native().service_name;
}
/**
* @brief The name of the @product configuration to run.
*
* This is the name used to find the &lt;routing_service&gt;
* XML tag in the configuration file; the name that will
* be used to refer to this execution in remote administration and
* monitoring.
*
* @default empty string.
*/
ServiceProperty& service_name(const std::string& name)
{
DDS_String_replace(
&native().service_name,
name.c_str());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string application_name() const
{
return native().application_name;
}
/**
* @brief Assigns a name to the execution of the @product.
*
* Remote commands and status information will refer to the service using
* this name.
*
* In addition, the name of DomainParticipants created by @product will be
* based on this name.
*
* @default empty string.
* If no application name is specified, @product will use
* ServiceProperty::service_name.
*
*/
ServiceProperty& application_name(const std::string& name)
{
DDS_String_replace(
&native().application_name,
name.c_str());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool enforce_xsd_validation() const
{
return (native().enforce_xsd_validation == DDS_BOOLEAN_TRUE)
? true
: false;
}
/**
* @brief Controls whether the service applies XSD validation to the loaded
* configuration.
*
* @default true
*/
ServiceProperty& enforce_xsd_validation(const bool enforce_xsd_validation)
{
native().enforce_xsd_validation = enforce_xsd_validation;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
int domain_id_base() const
{
return native().domain_id_base;
}
/*e
* @brief Value that is added to the domain IDs of the
* domain routes in the XML configuration.
*
* By using this, an XML file can use relative domain IDs.
*
* @default 0
*/
ServiceProperty& domain_id_base(const int domain_id)
{
native().domain_id_base = domain_id;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string plugin_search_path() const
{
return native().plugin_search_path == NULL
? ""
: native().plugin_search_path;
}
/**
* @brief This path is used to look for plugin libraries.
*
* If the plugin class libraries specified in the XML file don't
* contain a full path, @product looks for them in this
* directory if not NULL.
*
* @default "." (working directory)
*/
ServiceProperty& plugin_search_path(const std::string& path)
{
DDS_String_replace(
&native().plugin_search_path,
path.c_str());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool dont_start_service() const
{
return (native().dont_start_service == DDS_BOOLEAN_TRUE)
? true
: false;
}
/**
* @brief Set this to true to if you do not want @product enabled when
* RoutingServcie::start is called.
*
* @product can be enabled afterwards through remote administration.
*
* @default false
*/
ServiceProperty& dont_start_service(const bool not_start)
{
native().dont_start_service = not_start
? DDS_BOOLEAN_TRUE
: DDS_BOOLEAN_FALSE;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool enable_administration() const
{
return (native().enable_administration == DDS_BOOLEAN_TRUE)
? true
: false;
}
/**
* @brief Set this to true to enable remote administration
* or false to disable it.
*
* @default false
*/
ServiceProperty& enable_administration(const bool enable)
{
native().enable_administration = enable
? DDS_BOOLEAN_TRUE
: DDS_BOOLEAN_FALSE;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
int administration_domain_id() const
{
return native().administration_domain_id;
}
/**
* @brief If ServiceProperty::enable_administration is true, this is
* the domain ID to use for remote administration.
*
* Takes precedence over the XML configuration.
* If ServiceProperty::enable_administration is false, this value is not used
* even if remote administration is enabled in the XML configuration.
*
* @default 0
*/
ServiceProperty& administration_domain_id(const int domain_id)
{
native().administration_domain_id = domain_id;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool enable_monitoring() const
{
return native().enable_monitoring == DDS_BOOLEAN_TRUE
? true
: false;
}
/**
* @brief Set it to true to enable remote monitoring
* or false to disable it.
*
* @default false
*/
ServiceProperty& enable_monitoring(const bool& enable)
{
native().enable_monitoring = enable
? DDS_BOOLEAN_TRUE
: DDS_BOOLEAN_FALSE;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
int monitoring_domain_id() const
{
return native().monitoring_domain_id;
}
/**
* @brief If ServiceProperty::enable_monitoring is true, this is
* the domain ID to use for remote monitoring.
*
* Takes precedence over the XML configuration.
* If ServiceProperty::enable_monitoring is false, this value is not used,
* even if remote monitoring is enabled in the XML configuration.
*
* @default 0
*/
ServiceProperty& monitoring_domain_id(const int& domain_id)
{
native().monitoring_domain_id = domain_id;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool skip_default_files() const
{
return (native().skip_default_files == DDS_BOOLEAN_TRUE)
? true
: false;
}
/**
* @brief Set it to true to avoid loading the
* standard files usually loaded by @product.
*
* Only the configuration in ServiceProperty::cfg_file or
* ServiceProperty::cfg_strings will be loaded.
*
* @default false
*/
ServiceProperty& skip_default_files(const bool& skip)
{
native().skip_default_files = skip
? DDS_BOOLEAN_TRUE
: DDS_BOOLEAN_FALSE;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool identify_execution() const
{
return (native().identify_execution == DDS_BOOLEAN_TRUE)
? true
: false;
}
/**
* @brief Set this to true to append the host name and process ID
* to the @product execution name.
*
* Used to get unique names for remote administration and monitoring.
*
* @default false
*/
ServiceProperty& identify_execution(const bool& identify)
{
native().identify_execution = identify
? DDS_BOOLEAN_TRUE
: DDS_BOOLEAN_FALSE;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string license_file_name() const
{
return native().license_file_name == NULL? ""
: native().license_file_name;
}
/**
* @brief Path to an @product license file.
*
* If not empty, this file is checked for a valid license; otherwise,
* default location will be used. This parameter is only used if your
* installation requires a license file.
*
* @default empty string.
*/
ServiceProperty& license_file_name(const std::string& filename)
{
DDS_String_replace(
&native().license_file_name,
filename.c_str());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::map<std::string, std::string> user_environment() const
{
std::map<std::string, std::string> properties;
PropertyAdapter::add_properties_from_native(
properties,
&native().user_environment);
return properties;
}
/**
* @brief Dictionary of user variables.
* The dictionary provides a parallel way to expand XML configuration
* variables in the form $(my_var), when they are not defined in the
* environment.
*
* @default empty
*/
ServiceProperty& user_environment(
const std::map<std::string, std::string>& user_environment)
{
rti::routing::PropertyAdapter::add_properties_to_native(
&native().user_environment,
user_environment);
return *this;
}
private:
std::vector<std::string> cfg_strings_;
};
}}
#endif // RTI_ROUTING_ROUTING_SERVICE_PROPERTY_HPP_
@@ -0,0 +1,210 @@
/*
* (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_INFO_HPP_
#define RTI_ROUTING_ADAPTER_STREAM_INFO_HPP_
// IMPORTANT: macros.hpp must be the first RTI header included in every header
// file so that symbols are exported correctly on Windows
#include <dds/core/macros.hpp>
#include <routingservice/routingservice_infrastructure.h>
#include <dds/core/Value.hpp>
#include <dds/core/Exception.hpp>
#include <rti/core/NativeValueType.hpp>
#include <rti/routing/TypeInfo.hpp>
namespace rti { namespace routing {
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
*/
class StreamInfoAdapter {
public:
typedef RTI_RoutingServiceStreamInfo native_type;
static void initialize(native_type& native_value)
{
RTIOsapiMemory_zero(
&native_value,
sizeof (RTI_RoutingServiceStreamInfo));
}
static void finalize(native_type& native_value)
{
TypeInfoAdapter::finalize(native_value.type_info);
if (native_value.stream_name != NULL) {
DDS_String_free(native_value.stream_name);
native_value.stream_name = NULL;
}
}
static void copy(native_type& destination, const native_type& source)
{
char *result = DDS_String_replace(
&destination.stream_name,
source.stream_name);
if (source.stream_name != NULL && result == NULL) {
throw std::bad_alloc();
}
destination.disposed = source.disposed;
TypeInfoAdapter::copy(
destination.type_info,
source.type_info);
}
static bool equals(const native_type& first, const native_type& second)
{
if (strcmp(first.stream_name, second.stream_name) != 0) {
return false;
}
if (first.disposed != second.disposed) {
return false;
}
return TypeInfoAdapter::equals(first.type_info, second.type_info);
}
};
class StreamInfo;
}
// native_type_traits needs to be defined in rti::core
namespace core {
template <>
struct native_type_traits<rti::routing::StreamInfo> {
typedef rti::routing::StreamInfoAdapter adapter_type;
typedef RTI_RoutingServiceStreamInfo native_type;
};
}
namespace routing {
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
* @class rti::routing::StreamInfo
*
* @brief Definition of the stream information that @product needs to manage
* user data streams.
*
* A stream in @product is a typed data channel to consume/produce data
* in a data domain.
*
*/
class StreamInfo : public rti::core::NativeValueType<StreamInfo> {
public:
RTI_NATIVE_VALUE_TYPE_DEFINE_DEFAULT_MOVE_OPERATIONS(StreamInfo)
typedef rti::core::NativeValueType<StreamInfo> Base;
public:
/**
* @brief Constructs a StreamInfo with the minimum required information.
*
* @param the_stream_name
* @rs_st_in The name of the stream.
* @param the_type_name
* @rs_st_in The name of the type associated with the data in the
* stream.
*/
StreamInfo(
const std::string& the_stream_name,
const std::string& the_type_name)
{
stream_name(the_stream_name);
type_info().type_name(the_type_name);
}
StreamInfo(const RTI_RoutingServiceStreamInfo &native_stream_info)
: Base(native_stream_info)
{
}
/**
* @brief Getter (see setter with the same name)
*/
bool disposed() const
{
return native().disposed ? true : false;
}
/**
* @brief Sets the dispose flag in this object.
*
* Indicates whether the stream is a newly discovered stream or a
* disposed stream that no longer exists.
*
* @param the_disposed
* @rs_st_in true if the stream is marked as disposed or false
* otherwise.
*/
StreamInfo& disposed(bool the_disposed)
{
native().disposed = the_disposed ? 1 : 0;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string stream_name() const
{
return native().stream_name;
}
/**
* @brief Sets the name of the stream
*
* @param the_stream_name
* @rs_st_in Name of the stream.
*/
StreamInfo& stream_name(const std::string& the_stream_name)
{
if (DDS_String_replace(
&native().stream_name,
the_stream_name.c_str()) == NULL) {
throw std::bad_alloc();
}
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
TypeInfo& type_info()
{
using namespace rti::core::native_conversions;
return cast_from_native<TypeInfo>(native().type_info);
}
/**
* @brief Sets the type information associated with the stream.
*
* @see TypeInfo.
*/
const TypeInfo& type_info() const
{
using namespace rti::core::native_conversions;
return cast_from_native<TypeInfo>(native().type_info);
}
};
}}
#endif // RTI_ROUTING_ADAPTER_STREAM_INFO_HPP_
@@ -0,0 +1,322 @@
/*
* (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_TYPE_INFOHPP_
#define RTI_ROUTING_ADAPTER_TYPE_INFOHPP_
// IMPORTANT: macros.hpp must be the first RTI header included in every header
// file so that symbols are exported correctly on Windows
#include <dds/core/macros.hpp>
#include <routingservice/routingservice_infrastructure.h>
#include <dds/core/Value.hpp>
#include <dds/core/SafeEnumeration.hpp>
#include <dds/core/xtypes/DynamicType.hpp>
#include <rti/core/NativeValueType.hpp>
namespace rti { namespace routing {
/**
* @ingroup RTI_RoutingServiceInfrastructureModule
*
*/
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
* @class TypeRepresentationKind_def
*
* @brief The definition of the rti::routing::TypeRepresentationKind
*
* The range [0-100] is reserved for RTI use. Within that range are some
* predefined type representations.
*
*/
struct TypeRepresentationKind_def {
/**
* @brief Definition of all the possible type representation kinds
*/
enum type {
/**
* @brief Dynamic type representation.
*
* Types with this representation are provided as \ndds TypeCodes.
*
* For more information about TypeCodes, see Chapter 3 in the
* RTI Core Libraries and Utilities User's Manual.
*/
DYNAMIC_TYPE = RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_DYNAMIC_TYPE,
/**
* @brief @not_supported XML type representation.
*
* Types with this representation are provided as XML strings.
* The XML schema is the \ndds XML schema for type representation.
*
* For more information about XML representation,
* see Chapter 3 in the RTI Core Libraries and Utilities User's Manual.
*/
XML = RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_XML,
/**
* @brief @not_supported Java object type representation.
*
* Types with this representation are provided as Java objects.
*/
JAVA_OBJECT = RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_JAVA_OBJECT,
/**
* @brief @not_supported Custom type representation.
*
* Types with this representation are specific to a concrete
* adapter implementation
*/
CUSTOM = RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_FIRST_CUSTOM_REPRESENTATION
};
};
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
* @class TypeRepresentationKind
*
* @brief valid type representations that @product accepts.
*
* @see rti::routing::TypeRepresentationKind_def
*/
typedef dds::core::safe_enum<TypeRepresentationKind_def> TypeRepresentationKind;
class TypeInfoAdapter {
public:
typedef RTI_RoutingServiceTypeInfo native_type;
static void initialize(native_type& native_value)
{
static const native_type default_value = {
NULL,
DDS_BOOLEAN_TRUE,
RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_DYNAMIC_TYPE,
NULL};
native_value = default_value;
}
static void finalize(native_type& native_value)
{
if (native_value.type_name != NULL) {
RTIOsapiHeap_freeString(native_value.type_name);
native_value.type_name = NULL;
}
}
static void copy(native_type& destination, const native_type& source)
{
char *result = DDS_String_replace(
&destination.type_name,
source.type_name);
if (source.type_name != NULL && result == NULL) {
throw std::bad_alloc();
}
destination.can_be_optimized = source.can_be_optimized;
destination.type_representation_kind =
source.type_representation_kind;
destination.type_representation =
source.type_representation;
}
static bool equals(const native_type& first, const native_type& second)
{
if (strcmp(first.type_name, second.type_name) != 0) {
return false;
}
if (first.type_representation_kind
!= second.type_representation_kind) {
return false;
}
return first.type_representation == second.type_representation;
}
};
class TypeInfo;
}
// native_type_traits needs to be defined in rti::core
namespace core {
template <>
struct native_type_traits<rti::routing::TypeInfo> {
typedef rti::routing::TypeInfoAdapter adapter_type;
typedef RTI_RoutingServiceTypeInfo native_type;
};
}
namespace routing {
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
* @class rti::routing::TypeInfo
*
* @brief Definition of the type information associated with a @product
* stream.
*
* @see StreamInfo.
*
*/
class TypeInfo : public rti::core::NativeValueType<TypeInfo> {
public:
RTI_NATIVE_VALUE_TYPE_DEFINE_DEFAULT_MOVE_OPERATIONS(TypeInfo)
typedef rti::core::NativeValueType<TypeInfo> Base;
/**
* @brief Type representation defined as an opaque pointer.
*
* How this opaque is interpreted depends on the TypeRepresentationKind.
*/
typedef RTI_RoutingServiceTypeRepresentation TypeRepresentationType;
public:
/**
* @brief Constructs a TypeInfo with the minimum required information.
*
* @param the_type_name
* @rs_st_in Registered name of the type associated with the data.
* @param the_type_representation_kind
* @rs_st_in Indicates the representation of the object that
* describes the type. Default: TypeRepresentationKind::DYNAMIC_TYPE.
*/
TypeInfo(
const std::string& the_type_name,
TypeRepresentationKind the_type_representation_kind =
TypeRepresentationKind::DYNAMIC_TYPE)
{
type_name(the_type_name);
type_representation_kind(the_type_representation_kind);
native().can_be_optimized = DDS_BOOLEAN_TRUE;
}
TypeInfo(const struct RTI_RoutingServiceTypeInfo &native_stream_info)
: Base(native_stream_info)
{
}
/**
* @brief Getter (see setter with the same name)
*/
std::string type_name() const
{
return native().type_name;
}
/**
* @brief Sets the registered name of the type associated with the data.
*
* @product uses the type name to provide the right type information to
* StreamReader and StreamWriter. Namely, a type match is performed by
* comparing this type name with the value specified in the tag
* &lt;registered_type_name&gt; within the &lt;input&gt; and &lt;output&gt;
* tags.
*/
TypeInfo& type_name(const std::string& the_type_name)
{
if (DDS_String_replace(
&native().type_name,
the_type_name.c_str()) == NULL) {
throw std::bad_alloc();
}
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
TypeRepresentationKind type_representation_kind() const
{
return static_cast<TypeRepresentationKind::type>(
native().type_representation_kind);
}
/**
* @brief Sets the type representation kind.
*
* This member indicates how to interpret the type representation.
*
* @see TypeRepresentationKind
*/
TypeInfo& type_representation_kind(
TypeRepresentationKind the_type_representation_kind)
{
native().type_representation_kind = static_cast<int>(
the_type_representation_kind.underlying());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
TypeRepresentationType type_representation() const
{
return native().type_representation;
}
/**
* @brief Sets the type representation value.
*
* This member is defined as an opaque pointer that can hold any type
* representation. How to interpret this pointer is determined by the
* TypeRepresentationKind, which shall be consistent with the object set
* in this member.
*/
TypeInfo& type_representation(TypeRepresentationType the_type_representation)
{
native().type_representation = the_type_representation;
return *this;
}
/**
* @brief Returns the type_representation as DynamicType object
*
* The operation throws if type_representation_kind is not DYNAMIC_TYPE
*
*/
const dds::core::xtypes::DynamicType& dynamic_type() const
{
if (type_representation_kind() != TypeRepresentationKind::DYNAMIC_TYPE) {
throw dds::core::IllegalOperationError(
"type representation is not dynamic type");
}
const DDS_TypeCode *native_typecode = reinterpret_cast<DDS_TypeCode*>(
type_representation());
return rti::core::native_conversions::cast_from_native<
dds::core::xtypes::DynamicType>(*native_typecode);
}
/**
* @brief Sets the type representation value as DynamicType object
*
* The provided DynamicType pointer must point to an object that remains
* valid until the StreamInfo object is destroyed.
*
* @see type_representation(TypeRepresentationType the_type_representation)
*/
void dynamic_type(const dds::core::xtypes::DynamicType *dynamic_type)
{
DDS_TypeCode *native_typecode = const_cast<DDS_TypeCode*>(
reinterpret_cast<const DDS_TypeCode *>(dynamic_type));
type_representation(static_cast<TypeRepresentationType>(native_typecode));
type_representation_kind(TypeRepresentationKind::DYNAMIC_TYPE);
}
};
}}
#endif // RTI_ROUTING_ADAPTER_TYPE_INFOHPP_
@@ -0,0 +1,60 @@
/*
* (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_UPDATABLE_ENTITY_HPP_
#define RTI_ROUTING_UPDATABLE_ENTITY_HPP_
#include <map>
#include <string>
namespace rti { namespace routing {
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
* @class rti::routing::UpdatableEntity
*
* @brief Defines a common interface for all the pluggable entities that can
* be updated at runtime.
*
* @product allows to update an pluggable entity through remote administration.
*
* @mtsafety Safe
* The UpdatableEntity::update operation is called only for one
* entity at a time. Additionally, no other operations can be made
* concurrently on a pluggable entity during the
* UpdatableEntity::update call.
*/
class UpdatableEntity {
public:
/**
* @brief Updates a pluggable entity.
*
* @param properties
* @rs_st_in The new configuration properties, obtained as result
* of parsing the elements within the &lt;property&gt; tag
* corresponding to the entity being updated.
*/
virtual void update(const std::map<std::string, std::string>& properties)
{
(void) properties;
}
/**
* @brief Virtual destructor.
*/
virtual ~UpdatableEntity()
{
}
};
}}
#endif // RTI_ROUTING_UPDATABLE_ENTITY_HPP_
@@ -0,0 +1,202 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_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 &lt;connection&gt;.
*
* @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
* &lt;adapter_plugin&gt; within &lt;plugin_library&gt;. 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
* &lt;connection&gt; 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
* &lt;output&gt; 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
* &lt;output&gt; 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
* &lt;session&gt; 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
* &lt;input&gt; within &lt;route&gt; and &lt;auto_route&gt;.
*
* @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
* &lt;output&gt; within &lt;route&gt; or &lt;auto_route&gt;.
*
* @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_
@@ -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_
@@ -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_
@@ -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_ */
@@ -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_
@@ -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_
@@ -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_
@@ -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_
@@ -0,0 +1,105 @@
/*
* (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_DETAIL_FORWARDER_UTILS_UTILS_HPP_
#define RTI_ROUTING_DETAIL_FORWARDER_UTILS_UTILS_HPP_
#include <map>
#include <dds/topic/Topic.hpp>
#include <rti/core/Exception.hpp>
#include <routingservice/routingservice_infrastructure.h>
namespace rti { namespace routing { namespace detail {
#define RTI_ROUTING_THROW_ON_NULL(pointer) \
if ((pointer) == NULL) { \
throw dds::core::Error("invalid return of NULL"); \
}
#define RTI_ROUTING_THROW_ON_ENV_ERROR(NATIVE_ENV) \
if (RTI_RoutingServiceEnvironment_error_occurred((NATIVE_ENV))) { \
dds::core::Error rex( \
RTI_RoutingServiceEnvironment_get_error_message((NATIVE_ENV))); \
RTI_RoutingServiceEnvironment_clear_error((NATIVE_ENV)); \
throw rex; \
}
#define RTI_ROUTING_SAMPLE_VECTOR_COPY_FROM_NATIVE( \
VECTOR, \
NATIVE_ARRAY, \
ARRAY_LENGTH) \
(VECTOR).resize((ARRAY_LENGTH)); \
memcpy(&((VECTOR)[0]), \
(NATIVE_ARRAY), \
sizeof (void*) * (ARRAY_LENGTH));
#define RTI_ROUTING_SAMPLE_VECTOR_COPY_FROM_NATIVE_W_OFFSET( \
VECTOR, \
NATIVE_ARRAY, \
OFFSET, \
ARRAY_LENGTH) \
(VECTOR).resize((ARRAY_LENGTH) + (OFFSET)); \
memcpy(&((VECTOR)[OFFSET]), \
(NATIVE_ARRAY), \
sizeof (void*) * (ARRAY_LENGTH));
#define RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS( \
TO_VECTOR, \
FROM_VECTOR) \
(TO_VECTOR).resize((FROM_VECTOR).size()); \
if ((FROM_VECTOR).size() > 0) { \
memcpy( \
&(TO_VECTOR[0]), \
&(FROM_VECTOR)[0], \
sizeof(void*) * (FROM_VECTOR).size()); \
}
template <typename OwnerType, typename ForwarderType>
struct ScopedForwarder {
ScopedForwarder(
OwnerType *owner,
ForwarderType *forwarder,
RTI_RoutingServiceEnvironment *environment)
:owner_(owner), forwarder_(forwarder), environment_(environment)
{
}
void release()
{
forwarder_ = NULL;
}
~ScopedForwarder()
{
if (forwarder_ != NULL) {
ForwarderType::delete_native(
owner_,
forwarder_->native(),
environment_);
}
}
private:
OwnerType *owner_;
ForwarderType *forwarder_;
RTI_RoutingServiceEnvironment *environment_;
};
} } }
#endif // RTI_ROUTING_DETAIL_FORWARDER_UTILS_UTILS_HPP_
@@ -0,0 +1,243 @@
/*
* (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_ROUTING_SERVICE_IMPL_HPP_
#define RTI_ROUTING_ROUTING_SERVICE_IMPL_HPP_
#include <dds/core/refmacros.hpp>
#include <rti/core/detail/SelfReference.hpp>
#include "routingservice/routingservice_adapter.h"
#include "routingservice/routingservice_service.h"
#include "routingservice/routingservice_log.h"
#include "routingservice/routingservice_remote_config.h"
#include "routingservice/ServiceAdmin.h"
#include <rti/routing/ServiceProperty.hpp>
#include <rti/routing/adapter/AdapterPlugin.hpp>
#include <rti/routing/transf/TransformationPlugin.hpp>
#include <rti/routing/processor/ProcessorPlugin.hpp>
#include <rti/routing/detail/ShutdownHookForwarder.hpp>
#include <rti/idlgen/ServiceAdmin.hpp>
namespace rti { namespace routing {
class RoutingServiceImpl
: public rti::core::detail::RetainableType<RoutingServiceImpl> {
public:
typedef RTI::Service::Admin::CommandRequest CommandRequest;
typedef RTI::Service::Admin::CommandReply CommandReply;
template <typename HookFunc>
explicit RoutingServiceImpl(
const ServiceProperty& property,
HookFunc& shutdown_hook)
: native_(RTI_RoutingService_new(&property.native())),
shutdown_hook_fwd_(
new rti::routing::detail::ShutdownHookForwarder<HookFunc>(
shutdown_hook))
{
rti::core::check_create_entity(native_, "RoutingService");
RTI_RoutingService_set_remote_shutdown_hook(
native_,
shutdown_hook_fwd_->native());
}
explicit RoutingServiceImpl(const ServiceProperty& property)
: native_(RTI_RoutingService_new(&property.native())),
shutdown_hook_fwd_(nullptr)
{
rti::core::check_create_entity(native_, "RoutingService");
}
RoutingServiceImpl(const RTI_RoutingServiceProperty& property)
: native_(RTI_RoutingService_new(&property)),
shutdown_hook_fwd_(NULL)
{
rti::core::check_create_entity(native_, "RoutingService");
}
RoutingServiceImpl(RTI_RoutingService *native)
: native_(native), shutdown_hook_fwd_(NULL)
{
rti::core::check_create_entity(native_, "RoutingService");
}
~RoutingServiceImpl()
{
RTI_RoutingService_delete(native_);
delete shutdown_hook_fwd_;
}
void start()
{
if (!RTI_RoutingService_start(native_)) {
throw dds::core::Error("failed to start RoutingService");
}
}
void stop()
{
if (!RTI_RoutingService_stop(native_)) {
throw dds::core::Error("failed to stop RoutingService");
}
}
void attach_adapter_plugin(
rti::routing::adapter::AdapterPlugin *adapter_plugin,
const std::string& registered_name)
{
RTI_RoutingServiceAdapterPluginExt *native_plugin =
adapter::detail::AdapterForwarder::create_plugin(adapter_plugin);
if (!RTI_RoutingService_attach_adapter_plugin(
native_,
native_plugin,
registered_name.c_str())) {
throw dds::core::Error("failed to attach native adapter");
}
}
void attach_transformation_plugin(
rti::routing::transf::TransformationPlugin *transformation_plugin,
const std::string& registered_name)
{
RTI_RoutingServiceTransformationPlugin *native_plugin =
transf::detail::TransformationPluginForwarder::create_plugin(
transformation_plugin);
if (!RTI_RoutingService_attach_transformation_plugin(
native_,
native_plugin,
registered_name.c_str())) {
throw dds::core::Error("failed to attach native transformation");
}
}
void attach_processor_plugin(
rti::routing::processor::ProcessorPlugin *processor_plugin,
const std::string& registered_name)
{
RTI_RoutingServiceProcessorPlugin *native_plugin =
processor::detail::ProcessorPluginForwarder::create_plugin(
processor_plugin);
if (!RTI_RoutingService_attach_processor_plugin(
native_,
native_plugin,
registered_name.c_str())) {
throw dds::core::Error("failed to attach native processor");
}
}
CommandReply& execute_command(
CommandReply& reply,
const CommandRequest& request)
{
RTI_Service_Admin_CommandRequest native_request =
RTI_Service_Admin_CommandRequest_INITIALIZER;
RTI_Service_Admin_CommandReply *native_reply_ptr = nullptr;
if (!RTI_Service_Admin_CommandRequest_initialize(&native_request)) {
RTI_Service_Admin_CommandRequest_finalize(&native_request);
throw dds::core::Error("failed to initialize CommandRequest");
}
std::shared_ptr<RTI_Service_Admin_CommandRequest> request_ptr(
&native_request,
[](RTI_Service_Admin_CommandRequest *native_req_ptr) {
RTI_Service_Admin_CommandRequest_finalize(native_req_ptr);
});
to_native(native_request, request);
RTI_RoutingService_execute_command(
native_,
&native_reply_ptr,
&native_request);
from_native(reply, *native_reply_ptr);
RTI_RoutingService_return_reply(native_, native_reply_ptr);
return reply;
}
CommandReply execute_command(const CommandRequest& request)
{
CommandReply reply;
return execute_command(reply, request);
}
RTI_RoutingService* native() const
{
return native_;
}
private:
RTI_RoutingService *native_;
rti::routing::detail::AbstractShutdownHookForwarder *shutdown_hook_fwd_;
static RTI_Service_Admin_CommandRequest& to_native(
RTI_Service_Admin_CommandRequest& native,
const RTI::Service::Admin::CommandRequest& request)
{
native.action = static_cast<RTI_Service_Admin_CommandActionKind>(
request.action());
if (request.application_name().is_set()) {
if (DDS_String_replace(
&native.application_name,
request.application_name().get().c_str()) == NULL) {
throw dds::core::Error("failed to set application name");
}
}
native.instance_id = request.instance_id();
if (DDS_String_replace(
&native.resource_identifier,
request.resource_identifier().c_str()) == NULL) {
throw dds::core::Error("failed to set resource identifier");
}
if (DDS_String_replace(
&native.string_body,
request.string_body().c_str()) == NULL) {
throw dds::core::Error("failed to set string body");
}
if (!DDS_OctetSeq_from_array(
&native.octet_body,
(DDS_Octet *) request.octet_body().data(),
(DDS_Long) request.octet_body().size())) {
throw dds::core::Error("failed to set octet body");
}
return native;
}
static RTI::Service::Admin::CommandReply& from_native(
RTI::Service::Admin::CommandReply& reply,
const RTI_Service_Admin_CommandReply& native)
{
using namespace RTI::Service::Admin;
reply.retcode(static_cast<CommandReplyRetcode>(native.retcode));
reply.native_retcode(native.native_retcode);
DDS_Octet *native_octet_body = DDS_OctetSeq_get_contiguous_buffer(
(DDS_OctetSeq *) &native.octet_body);
if (DDS_OctetSeq_get_length(&native.octet_body) < 0) {
throw dds::core::Error("invalid octet_body length");
}
reply.octet_body().resize(
(size_t) DDS_OctetSeq_get_length(&native.octet_body));
std::copy(
native_octet_body,
native_octet_body + DDS_OctetSeq_get_length(&native.octet_body),
reply.octet_body().begin());
reply.string_body(native.string_body);
return reply;
}
};
}}
#endif // RTI_ROUTINGv_ROUTING_SERVICE_IMPL_HPP_
@@ -0,0 +1,79 @@
/*
* (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_SHUTDOWN_HOOK_HPP_
#define RTI_ROUTING_SHUTDOWN_HOOK_HPP_
#include "routingservice/routingservice_service.h"
namespace rti { namespace routing { namespace detail {
class AbstractShutdownHookForwarder {
public:
AbstractShutdownHookForwarder()
{
native_.on_shutdown = on_shutdown_forwarder;
native_.shutdown_hook_data = this;
}
virtual ~AbstractShutdownHookForwarder()
{
}
virtual void on_shutdown()
{
}
static void on_shutdown_forwarder(void *hook_data)
{
AbstractShutdownHookForwarder *self =
static_cast<AbstractShutdownHookForwarder*>(hook_data);
try {
self->on_shutdown();
} catch(...) {}
}
const RTI_RoutingServiceRemoteShutdownHook* native() const
{
return &native_;
}
private:
RTI_RoutingServiceRemoteShutdownHook native_;
};
template<typename HookFunc>
class ShutdownHookForwarder : public AbstractShutdownHookForwarder {
public:
ShutdownHookForwarder(HookFunc& shutdown_hook)
: shutdown_hook_(shutdown_hook)
{
}
void on_shutdown()
{
shutdown_hook_();
};
private:
HookFunc& shutdown_hook_;
};
}
} }
#endif /* RTI_ROUTING_SHUTDOWN_HOOK_HPP_ */
@@ -0,0 +1,61 @@
/*
* (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_DETAIL_UPDATABLE_ENTITY_FORWARDER_HPP_
#define RTI_ROUTING_DETAIL_UPDATABLE_ENTITY_FORWARDER_HPP_
#include <rti/core/Exception.hpp>
#include <rti/apputils/ServiceException.hpp>
#include <rti/routing/UpdatableEntity.hpp>
#include <rti/routing/ServiceProperty.hpp>
#include <rti/routing/detail/ForwarderUtils.hpp>
namespace rti { namespace routing { namespace detail {
class UpdatableEntityForwarder {
public:
static void update(
UpdatableEntity *updatable_entity,
const struct RTI_RoutingServiceProperties *native_properties,
RTI_RoutingServiceEnvironment *environment)
{
try {
// Set properties
PropertySet properties;
rti::routing::PropertyAdapter::add_properties_from_native(
properties,
native_properties);
updatable_entity->update(properties);
} 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;
}
}
};
}}}
#endif // RTI_ROUTING_DETAIL_UPDATABLE_ENTITY_FORWARDER_HPP_
@@ -0,0 +1,73 @@
/*
(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 HPP_ROUTING_LOG_LOG_CONFIG_HPP_
#define HPP_ROUTING_LOG_LOG_CONFIG_HPP_
#include <cstdio>
#include <cstdarg>
#include "log/log_common.h"
#include "routingservice/routingservice_log.h"
#include "ndds/ndds_config_c.h"
namespace rti { namespace routing { namespace log {
class LogConfig {
public:
static rti::routing::log::LogConfig& instance()
{
static rti::routing::log::LogConfig singleton;
return singleton;
}
// Deleted constructor to avoid multiple instances.
LogConfig(const LogConfig&) = delete;
LogConfig(LogConfig&&) = delete;
RTILogBitmap instrumentation_mask() const
{
NDDS_Config_LogVerbosity verbosity =
NDDS_Config_Logger_get_verbosity_by_service(
NDDS_Config_Logger_get_instance(),
NDDS_CONFIG_LOG_SERVICE_ROUTING);
return (RTILogBitmap) verbosity;
}
LogConfig& instrumentation_mask(RTILogBitmap logmask)
{
NDDS_Config_Logger_set_verbosity_by_service(
NDDS_Config_Logger_get_instance(),
NDDS_CONFIG_LOG_SERVICE_ROUTING,
(NDDS_Config_LogVerbosity) logmask);
return *this;
}
void router_instrumentation_mask(RTILogBitmap logmask)
{
instrumentation_mask(logmask);
}
void update_native(RTILogBitmap logmask)
{
router_instrumentation_mask(logmask);
}
private:
// Constructor is private: this class is a singleton
LogConfig() = default;
};
}}} // rti::routing::log
#endif /* HPP_ROUTING_LOG_LOG_CONFIG_HPP_ */
@@ -0,0 +1,703 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_PROCESSOR_INPUT_HPP_
#define RTI_ROUTING_PROCESSOR_INPUT_HPP_
#include <dds/core/Value.hpp>
#include <dds/core/SafeEnumeration.hpp>
#include <rti/core/NativeValueType.hpp>
#include <rti/core/Entity.hpp>
#include <dds/sub/DataReader.hpp>
#include <dds/core/xtypes/DynamicData.hpp>
#include "routingservice/routingservice_processor.h"
#include "routingservice/routingservice_adapter_new.h"
#include <rti/routing/StreamInfo.hpp>
#include <rti/routing/adapter/StreamReader.hpp>
#include <rti/routing/processor/LoanedSamples.hpp>
#include <rti/routing/processor/Query.hpp>
namespace rti { namespace routing { namespace processor {
class Route;
template <typename Data, typename Info> class TypedInput;
template <typename Data, typename Info = dds::sub::SampleInfo>
class TypedInput;
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::Input
*
* @brief Generic Representation of a Route's input.
*
*
* This class provides a base representation of the inputs contained in a Route.
* Since it is generic, this object does not allow you to perform any operation
* that requires dealing with the data provided by the underlying
* rti::routing::adapter::StreamReader.
*/
class Input {
public:
/*i
*/
Input(RTI_RoutingServiceInput *native,
int32_t index,
RTI_RoutingServiceRoute *native_route)
: native_(native),
index_(index),
native_route_(native_route),
stream_info_("", ""),
name_(RTI_RoutingServiceInput_get_name(native))
{
const RTI_RoutingServiceStreamInfo *native_stream_info =
RTI_RoutingServiceInput_get_stream_info(native);
if (native_stream_info == nullptr) {
throw dds::core::InvalidArgumentError(
"invalid argument: invalid StreamInfo for input");
}
stream_info_ = *native_stream_info;
}
/*i
*
*/
const rti::routing::StreamInfo& stream_info() const
{
return stream_info_;
}
/*i
*
*/
const std::string& name() const
{
return name_;
}
/*i
*
*/
int32_t index()
{
return index_;
}
/**
* @brief Returns a typed version of this Input.
*
* Note: This operation is not type-safe. It is the caller's responsibility
* to use the appropriate type.
*
*
* @see TypedInput
* @see <tt>TypedInput<DataRep, Info> Route<DataRep, InfoRep>::input(int32_t index)</tt>
*/
template <typename Data, typename Info>
TypedInput<Data, Info> get()
{
return this;
}
/**
* @brief Returns a typed version of this Input.
*
* Note: This operation is not type-safe. It is the caller's responsibility
* to use the appropriate type.
*
* @see TypedInput
* @see TypedInput<tt><DataRep, dds::sub::SampleInfo></tt> Route<DataRep>::input(int32_t index)
*/
template <typename Data>
TypedInput<Data, dds::sub::SampleInfo> get()
{
return this;
}
/*i
*
*/
RTI_RoutingServiceInput* native()
{
return native_;
}
// Implementation details
private:
template <typename Data, typename Info> friend class TypedInput;
friend class Route;
friend class std::allocator<Input>;
RTI_RoutingServiceInput *native_;
int32_t index_;
RTI_RoutingServiceRoute *native_route_;
rti::routing::StreamInfo stream_info_;
std::string name_;
};
template <typename Data, typename Info = dds::sub::SampleInfo>
class Selector;
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::TypedInput
*
* @brief Representation of an Input whose data representation is \p DataRep,
* whose info representation is \p InfoRep.
*
*/
template <typename Data, typename Info>
class TypedInput{
public:
typedef rti::routing::processor::Selector<Data, Info> Selector;
TypedInput(Input *input);
/**
* @brief Returns the StreamInfo associated with this object.
*
* The associated StreamInfo represents an equivalent object to the one
* used to create the underlying rti::routing::adapter::StreamReader.
*/
const rti::routing::StreamInfo& stream_info() const;
/**
* @brief Returns the name of this output.
*
* The name is given by the name of the corresponding XML configuration tag.
*/
const std::string& name() const;
/**
* @brief Returns all the available samples in this object.
*
* This operation will call rti::routing::adapter::StreamReader::take on
* the underlying rti::routing::adapter::StreamReader.
*
* The returned samples are interpreted to contain data represented
* as \c Data and info represented as \c Info.
*
* @see LoanedSamples
* @see rti::routing::adapter::StreamReader::take
*/
LoanedSamples<Data, Info> take();
/**
* @brief Same as take() but this calls
* rti::routing::adapter::StreamReader::read instead.
*
* @see LoanedSamples
* @see rti::routing::adapter::StreamReader::read
* @see take
*/
LoanedSamples<Data, Info> read();
/**
* @brief Gets a Selector to perform complex data selections, such as
* per-instance selection, content and status filtering.
*
* The selector can be used as follows:
* \code{.c++}
* LoanedSamples<DynamicData> samples = input.select()
* .instance(handle)
* .content(query)
* .state(state)
* .take();
* \endcode
*
* This shows how samples can be taken by selecting a specific instance,
* then filtering by state and content.
*
* Note that when the application wants to access all available samples,
* it can simply call read() or take().
*
* @return A Selector, typically used in-line to configure it and finally
* call Selector::read() or Selector::take().
*
* @see Selector for the different parameters that can be set to
* configure which samples to read or take. Selecting what samples to
* read.
*/
Selector select();
rti::routing::processor::Query query(
const dds::topic::Filter& filter);
/**
* @brief Indicates whether this input has received new data since the last
* time any variant of the read operations was called.
*
* @note Given the time decoupling between the notification of new data and
* when it the data is read, it is possible this function may return
* true and yet there is no data to be returned.
*
* @return True if this input has new data received since the last read
* access.
*/
bool active();
/**
* @brief Creates a new data sample from this input.
*
* The data constructor called in this operation depends on the data
* representation kind of the TypeInfo associated with this input.
* If the type representation is a dynamic type, then it will assume
* the following constructor:
* \code Data(const dds::core::xtypes::DynamicType&) \endcode
*
* and will use the type code object downcasted from the value
* returned by TypeInfo::type_representation.
*
* Otherwise:
* \code Data() \endcode
*
* @return A new data sample
*/
Data create_data();
/*i
*
*/
TypedInput<Data, Info>* operator->()
{
return this;
}
/**
* @brief Returns the underlying DDS DataReader that is part of this
* StreamReader implementation, assuming this input holds a DDS StreamReader.
*
* This operation will throw an exception if this input does not hold a
* DDS StreamReader.
*
* @note The access to the underlying DataReader is allowed only as long as
* this Input remains enabled. The object representing the DataReader
* must be invalidated before the input is disabled, otherwise the behavior
* is undefined.
*
* @throw std::exception
*
* @return dds::sub::DataReader<Data>
*/
dds::sub::DataReader<Data> dds_data_reader()
{
using rti::core::detail::create_from_native_entity;
DDS_DataReader *native_reader =
RTI_RoutingServiceInput_get_dds_reader(input_->native_);
if (native_reader == NULL) {
throw dds::core::InvalidArgumentError(
"invalid argument: input does not hold a DDS StreamReader");
}
typedef dds::sub::DataReader<Data> data_reader_type;
return rti::core::detail::create_from_native_entity<data_reader_type>(
native_reader);
}
private:
TypedInput();
friend class rti::routing::processor::Selector<Data, Info>;
LoanedSamples<Data, Info> take(
const rti::routing::adapter::SelectorState& selector_state);
LoanedSamples<Data, Info> read(
const rti::routing::adapter::SelectorState& selector_state);
friend class rti::routing::processor::Route;
Input *input_;
};
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::Selector
*
* @brief An element that allows reading data that meet a set of specified
* attributes.
*
* The Selector class is used by the TypedInput to compose read and take
* operations.
*
* A Selector has an associated TypedInput and configures the behavior of the
* read or take operation performed by that TypedInput.
*
* For example, to perform a read of at most 5 unread samples:
* \code
* LoanedSamples<Foo> samples = reader.select()
* .read()
* .max_samples(5)
* .state(dds::sub::status::DataState::new_data());
* \endcode
*
* @note It's very important to consider that the behavior of this class is
* tightly coupled and dependent on the underlying
* rti::routing::adapter::StreamReader of the attached TypedInput. In
* particular, the samples returned by a Selector depend on the behavior
* of the rti::routing::adapter::StreamReader::take(SelectorState) and
* rti::routing::adapter::StreamReader::read(SelectorState). If the
* implementation of these operations behave according to the requirements,
* then the behavior offered by this class will be consistent.
*
* @see rti::routing::adapter::SelectorState
* @see dds::sub::DataReader::Selector for equivalent semantics and behavior
* with DataReaders
*/
template <typename Data, typename Info>
class Selector {
public:
/**
* @brief Create a Selector for a TypedInput.
*
* Selectors are created with the default filter state of the TypedInput.
*
* @param[in] input
* The TypedInput that this Selector is attached to.
*/
Selector(const rti::routing::processor::TypedInput<Data, Info> input)
: typed_input_(input), query_(dds::core::null)
{
}
/**
* @brief Copy constructor
*/
Selector(const Selector& other)
: typed_input_(other.typed_input_),
state_(other.state_),
query_(other.query_)
{
}
/**
* @brief Select a specific dds::sub::status::DataState.
*
* By setting the DataState, you can specify the state of the samples that
* should be read or taken. The DataState of a sample encapsulates the
* SampleState, ViewState, and InstanceState of a sample.
*
* @param[in] the_state
* The selected DataState
*
*/
Selector& state(
const dds::sub::status::DataState& the_state)
{
state_.state(the_state);
return *this;
}
/**
* @brief Choose to only read/take up to a maximum number of samples.
*
* @param[in] count
* The maximum number of samples to read/take.
*/
Selector& max_samples(
const int32_t count)
{
state_.max_samples(count);
return *this;
}
/**
* @brief Select a specific instance to read/take.
*
* This operation causes the subsequent read or take operation to access
* only samples belonging the single specified instance whose handle is
* \p the_handle.
*
* Upon successful completion, the data collection will contain samples all
* belonging to the same instance.
*
* The subsequent read/take may operation may fail if the InstanceHandle
* does not correspond to an existing data-object known to the TypedInput.
*
* @param[in] the_handle
* The handle of the instance to select
*
* @see rti::routing::adapter::SelectorState
* @see dds::sub::DataReader::Selector::instance
*/
Selector& instance(
const dds::core::InstanceHandle& the_handle)
{
state_.instance(the_handle);
return *this;
}
/**
* @brief Select the instance after a specific instance.
*
* This operation causes the subsequent read or take operation to
* access only samples belonging a single instance whose handle is
* considered 'next' after the provided InstanceHandle, \p the_handle.
*
* The accessed samples will all belong to the 'next' instance with
* InstanceHandle 'greater' than the specified previous handle that has
* available samples.
*
* The special value dds::core::InstanceHandle::nil() is guaranteed to be
* 'less than' any valid instance_handle. So the use of the parameter value
* previous_handle == dds::core::InstanceHandle::nil() will return the
* samples for the instance that has the smallest instance_handle among all
* the instances that contain available samples.
*
* Note that it is possible to call the
* dds::sub::next_instance(const dds::core::InstanceHandle& h) operation
* with a previous_handle that does not correspond to an instance currently
* managed by the underlying rti::routing::adapter::StreamReader.
*
* @param[in] the_handle
* The reference instance. The instance after this one will be
* selected.
*
* @see rti::routing::adapter::SelectorState
* @see dds::sub::DataReader::Selector::next_instance
*/
Selector& next_instance(
const dds::core::InstanceHandle& the_handle)
{
state_.next_instance(the_handle);
return *this;
}
/**
* @brief Select samples based on a content filter parameters.
*
* The effect of using this manipulator is that the subsequent read/take
* will filter the samples based on the dds::topic::Filter. If the
* Input has no samples that meet the constraints, the read/take will not
* return any data.
*
* This selection is applied in combination with the other settings of
* this Selector.
*
* @param[in] the_filter
*/
Selector& filter(
const dds::topic::Filter& the_filter)
{
state_.filter(the_filter);
return *this;
}
/**
* @brief Select samples based on a rti::routing::processor::Query.
*
* When passing a Query, the effect of calling this method is that the
* underlying rti::routing::adapter::StreamReader shall filter the samples
* based only on the Query's settings.
*
* Using this manipulator will always override the selection specified
* with Selector::filter, no matter the order in which operations are
* called. To reset this selection, you can call this operation passing
* dds::core::null.
*
* @param[in] the_query
* The Query to read/take with.
*/
Selector& query(const rti::routing::processor::Query& the_query)
{
query_ = the_query;
state_.content(the_query.delegate().get()->query_data_);
return *this;
}
/**
* @brief Take samples based on the state associated with this Selector.
*
* @note This operation will call rti::routing::adapter::StreamReader::take(SelectorState)
* on the underlying rti::routing::adapter::StreamReader.
*
* @throw std::exception
*
* @return rti::routing::processor::LoanedSamples
*/
LoanedSamples<Data, Info> take()
{
return typed_input_.take(state_);
}
/**
* @brief Read samples based on the state associated with this Selector.
*
* @note This operation will call rti::routing::adapter::StreamReader::read(SelectorState)
* on the underlying rti::routing::adapter::StreamReader.
*
* @throw std::exception
*
* @return rti::routing::processor::LoanedSamples
*/
LoanedSamples<Data, Info> read()
{
return typed_input_.read(state_);
}
private:
rti::routing::processor::TypedInput<Data, Info> typed_input_;
rti::routing::adapter::SelectorState state_;
rti::routing::processor::Query query_;
};
template <typename Data, typename Info>
struct create_data_from_input {
static Data get(TypedInput<Data, Info>& )
{
return Data();
}
};
template <typename Info>
struct create_data_from_input<dds::core::xtypes::DynamicData, Info> {
static dds::core::xtypes::DynamicData get(
TypedInput<dds::core::xtypes::DynamicData, Info>& input)
{
if (input->stream_info().type_info().type_representation_kind()
!= TypeRepresentationKind::DYNAMIC_TYPE) {
throw dds::core::PreconditionNotMetError(
"inconsistent data representation kind");
}
dds::core::xtypes::DynamicType *type_code =
static_cast<dds::core::xtypes::DynamicType *> (
input->stream_info().type_info().type_representation());
return dds::core::xtypes::DynamicData(*type_code);
}
};
template <typename Data, typename Info>
TypedInput<Data, Info>::TypedInput(Input *input)
: input_(input)
{
}
template <typename Data, typename Info>
const rti::routing::StreamInfo& TypedInput<Data, Info>::stream_info() const
{
return input_->stream_info_;
}
template <typename Data, typename Info>
const std::string& TypedInput<Data, Info>::name() const
{
return input_->name_;
}
template <typename Data, typename Info>
LoanedSamples<Data, Info> TypedInput<Data, Info>::take()
{
RTI_RoutingServiceLoanedSamples native_samples =
RTI_RoutingServiceLoanedSamples_INITIALIZER;
if (!RTI_RoutingServiceInput_take(
input_->native_,
&native_samples)) {
throw dds::core::Error("error taking samples from native input");
}
return LoanedSamples<Data, Info>(input_->native_, native_samples);
}
template <typename Data, typename Info>
LoanedSamples<Data, Info> TypedInput<Data, Info>::read()
{
RTI_RoutingServiceLoanedSamples native_samples =
RTI_RoutingServiceLoanedSamples_INITIALIZER;
if (!RTI_RoutingServiceInput_read(
input_->native_,
&native_samples)) {
throw dds::core::Error("error reading samples from native input");
}
return LoanedSamples<Data, Info>(input_->native_, native_samples);
}
template <typename Data, typename Info>
rti::routing::processor::Selector<Data, Info>
TypedInput<Data, Info>::select()
{
return rti::routing::processor::Selector<Data, Info>(*this);
}
template <typename Data, typename Info>
rti::routing::processor::Query TypedInput<Data, Info>::query(
const dds::topic::Filter& filter)
{
return rti::routing::processor::Query(input_->native_, filter);
}
template <typename Data, typename Info>
LoanedSamples<Data, Info> TypedInput<Data, Info>::take(
const rti::routing::adapter::SelectorState& selector_state)
{
RTI_RoutingServiceLoanedSamples native_samples =
RTI_RoutingServiceLoanedSamples_INITIALIZER;
if (!RTI_RoutingServiceInput_take_w_selector(
input_->native_,
&native_samples,
&selector_state.native())) {
throw dds::core::Error("error taking samples with selector from native input");
}
return LoanedSamples<Data, Info>(input_->native_, native_samples);
}
template <typename Data, typename Info>
LoanedSamples<Data, Info> TypedInput<Data, Info>::read(
const rti::routing::adapter::SelectorState& selector_state)
{
RTI_RoutingServiceLoanedSamples native_samples =
RTI_RoutingServiceLoanedSamples_INITIALIZER;
if (!RTI_RoutingServiceInput_read_w_selector(
input_->native_,
&native_samples,
&selector_state.native())) {
throw dds::core::Error("error reading samples with selector from native input");
}
return LoanedSamples<Data, Info>(input_->native_, native_samples);
}
template <typename Data, typename Info>
bool TypedInput<Data, Info>::active()
{
return RTI_RoutingServiceInput_is_active(input_->native_) ? true : false;
}
template <typename Data, typename Info>
Data TypedInput<Data,Info>::create_data()
{
return create_data_from_input<Data, Info>::get(*this);
}
/**
* @brief Convenient definition of a TypedInput whose data representation
* is DynamicData and info representation is dds::sub::SampleInfo.
*
* These data and info representations are expected be used by most of the
* rti::routing::adapter::StreamReader implementations.
*/
typedef TypedInput<dds::core::xtypes::DynamicData> DynamicDataInput;
typedef dds::sub::DataReader<dds::core::xtypes::DynamicData> DynamicDataReader;
} } }
#endif // RTI_ROUTING_PROCESSOR_INPUT_HPP_
@@ -0,0 +1,130 @@
/* $Id$
(c) Copyright, Real-Time Innovations, 2015-2016.
All rights reserved.
No duplications, whole or partial, manual or electronic, may be made
without express written permission. Any such copies, or
revisions thereof, must display this notice unaltered.
This code contains trade secrets of Real-Time Innovations, Inc.
============================================================================= */
#ifndef RTI_ROUTING_PROCESSOR_LOANED_SAMPLE_HPP_
#define RTI_ROUTING_PROCESSOR_LOANED_SAMPLE_HPP_
#include <exception>
namespace rti { namespace routing { namespace processor {
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::LoanedSample
*
* @brief
*/
template <typename T, typename U>
class LoanedSample
{
public:
/**
* @brief The data type
*/
typedef T DataType;
/**
* @brief The info type
*/
typedef U InfoType;
LoanedSample()
: _data_ptr(NULL),
_info_ptr(NULL)
{}
LoanedSample(const DataType * the_data, const InfoType * the_info)
: _data_ptr(the_data),
_info_ptr(the_info)
{}
LoanedSample(const void * the_data, const void * the_info)
: _data_ptr(static_cast<const T*>(the_data)),
_info_ptr(static_cast<const U*>(the_info))
{}
const DataType & data() const
{
if (_info_ptr != NULL && !info().valid()) {
throw dds::core::PreconditionNotMetError("Invalid data");
}
return *_data_ptr;
}
/**
* @brief Gets the sample info
*/
const InfoType & info() const {
if (_info_ptr == NULL) {
throw dds::core::PreconditionNotMetError(
"Sample Info not available");
}
return *_info_ptr;
}
operator const DataType & () const
{
return data();
}
LoanedSample<DataType, InfoType> * operator ->() {
return this;
}
const LoanedSample<DataType, InfoType> * operator ->() const {
return this;
}
/**
* @brief Compares the data and info
*/
bool operator==(const LoanedSample& other) const
{
if (info() != other.info()) {
return false;
}
if (info().valid()) {
if (data() != other.data()) {
return false;
}
}
return true;
}
bool operator!=(const LoanedSample& other) const
{
return !(*this == other);
}
void swap(LoanedSample & other) throw()
{
using std::swap;
swap(_data_ptr, other._data_ptr);
swap(_info_ptr, other._info_ptr);
}
private:
const DataType * _data_ptr;
const InfoType * _info_ptr;
};
} } }
#endif // RTI_ROUTING_PROCESSOR_LOANED_SAMPLE_HPP_
@@ -0,0 +1,306 @@
/* $Id$
(c) Copyright, Real-Time Innovations, 2013-2016.
All rights reserved.
No duplications, whole or partial, manual or electronic, may be made
without express written permission. Any such copies, or
revisions thereof, must display this notice unaltered.
This code contains trade secrets of Real-Time Innovations, Inc.
============================================================================= */
#ifndef RTI_ROUTING_PROCESSOR_LOANED_SAMPLES_HPP_
#define RTI_ROUTING_PROCESSOR_LOANED_SAMPLES_HPP_
#include <utility> // std::move
#include <iterator>
#include "routingservice/routingservice_adapter_new.h"
#include <dds/core/types.hpp>
#include <rti/routing/processor/LoanedSample.hpp>
#include <rti/routing/adapter/StreamReader.hpp>
#include <rti/routing/processor/SampleIterator.hpp>
namespace rti { namespace routing { namespace processor {
template <typename T, typename U> class TypedInput;
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::LoanedSamples
*
* @brief Provides temporary access to a collection of samples (data and info)
* from a TypedInput.
*
* @tparam T The sample data type representation. It has to match the type of
* the underlying rti::routing::adapter::StreamReader of the TypedInput.
*
* @tparam U The sample info type representation. It has to match the type of
* the underlying rti::routing::adapter::StreamReader of the TypedInput.
*
* This STL-like container encapsulates a collection of loaned, read-only data
* samples rti::sub::LoanedSample::data() and
* rti::sub::LoanedSample::info() from a TypedInput.
*
* To obtain a LoanedSamples, you need to call one of the read/take operations
* from a TypedInput. The samples have to be eventually returned to the
* TypedInput by calling rti::routing::adapter::StreamReader::return_loan on
* the underlying rti::routing::adapter::StreamReader of the TypedInput. The
* destructor takes care of that, and the return_loan() function lets you do
* it explicitly if needed.
*
* As a move-only type, copying a LoanedSamples is not allowed. If you need
* to return a LoanedSamples from a function or assign it to another variable,
* use \p dds::core::move() (or \p std::move() for C++11).
*
* Iterators and overloaded subscript operators let you access the samples
* in this container, which are of the type rti::routing::processor::LoanedSample.
*
* This code demonstrates how to access the info and data of each sample in
* a DataReader:
*
* \code
* auto samples = reader.take();
* for (const auto& sample : samples) {
* if (sample.info().valid()) {
* std::cout << sample.data() << std::endl;
* }
* }
* \endcode
*
* @see dds::sub::LoanedSamples
*
*/
template <typename T, typename U = dds::sub::SampleInfo>
class LoanedSamples {
public:
typedef rti::routing::adapter::StreamReader StreamReader;
typedef typename std::vector<StreamReader::SamplePtr> SampleSeqType;
typedef typename std::vector<StreamReader::InfoPtr> InfoSeqType;
/**
* @brief The iterator type
*/
typedef SampleIterator<T, U> iterator;
typedef SampleIterator<T, U> const_iterator;
typedef typename SampleIterator<T, U>::value_type value_type;
typedef std::ptrdiff_t difference_type;
/**
* @brief Creates an empty LoanedSamples object.
*/
LoanedSamples() : input_(NULL)
{
native_samples_.data_array = NULL;
native_samples_.info_array = NULL;
native_samples_.length = 0;
}
public:
// Private c-tor only to be used by static method create_from_loans()
LoanedSamples(
RTI_RoutingServiceInput *native_input,
RTI_RoutingServiceLoanedSamples& native_samples)
: input_(native_input),
native_samples_(native_samples)
{
}
public:
/**
* @brief Automatically returns the loan to the TypedInput used
* to obtained these samples.
*
* @see return_loan
*/
~LoanedSamples() throw()
{
try {
return_loan();
} catch (const std::exception&) { // Do not throw in destructor
}
}
/**
* @brief Provides access to the underlying LoanedSample object in
* array-like syntax.
*
* @param[in] index
* The index of the Sample. Allowed values are from 0 to length()-1.
*
* @return A LoanedSample object that refers to data and info
* at the specified \p index.
*/
LoanedSample<T,U> operator [] (size_t index)
{
return native_samples_.info_array == NULL
? LoanedSample<T, U>(native_samples_.data_array[index], NULL)
: LoanedSample<T, U>(
native_samples_.data_array[index],
native_samples_.info_array[index]);
}
/**
* @brief Gets the number of samples in this collection
*/
int32_t length() const
{
return native_samples_.length;
}
/**
* @brief Returns the samples to the TypedInput used to get these
* samples.
*
* Thes operation returns the samples by calling the
* \link rti::routing::adapter::StreamReader::return_loan return_loan\endlink
* operation on the underlying rti::routing::stream::StreamReader of the
* TypedInput.
*
* @note Explicitly calling return_loan is optional, since the
* destructor does it implicitly.
*
* This operation tells the TypedInput that the application
* is done accessing the collection of samples.
*
* It is not necessary for an application to return the loans immediately
* after the call to read or take. However, as these buffers correspond to
* internal resources, the application should not retain them indefinitely.
*
* @throw std::exception
* If there was an error returning the loan to the TypedInput.
*/
void return_loan()
{
if (input_) {
if (!RTI_RoutingServiceInput_return_loan(
input_,
&native_samples_)) {
throw dds::core::Error("error returning loaned samples to native input");
}
input_ = NULL; // Indicate that this object doesn't hold a loan anymore
}
}
/**
* @brief Returns whether the Info part is available for each Data item of
* this set of loaned samples.
*/
bool has_infos()
{
return (native_samples_.info_array != NULL);
}
/**
* @brief Gets an iterator to the first sample
*/
iterator begin()
{
return iterator(
native_samples_.data_array,
native_samples_.info_array,
native_samples_.length);
}
/**
* @brief Gets an iterator to one past the last sample
*/
iterator end()
{
return iterator(
native_samples_.data_array,
native_samples_.info_array,
native_samples_.length,
native_samples_.length);
}
/**
* @brief Gets an iterator to the first sample
*/
const_iterator begin() const
{
return const_iterator(
native_samples_.data_array,
native_samples_.info_array,
native_samples_.length);
}
/**
* @brief Gets an iterator to one past the last sample
*/
const_iterator end() const
{
return const_iterator(
native_samples_.data_array,
native_samples_.info_array,
native_samples_.length,
native_samples_.length);
}
/**
* @brief Swaps two LoanedSamples containers
*/
void swap(LoanedSamples& other) throw()
{
std::swap(input_, other.input_);
std::swap(native_samples_, other.native_samples_);
}
LoanedSamples(LoanedSamples&& other)
:input_(NULL)
{
native_samples_.data_array = NULL;
native_samples_.info_array = NULL;
native_samples_.length = 0;
other.swap(*this);
}
LoanedSamples& operator= (LoanedSamples&& other) throw ()
{
// clean up existing values
LoanedSamples temp(std::move(other));
temp.swap(*this);
return *this;
}
private:
friend class TypedInput<T, U>;
void release()
{
input_ = NULL;
}
RTI_RoutingServiceLoanedSamples& native_samples()
{
return native_samples_;
}
private:
// reference to the reader that created this LoanedSamples object
RTI_RoutingServiceInput *input_;
RTI_RoutingServiceLoanedSamples native_samples_;
};
template <typename T, typename U>
LoanedSamples<T, U> move(LoanedSamples<T,U> & ls) OMG_NOEXCEPT
{
return std::move(ls);
}
} } }
#endif // RTI_ROUTING_PROCESSOR_LOANED_SAMPLES_HPP_
@@ -0,0 +1,326 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_PROCESSOR_OUTPUT_HPP_
#define RTI_ROUTING_PROCESSOR_OUTPUT_HPP_
#include <dds/core/Value.hpp>
#include <dds/core/SafeEnumeration.hpp>
#include <rti/core/NativeValueType.hpp>
#include <dds/pub/DataWriter.hpp>
#include <dds/core/xtypes/DynamicData.hpp>
#include "routingservice/routingservice_processor.h"
#include "routingservice/routingservice_adapter_new.h"
#include <rti/routing/adapter/StreamWriter.hpp>
namespace rti { namespace routing { namespace processor {
class Route;
template <typename Data, typename Info> class TypedOutput;
template <typename Data, typename Info = dds::sub::SampleInfo>
class TypedOutput;
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::Output
*
* @brief Generic Representation of a Route's output.
*
* This class provides a base representation of the outputs contained in a Route.
* Since it is generic, this object does not allow performing any operation
* that requires dealing with the data passed to the underlying
* rti::routing::adapter::StreamWriter.
*/
class Output {
public:
/*i
*/
Output(
RTI_RoutingServiceOutput *native,
int32_t index,
RTI_RoutingServiceRoute *native_route) :
native_(native),
index_(index),
native_route_(native_route),
stream_info_(*RTI_RoutingServiceOutput_get_stream_info(native)),
name_(RTI_RoutingServiceOutput_get_name(native))
{
}
/*i
*/
const rti::routing::StreamInfo& stream_info() const
{
return stream_info_;
}
/*i
*
*/
const std::string& name() const
{
return name_;
}
/*i
*
*/
int32_t index()
{
return index_;
}
/**
* @brief Returns a typed version of this Output.
*
* Note: This operation is not type-safe and it is the caller's
* responsibility to use the appropriate type.
*
* @see TypedOutput
* @see <tt>TypedOutput<DataRep, Info> Route<DataRep, InfoRep>::output(int32_t index)</tt>
*/
template <typename Data, typename Info>
TypedOutput<Data, Info> get()
{
return this;
}
/**
* @brief Returns a typed version of this Output.
*
* Note: This operation is not type-safe and it is the caller's
* responsibility to use the appropriate type.
*
* @see TypedOutput
* @see TypedOutput<tt><DataRep, dds::sub::SampleInfo></tt> Route<DataRep>::output(int32_t index)
*/
template <typename Data>
TypedOutput<Data, dds::sub::SampleInfo> get()
{
return this;
}
private:
template <typename Data, typename Info> friend class TypedOutput;
friend class Route;
RTI_RoutingServiceOutput *native_;
int32_t index_;
RTI_RoutingServiceRoute *native_route_;
rti::routing::StreamInfo stream_info_;
std::string name_;
};
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::TypedOutput
*
* @brief Representation of an Output whose data representation is \p DataRep,
* whose info representation is \p InfoRep.
*
*/
template <typename Data, typename Info>
class TypedOutput{
public:
TypedOutput(Output *output) ;
TypedOutput<Data, Info>* operator->();
/**
* @brief Returns the StreamInfo associated with this object.
*
* The associated StreamInfo represents an equivalent object to the one
* used to create the underlying rti::routing::adapter::StreamWriter.
*/
const rti::routing::StreamInfo& stream_info() const;
/**
* @brief Returns the name of this output.
*
* The name is given by the name of the corresponding XML configuration tag.
*/
const std::string& name() const;
/**
* @brief Writes the specified data and info sample in this output.
*
* This operation will call rti::routing::adapter::StreamWriter::write on
* the underlying rti::routing::adapter::StreamWriter.
*
* The provided sample is interpreted to contain data represented
* as \c Data and the info as \c Info.
*
* @see rti::routing::adapter::StreamWriter::write
*/
void write(const Data& sample, const Info& info);
/*
* @brief Writes a sample given its data only.
*
* This operation will call rti::routing::adapter::StreamWriter::write
* on the underlying rti::routing::adapter::StreamWriter, providing a null
* value for the info sample. The underlying adapter will compute any
* associated metadata from the data sample.
*/
void write(const Data& sample);
/**
* @brief Creates a new data sample that can be used to write in this
* output.
*
* The data constructor called in this operation depends on the data
* representation kind of the TypeInfo associated with this output.
* If the type representation is a dynamic type, then it will assume
* the following constructor:
* \code Data(const dds::core::xtypes::DynamicType&) \endcode
*
* and will use the type code object downcasted from the value
* returned by TypeInfo::type_representation.
*
* Otherwise:
* \code Data() \endcode
*
* @return A new data sample
*/
Data create_data();
/**
* @brief Returns the underlying DDS DataWriter that is part of this
* StreamWriter implementation, assuming this input holds a DDS StreamWriter.
*
* This operation will throw an exception if this output does not hold a
* DDS StreamWriter.
*
* @note The access to the underlying DataWriter is allowed only as long as
* this Output remains enabled. The object representing the DataWriter
* must be invalidated before the output is disabled, otherwise the behavior
* is undefined.
*
* @throw std::exception
*
* @return dds::pub::DataWriter<Data>
*/
dds::pub::DataWriter<Data> dds_data_writer()
{
DDS_DataWriter *native_writer =
RTI_RoutingServiceOutput_get_dds_writer(output_->native_);
if (native_writer == NULL) {
throw dds::core::InvalidArgumentError(
"invalid argument: input does not hold a DDS StreamWriter");
}
typedef dds::pub::DataWriter<Data> data_writer_type;
return rti::core::detail::create_from_native_entity<data_writer_type>(
native_writer);
}
private:
friend class rti::routing::processor::Route;
Output *output_;
};
template <typename Data, typename Info>
struct create_data_from_output {
static Data get(TypedOutput<Data, Info>& )
{
return Data();
}
};
template <typename Info>
struct create_data_from_output<dds::core::xtypes::DynamicData, Info> {
static dds::core::xtypes::DynamicData get(TypedOutput<dds::core::xtypes::DynamicData, Info>& output)
{
if (output->stream_info().type_info().type_representation_kind()
!= TypeRepresentationKind::DYNAMIC_TYPE) {
throw dds::core::PreconditionNotMetError(
"inconsistent data representation kind");
}
dds::core::xtypes::DynamicType *type_code =
static_cast<dds::core::xtypes::DynamicType *> (
output->stream_info().type_info().type_representation());
return dds::core::xtypes::DynamicData(*type_code);
}
};
template <typename Data, typename Info>
TypedOutput<Data,Info>::TypedOutput(Output* output) : output_(output)
{
}
template <typename Data, typename Info>
const rti::routing::StreamInfo& TypedOutput<Data, Info>::stream_info() const
{
return output_->stream_info_;
}
template <typename Data, typename Info>
const std::string& TypedOutput<Data, Info>::name() const
{
return output_->name_;
}
template <typename Data, typename Info>
TypedOutput<Data, Info>* TypedOutput<Data,Info>::operator->()
{
return this;
}
template <typename Data, typename Info>
void TypedOutput<Data, Info>::write(const Data& sample, const Info& info)
{
if (!RTI_RoutingServiceOutput_write_sample(
output_->native_,
const_cast<void *> (reinterpret_cast<const void*> (&sample)),
const_cast<void *> (reinterpret_cast<const void*> (&info)))) {
throw dds::core::Error("error writing sample to native output");
}
}
template <typename Data, typename Info>
void TypedOutput<Data,Info>::write(const Data& sample)
{
if (!RTI_RoutingServiceOutput_write_sample(
output_->native_,
const_cast<void *> (reinterpret_cast<const void*> (&sample)),
NULL)) {
throw dds::core::Error("error writing sample to native output");
}
}
template <typename Data, typename Info>
Data TypedOutput<Data,Info>::create_data()
{
return create_data_from_output<Data, Info>::get(*this);
}
/**
* @brief Convenient definition of a TypedOutput whose data representation
* is DynamicData and info representation is dds::sub::SampleInfo.
*
* These data and info representations are expected be used by most
* rti::routing::adapter::StreamWriter implementations.
*/
typedef TypedOutput<dds::core::xtypes::DynamicData> DynamicDataOutput;
typedef dds::pub::DataWriter<dds::core::xtypes::DynamicData> DynamicDataWriter;
} } }
#endif // RTI_ROUTING_PROCESSOR_OUTPUT_HPP_
@@ -0,0 +1,202 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_PROCESSOR_PORTS_ITERATOR_HPP_
#define RTI_ROUTING_PROCESSOR_PORTS_ITERATOR_HPP_
#include <dds/core/Value.hpp>
#include <dds/core/SafeEnumeration.hpp>
#include <rti/core/NativeValueType.hpp>
#include <dds/core/xtypes/DynamicData.hpp>
#include <dds/sub/SampleInfo.hpp>
#include <rti/routing/processor/Input.hpp>
#include <rti/routing/processor/Output.hpp>
namespace rti { namespace routing { namespace processor {
template <typename PORT, typename DataRep, typename InfoRep> struct TypedPortType;
template <typename DataRep, typename InfoRep>
struct TypedPortType<Input, DataRep, InfoRep>
{
typedef TypedInput<DataRep, InfoRep> type;
typedef RTI_RoutingServiceInput native_type;
static native_type * begin(RTI_RoutingServiceRoute *native_route)
{
return RTI_RoutingServiceRoute_get_first_input(native_route);
}
static native_type * next(
RTI_RoutingServiceRoute *native_route,
native_type *native)
{
return RTI_RoutingServiceRoute_get_next_input(native_route, native);
}
static Input* from_native(native_type *native)
{
return static_cast<Input*>(RTI_RoutingServiceInput_get_user_data(
native));
}
};
template <typename DataRep, typename InfoRep>
struct TypedPortType<Output, DataRep, InfoRep>
{
typedef TypedOutput<DataRep, InfoRep> type;
typedef RTI_RoutingServiceOutput native_type;
static native_type * begin(RTI_RoutingServiceRoute *native_route)
{
return RTI_RoutingServiceRoute_get_first_output(native_route);
}
static native_type * next(
RTI_RoutingServiceRoute *native_route,
native_type *native)
{
return RTI_RoutingServiceRoute_get_next_output(native_route, native);
}
static Output* from_native(native_type *native)
{
return static_cast<Output*>(RTI_RoutingServiceOutput_get_user_data(
native));
}
};
template <typename PORT,
typename DataRep,
typename InfoRep = dds::sub::SampleInfo>
class PortIterator {
public:
// iterator traits
typedef std::random_access_iterator_tag iterator_category;
typedef typename TypedPortType<PORT, DataRep, InfoRep>::type value_type;
typedef value_type reference;
typedef value_type pointer;
typedef std::ptrdiff_t difference_type;
explicit PortIterator(
RTI_RoutingServiceRoute *native_route)
: native_route_(native_route)
{
native_ = TypedPortType<PORT, DataRep, InfoRep>::begin(native_route);
}
explicit PortIterator()
: native_route_(NULL), native_(NULL)
{
}
PortIterator (const PortIterator<PORT, DataRep, InfoRep>& other)
: native_route_(other.native_route_),
native_(other.native_)
{}
PortIterator & operator = (const PortIterator<PORT, DataRep, InfoRep>& other)
{
native_route_ = other.native_route_;
native_ = other.native_;
return *this;
}
value_type operator*()
{
return TypedPortType<PORT, DataRep, InfoRep>::from_native(native_);
}
value_type operator->()
{
return *(*this);
}
PortIterator & operator++()
{
native_ = TypedPortType<PORT, DataRep, InfoRep>::next(
native_route_,
native_);
return *this;
}
PortIterator operator++(int)
{
PortIterator temp(*this);
++(*this);
return temp;
}
friend bool operator<(
const PortIterator & s1,
const PortIterator & s2)
{
return s1.index() < s2.index();
}
friend bool operator>(
const PortIterator & s1,
const PortIterator & s2)
{
return s1.index() > s2.index();
}
friend bool operator<=(
const PortIterator & s1,
const PortIterator & s2)
{
return s1.index() <= s2.index();
}
friend bool operator>=(
const PortIterator & s1,
const PortIterator & s2)
{
return s1.index() >= s2.index();
}
friend bool operator==(
const PortIterator & s1,
const PortIterator & s2)
{
return (s1.index() == s2.index());
}
friend bool operator!=(
const PortIterator & s1,
const PortIterator & s2)
{
return !(s1 == s2);
}
private:
int32_t index() const
{
return (native_ == NULL)
? RTI_INT32_MAX
: TypedPortType<PORT, DataRep, InfoRep>::from_native(native_)->index();
}
RTI_RoutingServiceRoute *native_route_;
typename TypedPortType<PORT, DataRep, InfoRep>::native_type *native_;
};
} } }
#endif // RTI_ROUTING_PROCESSOR_PORTS_ITERATOR_HPP_
@@ -0,0 +1,397 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_PROCESSOR_PROCESSOR_HPP_
#define RTI_ROUTING_PROCESSOR_PROCESSOR_HPP_
#include <dds/core/Value.hpp>
#include <dds/core/SafeEnumeration.hpp>
#include <rti/core/NativeValueType.hpp>
#include "routingservice/routingservice_processor.h"
#include <rti/routing/processor/Route.hpp>
#include <rti/routing/UpdatableEntity.hpp>
namespace rti { namespace routing { namespace processor {
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::Processor
*
* @brief Processor interface definition. Provides a way to process Route events
* and control the data forwarding process.
*
* A Processor receives event notifications from its Route owner in the form of
* operation callbacks. Each event occurrence will be dispatched to the Processor
* by calling the corresponding method.
*
* Each dispatching method has a signature according to the event kind and data
* it is associated with. Each event is associated with a Route state; hence
* limitations and constraints may apply individually to each method.
*
* Note that throwing an exception while processing any of the
* event notifications is allowed. In this situation, the Route owner will
* reject the events and none of the associated post conditions will be applied,
* including state transitions.
*
* @mtsafety Partially Safe
* All operations on a concrete Processor object are safe and
* always serialized on a given Session. Operations on different
* Processor objects may be called concurrently if they belong
* to different Routes.
*
* @see ProcessorPlugin
* @see Route
*/
class Processor : public rti::routing::UpdatableEntity {
public:
/**
* @brief Notification of the \c INPUT_ENABLED event.
*
* This operation is called when an Input enabled event occurs that
* affects any of the inputs contained in the owner Route.
*
* This operation is called right after the affected Input has been enabled.
*
* A running Routing Service instance will produce a log indicating the occurrence
* of the event. For example:
*
* \code
* [.../sessions/Session/routes/Route/inputs/Input1|ENABLE] stream=Example
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
* @param[in] input
* The just enabled Input.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p input
* to be automatically disabled right after.
*/
virtual void on_input_enabled(
Route& route,
rti::routing::processor::Input& input) = 0;
/**
* @brief Notification of the Input disabled event.
*
* This operation is called when an \c INPUT_DISABLED event occurs that
* affects any of the inputs contained in the owner Route.
*
* This operation is called right before the affected Input is disabled.
*
* A running Routing Service instance will produce a log indicating the occurrence
* of the event. For example:
*
* \code
* [.../sessions/Session/routes/Route/inputs/Input1|DISABLE] stream=Example
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
* @param[in] input
* The Input about to be disabled.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p input
* to remain enabled.
*/
virtual void on_input_disabled(
Route& route,
rti::routing::processor::Input& input) = 0;
/**
* @brief Notification of the Output enabled event.
*
* This operation is called when an \c OUTPUT_DISABLED event occurs that
* affects any of the outputs contained in the owner Route.
*
* This operation is called right after the affected Output has been enabled.
*
* A running Routing Service instance will produce a log indicating the occurrence
* of the event. For example:
*
* \code
* [.../sessions/Session/routes/Route/outputs/Output1|ENABLE] stream=Example
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
* @param[in] output
* The just enabled output.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p output
* to be automatically disabled right after.
*/
virtual void on_output_enabled(
Route& route,
rti::routing::processor::Output& output) = 0;
/**
* @brief Notification of the Output disabled event.
*
* This operation is called when an \c OUTPUT_DISABLED event occurs that
* affects any of the outputs contained in the owner Route.
*
* This operation is called right before the affected Output is disabled.
*
* A running Routing Service instance will produce a log indicating the occurrence
* of the event. For example:
*
* \code
* [.../sessions/Session/routes/Route/outputs/Output1|DISABLE] stream=Example
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
* @param[in] output
* The Output about to be disabled.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p output
* to remain enabled.
*/
virtual void on_output_disabled(
Route& route,
rti::routing::processor::Output& output) = 0;
/**
* @brief Notification of the Route started event.
*
* This operation is called right before the Route enters the \c STARTED
* state. At the time this operation is called, all the inputs and outputs
* within the Route are enabled.
*
* A running Routing Service instance will produce a log indicating the
* occurrence of the event. For example:
* \code
* [.../domain_routes/DomainRoute/sessions/Session/routes/Route|START]
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p route
* to remain \c STOPPED.
*/
virtual void on_start(Route& route) = 0;
/**
* @brief Notification of the Route stopped event.
*
* This operation is called right before the Route enters the \c STOPPED
* state. At the time this operation is called, all the inputs and outputs
* within the Route are still enabled.
*
* A running Routing Service instance will produce a log indicating the
* occurrence of the event. For example:
* \code
* [.../domain_routes/DomainRoute/sessions/Session/routes/Route|STOP]
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p route
* to remain \c STARTED.
*
*/
virtual void on_stop(Route& route) = 0;
/**
* @brief Notification of the Route \c RUN event.
*
* This operation is called right before the Route enters the \c RUNNING
* state. This operation is called after the Route went to \c STARTED after
* a successful notification to this Processor,
*
* \note
* If the Route was manually paused before via an Administration call, this
* operation will not be called until a manual run operation is performed.
*
* A Routing Service running instance will produce a log indicating the occurrence
* of the event. For example:
* \code
* [.../domain_routes/DomainRoute/sessions/Session/routes/Route|RUN]
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p route
* to remain \c PAUSED.
*
*/
virtual void on_run(Route& route) = 0;
/**
* @brief Notification of the Route stopped event.
*
* This operation is called right before the Route enters the \c PAUSED
* state. At the time this operation is called, all the inputs and outputs
* within the Route are still enabled.
*
* A Routing Service running instance will produce a log indicating the occurrence
* of the event. For example:
* \code
* [.../domain_routes/DomainRoute/sessions/Session/routes/Route|PAUSE]
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
*
* @throw std::exception
* Throwing an error in this operation will cause the \p route
* to remain \c RUNNING.
*
*/
virtual void on_pause(Route& route) = 0;
/**
* @brief Notification of the Route periodic action event.
*
* This operation is called periodically at the rate specified in the parent
* Session of the Route owner.
*
* Periodic notifications can occur only while the Route is in the \c RUNNING
* state.
*
* Implementations are allowed to access any of the Input and Output of the
* owner Route to read and write data, respectively.
*
* A Routing Service running instance will produce a log indicating the occurrence
* of the event. For example:
* \code
* [.../domain_routes/DomainRoute/sessions/Session/routes/Route] process event=PERODIC_ACTION
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
*
* @throw std::exception
* Throwing an error in this operation will produce a log message
* without affecting the Route state and notifications of this event
* to this Processor will keep occurring.
*/
virtual void on_periodic_action(Route& route) = 0;
/**
* @brief Notification of the Route \c DATA_AVAILABLE event
*
* This operation is called each time any of the inputs contained in the
* owner Route is notified about new data. Notifications of this event can
* occur only while the Route is in the \c RUNNING state.
*
* Implementations are allowed to access any of the Input and Output of the
* owner Route to read and write data, respectively.
*
* A running Routing Service instance will produce a log indicating the
* occurrence of the event. For example:
* \code
* [.../domain_routes/DomainRoute/sessions/Session/routes/Route] process event=DATA_ON_INPUTS
* \endcode
*
*
* @param[in] route
* Route owner that contains this Processor.
*
* @throw std::exception
* Throwing an error in this operation will produce a log message
* without affecting the Route state and notifications of this event
* to this Processor will keep occurring.
*
*/
virtual void on_data_available(Route& route) = 0;
/**
* @brief Virtual destructor
*/
virtual ~Processor() {}
};
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::NoOpProcessor
*
* @brief An empty implementation of the pure virtual interface
* rti::routing::processor::Processor.
*
* Your Processor implementation can inherit from this class and override
* just the methods that are of interest.
*/
class NoOpProcessor : public Processor {
virtual void on_input_enabled(Route&, rti::routing::processor::Input&)
{
}
virtual void on_input_disabled(Route&, rti::routing::processor::Input&)
{
}
virtual void on_output_enabled(Route&, rti::routing::processor::Output&)
{
}
virtual void on_output_disabled(Route&, rti::routing::processor::Output&)
{
}
virtual void on_start(Route&)
{
}
virtual void on_stop(Route&)
{
}
virtual void on_run(Route&)
{
}
virtual void on_pause(Route&)
{
}
virtual void on_data_available(Route&)
{
}
virtual void on_periodic_action(Route&)
{
}
};
} } }
#endif // RTI_ROUTING_PROCESSOR_PROCESSOR_HPP_
@@ -0,0 +1,389 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_PROCESSOR_PROCESSOR_PLUGIN_HPP_
#define RTI_ROUTING_PROCESSOR_PROCESSOR_PLUGIN_HPP_
#include "routingservice/routingservice_log.h"
#include <rti/config/Version.hpp>
#include <rti/routing/PropertySet.hpp>
#include <rti/routing/processor/Route.hpp>
#include <rti/routing/processor/Processor.hpp>
/** @file
* @brief \product C++ Processor API
*/
/** @defgroup RTI_RoutingServiceProcessorModule RTI Routing Service Processor API
* @ingroup ROUTER
* @brief This module describes the Processor API.
*
* @product rti::routing::processor::Processor are **event-oriented pluggable
* components** that allow you to control the forwarding process that occur within a Route.
*
* ## Development Requirements
*
* | | Linux/macOS Systems | Windows Systems |
* | --------------: | :----------------: | :-------------: |
* | Shared Libraries| librtiroutingservice.so | librtiroutingservice.lib |
* | ^ | librtirsinfrastructure.so | rtirsinfrastructure.lib |
* | ^ | libnddscpp2.so | nddscpp2.lib |
* | ^ | libnddsc.so | nddsc.lib |
* | ^ | libnddscore.so | nddscore.lib |
* | Headers | rti/routing/processor/ProcessorPlugin.hpp ||
*
* ## Architecture
*
* A rti::routing::processor::Processor represents a multiple-input,
* multiple-output component attached to a rti::routing::processor::Route,
* which dispatches events to the rti::routing::processor::Processor.
* The figure below shows the role of a rti::routing::processor::Processor within
* @product.
*
* \htmlonly <div style="margin:auto;width:700px;">\endhtmlonly
* \image html RouterProcessorComponent.svg "Overview of a Processor component in @product" width=700px
* \htmlonly </div>\endhtmlonly
*
* A Processor can access the *N* inputs and *M* outputs of the owner Route.
* Upon event notification, the Processor can read data from any input,
* perform any manipulation on the data, and write it on any of the outputs.
*
* Note in the figure above that any data a Processor writes on an output is
* first transformed with an rti::routing::transf::Transformation before passing
* it to the underlying rti::routing::adapter::StreamWriter.
*
* An example snippet is shown below. The example code is reading data from
* two inputs, merging it together in an intermediate data buffer and writing
* into a single output.
*
* \code{.cpp}
* on_data_available(Route& route)
* {
* auto output = route.output<DynamicData>(0);
* auto output_sample = output.create_data();
* for(const auto& status : route.input<DynamicData>(0).take()) {
* auto periodic = route.input<DynamicData>(1)
* .select().instance(status.info().instance_handle()).read();
* output_sample.value<int>(
* "id",
* status.data().get<int>("id"));
* output_sample.value<int>(
* "config",
* status.data().get<string>("config"));
* output_sample.value<int>(
* "latency",
* periodic[0].data().get<int>("latency"));
* output.write(output_sample);
* }
* }
* \endcode
*
* The Processor API component model is shown in figure below.
*
* \htmlonly <div style="margin:auto;width:800px;">\endhtmlonly
* \image html RouterProcessorClass.svg "Processor API component model" width=800px
* \htmlonly </div>\endhtmlonly
*
* * rti::routing::processor::Processor
* * rti::routing::processor::Route
* * rti::routing::processor::Input
* * rti::routing::processor::Output
* * rti::routing::processor::Selector
*
* ## Event dispatching
*
* A rti::routing::processor::Route will notify its contained
* rti::routing::processor::Processor about the events that affect the Route
* object. Each event kind maps to a virtual operation in the
* rti::routing::processor::Processor interface:
*
* * **Input Enabled**: Event that represents the transition from disables to
* enabled on any of the contained rti::routing::processor::Input. Enabling
* an Input results in the creation of the underlying
* rti::routing::adapter::StreamReader.
* This event is notified through rti::routing::processor::Processor::on_input_enabled.
*
* * **Input Disabled**: Event that represents the transition from enabled to
* disabled on any of the contained rti::routing::processor::Input. Disabling
* an Input results in the deletion of the underlying
* rti::routing::adapter::StreamReader.
* This event is notified through rti::routing::processor::Processor::on_input_disabled.
*
* * **Output Enabled**: Event that represents the transition from disabled to
* enabled on any of the contained rti::routing::processor::Output. Enabling
* an Output results in the creation of the underlying
* rti::routing::transf::Transformation and rti::routing::adapter::StreamWriter.
* This event is notified through rti::routing::processor::Processor::on_output_enabled.
*
* * **Output Disabled**: Event that represents the transition from enabled to
* disabled on any of the contained rti::routing::processor::Output. Disabling
* an Output results in the deletion of the underlying
* rti::routing::transf::Transformation and rti::routing::adapter::StreamWriter.
* This event is notified through rti::routing::processor::Processor::on_output_disabled.
*
* * **Route Started**: This event indicates that the owner
* rti::routing::processor::Route has enabled all inputs and outputs.
* This event is notified through rti::routing::processor::Processor::on_start.
*
* * **Route Stopped**: This event indicates that the owner
* rti::routing::processor::Route is about to disable at least one of its
* inputs or outputs.
* This event is notified through rti::routing::processor::Processor::on_stop.
*
* * **Route Running**: This event indicates that the owner
* rti::routing::processor::Route is ready to provide user event
* notifications.
* This event is notified through rti::routing::processor::Processor::on_run.
*
* * **Route Paused**: This event indicates that the owner
* rti::routing::processor::Route will temporarily stop providing user
* event notifications.
* This event is notified through rti::routing::processor::Processor::on_pause.
*
* * **Data Available**: This user event indicates at least one of the inputs
* within the owner rti::routing::processor::Route has received new data.
* This event is notified through rti::routing::processor::Processor::on_data_available.
*
* * **Periodic Action**: This user event represents a periodic notification,
* at a rate configured in the parent Session of the owner
* rti::routing::processor::Route.
* This event is notified through rti::routing::processor::Processor::on_periodic_action.
*
*
* ## Threading
*
* A rti::routing::processor::Route dispatches all the events to its contained
* processors **sequentially**, from within one of the parent Session's threads.
* For any given Route, and hence a Processor, it is guaranteed that only
* one event is dispatched at at time. That is, the operations on the Processor
* are never called concurrently for a given Route.
*
* A parent Session with *L* threads can only process one Route at
* a time but it can dispatch different Routes concurrently. Namely, it can
* dispatch up to *L* Routes concurrently. You should keep this behavior in mind
* for implementations that share state between Processor objects.
*
* ## Constraints
*
* There are several constraints that affect the behavior and relationship
* of the Processor API components:
*
* * A Route can have one and only one Processor. Alternatively, *semantically* a
* Processor can belong to one and only one Route. That is, each Route will
* call rti::routing::processor::ProcessorPlugin::create_processor and
* rti::routing::processor::ProcessorPlugin::delete_processor on the
* corresponding plug-in instance, if the implementation is returning the
* same physical object.
*
* * An Input/Output can belong to one and only one Route. Thus, they cannot
* be shared across different Routes. Alternatively, operations on an
* Input, Output and Route can be performed only from within the associated
* Processor. It is forbidden to pass Input, Output and Route objects between
* Processors
*/
namespace rti { namespace routing { namespace processor {
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::ProcessorPlugin
* @brief The top-level plug-in class.
*
* Represents a factory of Processor.
*/
class ProcessorPlugin {
public:
/**
* @brief Creates a Route Processor.
*
* This function is called when the Route containing the Processor
* is enabled.
*
* A Routing Service running instance will product a log indicating the
* occurrence of this event. For example:
* \code
* [.../domain_routes/DomainRoute|START|/sessions/Session|START|/routes/Route|ENABLE]
* \endcode
*
*
* <b>Required:</b> yes
*
* @param route
* @rs_st_in An object representation of the Route that owns
* the Processor.
* @param properties
* @rs_st_in Configuration properties for the Processor.
* These properties corresponds to the properties specified within
* the tag &lt;processor&gt;.
*
* @return New Processor if successful. Cannot return @null_value.
* @throw std::exception
* @mtsafety Safe
*/
virtual Processor * create_processor(
Route& route,
const rti::routing::PropertySet& properties) = 0;
/**
* @brief Deletes a Route Processor.
*
* This function is called when the Route containing the Processor
* is disabled.
*
* <b>Required:</b> yes
*
* @param route
* @rs_st_in An object representation of the Route that owns
* the Processor.
* @param processor
* @rs_st_in Processor object to be deleted.
*
* @throw std::exception
* @mtsafety Safe
*/
virtual void delete_processor(
Route& route,
Processor *processor) = 0;
/**
* @return The version of this TransformationPlugin.
*
* The version is used for logging purposes. It allows you to track which
* version of the TransformationPlugin the @product is using.
*
* Default implementation of this operation returns the version of the
* required Connext libraries.
*/
virtual rti::config::LibraryVersion get_version() const
{
return rti::config::LibraryVersion();
}
/**
* @brief Virtual destructor
*/
virtual ~ProcessorPlugin() {}
};
} } }
#include <rti/routing/processor/detail/ProcessorPluginForwarder.hpp>
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @brief Utility macro that declares a native extern function that can
* be used to load a ProcessorPlugin through a shared library.
*
* The prototype of the function is given by a native definition of the
* create operation.
*
* To register a ProcessorPlugin with @product, you must use the tag
* &lt;processor_plugin&gt; within &lt;plugin_library&gt;. For example:
*
* \code
* <dds>
* ...
* <plugin_library name="MyPluginLib">
* <processor_plugin name="MyProcessorPlugin">
* <dll>myprocessor</dll>
* <create_function>
* MyProcessorPlugin_create
* </create_function>
* </processor_plugin>
* ...
* </plugin_library>
* ...
* <routing_service>
* ...
* </routing_service>
* ...
* </dds>
* \endcode
*
* Once a ProcessorPlugin is registered, a Route can use it to create a
* Processor.
*
* For example:
*
* \code
* <topic_route name="SquareAndCircleToTriangle">
* ...
* <processor plugin_name="MyPluginLib::MyProcessorPlugin">
* <property>
* <value>
* <element>
* <name>my_property_name</name>
* <value>my_property_value</value>
* </element>
* </value>
* </property>
* </processor>
* <input participant="DomainIn">
* <topic_name>Square</topic_name>
* <registered_type_name>ShapeType</registered_type_name>
* </input>
* <input participant="DomainIn">
* <topic_name>Circle</topic_name>
* <registered_type_name>ShapeType</registered_type_name>
* </input>
* <output participant="DomainOut">
* <topic_name>Triangle</topic_name>
* <registered_type_name>ShapeType</registered_type_name>
* </output>
* </topic_route>
* \endcode
*
* For additional information on configuring Processors, see the
* \ref_url_routing_service_users_manual.
*
* @param PROCESSOR_CLASS
* Class name of a ProcessorPlugin implementation
*/
#define RTI_PROCESSOR_PLUGIN_CREATE_FUNCTION_DECL(PROCESSOR_CLASS) \
extern "C" RTI_USER_DLL_EXPORT struct RTI_RoutingServiceProcessorPlugin* \
PROCESSOR_CLASS ## _create_processor_plugin(\
const struct RTI_RoutingServiceProperties *, \
RTI_RoutingServiceEnvironment *); \
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @brief Utility macro that implements the ProcessorPlugin entry point
* declared with RTI_PROCESSOR_PLUGIN_CREATE_FUNCTION_DECL.
*/
#define RTI_PROCESSOR_PLUGIN_CREATE_FUNCTION_DEF(PROCESSOR_CLASS) \
struct RTI_RoutingServiceProcessorPlugin * PROCESSOR_CLASS ## _create_processor_plugin( \
const struct RTI_RoutingServiceProperties * native_properties, \
RTI_RoutingServiceEnvironment *environment) \
{ \
PropertySet properties; \
rti::routing::PropertyAdapter::add_properties_from_native(\
properties,\
native_properties); \
try { \
return rti::routing::processor::detail::ProcessorPluginForwarder::create_plugin(\
new PROCESSOR_CLASS(properties)); \
} catch (const std::exception& ex) {\
RTI_RoutingServiceEnvironment_set_error(\
environment,\
"%s",\
ex.what());\
} catch (...) {}\
\
return NULL; \
}
#endif // RTI_ROUTING_PROCESSOR_PROCESSOR_PLUGIN_HPP_
@@ -0,0 +1,138 @@
/* $Id$
(c) Copyright, Real-Time Innovations, 2015-2016.
All rights reserved.
No duplications, whole or partial, manual or electronic, may be made
without express written permission. Any such copies, or
revisions thereof, must display this notice unaltered.
This code contains trade secrets of Real-Time Innovations, Inc.
============================================================================= */
#ifndef RTI_ROUTING_PROCESSOR_QUERY_HPP_
#define RTI_ROUTING_PROCESSOR_QUERY_HPP_
#include "routingservice/routingservice_processor.h"
#include <dds/core/Reference.hpp>
#include <rti/core/detail/SelfReference.hpp>
namespace rti { namespace routing { namespace processor {
class Input;
class QueryHolder : public rti::core::detail::RetainableType<QueryHolder>{
public:
QueryHolder() : input_(NULL), query_data_(NULL)
{
}
QueryHolder(RTI_RoutingServiceInput *input, const dds::topic::Filter& the_filter)
: input_(input),
query_data_(NULL)
{
filter(the_filter);
}
~QueryHolder()
{
if (query_data_ != NULL) {
/*
* Ignore the error. We can't throw in the destructor and this
* layer does not log anything
*/
(void) RTI_RoutingServiceInput_delete_content_query(
input_,
query_data_);
}
}
void filter(const dds::topic::Filter& filter)
{
RTI_RoutingServiceSelectorContent content =
RTI_RoutingServiceSelectorContent_INITIALIZER;
content.expression = (char *) filter.expression().c_str();
rti::core::native_conversions::to_native(
content.expression_parameters,
filter->parameters());
query_data_ = RTI_RoutingServiceInput_create_content_query(
input_,
query_data_,
&content);
DDS_StringSeq_finalize(&content.expression_parameters);
if (query_data_ == NULL) {
throw dds::core::Error("error creating content query from native input");
}
}
RTI_RoutingServiceInput *input_;
void* query_data_;
};
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::Query
*
* @brief Encapsulates a content query to select data from a
* rti::routing::adapter::StreamReader.
*
* Note that syntax for the query filter is StreamReader implementation
* dependent. For the DDS Adapter case, the syntax corresponds to that
* of the SQL filter.
*
* A Query object holds a custom query obtained by calling
* rti::routing::adapter::StreamReader::create_content_query. Likewise,
* the deletion of a Query object will call
* rti::routing::adapter::StreamReader::delete_content_query.
*/
class Query : public dds::core::Reference<rti::routing::processor::QueryHolder> {
public:
typedef dds::core::Reference<QueryHolder> Base;
OMG_DDS_REF_TYPE_NOTYPENAME(
Query,
dds::core::Reference,
rti::routing::processor::QueryHolder);
explicit Query(Base::DELEGATE_REF_T reference) : Base(reference)
{
if (this->delegate()) {
this->delegate()->remember_reference(this->delegate());
}
}
/**
* @brief Creates a Query described by a filter on an input.
*
* @param[in] input The native Input to query the data from.
* @param[in] filter Description of the content query based on an expression
* and parameters.
*
* @see dds::topic::Filter
*/
Query(RTI_RoutingServiceInput *input, const dds::topic::Filter& filter)
: Base(new QueryHolder(input, filter))
{
this->delegate()->remember_reference(this->delegate());
}
/**
* @brief Updates the current Query content filter.
*
* This operation will call
* rti::routing::adapter::StreamReader::create_content_query providing
* the current query content data this Query holds.
*/
void filter(const dds::topic::Filter& filter)
{
this->delegate()->filter(filter);
}
};
} } }
#endif // RTI_ROUTING_PROCESSOR_QUERY_HPP_
@@ -0,0 +1,555 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_PROCESSOR_ROUTE_HPP_
#define RTI_ROUTING_PROCESSOR_ROUTE_HPP_
#include <dds/core/Value.hpp>
#include <dds/core/SafeEnumeration.hpp>
#include <rti/core/NativeValueType.hpp>
#include "routingservice/routingservice_processor.h"
#include "routingservice/routingservice_processor_impl.h"
#include <dds/core/xtypes/DynamicData.hpp>
#include <dds/sub/SampleInfo.hpp>
#include <rti/routing/adapter/AdapterPlugin.hpp>
#include <rti/routing/processor/Input.hpp>
#include <rti/routing/processor/Output.hpp>
#include <rti/routing/processor/LoanedSamples.hpp>
#include <rti/routing/processor/PortIterator.hpp>
namespace rti { namespace routing { namespace processor {
namespace detail {
class ProcessorForwarder;
}
class Route;
template <typename PORT> struct port_list;
template <> struct port_list<Input>
{
static std::vector<Input>& get(Route& route);
};
template <> struct port_list<Output>
{
static std::vector<Output>& get(Route& route);
};
/** @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::Route
*
* @brief Representation of the Route object that owns a Processor.
*
* This class provides an interface to access the capabilities of a Route, such
* as retrieving any of its inputs and outputs. Usage of this class
* is restricted within the Processor context where the object is passed.
*
* An example of how to use this object is shown below. This example illustrates
* a simple use case of reading from all inputs and writing to all outputs,
* assuming that the sample data and info have the same representation and
* type.
*
* \code{.c++}
* using dds::core::xtypes::DynamicData;
* using dds::sub::SampleInfo;
* using namespace rti::routing::processor;
*
* ...
*
* for (auto input : route.inputs<DynamicData>()) {
* LoanedSamples<DynamicData> samples = input->read();
*
* for (auto output : route.outputs<DynamicData>()) {
* for(auto sample = samples) {
* output.write(sample.data(), sample.info());
* }
* }
* }
* \endcode
*/
class Route {
public:
template <typename DataRep, typename InfoRep = dds::sub::SampleInfo>
struct Inputs {
typedef PortIterator<Input, DataRep, InfoRep> iterator;
Inputs(RTI_RoutingServiceRoute *native_route)
: native_route_(native_route)
{
}
iterator begin()
{
return iterator(native_route_);
}
iterator end()
{
return iterator();
}
private:
RTI_RoutingServiceRoute *native_route_;
};
template <typename DataRep, typename InfoRep = dds::sub::SampleInfo>
struct Outputs {
typedef PortIterator<Output, DataRep, InfoRep> iterator;
Outputs(RTI_RoutingServiceRoute *native_route)
: native_route_(native_route)
{
}
iterator begin()
{
return iterator(native_route_);
}
iterator end()
{
return iterator();
}
private:
RTI_RoutingServiceRoute *native_route_;
};
/**
* @brief Returns the total number of inputs in this Route.
*
*/
int32_t input_count() const
{
return RTI_RoutingServiceRoute_get_input_count(native_route_);
}
/**
* @brief Returns the total number of outputs in this Route.
*
*/
int32_t output_count() const
{
return RTI_RoutingServiceRoute_get_output_count(native_route_);
}
/**
*@brief Checks whether the Input at the specified index is enabled
*
*/
bool input_enabled(int32_t index) const
{
return RTI_RoutingServiceRoute_is_input_enabled(native_route_, index)
? true
: false;
}
/**
*@brief Checks whether the Input at the specified index is enabled
*
*/
bool output_enabled(int32_t index) const
{
return RTI_RoutingServiceRoute_is_output_enabled(native_route_, index)
? true
: false;
}
/**
* @brief Returns the Input object at the specified index.
*
* Input indexes are assigned in increasing creation order, starting at 0.
* The creation order is the same order than the inputs are defined within
* the Route configuration.
*
* The returned object can be used to construct the appropriate TypedInput,
* which can be used for reading data.
*
* @param[in] index
* The index of the Input to be retrieved.
*
* @return The Input at the specified index.
*
* @see TypedInput
*
*/
Input& input(int32_t index)
{
return *(get_input_at_index(index));
}
/**
* @brief Returns the Input object with the specified name or throws an
* exception if the input with the given name is not found or if it is
* found but is not enabled.
*
* \b NOTE: The condition that the input must be enabled will be removed
* in a future version. This is being tracked with issue ID ROUTING-1131.
*
* @param[in] name The input configuration name
*
* @see TypedInput::name
* @throw std::logic_error
*/
Input& input(const std::string& name)
{
return *(lookup_input(name));
}
/**
* @brief Returns the TypedInput object at the specified index.
*
* The returned object is typed so it can read samples whose type is
* \p DataRep for data, and \p InfoRep for info. These types must
* match the expected type representations of the underlying
* rti::routing::adapter::StreamReader.
*
* Typically, these template arguments are typed
* dds::core::xtypes::DynamicData and dds::sub::SampleInfo, respectively.
*
* @warning This operation performs no type integrity check. It is
* responsibility of the caller to ensure the provided template
* arguments match with the expected types of the input. Otherwise
* behavior accessing the input is undefined.
*
* @return The TypedInput object at the specified index.
*
* @see input(int32_t)
* @see TypedInput
*/
template <typename DataRep, typename InfoRep>
TypedInput<DataRep, InfoRep> input(int32_t index)
{
return &input(index);
}
/**
* @brief Same as <tt>input<DataRep, InfoRep>(int32_t)</tt> with
* InfoRep = dds::sub::SampleInfo.
*
*/
template <typename DataRep>
TypedInput<DataRep> input(int32_t index)
{
return input<DataRep, dds::sub::SampleInfo>(index);
}
/**
* @brief Same as <tt>input<DataRep, InfoRep>(int32_t)</tt> but using
* the configuration name of the input.
*
*/
template <typename DataRep, typename InfoRep>
TypedInput<DataRep, InfoRep> input(const std::string& name)
{
return &input(name);
}
/**
* @brief Same as <tt>input<DataRep, InfoRep>(std::string&)</tt> with
* InfoRep = dds::sub::SampleInfo.
*/
template <typename DataRep>
TypedInput<DataRep> input(const std::string& name)
{
return input<DataRep, dds::sub::SampleInfo>(name);
}
/**
* @brief Returns the Output object at the specified index.
*
* Output indexes are assigned in increasing creation order, starting at 0.
* The creation order is the same order than the outputs are defined within
* the Route configuration.
*
* The returned object can be used to construct the appropriate TypedOutput,
* which can be used for writing data.
*
* @param[in] index
* The index of the Output to be retrieved.
*
* @return The Output at the specified index.
*
* @see TypedOutput
*
*/
Output& output(int32_t index)
{
return *(get_output_at_index(index));
}
/**
* @brief Returns the Output object with the specified name or throws an
* exception if the output with the given name is not found or if it is
* found but is not enabled.
*
* \b NOTE: The condition that the input must be enabled will be removed
* in a future version. This is being tracked with issue ID ROUTING-1131.
*
* @param[in] name The output configuration name
*
* @see TypedOutput::name
* @throw std::logic_error
*/
Output& output(const std::string& name)
{
return *(lookup_output(name));
}
/**
* @brief Returns the TypedOutput object at the specified index.
*
* The returned object is typed so it can write samples whose type is
* \p DataRep for data, and \p InfoRep for info. These types must
* match the expected type representations of the underlying
* rti::routing::adapter::StreamWriter.
*
* Typically, these template arguments are typed
* dds::core::xtypes::DynamicData and dds::sub::SampleInfo, respectively.
*
* @warning This operation performs no type integrity check. It is
* responsibility of the caller to ensure the provided template
* arguments match with the expected types of the output. Otherwise
* behavior accessing the output is undefined.
*
* @return The TypedOutput object at the specified index.
*
* @see input(int32_t)
*/
template <typename DataRep, typename InfoRep>
TypedOutput<DataRep, InfoRep> output(int32_t index)
{
return &output(index);
}
/**
* @brief Same as <tt>output<DataRep, InfoRep>(int32_t)</tt> with
* InfoRep = dds::sub::SampleInfo.
*
*/
template <typename DataRep>
TypedOutput<DataRep> output(int32_t index)
{
return output<DataRep, dds::sub::SampleInfo>(index);
}
/**
* @brief Same as <tt>output<DataRep, InfoRep>(int32_t)</tt> but using
* the configuration name of the output.
*
*/
template <typename DataRep, typename InfoRep>
TypedOutput<DataRep, InfoRep> output(const std::string& name)
{
return &output(name);
}
/**
* @brief Same as <tt>output<DataRep, InfoRep>(std::string&)</tt> with
* InfoRep = dds::sub::SampleInfo.
*/
template <typename DataRep>
TypedOutput<DataRep> output(const std::string& name)
{
return output<DataRep, dds::sub::SampleInfo>(name);
}
/**
* @brief Returns an accessor for the contained inputs.
*
* The returned object that allows iterating over the
* contained inputs, treating them as <tt>TypedInput<DataRep, InfoRep></tt>.
*
* @see <tt>Inputs<DataRep, InfoRep></tt>
* @see <tt>TypedInput<DataRep, InfoRep> input(int32_t index)</tt>
*/
template <typename DataRep, typename InfoRep>
Inputs<DataRep, InfoRep> inputs()
{
return Inputs<DataRep, InfoRep>(native_route_);
}
/**
* @brief Same as <tt>Inputs<DataRep, InfoRep> inputs()</tt> with
* InfoRep = dds::sub::SampleInfo.
*/
template <typename DataRep>
Inputs<DataRep> inputs()
{
return inputs<DataRep, dds::sub::SampleInfo>();
}
/**
* @brief Returns an accessor for the contained outputs.
*
* The returned object that allows iterating over the
* contained outputs, treating them as <tt>TypedOutput<DataRep, InfoRep></tt>.
*
* @see <tt>Outputs<DataRep, InfoRep></tt>
* @see <tt>TypedOutput<DataRep, InfoRep> input(int32_t index)</tt>
*/
template <typename DataRep, typename InfoRep>
Outputs<DataRep, InfoRep> outputs()
{
return Outputs<DataRep, InfoRep>(native_route_);
}
/**
* @brief Same as <tt>Inputs<DataRep, InfoRep> outputs()</tt> with
* InfoRep = dds::sub::SampleInfo.
*/
template <typename DataRep>
Outputs<DataRep> outputs()
{
return outputs<DataRep, dds::sub::SampleInfo>();
}
/**
*
* @brief Changes the event period of this Route.
*
* This operation can be called many times within the same periodic event,
* in which only the last call will have effect.
*
* The operation will enable the periodic event in this route if this
* operation is called for the first time in a route with no period set
* in the configuration.
*
* @param[in] period New session period
*/
void period(const dds::core::Duration& period)
{
struct DDS_Duration_t native_period = DDS_DURATION_ZERO;
rti::core::native_conversions::to_native(native_period, period);
RTI_RoutingServiceRoute_set_period(
native_route_,
&native_period);
}
dds::core::Duration period() const
{
struct DDS_Duration_t native_period = DDS_DURATION_ZERO;
RTI_RoutingServiceRoute_get_period(
native_route_,
&native_period);
return rti::core::native_conversions::from_native(native_period);
}
/**
*
* @brief Returns the fully qualified of this Route, derived from the configuration.
*
*/
const std::string& full_name() const
{
return full_name_;
}
private:
friend class detail::ProcessorForwarder;
friend class Output;
friend struct port_list<Input>;
friend struct port_list<Output>;
typedef std::vector<Input>::iterator private_input_it;
typedef std::vector<Output>::iterator private_output_it;
Route& operator= (const Route& other);
Route(RTI_RoutingServiceRoute *native_route,
RTI_RoutingServiceEnvironment *native_env)
: native_route_(native_route),
native_env_(native_env)
{
const char *native_full_name =
RTI_RoutingServiceRoute_get_full_name(native_route);
if (native_full_name == nullptr) {
throw dds::core::InvalidArgumentError(
"Native Route has invalid full name");
}
full_name_ = native_full_name;
}
Input* get_input_at_index(int32_t index)
{
RTI_RoutingServiceInput *native_input =
RTI_RoutingServiceRoute_get_input_at(native_route_, index);
if (native_input == NULL) {
throw dds::core::InvalidArgumentError(
RTI_RoutingServiceEnvironment_get_error_message(native_env_));
}
return static_cast<Input*>(RTI_RoutingServiceInput_get_user_data(native_input));
}
Output* get_output_at_index(int32_t index)
{
RTI_RoutingServiceOutput *native_output =
RTI_RoutingServiceRoute_get_output_at(native_route_, index);
if (native_output == NULL) {
throw dds::core::InvalidArgumentError(
RTI_RoutingServiceEnvironment_get_error_message(native_env_));
}
return static_cast<Output*>(RTI_RoutingServiceOutput_get_user_data(native_output));
}
Input* lookup_input(const std::string& name)
{
RTI_RoutingServiceInput *native_input =
RTI_RoutingServiceRoute_lookup_input_by_name(
native_route_,
name.c_str());
if (native_input == NULL) {
throw dds::core::InvalidArgumentError(
RTI_RoutingServiceEnvironment_get_error_message(native_env_));
}
return static_cast<Input*>(RTI_RoutingServiceInput_get_user_data(native_input));
}
Output* lookup_output(const std::string& name)
{
RTI_RoutingServiceOutput *native_output =
RTI_RoutingServiceRoute_lookup_output_by_name(
native_route_,
name.c_str());
if (native_output == NULL) {
throw dds::core::InvalidArgumentError(
RTI_RoutingServiceEnvironment_get_error_message(native_env_));
}
return static_cast<Output*>(RTI_RoutingServiceOutput_get_user_data(native_output));
}
private:
RTI_RoutingServiceRoute *native_route_;
RTI_RoutingServiceEnvironment *native_env_;
std::string full_name_;
};
} } }
#endif // RTI_ROUTING_PROCESSOR_ROUTE_HPP_
@@ -0,0 +1,275 @@
/* $Id$
(c) Copyright, Real-Time Innovations, 2014-2016.
All rights reserved.
No duplications, whole or partial, manual or electronic, may be made
without express written permission. Any such copies, or
revisions thereof, must display this notice unaltered.
This code contains trade secrets of Real-Time Innovations, Inc.
modification history
--------------------
1.0a,05may14,acr Added ValidSampleIterator and valid_samples helper
1.0a,20mar13,acr Created
============================================================================= */
#ifndef RTI_ROUTING_PROCESSOR_SAMPLE_ITERATOR_HPP_
#define RTI_ROUTING_PROCESSOR_SAMPLE_ITERATOR_HPP_
#include <rti/routing/processor/LoanedSample.hpp>
#include <exception>
namespace rti {
namespace routing {
namespace processor {
/*i
* @brief Tag type to emulate/indicate that sample infos are not available
*/
struct no_sample_info_t {
};
/**
* @ingroup RTI_RoutingServiceProcessorModule
*
* @class rti::routing::processor::SampleIterator
* @brief A random-access iterator of LoanedSample
*
* @see rti::routing::processor::LoanedSamples
*/
template <typename T, typename U>
class SampleIterator {
public:
// iterator traits
using iterator_category = std::random_access_iterator_tag;
using value_type = const LoanedSample<T, U>;
using reference = value_type;
using pointer = value_type;
using difference_type = std::size_t;
using SampleSeqType = RTI_RoutingServiceSample*;
using InfoSeqType = RTI_RoutingServiceSampleInfo*;
private:
static no_sample_info_t *_null_info_scrachtpad[1];
static InfoSeqType _null_info_seq;
static difference_type _null_info_pos;
public:
SampleIterator()
: _sample_seq(0),
_info_seq(0),
_length(0),
_pos(0),
_info_pos(_pos)
{
}
SampleIterator(
const SampleSeqType sample_seq,
const InfoSeqType info_seq,
int length,
int position = 0)
: _sample_seq(sample_seq),
_info_seq(info_seq == NULL ? _null_info_seq : info_seq),
_length(length),
_info_pos(info_seq == NULL ? _null_info_pos : _pos)
{
if (position < 0) {
throw dds::core::IllegalOperationError("SampleIterator out of range");
}
_pos = static_cast<difference_type>(position);
}
SampleIterator(const SampleIterator<T, U> & other)
: _sample_seq(other._sample_seq),
_info_seq(other._info_seq),
_length(other._length),
_pos(other._pos),
_info_pos(other._info_pos)
{
}
SampleIterator & operator=(const SampleIterator<T, U> & other)
{
_sample_seq = other._sample_seq;
_info_seq = other._info_seq;
_length = other._length;
_pos = other._pos;
_info_pos = other._info_pos;
return *this;
}
value_type operator*() const
{
return value_type(_sample_seq[_pos], _info_seq[_info_pos]);
}
value_type operator->() const
{
return value_type(_sample_seq[_pos], _info_seq[_info_pos]);
}
value_type operator[](difference_type offset) const
{
return (_info_seq == _null_info_seq)
? value_type(_sample_seq[_pos], NULL)
: value_type(_sample_seq[_pos + offset], _info_seq[_info_pos + offset]);
}
/*
* Windows defines min and max in one of the Windows headers, and they
* collide with the max() definition we use below
*/
#ifdef RTI_WIN32
#undef max
#undef min
#endif
SampleIterator & operator++()
{
if (_pos == std::numeric_limits<difference_type>::max()) {
throw dds::core::IllegalOperationError("SampleIterator out of range");
}
++_pos;
return *this;
}
SampleIterator operator++(int)
{
SampleIterator temp(*this);
++(*this);
return temp;
}
SampleIterator & operator--()
{
if (_pos == std::numeric_limits<difference_type>::min()) {
throw dds::core::IllegalOperationError("SampleIterator out of range");
}
--_pos;
return *this;
}
SampleIterator operator--(int)
{
SampleIterator temp(*this);
--(*this);
return temp;
}
SampleIterator & operator-=(difference_type i)
{
if (i > _pos) {
throw dds::core::IllegalOperationError("SampleIterator out of range");
}
_pos -= i;
return *this;
}
SampleIterator & operator+=(difference_type i)
{
if ((std::numeric_limits<difference_type>::max() - _pos) < i) {
throw dds::core::IllegalOperationError("SampleIterator out of range");
}
_pos += i;
return *this;
}
friend SampleIterator operator-(
const SampleIterator& si,
difference_type i)
{
SampleIterator temp(si);
temp -= i;
return temp;
}
friend SampleIterator operator+(
const SampleIterator& si,
difference_type i)
{
SampleIterator temp(si);
temp += i;
return temp;
}
friend difference_type operator-(
const SampleIterator& s1,
const SampleIterator& s2)
{
return s1._pos - s2._pos;
}
friend bool operator<(const SampleIterator & s1,
const SampleIterator & s2)
{
return s1._pos < s2._pos;
}
friend bool operator>(const SampleIterator & s1,
const SampleIterator & s2)
{
return s1._pos > s2._pos;
}
friend bool operator<=(const SampleIterator & s1,
const SampleIterator & s2)
{
return s1._pos <= s2._pos;
}
friend bool operator>=(const SampleIterator & s1,
const SampleIterator & s2)
{
return s1._pos >= s2._pos;
}
friend bool operator==(const SampleIterator & s1,
const SampleIterator & s2)
{
return (s1._sample_seq == s2._sample_seq) && (s1._pos == s2._pos);
}
friend bool operator!=(const SampleIterator & s1,
const SampleIterator & s2)
{
return !(s1 == s2);
}
bool is_end() const
{
return (_length == _pos);
}
// Keep these members public otherwise some of the
// converting constructors will not compile.
public:
SampleSeqType _sample_seq;
InfoSeqType _info_seq;
int _length;
difference_type _pos;
difference_type& _info_pos;
};
template <typename T, typename U>
std::size_t SampleIterator<T, U>::_null_info_pos = 0;
template <typename T, typename U>
no_sample_info_t * SampleIterator<T, U>::_null_info_scrachtpad[1] = {NULL};
template <typename T, typename U>
typename SampleIterator<T, U>::InfoSeqType SampleIterator<T, U>::_null_info_seq =
reinterpret_cast<InfoSeqType> (SampleIterator<T, U>::_null_info_scrachtpad);
} } }
#endif // RTI_ROUTING_PROCESSOR_SAMPLE_ITERATOR_HPP_
@@ -0,0 +1,353 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_PROCESSOR_DETAIL_PROCESSOR_FORWARDER_HPP_
#define RTI_ROUTING_PROCESSOR_DETAIL_PROCESSOR_FORWARDER_HPP_
#include <rti/core/Exception.hpp>
#include "rti/apputils/ServiceException.hpp"
#include "routingservice/routingservice_processor_impl.h"
#include <rti/routing/detail/ForwarderUtils.hpp>
#include <rti/routing/detail/UpdatableEntityForwarder.hpp>
#include <rti/routing/processor/Route.hpp>
#include <rti/routing/processor/Input.hpp>
#include <rti/routing/processor/Output.hpp>
namespace rti { namespace routing { namespace processor { namespace detail {
class ProcessorForwarder {
private:
template <typename PORT, typename NATIVE>
class ScopedPort {
public:
ScopedPort(Route& route, int32_t index, NATIVE *native)
: route_(route),
port_(new PORT(native, index, route.native_route_))
{
}
PORT* get()
{
return port_;
}
void clear()
{
port_ = NULL;
}
~ScopedPort()
{
if (port_ != NULL) {
delete port_;
port_ = NULL;
}
}
private:
Route& route_;
PORT *port_;
};
public:
static RTI_RoutingServiceProcessor * create_native(
ProcessorPlugin *plugin,
RTI_RoutingServiceRoute *native_route,
const struct RTI_RoutingServiceProperties *native_properties,
RTI_RoutingServiceEnvironment *environment)
{
try {
using rti::routing::detail::ScopedForwarder;
std::map<std::string, std::string> properties;
rti::routing::PropertyAdapter::add_properties_from_native(
properties,
native_properties);
ProcessorForwarder *forwarder = new ProcessorForwarder(
native_route,
environment);
ScopedForwarder<ProcessorPlugin, ProcessorForwarder> scoped(
plugin,
forwarder,
environment);
forwarder->processor_ = plugin->create_processor(
forwarder->route(),
properties);
RTI_ROUTING_THROW_ON_NULL(forwarder->processor_);
scoped.release();
// TRUST-134: the forwarder is not leaked here. It might be leaked
// if delete_native() were not to be called, but Routing Service
// will make sure that is not the case
/* coverity[leaked_storage : FALSE] */
return forwarder->native();
} catch(const rti::apputils::FatalServiceException& ex) {
RTI_RoutingServiceEnvironment_fatal_error(
environment,
ex.what());
return NULL;
} catch(const std::exception& ex) {
RTI_RoutingServiceEnvironment_set_error(
environment,
ex.what());
return NULL;
} catch (...) {
RTI_RoutingServiceEnvironment_set_error(
environment,
"unexpected exception");
return NULL;
}
}
static void delete_native(
ProcessorPlugin *plugin,
RTI_RoutingServiceProcessor *native_processor,
RTI_RoutingServiceEnvironment *environment)
{
ProcessorForwarder *processor_forwarder =
static_cast<ProcessorForwarder*>(native_processor->processor_data);
try {
if (processor_forwarder->processor_ != NULL) {
plugin->delete_processor(
processor_forwarder->route_,
processor_forwarder->processor_);
processor_forwarder->processor_ = NULL;
}
} catch(const rti::apputils::FatalServiceException& ex) {
RTI_RoutingServiceEnvironment_fatal_error(
environment,
ex.what());
} catch(const std::exception& ex) {
RTI_RoutingServiceEnvironment_set_error(
environment,
ex.what());
} catch (...) {
RTI_RoutingServiceEnvironment_set_error(
environment,
"unexpected exception");
}
delete processor_forwarder;
}
static void forward_on_route_event(
void *native_processor_data,
RTI_RoutingServiceRouteEvent *native_route_event,
RTI_RoutingServiceEnvironment *environment)
{
ProcessorForwarder *forwarder =
static_cast<ProcessorForwarder*>(native_processor_data);
try {
// build up wrapper objects based on the event
switch (RTI_RoutingServiceRouteEvent_get_kind(native_route_event)) {
case RTI_ROUTING_SERVICE_ROUTE_EVENT_DATA_ON_INPUTS:
forwarder->processor_->on_data_available(forwarder->route());
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_PERIODIC_ACTION:
forwarder->processor_->on_periodic_action(forwarder->route());
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_INPUT_ENABLED:
{
void *affected_entity =
RTI_RoutingServiceRouteEvent_get_affected_entity(native_route_event);
void *index =
RTI_RoutingServiceRouteEvent_get_event_data(native_route_event);
/* ScopedPort helps to delete the Input if an exception occurs */
ScopedPort<Input, RTI_RoutingServiceInput> port(
forwarder->route_,
*(static_cast<int32_t*>(index)),
static_cast<RTI_RoutingServiceInput *>(affected_entity));
forwarder->processor_->on_input_enabled(
forwarder->route(),
*port.get());
RTI_RoutingServiceInput_set_user_data(
static_cast<RTI_RoutingServiceInput *>(affected_entity),
port.get());
/*
* Input successfully enabled, so clear the ScopedPort so it
* doesn't delete it
*/
port.clear();
}
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_INPUT_DISABLED:
{
void *affected_entity =
RTI_RoutingServiceRouteEvent_get_affected_entity(native_route_event);
RTI_RoutingServiceInput *native_input =
static_cast<RTI_RoutingServiceInput *>(affected_entity);
Input *input = reinterpret_cast<Input*>(
RTI_RoutingServiceInput_get_user_data(native_input));
forwarder->processor_->on_input_disabled(
forwarder->route(),
*input);
RTI_RoutingServiceInput_set_user_data(native_input, NULL);
delete input;
}
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_OUTPUT_ENABLED:
{
void *affected_entity =
RTI_RoutingServiceRouteEvent_get_affected_entity(native_route_event);
void *index =
RTI_RoutingServiceRouteEvent_get_event_data(native_route_event);
/* ScopedPort helps to delete the Output if an exception occurs */
ScopedPort<Output, RTI_RoutingServiceOutput> port(
forwarder->route_,
*(static_cast<int32_t*>(index)),
static_cast<RTI_RoutingServiceOutput *>(affected_entity));
forwarder->processor_->on_output_enabled(
forwarder->route(),
*port.get());
RTI_RoutingServiceOutput_set_user_data(
static_cast<RTI_RoutingServiceOutput *>(affected_entity),
port.get());
/*
* Output successfully enabled, so clear the ScopedPort so it
* doesn't delete it
*/
port.clear();
}
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_OUTPUT_DISABLED:
{
void *affected_entity =
RTI_RoutingServiceRouteEvent_get_affected_entity(native_route_event);
RTI_RoutingServiceOutput *native_output =
static_cast<RTI_RoutingServiceOutput *>(affected_entity);
Output *output = reinterpret_cast<Output*>(
RTI_RoutingServiceOutput_get_user_data(native_output));
forwarder->processor_->on_output_disabled(
forwarder->route(),
*output);
RTI_RoutingServiceOutput_set_user_data(native_output, NULL);
delete output;
}
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_ROUTE_STARTED:
forwarder->processor_->on_start(forwarder->route());
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_ROUTE_STOPPED:
forwarder->processor_->on_stop(forwarder->route());
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_ROUTE_RUNNING:
forwarder->processor_->on_run(forwarder->route());
break;
case RTI_ROUTING_SERVICE_ROUTE_EVENT_ROUTE_PAUSED:
forwarder->processor_->on_pause(forwarder->route());
break;
default:
break;
};
} catch (const rti::apputils::FatalServiceException& ex) {
RTI_RoutingServiceEnvironment_fatal_error(
environment,
ex.what());
} catch (const std::exception& ex) {
RTI_RoutingServiceEnvironment_set_error(
environment,
ex.what());
} catch (...) {
RTI_RoutingServiceEnvironment_set_error(
environment,
"%s",
"unexpected exception");
}
}
static void forward_update(
void *native_processor_data,
const struct RTI_RoutingServiceProperties *native_properties,
RTI_RoutingServiceEnvironment *environment)
{
ProcessorForwarder *processorForwarder =
static_cast<ProcessorForwarder*> (native_processor_data);
rti::routing::detail::UpdatableEntityForwarder::update(
processorForwarder->processor_,
native_properties,
environment);
}
RTI_RoutingServiceProcessor* native()
{
return &native_;
}
private:
ProcessorForwarder(
RTI_RoutingServiceRoute *native_route,
RTI_RoutingServiceEnvironment *native_env) :
processor_(NULL),
route_(native_route, native_env)
{
RTIOsapiMemory_zero(&native_, sizeof(native_));
/* initialize native implementation */
native_.processor_data = static_cast<void *>(this);
native_.on_route_event = ProcessorForwarder::forward_on_route_event;
native_.update = ProcessorForwarder::forward_update;
}
rti::routing::processor::Route& route()
{
return route_;
}
~ProcessorForwarder()
{
}
private:
RTI_RoutingServiceProcessor native_;
Processor *processor_;
rti::routing::processor::Route route_;
};
}}}}
#endif // RTI_ROUTING_PROCESSOR_DETAIL_PROCESSOR_FORWARDER_HPP_
@@ -0,0 +1,99 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_PROCESSOR_PLUGIN_DETAIL_PROCESSOR_PLUGIN_FORWARDER_HPP_
#define RTI_ROUTING_PROCESSOR_PLUGIN_DETAIL_PROCESSOR_PLUGIN_FORWARDER_HPP_
#include <rti/core/Exception.hpp>
#include <rti/routing/processor/detail/ProcessorForwarder.hpp>
#include <rti/routing/detail/ForwarderUtils.hpp>
namespace rti { namespace routing { namespace processor { namespace detail {
class ProcessorPluginForwarder {
public:
static RTI_RoutingServiceProcessorPlugin * create_plugin(
ProcessorPlugin *plugin)
{
RTI_RoutingServiceProcessorPlugin *native_plugin = NULL;
RTIOsapiHeap_allocateStructure(
&native_plugin,
struct RTI_RoutingServiceProcessorPlugin);
rti::core::check_create_entity(
native_plugin,
"RTI_RoutingServiceProcessorPlugin");
RTI_RoutingServiceProcessorPlugin_initialize(native_plugin);
// Set adapter version
rti::config::LibraryVersion version = plugin->get_version();
native_plugin->plugin_version.major = version.major_version();
native_plugin->plugin_version.minor = version.minor_version();
native_plugin->plugin_version.release = version.release_version();
// Initialize native implementation
native_plugin->processor_plugin_data =
static_cast<void *>(plugin);
native_plugin->plugin_delete =
ProcessorPluginForwarder::delete_plugin;
native_plugin->create_processor =
ProcessorPluginForwarder::forward_create_processor;
native_plugin->delete_processor =
ProcessorPluginForwarder::forward_delete_processor;
return native_plugin;
}
static void delete_plugin(
RTI_RoutingServiceProcessorPlugin *native_plugin,
RTI_RoutingServiceEnvironment *)
{
ProcessorPlugin *plugin = static_cast<ProcessorPlugin*>(
native_plugin->processor_plugin_data);
// Plug-in is destructor not allowed to throw
delete plugin;
RTIOsapiHeap_freeStructure(native_plugin);
}
static RTI_RoutingServiceProcessor * forward_create_processor(
void *native_plugin_data,
RTI_RoutingServiceRoute *native_route,
const struct RTI_RoutingServiceProperties *native_properties,
RTI_RoutingServiceEnvironment *environment)
{
return ProcessorForwarder::create_native(
static_cast<ProcessorPlugin *>(native_plugin_data),
native_route,
native_properties,
environment);
}
static void forward_delete_processor(
void *native_plugin_data,
struct RTI_RoutingServiceProcessor *native_processor,
RTI_RoutingServiceRoute *,
RTI_RoutingServiceEnvironment *environment)
{
ProcessorForwarder::delete_native(
static_cast<ProcessorPlugin *>(native_plugin_data),
native_processor,
environment);
}
};
}}}}
#endif // RTI_ROUTING_PROCESSOR_PLUGIN_DETAIL_PROCESSOR_PLUGIN_FORWARDER_HPP_
@@ -0,0 +1,223 @@
/*
* (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_TRANSF_TRANSFORMATION_HPP_
#define RTI_ROUTING_TRANSF_TRANSFORMATION_HPP_
#include <vector>
#include <dds/core/xtypes/DynamicData.hpp>
#include <dds/sub/SampleInfo.hpp>
#include <rti/routing/UpdatableEntity.hpp>
#include <rti/routing/detail/ForwarderUtils.hpp>
namespace rti { namespace routing { namespace transf {
/** @ingroup RTI_RoutingServiceTransformationModule
*
* @class rti::routing::transf::Transformation
* @brief Provides a way to transform input samples into output samples of a
* different format and/or content.
*
* @mtsafety Partially Safe
* All operations on a concrete Transformation object are safe and
* always serialized on a given Output. Operations on different
* Transformations objects may be called concurrently if they
* belong to different Outputs from different Routes.
*/
class Transformation : public UpdatableEntity{
public:
typedef void* SamplePtr;
typedef void* InfoPtr;
/**
* @brief Transforms a vector of input samples into a vector of output
* samples.
*
* When @product is done using the output samples, it will 'return the loan'
* to the transformation by calling Transformation::return_loan. It is
* guaranteed @product takes one outstanding loan at time.
*
* The number of output samples can be different than the number of input
* samples.
*
* The format associated with the input and output data samples and info
* samples depends on the format provided and consumed by the input's
* rti::routing::adapter::StreamReader and the output's
* rti::routing::adapter::StreamWriter.
*
* For the built-in DDS adapter, the format of the samples is
* dds::core::xtypes::DynamicData and the format of the sample info is
* dds::sub::SampleInfo.
*
* @param output_sample_seq
* @rs_st_inout Vector that will hold the output data samples. @product
* provides this vector to the Transformation to fill. For each call,
* the size of the vector is zero.
* @param output_info_seq
* @rs_st_inout Vector that will hold the input info samples. @product
* provides this vector to the Transformation to fill. For each call,
* the size of the vector is zero.
* @param input_sample_seq
* @rs_st_in Vector of input data samples. This vector contains the list
* of samples that need to be transformed before calling
* rti::routing::adapter::StreamWriter::write.
* @param input_info_seq
* @rs_st_in Vector of input info sample. This vector contains the list
* of samples that need to be transformed before calling
* rti::routing::adapter::StreamWriter::write.
*
* @throw std::exception
*/
virtual void transform(
std::vector<SamplePtr>& output_sample_seq,
std::vector<InfoPtr>& output_info_seq,
const std::vector<SamplePtr>& input_sample_seq,
const std::vector<InfoPtr>& input_info_seq) = 0;
/**
* @brief Returns a loan on the transformed 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 Transformation::transform.
*
* @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;
virtual ~Transformation() {}
};
/** @ingroup RTI_RoutingServiceTransformationModule
*
* @class rti::routing::transf::TypedTransformation
*
* @brief A wrapper implementation of a Transformation 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 TypedTransformation : public Transformation {
public:
/**
* @brief The data type
*/
typedef Data DataRep;
/**
* @brief The info type
*/
typedef Info InfoRep;
using Transformation::transform;
using Transformation::return_loan;
/**
* @brief Performs the conversion between the vector of data and info
* pointers to strongly-type pointers.
*/
void transform(
std::vector<SamplePtr>& output_sample_seq,
std::vector<InfoPtr>& output_info_seq,
const std::vector<SamplePtr>& input_sample_seq,
const std::vector<InfoPtr>& input_info_seq) RTI_FINAL
{
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(in_sample_seq_, input_sample_seq);
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(in_info_seq_, input_info_seq);
transform(
out_sample_seq_,
out_info_seq_,
in_sample_seq_,
in_info_seq_);
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(output_sample_seq, out_sample_seq_);
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(output_info_seq, out_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(out_sample_seq_, sample_seq);
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(out_info_seq_, info_seq);
return_loan(out_sample_seq_, out_info_seq_);
out_sample_seq_.clear();
out_info_seq_.clear();
}
/**
* @brief Interface redefinition
*
* @see Transformation::transform
*/
virtual void transform(
std::vector<Data*>& output_sample_seq,
std::vector<Info*>& output_info_seq,
const std::vector<Data*>& input_sample_seq,
const std::vector<Info*>& input_info_seq) = 0;
/**
* @brief Interface redefinition
*
* @see Transformation::return_loan
*/
virtual void return_loan(
std::vector<Data*>& sample_seq,
std::vector<Info*>& info_seq) = 0;
/**
* @brief Virtual destructor
*/
virtual ~TypedTransformation()
{
}
private:
std::vector<Data*> in_sample_seq_;
std::vector<Info*> in_info_seq_;
std::vector<Data*> out_sample_seq_;
std::vector<Info*> out_info_seq_;
};
/** @ingroup RTI_RoutingServiceTransformationModule
*
* @brief Convenient definition of TypedTransformation that requires
* dds::core::xtypes::DynamicData for data samples and dds::sub::SampleInfo
* for info samples.
*
*/
typedef TypedTransformation<dds::core::xtypes::DynamicData, dds::sub::SampleInfo>
DynamicDataTransformation;
}}}
#endif // RTI_ROUTING_TRANSF_TRANSFORMATION_HPP_
@@ -0,0 +1,221 @@
/*
* (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_TRANSF_TRANSFORMATION_PLUGIN_HPP_
#define RTI_ROUTING_TRANSF_TRANSFORMATION_PLUGIN_HPP_
#include "routingservice/routingservice_log.h"
#include <rti/config/Version.hpp>
#include <rti/routing/TypeInfo.hpp>
#include <rti/routing/PropertySet.hpp>
#include <rti/routing/transf/Transformation.hpp>
#include <rti/routing/detail/ForwarderUtils.hpp>
/*e \file
@brief RTI Routing Service Transformation API
*/
/** @defgroup RTI_RoutingServiceTransformationModule RTI Routing Service Transformation API
* @ingroup ROUTER
* @brief This module describes the Transformation API.
*
* An @product Output transforms the incoming data using a @em transformation,
* which is an object created by a transformation plugin.<br>
*
*/
namespace rti { namespace routing { namespace transf {
/** @ingroup RTI_RoutingServiceTransformationModule
*
* @class rti::routing::transf::TransformationPlugin
*
* @brief The top-level plug-in class.
*
* Represents a factory of Transformation.
*/
class TransformationPlugin {
public:
/**
* @brief Creates an Output Transformation.
*
* This function is called when the Output containing the transformation
* is enabled.
*
* The format associated with the input and output types depends on
* the format provided by the input and output adapters.
*
* For the built-in DDS adapter, the format of the types is DDS_TypeCode.
* <b>Required:</b> yes
*
* @param input_type_info
* @rs_st_in Type information associated with the input samples.
* @param output_type_info
* @rs_st_in Type information associated with the output samples.
* @param properties
* @rs_st_in Configuration properties for the Transformation.
* These properties corresponds to the properties specified within
* the tag &lt;transformation&gt;.
*
* @return New Transformation if successful. Cannot return @null_value.
* @throw std::exception
* @mtsafety Safe
*/
virtual Transformation * create_transformation(
const rti::routing::TypeInfo& input_type_info,
const rti::routing::TypeInfo& output_type_info,
const rti::routing::PropertySet& properties) = 0;
/**
* @brief Deletes a Transformation.
*
* This function is called when the Output containing the transformation is
* disabled.
*
* @param transformation
* @rs_st_in Transformation to be deleted.
*
* @throw std::exception
* @mtsafety Safe
*/
virtual void delete_transformation(Transformation *transformation) = 0;
/**
* @return The version of this TransformationPlugin.
*
* Version is used for logging purposes and allows you to track which
* version of the TransformationPlugin @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 ~TransformationPlugin() {}
};
}}}
#include <rti/routing/transf/detail/TransformationPluginForwarder.hpp>
/** @ingroup RTI_RoutingServiceTransformationModule
*
* @brief Utility macro that declares a native extern function that can
* be used to load a TransformationPlugin through a shared library.
*
* The prototype of the function is given by
* RTI_RoutingServiceTransformationPlugin_CreateFcn.
*
* To register a transformation plugin with @product, you must use the tag
* &lt;transformation_plugin&gt; within &lt;plugin_library&gt;. For example:
*
* \code
* <dds>
* ...
* <plugin_library name="MyPluginLib">
* <transformation_plugin name="MyTransfPlugin">
* <dll>mytransformation</dll>
* <create_function>
* MyTransfPlugin_create
* </create_function>
* </transformation_plugin>
* ...
* </plugin_library>
* ...
* <routing_service>
* ...
* </routing_service>
* ...
* </dds>
* \endcode
*
* Once a transformation plugin is registered, an Output can use it to create a
* data transformation.
*
* For example:
*
* \code
* <topic_route name="SquareSwitchCoord">
* <input participant="1">
* <topic_name>Square</topic_name>
* <registered_type_name>ShapeType</registered_type_name>
* </input>
* <output>
* <topic_name>Square</topic_name>
* <registered_type_name>ShapeType</registered_type_name>
* <transformation plugin_name="MyPluginLib::MyTransPlugin">
* <property>
* <value>
* <element>
* <name>X</name>
* <value>Y</value>
* </element>
* <element>
* <name>Y</name>
* <value>X</value>
* </element>
* </value>
* </property>
* </transformation>
* </output>
* </topic_route>
* \endcode
*
* For additional information on configuring transformations, see the
* \ref_url_routing_service_users_manual.
*
* @param TRANSFORMATION_PLUGIN_CLASS
* Class name of a TransformationPlugin implementation
*/
#define RTI_TRANSFORMATION_PLUGIN_CREATE_FUNCTION_DECL(TRANSFORMATION_PLUGIN_CLASS) \
extern "C" RTI_USER_DLL_EXPORT struct RTI_RoutingServiceTransformationPlugin * \
TRANSFORMATION_PLUGIN_CLASS ## _create_transformation_plugin(\
const struct RTI_RoutingServiceProperties *, \
RTI_RoutingServiceEnvironment *); \
/** @ingroup RTI_RoutingServiceTransformationModule
*
* @brief Utility macro that implements the TransformationPlugin entry point
* declared with RTI_TRANSFORMATION_PLUGIN_CREATE_FUNCTION_DECL.
*/
#define RTI_TRANSFORMATION_PLUGIN_CREATE_FUNCTION_DEF(TRANSFORMATION_PLUGIN_CLASS) \
struct RTI_RoutingServiceTransformationPlugin * \
TRANSFORMATION_PLUGIN_CLASS ## _create_transformation_plugin( \
const struct RTI_RoutingServiceProperties * native_properties, \
RTI_RoutingServiceEnvironment *environment) \
{ \
rti::routing::PropertySet properties; \
rti::routing::PropertyAdapter::add_properties_from_native(\
properties,\
native_properties); \
try { \
return rti::routing::transf::detail::TransformationPluginForwarder::create_plugin(\
new TRANSFORMATION_PLUGIN_CLASS(properties)); \
} catch (const std::exception& ex) {\
RTI_RoutingServiceEnvironment_set_error(\
environment,\
"%s",\
ex.what());\
} catch (...) {}\
\
return NULL; \
}
#endif // RTI_ROUTING_TRANSF_TRANSFORMATION_PLUGIN_HPP_
@@ -0,0 +1,257 @@
/*
* (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_TRANSF_DETAIL_TRANSFORMATION_FORWARDER_HPP_
#define RTI_ROUTING_TRANSF_DETAIL_TRANSFORMATION_FORWARDER_HPP_
#include <rti/core/Exception.hpp>
#include <dds/core/xtypes/DynamicData.hpp>
#include <dds/sub/SampleInfo.hpp>
#include <rti/routing/transf/Transformation.hpp>
#include <rti/routing/TypeInfo.hpp>
#include <rti/routing/detail/UpdatableEntityForwarder.hpp>
#include <rti/routing/detail/ForwarderUtils.hpp>
#include "rti/apputils/ServiceException.hpp"
namespace rti { namespace routing { namespace transf { namespace detail {
class TransformationForwarder{
public:
static RTI_RoutingServiceTransformation create_native(
TransformationPlugin *plugin,
const struct RTI_RoutingServiceTypeInfo *native_input_type_info,
const struct RTI_RoutingServiceTypeInfo *native_output_type_info,
const struct RTI_RoutingServiceProperties *native_properties,
RTI_RoutingServiceEnvironment *environment)
{
try {
using rti::routing::detail::ScopedForwarder;
TypeInfo input_type_info(*native_input_type_info);
TypeInfo output_type_info(*native_output_type_info);
std::map<std::string, std::string> properties;
rti::routing::PropertyAdapter::add_properties_from_native(
properties,
native_properties);
TransformationForwarder *forwarder = new TransformationForwarder();
ScopedForwarder<TransformationPlugin, TransformationForwarder> scoped(
plugin,
forwarder,
environment);
forwarder->transformation_ = plugin->create_transformation(
input_type_info,
output_type_info,
properties);
RTI_ROUTING_THROW_ON_NULL(forwarder->transformation_);
scoped.release();
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(
TransformationPlugin *plugin,
RTI_RoutingServiceTransformation native_transformation,
RTI_RoutingServiceEnvironment *environment)
{
TransformationForwarder *forwarder =
static_cast<TransformationForwarder*>(native_transformation);
try {
if (forwarder->transformation_ != NULL) {
plugin->delete_transformation(
forwarder->transformation_);
forwarder->transformation_ = 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 forwarder;
}
static void transform(
RTI_RoutingServiceTransformation native_transformation,
RTI_RoutingServiceSample **out_sample_lst,
RTI_RoutingServiceSampleInfo **out_info_lst,
int *out_count,
RTI_RoutingServiceSample *in_sample_lst,
RTI_RoutingServiceSampleInfo *in_info_lst,
int in_count,
RTI_RoutingServiceEnvironment *environment)
{
TransformationForwarder *forwarder =
static_cast<TransformationForwarder*> (native_transformation);
if (forwarder->transformation_ == NULL) {
return;
}
*out_count = 0;
try {
// get native samples
forwarder->in_sample_seq_.resize(in_count);
forwarder->in_info_seq_.resize(in_count);
for (int i = 0; i < in_count; i++) {
forwarder->in_sample_seq_[i] = in_sample_lst[i];
if (in_info_lst != NULL) {
forwarder->in_info_seq_[i] = in_info_lst[i];
}
}
forwarder->transformation_->transform(
forwarder->out_sample_seq_,
forwarder->out_info_seq_,
forwarder->in_sample_seq_,
forwarder->in_info_seq_);
if (!forwarder->out_info_seq_.empty()
&& (forwarder->out_info_seq_.size()
!= forwarder->out_sample_seq_.size())) {
throw dds::core::PreconditionNotMetError(
"sample and info sequences length mismatch");
}
} catch (const rti::apputils::FatalServiceException& ex) {
RTI_RoutingServiceEnvironment_fatal_error(
environment,
ex.what());
return;
} catch (const std::exception& ex) {
RTI_RoutingServiceEnvironment_set_error(
environment,
ex.what());
return;
} catch (...) {
RTI_RoutingServiceEnvironment_set_error(
environment,
"unexpected exception");
return;
}
// direct mapping
*out_count = static_cast<int>(forwarder->out_sample_seq_.size());
if (*out_count > 0) {
*out_sample_lst = &forwarder->out_sample_seq_[0];
*out_info_lst = &forwarder->out_info_seq_[0];
}
}
static void return_loan(
RTI_RoutingServiceTransformation native_transformation,
RTI_RoutingServiceSample *,
RTI_RoutingServiceSampleInfo *,
int,
RTI_RoutingServiceEnvironment *environment)
{
TransformationForwarder *forwarder =
static_cast<TransformationForwarder*>(native_transformation);
if (forwarder->transformation_ == NULL) {
return;
}
try {
forwarder->transformation_->return_loan(
forwarder->out_sample_seq_,
forwarder->out_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->out_sample_seq_.clear();
forwarder->out_info_seq_.clear();
}
static void update(
RTI_RoutingServiceTransformation native_stream_reader,
const struct RTI_RoutingServiceProperties *native_properties,
RTI_RoutingServiceEnvironment *environment)
{
TransformationForwarder *stream_reader_forwarder =
static_cast<TransformationForwarder*> (native_stream_reader);
rti::routing::detail::UpdatableEntityForwarder::update(
stream_reader_forwarder->transformation_,
native_properties,
environment);
}
RTI_RoutingServiceTransformation native()
{
return this;
}
private:
TransformationForwarder()
: transformation_(NULL)
{
}
~TransformationForwarder()
{
}
private:
Transformation *transformation_;
std::vector<Transformation::SamplePtr> out_sample_seq_;
std::vector<Transformation::InfoPtr> out_info_seq_;
std::vector<Transformation::SamplePtr> in_sample_seq_;
std::vector<Transformation::InfoPtr> in_info_seq_;
};
}}}}
#endif // RTI_ROUTING_TRANSF_DETAIL_TRANSFORMATION_FORWARDER_HPP_
@@ -0,0 +1,104 @@
/*
* (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_TRANSF_DETAIL_TRANSFORMATION_PLUGIN_FORWARDER_HPP_
#define RTI_ROUTING_TRANSF_DETAIL_TRANSFORMATION_PLUGIN_FORWARDER_HPP_
#include <rti/core/Exception.hpp>
#include <routingservice/routingservice_transformation.h>
#include <rti/routing/transf/detail/TransformationForwarder.hpp>
namespace rti { namespace routing { namespace transf { namespace detail {
class TransformationPluginForwarder {
public:
static RTI_RoutingServiceTransformationPlugin * create_plugin(
TransformationPlugin *transformation_plugin)
{
RTI_RoutingServiceTransformationPlugin *native_plugin = NULL;
RTIOsapiHeap_allocateStructure(
&native_plugin,
struct RTI_RoutingServiceTransformationPlugin);
rti::core::check_create_entity(
native_plugin,
"RTI_RoutingServiceTransformationPlugin");
RTI_RoutingServiceTransformationPlugin_initialize(native_plugin);
// Set adapter version
rti::config::LibraryVersion version = transformation_plugin->get_version();
native_plugin->plugin_version.major = version.major_version();
native_plugin->plugin_version.minor = version.minor_version();
native_plugin->plugin_version.release = version.release_version();
// Initiallize adapter methods
native_plugin->user_object = static_cast<void *>(transformation_plugin);
native_plugin->transformation_plugin_delete =
TransformationPluginForwarder::delete_plugin;
native_plugin->transformation_plugin_create_transformation =
TransformationPluginForwarder::create_transformation;
native_plugin->transformation_plugin_delete_transformation =
TransformationPluginForwarder::delete_transformation;
native_plugin->transformation_transform =
TransformationForwarder::transform;
native_plugin->transformation_return_loan =
TransformationForwarder::return_loan;
native_plugin->transformation_update =
TransformationForwarder::update;
return native_plugin;
}
static void delete_plugin(
RTI_RoutingServiceTransformationPlugin *native_plugin,
RTI_RoutingServiceEnvironment *)
{
TransformationPlugin *plugin = static_cast<TransformationPlugin *>(
native_plugin->user_object);
// Plug-in is destructor not allowed to throw
delete plugin;
RTIOsapiHeap_freeStructure(native_plugin);
}
static RTI_RoutingServiceTransformation create_transformation(
struct RTI_RoutingServiceTransformationPlugin *native_plugin,
const struct RTI_RoutingServiceTypeInfo *input_type_info,
const struct RTI_RoutingServiceTypeInfo *output_type_info,
const struct RTI_RoutingServiceProperties *native_properties,
RTI_RoutingServiceEnvironment *environment)
{
return TransformationForwarder::create_native(
static_cast<TransformationPlugin *>(native_plugin->user_object),
input_type_info,
output_type_info,
native_properties,
environment);
}
static void delete_transformation(
struct RTI_RoutingServiceTransformationPlugin *native_plugin,
RTI_RoutingServiceTransformation native_transformation,
RTI_RoutingServiceEnvironment *environment)
{
TransformationForwarder::delete_native(
static_cast<TransformationPlugin *>(native_plugin->user_object),
native_transformation,
environment);
}
};
}}}}
#endif // RTI_ROUTING_TRANSF_DETAIL_TRANSFORMATION_PLUGIN_FORWARDER_HPP_