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