Adds immediate migration results

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

No files matched your search

@@ -0,0 +1,144 @@
/*
* $Id$
*
* (c) Copyright, Real-Time Innovations, 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 HPP_SERVICE_DYNAMIC_BUFFER_HPP_
#define HPP_SERVICE_DYNAMIC_BUFFER_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 "osapi/osapi_heap.h"
#include <dds/core/Value.hpp>
#include <dds/core/types.hpp>
#include <rti/apputils/ServiceException.hpp>
namespace rti { namespace apputils {
class DynamicBufferProperty {
public:
DynamicBufferProperty(int32_t min_size, bool trim_to_size)
:min_size_(min_size), trim_to_size_(trim_to_size)
{
}
DynamicBufferProperty(const DynamicBufferProperty &property)
:min_size_(property.min_size_), trim_to_size_(property.trim_to_size_)
{
}
DynamicBufferProperty& min_size(int32_t min_size)
{
min_size_ = min_size;
return *this;
}
int32_t min_size() const
{
return min_size_;
}
DynamicBufferProperty& trim_to_size(bool trim_to_size)
{
trim_to_size_ = trim_to_size;
return *this;
}
bool trim_to_size() const
{
return trim_to_size_;
}
private:
int32_t min_size_;
bool trim_to_size_;
};
class DynamicBuffer {
public:
DynamicBuffer(const DynamicBufferProperty &property)
:property_(property), buffer_(NULL), buffer_length_(0)
{
ensure_length(property.min_size());
}
~DynamicBuffer()
{
if (buffer_ != NULL) {
RTIOsapiHeap_freeArray(buffer_);
buffer_ = NULL;
}
buffer_length_ = 0;
}
void ensure_length(int32_t new_length)
{
if (new_length > buffer_length_) {
if (!RTIOsapiHeap_reallocateArray(&buffer_, new_length, char)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_OSAPI_MEMORY_LOG_OUT_OF_HEAP_STRING_d,
new_length);
}
buffer_length_ = new_length;
}
}
void trim_to_size()
{
if (property_.trim_to_size()) {
if (!RTIOsapiHeap_reallocateArray(
&buffer_,
property_.min_size(),
char)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_OSAPI_MEMORY_LOG_OUT_OF_HEAP_STRING_d,
property_.min_size());
}
buffer_length_ = property_.min_size();
}
}
void release(char *&buffer, int32_t& length)
{
buffer = buffer_;
length = buffer_length_;
buffer_ = NULL;
buffer_length_ = 0;
}
void own(char *buffer, int32_t length)
{
buffer_ = buffer;
buffer_length_ = length;
}
char *buffer()
{
return buffer_;
}
int32_t length()
{
return buffer_length_;
}
private:
const DynamicBufferProperty property_;
char* buffer_;
int32_t buffer_length_;
};
} } /* namespace rti::apputils */
#endif /* HPP_SERVICE_DYNAMIC_BUFFER_HPP_ */
@@ -0,0 +1,247 @@
/*
* (c) Copyright, Real-Time Innovations, 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 HPP_SERVICE_DYNAMIC_DATA_CONVERTER_HPP_
#define HPP_SERVICE_DYNAMIC_DATA_CONVERTER_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 "osapi/osapi_heap.h"
#include <dds/core/Value.hpp>
#include <dds/core/types.hpp>
#include <assert.h>
#include <dds/core/xtypes/DynamicType.hpp>
#include <dds/core/xtypes/DynamicData.hpp>
#include <rti/core/NativeValueType.hpp>
#include <rti/apputils/ServiceException.hpp>
#include <rti/apputils/DynamicBuffer.hpp>
#include "apputils/apputils_dynamic_data_converter_impl.h"
namespace rti { namespace apputils {
class DynamicDataConverter {
public:
class ScopedSample {
public:
ScopedSample(
APPUTILSDynamicDataConverter *converter,
DDS_DynamicData *native) :
converter_(converter),
native_(native)
{
}
~ScopedSample()
{
APPUTILSDynamicDataConverter_return_sample(converter_, native_);
}
dds::core::xtypes::DynamicData& get()
{
return rti::core::native_conversions::cast_from_native<
dds::core::xtypes::DynamicData>(*native_);
}
private:
APPUTILSDynamicDataConverter *converter_;
DDS_DynamicData *native_;
};
class ScopedBuffer {
public:
ScopedBuffer() : converter_(NULL), native_(NULL), native_length_(0)
{
}
ScopedBuffer(
APPUTILSDynamicDataConverter *converter,
void *native,
uint32_t native_length) :
converter_(converter),
native_(native),
native_length_(native_length)
{
}
~ScopedBuffer()
{
if (native_ != NULL) {
APPUTILSDynamicDataConverter_return_buffer(converter_, native_);
}
}
void clear()
{
assign(converter_, NULL, 0);
}
void assign(
APPUTILSDynamicDataConverter *converter,
void *native,
uint32_t native_length)
{
if (native_ != NULL) {
APPUTILSDynamicDataConverter_return_buffer(
converter_,
const_cast<void *>(native_));
}
converter_ = converter;
native_ = native;
native_length_ = native_length;
}
ScopedBuffer& operator =(ScopedBuffer& other)
{
assign(other.converter_, other.native_, other.native_length_);
return *this;
}
const void * get()
{
return native_;
}
template <typename T>
const T * get() {
return static_cast<const T *>(native_);
}
uint32_t length()
{
return native_length_;
}
private:
APPUTILSDynamicDataConverter *converter_;
void *native_;
uint32_t native_length_;
};
/**
* The dynamic data converter allows for deferred initialization. When doing
* so, it can be initialized at any moment by calling the set() method.
*/
DynamicDataConverter() : initialized_(false) {}
/**
* Direct initialization constructor. A valid type-code has to be provided
* (not null and it has to be a non-primitive and non null type-kind type).
*/
DynamicDataConverter(
const dds::core::xtypes::DynamicType& type_code,
const DynamicBufferProperty &property) :
initialized_(false)
{
set(type_code, property);
}
/**
* Initialize this dynamic data converter. A valid type-code has to be
* provided (not null and it has to be a non-primitive and non null
* type-kind type).
* If the converter has already been initialized, this method is a no-op.
*/
void set(
const dds::core::xtypes::DynamicType& type_code,
const DynamicBufferProperty &property)
{
if (!initialized_) {
if (!APPUTILSDynamicDataConverter_initialize(
&converter_,
&(type_code.native()),
(RTI_UINT32) property.min_size())) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_INIT_FAILURE_s,
"native converter");
}
initialized_ = true;
}
}
~DynamicDataConverter()
{
if (initialized_) {
APPUTILSDynamicDataConverter_finalize(&converter_);
}
}
ScopedSample sample(
const dds::core::xtypes::DynamicData& sample,
const DDS_DataRepresentationId_t target_representation)
{
DDS_DynamicData *native = APPUTILSDynamicDataConverter_get_sample(
&converter_,
const_cast<DDS_DynamicData *>(&sample.native()),
target_representation);
if (native == NULL) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_FAILURE_s,
"get native sample");
}
return ScopedSample(&converter_, native);
}
ScopedBuffer buffer(
const dds::core::xtypes::DynamicData& sample,
const DDS_DataRepresentationId_t target_representation)
{
DDS_UnsignedLong native_length = 0;
void *native = APPUTILSDynamicDataConverter_get_buffer(
&converter_,
&native_length,
const_cast<DDS_DynamicData *>(&sample.native()),
target_representation);
if (native == NULL) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_FAILURE_s,
"get native buffer");
}
return ScopedBuffer(&converter_, native, (uint32_t) native_length);
}
void buffer(
ScopedBuffer& scoped_buffer,
const dds::core::xtypes::DynamicData& sample,
const DDS_DataRepresentationId_t target_representation)
{
DDS_UnsignedLong native_length = 0;
/*
* The scoped buffer has to be cleared before we can use it again. The
* buffer will automatically be returned to this converter. After this,
* we can safely get the buffer again from the dynamic data sample and
* reassign to the scoped buffer.
*/
scoped_buffer.clear();
void *native = APPUTILSDynamicDataConverter_get_buffer(
&converter_,
&native_length,
const_cast<DDS_DynamicData *>(&sample.native()),
target_representation);
if (native == NULL) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_FAILURE_s,
"get native buffer");
}
scoped_buffer.assign(&converter_, native, (uint32_t) native_length);
}
private:
APPUTILSDynamicDataConverter converter_;
bool initialized_;
};
} } /* namespace rti::apputils */
#endif /* HPP_SERVICE_DYNAMIC_DATA_CONVERTER_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 HPP_SERVICE_ENTITY_ID_HPP_
#define HPP_SERVICE_ENTITY_ID_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 "rtixmlutils/rtixmlutils_object.h"
namespace rti { namespace apputils {
class EntityFullNameIterator {
public:
EntityFullNameIterator(const std::string& full_name)
: full_name_(full_name), substring_pos_(0), next_substring_pos_(0)
{
next();
}
~EntityFullNameIterator()
{
}
bool is_end() const
{
return substring_pos_ == full_name_.length();
}
EntityFullNameIterator& end()
{
substring_pos_ = full_name_.length();
next_substring_pos_ = substring_pos_;
return *this;
}
EntityFullNameIterator& last()
{
next_substring_pos_ = full_name_.length();
substring_pos_ = next_substring_pos_;
for (; substring_pos_ > 0; --substring_pos_) {
if (full_name_[substring_pos_] == '\"') {
size_t opening_quotes = full_name_.rfind(
"\"",
substring_pos_ - 1);
if (opening_quotes == std::string::npos) {
DDSLog_warn(
&RTI_LOG_ANY_s,
"detected unbalanced escaped name. Missing closing '\"'?");
} else {
// skip all characters in escaped name
substring_pos_ = opening_quotes;
}
} else if (full_name_.find(
RTIXMLUTILS_OBJECT_NAME_SEPARATOR,
substring_pos_) == substring_pos_) {
substring_pos_ += strlen(RTIXMLUTILS_OBJECT_NAME_SEPARATOR);
break;
}
}
return *this;
}
std::string parent()
{
size_t parent_length = (substring_pos_ == 0)
? 0
: substring_pos_ - strlen(RTIXMLUTILS_OBJECT_NAME_SEPARATOR);
return full_name_.substr(0, parent_length);
}
std::string operator*() const
{
size_t substring_pos = substring_pos_;
size_t name_length = next_substring_pos_ - substring_pos_;
if (name_length > 1
&& full_name_[substring_pos_ + name_length - 1] == '\"'
&& full_name_[substring_pos_] == '\"') {
name_length -= 2;
++substring_pos;
}
return full_name_.substr(substring_pos, name_length);
}
EntityFullNameIterator& operator++()
{
next();
return *this;
}
std::string escaped()
{
size_t substring_pos = substring_pos_;
size_t name_length = next_substring_pos_ - substring_pos_;
return full_name_.substr(substring_pos, name_length);
}
friend bool operator==(
const EntityFullNameIterator &s1,
const EntityFullNameIterator &s2)
{
return s1.substring_pos_ == s2.substring_pos_
&& s1.next_substring_pos_ == s2.next_substring_pos_
&& &s1.full_name_ == &s2.full_name_;
}
friend bool operator!=(
const EntityFullNameIterator &s1,
const EntityFullNameIterator &s2)
{
return !(s1 == s2);
}
private:
void next()
{
if (full_name_.find(
RTIXMLUTILS_OBJECT_NAME_SEPARATOR,
next_substring_pos_) == next_substring_pos_) {
next_substring_pos_ += strlen(RTIXMLUTILS_OBJECT_NAME_SEPARATOR);
}
substring_pos_ = next_substring_pos_;
for (; next_substring_pos_ < full_name_.length(); ++next_substring_pos_) {
if (full_name_[next_substring_pos_] == '\"') {
size_t closing_quotes = full_name_.find(
"\"",
next_substring_pos_ + 1);
if (closing_quotes == std::string::npos) {
DDSLog_warn(
&RTI_LOG_ANY_s,
"detected unbalanced escaped name. Missing closing '\"'?");
} else {
// skip all characters in escaped name
next_substring_pos_ = closing_quotes;
}
} else if (full_name_.find(
RTIXMLUTILS_OBJECT_NAME_SEPARATOR,
next_substring_pos_) == next_substring_pos_) {
break;
}
}
}
private:
const std::string& full_name_;
size_t substring_pos_;
size_t next_substring_pos_;
};
template<typename ENTITY_KIND_TYPE>
class EntityId {
public:
typedef EntityFullNameIterator name_iterator;
public:
EntityId(const std::string& the_full_name, ENTITY_KIND_TYPE the_kind)
: full_name_(the_full_name), kind_(the_kind)
{
}
bool is_nil() const
{
return kind_ == ENTITY_KIND_TYPE::count_;
}
name_iterator begin() const
{
return EntityFullNameIterator(full_name_);
}
name_iterator end() const
{
return EntityFullNameIterator(full_name_).end();
}
const std::string& full_name() const
{
return full_name_;
}
const std::string name() const
{
return (*EntityFullNameIterator(full_name_).last());
}
const std::string parent_name() const
{
return EntityFullNameIterator(full_name_).last().parent();
}
const ENTITY_KIND_TYPE& kind() const
{
return kind_;
}
static EntityId<ENTITY_KIND_TYPE> nil()
{
static EntityId<ENTITY_KIND_TYPE> nil(
"",
ENTITY_KIND_TYPE::count_);
return nil;
}
friend bool operator==(
const EntityId<ENTITY_KIND_TYPE>& left,
const EntityId<ENTITY_KIND_TYPE>& right)
{
return left.kind_ == right.kind_
&& left.full_name_ == right.full_name_;
}
private:
std::string full_name_;
ENTITY_KIND_TYPE kind_;
};
} } /* namespace rti::apputils */
#endif //HPP_SERVICE_ENTITY_ID_HPP_
@@ -0,0 +1,395 @@
/*
* $Id$
*
* (c) Copyright, Real-Time Innovations, 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 HPP_SERVICE_RESOURCE_IDENTIFIER_HPP_
#define HPP_SERVICE_RESOURCE_IDENTIFIER_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 <assert.h>
#include "reda/reda_inlineList.h"
#include "apputils/apputils_resource_identifier_impl.h"
#include <dds/core/Value.hpp>
#include <rti/core/NativeValueType.hpp>
#include <rti/apputils/ServiceException.hpp>
#include <rti/apputils/EntityId.hpp>
namespace rti { namespace apputils {
class ResourceIdentifier;
class RelativeResource {
public:
typedef const APPUTILSRelativeResourceInfo native_type;
RelativeResource(native_type *native_value)
: native_relative_resource_(native_value)
{
}
~RelativeResource()
{
}
RelativeResource(const RelativeResource &other)
: native_relative_resource_(other.native_relative_resource_)
{
}
RelativeResource operator * () const
{
return RelativeResource(*this);
}
RelativeResource & operator = (const RelativeResource& other)
{
native_relative_resource_ = other.native_relative_resource_;
return *this;
}
RelativeResource& operator ++ ()
{
native_relative_resource_ = next();
return *this;
}
RelativeResource& operator -- ()
{
native_relative_resource_ = prev();
return *this;
}
friend bool operator == (
const RelativeResource & s1,
const RelativeResource & s2)
{
return s1.native_relative_resource_ == s2.native_relative_resource_;
}
friend bool operator != (
const RelativeResource & s1,
const RelativeResource & s2)
{
return !(s1 == s2);
}
std::string name() const
{
return APPUTILSRelativeResourceInfo_get_name(
native_relative_resource_);
}
std::string kind() const
{
return APPUTILSRelativeResourceInfo_get_kind(
native_relative_resource_);
}
RelativeResource& last()
{
REDAInlineListNode *last = (struct REDAInlineListNode *)
REDAInlineList_getLast(
native_relative_resource_->_node.inlineList);
assert(last != NULL);
native_relative_resource_ = reinterpret_cast<native_type*>(last);
return *this;
}
RelativeResource& begin()
{
REDAInlineListNode *first = (struct REDAInlineListNode *)
REDAInlineList_getFirst(
native_relative_resource_->_node.inlineList);
assert(first != NULL);
native_relative_resource_ = reinterpret_cast<native_type*> (first);
return *this;
}
friend const std::string to_string(
const RelativeResource& relative_id)
{
return relative_id.kind() + "/" + relative_id.name();
}
friend class ResourceIdentifier;
private:
static RelativeResource nil()
{
static RelativeResource nil(NULL);
return nil;
}
native_type *next()
{
return reinterpret_cast<native_type *>(
REDAInlineListNode_getNext(&native_relative_resource_->_node));
}
native_type * prev()
{
void *prev =
REDAInlineListNode_getPrev(&native_relative_resource_->_node);
if (prev != NULL) {
return reinterpret_cast<native_type*> (prev);
}
return native_relative_resource_;
}
private:
native_type *native_relative_resource_;
};
class ResourceIdentifier {
public:
typedef APPUTILSResourceIdentifier native_type;
typedef RelativeResource iterator;
typedef RelativeResource relative_resource;
public:
ResourceIdentifier()
{
if (!APPUTILSResourceIdentifier_initialize(&native_)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_INIT_FAILURE_s,
"native resource identifier");
}
}
ResourceIdentifier(const std::string& formatted_uri)
{
if (!APPUTILSResourceIdentifier_initialize(&native_)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_INIT_FAILURE_s,
"native resource identifier");
}
if (!APPUTILSResourceIdentifier_parse_formatted_identifier(
&native_,
formatted_uri.c_str())) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_SERVICE_LOG_MALFORMED_RESOURCE_IDENTIFIER_s,
formatted_uri.c_str());
}
parse(formatted_uri);
}
ResourceIdentifier(const ResourceIdentifier& other)
{
if (!APPUTILSResourceIdentifier_initialize(&native_)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_INIT_FAILURE_s,
"native resource identifier");
}
append(other);
}
ResourceIdentifier(
const ResourceIdentifier& parent,
const ResourceIdentifier& child)
{
if (!APPUTILSResourceIdentifier_initialize(&native_)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_INIT_FAILURE_s,
"native resource identifier");
}
append(parent);
append(child);
}
ResourceIdentifier(
const std::string& kind,
const std::string& name)
{
if (!APPUTILSResourceIdentifier_initialize(&native_)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_INIT_FAILURE_s,
"native resource identifier");
}
add(kind, name);
}
ResourceIdentifier(
const ResourceIdentifier::relative_resource& relative_resource)
{
if (!APPUTILSResourceIdentifier_initialize(&native_)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_INIT_FAILURE_s,
"native resource identifier");
}
add(relative_resource);
}
ResourceIdentifier& parse(const std::string& formatted_uri)
{
if (!APPUTILSResourceIdentifier_parse_formatted_identifier(
&native_,
formatted_uri.c_str())) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_SERVICE_LOG_MALFORMED_RESOURCE_IDENTIFIER_s,
formatted_uri.c_str());
}
return *this;
}
~ResourceIdentifier()
{
APPUTILSResourceIdentifier_finalize(&native_);
}
iterator last() const
{
return iterator(APPUTILSResourceIdentifier_get_resource(
const_cast<native_type*> (&native_)));
}
iterator end() const
{
return iterator::nil();
}
iterator begin() const
{
iterator last = this->last();
if (last != end()) {
return last.begin();
}
return last;
}
ResourceIdentifier parent() const
{
ResourceIdentifier parent_id;
iterator it = begin();
for (; it != last(); ++it) {
parent_id += ResourceIdentifier(it.kind(), it.name());
}
return parent_id;
}
std::string fully_qualified_name() const
{
const auto result = APPUTILSResourceIdentifier_get_fully_qualified_name(
const_cast<native_type *>(&native_));
return (result == nullptr) ? "" : result;
}
std::string fully_qualified_kind() const
{
const auto result = APPUTILSResourceIdentifier_get_fully_qualified_kind(
const_cast<native_type *>(&native_));
return (result == nullptr) ? "" : result;
}
std::string custom_method() const
{
const auto result = APPUTILSResourceIdentifier_get_custom_method(
const_cast<native_type *>(&native_));
return (result == nullptr) ? "" : result;
}
ResourceIdentifier& operator+=(
const ResourceIdentifier& right)
{
return append(right);
}
friend std::ostream& operator<<(
std::ostream& os,
const ResourceIdentifier& resource_id)
{
os << to_string(resource_id);
return os;
}
friend const std::string to_string(
const ResourceIdentifier& resource_id)
{
const char* resource_id_str = to_native_string(resource_id);
if (resource_id_str != NULL) {
return std::string(resource_id_str);
} else {
return std::string("");
}
}
friend const char* to_native_string(
const ResourceIdentifier& resource_id)
{
return APPUTILSResourceIdentifier_to_string(
const_cast<native_type*>(&resource_id.native_));
}
native_type& native() const
{
return const_cast<native_type&>(native_);
}
private:
ResourceIdentifier& add(
const std::string& kind,
const std::string& name = "")
{
if (!APPUTILSResourceIdentifier_add_relative_resource(
&native_,
kind.c_str(),
name.c_str())) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ADD_FAILURE_s,
"relative resource");
}
return *this;
}
ResourceIdentifier& add(
const ResourceIdentifier::relative_resource& relative_resource)
{
add(relative_resource.kind(), relative_resource.name());
return *this;
}
ResourceIdentifier& append(
const ResourceIdentifier& right)
{
ResourceIdentifier::iterator it = right.begin();
for (; it != end(); ++it) {
add(it);
}
return *this;
}
native_type native_;
};
} } /* namespace rti::apputils */
#endif /* HPP_SERVICE_RESOURCE_IDENTIFIER_HPP_ */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,205 @@
/*
* $Id$
*
* (c) Copyright, Real-Time Innovations, 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 HPP_SERVICE_SERVICE_EXCEPTION_HPP_
#define HPP_SERVICE_SERVICE_EXCEPTION_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 <dds/core/types.hpp>
#include <rti/core/Exception.hpp>
namespace rti { namespace apputils {
static
void initialize_exception_message(
std::string& message,
const char *throwing_context,
const RTILogMessage *log_message,
va_list ap)
{
char message_buffer[RTI_LOG_MSG_SIZE_MAX];
RTIOsapiUtility_unusedReturnValue(
RTIOsapiUtility_vsnprintf(
message_buffer,
RTI_LOG_MSG_SIZE_MAX,
log_message->format,
ap),
int);
RTIOsapiUtility_unusedReturnValue(
RTIOsapiUtility_snprintf(
&message[0],
RTI_LOG_MSG_SIZE_MAX,
"%s:%s",
throwing_context,
message_buffer),
int);
}
static
void initialize_exception_message(
std::string& message,
const char *throwing_context,
const RTILogMessageTemplate *log_message,
const char *parameterizedString,
va_list ap)
{
char message_buffer[RTI_LOG_MSG_SIZE_MAX];
const char *SEPARATOR_STR = " | ";
RTIOsapiUtility_unusedReturnValue(
RTIOsapiUtility_vsnprintf(
message_buffer,
RTI_LOG_MSG_SIZE_MAX,
parameterizedString,
ap),
int);
RTIOsapiUtility_unusedReturnValue(
RTIOsapiUtility_snprintf(
&message[0],
RTI_LOG_MSG_SIZE_MAX,
"%s%s%s:%s",
throwing_context,
log_message->format,
strlen(log_message->format) > 0 ? SEPARATOR_STR : "",
message_buffer),
int);
}
/**
* @brief Exception class for Services
*/
class ServiceException : public std::exception {
public:
ServiceException(
const char *throwing_context,
const RTILogMessage *log_message,
...)
: message_(RTI_LOG_MSG_SIZE_MAX, '\0'),
message_id_(log_message->messageId)
{
va_list ap;
va_start(ap, log_message);
initialize_exception_message(
message_,
throwing_context,
log_message,
ap);
va_end(ap);
}
ServiceException(
const char *throwing_context,
const RTILogMessageTemplate *log_message,
const char *parameterizedString,
...)
: message_(RTI_LOG_MSG_SIZE_MAX, '\0'),
message_id_(log_message->messageId)
{
va_list ap;
va_start(ap, parameterizedString);
initialize_exception_message(
message_,
throwing_context,
log_message,
parameterizedString,
ap);
va_end(ap);
}
uint32_t message_id() const
{
return message_id_;
}
virtual const char* what() const throw ()
{
return message_.c_str();
}
virtual ~ServiceException() throw ()
{
}
private:
ServiceException() : message_id_(0u)
{
}
std::string message_;
std::uint32_t message_id_;
};
/**
* @brief Fatal exception class for Services. This exception will cause
* the underlying service to call the shutdown hook.
*/
class FatalServiceException : public ServiceException {
public:
template <typename... Args>
FatalServiceException(
const char *throwing_context,
const RTILogMessage *log_message,
Args... args)
: ServiceException(throwing_context, log_message, args...)
{ }
template <typename... Args>
FatalServiceException(
const char *throwing_context,
const RTILogMessageTemplate *log_message,
const char *parameterizedString,
Args... args)
: ServiceException(
throwing_context,
log_message,
parameterizedString,
args...)
{ }
virtual ~FatalServiceException() throw()
{ }
};
} } /* namespace rti::apputils */
#define RTI_THROW_SERVICE_EXCEPTION(...) \
throw rti::apputils::ServiceException(\
RTI_FUNCTION_NAME,\
__VA_ARGS__)
#define RTI_THROW_FATAL_SERVICE_EXCEPTION(...) \
throw rti::apputils::FatalServiceException(\
RTI_FUNCTION_NAME,\
__VA_ARGS__)
#define RTI_SERVICE_CHECK_CONDITION(EXPRESSION) \
if(!(EXPRESSION)) { \
RTI_THROW_SERVICE_EXCEPTION( \
&RTI_LOG_ANY_s, \
__FILE__ ":" RTI_TOSTRING(__LINE__) ": condition failed: " #EXPRESSION); \
}
#define RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(EXPRESSION, EXTRA_INFO) \
if(!(EXPRESSION)) { \
RTI_THROW_SERVICE_EXCEPTION( \
&RTI_LOG_ANY_ss, \
__FILE__ ":" RTI_TOSTRING(__LINE__) ": condition failed: " #EXPRESSION ", ", \
EXTRA_INFO); \
}
#endif /* HPP_SERVICE_SERVICE_EXCEPTION_HPP_ */
@@ -0,0 +1,295 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 STRING_BUFFER_HPP
#define STRING_BUFFER_HPP
#include "rti/apputils/ServiceException.hpp"
namespace rti { namespace apputils {
// Default value of a StringBuffer
constexpr size_t STRING_BUFFER_LENGTH = 1000;
/**
* A GenericStringBuffer is a smart buffer that allocates an INITIAL_CAPACITY
* in the stack and allocates more capacity in the heap if needed. The template
* parameter INITIAL_CAPACITY determines the capacity that is allocated in the
* stack. In case there is a resize which involves heap allocation, the
* destructor of the GenericStringBuffer class frees the memory.
*/
template <std::size_t INITIAL_CAPACITY>
class GenericStringBuffer {
public:
/**
* This constructor creates a new empty GenericStringBuffer with
* INITIAL_CAPACITY.
*/
GenericStringBuffer() : capacity_(INITIAL_CAPACITY), c_str_ptr_(nullptr)
{
RTIOsapiMemory_zero(c_str_, capacity_);
c_str_ptr_ = c_str_;
}
/**
* This constructor creates a new GenericStringBuffer ensuring the size
* of the input parameter. It allocates memory in the heap if necessary.
* @param size Size to ensure.
*/
GenericStringBuffer(const size_t size)
: capacity_(INITIAL_CAPACITY), c_str_ptr_(nullptr)
{
RTIOsapiMemory_zero(c_str_, capacity_);
c_str_ptr_ = c_str_;
ensure_capacity(size);
}
/**
* This constructor creates a new GenericStringBuffer object containing
* an input string. It ensures whatever capacity is necessary for the input
* string.
* @param str std::string that initializes the GenericStringBuffer.
*/
GenericStringBuffer(const std::string& str)
: capacity_(INITIAL_CAPACITY), c_str_ptr_(nullptr)
{
RTIOsapiMemory_zero(c_str_, capacity_);
c_str_ptr_ = c_str_;
ensure_capacity(str.length() + 1);
RTIOsapiUtility_unusedReturnValue(
RTIOsapiUtility_strcpy(c_str_ptr_, str.length(), str.c_str()),
char *);
}
/**
* Copy constructor.
* @param other String buffer that we want to copy
*/
GenericStringBuffer(const GenericStringBuffer& other)
: capacity_(INITIAL_CAPACITY), c_str_ptr_(nullptr)
{
RTIOsapiMemory_zero(c_str_, capacity_);
c_str_ptr_ = c_str_;
ensure_capacity(other.length() + 1);
RTIOsapiUtility_unusedReturnValue(
RTIOsapiUtility_strcpy(
c_str_ptr_,
other.length(),
other.c_str()),
char *);
}
/**
* Move constructor.
* @param other String buffer that we want to move
*/
GenericStringBuffer(GenericStringBuffer&& other)
: capacity_(INITIAL_CAPACITY), c_str_ptr_(nullptr)
{
*this = std::move(other);
}
/**
* Destructor of the GenericStringBuffer. It frees whatever memory may
* have been allocated by the ensure_capacity method().
*/
~GenericStringBuffer()
{
if (capacity_ > INITIAL_CAPACITY) {
DDS_String_free(c_str_ptr_);
c_str_ptr_ = nullptr;
}
}
/**
* Copy-assignment operator
* @param other The buffer we want to copy.
* @return Object in which we have copied.
*/
GenericStringBuffer& operator=(const GenericStringBuffer& other)
{
if (this != &other) {
ensure_capacity(other.length() + 1);
RTIOsapiUtility_unusedReturnValue(
RTIOsapiUtility_strcpy(
c_str_ptr_,
other.length(),
other.c_str()),
char *);
}
return *this;
}
/**
* Move-assignment operator
* @param other The buffer we want to move.
* @return Object in which we have moved.
*/
GenericStringBuffer& operator=(GenericStringBuffer&& other)
{
if (this != &other) {
if (other.capacity_ <= INITIAL_CAPACITY) {
RTIOsapiMemory_move(c_str_, other.c_str_, INITIAL_CAPACITY);
c_str_ptr_ = c_str_;
} else {
capacity_ = other.capacity_;
c_str_ptr_ = other.c_str_ptr_;
other.capacity_ = INITIAL_CAPACITY;
other.c_str_ptr_ = nullptr;
}
}
return *this;
}
/**
* Returns the number of bytes that can be written in the internal char *
* buffer
* @return Capacity of the internal char * buffer.
*/
size_t capacity() const
{
return capacity_;
}
/**
* Returns the length of the internal char * buffer. That is the strlen
* of whatever is in there.
* @return Size of the string stored in the internal char * buffer.
*/
size_t length() const
{
return strlen(c_str_ptr_);
}
/**
* Returns a const pointer to the internal char * buffer.
* @return Const pointer to the internal char * buffer.
*/
const char *c_str() const
{
return c_str_ptr_;
}
/**
* Returns a pointer to the internal char * buffer
* @return Pointer to the internal char * buffer.
*/
char *c_str_ptr()
{
return c_str_ptr_;
}
/**
* This method ensures a capacity by either asserting that the
* GenericStringBuffer has enough space to allocate a string, or
* reallocating some space in the heap. If that is the case more space is
* allocated in the heap via DDS_String_alloc().
* @param capacity Size that needs to be ensured.
*/
void ensure_capacity(const size_t capacity)
{
if (capacity > capacity_) {
// We need to free the string if it was already allocated, this
// happens when _capacity > INITIAL_CAPACITY
if (capacity_ > INITIAL_CAPACITY) {
DDS_String_free(c_str_ptr_);
}
// DDS_String_alloc adds one to the input parameter. We could
// spare a byte, but we want to be precise.
c_str_ptr_ = DDS_String_alloc(capacity - 1);
if (c_str_ptr_ == nullptr) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_FAILURE_s,
"Error allocating string.");
}
RTIOsapiMemory_zero(c_str_ptr_, capacity_);
capacity_ = capacity;
}
}
private:
size_t capacity_;
char *c_str_ptr_;
char c_str_[INITIAL_CAPACITY];
};
/**
* A StringBuffer is a GenericStringBuffer with an initial STRING_BUFFER_LENGTH.
*/
typedef GenericStringBuffer<STRING_BUFFER_LENGTH> StringBuffer;
/**
* This method saves a "freeform string" into a StringBuffer object.
* @param [in,out] string_buffer StringBuffer in which the input string will
* be saved. Note that if there's not enough capacity, the method will
* automatically allocate more space for the string.
* @param format Format of the string to be saved.
* @param ... Parameters to the formatted string.
*/
inline void StringBuffer_save_freeform(
StringBuffer& string_buffer,
const char *format,
...)
{
char *c_str_ptr = string_buffer.c_str_ptr();
size_t capacity = string_buffer.capacity();
va_list args, args_aux;
RTIXMLSaveContext save_ctxt = RTIXMLSaveContext_INITIALIZER;
RTIXMLSaveContext_initialize(&save_ctxt);
save_ctxt.sout = c_str_ptr;
if (!RTIOsapiUtility_sizeToUInt32(save_ctxt.ssize, capacity)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_FAILURE_s,
"Error allocating string.");
}
// Wrap RTIXMLSaveContext_freeform_w_argsI call with va_start and va_end
// of the va_list that we need to pass in.
va_start(args, format);
va_start(args_aux, format);
RTIXMLSaveContext_freeform_v(&save_ctxt, format, args, args_aux);
va_end(args);
va_end(args_aux);
if (save_ctxt.outputStringLength + 1 > capacity) {
capacity = save_ctxt.outputStringLength + 1;
string_buffer.ensure_capacity(capacity);
RTIXMLSaveContext_initialize(&save_ctxt);
save_ctxt.sout = string_buffer.c_str_ptr();
if (!RTIOsapiUtility_sizeToUInt32(save_ctxt.ssize, capacity)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_FAILURE_s,
"Error allocating string.");
}
// Wrap RTIXMLSaveContext_freeform_w_argsI call with va_start and
// va_end of the va_list that we need to pass in.
va_start(args, format);
va_start(args_aux, format);
RTIXMLSaveContext_freeform_v(&save_ctxt, format, args, args_aux);
va_end(args);
va_end(args_aux);
}
}
}} // namespace rti::apputils
#endif // STRING_BUFFER_HPP
@@ -0,0 +1,355 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 HTTP_CLIENT_CONNECTION_HPP
#define HTTP_CLIENT_CONNECTION_HPP
#include <array>
#include <chrono>
#include <memory>
#include <string>
#include <thread>
#include <civetweb.h>
#include "rti/apputils/ServiceException.hpp"
#include "rti/apputils/http/common/Response.hpp"
#include "rti/apputils/http/common/HttpUtils.hpp"
#include "rti/apputils/http/log/Log.hpp"
#include "Request.hpp"
namespace rti { namespace apputils { namespace http { namespace client {
/**
* @brief This class is a wrapper around the SSL configuration for the client.
*
*/
struct SslConfig {
SslConfig(
bool the_enabled = false,
std::string the_client_cert = "",
std::string the_server_cert = "")
: enabled(the_enabled),
client_cert(the_client_cert),
server_cert(the_server_cert)
{ }
bool enabled;
std::string client_cert;
std::string server_cert;
};
/**
* @brief This class deal with actual HTTP client requests and
* responses to and from CivetWeb.
*/
class Connection {
public:
/**
* @brief Construct a new Connection object Note that since every request
* reconnects the connection, we do not need to connect in the constructor
* itself.
*
* @param host Hostname of the server
* @param port Port of the server
* @param ssl_config SSL configuration for the client
*/
Connection(
const std::string& host = std::string("localhost"),
std::uint16_t port = HTTP_SERVER_DEFAULT_PORT,
SslConfig ssl_config = SslConfig())
: host_ { host }, port_ { port }, ssl_config_ { ssl_config }
{ }
/**
* @brief send an actual HTTP request to CivetWeb. It extracts all
* the information from the request and constructs a valid HTTP request
* string.
*
* @param request HTTP request to be sent to the server.
*/
void send_http_request(const Request& request)
{
connect();
// Send HTTP method and URL
auto mg_result = mg_printf(
connection_.get(),
"%s %s",
method_to_string(request.http_method()).c_str(),
request.uri());
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result > 0,
msg_client_error_printf);
// Add URL params to URL
if (request.uri_parameters().size() > 0) {
mg_result = mg_printf(connection_.get(), "?");
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result > 0,
msg_client_error_printf);
for (const auto& uri_param : request.uri_parameters()) {
std::array<char, MAX_URI_LENGTH> uri_param_value;
uri_param_value.fill('\0');
// We need to encode the URI params in case they contain
// spaces or any other character that may not be valid in a
// URL
mg_result = mg_url_encode(
uri_param.second.c_str(),
uri_param_value.data(),
MAX_URI_LENGTH);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result > 0,
msg_client_error_url_encode);
mg_result = mg_printf(
connection_.get(),
"%s=%s&",
uri_param.first.c_str(),
uri_param_value.data());
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result > 0,
msg_client_error_printf);
}
}
// Specify HTTP version
mg_result = mg_printf(connection_.get(), " HTTP/%s\r\n", HTTP_VERSION);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result > 0,
msg_client_error_printf);
// Add user-defined headers
for (const auto& header : request.headers()) {
mg_result = mg_printf(
connection_.get(),
"%s: %s\r\n",
header.first.c_str(),
header.second.c_str());
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result > 0,
msg_client_error_printf);
}
// Add default headers if not defined
if (request.header("Content-Length") == nullptr) {
mg_result = mg_printf(
connection_.get(),
"Content-Length: %llu\r\n",
static_cast<unsigned long long>(request.body().length()));
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result > 0,
msg_client_error_printf);
}
if (request.header("Content-Type") == nullptr) {
mg_result = mg_printf(
connection_.get(),
"Content-Type: %s\r\n",
HTTP_PLAIN_TEXT_CONTENT_TYPE);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result > 0,
msg_client_error_printf);
}
if (request.header("Cache-Control") == nullptr) {
mg_result = mg_printf(
connection_.get(),
"Cache-Control: %s\r\n",
HTTP_CACHE_CONTROL_NO_CACHE);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result > 0,
msg_client_error_printf);
}
if (request.header("Date") == nullptr) {
mg_result = mg_printf(
connection_.get(),
"Date: %s\r\n",
HttpSettings::get_current_date().c_str());
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result > 0,
msg_client_error_printf);
}
// Separate headers from body
mg_result = mg_printf(connection_.get(), "\r\n");
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result > 0,
msg_client_error_printf);
// Send body of the HTTP request -- if empty it will not write anything
mg_result = mg_printf(connection_.get(), "%s", request.body().c_str());
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result >= 0,
msg_client_error_printf);
}
/**
* @brief returns a Response based on the actual HTTP response received from
* CivetWeb. It extracts all the information originally stored in the
* mg_connection and transforms it into a valid Response object.
*
* @param timeout Number of milliseconds to wait for a response. A negative
* value means wait indefinitely.
*
* @return Response object with the response from CivetWeb.
*/
Response get_http_response(int timeout = HTTP_CLIENT_TIMEOUT_MS)
{
std::array<char, HTTP_BODY_INITIAL_LENGTH> error_buffer;
error_buffer[0] = '\0';
// Get CivetWeb's response.
const auto result = mg_get_response(
connection_.get(),
error_buffer.data(),
error_buffer.size(),
timeout);
// If we timeout trying to get the response, throw an exception.
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
result >= 0,
error_buffer.data());
// Convert CivetWeb's response into a Response
const mg_response_info *response_info =
mg_get_response_info(connection_.get());
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
response_info != nullptr,
msg_client_error_get_response_info);
return Response {
static_cast<unsigned short>(response_info->status_code),
response_info->status_text,
[&] {
const auto header =
mg_get_header(connection_.get(), "Content-Type");
return (header == nullptr) ? "" : header;
}(),
this->read_content(),
[&] {
std::unordered_map<std::string, std::string> headers;
for (int i = 0; i < response_info->num_headers; ++i) {
headers.emplace(
response_info->http_headers[i].name,
response_info->http_headers[i].value);
}
return headers;
}()
};
}
std::string read_content(std::size_t chunk_size = 256)
{
const auto response_info = mg_get_response_info(connection_.get());
if (response_info == nullptr) {
RTI_THROW_HTTP_EXCEPTION(
StatusCode::internal_server_error,
&RTI_LOG_ANY_FAILURE_s,
"Error reading content");
}
if (response_info->content_length >= 0) {
return read_content_with_content_length(
connection_.get(),
static_cast<std::size_t>(response_info->content_length));
}
return read_content_without_content_length(
connection_.get(),
chunk_size);
}
private:
/**
* @brief time we connect, we reset the mg_connection. This ensures
* that CivetWeb's internal buffers and state is cleaned up. This makes
* the Connection easier to use, since it does not need
* to be reconnected with every unit test run.
*/
void connect()
{
std::array<char, HTTP_BODY_INITIAL_LENGTH> error_buffer;
error_buffer[0] = 0;
if (ssl_config_.enabled) {
mg_client_options client_options = create_client_options();
connection_.reset(mg_connect_client_secure(
&client_options,
error_buffer.data(),
HTTP_BODY_INITIAL_LENGTH));
} else {
connection_.reset(mg_connect_client(
host_.c_str(),
port_,
ssl_config_.enabled,
error_buffer.data(),
HTTP_BODY_INITIAL_LENGTH));
}
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
connection_ != nullptr || error_buffer[0] == 0,
error_buffer.data());
}
/**
* @brief This method closes any existing connection.
*/
struct Disconnect {
void operator()(mg_connection *connection) const
{
mg_close_connection(connection);
}
};
/**
* @brief This method create a new mg_client_options object with the
* information provided by the user.
*/
mg_client_options create_client_options()
{
mg_client_options client_options;
client_options.host = host_.c_str();
client_options.port = port_;
client_options.client_cert =
(ssl_config_.client_cert.empty() || !ssl_config_.enabled)
? nullptr
: ssl_config_.client_cert.c_str();
client_options.server_cert =
(ssl_config_.server_cert.empty() || !ssl_config_.enabled)
? nullptr
: ssl_config_.server_cert.c_str();
client_options.host_name =
!ssl_config_.enabled ? nullptr : client_options.host;
return client_options;
}
private:
std::unique_ptr<mg_connection, Disconnect> connection_;
std::string host_;
std::uint16_t port_;
SslConfig ssl_config_;
};
}}}} // namespace rti::apputils::http::client
#endif // HTTP_CLIENT_CONNECTION_HPP
@@ -0,0 +1,202 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 HTTP_CLIENT_REQUEST_HPP
#define HTTP_CLIENT_REQUEST_HPP
#include <array>
#include <string>
#include <cassert>
#include <cstring>
#include "rti/apputils/http/common/Method.hpp"
#include "rti/apputils/http/common/HttpUtils.hpp"
namespace rti { namespace apputils { namespace http { namespace client {
/**
* @brief Request class allow users to define their own requests in order to
* send them to the server trough the Connection class.
*/
class Request {
public:
/**
* @brief Construct a new Request empty object
*/
Request()
{
uri_.fill('\0');
}
/**
* @brief Getter for the HTTP method.
*
* @return Method object associated to the request.
*/
Method http_method() const
{
return http_method_;
}
/**
* @brief Setter for the HTTP method.
*
* @param http_method HTTP method (POST, PUT, GET, DELETE, HEAD, PATCH,
* OPTIONS).
* @return Reference to the Request object.
*/
Request& http_method(Method http_method)
{
http_method_ = http_method;
return *this;
}
/**
* @brief Gets the URL of the HTTP request.
*
* @return URL of the HTTP request.
*/
const char *uri() const
{
return uri_.data();
}
/**
* @brief Sets the URL of the HTTP request.
*
* @param uri URL of the HTTP request.
* @return Reference to the Request object.
*/
Request& uri(const char *uri)
{
std::copy(uri, uri + std::strlen(uri), uri_.data());
return *this;
}
/**
* @brief Sets the URL of the HTTP request.
*
* @param uri URL of the HTTP request.
* @return Reference to the Request object.
*/
Request& uri(const std::string& uri)
{
return this->uri(uri.c_str());
}
/**
* @brief Gets the value of an uri parameter.
*
* @param name Name of the parameter.
* @return const std::string*
*/
const std::string *uri_parameter(const std::string& name) const
{
const auto it = uri_parameters_.find(name);
if (it == uri_parameters_.end()) {
return nullptr;
}
return &it->second;
}
/**
* @brief Gets all the uri parameters.
*
* @return const StringMap&
*/
const StringMap& uri_parameters() const
{
return uri_parameters_;
}
/**
* @brief Sets all the uri parameters.
*
* @param uri_parameters StringMap with all the uri parameters.
* @return Request&
*/
Request& uri_parameters(const StringMap& uri_parameters)
{
uri_parameters_ = uri_parameters;
return *this;
}
/**
* @brief Gets the value of a header.\
*
* @param name Name of the parameter.
* @return const std::string*
*/
const std::string *header(const std::string& name) const
{
const auto it = headers_.find(name);
if (it == headers_.end()) {
return nullptr;
}
return &it->second;
}
/**
* @brief Gets all the headers.
*
* @return const StringMap&
*/
const StringMap& headers() const
{
return headers_;
}
/**
* @brief Sets all the headers.
*
* @param headers StringMap with all the headers.
* @return Request&
*/
Request& headers(const StringMap& headers)
{
headers_ = headers;
return *this;
}
/**
* @brief Gets the body of the request.
*
* @return const std::string&
*/
const std::string& body() const
{
return body_;
}
/**
* @brief Sets the body of the request.
*
* @param body Body of the request.
* @return Request&
*/
Request& body(const std::string& body)
{
body_ = body;
return *this;
}
private:
Method http_method_ = Method::http_get;
std::array<char, MAX_URI_LENGTH> uri_;
StringMap uri_parameters_;
StringMap headers_;
std::string body_;
};
}}}} // namespace rti::apputils::http::client
#endif // HTTP_CLIENT_REQUEST_HPP
@@ -0,0 +1,177 @@
/*
* (c) Copyright, Real-Time Innovations, 2020.
* 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 CIVETWEBSOCKET_TEST_CONNECTION_CLIENT_H
#define CIVETWEBSOCKET_TEST_CONNECTION_CLIENT_H
#include <memory>
#include <mutex>
#include "civetweb.h"
#include <queue>
#include <rti/apputils/http/server/CivetWebSocketConnection.hpp>
#include <rti/apputils/log/LogConfig.hpp>
#include "log/LogMsg.hpp"
// #include "utils/WebDDSUtils.h"
#define CIVETWEB_CLIENT_TIMEOUT_MS 1000
#define WEBSOCKET_ERROR_BUFFER_SIZE 10000
#define WEBSOCKETinput_buffer__SIZE 10000
#define WEBSERVER_DEFAULT_PORT 19020
namespace rti { namespace apputils { namespace http { namespace client {
namespace test {
class CivetWebSocketClient {
public:
~CivetWebSocketClient()
{
mg_close_connection(conn_);
}
static int websocket_client_data_handler(
struct mg_connection * /*conn*/,
int flags,
char *data,
size_t data_len,
void *user_data)
{
CivetWebSocketClient *user = NULL;
if (user_data == NULL) {
SERVICELog_exception(
&RTI_LOG_ANY_FAILURE_s,
"No user data defined");
return 1;
}
switch (((unsigned) flags & 0xFu)) {
case MG_WEBSOCKET_OPCODE_TEXT:
user = reinterpret_cast<CivetWebSocketClient *>(user_data);
user->receive(std::string(data, data_len));
break;
default:
SERVICELog_exception(
&RTI_LOG_ANY_FAILURE_s,
"The websocket message code received is not recognize");
break;
}
return 1;
}
static void websocket_client_close_handler(
const struct mg_connection *conn,
void *user_data)
{
struct mg_context *context = mg_get_context(conn);
if (user_data == NULL) {
SERVICELog_exception(
&RTI_LOG_ANY_FAILURE_s,
"No user data defined");
return;
}
mg_lock_context(context);
mg_set_user_connection_data((struct mg_connection *) conn, NULL);
mg_unlock_context(context);
}
static std::shared_ptr<CivetWebSocketClient> connect(
const char *host = "localhost",
int port = WEBSERVER_DEFAULT_PORT,
bool use_ssl = false,
const char *path = "/dds/websocket/test")
{
StringBuffer error_buffer(WEBSOCKET_ERROR_BUFFER_SIZE);
auto result = std::make_shared<CivetWebSocketClient>();
struct mg_connection *conn = mg_connect_websocket_client(
host,
port,
use_ssl,
(char *) error_buffer.c_str_ptr(),
WEBSOCKET_ERROR_BUFFER_SIZE,
path,
NULL,
websocket_client_data_handler,
websocket_client_close_handler,
result.get());
if (conn == NULL) {
SERVICELog_exception(&RTI_LOG_ANY_FAILURE_s, "No Connection");
result.reset();
return result;
}
result->connection(conn);
return result;
}
public:
CivetWebSocketClient() = default;
CivetWebSocketClient(mg_connection *conn)
: conn_(conn)
{ }
void send(const StringBuffer& msg)
{
mg_websocket_client_write(
conn_,
MG_WEBSOCKET_OPCODE_TEXT,
msg.c_str(),
msg.length());
}
void request_close()
{
mg_websocket_client_write(
conn_,
MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE,
NULL,
0);
}
void receive(const StringBuffer& buffer)
{
std::lock_guard<std::recursive_mutex> guard(mutex_);
received_buffer_.push(buffer);
}
bool buffer(StringBuffer& buffer)
{
std::lock_guard<std::recursive_mutex> guard(mutex_);
bool received = false;
if (!received_buffer_.empty()) {
buffer = received_buffer_.front();
received_buffer_.pop();
received = true;
}
return received;
}
void connection(mg_connection *conn)
{
conn_ = conn;
}
private:
mg_connection *conn_ = nullptr;
std::queue<StringBuffer> received_buffer_;
std::recursive_mutex mutex_;
};
}}}}} // namespace rti::apputils::http::client::test
#endif
@@ -0,0 +1,74 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 HTTP_EXCEPTION_HPP
#define HTTP_EXCEPTION_HPP
// RTI headers
#include "rti/apputils/http/common/StatusCode.hpp"
#include "rti/apputils/ServiceException.hpp"
namespace rti { namespace apputils { namespace http {
/**
* @brief Exception class for HTTP errors that inherit from ServiceException
*/
class HttpException : public ServiceException {
public:
/**
* @brief Constructor
*
* @param throwing_context The context where the exception was thrown
* @param status_code HTTP status code
* @param log_message RTILog message (it could be a format string)
*/
template <typename... Args>
HttpException(
const char *throwing_context,
StatusCode error_code,
const RTILogMessage *log_message,
Args... args)
: ServiceException(throwing_context, log_message, args...),
error_code_(error_code)
{ }
/**
* @brief Constructor
*
* @param ServiceException Service Exception to build the HttpException
* @param status_code HTTP status code
*/
HttpException(
const ServiceException& e,
StatusCode error_code)
: ServiceException(e),
error_code_(error_code)
{ }
/**
* @brief Get the HTTP status code
*
* @return HTTP status code
*/
StatusCode error_code() const
{
return error_code_;
}
private:
StatusCode error_code_;
};
}}} // namespace rti::apputils::http
#define RTI_THROW_HTTP_EXCEPTION(...) \
throw rti::apputils::http::HttpException(RTI_FUNCTION_NAME, __VA_ARGS__)
#endif // HTTP_EXCEPTION_HPP
@@ -0,0 +1,167 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 HTTP_UTILS_H
#define HTTP_UTILS_H
#include <ctime>
#include <cstring>
#include <unordered_map>
#include <civetweb.h>
#include <reda/reda_string.h>
#include <dds_c/dds_c_printformat.h>
#include "HttpException.hpp"
#include "StatusCode.hpp"
namespace rti { namespace apputils { namespace http {
using StringMap = std::unordered_map<std::string, std::string>;
// Unfortunately Civetweb doesn't expose these constants, so we needed to
// copy the values from civetweb.c (static struct mg_option config_options[])
constexpr auto HTTP_CLIENT_TIMEOUT_MS = int { 1000 };
constexpr auto HTTP_SERVER_DEFAULT_PORT = int { 8080 };
constexpr auto HTTP_SERVER_DEFAULT_PORT_STR = "8080";
constexpr auto HTTP_SERVER_DEFAULT_HOST = "127.0.0.1";
constexpr auto HTTP_VERSION = "1.1";
constexpr auto HTTP_CACHE_CONTROL_NO_CACHE = "no-cache";
constexpr auto HTTP_BODY_INITIAL_LENGTH = std::size_t { 1000 };
constexpr auto HTTP_PLAIN_TEXT_CONTENT_TYPE = "text/plain";
constexpr auto HTTP_JSON_CONTENT_TYPE = "application/json";
constexpr auto HTTP_XML_CONTENT_TYPE = "application/xml";
constexpr auto HTTP_CONTENT_TYPE_HEADER = "Content-Type";
constexpr auto HTTP_DATE_STR_LENGTH = std::size_t { 64 };
/**
* Maximum URL length we handle is 2048. This value is based on the
* comments on this article http://stackoverflow.com/questions/417142
*/
constexpr auto MAX_URI_LENGTH = int { 2048 };
/**
* @brief This structure contains utility methods to generate HttpSettings that
* need to be set as part of the HTTP response.
*/
struct HttpSettings {
/**
* @brief This method converts time_t to a string. According to RFC2616,
* Sec 14.18, this must be included in all responses other than
* 100, 101, 5xx.
*
* @return A string containing the date in the format specified by RFC2616.
*/
static std::string get_current_date()
{
const auto curtime = std::time(nullptr);
if (curtime == (time_t) -1) {
return "Thu, 01 Jan 1970 00:00:00 GMT";
}
struct tm curr_tm;
#ifdef RTI_WIN32
if (gmtime_s(&curr_tm, &curtime) != 0) {
return "Thu, 01 Jan 1970 00:00:00 GMT";
}
#else
if (gmtime_r(&curtime, &curr_tm) != &curr_tm) {
return "Thu, 01 Jan 1970 00:00:00 GMT";
}
#endif
auto result = std::string(HTTP_DATE_STR_LENGTH, '\0');
const auto bytes_written = std::strftime(
&result[0],
result.size(),
"%a, %d %b %Y %H:%M:%S GMT",
&curr_tm);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
bytes_written > 0,
"Error in std::strftime");
result.resize(bytes_written);
return result;
}
};
inline std::string read_content_with_content_length(
mg_connection *connection,
std::size_t content_length)
{
auto content = std::string(content_length, 0);
auto result = 0;
while (content_length > 0 && result >= 0) {
result = mg_read(connection,
&content[content.size() - content_length],
content_length);
content_length -= result;
}
return content;
}
inline std::string read_content_without_content_length(
mg_connection *connection,
std::size_t chunk_size = 256)
{
auto content = std::string();
auto bytes_read = std::size_t { 0 };
auto result = 0;
do {
bytes_read += result;
content.resize(bytes_read + chunk_size);
result = mg_read(connection, &content[bytes_read], chunk_size);
} while (result > 0);
content.resize(bytes_read);
return content;
}
inline std::string base64_encode(const std::string& in)
{
std::string out;
out.reserve(in.size() * 2);
const char *b64 =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (std::size_t i = 0; i < in.size(); i += 3) {
// Static cast to unsigned char to avoid cert_str34_c_violation
int a = static_cast<unsigned char>(in[i]);
int b = i + 1 >= in.size() ? 0 : static_cast<unsigned char>(in[i + 1]);
int c = i + 2 >= in.size() ? 0 : static_cast<unsigned char>(in[i + 2]);
out.push_back(b64[a >> 2]);
out.push_back(b64[((a & 3) << 4) | (b >> 4)]);
if (i + 1 < in.size()) {
out.push_back(b64[(b & 15) << 2 | (c >> 6)]);
}
if (i + 2 < in.size()) {
out.push_back(b64[c & 63]);
}
}
while (out.size() % 4 != 0) {
out.push_back('=');
}
out.shrink_to_fit();
return out;
}
}}} // namespace rti::apputils::http
#endif // HTTP_UTILS_H
@@ -0,0 +1,96 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 HTTP_METHOD_HPP
#define HTTP_METHOD_HPP
#include <string>
#include "rti/apputils/http/common/HttpException.hpp"
namespace rti {
namespace apputils { namespace http {
/**
* Enum class with every HTTP method
*/
enum class Method {
http_post,
http_put,
http_get,
http_delete,
http_options,
http_head,
http_patch
};
/**
* @brief Convert a Method enum to an std::string
*
* @param http_method Method enum to convert
* @return std::string with the method name
*/
inline std::string method_to_string(Method http_method)
{
switch (http_method) {
case Method::http_post:
return "POST";
case Method::http_put:
return "PUT";
case Method::http_get:
return "GET";
case Method::http_delete:
return "DELETE";
case Method::http_options:
return "OPTIONS";
case Method::http_head:
return "HEAD";
case Method::http_patch:
return "PATCH";
default:
RTI_THROW_HTTP_EXCEPTION(
StatusCode::bad_request,
&RTI_LOG_ANY_FAILURE_s,
"Invalid HTTP method");
}
}
/**
* @brief Convert a std::string to a Method enum
*
* @param http_method String to convert
* @return Method enum
*/
inline Method method_from_string(const std::string& http_method)
{
if (http_method == "POST") {
return Method::http_post;
} else if (http_method == "PUT") {
return Method::http_put;
} else if (http_method == "GET") {
return Method::http_get;
} else if (http_method == "DELETE") {
return Method::http_delete;
} else if (http_method == "OPTIONS") {
return Method::http_options;
} else if (http_method == "HEAD") {
return Method::http_head;
} else if (http_method == "PATCH") {
return Method::http_patch;
} else {
RTI_THROW_HTTP_EXCEPTION(
StatusCode::bad_request,
&RTI_LOG_ANY_FAILURE_s,
"Invalid HTTP method");
}
}
}}} // namespace rti::apputils::http
#endif // HTTP_METHOD_HPP
@@ -0,0 +1,51 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 HTTP_RESPONSE_HPP
#define HTTP_RESPONSE_HPP
#include <string>
#include <unordered_map>
namespace rti { namespace apputils { namespace http {
/**
* @brief This class contains all the elements involved in an HTTP response
*/
struct Response {
/**
* Response's status code
*/
unsigned short http_status_code;
/**
* Response's reason phrase
*/
std::string http_reason_phrase;
/**
* Response's content type
*/
std::string http_content_type;
/**
* Response's body
*/
std::string http_content;
/**
* Response's headers as a map
*/
std::unordered_map<std::string, std::string> http_headers;
};
}}} // namespace rti::apputils::http
#endif // HTTP_RESPONSE_HPP
@@ -0,0 +1,90 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 HTTP_STATUS_CODE_HPP
#define HTTP_STATUS_CODE_HPP
#include <string>
namespace rti { namespace apputils { namespace http {
/**
* @brief Enum class with HTTP status codes.
*/
enum class StatusCode {
ok = 200,
created = 201,
accepted = 202,
no_content = 204,
multiple_choices = 300,
moved_permanently = 301,
moved_temporarily = 302,
not_modified = 304,
bad_request = 400,
unauthorized = 401,
forbidden = 403,
not_found = 404,
not_allowed = 405,
internal_server_error = 500,
not_implemented = 501,
bad_gateway = 502,
service_unavailable = 503
};
/**
* @brief Convert a StatusCode enum to an std::string
*
* @param status_code StatusCode enum to convert
* @return std::string with the status code name
*/
inline std::string status_code_to_string(StatusCode status_code)
{
switch (status_code) {
case StatusCode::ok:
return "OK";
case StatusCode::created:
return "Created";
case StatusCode::accepted:
return "Accepted";
case StatusCode::no_content:
return "No Content";
case StatusCode::multiple_choices:
return "Multiple Choices";
case StatusCode::moved_permanently:
return "Moved Permanently";
case StatusCode::moved_temporarily:
return "Moved Temporarily";
case StatusCode::not_modified:
return "Not Modified";
case StatusCode::bad_request:
return "Bad Request";
case StatusCode::unauthorized:
return "Unauthorized";
case StatusCode::forbidden:
return "Forbidden";
case StatusCode::not_found:
return "Not Found";
case StatusCode::not_allowed:
return "Not Allowed";
case StatusCode::internal_server_error:
return "Internal Server Error";
case StatusCode::not_implemented:
return "Not Implemented";
case StatusCode::bad_gateway:
return "Bad Gateway";
case StatusCode::service_unavailable:
return "Service Unavailable";
default:
return "";
}
}
}}} // namespace rti::apputils::http
#endif // HTTP_STATUS_CODE_HPP
@@ -0,0 +1,100 @@
/*
* (c) Copyright, Real-Time Innovations, 2024.
* 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 WEBSOCKET_API_UTILS_H_
#define WEBSOCKET_API_UTILS_H_
#include "dds_c/dds_c_printformat.h"
#include <memory>
#include <rti/apputils/http/common/HttpException.hpp>
#define ERR_LOST_HEADER "Lost header"
#define WEBSOCKET_RESPONSE_NAME "response"
#define WEBSOCKET_HELLO_FAIL_HEADER "HELLO FAIL:"
namespace rti { namespace apputils { namespace websocket {
enum class WebSocketStateKind{
UNKNOWN,
CREATE,
OPEN,
READY,
CLOSE
};
enum class WebSocketContentType{
UNKNOWN,
JSON,
XML
};
inline DDS_PrintFormatKind to_print_format_kind(WebSocketContentType contentType) {
return contentType == WebSocketContentType::JSON
? DDS_JSON_PRINT_FORMAT
: DDS_XML_PRINT_FORMAT;
}
inline WebSocketContentType to_websocket_content_type(DDS_PrintFormatKind formatKind) {
WebSocketContentType value = WebSocketContentType::UNKNOWN;
switch (formatKind) {
case DDS_JSON_PRINT_FORMAT:
value = WebSocketContentType::JSON;
break;
case DDS_XML_PRINT_FORMAT:
value = WebSocketContentType::XML;
break;
case DDS_DEFAULT_PRINT_FORMAT:
value = WebSocketContentType::XML;
break;
default:
value = WebSocketContentType::UNKNOWN;
break;
}
return value;
}
/**
* The RequestException class defines a exception will log an error message
* via RTIWsddsLog_exeption or will just propagate a given return code
* identifying the error and an error message. The class inherits from
* Exception, as a result users can use familiar interfaces, such as what() to
* get the error message. Also it have the request id to create the error
* message to be sent.
*/
class RequestException : public rti::apputils::http::HttpException {
public:
RequestException(
const char *throwing_context,
rti::apputils::http::StatusCode error_code,
const RTILogMessage *log_message,
const char *method_name,
...)
: HttpException(throwing_context, error_code, log_message),
method_name_(method_name)
{
}
/**
* Returns the method name that threw the exception.
* @return Method name that threw the exception.
*/
const char * get_method_name() const
{
return method_name_;
}
private:
const char *method_name_;
};
}}} // namespace rti::webdds::websocket
#endif // WEBSOCKET_API_UTILS_H_
@@ -0,0 +1,41 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 HTTP_LOG_HPP
#define HTTP_LOG_HPP
#include "log/log_common.h"
#include "log.peer.h"
#include "apputils/apputils_log.h"
#define APPUTILS_CURRENT_SUBMODULE SUBMODULE_APPUTILS_HTTP
const struct RTILogMessage APPUTILS_LOG_HTTP_EXAMPLE_sss= {
PRODUCT_WAVEWORKS|MODULE_APPUTILS|SUBMODULE_APPUTILS_HTTP|0,
"%s: %s: %s"
};
const struct RTILogMessage APPUTILS_LOG_HTTP_SENT_RESPONSE_us= {
PRODUCT_WAVEWORKS|MODULE_APPUTILS|SUBMODULE_APPUTILS_HTTP|1,
"Sent response %u '%s'\n"
};
constexpr auto msg_client_error_printf = "Client: error at mg_printf";
constexpr auto msg_client_error_url_encode = "Client: error at mg_url_encode";
constexpr auto msg_client_error_get_response_info =
"Client: error at mg_get_response_info";
constexpr auto msg_server_error_printf = "Server: error at mg_printf";
constexpr auto msg_server_error_read = "Server: error at mg_read";
constexpr auto msg_server_error_send_http_error = "Server: error at mg_send_http_error";
constexpr auto msg_server_error_get_request_info = "Server: error at mg_get_request_info";
constexpr auto msg_server_error_get_header = "Server: error at mg_get_header";
#endif // HTTP_UTILS_HPP
@@ -0,0 +1,84 @@
/*
* (c) Copyright, Real-Time Innovations, 2024.
* 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 CIVETWEBSOCKET_CONNECTION_H
#define CIVETWEBSOCKET_CONNECTION_H
#include <civetweb.h>
#include "WebSocketConnection.hpp"
namespace rti { namespace apputils { namespace websocket { namespace civetweb {
class CivetWebSocketConnection : public WebSocketConnection {
public:
explicit CivetWebSocketConnection(struct mg_connection *conn) : conn_(conn)
{
}
void send(const StringBuffer& msg)
{
struct mg_context *context = mg_get_context(conn_);
mg_lock_context(context);
mg_websocket_write(
conn_,
MG_WEBSOCKET_OPCODE_TEXT,
msg.c_str(),
msg.length());
mg_unlock_context(context);
}
void send_pong(const StringBuffer& msg)
{
mg_context *context = mg_get_context(conn_);
mg_lock_context(context);
mg_websocket_write(
conn_,
MG_WEBSOCKET_OPCODE_PONG,
msg.c_str(),
msg.length());
mg_unlock_context(context);
}
bool operator==(WebSocketConnection* conn)
{
return conn_ == static_cast<CivetWebSocketConnection *>(conn)->conn();
}
const struct mg_connection* conn() const
{
return conn_;
}
void close()
{
struct mg_context *context = mg_get_context(conn_);
mg_lock_context(context);
mg_close_connection(conn_);
mg_unlock_context(context);
}
private:
mg_connection* conn_;
};
}}}} // namespace rti::apputils::websocket::civetweb
#endif // CIVETWEBSOCKET_CONNECTION_H
@@ -0,0 +1,292 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 HTTP_SERVER_CONNECTION_HPP
#define HTTP_SERVER_CONNECTION_HPP
#include <CivetServer.h>
#include <civetweb.h>
#include <nlohmann/json.hpp>
#include "rti/apputils/http/common/HttpUtils.hpp"
#include "rti/apputils/http/common/Response.hpp"
#include "rti/apputils/http/log/Log.hpp"
#include "log.peer.h"
#include "Request.hpp"
namespace rti { namespace apputils { namespace http { namespace server {
/**
* @brief This class implements the interfaces defined by rest::Connection to
* deal with CivetWeb's native connections.
*/
class Connection {
public:
/**
* @brief Constructor of the Connection class. It saves a reference to
* CivetWeb's native connection. It also constructs a Request from
* the connection passed by parameter.
*
* @param conn CivetWeb's connection that is wrapped in this class.
*/
explicit Connection(mg_connection *conn) : conn_(conn), request_(conn_)
{ }
/**
* Destructor of the Connection class.
*/
~Connection()
{ }
/**
* @brief This method returns the HTTP request.
*
* @return The HTTP Request.
*/
const Request& request() const
{
return request_;
}
/**
* @brief This method returns the CivetWeb's native connection.
*
* @return The CivetWeb's native connection.
*/
mg_connection *connection() const
{
return conn_;
}
/**
* @brief This method sends an "Error 501: Not Implemented" response.
*/
void send_not_implemented(std::string const& message = std::string())
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code =
static_cast<unsigned short>(StatusCode::not_implemented);
response.http_reason_phrase =
status_code_to_string(StatusCode::not_implemented);
response.http_content = message;
this->send_http_response(response);
}
/**
* @brief This method sends an "OK 204: No Content" response.
*/
void send_http_ok_no_content()
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code =
static_cast<unsigned short>(StatusCode::no_content);
response.http_reason_phrase =
status_code_to_string(StatusCode::no_content);
this->send_http_response(response);
}
/**
* @brief This method sends an "Error 400: Bad Request" response.
*/
void send_http_bad_request(std::string const& message = std::string())
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code =
static_cast<unsigned short>(StatusCode::bad_request);
response.http_reason_phrase =
status_code_to_string(StatusCode::bad_request);
response.http_content = message;
this->send_http_response(response);
}
/**
* @brief This method sends an "Error 404: Not Found" response.
*/
void send_http_not_found(std::string const& message = std::string())
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code =
static_cast<unsigned short>(StatusCode::not_found);
response.http_reason_phrase =
status_code_to_string(StatusCode::not_found);
response.http_content = message;
this->send_http_response(response);
}
/**
* @brief This method sends an "Error 405: Method Not Allowed" response.
*/
void send_http_method_not_allowed(
std::string const& message = std::string())
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code =
static_cast<unsigned short>(StatusCode::not_allowed);
response.http_reason_phrase =
status_code_to_string(StatusCode::not_allowed);
response.http_content = message;
this->send_http_response(response);
}
/**
* @brief This method sends an "OK 202: Accepted" response.
*/
void send_http_accepted(std::string const& message = std::string())
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code =
static_cast<unsigned short>(StatusCode::accepted);
response.http_reason_phrase =
status_code_to_string(StatusCode::accepted);
response.http_content = message;
this->send_http_response(response);
}
/**
* @brief This method sends an "OK 200: OK" response.
*/
void send_http_ok(std::string const& message = std::string())
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code = static_cast<unsigned short>(StatusCode::ok);
response.http_reason_phrase = status_code_to_string(StatusCode::ok);
response.http_content = message;
this->send_http_response(response);
}
/**
* @brief This operation constructs an HTTP response given its definition in
* Response format. Once the Response is constructed, is sent via CivetWeb's
* native APIs.
*/
void send_http_response(const Response& rpns)
{
// Constructs headers and body of the HTTP response.
auto mg_result = mg_printf(
conn_,
"HTTP/%s %u %s\r\n"
"Content-Type: %s\r\n"
"Cache-Control: %s\r\n"
"Content-Length: %lu\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Date: %s\r\n\r\n"
"%s",
HTTP_VERSION,
rpns.http_status_code,
rpns.http_reason_phrase.c_str(),
rpns.http_content_type.c_str(),
HTTP_CACHE_CONTROL_NO_CACHE,
rpns.http_content.length(),
HttpSettings::get_current_date().c_str(),
rpns.http_content.c_str());
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result >= 0,
msg_server_error_printf);
APPUTILSLogMessage_log(
RTI_LOG_BIT_LOCAL,
&APPUTILS_LOG_HTTP_SENT_RESPONSE_us,
rpns.http_status_code,
rpns.http_reason_phrase.c_str());
}
/**
* @brief Prepares and send the body of an HTTP response given an exception.
*
* @param [in] e Exception to be formatted and sent.
*/
void send_error_exception_response(const HttpException& e)
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code = static_cast<unsigned short>(e.error_code());
response.http_reason_phrase = status_code_to_string(e.error_code());
nlohmann::json http_content_json;
http_content_json["code"] = status_code_to_string(e.error_code());
http_content_json["message"] = e.what();
response.http_content = http_content_json.dump();
this->send_http_response(response);
}
/**
* @brief Read the content of an HTTP request.
*
* @param chunk_size size of the chunk to read.
* @return std::string with the read content.
*/
std::string read_content(std::size_t chunk_size = 256)
{
const auto request_info = mg_get_request_info(conn_);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
request_info != nullptr,
msg_server_error_get_request_info);
if (request_info->content_length >= 0) {
return read_content_with_content_length(
conn_,
static_cast<std::size_t>(request_info->content_length));
}
return read_content_without_content_length(conn_, chunk_size);
}
/**
* @brief Check that content type is the expected one.
*
* @param expected_content_type
* @return true if the content type is the expected one. otherwise
* false.
*/
bool check_content_type(const std::string& expected_content_type)
{
auto ret = true;
// Check if Content-Type is application/json
if (this->request().get_header(
rti::apputils::http::HTTP_CONTENT_TYPE_HEADER)
!= expected_content_type) {
ret = false;
}
return ret;
}
private:
mg_connection *conn_;
Request request_;
};
}}}} // namespace rti::apputils::http::server
#endif // HTTP_SERVER_CONNECTION_HPP
@@ -0,0 +1,232 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 HTTP_SERVER_REQUEST_HPP
#define HTTP_SERVER_REQUEST_HPP
#include <string>
#include <cstring>
#include <CivetServer.h>
#include <civetweb.h>
#include "rti/apputils/StringBuffer.hpp"
#include "rti/apputils/http/common/Method.hpp"
#include "rti/apputils/http/common/HttpException.hpp"
namespace rti { namespace apputils { namespace http { namespace server {
/**
* @brief This class implements the Request to handle Requests, that is
* requests provided by the CivetWeb server.
*/
class Request {
public:
/**
* @brief Constructor of the Request. Retrieves information from the
* mg_request_info provided by CivetWeb's connection.
*
* @param conn Civetweb's connection.
*/
explicit Request(mg_connection *conn) : conn_(conn)
{ }
/**
* @brief Destructor of the Request class.
*/
~Request()
{ }
/**
* @brief Returns the URL of CivetWeb's request.
*
* @return URL of the HTTP request.
*/
const char *uri() const
{
const auto req = mg_get_request_info(conn_);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
req != nullptr,
msg_server_error_get_request_info);
return req->local_uri;
}
/**
* @brief Gets a URI parameter given its name.
*
* @param value The value of the parameter.
* @param name of the parameter to be retrieved.
* @return Indicates whether the parameter was found.
*/
bool uri_param(std::string& value, const std::string& name) const
{
const auto req = mg_get_request_info(conn_);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
req != nullptr,
msg_server_error_get_request_info);
if (req->query_string == nullptr) {
return false;
}
return CivetServer::getParam(req->query_string, name.c_str(), value);
}
/**
* @brief Constructs a map with the query parameters in a given URI.
*
* @param params Map with decoded names and values of all the query
* parameters in the URI.
* @return Boolean value indicating whether query parameters were retrieved
* or not.
*/
bool uri_params(StringMap& params) const
{
const auto req = mg_get_request_info(conn_);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
req != nullptr,
msg_server_error_get_request_info);
if (req->query_string == nullptr) {
return false;
}
const auto query_string = req->query_string;
auto query_string_length = strlen(query_string);
auto i = std::size_t { 0 };
while (i < query_string_length) {
// Get Name
auto i0 = i;
while ((i < query_string_length) && query_string[i] != '='
&& query_string[i] != '&') {
i++;
}
auto name = std::string();
CivetServer::urlDecode(&query_string[i0], i - i0, name, true);
if (i < query_string_length && query_string[i] == '=') {
i++;
}
// Get Value
i0 = i;
while ((i < query_string_length) && query_string[i] != '&') {
i++;
}
auto value = std::string();
CivetServer::urlDecode(&query_string[i0], i - i0, value, true);
if (i < query_string_length && query_string[i] == '&') {
i++;
}
// Add key-value pair to the map
params[name] = value;
}
return true;
}
/**
* @brief Gets a URI header given its name.
*
* @param Name of the header to be retrieved.
* @return Gets the value of an HTTP header given its name.
*/
const char *get_header(const char *name) const
{
const char *value = mg_get_header(conn_, name);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
value != nullptr,
msg_server_error_get_header);
return value;
}
/**
* @brief This method saves the body of the HTTP request in the body buffer.
*
* @param [out] Body of the HTTP request.
* @param [in,out] Length of the body of the HTTP request.
*/
void get_body(char *& body, size_t& body_length) const
{
auto mg_result = mg_read(conn_, body, body_length);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result >= 0,
msg_server_error_read);
}
/**
* @brief Saves the body of the HTTP request in a string buffer.
*
* @param [out] Body of the HTTP request in StringBuffer.
*/
void get_body(StringBuffer& body) const
{
const auto body_length = get_body_length();
body.ensure_capacity(body_length + 1);
auto mg_result = mg_read(conn_, body.c_str_ptr(), body_length);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result >= 0,
msg_server_error_read);
}
/**
* @brief Returns the length of the body of the HTTP request.
*
* @return Body length.
*/
size_t get_body_length() const
{
const auto req = mg_get_request_info(conn_);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
req != nullptr,
msg_server_error_get_request_info);
auto content_length = req->content_length;
// Check that the content_length is not negative (except for GET,
// DELETE, and PUT operations) where it is permitted.
if ((content_length < 0) && (strcmp(req->request_method, "GET") != 0)
&& (strcmp(req->request_method, "DELETE") != 0)
&& (strcmp(req->request_method, "PUT") != 0)) {
RTI_THROW_HTTP_EXCEPTION(
StatusCode::bad_request,
&RTI_LOG_ANY_FAILURE_s,
"Content-length of the HTTP request is invalid.");
}
return content_length < 0 ? 0 : static_cast<size_t>(content_length);
}
/**
* @brief Returns the method of the HTTP request.
*
* @return Method of the HTTP request.
*/
Method get_http_method() const
{
const struct mg_request_info *req = mg_get_request_info(conn_);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
req != nullptr,
msg_server_error_get_request_info);
return method_from_string(
req->request_method == nullptr ? "" : req->request_method);
}
private:
struct mg_connection *conn_;
};
}}}} // namespace rti::apputils::http::server
#endif // HTTP_SERVER_REQUEST_HPP
@@ -0,0 +1,157 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 HTTP_SERVER_REQUEST_HANDLER_HPP
#define HTTP_SERVER_REQUEST_HANDLER_HPP
#include <functional>
#include "rti/apputils/http/common/Method.hpp"
#include "rti/apputils/http/common/HttpUtils.hpp"
#include "Connection.hpp"
#include "ServerProperty.hpp"
namespace rti { namespace apputils { namespace http { namespace server {
// Forward declaration
class Server;
/**
* @brief This class defines a generic interface to be implemented by each
* RequestHandler. This implies implementing a set or methods to handle
* different types of requests (e.g., POST, PUT, GET, DELETE, OPTIONS, HEAD and
* PATCH).
*/
class RequestHandler {
public:
/**
* @brief Virtual destructor of the RequestHandler class.
*/
virtual ~RequestHandler()
{ }
/**
* @brief The POST request handler is an interface to implement a method
* that addresses POST requests and generates responses.
*
* @param server Reference to the wrapper of the internal server API.
* @param connection
* @param web_server_property Reference to the web server properties.
*/
virtual void handle_post(
Server&,
Connection& connection,
const ServerProperty&)
{
connection.send_not_implemented();
}
/**
* @brief The PUT request handler is an interface to implement a method that
* addresses PUT requests and generates responses.
*
* @param server Reference to the wrapper of the internal server API.
* @param connection
* @param web_server_property Reference to the service properties.
*/
virtual void handle_put(
Server&,
Connection& connection,
const ServerProperty&)
{
connection.send_not_implemented();
}
/**
* @brief The GET request handler is an interface to implement a method that
* addresses GET requests and generates responses.
*
* @param server Reference to the wrapper of the internal server API.
* @param connection
* @param web_server_property Reference to the service properties.
*/
virtual void handle_get(
Server&,
Connection& connection,
const ServerProperty&)
{
connection.send_not_implemented();
}
/**
* @brief The DELETE request handler is an interface to implement a method
* that addresses DELETE requests and generates responses.
*
* @param server Reference to the wrapper of the internal server API.
* @param connection
* @param web_server_property Reference to the web server properties.
*/
virtual void handle_delete(
Server&,
Connection& connection,
const ServerProperty&)
{
connection.send_not_implemented();
}
/**
* @brief The OPTIONS request handler is an interface to implement a method
* that addresses OPTIONS requests and generates responses.
*
* @param server Reference to the wrapper of the internal server API.
* @param connection
* @param web_server_property Reference to the web server properties.
*/
virtual void handle_options(
Server&,
Connection& connection,
const ServerProperty&)
{
connection.send_not_implemented();
}
/**
* @brief The HEAD request handler is an interface to implement a method
* that addresses HEAD requests and generates responses.
*
* @param server Reference to the wrapper of the internal server API.
* @param connection
* @param web_server_property Reference to the web server properties.
*/
virtual void handle_head(
Server&,
Connection& connection,
const ServerProperty&)
{
connection.send_not_implemented();
}
/**
* @brief The PATCH request handler is an interface to implement a method
* that addresses PATCH requests and generates responses.
*
* @param server Reference to the wrapper of the internal server API.
* @param connection
* @param web_server_property Reference to the web server properties.
*/
virtual void handle_patch(
Server&,
Connection& connection,
const ServerProperty&)
{
connection.send_not_implemented();
}
};
}}}} // namespace rti::apputils::http::server
#endif // HTTP_SERVER_REQUEST_HANDLER_HPP
@@ -0,0 +1,125 @@
/*
* (c) Copyright, Real-Time Innovations, 2019.
* 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 HTTP_SERVER_HPP
#define HTTP_SERVER_HPP
#include <memory>
#include <string>
#include <thread>
#include <CivetServer.h>
#include "ServerProperty.hpp"
#include "rti/apputils/http/server/detail/CivetWebHandler.hpp"
namespace rti { namespace apputils { namespace http { namespace server {
/**
* @brief Server defines an interface to CivetWeb::CivetServer and allow us to
* create handlers and close the server thought it.
*/
class Server {
public:
/**
* @brief Constructor of the Server class.
*
* @param options CivetServer options
* @param callbacks Callbacks methods
*/
Server(const ServerProperty& server_property,
const CivetCallbacks *callbacks = nullptr)
: server_(std::unique_ptr<CivetServer>(new CivetServer(
server_property.webserver_options(),
callbacks))),
server_property_(server_property),
handlers_()
{ }
~Server()
{
close();
mg_exit_library();
}
/**
* @brief This method closes the server, i.e. calls CivetServer::close().
*/
void close()
{
constexpr auto num_retries = 10u;
for (auto i = 0u; !can_close() && i < num_retries; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
server_->close();
}
/**
* @brief Checks if the server has any callbacks still running so that it
* can be closed.
*
* @return True if the server can be closed. False otherwise.
*/
bool can_close()
{
return std::none_of(
handlers_.begin(),
handlers_.end(),
[](const std::unique_ptr<CivetWebHandler>& handler) {
return handler->callbacks_running();
});
}
template <typename Handler>
void add_handler(Handler *handler)
{
handlers_.emplace_back(std::unique_ptr<CivetWebHandler>(
new CivetWebHandler(server_property_, *this, handler)));
server_->addHandler(Handler::URI_PATTERN, handlers_.back().get());
}
/**
* @brief Adds a URI handler. Existing handlers will be overwritten.
*
* @param uri String with the URI
* @param handler CivetServer pointer to the handler that to be added
*/
template <typename Handler>
void add_handler()
{
add_handler(new Handler());
}
/**
* @brief Adds a URI websocket handler. Existing websocket handlers will be
* overwritten.
*
* @param uri String with the URI
* @param websocket_handler CivetServer pointer to the handler that to be
* added
*/
void add_websocket_handler(const std::string& uri, void *websocket_handler)
{
server_->addWebSocketHandler(
uri,
reinterpret_cast<CivetWebSocketHandler *>(websocket_handler));
}
private:
std::unique_ptr<CivetServer> server_;
const ServerProperty& server_property_;
std::vector<std::unique_ptr<CivetWebHandler>> handlers_;
};
}}}} // namespace rti::apputils::http::server
#endif // HTTP_SERVER_HPP
@@ -0,0 +1,213 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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 HTTP_SERVER_PROPERTY_HPP
#define HTTP_SERVER_PROPERTY_HPP
#include <algorithm>
#include <dds/core/macros.hpp>
#include <rti/core/NativeValueType.hpp>
#include "rti/apputils/util/Path.hpp"
#include "rti/apputils/http/common/HttpUtils.hpp"
namespace rti { namespace apputils { namespace http { namespace server {
/**
* @brief This class contains the HTTP server properties
*/
class ServerProperty {
public:
/**
* @brief ServerProperty constructor
*/
ServerProperty(const std::string& ports = HTTP_SERVER_DEFAULT_PORT_STR)
: handle_options_request_(false)
{
listening_ports(ports);
}
/**
* @brief Destroy the Server Property object
*/
virtual ~ServerProperty() = default;
/**
* @brief Return the document root path.
*
* @return const std::string&
*/
const std::string& document_root() const
{
return document_root_;
}
/**
* @brief Return the web server options.
*
* @return const std::vector<std::string>&
*/
const std::vector<std::string>& webserver_options() const
{
return webserver_options_;
}
/**
* @brief Return the value of a web server options given it name. If the
* option is not found, the name will be returned.
*
* @return const std::string>& option value, or option name if not found.
*/
const std::string& webserver_option(std::string& name) const
{
auto it = std::find(
webserver_options_.begin(),
webserver_options_.end(),
name);
if (it != webserver_options_.end()
&& ++it != webserver_options_.end()) {
return *it;
}
return name;
}
/**
* @brief This method returns true if the server will handle OPTIONS
* requests, otherwise false.
*
* @return boolean
*/
bool handle_options_request() const
{
return handle_options_request_;
}
/**
* @brief Set the document root path.
*
* @param document_root
* @return ServerProperty&
*/
ServerProperty& document_root(const std::string& document_root)
{
if (!document_root.empty()) {
document_root_ = util::Path(document_root);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
document_root_.exists(),
"Document root path does not exist");
set_webserver_option("document_root", document_root_.c_str());
}
return *this;
}
/**
* @brief Set the listening ports.
*
* @param listening_ports
* @return ServerProperty&
*/
ServerProperty& listening_ports(const std::string& listening_ports)
{
listening_ports_ = listening_ports;
set_webserver_option("listening_ports", listening_ports.c_str());
return *this;
}
/**
* @brief This method enters a key-value pair into the webserver_options
* array.
*
* @param key Name of the option to be set.
* @param value Value of the option.
*/
ServerProperty& set_webserver_option(const char *key, const char *value)
{
// Check if the option already exists.
auto it = std::find(
webserver_options_.begin(),
webserver_options_.end(),
key);
// if exists modify the value
if (it != webserver_options_.end()
&& ++it != webserver_options_.end()) {
*it = value;
} else {
// Add option name
webserver_options_.emplace_back(key);
// Add option value
webserver_options_.emplace_back(value);
}
return *this;
}
/**
* @brief This option enables the server to handle OPTIONS requests if true,
* otherwise civetweb will handle them.
*
* @param handle_options_request boolean value to handle OPTIONS requests.
* @return ServerProperty&
*/
ServerProperty& handle_options_request(bool handle_options_request)
{
handle_options_request_ = handle_options_request;
return *this;
}
static std::string parse_port(const std::string& host)
{
std::string::size_type scheme_pos = host.find("://");
if (scheme_pos == std::string::npos) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_INIT_FAILURE_s,
"Invalid scheme format");
}
std::string unformatted_host = host.substr(scheme_pos + 1);
std::string::size_type port_pos = unformatted_host.find(":");
if (port_pos == std::string::npos) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_INIT_FAILURE_s,
"Invalid host:port format");
}
std::string port_string = unformatted_host.substr(port_pos + 1);
try {
// Check that port has a valid format
std::stoi(port_string);
} catch (...) {
std::string error_msg;
error_msg.append("Invalid port value: ").append(port_string);
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_INIT_FAILURE_s,
error_msg.c_str());
}
return port_string;
}
private:
// Server options
util::Path document_root_;
std::string listening_ports_;
std::vector<std::string> webserver_options_;
bool handle_options_request_;
};
}}}} // namespace rti::apputils::http::server
#endif // HTTP_SERVER_PROPERTY_HPP
@@ -0,0 +1,320 @@
/*
* (c) Copyright, Real-Time Innovations, 2024.
* 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 _WEBSOCKET_CONNECTION_H_
#define _WEBSOCKET_CONNECTION_H_
#include <civetweb.h>
#include <map>
#include <rti/apputils/StringBuffer.hpp>
#include <rti/apputils/http/common/WebSocketUtils.h>
#include <rti/apputils/http/common/StatusCode.hpp>
#include <rti/apputils/http/common/HttpException.hpp>
namespace rti { namespace apputils { namespace websocket {
/*
* This class wraps the state of the client connection. Every instance created
* from this class must be kept alive until the connection is closed. Whenever
* the server receives a new web_wait_factorysocket connection attempt, it
* creates a WebSocketConnection instance and this WebSocketConnection will be
* attached to the client connection.
*
* This class has the state of the client connection, the type of content that
* the client accepts and the bind ids that each connection have bound.
*/
class WebSocketConnection {
public:
explicit WebSocketConnection()
: state_(WebSocketStateKind::UNKNOWN),
content_type_(WebSocketContentType::UNKNOWN)
{ }
virtual ~WebSocketConnection() = default;
/**
* Overloading the == operator to compare connections.
* @param conn A pointer to the connection to compare
*/
virtual bool operator==(WebSocketConnection *conn) = 0;
/**
* This method returns the state of the connection
* @return WebSocketStateKind the current status
*/
WebSocketStateKind state() const
{
return state_;
}
/**
* This method returns the content type accepted for the connection
* @return WebSocketContentType
*/
WebSocketContentType content_type() const
{
return content_type_;
}
/**
* This method sets the state of the connection
* @param state WebSocketStateKind the new status
*/
void state(const WebSocketStateKind& state)
{
state_ = state;
}
/**
* This method sets the content type accepted for the connection
* @param content WebSocketContentType
*/
void content_type(const WebSocketContentType& content)
{
content_type_ = content;
}
/**
* This function sends a MG_WEBSOCKET_OPCODE_TEXT message to the user.
* @param msg The message string to be sent
*/
virtual void send(const StringBuffer& msg) = 0;
/**
* This function sends a MG_WEBSOCKET_OPCODE_PONG message to the user.
* @param msg The message string to be sent
*/
virtual void send_pong(const StringBuffer& msg) = 0;
/**
* This function creates the error message to the user.
* @param ex Excetion with the info of an issue
* @param save_ctx context with that point to the message
*/
void create_error(
RTIXMLSaveContext& save_ctx,
const rti::apputils::http::HttpException& ex)
{
struct DDS_PrintFormat format = DDS_PrintFormat_INITIALIZER;
DDS_PrintFormatProperty properties = DDS_PrintFormatProperty_INITIALIZER;
DDS_ReturnCode_t retcode = DDS_RETCODE_ERROR;
if (content_type_ == WebSocketContentType::JSON) {
properties.kind = DDS_JSON_PRINT_FORMAT;
} else if (content_type_ == WebSocketContentType::XML) {
properties.kind = DDS_XML_PRINT_FORMAT;
} else {
properties.kind = DDS_XML_PRINT_FORMAT;
}
retcode = DDS_PrintFormatProperty_to_print_format(&properties, &format);
if (retcode != DDS_RETCODE_OK) {
RTI_THROW_HTTP_EXCEPTION(
rti::apputils::http::StatusCode::internal_server_error,
&RTI_LOG_ANY_FAILURE_s,
"Unsupported content type");
}
format.print_top_level_beginning(&format, &save_ctx, "error", 0);
format.print_primitive_type_beginning(&format, &save_ctx, "code", 1);
RTIXMLSaveContext_freeform(
&save_ctx,
"%d",
ex.error_code());
format.print_primitive_type_ending(&format, &save_ctx, "code", 1);
RTIXMLSaveContext_freeform(&save_ctx, "%s", format.element_separator);
format.print_primitive_type_beginning(&format, &save_ctx, "message", 1);
RTIXMLSaveContext_freeform(
&save_ctx,
"%sError %s%s",
format.string_opening_delimiter,
ex.what(),
format.string_closing_delimiter);
format.print_primitive_type_ending(&format, &save_ctx, "message", 1);
RTIXMLSaveContext_freeform(&save_ctx, "%s", format.element_separator);
format.print_primitive_type_beginning(&format, &save_ctx, "method", 1);
RTIXMLSaveContext_freeform(
&save_ctx,
"%s%s%s",
format.string_opening_delimiter,
RTI_FUNCTION_NAME,
format.string_closing_delimiter);
format.print_primitive_type_ending(&format, &save_ctx, "method", 1);
format.print_top_level_ending(&format, &save_ctx, "error", 0);
}
/**
* This function sends an error message to the user.
* @param msg The error message that the error will have
*/
void send_error(const rti::apputils::http::HttpException& ex)
{
StringBuffer buffer;
RTIXMLSaveContext save_ctx = RTIXMLSaveContext_INITIALIZER;
save_ctx.sout = (char*) buffer.c_str();
if (!RTIOsapiUtility_sizeToUInt32(save_ctx.ssize, buffer.capacity())) {
RTI_THROW_HTTP_EXCEPTION(
rti::apputils::http::StatusCode::internal_server_error,
&RTI_LOG_ANY_FAILURE_s,
"Error allocating string");
}
create_error(save_ctx, ex);
if (save_ctx.outputStringLength + 1 > buffer.capacity()) {
buffer.ensure_capacity(save_ctx.outputStringLength + 1);
// Reset save_context
RTIXMLSaveContext_initialize(&save_ctx);
save_ctx.sout = (char *) buffer.c_str();
if (!RTIOsapiUtility_sizeToUInt32(save_ctx.ssize, buffer.capacity())) {
RTI_THROW_HTTP_EXCEPTION(
rti::apputils::http::StatusCode::internal_server_error,
&RTI_LOG_ANY_FAILURE_s,
"Error allocating string");
}
create_error(save_ctx, ex);
}
send(buffer);
}
/**
* This function creates the request error message to the user.
* @param ex RequestExcetion with the info of an issue
* @param save_ctx context with that point to the message
*/
void create_request_error(
RTIXMLSaveContext& save_ctx,
const RequestException& ex)
{
struct DDS_PrintFormat format = DDS_PrintFormat_INITIALIZER;
DDS_PrintFormatProperty properties = DDS_PrintFormatProperty_INITIALIZER;
DDS_ReturnCode_t retcode = DDS_RETCODE_ERROR;
if (content_type_ == WebSocketContentType::JSON) {
properties.kind = DDS_JSON_PRINT_FORMAT;
} else if (content_type_ == WebSocketContentType::XML) {
properties.kind = DDS_XML_PRINT_FORMAT;
} else {
properties.kind = DDS_XML_PRINT_FORMAT;
}
retcode = DDS_PrintFormatProperty_to_print_format(&properties, &format);
if (retcode != DDS_RETCODE_OK) {
RTI_THROW_HTTP_EXCEPTION(
rti::apputils::http::StatusCode::internal_server_error,
&RTI_LOG_ANY_FAILURE_s,
"Unsupported content type");
}
format.print_top_level_beginning(
&format,
&save_ctx,
WEBSOCKET_RESPONSE_NAME,
0);
format.print_primitive_type_beginning(&format, &save_ctx, "return_code", 1);
RTIXMLSaveContext_freeform(
&save_ctx,
"%d",
ex.error_code());
format.print_primitive_type_ending(&format, &save_ctx, "return_code", 1);
RTIXMLSaveContext_freeform(&save_ctx, "%s", format.element_separator);
format.print_primitive_type_beginning(&format, &save_ctx, "error", 1);
RTIXMLSaveContext_freeform(
&save_ctx,
"%s%s%s",
format.string_opening_delimiter,
ex.what(),
format.string_closing_delimiter);
format.print_primitive_type_ending(&format, &save_ctx, "error", 1);
RTIXMLSaveContext_freeform(&save_ctx, "%s", format.element_separator);
format.print_primitive_type_beginning(&format, &save_ctx, "method", 1);
RTIXMLSaveContext_freeform(
&save_ctx,
"%s%s%s",
format.string_opening_delimiter,
ex.get_method_name(),
format.string_closing_delimiter);
format.print_primitive_type_ending(&format, &save_ctx, "method", 1);
format.print_top_level_ending(
&format,
&save_ctx,
WEBSOCKET_RESPONSE_NAME,
0);
}
/**
* This function sends an REQUEST error message to the user.
* @param msg The error message that the error will have
*/
void send_request_error(const RequestException& ex)
{
StringBuffer buffer;
RTIXMLSaveContext save_ctx = RTIXMLSaveContext_INITIALIZER;
save_ctx.sout = (char*) buffer.c_str();
if (!RTIOsapiUtility_sizeToUInt32(save_ctx.ssize, buffer.capacity())) {
RTI_THROW_HTTP_EXCEPTION(
rti::apputils::http::StatusCode::internal_server_error,
&RTI_LOG_ANY_FAILURE_s,
"Error allocating string");
}
create_request_error(save_ctx, ex);
if (save_ctx.outputStringLength + 1 > buffer.capacity()) {
buffer.ensure_capacity(save_ctx.outputStringLength + 1);
// Reset save_context
RTIXMLSaveContext_initialize(&save_ctx);
save_ctx.sout = (char *) buffer.c_str();
if (!RTIOsapiUtility_sizeToUInt32(save_ctx.ssize, buffer.capacity())) {
RTI_THROW_HTTP_EXCEPTION(
rti::apputils::http::StatusCode::internal_server_error,
&RTI_LOG_ANY_FAILURE_s,
"Error allocating string");
}
create_request_error(save_ctx, ex);
}
send(buffer);
}
/**
* This function close a WebSocketConnection.
* @param exception with the error message that happend
*/
virtual void close() = 0;
private:
WebSocketStateKind state_;
WebSocketContentType content_type_;
};
}}} // namespace rti::webdds::websocket
#endif // _WEBSOCKET_CONNECTION_H_
@@ -0,0 +1,209 @@
/*
* (c) Copyright, Real-Time Innovations, 2015.
* 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 CIVETWEB_HANDLER_HPP
#define CIVETWEB_HANDLER_HPP
#include <atomic>
#include <CivetServer.h>
#include <civetweb.h>
#include "rti/apputils/http/server/ServerProperty.hpp"
#include "rti/apputils/http/server/Connection.hpp"
#include "rti/apputils/http/server/RequestHandler.hpp"
namespace rti { namespace apputils { namespace http { namespace server {
// Forward declaration
class Server;
/**
* @brief WebHandler implements the handler functions of CivetWeb's API,
* wrapping the calls to the generic RequestHandler. The Request is specialized
* to an specific kind of request handler (e.g., PublisherHandler) whose type is
* specified via template.
*/
class CivetWebHandler : public CivetHandler {
public:
/**
* @brief Constructor of the CivetWebHandler class. It calls the constructor
* of the specific RequestHandler it implements (i.e., handler)
*
* @param web_server_property Reference to the ServerProperty that will
* be used by the RequestHandler.
* @param server Web's server.
*/
explicit CivetWebHandler(
const ServerProperty& web_server_property,
Server& server,
RequestHandler *handler)
: web_server_property_(web_server_property),
server_(server),
handler_(handler),
callbacks_counter_(0)
{ }
/**
* @brief Destructor of the CivetWebHandler class.
*/
virtual ~CivetWebHandler() = default;
/**
* @brief This method handles the POST operation.
*
* @param server CivetWeb's server.
* @param conn CiveWeb's connection.
* @return Always returns true given the fact that the operation is always
* processed by the underlying interfaces.
*/
virtual bool handlePost(CivetServer *, struct mg_connection *conn) final
{
CounterGuard guard { callbacks_counter_ };
Connection connection(conn);
handler_->handle_post(server_, connection, web_server_property_);
return true;
}
/**
* @brief This method handles the PUT operation.
*
* @param server CivetWeb's server.
* @param conn CiveWeb's connection.
* @return Always returns true given the fact that the operation is always
* processed by the underlying interfaces.
*/
virtual bool handlePut(CivetServer *, struct mg_connection *conn) final
{
CounterGuard guard { callbacks_counter_ };
Connection connection(conn);
handler_->handle_put(server_, connection, web_server_property_);
return true;
}
/**
* @brief This method handles the GET operation.
*
* @param server CivetWeb's server.
* @param conn CiveWeb's connection.
* @return Always returns true given the fact that the operation is always
* processed by the underlying interfaces.
*/
virtual bool handleGet(CivetServer *, struct mg_connection *conn) final
{
CounterGuard guard { callbacks_counter_ };
Connection connection(conn);
handler_->handle_get(server_, connection, web_server_property_);
return true;
}
/**
* @brief This method handles the DELETE operation.
*
* @param server CivetWeb's server.
* @param conn CiveWeb's connection.
* @return Always returns true given the fact that the operation is always
* processed by the underlying interfaces.
*/
virtual bool handleDelete(CivetServer *, struct mg_connection *conn) final
{
CounterGuard guard { callbacks_counter_ };
Connection connection(conn);
handler_->handle_delete(server_, connection, web_server_property_);
return true;
}
/**
* @brief This method handles the OPTIONS operation.
*
* @param server CivetWeb's server.
* @param conn CiveWeb's connection.
* @return true if the request was processed by the custom handler,
* otherwise false.
*/
virtual bool handleOptions(CivetServer *, struct mg_connection *conn) final
{
CounterGuard guard { callbacks_counter_ };
if (web_server_property_.handle_options_request()) {
Connection connection(conn);
handler_->handle_options(server_, connection, web_server_property_);
return true;
}
return false;
}
/**
* @brief This method handles the HEAD operation.
*
* @param server CivetWeb's server.
* @param conn CiveWeb's connection.
* @return Always returns true given the fact that the operation is always
* processed by the underlying interfaces.
*/
virtual bool handleHead(CivetServer *, struct mg_connection *conn) final
{
CounterGuard guard { callbacks_counter_ };
Connection connection(conn);
handler_->handle_head(server_, connection, web_server_property_);
return true;
}
/**
* @brief This method handles the PATCH operation.
*
* @param server CivetWeb's server.
* @param conn CiveWeb's connection.
* @return Always returns true given the fact that the operation is always
* processed by the underlying interfaces.
*/
virtual bool handlePatch(CivetServer *, struct mg_connection *conn) final
{
CounterGuard guard { callbacks_counter_ };
Connection connection(conn);
handler_->handle_patch(server_, connection, web_server_property_);
return true;
}
bool callbacks_running() const
{
return callbacks_counter_ != 0;
}
private:
struct CounterGuard {
CounterGuard(std::atomic_short& counter) : counter_(counter)
{
++counter_;
}
~CounterGuard()
{
--counter_;
}
std::atomic_short& counter_;
};
const ServerProperty& web_server_property_;
Server& server_;
std::unique_ptr<RequestHandler> handler_;
std::atomic_short callbacks_counter_;
};
}}}} // namespace rti::apputils::http::server
#endif // CIVETWEB_HANDLER_HPP
@@ -0,0 +1,165 @@
/*
* (c) Copyright, Real-Time Innovations, 2024.
* 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 CIVETWEB_WEBSOCKET_HANDLER_H
#define CIVETWEB_WEBSOCKET_HANDLER_H
#include <CivetServer.h>
#include <civetweb.h>
#include <rti/apputils/http/server/CivetWebSocketConnection.hpp>
#include <rti/apputils/http/server/detail/WebSocketHandler.hpp>
namespace rti { namespace apputils { namespace websocket { namespace civetweb {
/**
* This class implements the CivetWebSocketHandler interface, which is part
* of the CivetWeb API. This class has a WebSocketHandler. It allows us
* to isolate the WebSocket handling that CivetWeb does and the WebSocket
* handling that our WebSocketAPI implements
*/
class CivetWebSocketHandlerImpl : public CivetWebSocketHandler {
public:
CivetWebSocketHandlerImpl(WebSocketHandler& handler) : handler_(handler)
{ }
/**
* This method handles new client connections to the server. For such
* purpose, it creates a new `WebSocketConnection` and attaches it to the
* internal CivetWeb `mg_connection`. This mechanisms allows existing
* connections to be reused in the future.
* @param server CivetWeb server. Unused parameter.
* @param conn CivetWeb connection.
* @return Boolean value indicating the success or failure of the operation.
*/
bool handleConnection(CivetServer *, const struct mg_connection *conn)
{
WebSocketConnection *client_conn =
new CivetWebSocketConnection(const_cast<mg_connection *>(conn));
handler_.handle_connection(*client_conn);
mg_set_user_connection_data(const_cast<mg_connection *>(conn), client_conn);
/*
* client_conn is not being leaked here, it's stored indirectly
* in the user connection data that can be get by calling
* mg_get_user_connection_data as we can see on handleClose.
*/
/* coverity[leaked_storage : FALSE] */
return true;
}
/**
* This method is called when a client connection has ended the handshake
* protocol with success.
* @param server CivetWeb server. Unused parameter.
* @param conn CivetWeb connection
*/
void handleReadyState(CivetServer *, struct mg_connection *conn)
{
WebSocketConnection *client = static_cast<WebSocketConnection *>(
mg_get_user_connection_data(conn));
handler_.handle_ready_state(*client);
}
/**
* This method is called every time a client sends a message to the server
* through the WebSocket connection.
* @param server CivetWeb server. Unused parameter
* @param conn CivetWeb connection
* @param bits A byte with the kind of data (TEXT, PONG, ...)
* @param data String containing the received message, it is not
* null-terminated
* @param data_size String size, the size of the string without the null
* character.
*/
bool handleData(
CivetServer *,
struct mg_connection *conn,
int bits,
char *data,
size_t data_len)
{
StringBuffer msg;
WebSocketConnection *client = static_cast<WebSocketConnection *>(
mg_get_user_connection_data(conn));
// The last byte of the bits say what kind of message it is
switch (((unsigned char) bits) & 0x0F) {
case MG_WEBSOCKET_OPCODE_TEXT:
// This marks the end of the string
*(data + data_len) = '\0';
msg = StringBuffer(data);
try {
handler_.handle_data(*client, msg);
} catch (const RequestException& ex) {
DDSLog_exception(&RTI_LOG_ANY_FAILURE_s, ex.what());
client->send_request_error(ex);
} catch (const rti::apputils::http::HttpException& ex) {
DDSLog_exception(&RTI_LOG_ANY_FAILURE_s, ex.what());
client->send_error(ex);
} catch (...) {
std::string message = "Unexpected exception. The connection will be closed.";
DDSLog_exception(&RTI_LOG_ANY_FAILURE_s, message.c_str());
message.append(": ");
message.append(RTI_FUNCTION_NAME);
client->send(message);
// Close the connection (Especially to avoid vulnerabilities)
client->state(WebSocketStateKind::CLOSE);
client->close();
}
break;
case MG_WEBSOCKET_OPCODE_PING:
// This marks the end of the string
data[data_len] = '\0';
msg = StringBuffer(data);
// just send back the message data in a pong frame
client->send_pong(msg);
break;
default:
break;
}
return true;
}
/**
* This method is called when a client closes the connection. The method
* deletes the connection object.
* @param server CivetWeb Server
* @param conn CivetWeb connection
*/
void handleClose(CivetServer *, const struct mg_connection *conn)
{
struct mg_context *ctx = mg_get_context(conn);
WebSocketConnection *client =
static_cast<WebSocketConnection *>(mg_get_user_connection_data(conn));
if (client->state() != WebSocketStateKind::CLOSE){
handler_.handle_close(*client);
}
mg_lock_context(ctx);
delete client;
mg_set_user_connection_data(const_cast<mg_connection *>(conn), NULL);
mg_unlock_context(ctx);
}
~CivetWebSocketHandlerImpl()
{
}
private:
WebSocketHandler& handler_;
};
}}}} // namespace rti::webdds::websocket::civetweb
#endif
@@ -0,0 +1,63 @@
/*
* (c) Copyright, Real-Time Innovations, 2024.
* 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 WEBSOCKET_HANDLER_HPP
#define WEBSOCKET_HANDLER_HPP
#include <rti/apputils/http/server/WebSocketConnection.hpp>
#include <rti/apputils/StringBuffer.hpp>
namespace rti { namespace apputils { namespace websocket {
/**
* This class is a generic handler for WebSocket communication. It
* implements methods that handle all the different events that can be
* triggered in the context of a WebSocket connection.
*/
class WebSocketHandler {
public:
/**
* This method is called when a client establishes a connection with the
* server. When that happens, we set the status of the WebSocketConnection
* to WebSocketStatus_CREATED.
* @param conn WebSocketConnection connection that will be created
*/
virtual void handle_connection(WebSocketConnection& conn) = 0;
/**
* This method is called when the websocket's handshake protocol has
* ended successfully. The state of the connection is marked as
* WebSocketStateKind::OPEN.
* @param conn WebSocketConnection connection that will be updated
*/
virtual void handle_ready_state(WebSocketConnection& conn) = 0;
/**
* This method is called every time a client sends a message. The message is
* wrapped in a StringBuffer. Upon reception, the method identifies the
* message kind and calls the appropriate Handler for that kind of message.
* @param conn WebSocketConnection connection that sent the message
* @param msg StringBuffer with the corresponding message
*/
virtual void handle_data(
WebSocketConnection& conn,
const StringBuffer& msg) = 0;
/**
* This method is called when a client closes a connection with the server.
* It detaches all conditions that have been previously attached to the
* connection.
* @param conn WebSocketConnection connection that will be closed
*/
virtual void handle_close(WebSocketConnection& conn) = 0;
};
}}} // namespace rti::apputils::websocket
#endif // WEBSOCKET_HANDLER_HPP
@@ -0,0 +1,304 @@
/*
(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_SERVICE_LOG_CONFIG_HPP_
#define HPP_SERVICE_LOG_CONFIG_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 <cstdio>
#include <cstdarg>
#include "log/log_common.h"
#include <rti/advlog/Context.hpp>
#include <rti/config/Logger.hpp>
#include <rti/apputils/ServiceException.hpp>
#define RTI_SUBMODULE_MASK_ALL (0xFFFF)
namespace rti { namespace apputils { namespace log {
/**
* @deprecated This class is deprecated and may be removed in future releases.
*
* @brief This class is used to configure the logging verbosity and mask of a
* Logger instance.
*/
class LogConfig {
public:
static LogConfig& instance()
{
static LogConfig singleton;
return singleton;
}
RTILogBitmap instrumentation_mask() const
{
return instrumentation_mask_;
}
LogConfig& instrumentation_mask(RTILogBitmap logmask)
{
instrumentation_mask_ = logmask;
return *this;
}
rti::config::Verbosity verbosity()
{
return static_cast<rti::config::Verbosity::type>(instrumentation_mask_);
}
void verbosity(rti::config::Verbosity verbosity)
{
instrumentation_mask(
static_cast<RTILogBitmap>(verbosity.underlying()));
}
~LogConfig()
{
}
static RTILogBitmap mask_all()
{
return RTI_SUBMODULE_MASK_ALL;
}
static RTILogBitmap mask_none()
{
return 0;
}
protected:
// Constructor is private: this class is a singleton
LogConfig()
: instrumentation_mask_(RTI_LOG_BITMAP_DEFAULT)
{
RTILog_appendPrintMask(RTI_LOG_PRINT_BIT_AT_METHOD);
}
RTILogBitmap instrumentation_mask_;
};
inline
rti::config::Verbosity dds_verbosity_from_level(int32_t level)
{
switch (level) {
case 6:
return rti::config::Verbosity::STATUS_REMOTE;
case 5:
/* no break */
case 4:
return rti::config::Verbosity::WARNING;
case 3:
/* no break */
case 2:
/* no break */
case 1:
return rti::config::Verbosity::EXCEPTION;
case 0:
return rti::config::Verbosity::SILENT;
default:
return rti::config::Verbosity::EXCEPTION;
}
}
inline
rti::config::Verbosity service_verbosity_from_level(int32_t level)
{
RTILogBitmap native_verbosity = RTI_LOG_BITMAP_NONE;
switch (level) {
/* no break */
case 6:
native_verbosity |= RTI_LOG_BIT_CONTENT;
/* no break */
case 5:
native_verbosity |= RTI_LOG_BIT_PERIODIC;
/* no break */
case 4:
native_verbosity |= RTI_LOG_BIT_REMOTE;
/* no break */
case 3:
native_verbosity |= RTI_LOG_BIT_LOCAL;
/* no break */
case 2:
native_verbosity |= RTI_LOG_BIT_WARN;
/* no break */
case 1:
native_verbosity |= RTI_LOG_BIT_EXCEPTION | RTI_LOG_BIT_FATAL_ERROR;
break;
case 0:
break;
default:
native_verbosity = RTI_LOG_BITMAP_DEFAULT;
break;
}
return static_cast<rti::config::Verbosity::type>(native_verbosity);
}
/*
* Example:
* MyCatcherMethod: caught exception from:
* MyThrowerMethod:!init failure
*/
inline void log_service_exception(
RTILogBitmap instrumentation_mask,
const rti::apputils::ServiceException& exception,
const char *method_name)
{
RTILogMessage log_message;
log_message.format = "caught exception from:\n %s";
log_message.messageId = exception.message_id();
if (instrumentation_mask & RTI_LOG_BIT_EXCEPTION) {
RTILogMessage_printWithParams(
RTI_LOG_PRINT_FORMAT_MASK_ALL_EXCEPT_LOCATION_FILELINE_AND_MODULE,
RTI_LOG_BIT_EXCEPTION,
MODULE_LOG,
NULL, /* filename */
0, /* lineno */
method_name,
&log_message,
exception.what());
}
}
} } } /* namespace rti::apputils::log */
/* ================================================================= */
/* Logging macros */
/* ================================================================= */
/* ----------------------------------------------------------------- */
/*i
* @brief See \ref RTILogCategory_log
*/
#define SERVICELogger_log(instrumentationBit__, logMessage__, worker__, ...) \
RTILogCategory_log( \
(MODULE_LOG_CONFIG).instrumentation_mask(), \
RTI_SUBMODULE_MASK_ALL, \
RTI_SUBMODULE_MASK_ALL, \
(instrumentationBit__), \
DEFINE_MODULE_NUMBER(MODULE_NS), \
(logMessage__), \
(worker__), \
__VA_ARGS__)
/*
* --- C-like logger macros ---------------------------------------------------
*/
#define SERVICELog_fromException(SERVICE_EXCEPTION) \
rti::apputils::log::log_service_exception( \
(MODULE_LOG_CONFIG).instrumentation_mask(), \
SERVICE_EXCEPTION, \
RTI_FUNCTION_NAME)
/*
* For legacy reasons, we keep the definition of freeForm.
* freeForm is now deprecated and it should not be used anymore.
* These are the alternatives to freeForm (only to be used in test code or
* non-production code, like an instrumented build):
* - If you need to log (verbosity filtered) an unformatted parameterized string
* you can use RTITestLog_logParamString (in tests) or
* RTILogParamString_logUnformatted (in non-test, instrumented build code).
* This is equivalent to old freeForm().
* - If you just need to print (not verbosity filtered) an unformatted parameterized
* string, use RTILogParamString_printPlain.
* - Finally, if you need print a formatted parameterized string, use RTILogParamString_print.
*/
#define SERVICELog_freeForm(INSTRUMENT_BIT, ...) \
RTILogParamString_logUnformatted( \
(MODULE_LOG_CONFIG).instrumentation_mask(), \
RTI_SUBMODULE_MASK_ALL, \
RTI_SUBMODULE_MASK_ALL, \
(INSTRUMENT_BIT), \
__VA_ARGS__)
#define SERVICELog_logMessage(INSTRUMENT_BIT, ...) \
RTILogMessage_log( \
(MODULE_LOG_CONFIG).instrumentation_mask(), \
RTI_SUBMODULE_MASK_ALL, \
RTI_SUBMODULE_MASK_ALL, \
RTI_LOG_PRINT_FORMAT_MASK_ALL_EXCEPT_LOCATION, \
(INSTRUMENT_BIT), \
DEFINE_MODULE_NUMBER(MODULE_NS), \
__VA_ARGS__)
#define SERVICELogMessage_log(INSTRUMENT_BIT, ...) \
RTILogMessage_log( \
(MODULE_LOG_CONFIG).instrumentation_mask(), \
RTI_SUBMODULE_MASK_ALL, \
RTI_SUBMODULE_MASK_ALL, \
RTI_LOG_PRINT_FORMAT_MASK_ALL, \
(INSTRUMENT_BIT), \
DEFINE_MODULE_NUMBER(MODULE_NS), \
__VA_ARGS__)
#define SERVICELog_exception(...) \
SERVICELogMessage_log(RTI_LOG_BIT_EXCEPTION, __VA_ARGS__)
#define SERVICELog_warn(...) \
SERVICELogMessage_log(RTI_LOG_BIT_WARN, __VA_ARGS__)
#define SERVICELog_local(...) \
SERVICELogMessage_log(RTI_LOG_BIT_LOCAL, __VA_ARGS__)
#define SERVICELog_content(...) \
SERVICELogMessage_log(RTI_LOG_BIT_CONTENT, __VA_ARGS__)
#define SERVICELog_remote(...) \
SERVICELogMessage_log(RTI_LOG_BIT_REMOTE, __VA_ARGS__)
#define SERVICELog_any(INSTRUMENT_BIT, ...) \
if ((((MODULE_LOG_CONFIG).instrumentation_mask()) & (INSTRUMENT_BIT)) \
&& ((RTI_SUBMODULE_MASK_ALL) & (RTI_SUBMODULE_MASK_ALL)))
#define SERVICELog_flushActivityContextWithAction(INSTRUMENT_BIT, ACTION) \
SERVICELog_logMessage((INSTRUMENT_BIT), &RTI_LOG_ANY_s, (ACTION));
#define SERVICELog_flushActivityContext(INSTRUMENT_BIT) \
SERVICELog_logMessage((INSTRUMENT_BIT), &RTI_LOG_ANY_s, "");
/*
* The macro:
* - Creates a contextScope
* - Enter a resource entry into the context.
* - Enter an activity entry into the context.
*
* When the function where the macro is called is end, the destructor of
* the contextScope will be called and the entries will leave the context.
*/
#define RTI_SERVICE_CONTEXT_ENTER( \
RESOURCE_ID, \
...) \
rti::advlog::ContextScope context_scope_guard_implicit__; \
context_scope_guard_implicit__.enter(RESOURCE_ID); \
context_scope_guard_implicit__.enter(__VA_ARGS__)
#define RTI_SERVICE_CONTEXT_ENTER_LOG( \
RESOURCE_ID, \
...) \
RTI_SERVICE_CONTEXT_ENTER( \
RESOURCE_ID, \
__VA_ARGS__); \
SERVICELog_flushActivityContext(RTI_LOG_BIT_LOCAL)
#endif /* HPP_SERVICE_LOG_CONFIG_HPP_ */
@@ -0,0 +1,37 @@
/*
* $Id$
*
* (c) Copyright, Real-Time Innovations, 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 HPP_SERVICE_MONITORING_COUNTERS_HPP_
#define HPP_SERVICE_MONITORING_COUNTERS_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 <dds/core/types.hpp>
namespace rti { namespace apputils { namespace monitoring {
struct NetworkPerformanceCounters {
NetworkPerformanceCounters()
:received_samples(0), received_bytes(0), latency_ms(0)
{
}
int64_t received_samples;
int64_t received_bytes;
int64_t latency_ms;
};
} } }// rti::apputils::monitoring
#endif /* HPP_SERVICE_MONITORING_COUNTERS_HPP_ */
@@ -0,0 +1,52 @@
/*
* $Id$
*
* (c) Copyright, Real-Time Innovations, 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 HPP_SERVICE_MONITORING_UTILS_HPP_
#define HPP_SERVICE_MONITORING_UTILS_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 "osapi/osapi_host.h"
#include "osapi/osapi_process.h"
#include "apputils/apputils_monitoring.h"
#include <rti/core/Guid.hpp>
#include <rti/apputils/ResourceIdentifier.hpp>
namespace rti { namespace apputils { namespace monitoring {
inline
void compute_object_id(
rti::core::Guid& out_guid,
const rti::core::Guid& application_id,
const rti::apputils::ResourceIdentifier& resource_id)
{
APPUTILSMonitoringSupport_compute_resource_guid(
&out_guid.native(),
&application_id.native(),
&resource_id.native());
}
inline
void compute_application_guid(
rti::core::Guid &out_guid,
const std::string& application_name)
{
APPUTILSMonitoringSupport_compute_application_guid(
&out_guid.native(),
application_name.c_str());
}
} } }// rti::apputils::monitoring
#endif /* HPP_SERVICE_MONITORING_UTILS_HPP_ */
@@ -0,0 +1,214 @@
/*
(c) Copyright, Real-Time Innovations, 2023-.
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_APPUTILS_SQLITEVERIFIER_HPP_
#define HPP_APPUTILS_SQLITEVERIFIER_HPP_
#include "rti/apputils/SQLiteConnection.hpp"
#include "rti/apputils/test/TestFramework.hpp"
#include "rti/util/util.hpp"
#include "rti/recording/storage/EStorageFormat.hpp"
namespace rti { namespace apputils { namespace test {
/**
* @brief Basic utility class with different checks for an SQLite Connection.
*/
class SQLiteVerifierBase {
public:
SQLiteVerifierBase(rti::apputils::SQLiteConnection& connection) :
connection_(connection) { }
bool check_table_exists(const std::string& table)
{
std::ostringstream string_stream;
string_stream << "SELECT name FROM sqlite_master WHERE name = '";
string_stream << table;
string_stream << "'";
rti::apputils::SQLiteConnection::RowIterator row_it =
connection_.begin(string_stream.str());
if (!row_it.at_end()) {
return true;
}
return false;
}
bool wait_till_table_exists(
const std::string& table,
const unsigned int seconds = DEFAULT_TEST_TIMEOUT_SEC)
{
bool exists = check_table_exists(table);
dds::core::Duration sleepDuration(1,0);
for (uint32_t i = 0; i < seconds && !exists; i++) {
rti::util::sleep(sleepDuration);
exists = check_table_exists(table);
}
if (!exists) {
RTITestLogger_log(
RTI_LOG_BIT_EXCEPTION,
&RTI_TEST_LOG_FAILURE_TEMPLATE,
"Table not found: %s",
table.c_str());
}
return exists;
}
bool check_column_exists(
const std::string& table,
const std::string& column)
{
std::ostringstream string_stream;
string_stream << "PRAGMA table_info([" << table << "])";
rti::apputils::SQLiteConnection::RowIterator row_it =
connection_.begin(string_stream.str());
while (!row_it.at_end()) {
std::string column_name;
row_it.get(1, column_name);
if (column_name.compare(column) == 0) {
return true;
}
++row_it;
}
return false;
}
uint32_t num_rows_for_statement(const std::string& sql)
{
rti::apputils::SQLiteConnection::RowIterator row_it =
connection_.begin(sql);
uint32_t row_count = 0;
while (!row_it.at_end()) {
row_count++;
++row_it;
}
return row_count;
}
/**
* @pre check_table_exists(table) == true
*/
uint32_t num_rows(
const std::string& table,
const bool filter_invalid = false)
{
std::ostringstream string_stream;
string_stream << "SELECT COUNT(*) FROM [" << table << "]";
if (filter_invalid) {
string_stream << " WHERE SampleInfo_valid_data = 1";
}
rti::apputils::SQLiteConnection::RowIterator row_it =
connection_.begin(string_stream.str());
int64_t value = 0;
row_it.get(0, value);
return (uint32_t) value;
}
bool check_num_rows(
const std::string& table,
const uint32_t expected_count,
const bool filter_invalid = false)
{
try {
RTI_TEST_ASSERT_EQUALS_INT(
expected_count,
num_rows(table, filter_invalid));
} catch (const std::exception&) {
return false;
}
return true;
}
bool check_num_rows_for_statement(
const std::string& sql,
const unsigned int expected_count)
{
try {
RTI_TEST_ASSERT_EQUALS_INT(
expected_count,
num_rows_for_statement(sql));
} catch (const std::exception&) {
return false;
}
return true;
}
bool wait_till_num_rows(
const std::string& table,
const unsigned int expected_count,
const bool filter_invalid = false,
const unsigned int seconds = DEFAULT_TEST_TIMEOUT_SEC)
{
try {
RTI_TEST_WAIT_FOR_EQUALS_INT(
expected_count,
num_rows(table, filter_invalid),
static_cast<int32_t>(seconds));
} catch (const std::exception& ex) {
RTITestLogger_log(
RTI_LOG_BIT_EXCEPTION,
&RTI_TEST_LOG_FAILURE_TEMPLATE,
"exception thrown: %s",
ex.what());
return false;
}
return true;
}
bool wait_till_num_rows_for_statement(
const std::string& sql,
const unsigned int expected_count,
const unsigned int seconds = DEFAULT_TEST_TIMEOUT_SEC)
{
try {
RTI_TEST_WAIT_FOR_EQUALS_INT(
expected_count,
num_rows_for_statement(sql),
static_cast<int32_t>(seconds));
} catch (const std::exception& ex) {
RTITestLogger_log(
RTI_LOG_BIT_EXCEPTION,
&RTI_TEST_LOG_FAILURE_TEMPLATE,
"exception thrown: %s",
ex.what());
return false;
}
return true;
}
bool check_num_rows_invariant(
const std::string& table,
const unsigned int expected_count,
const bool filter_invalid = false,
const unsigned int seconds = DEFAULT_TEST_TIMEOUT_SEC)
{
const struct RTINtpTime sleepTime = {0,429496730};
int sleeps = 0;
bool result = check_num_rows(table, expected_count, filter_invalid);
while(result && sleeps < (static_cast<int32_t>(seconds)) * 10) {
RTIOsapiThread_sleep(&sleepTime);
++sleeps;
result = check_num_rows(table, expected_count, filter_invalid);
}
return result;
}
protected:
rti::apputils::SQLiteConnection& connection_;
};
} } } /* namespace rti::apputils::test */
#endif /* HPP_APPUTILS_SQLITEVERIFIER_HPP_ */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,95 @@
/*
(c) Copyright, Real-Time Innovations, 2023.
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_APPUTILS_TEST_LOG_CAPTURE_HPP_
#define HPP_APPUTILS_TEST_LOG_CAPTURE_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/apputils/ServiceException.hpp>
#include "rtitest/test_setting.h"
#include "ddsctesthelpers/test_helper.h"
namespace rti { namespace apputils { namespace test {
/**
* @brief This class is a C++ wrapper for the APPUTILSTestUtils_LoggerDevice
* type, used to capture logs and find expected messages.
*/
class TestLogCapture {
public:
TestLogCapture(const std::string& expected_message) :
expected_message_(expected_message)
{
device_data_ = DDSCTesterHelperLoggerDeviceData_INITIALIZER(NULL);
if (!DDSCTesterHelperLoggerDeviceData_initialize(&device_data_)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_INIT_FAILURE_s,
"logger device data");
}
device_data_.expectedMessage = expected_message_.c_str();
if (!DDSCTesterHelper_cacheLoggingConfiguration()) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_FAILURE_s,
"cache logging configuration");
}
// Prepare the device logger for catching the expected message
logger_device_ = NDDS_Config_LoggerDevice_INITIALIZER;
logger_device_.device_data = &device_data_;
logger_device_.write = DDSCTesterHelper_loggerDeviceWrite;
if (!NDDS_Config_Logger_set_output_device(
NDDS_Config_Logger_get_instance(),
&logger_device_)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_INIT_FAILURE_s,
"set output device");
}
}
~TestLogCapture()
{
DDSCTesterHelperLoggerDeviceData_finalize(&device_data_);
// Restore the logging configuration; this will restore the previous
// output device if it was changed
if (!DDSCTesterHelper_restoreLoggingConfiguration()) {
RTITestLogger_log(
RTI_LOG_BIT_EXCEPTION,
&RTI_TEST_LOG_FAILURE_TEMPLATE,
"restore logging configuration");
}
}
unsigned int found_messages() const
{
return device_data_.foundMessages;
}
private:
struct NDDS_Config_LoggerDevice logger_device_;
struct DDSCTesterHelperLoggerDeviceData device_data_;
std::string expected_message_;
};
} } } /* namespace rti::apputils::test */
#endif /* HPP_APPUTILS_TEST_LOG_CAPTURE_HPP_ */
// --------------------------------------------------------------------
/* End $Id$ */
@@ -0,0 +1,83 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
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_APPUTILS_LOCKEDBUFFER_HPP_
#define HPP_APPUTILS_LOCKEDBUFFER_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 "dds/core/types.hpp"
namespace rti { namespace apputils { namespace util {
/**
* A type-agnostic class that services as a locked, unmodifiable region in
* memory. This is handy to transport a data buffer from one code region to
* another without having to perform any copy operations. Producer of the buffer
* and consumer of the buffer know how to work with the raw data.
*/
class UntypedLockedBuffer {
public:
UntypedLockedBuffer() : buffer_(NULL), size_(0) {}
UntypedLockedBuffer(const void *buffer, const uint32_t size) :
buffer_(buffer), size_(size) {}
~UntypedLockedBuffer() {}
void set(const void *buffer, const uint32_t size)
{
buffer_ = buffer;
size_ = size;
}
void reset()
{
buffer_ = NULL;
size_ = 0;
}
uint32_t size() const { return size_; }
protected:
const void * buffer() const { return buffer_; }
private:
const void *buffer_;
uint32_t size_;
};
/**
* This class represents a locked, unmodifiable region in memory. This is handy
* to transport a data buffer from one code region to another without having to
* perform any copy operations. Producer of the buffer and consumer of the
* buffer know how to work with the raw data.
*/
template <typename T>
class LockedBuffer : public UntypedLockedBuffer {
public:
LockedBuffer() : UntypedLockedBuffer() {}
LockedBuffer(const T *buffer, const uint32_t size) :
UntypedLockedBuffer(static_cast<const void *>(buffer), size) {}
~LockedBuffer() {}
void set(const T *buffer, const uint32_t size)
{
UntypedLockedBuffer::set(static_cast<const void *>(buffer), size);
}
const T * buffer() const {
return static_cast<const T *>(UntypedLockedBuffer::buffer());
}
};
} } } // namespace rti::apputils::util
#endif /* HPP_APPUTILS_LOCKEDBUFFER_HPP_ */
@@ -0,0 +1,495 @@
/*
* (c) Copyright, Real-Time Innovations, 2018.
* 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_APPUTILS_PATH_HPP_
#define HPP_APPUTILS_PATH_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 <string>
#include <vector>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdint.h>
#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(RTI_UNIX) || defined(RTI_QNX)
#include <unistd.h>
#include <time.h>
#endif
#if defined(RTI_UNIX) || defined(RTI_QNX)
#if !defined(_XOPEN_SOURCE) && !defined(RTI_DARWIN)
#define _XOPEN_SOURCE 600
#endif
#include <ftw.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdint.h>
#endif
#ifdef RTI_WIN32
#include <windows.h>
#endif
#include "osapi/osapi_type.h"
#include "osapi/osapi_utility.h"
#include <rti/core/Exception.hpp>
#include <rti/apputils/ServiceException.hpp>
namespace rti { namespace apputils { namespace util {
class Path {
public:
Path()
{ }
Path(const std::string& path) : path_string_(path)
{
path_string_ = remove_double_separators(path_string_);
path_string_ = remove_trailing_separators(path_string_);
}
Path(const Path& path) : path_string_(path.path_string_)
{ }
operator const std::string &() const
{
return path_string_;
}
operator const char *() const
{
return path_string_.c_str();
}
const char *c_str() const
{
return path_string_.c_str();
}
bool empty() const
{
return path_string_.empty();
}
void append(const std::string& fragment)
{
if (!path_string_.empty()) {
path_string_ += "/";
}
path_string_ += fragment;
path_string_ = remove_double_separators(path_string_);
path_string_ = remove_trailing_separators(path_string_);
}
void append(const Path& fragment)
{
append((const std::string&) fragment);
}
void operator+=(const std::string& fragment)
{
append(fragment);
}
void operator+=(const Path& fragment)
{
append((const std::string&) fragment);
}
Path operator+(const std::string& other) const
{
Path path(*this);
path.append(other);
return path;
}
Path operator+(const Path& other) const
{
Path path(*this);
path.append(other);
return path;
}
int compare(const Path& other)
{
return path_string_.compare((const std::string&) other);
}
int compare(const std::string& other)
{
return path_string_.compare(other);
}
int compare(const char *other)
{
return path_string_.compare(other);
}
/**
* Path is interpreted as a file. Return whether the file exists or not.
*/
bool exists() const
{
// Check if the path is a file and if it exists
if (RTIOsapiFile_exists(path_string_.c_str()) == RTI_TRUE) {
return true;
} else {
#if defined(RTI_UNIX) || defined(RTI_QNX)
// Otherwise check if it's a directory and if it exists
struct stat info;
if (stat(path_string_.c_str(), &info) == 0
&& S_ISDIR(info.st_mode)) {
return true;
} else {
return false;
}
#elif defined(RTI_WIN32)
#ifndef S_ISDIR
#define S_ISDIR(mode) (((mode) &_S_IFMT) == _S_IFDIR)
#endif
// Otherwise check if it's a directory and if it exists
struct _stat info;
if (_stat(path_string_.c_str(), &info) == 0
&& S_ISDIR(info.st_mode)) {
return true;
} else {
return false;
}
#endif
}
}
static void create_directory(const Path& path)
{
#if defined(RTI_UNIX) || defined(RTI_QNX)
errno = 0;
if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0
&& (errno != EEXIST)) {
std::stringstream error_msg;
error_msg << "!create directory: " << path << "\n"
<< "CreateDirectory() error code: " << errno << "\n";
throw dds::core::IllegalOperationError(error_msg.str());
}
#elif defined(RTI_WIN32)
if (!CreateDirectory(path, NULL)) {
DWORD last_error = GetLastError();
if (last_error != ERROR_ALREADY_EXISTS) {
std::stringstream error_msg;
error_msg << "!create directory: " << path << "\n"
<< "CreateDirectory() error code: " << last_error
<< "\n";
throw dds::core::IllegalOperationError(error_msg.str());
}
}
#else
throw dds::core::IllegalOperationError("unsupported");
#endif
}
/**
* Interpreting the path as a directory, create any non-existing directories
* in the path.
*/
void create_directory()
{
// If the path is a file, and it exists, exit
if (exists()) {
return;
}
// Get splits, build a
std::vector<std::string> splits = split();
Path aux;
for (std::vector<std::string>::iterator split_it = splits.begin();
split_it != splits.end();
split_it++) {
aux += *split_it;
if (!aux.exists()) {
create_directory(aux);
}
}
}
static void remove_directory(const Path& path)
{
#if defined(RTI_UNIX) || defined(RTI_QNX)
errno = 0;
if (nftw(path, remove_file, 20, FTW_DEPTH) == -1) {
if (errno != ENOENT) {
perror("nftw");
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_FAILURE_s,
"remove_directory() error");
}
}
#else
if (!RTIOsapiFile_removeFileOrDirectory(path.c_str())) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_ss,
"Failed to delete directory: ",
path.c_str());
}
#endif
}
void copy_to(const Path& destination_path)
{
if (!exists()) {
return;
}
try {
std::ifstream src(path_string_.c_str(), std::ios::binary);
std::ofstream dst(
destination_path.path_string_.c_str(),
std::ios::binary);
dst << src.rdbuf();
} catch (std::exception& ex) {
std::stringstream stream;
stream << "Failed to copy file" << std::endl;
stream << " origin : " << path_string_ << std::endl;
stream << " destination: " << destination_path << std::endl;
stream << " error message: " << ex.what() << std::endl;
DDSLog_exception(&RTI_LOG_ANY_s, stream.str().c_str());
}
}
void append_extension(const std::string& extension)
{
path_string_ += extension;
}
/**
* This method detects and returns a (last) "." in the last split of a
* string. The substring after this dot is considered to be the file
* extension.
*/
std::string detect_file_extension()
{
std::string file_extension;
std::vector<std::string> splits = split();
std::string last_split = splits[splits.size() - 1];
std::string::size_type pos = last_split.find_last_of('.');
if (pos != std::string::npos) {
file_extension = last_split.substr(pos + 1);
}
return file_extension;
}
/**
* This method returns the file name (the last split in the path). Depending
* on the parameter, it will strip out the file extension or not.
*/
std::string detect_file_name(bool include_extension = true) const
{
std::vector<std::string> splits = split();
std::string last_split = splits[splits.size() - 1];
if (!include_extension) {
std::string::size_type pos = last_split.find_last_of('.');
if (pos != std::string::npos) {
return last_split.substr(0, pos);
}
}
return last_split;
}
std::vector<std::string> split() const
{
std::vector<std::string> splits;
std::istringstream stream(path_string_);
std::string string_split;
bool prepend_separator = false;
while (getline(stream, string_split, '/')) {
if (string_split.empty()) {
// This can happen if the path is absolute (starts with a
// separator). The first split should contain that separator.
// Signal this with a boolean variable
prepend_separator = true;
continue;
}
if (prepend_separator) {
splits.push_back("/" + string_split);
prepend_separator = false;
} else {
splits.push_back(string_split);
}
}
return splits;
}
static Path from_splits(const std::vector<std::string>& splits)
{
Path path;
for (size_t i = 0; i < splits.size(); i++) {
path += splits[i];
}
return path;
}
uint64_t file_size() const
{
#ifdef RTI_WIN32
HANDLE file_handle = CreateFile(
path_string_.c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
DDSLog_warn(
&RTI_LOG_ANY_ss,
"Failed to get file size for file: ",
path_string_.c_str());
return 0;
}
LARGE_INTEGER size;
if (!GetFileSizeEx(file_handle, &size)) {
CloseHandle(file_handle);
DDSLog_warn(
&RTI_LOG_ANY_ss,
"Failed to get file size for file: ",
path_string_.c_str());
return 0;
}
CloseHandle(file_handle);
return size.QuadPart;
#else
struct stat buffer;
if (stat(path_string_.c_str(), &buffer) != 0) {
DDSLog_warn(
&RTI_LOG_ANY_ss,
"Failed to get file size for file: ",
path_string_.c_str());
return 0;
}
return (uint64_t) buffer.st_size;
#endif
}
#if !defined(RTI_INTY)
/*
* CORE-10727 [Antonio L]:
* cwd() is not supported in all the architectures. We have to
* port it.
*/
static Path cwd()
{
char working_directory[RTI_OSAPI_STRING_SEQ_STRING_MAX_SIZE] = { 0 };
bool no_error = false;
no_error =
(RTIOsapiUtility_getCurrentDirectory(
working_directory,
RTI_OSAPI_STRING_SEQ_STRING_MAX_SIZE)
!= NULL);
if (!no_error) {
int errnum = RTIOsapiUtility_getError();
char error_string[RTI_OSAPI_ERROR_STRING_MAX_SIZE] = { 0 };
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_OS_FAILURE_sXs,
"getcwd",
errnum,
RTIOsapiUtility_getErrorString(
error_string,
RTI_OSAPI_ERROR_STRING_MAX_SIZE,
errnum));
}
return Path(working_directory);
}
#endif
private:
std::string path_string_;
#define SEPARATOR_STR "/"
/**
* Converter Windows-style separators into Unix-style ones
*/
std::string normalize(const std::string& path)
{
std::string normalized(path);
const std::string SEPARATOR(SEPARATOR_STR);
std::string::size_type pos = normalized.find_first_of('\\');
while (pos != std::string::npos) {
normalized = normalized.replace(pos, 1, SEPARATOR);
pos = normalized.find_first_of('\\', pos + 1);
}
return normalized;
}
std::string remove_trailing_separators(const std::string& path)
{
std::string modified(normalize(path));
if (!modified.empty() && modified.at(modified.size() - 1) == '/') {
modified.erase(modified.size() - 1);
}
return modified;
}
std::string remove_double_separators(std::string& path)
{
const std::string DOUBLE_SEPARATOR_STR("//");
std::string modified(normalize(path));
std::string::size_type pos = modified.find(DOUBLE_SEPARATOR_STR);
while (pos != std::string::npos) {
modified = modified.replace(
pos,
DOUBLE_SEPARATOR_STR.size(),
SEPARATOR_STR);
pos = modified.find(DOUBLE_SEPARATOR_STR, pos + 1);
}
return modified;
}
static int remove_file(
const char *fpath,
const struct stat *sb,
int tflag,
struct FTW *ftwbuf)
{
RTIOsapiUtility_unusedParameter(sb);
RTIOsapiUtility_unusedParameter(tflag);
RTIOsapiUtility_unusedParameter(ftwbuf);
#ifdef RTI_QNX
/**
* In QNX we create the working directory in the NFS. Because the NFS
* have important delays, if we try to remove all the directories,
* the remove will fail because the NFS will accept the request to
* remove the files, but they won't be removed once we reach the upper
* level. Therefore, we will not remove the directories of the QNX
* testers
*/
struct stat buf;
int err = stat(fpath, &buf);
errno = 0;
if (err == 0 && (buf.st_mode & _S_IFMT) != S_IFDIR)
errno = remove(fpath);
return errno;
#else
return remove(fpath);
#endif
}
};
}}} // namespace rti::apputils::util
#endif /* HPP_APPUTILS_PATH_HPP_ */
@@ -0,0 +1,122 @@
/*
* (c) Copyright, Real-Time Innovations, 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 APPUTILS_HPP_
#define APPUTILS_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 <cstdint>
#include <cstdio>
#include <cstdlib>
#include <limits>
#include <string>
#include <sstream>
#include "osapi/osapi_utility.h"
#include <dds/core/types.hpp>
#include <rti/core/Exception.hpp>
#include "dds/core/Time.hpp"
#define STATIC_CONST_STRING_DEFINITION(classname, name, value) \
const std::string& classname::name() \
{ \
static std::string name##var(value); \
return name##var; \
}
#define RECORDER_FILE_PATH_MAX_LENGTH (4096)
namespace rti { namespace apputils { namespace util {
constexpr int64_t g_int64_max = 0x7FFFFFFFFFFFFFFFULL;
constexpr uint64_t g_uint64_max = 0xFFFFFFFFFFFFFFFFULL;
inline
std::string normalize_path(const std::string& file_name)
{
char normalized[RECORDER_FILE_PATH_MAX_LENGTH] = {'\0'};
if (!RTIOsapiUtility_normalizePath(
normalized,
RECORDER_FILE_PATH_MAX_LENGTH,
file_name.c_str())) {
std::stringstream error_msg;
error_msg << "!normalize path " << file_name.c_str() << "\n";
throw dds::core::IllegalOperationError(error_msg.str());
}
return normalized;
}
inline
int64_t convert_uint64_into_int64(uint64_t value)
{
int64_t signed_int64 = 0;
if (value > g_int64_max) {
signed_int64 = g_int64_max;
} else {
signed_int64 = (int64_t) value;
}
return signed_int64;
}
inline
uint64_t to_nanosecs(dds::core::Time time)
{
uint64_t nanosec;
try {
nanosec = time.to_nanosecs();
} catch (std::overflow_error&) {
nanosec = g_uint64_max;
}
return nanosec;
}
/**
* @brief Check if the sum of two values would produce an overflow.
*
* @tparam T type of the elements to be summed.
*
* @param lhs Left-hand side of the sum
* @param rhs Right-hand side of the sum
*
* @return true if the sum overflows, false otherwise.
*/
template <typename T>
bool sum_overflows(T lhs, T rhs)
{
return lhs > 0 && rhs > 0 && (std::numeric_limits<T>::max)() - lhs < rhs;
}
/**
* @brief Check if the sum of two values would produce an underflow.
*
* @tparam T type of the elements to be summed.
*
* @param lhs Left-hand side of the sum
* @param rhs Right-hand side of the sum
*
* @return true if the sum underflows, false otherwise.
*/
template <typename T>
bool sum_underflows(T lhs, T rhs)
{
return lhs < 0 && rhs < 0 && std::numeric_limits<T>::lowest() - lhs > rhs;
}
} } } // namespace rti:apputils::util
#endif /* APPUTILS_HPP_ */
@@ -0,0 +1,155 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
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_RTI_APPUTILS_VERSIONABLECOMPONENT_HPP_
#define HPP_RTI_APPUTILS_VERSIONABLECOMPONENT_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 <sstream>
#include <string>
#include <stdint.h>
#include <assert.h>
#include "dds/core/Exception.hpp"
namespace rti { namespace apputils { namespace util {
class ComponentVersion {
public:
constexpr ComponentVersion() noexcept :
major_(0),
minor_(0)
{ }
constexpr ComponentVersion(const uint8_t major, const uint8_t minor) noexcept :
major_(major),
minor_(minor)
{ }
ComponentVersion(const std::string& version_str)
{
std::istringstream stream(version_str);
int16_t value;
stream >> value;
if (stream.fail()) {
throw dds::core::InvalidArgumentError(version_string_error(version_str));
}
major_ = static_cast<uint8_t>(value);
char separator;
stream >> separator;
if (stream.fail() || separator != '.') {
throw dds::core::InvalidArgumentError(version_string_error(version_str));
}
stream >> value;
if (stream.fail()) {
throw dds::core::InvalidArgumentError(version_string_error(version_str));
}
minor_ = static_cast<uint8_t>(value);
}
uint8_t get_major() const noexcept { return major_; }
uint8_t get_minor() const noexcept { return minor_; }
bool operator ==(const ComponentVersion& other) const noexcept
{
return (major_ == other.major_ && minor_ == other.minor_);
}
bool operator !=(const ComponentVersion& other) const noexcept
{
return !(*this == other);
}
bool operator < (const ComponentVersion& other) const noexcept
{
if ((int16_t) major_ - (int16_t) other.major_ == 0) {
return ((int16_t) minor_ - (int16_t) other.minor_ < 0);
} else {
return ((int16_t) major_ - (int16_t) other.major_ < 0);
}
}
bool operator > (const ComponentVersion& other) const noexcept
{
if ((int16_t) major_ - (int16_t) other.major_ == 0) {
return ((int16_t) minor_ - (int16_t) other.minor_ > 0);
} else {
return ((int16_t) major_ - (int16_t) other.major_ > 0);
}
}
operator std::string () const noexcept
{
return std::to_string(major_) + "." + std::to_string(minor_);
}
private:
uint8_t major_;
uint8_t minor_;
std::string version_string_error (const std::string & str) const noexcept
{
return "VersionableComponent: invalid version string: " + str;
}
};
/**
* @brief A versionable component has a name and a version and it's used to
* keep track of the versions of the components used to record data.
* This information is kept in the 'metadata' database file. It can later
* be recovered by Replay/Converter to use exactly the same components'
* versions that were when recording.
* @param VersionType The version object to be used. By default, the Version
* type implemented above is used (a simple, two-digit, stringifyable
* version type).
*/
template<typename VersionType>
class VersionableComponent {
public:
VersionableComponent(
std::string component_name,
const VersionType& version) :
component_name_(component_name),
version_(version) { }
const VersionType& version() const { return version_; }
const std::string& component_name() const { return component_name_; }
void verify_version(const VersionType& version) const
{
if (version > version_) {
std::stringstream error_stream;
error_stream << "VersionableComponent: " << component_name_.c_str()
<< ": detected newer version. The current version of the "
<< "component in this tool ("
<< ((const std::string&) version_).c_str()
<< ") is unable to read the newer "
<< component_name_.c_str() <<" version ("
<< ((const std::string&) version).c_str() <<") found ";
throw dds::core::IllegalOperationError(error_stream.str());
}
}
private:
std::string component_name_;
VersionType version_;
};
typedef VersionableComponent<ComponentVersion> DefaultVersionableComponent;
} } } /* namespace rti::apputils::util */
#endif /* HPP_RTI_APPUTILS_VERSIONABLECOMPONENT_HPP_ */
@@ -0,0 +1,223 @@
/**
* (c) Copyright, Real-Time Innovations, 2020. 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_CDS_LOGGER_HPP_
#define RTI_CDS_LOGGER_HPP_
#include <dds/core/Reference.hpp>
#include <rti/config/Logger.hpp>
#include "clouddiscoveryservice/clouddiscoveryservice_service.h"
#include "clouddiscoveryservice/clouddiscoveryservice_log.h"
namespace rti { namespace cds {
/** \defgroup RTI_CDS_Logger Logging
*
* @brief Provides control over the logging facilities for @product.
*/
/** \ingroup RTI_CDS_Logger
*
* @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_CLOUD_DISCOVERY,
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_CLOUD_DISCOVERY);
return static_cast<rti::config::Verbosity::type>(instrumentation_mask);
}
/**
* @brief Logs a 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::cds::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::cds::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 a 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::cds::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::cds::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_CDS_Logger_log(
static_cast<NDDS_Config_LogLevel>(level.underlying()),
"%s",
msg);
}
Logger()
{
}
// Disable copy
Logger(const Logger&);
Logger& operator=(const Logger&);
};
}}
#endif // RTI_CDS_LOGGER_HPP_
@@ -0,0 +1,14 @@
#ifndef RTI_CDS_PROPERTYSET_HPP
#define RTI_CDS_PROPERTYSET_HPP
#include <rti/routing/PropertySet.hpp>
namespace rti { namespace recording {
typedef rti::routing::PropertySet PropertySet;
}}
#endif /* RTI_CDS_PROPERTYSET_HPP */
@@ -0,0 +1,200 @@
/**
* (c) Copyright, Real-Time Innovations, 2020. 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_CDS_CLOUD_DISCOVERY_SERVICE_HPP_
#define RTI_CDS_CLOUD_DISCOVERY_SERVICE_HPP_
#include <dds/core/Reference.hpp>
#include <rti/config/Logger.hpp>
#include <rti/cds/Logger.hpp>
#include <rti/cds/ServiceProperty.hpp>
#include <rti/cds/detail/CloudDiscoveryServiceImpl.hpp>
#include "routingservice/routingservice_service.h"
#include "clouddiscoveryservice/clouddiscoveryservice_log.h"
namespace rti { namespace cds {
/*e \defgroup RTI_CDS_ServiceLibModule Library API
*
* @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::cds::Service service(
* rti::cds::ServiceProperty()
* .cfg_file("MyCloudDiscoveryService.xml")
* .service_name("MyCloudDiscoveryService"));
* ...
*
* service.start();
*
* while (keep_running) {
* sleep();
* ...
* }
*
* return 0;
* }
*
* \endcode
*
* Instead of a file, you can use XML strings to configure @product.
* See ServiceProperty for more information.
* <p>
* To build your application you need to link with the @product native library
* in <b> &lt;@ndds home&gt;/bin/&lt;architecture&gt;/ </b>.
*
* An example is provided at <b>https://github.com/rticommunity/rticonnextdds-examples/tree/master/examples/cloud_discovery_service/library_api</b>.
*
* ### Development Requirements
*
* | | Linux Systems | Windows Systems |
* | ----------------------------: | :----------------------------: | :---------------------------: |
* | Link Libraries (Compile Time) | librticlouddiscoveryservice.so | rticlouddiscoveryservice.dll |
* | Shared Libraries (Run Time) | librtiroutingservice.so | rtiroutingservice.dll |
* | ^ | librtidlc.so | rtidlc.dll |
* | ^ | librticonnextmsgc.so | rticonnextmsgc.dll |
* | ^ | libnddsmetp.so | nddsmetp.dll |
* | ^ | librtiapputilsc.so | rtiapputilsc.dll |
* | ^ | librtixml2.so | rtixml2.dll |
* | ^ | libnddscpp2.so | nddscpp2.dll |
* | ^ | libnddsc.so | nddsc.dll |
* | ^ | libnddscore.so | nddscore.dll |
* | Static Libraries | librticlouddiscoveryservicez.a | rticlouddiscoveryservicez.lib |
* | ^ | librtiroutingservicez.a | rtiroutingservicez.lib |
* | ^ | librtidlcz.a | rtidlcz.lib |
* | ^ | librticonnextmsgcz.a | rticonnextmsgcz.lib |
* | ^ | libnddsmetpz.a | nddsmetpz.lib |
* | ^ | librtiapputilscz.a | rtiapputilscz.lib |
* | ^ | librtixml2z.a | rtixml2z.lib |
* | ^ | libnddscpp2z.a | nddscpp2z.lib |
* | ^ | libnddscz.a | nddscz.lib |
* | ^ | libnddscorez.a | nddscorez.lib |
* | Headers | rti/cds/CloudDiscoveryService.hpp | |
*
* <b>NOTE:</b> If you are using debug libraries, remember to add the 'd' suffix
* to the library name. For shared libraries on macOS systems, the library name
* is the same as that for Linux except the extension is '.dylib' instead of '.so'.
*/
/** \ingroup RTI_CDS_ServiceLibModule
*
* @brief The @product.
*
*/
class Service : public dds::core::Reference<CloudDiscoveryServiceImpl> {
public:
typedef dds::core::Reference<CloudDiscoveryServiceImpl> Base;
OMG_DDS_REF_TYPE_NOTYPENAME(
Service,
dds::core::Reference,
CloudDiscoveryServiceImpl);
/**
* @brief Creates a @product instance
*
* @param property
* @rs_st_in The property to configure @product instance.
*
*/
explicit Service(const ServiceProperty& property)
: Base(new CloudDiscoveryServiceImpl(property))
{
this->delegate()->remember_reference(this->delegate());
}
Service(const RTI_CDS_Property& property)
: Base(new CloudDiscoveryServiceImpl(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 block until the instance is fully stopped.
*/
void stop()
{
this->delegate()->stop();
}
/**
* @brief Returns true if the @product is started.
*
* This operation is useful to inspect if the @product instance is up and running.
*/
bool is_started()
{
return this->delegate()->is_started();
}
/**
* @brief Sets the dds.sec.crypto.rtps_psk_secret_passphrase property
* for the @product instance that is started.
*
* This operation performs an update; if there was no value for the
* dds.sec.crypto.rtps_psk_secret_passphrase property in the XML
* configuration when @product was started, the operation would fail.
*
* @param rtps_psk_secret_passphrase
* The new value for the dds.sec.crypto.rtps_psk_secret_passphrase property
*/
bool update_rtps_psk_secret_passphrase(
const std::string rtps_psk_secret_passphrase)
{
return this->delegate()->update_rtps_psk_secret_passphrase(
rtps_psk_secret_passphrase);
}
/**
* @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::cds::Logger::instance().warn(
"Calling 'rti::cds::Service::finalize_globals()' is no "
"longer necessary and the function will be removed in future "
"versions");
}
};
} }
#endif // RTI_CDS_CLOUD_DISCOVERY_SERVICE_HPP_
@@ -0,0 +1,678 @@
/**
* (c) Copyright, Real-Time Innovations, 2020. 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_CDS_CLOUD_DISCOVERY_SERVICE_PROPERTY_HPP_
#define RTI_CDS_CLOUD_DISCOVERY_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 "clouddiscoveryservice/clouddiscoveryservice_infrastructure.h"
#include "clouddiscoveryservice/clouddiscoveryservice_service.h"
namespace rti { namespace cds {
/** \ingroup RTI_CDS_ServiceLibModule
*
* @brief Specifies the list of domain IDs to allow or deny. Overrides XML
* configuration if specified.
*/
class DomainListProperty {
public:
DomainListProperty() : allow_domain_ids_(""), deny_domain_ids_("")
{
}
DomainListProperty(std::string allow_domain_ids, std::string deny_domain_ids)
{
allow_domain_ids_ = allow_domain_ids;
deny_domain_ids_ = deny_domain_ids;
}
/**
* @brief The list of domain IDs where @product processes the incoming
* participant announcements.
*
* @default Empty string. Use value from XML configuration.
*/
void allow_domain_ids(std::string allow_domain_ids)
{
allow_domain_ids_ = allow_domain_ids;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string& allow_domain_ids()
{
return allow_domain_ids_;
}
/**
* @brief The list of domain IDs to deny or ignore. Overrides
* \ref allow_domain_ids.
*
* @default Empty string. Use value from XML configuration.
*/
void deny_domain_ids(std::string deny_domain_ids)
{
deny_domain_ids_ = deny_domain_ids;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string& deny_domain_ids()
{
return deny_domain_ids_;
}
private:
std::string allow_domain_ids_;
std::string deny_domain_ids_;
};
/** \ingroup RTI_CDS_ServiceLibModule
*
* @brief Specifies the alias name of the transport to be used by @product for
* sending or receiving announcements. It also indicates the port where incoming
* participant announcements are received. Overrides XML configuration if specified.
*
* Refer to \ref_url_cloud_discovery_service_users_manual_available_transports to
* check the list of aliases for the preconfigured transports.
*/
class TransportUnicastProperty {
public:
TransportUnicastProperty(std::string alias, int receive_port)
{
alias_ = alias;
receive_port_ = receive_port;
}
/**
* @brief Transport alias name
*/
void alias(std::string alias)
{
alias_ = alias;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string& alias()
{
return alias_;
}
/**
* @brief Receive port
*/
void receive_port(int receive_port)
{
receive_port_ = receive_port;
}
/**
* @brief Getter (see setter with the same name)
*/
int receive_port()
{
return receive_port_;
}
private:
std::string alias_;
int receive_port_;
};
class PropertyAdapter {
public:
typedef RTI_CDS_Property native_type;
static void initialize(native_type& native_value)
{
static const native_type DEFAULT
= RTI_CDS_Property_INITIALIZER;
native_value = DEFAULT;
// Replicating the defaults from the C Library API as specified in service.ifc
native_value.service_verbosity = RTI_LOG_BIT_EXCEPTION;
native_value.dds_verbosity = RTI_LOG_BIT_EXCEPTION;
}
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_CDS_Property_finalize(&native_value);
}
static void copy(native_type& destination, const native_type& source)
{
if (RTI_CDS_Property_copy(&destination, &source) == NULL) {
throw dds::core::Error("Native RTI_CDS_Property_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_transports_from_native(
std::vector<TransportUnicastProperty>& transport_selection,
const struct RTI_CDS_TransportSelectionProperty *transport_selection_native)
{
for (int i = 0; i < transport_selection_native->count; i++) {
transport_selection.push_back(TransportUnicastProperty(
transport_selection_native->transports[i].alias,
transport_selection_native->transports[i].receive_port));
}
}
static void add_transports_to_native(
struct RTI_CDS_TransportSelectionProperty *transport_selection_native,
std::vector<TransportUnicastProperty>& transport_selection)
{
transport_selection_native->count = transport_selection.size();
for (unsigned int i = 0; i < transport_selection.size(); i++) {
RTIOsapiUtility_strcpy(
transport_selection_native->transports[i].alias,
RTI_CDS_TRANSPORT_UNICAST_PROPERTY_ALIAS_LENGTH_MAX,
transport_selection[i].alias().c_str());
transport_selection_native->transports[i].receive_port
= transport_selection[i].receive_port();
}
}
static void add_domain_list_from_native(
DomainListProperty& domain_ids,
const struct RTI_CDS_DomainListProperty *domain_ids_native)
{
domain_ids.allow_domain_ids(domain_ids_native->allow_domain_ids);
domain_ids.deny_domain_ids(domain_ids_native->deny_domain_ids);
}
static void add_domain_list_to_native(
struct RTI_CDS_DomainListProperty *domain_ids_native,
DomainListProperty& domain_ids)
{
DDS_String_replace(
&domain_ids_native->allow_domain_ids,
domain_ids.allow_domain_ids().c_str());
DDS_String_replace(
&domain_ids_native->deny_domain_ids,
domain_ids.deny_domain_ids().c_str());
}
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);
if (!RTI_RoutingServiceProperties_initialize(native_properties)) {
throw dds::core::Error("failed to initialize native property");
}
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::cds::ServiceProperty> {
typedef rti::cds::PropertyAdapter adapter_type;
typedef RTI_CDS_Property native_type;
};
}
namespace cds {
/** \ingroup RTI_CDS_ServiceLibModule
*
* @brief Configuration properties 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_CDS_Property &native_property)
: Base(native_property)
{
}
/**
* @brief Getter (see setter with the same name)
*/
std::string cfg_file() const
{
return native().cfg_file == NULL ? "" : native().cfg_file;
}
/**
* @brief Path to an @product configuration file
*
* @default Empty string.
*/
ServiceProperty& cfg_file(const std::string& filename)
{
DDS_String_replace(
&native().cfg_file,
filename.c_str());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
const std::vector<std::string>& cfg_strings() const
{
return cfg_strings_;
}
/**
* @brief XML configuration represented as strings
*
* An array of strings that altogether make up an
* XML document to configure @product. This parameter is used
* only if ServiceProperty::cfg_file is empty.
*
* The reason for using an array instead of one single string is to
* get around the limited size of literal strings.
* In general, if you create the XML string dynamically
* the vector needs only one element.
*
* @default Empty.
*/
ServiceProperty& cfg_strings(
const std::vector<std::string>& the_cfg_strings)
{
cfg_strings_ = the_cfg_strings;
if (cfg_strings_.size() > 0) {
if (!RTIOsapiHeap_reallocateArray(
(char ***) &native().cfg_strings,
cfg_strings_.size(),
char *)) {
throw dds::core::OutOfResourcesError("cfg_strings native array");
}
for (uint32_t i = 0; i < cfg_strings_.size(); i++) {
native().cfg_strings[i] = cfg_strings_[i].c_str();
}
}
native().cfg_strings_count = static_cast<int>(cfg_strings_.size());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string service_name() const
{
return native().service_name == NULL ? "" : native().service_name;
}
/**
* @brief The name of the @product configuration to run.
*
* This is the name used to find the &lt;cloud_discovery_service&gt;
* XML tag in the configuration file; this is the default name that will
* be used to refer to this execution in remote administration and
* monitoring if application_name isn't specified.
*
* @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 == NULL ? "" : native().application_name;
}
/**
* @brief Assigns a name to the execution of the RTI Cloud Discovery Service.
*
* Remote commands and status information will refer to the RTI Cloud Discovery
* Service using this name.
*
* \default service_name if this value is not set.
*/
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)
*/
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)
*/
std::vector<TransportUnicastProperty> transport_selection()
{
PropertyAdapter::add_transports_from_native(
transport_selection_,
&native().transport_selection);
return transport_selection_;
}
/**
* @brief Specifies the transport and receive ports used to receive and
* send discovery traffic. Specifically, a receive resource is uniquely
* specified by a transport class-receive port pair.
* Overrides XML configuration if specified.
*
* @default Unspecified. Use value from XML configuration.
*/
ServiceProperty& transport_selection(
const std::vector<TransportUnicastProperty>& transport_selection)
{
transport_selection_ = transport_selection;
PropertyAdapter::add_transports_to_native(
&native().transport_selection,
transport_selection_);
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
DomainListProperty domain_list()
{
PropertyAdapter::add_domain_list_from_native(
domain_list_,
&native().domain_list);
return domain_list_;
}
/**
* @brief Specifies the set of domain IDs the service will accept
* announcements from.
*
* @default Unspecified. Use value from XML configuration.
*/
ServiceProperty& domain_list(
const DomainListProperty& domain_list)
{
domain_list_ = domain_list;
PropertyAdapter::add_domain_list_to_native(
&native().domain_list,
domain_list_);
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 this to true to enable 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 publishing monitoring topics.
*
* Takes precedence over the XML configuration.
* If ServiceProperty::enable_monitoring is false, this value is not
* used even if 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)
*/
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& file_name)
{
DDS_String_replace(
&native().license_file_name,
file_name.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)
{
PropertyAdapter::add_properties_to_native(
&native().user_environment,
user_environment);
return *this;
}
private:
std::vector<std::string> cfg_strings_;
std::vector<TransportUnicastProperty> transport_selection_;
DomainListProperty domain_list_;
};
}}
#endif // RTI_CDS_CLOUD_DISCOVERY_SERVICE_PROPERTY_HPP_
@@ -0,0 +1,86 @@
/**
* (c) Copyright, Real-Time Innovations, 2020. 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_CDS_CLOUD_DISCOVERY_SERVICE_IMPL_HPP_
#define RTI_CDS_CLOUD_DISCOVERY_SERVICE_IMPL_HPP_
#include <dds/core/refmacros.hpp>
#include <rti/core/detail/SelfReference.hpp>
#include <rti/core/Exception.hpp>
#include "clouddiscoveryservice/clouddiscoveryservice_service.h"
#include <rti/cds/ServiceProperty.hpp>
namespace rti { namespace cds {
class CloudDiscoveryServiceImpl
: public rti::core::detail::RetainableType<CloudDiscoveryServiceImpl>
{
public:
explicit CloudDiscoveryServiceImpl(const ServiceProperty& property)
{
native_ = RTI_CDS_Service_new(&property.native());
rti::core::check_create_entity(native_, "CloudDiscoveryService");
}
CloudDiscoveryServiceImpl(const RTI_CDS_Property& property) : native_(NULL)
{
native_ = RTI_CDS_Service_new(&property);
rti::core::check_create_entity(native_, "CloudDiscoveryService");
}
CloudDiscoveryServiceImpl(RTI_CDS_Service *native) : native_(native)
{
rti::core::check_create_entity(native_, "CloudDiscoveryService");
}
~CloudDiscoveryServiceImpl()
{
RTI_CDS_Service_delete(native_);
}
void start()
{
if (!RTI_CDS_Service_start(native_)) {
throw dds::core::Error("Error starting CloudDiscoveryService");
}
}
void stop()
{
if (!RTI_CDS_Service_stop(native_)) {
throw dds::core::Error("Error stopping CloudDiscoveryService");
}
}
bool is_started()
{
return RTI_CDS_Service_is_started(native_);
}
bool update_rtps_psk_secret_passphrase(
const std::string rtps_psk_secret_passphrase)
{
return RTI_CDS_Service_update_rtps_psk_secret_passphrase(
native_,
rtps_psk_secret_passphrase.c_str());
}
RTI_CDS_Service* native() const
{
return native_;
}
private:
RTI_CDS_Service *native_;
};
}}
#endif // RTI_CDS_CLOUD_DISCOVERY_SERVICE_IMPL_HPP_
@@ -0,0 +1,558 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
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_DDS_FLAT_AGGREGATIONBUILDERS_HPP_
#define RTI_DDS_FLAT_AGGREGATIONBUILDERS_HPP_
#include "rti/flat/BuilderHelper.hpp"
#include "rti/flat/Builder.hpp"
#include "xcdr/xcdr_interpreter.h"
namespace rti { namespace flat {
/*
* Parameters describing a member to be added or built.
*
* The information encoded by this structure is used to set the appropriate
* bits in the header that precedes each member of a mutable type.
*/
struct MemberParams {
/*
* Indicates whether the member is part of the key.
*/
bool key;
/*
* Indicates whether the member is the discriminator of a union.
*/
bool discriminator;
/*
* Indicates whether the member has been marked as "must understand".
*/
bool must_understand;
MemberParams() : key(false), discriminator(false), must_understand(false)
{ }
/*
* Check whether the current XCDR2 compliance mask allows the
* specified features.
*
* This function will cache the value of the compliance mask to avoid
* repeated nested function calls at runtime.
*
* @param check_mask The feature bits to check in the compliance mask.
* @param reload_mask If true, force reloading of the compliance mask
* from the global configuration.
* @return true if all the bits in check_mask are set in the compliance
* mask.
*/
static bool xcdr2_compliant(
const RTIXCdrXTypesComplianceMask check_mask,
const bool reload_mask)
{
static bool g_compliance_mask_set = false;
static RTIXCdrXTypesComplianceMask g_compliance_mask = 0;
// Initialize the compliance mask on first use
// There could be a data race here but the worst that can happen is
// that the compliance mask is read more than once.
// The goal is to avoid nested function calls on each and every call.
if (reload_mask || !g_compliance_mask_set) {
g_compliance_mask =
RTIXCdrInterpreter_getGlobalXtypeComplianceMask();
g_compliance_mask_set = true;
}
return (g_compliance_mask & check_mask);
}
/*
* Check if the must_understand bit should be set in the header for this
* member.
*
* The bit will always be set if the must_understand attribute is true.
* Additionally, if the current XCDR2 compliance mask allows it, the bit
* will also be set for key members and discriminators.
*
* @return true if the must_understand bit should be set.
*/
bool has_must_understand_bit() const
{
return must_understand
|| (xcdr2_compliant(
RTI_XCDR_XTYPES_MUST_UNDERSTAND_IN_KEY_AND_DISCRIMINATOR_BIT,
false)
&& (key || discriminator));
}
};
/*
* Provides the common functionality for builders of aggregated types
*
* Extends and specializes AbstractBuilder to add or override the functionality
* required to build an aggregated type:
*
* - Add or build members, prepending the member header
* - Add dheader at the beginning
* - Add parameter-list-end header at the end
*/
/**
* @ingroup RTIFlatBuildersModule
* @brief Base class of struct and union builders.
*
* This class contains implementation details and doesn't add any public function
* to AbstractBuilder. See MyFlatMutableBuilder for a concrete example of a
* struct builder.
*/
class AggregationBuilder : public AbstractBuilder {
protected:
AggregationBuilder() :
dheader_position_(NULL),
emheader_position_(NULL)
{
}
// Create a new top-level builder
AggregationBuilder(
unsigned char *initial_buffer,
offset_t size,
bool initialize_members) :
AbstractBuilder(initial_buffer, size, initialize_members),
dheader_position_(NULL),
emheader_position_(NULL)
{
dheader_position_ = stream().serialize_dheader();
if (dheader_position_ == NULL) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(invalidate());
}
}
public:
// For internal use and testing
//
// Modifies the encapsulation set in the constructor with a custom value.
// This function can only be called after the construction of a non-nested
// Builder, before any member is built or added.
//
void set_encapsulation_impl(RTIXCdrEncapsulationId encapsulation_id)
{
// Only a top-level Builder can change the encapsulation
RTI_FLAT_CHECK_PRECONDITION(!is_nested(), return);
char *current_position = (char *) owned_stream_.current_position();
// This operation is only valid right after construction, when no
// member has been added yet
RTI_FLAT_CHECK_PRECONDITION(
current_position == dheader_position_ + RTI_XCDR_DHEADER_SIZE,
return);
owned_stream_.skip_back(
RTI_XCDR_DHEADER_SIZE + RTI_XCDR_ENCAPSULATION_HEADER_SIZE);
if (!RTIXCdrFlatSample_initializeEncapsulationAndStream(
(char *) owned_stream_.buffer(),
&owned_stream_.c_stream(),
encapsulation_id,
owned_stream_.total_size())) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return);
}
stream().serialize_dheader();
}
protected:
#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
AggregationBuilder(AggregationBuilder&& other) = default;
AggregationBuilder& operator=(AggregationBuilder&& other)
{
if (this == &other) {
return *this;
}
finish_untyped_impl();
AbstractBuilder::operator=(static_cast<AbstractBuilder&&>(other));
dheader_position_ = other.dheader_position_;
emheader_position_ = other.emheader_position_;
return *this;
}
#else
public:
// Enable the safe-move-constructor idiom without C++11 move constructors
struct UntypedAggregationBuilderMoveProxy : AbstractBuilderMoveProxy {
char * dheader_position_;
char * emheader_position_;
};
operator UntypedAggregationBuilderMoveProxy () throw() // move-constructor idiom
{
UntypedAggregationBuilderMoveProxy other;
move_to(other);
return other;
}
protected:
void move_from(UntypedAggregationBuilderMoveProxy& other)
{
AbstractBuilder::move_from(other);
dheader_position_ = other.dheader_position_;
emheader_position_ = other.emheader_position_;
}
void move_to(UntypedAggregationBuilderMoveProxy& other)
{
AbstractBuilder::move_to(other);
other.dheader_position_ = dheader_position_;
other.emheader_position_ = emheader_position_;
}
#endif
protected:
virtual ~AggregationBuilder()
{
// AggregationBuilder::finish_untyped_impl() is specialized
// with respect to AbstractBuilder::finish_untyped_impl()
finish_untyped_impl();
}
template <typename T>
bool add_primitive_member(
member_id_t id,
T value,
const MemberParams& params)
{
RTI_FLAT_BUILDER_CHECK_VALID(return false);
rti::xcdr::Stream::Memento stream_memento(stream());
if (!begin_emheader(id, detail::primitive_lc_code<T>::value, params)) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return false);
}
// no need to call finish_emheader()
if (!stream().serialize_no_align(value)) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return false);
}
stream_memento.discard(); // success: do not restore the current position
return true;
}
template <typename T>
bool add_primitive_member(member_id_t id, T value)
{
static const MemberParams default_params;
return add_primitive_member(id, value, default_params);
}
template <typename OffsetType>
OffsetType add_member(member_id_t id, const MemberParams& params)
{
RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
// save state in case of error
rti::xcdr::Stream::Memento stream_memento(stream());
return add_member<OffsetType>(id, stream_memento, params);
}
template <typename OffsetType>
OffsetType add_member(member_id_t id)
{
RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
// save state in case of error
rti::xcdr::Stream::Memento stream_memento(stream());
static const MemberParams default_params;
return add_member<OffsetType>(id, stream_memento, default_params);
}
template <typename OffsetType>
OffsetType add_member(
member_id_t id,
rti::xcdr::Stream::Memento& stream_memento)
{
static const MemberParams default_params;
return add_member<OffsetType>(id, stream_memento, default_params);
}
template <typename OffsetType>
OffsetType add_member(
member_id_t id,
rti::xcdr::Stream::Memento& stream_memento,
const MemberParams& params)
{
// fixed-size non-primitive members may have a dheader or not; when they
// do the LC code is 5, otherwise it is 4.
if (!begin_emheader(
id,
detail::is_fixed_type_w_dheader<OffsetType>::value() ? 5
: 4,
params)) {
return OffsetType();
}
OffsetType result = AbstractBuilder::add_element<OffsetType>();
finish_emheader();
stream_memento.discard(); // success - do not restore the previous state
return result;
}
template <typename NestedBuilder>
NestedBuilder build_member(member_id_t id, const MemberParams& params)
{
RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
// save state in case of error
rti::xcdr::Stream::Memento stream_memento(stream());
return build_member<NestedBuilder>(id, stream_memento, params);
}
template <typename NestedBuilder>
NestedBuilder build_member(member_id_t id)
{
static const MemberParams default_params;
return build_member<NestedBuilder>(id, default_params);
}
template <typename NestedBuilder>
NestedBuilder build_member(
member_id_t id,
rti::xcdr::Stream::Memento& stream_memento)
{
static const MemberParams default_params;
return build_member<NestedBuilder>(id, stream_memento, default_params);
}
template <typename NestedBuilder>
NestedBuilder build_member(
member_id_t id,
rti::xcdr::Stream::Memento& stream_memento,
const MemberParams& params)
{
if (!begin_emheader(
id,
static_cast<RTIXCdrUnsignedLong>(
detail::lc_code<NestedBuilder>::value()),
params)) {
return NestedBuilder();
}
return AbstractBuilder::build_element_no_align<NestedBuilder>(
stream_memento);
}
unsigned char* finish_sample_impl()
{
RTI_FLAT_BUILDER_CHECK_VALID(return NULL);
RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NULL);
RTI_FLAT_BUILDER_CHECK_CAN_FINISH_SAMPLE(return NULL);
if (!stream().finish_dheader(dheader_position_)) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return NULL);
}
unsigned char *return_sample = stream().buffer();
invalidate();
return return_sample;
}
// Same as finish_impl() but it doesn't throw exceptions or return an Offset
void finish_untyped_impl()
{
if (is_valid() && is_nested()) {
stream().finish_dheader(dheader_position_);
AbstractBuilder::finish_untyped_impl();
}
}
template <typename OffsetType>
OffsetType finish_impl()
{
RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return OffsetType());
stream().finish_dheader(dheader_position_);
return AbstractBuilder::finish_impl<OffsetType>();
}
public:
// For internal use; need to use rti::flat::discard_sample(writer, builder)
unsigned char * discard_sample_impl()
{
RTI_FLAT_BUILDER_CHECK_VALID(return NULL);
RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NULL);
RTI_FLAT_BUILDER_CHECK_CAN_FINISH_SAMPLE(return NULL);
unsigned char *buffer = this->buffer();
invalidate();
return buffer;
}
private:
void finish_member() // override noexcept
{
if (!is_valid()) {
return;
}
finish_emheader();
AbstractBuilder::finish_member();
}
private:
bool begin_emheader(
member_id_t id,
RTIXCdrUnsignedLong lc,
const MemberParams& params)
{
RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return false);
if (!stream().serialize_emheader(
emheader_position_,
id,
lc,
params.has_must_understand_bit())) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return false);
}
return true;
}
void finish_emheader() // noexcept
{
if (emheader_position_ != NULL) {
stream().finish_emheader(emheader_position_);
emheader_position_ = NULL;
}
}
protected:
// Create a nested builder
AggregationBuilder(nested_tag_t, AbstractBuilder& parent, unsigned int alignment)
: AbstractBuilder(nested_tag_t(), parent, alignment),
dheader_position_(NULL),
emheader_position_(NULL)
{
dheader_position_ = stream().serialize_dheader();
if (dheader_position_ == NULL) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(invalidate());
}
}
private:
char * dheader_position_;
char * emheader_position_;
};
// Specializes an AggregationBuilder to enforce that only one member can
// be set at a time
/**
* @ingroup RTIFlatBuildersModule
* @brief Base class of builders for user-defined mutable unions.
*
* Union builders can only add or build a single member.
*
* This class contains implementation details and doesn't add any public function
* to AbstractBuilder.
*/
template <typename Discriminator>
class UnionBuilder : public AggregationBuilder {
protected:
UnionBuilder()
{
}
// Create a new top-level builder
UnionBuilder(
unsigned char *initial_buffer,
offset_t size,
bool initialize_members) :
AggregationBuilder(initial_buffer, size, initialize_members)
{
}
template <typename T>
bool add_primitive_member(member_id_t id, Discriminator disc, T value)
{
RTI_FLAT_BUILDER_CHECK_VALID(return false);
// Always start at the beginning and override any member or discriminator
// that may have been set
move_to_discriminator();
rti::xcdr::Stream::Memento stream_memento(stream());
if (!add_discriminator(disc)) {
return false;
}
if (!AggregationBuilder::add_primitive_member(id, value)) {
return false;
}
stream_memento.discard(); // success: do not restore the current position
return true;
}
template <typename OffsetType>
OffsetType add_member(member_id_t id, Discriminator disc)
{
RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
move_to_discriminator();
rti::xcdr::Stream::Memento stream_memento(stream());
if (!add_discriminator(disc)) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return OffsetType());
}
return AggregationBuilder::add_member<OffsetType>(id, stream_memento);
}
template <typename NestedBuilder>
NestedBuilder build_member(member_id_t id, Discriminator disc)
{
RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
move_to_discriminator();
rti::xcdr::Stream::Memento stream_memento(stream());
add_discriminator(disc);
return AggregationBuilder::build_member<NestedBuilder>(id, stream_memento);
}
// Create a nested builder
UnionBuilder(nested_tag_t, AbstractBuilder& parent, unsigned int alignment)
: AggregationBuilder(nested_tag_t(), parent, alignment)
{
}
private:
void move_to_discriminator()
{
stream().current_position(begin_position() + RTI_XCDR_DHEADER_SIZE);
}
bool add_discriminator(Discriminator disc)
{
MemberParams params;
params.discriminator = true;
return AggregationBuilder::add_primitive_member(0, disc, params);
}
};
} }
#endif // RTI_DDS_FLAT_AGGREGATIONBUILDERS_HPP_
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,220 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
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_DDS_FLAT_BUILDERHELPER_HPP_
#define RTI_DDS_FLAT_BUILDERHELPER_HPP_
namespace rti { namespace flat {
template <typename T>
class PrimitiveSequenceBuilder;
template <typename ElementBuilder>
class MutableSequenceBuilder;
template <typename ElementOffset>
class FinalSequenceBuilder;
template <typename ElementBuilder, unsigned int N>
class MutableArrayBuilder;
class StringBuilder;
namespace detail {
//
// lc_code:
//
template <size_t PrimitiveSize>
struct primitive_lc_code_helper;
template <>
struct primitive_lc_code_helper<1> {
enum {
single = 0, // LC = 1 => member length is 1
sequence = 5 // LC = 5 => member length is also NEXTINT
};
};
template <>
struct primitive_lc_code_helper<2> {
enum {
single = 1, // LC = 1 => member length is 2
sequence = 4 // LC = 4 => member length is provided as an additional int
};
};
template <>
struct primitive_lc_code_helper<4> {
enum {
single = 2, // LC = 2 => member length is 4
sequence = 6 // LC = 6 => member length is 4 * NEXTINT
};
};
template <>
struct primitive_lc_code_helper<8> {
enum {
single = 3, // LC = 3 => member length is 8
sequence = 7 // LC = 7 => member length is 8 * NEXTINT
};
};
template <typename T>
struct primitive_lc_code {
enum { value = primitive_lc_code_helper<sizeof(T)>::single };
};
// In general, use LC = 5, for mutable aggregation types. Final aggregation
// types don't use this 'lc_code' trait type. The other cases are specialized
// after this.
template <typename T, typename Enable = void>
struct lc_code {
static int value()
{
return 5; // LC = 5 => member length is provided in NEXTINT/
}
};
// For collections of complex types and enums, if we serialize the DHeader
// (XCDR2 compliant behavior) we use LC = 5; if we don't (legacy RTI behavior)
// we use LC = 4, since we codify the length in the member header.
template <typename T>
struct lc_code<MutableSequenceBuilder<T> > {
static int value()
{
return is_dheader_required_in_non_primitive_collections() ? 5 : 4;
}
};
template <typename T>
struct lc_code<FinalSequenceBuilder<T> > {
static int value()
{
return is_dheader_required_in_non_primitive_collections() ? 5 : 4;
}
};
template <typename T, unsigned int N>
struct lc_code<MutableArrayBuilder<T, N> > {
static int value()
{
return is_dheader_required_in_non_primitive_collections() ? 5 : 4;
}
};
#if defined(RTI_FLAT_DATA_NO_EXCEPTIONS)
// Traditional C++: no support for std::is_enum<T>
template <typename T>
struct lc_code<PrimitiveSequenceBuilder<T> > {
static int value()
{
return primitive_lc_code_helper<sizeof(T)>::sequence;
}
};
#else
template <typename T>
struct lc_code<
PrimitiveSequenceBuilder<T>,
typename std::enable_if<!std::is_enum<T>::value>::type> {
static int value()
{
return primitive_lc_code_helper<sizeof(T)>::sequence;
}
};
template <typename T>
struct lc_code<
PrimitiveSequenceBuilder<T>,
typename std::enable_if<std::is_enum<T>::value>::type> {
static int value()
{
return is_dheader_required_in_enum_collections()
? 5
: primitive_lc_code_helper<sizeof(T)>::sequence;
}
};
#endif
//
// Initialization of final types
//
template <typename Offset>
struct final_offset_initializer {
static bool initialize(Offset& offset)
{
return RTI_XCDR_TRUE == RTIXCdrFlatData_initializeSample(
(char *) offset.get_buffer(),
offset.get_buffer_size(),
rti::xcdr::type_programs<rti::flat::Sample<Offset> >::get());
}
};
// This will be specialized for enums in generated code (traditional C++)
// and for enum classes in FlatDataTraits.hpp (modern C++)
template <typename T, typename Enable = void>
struct default_primitive_value {
static T get()
{
return (T) 0;
}
};
template <typename T, unsigned int N>
struct final_offset_initializer<rti::flat::PrimitiveArrayOffset<T, N> > {
static bool initialize(rti::flat::PrimitiveArrayOffset<T, N>& array)
{
T default_value = default_primitive_value<T>::get();
if (default_value == (T) 0) { // don't need to deal with endianness
memset(array.get_buffer(), 0, array.get_buffer_size());
} else {
for (unsigned int i = 0; i < array.element_count(); i++) {
array.set_element(i, default_value);
}
}
return true;
}
};
template <typename T, unsigned int N>
struct final_offset_initializer<rti::flat::FinalAlignedArrayOffset<T, N> > {
static bool initialize(rti::flat::FinalAlignedArrayOffset<T, N>& array)
{
for (unsigned int i = 0; i < N; i++) {
T offset = array.get_element(i);
if (offset.is_null()) {
return false;
}
if (!final_offset_initializer<T>::initialize(offset)) {
return false;
}
}
return true;
}
};
} } }
#endif // RTI_DDS_FLAT_BUILDERHELPER_HPP_
@@ -0,0 +1,179 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
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_DDS_FLAT_EXCEPTIONHELPER_HPP_
#define RTI_DDS_FLAT_EXCEPTIONHELPER_HPP_
//
// Enable debug assertions (RTI_FLAT_ASSERT) in debug mode
//
#if !defined(NDEBUG)
#define RTI_FLAT_DATA_ENABLE_DEBUG_ASSERTIONS
#endif
//
// Error handling without C++ exceptions (traditional C++ and Micro C++ APIs)
//
#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
// TODO: use MSG
#ifdef RTI_FLAT_DATA_ENABLE_DEBUG_ASSERTIONS
#define RTI_FLAT_ASSERT(COND, ACTION) \
if (!(COND)) { \
RTIXCdrFlatData_logPreconditionError(__FILE__, __LINE__, "Assertion failure: " #COND); \
ACTION; \
}
#else
#define RTI_FLAT_ASSERT(COND, ACTION)
#endif
// CR decission: Log error messages. Export function for each log kind (serialize, deserialize, precondition, skip)
// pass type/field (if possible) to serialization errors
#define RTI_FLAT_OFFSET_CHECK_NOT_NULL(ACTION) \
if (this->is_null()) { \
RTIXCdrFlatData_logPreconditionError(__FILE__, __LINE__, "null offset"); \
ACTION; \
}
#define RTI_FLAT_OFFSET_PRECONDITION_ERROR(MSG, ACTION) \
RTIXCdrFlatData_logPreconditionError(__FILE__, __LINE__, MSG); \
ACTION
#define RTI_FLAT_CHECK_PRECONDITION(COND, ACTION) \
if (!(COND)) { \
RTIXCdrFlatData_logPreconditionError(__FILE__, __LINE__, "Precondition failure: " #COND); \
ACTION; \
}
#define RTI_FLAT_BUILDER_CHECK_NOT_BOUND(ACTION) \
if (this->bind_position_) { \
RTIXCdrFlatData_logPreconditionError(__FILE__, __LINE__, "Builder is currently bound - call finish() first"); \
ACTION; \
}
#define RTI_FLAT_BUILDER_CHECK_CAN_FINISH(ACTION) \
if (!this->is_nested()) { \
RTIXCdrFlatData_logPreconditionError(__FILE__, __LINE__, "This is not a member builder; call finish_sample() instead"); \
ACTION; \
}
#define RTI_FLAT_BUILDER_CHECK_CAN_FINISH_SAMPLE(ACTION) \
if (this->is_nested()) { \
RTIXCdrFlatData_logPreconditionError(__FILE__, __LINE__, "This is a member builder; call finish() instead"); \
ACTION; \
}
#define RTI_FLAT_BUILDER_CHECK_VALID(ACTION) \
if (!this->is_valid()) { \
RTIXCdrFlatData_logPreconditionError(__FILE__, __LINE__, "This Builder is not valid"); \
ACTION; \
}
#define RTI_FLAT_BUILDER_CHECK_CREATE_BUILDER(BUILDER, ACTION) \
if (!BUILDER.is_valid()) { \
this->set_failure(); \
RTIXCdrFlatData_logCreationError(__FILE__, __LINE__, "Builder"); \
ACTION; \
}
#define RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(ACTION) \
this->set_failure(); \
RTIXCdrFlatData_logBuilderOutOfResources(__FILE__, __LINE__); \
ACTION
#define RTI_FLAT_BUILDER_PRECONDITION_ERROR(MSG, ACTION) \
this->set_failure(); \
RTIXCdrFlatData_logPreconditionError(__FILE__, __LINE__, MSG); \
ACTION
//
// Error handling with C++ exceptions (modern C++ API)
//
#else // !RTI_FLAT_DATA_NO_EXCEPTIONS
#ifdef RTI_FLAT_DATA_ENABLE_DEBUG_ASSERTIONS
#define RTI_FLAT_ASSERT(COND, ACTION) \
if (!(COND)) throw dds::core::PreconditionNotMetError("Assertion failure: " #COND)
#else
#define RTI_FLAT_ASSERT(COND, ACTION)
#endif
#define RTI_FLAT_OFFSET_CHECK_NOT_NULL(ACTION) \
if (this->is_null()) throw dds::core::NullReferenceError("null offset")
#define RTI_FLAT_OFFSET_PRECONDITION_ERROR(MSG, ACTION) \
throw dds::core::PreconditionNotMetError(MSG)
#define RTI_FLAT_CHECK_PRECONDITION(COND, ACTION) \
if (!(COND)) throw dds::core::PreconditionNotMetError("Precondition failure: " #COND)
#define RTI_FLAT_BUILDER_CHECK_NOT_BOUND(ACTION) \
if (bind_position_) \
throw dds::core::PreconditionNotMetError( \
"Builder is currently bound - call finish() first")
#define RTI_FLAT_BUILDER_CHECK_CAN_FINISH(ACTION) \
if (!is_nested()) \
throw dds::core::PreconditionNotMetError( \
"This is not a member builder; call finish_sample() instead")
#define RTI_FLAT_BUILDER_CHECK_CAN_FINISH_SAMPLE(ACTION) \
if (is_nested()) \
throw dds::core::PreconditionNotMetError( \
"This is a member builder; call finish() instead")
#define RTI_FLAT_BUILDER_CHECK_VALID(ACTION) \
if (!is_valid()) \
throw dds::core::PreconditionNotMetError("This Builder is not valid")
// With exceptions, nothing to check (exception would have been thrown)
#define RTI_FLAT_BUILDER_CHECK_CREATE_BUILDER(BUILDER, ACTION)
#define RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(ACTION) \
throw dds::core::OutOfResourcesError("builder reached end of buffer")
#define RTI_FLAT_BUILDER_PRECONDITION_ERROR(MSG, ACTION) \
throw dds::core::PreconditionNotMetError(MSG)
#endif // RTI_FLAT_DATA_NO_EXCEPTIONS
//
// Error checking (other than assertions) in release mode is enabled unless
// the sources are compiled with -DRTI_FLAT_DATA_DISABLE_ERROR_CHECKING
//
// In that case, most error checks that deal with preconditions due to incorrect
// usage of the API are disabled in release mode. This would lead to undefined
// behavior in case of bad usage, but can improve performance.
//
#if defined(RTI_FLAT_DATA_ENABLE_DEBUG_ASSERTIONS) \
|| !defined(RTI_FLAT_DATA_DISABLE_ERROR_CHECKING)
#define RTI_FLAT_DATA_ENABLE_ERROR_CHECKING
#endif
#ifndef RTI_FLAT_DATA_ENABLE_ERROR_CHECKING
#define RTI_FLAT_OFFSET_CHECK_NOT_NULL(ACTION)
#define RTI_FLAT_ASSERT(COND, ACTION)
#define RTI_FLAT_CHECK_PRECONDITION(COND, ACTION)
#define RTI_FLAT_BUILDER_CHECK_NOT_BOUND(ACTION)
#define RTI_FLAT_BUILDER_CHECK_CAN_FINISH(ACTION)
#define RTI_FLAT_BUILDER_CHECK_CAN_FINISH_SAMPLE(ACTION)
#define RTI_FLAT_BUILDER_CHECK_VALID(ACTION)
#define RTI_FLAT_BUILDER_CHECK_CREATE_BUILDER(BUILDER, ACTION)
#endif // RTI_FLAT_DATA_ENABLE_ERROR_CHECKING
namespace rti { namespace flat { namespace detail {
} } }
#endif // RTI_DDS_FLAT_EXCEPTIONHELPER_HPP_
@@ -0,0 +1,451 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
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_DDS_FLAT_FLATSAMPLE_HPP_
#define RTI_DDS_FLAT_FLATSAMPLE_HPP_
// Note: FlatSampleImpl.hpp needs to be included in addition to this header.
#include <cstdlib>
#include <memory>
#include "xcdr/xcdr_stream_impl.h"
#include "xcdr/xcdr_flat_data.h"
#include "xcdr/xcdr_interpreter.h"
#include "rti/xcdr/Interpreter.hpp" // for type_programs
/**
* @defgroup RTIFlatSampleModule FlatData Samples
* @ingroup RTIFlatDataModule
* @brief A Sample represents an instance of the IDL topic-type and contains
* the data in serialized format.
*
* All FlatData topic-types are instantiations of rti::flat::Sample.
* This documentation uses the following three example types to illustrate the
* different ways FlatData IDL types map to C++:
* - \ref MyFlatFinal, the type generated for a final IDL struct
* - \ref MyFlatMutable, the type generated for a mutable IDL struct
* - \ref MyFlatUnion, the type generated for an IDL union
*/
namespace rti { namespace flat {
struct fixed_size_type_tag_t {};
struct variable_size_type_tag_t {};
typedef RTIXCdrUnsignedLong offset_t;
typedef RTIXCdrUnsignedLong member_id_t;
// The untemplated base of Sample<T>
class SampleBase {
public:
unsigned char* get_buffer()
{
return &data[0];
}
const unsigned char* get_buffer() const
{
return &data[0];
}
unsigned char* get_root_buffer()
{
return get_buffer() + RTI_XCDR_ENCAPSULATION_SIZE;
}
/*i
* @brief Provides the address of the top-level type
*/
const unsigned char* get_root_buffer() const
{
return get_buffer() + RTI_XCDR_ENCAPSULATION_SIZE;
}
void initialize_stream(
RTIXCdrStream& stream,
offset_t offset,
offset_t serialized_size) const
{
RTIXCdrFlatData_initializeStream(
&stream,
const_cast<unsigned char*>(get_buffer()),
offset,
serialized_size);
}
protected: // xlc compiler fails when the default constructor is private
#if !defined(RTI_FLAT_DATA_CXX11_DELETED_FUNCTIONS)
SampleBase() {} // Samples can only be created via Sample::create_data
SampleBase(const SampleBase&) {}
SampleBase& operator=(const SampleBase&);
#else
SampleBase() = delete;
SampleBase(const SampleBase&) = delete;
SampleBase& operator=(const SampleBase&) = delete;
#endif
// The actual size of data (and therefore, the Sample object) is variable,
// and equal to the serialized size of the IDL Sample
unsigned char data[1];
};
/**
* @ingroup RTIFlatSampleModule
* @brief The generic definition of FlatData topic-types
*
* @tparam OffsetType The Offset to the beginning of the data Sample (the root),
* for example MyFlatFinalOffset, or MyFlatMutableOffset.
*
* For a FlatData IDL type, \nddsgen generates an instantiation of this class,
* such as MyFlatFinal or MyFlatMutable. That's the <b>topic-type</b> used to
* declare a \idref_Topic and write or read FlatData samples.
*
* A FlatData Sample owns an inline buffer that contains the serialized data.
* To access the Sample data members we use \ref RTIFlatOffsetsModule "Offsets",
* iterators that point to the position of a member in the Sample buffer. The
* root() is the Offset to the top-level element (for example MyFlatMutableOffset).
* From there MyFlatMutableOffset's member functions provide access to its
* members.
*
* The method to create a Sample varies depending on whether the type is final
* or mutable.
*
* Samples of <b>final</b> FlatData types always have the same size, and
* can be obtained directly with \idref_FooDataWriter_get_loan().
*
* Samples of <b>mutable</b> FlatData types need to be "built" using the Builder
* returned by rti::flat::build_data() (MyFlatMutableBuilder in this example).
* A Builder allows adding each member individually in any order, and sizing
* sequences as needed.
*
* See \ref PublishingFlatData for code snippets.
*
* Samples created with \idref_FooDataWriter_get_loan() or rti::flat::build_data()
* are DataWriter-managed and do not need to be explicitly deleted. See
* \idref_FooDataWriter_get_loan() for an explanation of the lifecycle of
* DataWriter-managed samples.
*
* Samples received with a \idref_FooDataReader can be examined by obtaining the
* root(), but cannot be modified. See \ref SubscribingFlatData.
*
* FlatData samples are not value types. They don't provide copy constructors
* or assignment operators, because of their definition as an inline buffer that
* contains the serialized Sample at all times. A Sample can be cloned with
* the static function clone(). A cloned Sample is unmanaged and has to be
* deleted with the static function delete_data().
*/
template <typename OffsetType>
class Sample : public SampleBase {
public:
/**
* @brief The related Offset type
*
* This is the template parameter, OffsetType
*/
typedef OffsetType Offset;
/**
* @brief The related read-only Offset type
*
* For example, MyFlatMutableOffset::ConstOffset.
*/
typedef typename OffsetType::ConstOffset ConstOffset;
/**
* @brief Provides the Offset to the top-level type
*
* @return An Offset that allows reading and modifying the members of this
* Sample, for example MyFlatFinalOffset or MyFlatMutableOffset.
*
* This overload allows modifying the Sample.
*
* Example:
* \code
* MyFlatFinal *my_sample = ...; // for example, created with DataWriter::get_loan()
* MyFlatFinalOffset my_sample_root = my_sample->root();
* my_sample_root.my_primitive(33);
* auto my_member_offset = my_sample_root.my_complex();
* // ... modify my_member_offset
* \endcode
*/
Offset root()
{
return root_impl(typename Offset::offset_kind());
}
/**
* @brief Provides the Offset to the top-level type
*
* @return An Offset that allows reading the members of this Sample.
* For example, MyFlatFinalOffset::ConstOffset or MyFlatMutableOffset::ConstOffset.
*
* This overload doesn't allow modifying the Sample.
*
* Example:
* \code
* const MyFlatMutable *my_sample = ...; // for example, read from a DataReader
* MyFlatMutableOffset::ConstOffset my_sample_root = my_sample->root();
* std::cout << my_sample_root.my_primitive() << std::endl;
* auto my_member_offset = my_sample_root.my_mutable_seq();
* // ... read my_member_offset
* \endcode
*/
ConstOffset root() const
{
return root_impl(typename ConstOffset::offset_kind());
}
/** @private
* @brief Returns the endianness in which this Sample is serialized
*/
RTIXCdrEndian endian() const
{
RTIXCdrStream tmp_stream;
initialize_stream(tmp_stream, 0, RTI_XCDR_ENCAPSULATION_SIZE);
return tmp_stream._endian;
}
/** @private
* @brief Casts a byte buffer into a Sample of this type
*/
static Sample<OffsetType>* from_buffer(unsigned char *buffer)
{
return reinterpret_cast<Sample<OffsetType>*>(buffer);
}
/**
* @brief Creates an unmanaged FlatData Sample
*
* @note In general on the publication side it is recommended to create
* DataWriter-managed samples using \idref_FooDataWriter_get_loan
* (for final types) and rti::flat::build_data() (for mutable types).
*
* If the topic-type is final, the returned Sample can be initialized
* by obtaining the root().
*
* If the topic-type is mutable, the resulting Sample has no members, and
* root() returns a \ref rti::flat::OffsetBase::is_null "null" Offset.
* The result of create_data() must be used to
* create a Builder. This is a rare use case, and rti::flat::build_data()
* should be used in most situations.
*
* In all cases, the returned Sample must be explicitly deleted with
* delete_data().
*/
static Sample<OffsetType>* create_data(); // impl in FlatSampleImpl.hpp
/**
* @brief Clones a Sample, creating an unmanaged Sample
*
* @warning When this Sample has been created with \idref_FooDataWriter_get_loan
* or rti::flat::build_data(), the clone this function creates cannot be
* used in \idref_FooDataWriter_write, because the DataWriter is managing
* the lifecycle of its samples.
*
* Creates a new Sample and copies the underlying serialized buffer.
*
* delete_data() must be called to release the Sample.
*/
Sample<OffsetType>* clone() const
{
unsigned char *buffer = RTIXCdrFlatData_cloneSample(
get_buffer(),
sample_size());
if (buffer == NULL) {
#ifndef RTI_FLAT_DATA_NO_EXCEPTIONS
throw std::bad_alloc();
#else
return NULL;
#endif
}
return reinterpret_cast<rti::flat::Sample<OffsetType> *>(buffer);
}
/**
* @brief Releases an unmanaged Sample
*
* Unmanaged samples are those created with create_data() or clone().
*
* @pre \p sample cannot have been created with \idref_FooDataWriter_get_loan
* or rti::flat::build_data().
*
* @post \p sample becomes invalid and shouldn't be used
*/
static void delete_data(rti::flat::Sample<OffsetType>* sample)
{
RTIXCdrFlatData_deleteSample(sample);
}
/** @private
*/
offset_t buffer_size() const
{
return sample_size() + RTI_XCDR_ENCAPSULATION_SIZE;
}
/** @private
*/
offset_t sample_size() const
{
return sample_size_impl(typename OffsetType::offset_kind());
}
private:
offset_t sample_size_impl(fixed_size_type_tag_t) const
{
return OffsetType::serialized_size(0);
}
offset_t sample_size_impl(variable_size_type_tag_t) const
{
return RTIXCdrFlatSample_getMutableSampleSize(
get_buffer(),
RTI_XCDR_ENCAPSULATION_SIZE);
}
Offset root_impl(fixed_size_type_tag_t)
{
return Offset(this, RTI_XCDR_ENCAPSULATION_SIZE);
}
Offset root_impl(variable_size_type_tag_t)
{
return Offset(this, RTI_XCDR_ENCAPSULATION_SIZE, sample_size());
}
ConstOffset root_impl(fixed_size_type_tag_t) const
{
return ConstOffset(this, RTI_XCDR_ENCAPSULATION_SIZE);
}
ConstOffset root_impl(variable_size_type_tag_t) const
{
return ConstOffset(this, RTI_XCDR_ENCAPSULATION_SIZE, sample_size());
}
};
template <typename T>
struct flat_type_traits;
} }
#ifdef DOXYGEN_DOCUMENTATION_ONLY
/**
* @ingroup RTIFlatSampleModule
* @brief Represents an arbitrary user-defined FlatData final IDL struct
*
* This documentation uses the following example IDL definition of MyFlatFinal:
*
* \code
* @language_binding(FLAT_DATA)
* @final
* struct MyFlatFinal {
* long my_primitive;
* FlatFinalBar my_complex; // Another arbitrary final FlatData type
* long my_primitive_array[10];
* FlatFinalBar my_complex_array[10];
* };
* \endcode
*
* For this type, \nddsgen generates:
* - MyFlatFinal (this instantiation of Sample),
* - MyFlatFinalOffset.
*
* Note that, as a final FlatData type, MyFlatFinal can only contain
* fixed-size types, such as primitives, other final FlatData structs, and arrays
* of fixed-size types.
*
* Samples of MyFlatFinal are created with \idref_FooDataWriter_get_loan.
* After creating a final Sample, modify its values using the MyFlatFinalOffset
* returned by \ref rti::flat::Sample::root "root()".
*/
typedef rti::flat::Sample<MyFlatFinalOffset> MyFlatFinal;
/**
* @ingroup RTIFlatSampleModule
* @brief Represents an arbitrary user-defined flat mutable IDL struct
*
* This documentation uses the following example IDL definition of MyFlatMutable:
*
* \code
* @language_binding(FLAT_DATA)
* @mutable
* struct MyFlatMutable {
* long my_primitive;
* @optional long my_optional_primitive;
* long my_primitive_array[10];
* sequence<long, 10> my_primitive_seq;
*
* MyFlatFinal my_final;
* MyFlatFinal my_final_array[10];
* sequence<MyFlatFinal, 10> my_final_seq;
*
* FlatMutableBar my_mutable;
* FlatMutableBar my_mutable_array[10];
* sequence<FlatMutableBar, 10> my_mutable_seq;
*
* string<255> my_string;
* sequence<string<255>, 10> my_string_seq;
* };
* \endcode
*
* For this type, \nddsgen generates:
* - MyFlatMutable (this instantiation of Sample),
* - MyFlatMutableOffset,
* - MyFlatMutableBuilder.
*
* As a mutable FlatData type, MyFlatMutable is not restricted to fixed-size
* members. Samples of MyFlatMutable are created with rti::flat::build_data(), which
* returns a MyFlatMutableBuilder. Once built, a mutable Sample can't change
* in size, but the value of members that already exist can be changed using
* the MyFlatMutableOffset returned by \ref rti::flat::Sample::root "root()".
*/
typedef rti::flat::Sample<MyFlatMutableOffset> MyFlatMutable;
/**
* @ingroup RTIFlatSampleModule
* @brief Represents an arbitrary user-defined flat mutable IDL union
*
* This documentation uses the following example IDL definition of MyFlatUnion:
*
* \code
* @language_binding(FLAT_DATA)
* @mutable
* union MyFlatUnion switch (long) {
* case 0:
* long my_primitive;
* case 1:
* case 2:
* MyFlatMutable my_mutable;
* case 3:
* MyFlatFinal my_final;
* };
* \endcode
*
* @note FlatData unions can only be <b>mutable</b> since unions are,
* by definition, variable-size types.
*
* For this type, \nddsgen generates:
* - MyFlatUnion (this instantiation of Sample),
* - MyFlatUnionOffset,
* - MyFlatUnionBuilder.
*
*/
typedef rti::flat::Sample<MyFlatUnionOffset> MyFlatUnion;
#endif
#endif // RTI_DDS_FLAT_FLATSAMPLE_HPP_
@@ -0,0 +1,76 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
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_DDS_FLAT_FLATSAMPLEIMPL_HPP_
#define RTI_DDS_FLAT_FLATSAMPLEIMPL_HPP_
// This file includes the implementation of some templates that need to
// appear after some types are defined in the generated code. This is a
// a restriction on some platforms such as pentiumInty11.pcx64 and other Intys,
// sparcSol2.10gcc3.4.2.
// For example, type_programs<T> needs to be defined (as an specialization
// for T) before its used in create_data().
#include "rti/flat/FlatSample.hpp"
namespace rti { namespace flat {
namespace detail {
template <typename OffsetType>
Sample<OffsetType>* create_data_impl(fixed_size_type_tag_t)
{
unsigned char *buffer = RTIXCdrFlatData_createSampleFinal(
OffsetType::serialized_size(0),
rti::xcdr::type_programs<Sample<OffsetType> >::get());
if (buffer == NULL) {
#ifndef RTI_FLAT_DATA_NO_EXCEPTIONS
throw std::bad_alloc();
#else
return NULL;
#endif
}
return reinterpret_cast<rti::flat::Sample<OffsetType> *>(buffer);
}
template <typename OffsetType>
Sample<OffsetType>* create_data_impl(variable_size_type_tag_t)
{
unsigned char *buffer = RTIXCdrFlatData_createSampleMutable(
rti::xcdr::type_programs<Sample<OffsetType> >::get());
if (buffer == NULL) {
#ifndef RTI_FLAT_DATA_NO_EXCEPTIONS
throw std::bad_alloc();
#else
return NULL;
#endif
}
return reinterpret_cast<rti::flat::Sample<OffsetType> *>(buffer);
}
}
// Declared in FlatSample.hpp
template <typename OffsetType>
Sample<OffsetType>* Sample<OffsetType>::create_data()
{
return detail::create_data_impl<OffsetType>(
typename OffsetType::offset_kind());
}
} }
#endif // RTI_DDS_FLAT_FLATSAMPLEIMPL_HPP_
@@ -0,0 +1,264 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
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_DDS_FLAT_FLATTYPETRAITS_HPP_
#define RTI_DDS_FLAT_FLATTYPETRAITS_HPP_
#include "rti/flat/Offset.hpp"
#include "rti/flat/SequenceOffsets.hpp"
#include "rti/flat/AggregationBuilders.hpp"
namespace rti { namespace flat {
/**
* @ingroup RTIFlatSampleModule
* @brief Given a Sample, an Offset or a Builder, it allows obtaining the other types.
*
* @tparam T One of the following:
* \li A Sample type, such as \ref MyFlatMutable
* \li An Offset type, such as MyFlatMutableOffset
* \li A Builder type, such as MyFlatMutableBuilder
*
* <p>Given \p T, this type provides the following typedefs:
* \li \p flat_type_traits<T>::offset, T's related offset type
* (undefined if T itself is an Offset)
* \li \p flat_type_traits<T>::builder, T's related builder type
* (undefined if T itself is a Builder, or the topic-type is not mutable)
* \li \p flat_type_traits<T>::flat_type, T's related Sample type
* (undefined if T itself is a Sample type)
* \li \p flat_type_traits<T>::plain_type, T's equivalent definition as a plain
* (non-FlatData) type.
*
* For example, for \p T = \ref MyFlatMutable, flat_type_traits is defined as follows:
*
* \code
* template <>
* struct flat_type_traits<MyFlatMutable> {
* typedef MyFlatMutablePlainHelper plain_type;
* typedef MyFlatMutableOffset offset;
* typedef MyFlatMutableBuilder builder;
* };
* \endcode
*
* Or if \p T = MyFlatMutableOffset:
*
* \code
* template <>
* struct flat_type_traits<MyFlatMutableOffset> {
* typedef MyFlatMutable flat_type;
* typedef MyFlatMutablePlainHelper plain_type;
* typedef MyFlatMutableBuilder builder;
* };
* \endcode
*
* @see rti::flat::plain_cast()
*/
// For aggregation types, this template is to be specialized in generated code
template <typename T>
struct flat_type_traits;
template <typename T, unsigned int N>
struct flat_type_traits<FinalArrayOffset<T, N> > {
typedef typename flat_type_traits<T>::plain_type plain_type;
};
template <typename T, unsigned int N>
struct flat_type_traits<PrimitiveArrayOffset<T, N> > {
typedef T plain_type;
};
template <typename T>
struct flat_type_traits<PrimitiveSequenceOffset<T> > {
typedef T plain_type;
};
template <typename T, unsigned int N>
struct flat_type_traits<FinalAlignedArrayOffset<T, N> > {
typedef typename flat_type_traits<T>::plain_type plain_type;
};
template <typename T, unsigned int N>
struct flat_type_traits<MutableArrayOffset<T, N> > {
typedef typename flat_type_traits<T>::plain_type plain_type;
};
template <typename T>
struct flat_type_traits<SequenceOffset<T> > {
typedef typename flat_type_traits<T>::plain_type plain_type;
};
template <>
struct flat_type_traits<StringOffset > :
flat_type_traits<PrimitiveSequenceOffset<char> > {
};
template <typename T>
struct flat_type_traits<PrimitiveOffset<T> > {
typedef T plain_type;
};
/**
* @ingroup RTIFlatOffsetsModule
* @brief Casts into an equivalent plain C++ type
*
* Some FlatData types can be cast to their equivalent <b>plain</b> definition as
* a regular non-FlatData C++ type. This is a more efficient way to access
* the data. This function casts, if possible, the member pointed to by the
* offset argument to an equivalent plain C++ type. Any changes made through
* the plain type are reflected in the FlatData sample.
*
* @tparam OffsetType The Offset type
*
* @pre plain_cast requires the type to meet the following restrictions:
* - The type must be a final struct, or an array or sequence of members of a
* type that meets these restrictions (including primitive types)
* - The type must be defined in a way such that the packing of the plain C++ type
* doesn't differ from the padding in XCDR2.
* - The type may not inherit from another type.
* - In addition, the sample must be serialized in the native endianness.
* For example, if a subscribing application on a little-endian platform
* receives a sample published from a big-endian system, it is not possible
* to plain_cast the sample or any of its members, except if the member is a
* primitive array or sequence of 1-byte elements.
*
* \ref rti::flat::OffsetBase::is_cpp_compatible "offset.is_cpp_compatible()"
* indicates if the member meets the requirements. If the type doesn't, this
* function \if CPP2_LANGUAGE_ONLY throws dds::core::PreconditionNotMetError.
* \else returns NULL. \endif
*
* @param offset The offset to the member to cast.
* @return The data that \p offset referred to, cast as a plain C++ type with the
* same definition. If \p offset is an array or sequence member, the returned pointer
* represents a C++ array with the same number of elements.
*
* The following table summarizes the possible parameters to this function (assuming
* that they meet the previous requirements), and the return type in each case:
*
* | \p OffsetType | return type
* | ------------- | -----------
* | Offset to a final struct, such as `MyFlatFinalOffset` | `MyFlatFinalPlainHelper*` (pointer to a single element). This is a type with the same IDL definition, but without `@language_binding(FLAT_DATA)`.
* | Offset to an array of final structs, such as `FinalArrayOffset<MyFlatFinalOffset, N>` | `MyFlatFinalPlainHelper*` (array of `N` elements)
* | Offset to a sequence of final structs, such as `SequenceOffset<MyFlatFinalOffset>` | `MyFlatFinalPlainHelper*` (array of `offset.element_count()` elements)
* | Offset to an array of primitive types, such as `PrimitiveArrayOffset<int32_t, N>` | `int32_t*` (array of `N` elements)
* | Offset to a sequence of primitive types, such as `PrimitiveSequenceOffset<int32_t>` | `int32_t*` (array of `offset.element_count()` elements)
*
*
* Due to the performance advantages that \p plain_cast offers, it is recommended
* to define FlatData types in a way that their largest member(s) can be
* \p plain_cast.
*
* The following example shows how to use \p plain_cast to cast a MyFlatFinalOffset
* into the type with the same IDL definition as \ref MyFlatFinal, but without
* the \p \@language_binding(FLAT_DATA) annotation:
*
* \code
* MyFlatMutable *my_sample = ...;
* auto my_root = my_sample->root();
* auto my_final = my_root.my_final();
*
* // Get the plain C++ type and modify an array
* auto my_final_plain = rti::flat::plain_cast(my_final);
* my_final_plain->my_primitive(3); // this is using the plain C++ setter
* my_final_plain->my_complex_array()[1].x(20); // this is a std::array
*
* // The change to my_complex_array is reflected in the FlatData sample
* std::cout << my_final.my_primitive() << std::endl; // 3
* std::cout << my_final.my_complex_array().get_element(1).x() << std::endl; // 20
* \endcode
*
* This example shows how to use plain_cast to efficiently build a sequence
* of final elements and a sequence of integers, both members of a mutable type:
*
* \code
* MyFlatMutableBuilder builder = rti::flat::build_data(writer);
*
* // 1)
* //
* // Build a sequence of 5 elements with add_n() instead of 5 calls to
* // add_next()
* rti::flat::FinalSequenceBuilder<MyFlatFinalOffset> seq_builder =
* builder.build_my_final_seq();
* seq_builder.add_n(5);
* // Finish the member, getting the offset to the member
* rti::flat::SequenceOffset<MyFlatFinalOffset> seq_offset = seq_builder.finish();
*
* // Cast it to an array of plain C++ type and initialize it.
* // This way to initialize it is more efficient than add_next().
* auto seq_elements = rti::flat::plain_cast(seq_offset);
* for (int i = 0; i < 5; i++) {
* seq_elements[i].my_primitive(i);
* // ...
* }
*
* // 2)
* //
* // Build a sequence of 1000 integers
* auto seq_builder = builder.build_my_primitive_seq();
* // make space for 1000 elements, but leave them uninitialized
* seq_builder.add_n(1000);
* auto seq_offset = seq_builder.finish();
*
* // Initialize the elements:
* int32_t *elements = rti::flat::plain_cast(seq_offset);
* for (int i = 0; i < 1000; i++) {
* elements[i] = ...;
* }
*
* // ... continue building the sample using 'builder'
* \endcode
*
*/
template <typename OffsetType>
typename flat_type_traits<OffsetType>::plain_type* plain_cast(OffsetType& offset)
{
RTI_FLAT_CHECK_PRECONDITION(offset.is_cpp_compatible(), return NULL);
return reinterpret_cast<typename flat_type_traits<OffsetType>::plain_type*>(
offset.get_buffer());
}
/**
* @ingroup RTIFlatOffsetsModule
* @brief Const version of plain_cast
*/
template <typename OffsetType>
const typename flat_type_traits<OffsetType>::plain_type* plain_cast(const OffsetType& offset)
{
RTI_FLAT_CHECK_PRECONDITION(offset.is_cpp_compatible(), return NULL);
return reinterpret_cast<const typename flat_type_traits<OffsetType>::plain_type*>(
offset.get_buffer());
}
namespace detail {
template <typename OffsetKind>
struct offset_kind_is_fixed_size {
enum { value = 0 };
};
template <>
struct offset_kind_is_fixed_size<rti::flat::fixed_size_type_tag_t> {
enum { value = 1 };
};
}
// Utility to determine if a Flat Data type is fixed size (final) or variable
// size (mutable)
template <typename T>
struct is_fixed_size_type
: detail::offset_kind_is_fixed_size<typename T::Offset::offset_kind>
{
};
} }
#endif // RTI_DDS_FLAT_FLATSAMPLE_HPP_
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,952 @@
/*
(c) Copyright, Real-Time Innovations, 2018-2024.
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_DDS_FLAT_SEQUENCEBUILDERS_HPP_
#define RTI_DDS_FLAT_SEQUENCEBUILDERS_HPP_
#include "rti/flat/Builder.hpp"
//
// Builders for sequences, strings, and arrays.
//
// Type hierarchy (- indicates an abstract builder; * a concrete, usable builder)
//
// - AbstractListBuilder
// * MutableArrayBuilder
// - AbstractSequenceBuilder
// * MutableSequenceBuilder
// * FinalSequenceBuilder
// * PrimitiveSequenceBuilder
// * StringBuilder
//
// Notes:
// - there's no "FinalArrayBuilder" because that's a fixed-size type and
// doesn't need a builder (it's constructed via an "add" operation, not a "build"
// operation).
// - MutableSequenceBuilder "builds" its elements
// - FinalSequenceBuilder "adds" its elements
//
namespace rti { namespace flat {
namespace detail {
template <bool IsForEnum>
struct DHeaderGeneratorImpl {
static bool reserve_dheader(rti::xcdr::Stream& stream)
{
if (collection_dheader_traits<IsForEnum>::dheader_required()) {
return stream.serialize_dheader() != NULL;
} else {
return true;
}
}
static bool finish_dheader(
rti::xcdr::Stream& stream,
unsigned char *dheader_position)
{
if (collection_dheader_traits<IsForEnum>::dheader_required()) {
return stream.finish_dheader((char *) dheader_position);
} else {
return true;
}
}
static bool move_after_dheader(
rti::xcdr::Stream& stream,
unsigned char *begin_position)
{
stream.current_position(begin_position);
if (collection_dheader_traits<IsForEnum>::dheader_required()) {
return stream.skip(RTI_XCDR_DHEADER_SIZE);
} else {
return true;
}
}
};
struct NoDHeaderGenerator {
static bool reserve_dheader(rti::xcdr::Stream&)
{
return true;
}
static bool finish_dheader(rti::xcdr::Stream&, unsigned char *)
{
return true;
}
static bool move_after_dheader(
rti::xcdr::Stream& stream,
unsigned char *begin_position)
{
stream.current_position(begin_position);
return true;
}
};
typedef DHeaderGeneratorImpl<false> DHeaderGenerator;
typedef DHeaderGeneratorImpl<true> DHeaderGeneratorForEnum;
// Maybe specialized for enums to select DHeaderGenerator
template <typename T, typename Enable = void>
struct primitive_sequence_dheader_gen {
typedef NoDHeaderGenerator type;
};
} // namespace detail
/*i
* Extends and specializes AbstractBuilder to add or override the
* functionality required to build a collection of consecutive elements
* (sequence or array):
*
* - Add or build elements
* - Keep track of the element count
* - Handle element alignment
*
*/
/**
* @ingroup RTIFlatBuildersModule
* @brief Base class of all array and sequence builders
*/
template <typename DHeaderGen>
class AbstractListBuilder : public AbstractBuilder {
protected:
AbstractListBuilder() : element_count_(0)
{ }
AbstractListBuilder(
nested_tag_t,
AbstractBuilder& parent,
unsigned int alignment)
: AbstractBuilder(nested_tag_t(), parent, alignment),
element_count_(0)
{
DHeaderGen::reserve_dheader(stream());
}
template <typename ElementBuilder>
ElementBuilder build_next()
{
rti::xcdr::Stream::Memento stream_memento(stream());
return build_element<ElementBuilder>(stream_memento);
}
template <typename ElementOffset>
ElementOffset add_next()
{
RTI_FLAT_BUILDER_CHECK_VALID(return ElementOffset());
// save state in case of error
rti::xcdr::Stream::Memento stream_memento(stream());
if (!stream().align(ElementOffset::required_alignment)) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return ElementOffset());
}
ElementOffset element = add_element<ElementOffset>();
if (element.is_null()) {
return ElementOffset();
}
// Success: clear memento, increment element count
stream_memento.discard();
element_count_++;
return element;
}
template <typename ElementOffset>
void add_n(unsigned int count)
{
RTI_FLAT_BUILDER_CHECK_VALID(return);
if (count == 0) {
return;
}
if (!stream().align(ElementOffset::required_alignment)) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return);
}
offset_t elements_size = ElementOffset::serialized_size(0)
+ ElementOffset::serialized_size_w_padding() * (count - 1);
if (!stream().skip(elements_size)) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return);
}
element_count_ += count;
}
/**
* @brief Returns the current number of elements that have been added
*/
unsigned int element_count() const
{
return element_count_;
}
#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
AbstractListBuilder(AbstractListBuilder&& other) = default;
AbstractListBuilder& operator=(AbstractListBuilder&& other)
{
if (this == &other) {
return *this;
}
finish_untyped_impl();
AbstractBuilder::operator=(static_cast<AbstractBuilder&&>(other));
element_count_ = other.element_count_;
other.element_count_ = 0;
return *this;
}
#else
public:
// Enables the safe-move-constructor idiom without C++11 move constructors
struct AbstractListBuilderMoveProxy : AbstractBuilderMoveProxy {
unsigned int element_count_;
};
operator AbstractListBuilderMoveProxy () throw() // move-constructor idiom
{
AbstractListBuilderMoveProxy other;
move_to(other);
return other;
}
protected:
void move_from(AbstractListBuilderMoveProxy& other)
{
AbstractBuilder::move_from(other);
element_count_ = other.element_count_;
}
void move_to(AbstractListBuilderMoveProxy& other)
{
AbstractBuilder::move_to(other);
other.element_count_ = element_count_;
}
#endif
private:
friend class AbstractBuilder;
virtual void finish_member() // override
{
RTI_FLAT_BUILDER_CHECK_VALID(return);
// Increment element count after the nested element builder finishes,
// instead of on build_next(). This makes it easier to roll back the
// state if the element building doesn't complete.
element_count_++;
AbstractBuilder::finish_member();
}
protected:
bool finish_dheader()
{
return DHeaderGen::finish_dheader(stream(), begin_position());
}
unsigned int element_count_;
};
// --- Array: -----------------------------------------------------------------
//
// (Note: there is no FinalArrayBuilder, because a final array's size is fixed,
// and is handled directly returning its offset with add_*; on the other hand,
// sequences are never fixed-size.)
/**
* @ingroup RTIFlatBuildersModule
* @brief Builds an array member of variable-size elements
*
* @tparam ElementBuilder The Builder type for the elements of the array
* @tparam N The array bound; the exact number of elements this array builder
* must build. For multidimensional arrays, \p N is the product
* of each dimension bound.
*
* Each element of this array needs to be built using the ElementBuilder returned
* by build_next(). N elements exactly must be built. Unlike a sequence Builder,
* it is not possible to finish an array with less than N elements.
*
* This example shows how to use a MutableArrayBuilder to build an array member
* of MyFlatMutableBuilder:
*
* \code
* MyFlatMutableBuilder builder = rti::flat::build_data(writer);
* auto array_builder = builder.build_my_mutable_array();
* for (int i = 0; i < 10; i++) {
* FlatMutableBarBuilder element_builder = array_builder.build_next();
* // ... build element
* element_builder.finish();
* }
* array_builder.finish();
* \endcode
*
* Note that Builder types are not necessary for arrays of fixed-size elements,
* since they are added at once (see MyFlatMutableBuilder::add_my_final_array()).
*/
template <typename ElementBuilder, unsigned int N>
class MutableArrayBuilder : public AbstractListBuilder<detail::DHeaderGenerator> {
public:
/**
* @brief The related Offset type
*/
typedef MutableArrayOffset<typename ElementBuilder::Offset, N> Offset;
typedef AbstractListBuilder<detail::DHeaderGenerator> Base;
MutableArrayBuilder()
{ }
// The destructor does the same as finish_impl() but doesn't need to return
// an Offset
~MutableArrayBuilder()
{
finish_untyped_impl();
}
#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
MutableArrayBuilder(MutableArrayBuilder&& other) = default;
MutableArrayBuilder& operator=(MutableArrayBuilder&& other)
{
finish_untyped_impl();
Base::operator=(static_cast<Base&&>(other));
return *this;
}
#endif
void finish_untyped_impl()
{
if (!Base::is_valid() || !Base::is_nested()) {
return;
}
Base::finish_dheader();
Base::finish_untyped_impl();
}
private:
friend class AbstractBuilder; // to allow access to the constructor
MutableArrayBuilder(
nested_tag_t,
AbstractBuilder& parent,
unsigned int alignment = 0)
: AbstractListBuilder(nested_tag_t(), parent, alignment)
{
}
public:
/**
* @brief Begins building the next element
*
* Before calling build_next() to create a new element, the element Builder
* returned by a previous call to build_next must have been finished.
*/
ElementBuilder build_next()
{
if (element_count() == N) {
RTI_FLAT_BUILDER_PRECONDITION_ERROR(
"Array builder build_next: too many elements",
return ElementBuilder());
}
return AbstractListBuilder::build_next<ElementBuilder>();
}
/**
* @brief Finishes building the array
*
* @pre build_next() must have been succesfully called \p N times exactly.
* @return The Offset to the member that has been built.
* @see discard()
*/
Offset finish()
{
RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return Offset());
if (element_count() != N) {
RTI_FLAT_BUILDER_PRECONDITION_ERROR(
"Cannot finish array builder: too few elements",
return Offset());
}
if (!finish_dheader()) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return Offset());
}
return finish_impl<Offset>();
}
RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
MutableArrayBuilder, AbstractListBuilder, AbstractListBuilderMoveProxy)
};
// --- Sequences: -------------------------------------------------------------
// Specializes AbstractListBuilder to handle the length header serialization
// common to all sequences (which arrays don't have)
/**
* @ingroup RTIFlatBuildersModule
* @brief Base class of Builders for sequence members.
*
* This class contains only implementation details and doesn't add any public
* function to AbstractListBuilder.
*/
template <typename DHeaderGen>
class AbstractSequenceBuilder : public AbstractListBuilder<DHeaderGen> {
public:
typedef AbstractListBuilder<DHeaderGen> Base;
using Base::element_count;
using Base::is_nested;
using Base::is_valid;
using Base::stream;
using typename Base::nested_tag_t;
#if !defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
using typename Base::AbstractListBuilderMoveProxy;
#endif
protected:
AbstractSequenceBuilder()
{
}
AbstractSequenceBuilder(
nested_tag_t,
AbstractBuilder& parent,
unsigned int alignment)
: Base(nested_tag_t(), parent, alignment)
{
// leave space for sequence length
if (!stream().check_size(sizeof(rti::xcdr::length_t))) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(this->invalidate());
} else {
// No need to align; the base constructor already aligned to 4 the
// begin_position
stream().template serialize_fast<rti::xcdr::length_t>(0);
}
}
// The destructor does the same as finish_impl() but doesn't need to return
// an Offset
~AbstractSequenceBuilder()
{
finish_untyped_impl();
}
#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
AbstractSequenceBuilder(AbstractSequenceBuilder&& other) = default;
AbstractSequenceBuilder& operator=(AbstractSequenceBuilder&& other)
{
finish_untyped_impl();
Base::operator=(static_cast<Base&&>(other));
return *this;
}
#endif
void finish_untyped_impl()
{
if (!Base::is_valid() || !Base::is_nested()) {
return;
}
Base::finish_dheader();
finish_length();
Base::finish_untyped_impl();
}
// Concrete sequences must call this method in their own finish() function
template <typename Offset>
Offset finish_impl()
{
RTI_FLAT_BUILDER_CHECK_VALID(return Offset());
RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return Offset());
Base::finish_dheader();
finish_length(); // serialize the length header
return Base::template finish_impl<Offset>();
}
private:
// Serializes the sequence length when finishing the builder.
void finish_length()
{
rti::xcdr::Stream::Memento stream_memento(stream());
DHeaderGen::move_after_dheader(stream(), Base::begin_position());
// Coverity found examples where element_count() is checked, but
// that's only done in Array builders, which are unrelated to this
// class, AbstractSequenceBuilder.
// coverity[CHECKED_RETURN : FALSE]
stream().template serialize_fast<rti::xcdr::length_t>(element_count());
}
};
/**
* @ingroup RTIFlatBuildersModule
* @brief Builds a sequence member of variable-size elements
*
* @tparam ElementBuilder The Builder type for the elements of the sequence
*
* To build the elements use the ElementBuilder returned
* by build_next(). An empty sequence can be built by calling finish() without
* any call to build_next().
*
* This class doesn't enforce the sequence bound set in IDL.
*
* The following example uses a MutableSequenceBuilder to initialize a sequence
* member of MyFlatMutableBuilder with two elements:
*
* \code
* MyFlatMutableBuilder builder = rti::flat::build_data(writer);
* auto seq_builder = builder.build_my_mutable_seq();
* auto element_builder = seq_builder.build_next();
* // ... build the first element
* element_builder.finish();
* element_builder = seq_builder.build_next();
* // ... build the second element
* element_builder.finish();
*
* seq_builder.finish();
* \endcode
*/
template <typename ElementBuilder>
class MutableSequenceBuilder
: public AbstractSequenceBuilder<detail::DHeaderGenerator> {
public:
/**
* @brief The related Offset type
*/
typedef SequenceOffset<typename ElementBuilder::Offset> Offset;
MutableSequenceBuilder()
{
}
private:
typedef AbstractSequenceBuilder<detail::DHeaderGenerator> Base;
friend class AbstractBuilder; // to allow access to the constructor
MutableSequenceBuilder(
nested_tag_t,
AbstractBuilder& parent,
unsigned int alignment = RTI_XCDR_DHEADER_ALIGNMENT)
: Base(nested_tag_t(), parent, alignment)
{
}
public:
/**
* @brief Begins building the next element
*
* Before calling build_next() to create a new element, the application must
* have called finish() on the previous element Builder.
*/
ElementBuilder build_next()
{
return AbstractListBuilder::build_next<ElementBuilder>();
}
/**
* @brief Finishes building the sequence
*
* @return An Offset to the member that has been built.
*
* @see discard()
*/
Offset finish()
{
return finish_impl<Offset>();
}
RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(
MutableSequenceBuilder,
Base,
AbstractListBuilderMoveProxy)
};
/**
* @ingroup RTIFlatBuildersModule
* @brief Builds a sequence member of fixed-size elements
*
* @tparam ElementOffset The Offset type for the elements of the sequence
*
* To add an element, call add_next() and use the ElementOffset it returns to
* initialize the element's values. An empty sequence can be built by
* calling finish() without any call to add_next().
*
* This class doesn't enforce the sequence bound set in IDL.
*
* The following example uses a FinalSequenceBuilder to initialize a sequence
* member of MyFlatMutableBuilder with two elements:
*
* \code
* MyFlatMutableBuilder builder = rti::flat::build_data(writer);
* auto seq_builder = builder.build_my_final_seq();
* MyFlatFinalOffset element = seq_builder.add_next();
* element.my_primitive(1);
* // ... continue initializing the first element
*
* element = seq_builder.add_next();
* element.my_primitive(2);
* // ... continue initializing the second element
*
* seq_builder.finish();
* \endcode
*
* If the element type meets certain requirements, rti::flat::plain_cast()
* provides a more efficient way to initialize a sequence of final elements.
*/
template <typename ElementOffset>
class FinalSequenceBuilder
: public AbstractSequenceBuilder<detail::DHeaderGenerator> {
public:
typedef SequenceOffset<ElementOffset> Offset;
FinalSequenceBuilder()
{
}
private:
friend class AbstractBuilder; // to allow access to the constructor
FinalSequenceBuilder(
nested_tag_t,
AbstractBuilder& parent,
unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
: AbstractSequenceBuilder(nested_tag_t(), parent, alignment)
{
}
public:
/**
* @brief Adds the next element
*
* @return The Offset that can be used to set the element values
*/
ElementOffset add_next()
{
return AbstractListBuilder::add_next<ElementOffset>();
}
/**
* @brief Adds a number of elements at once
*
* This is an alternative to add_next().
*
* To initialize the elements, call finish() and use the Offset it returns
* to access the elements.
*/
FinalSequenceBuilder& add_n(unsigned int count)
{
AbstractListBuilder::add_n<ElementOffset>(count);
return *this;
}
/**
* @brief Finishes building the sequence
*
* @return An Offset to the member that has been built.
* @see discard()
*/
Offset finish()
{
return finish_impl<Offset>();
}
RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
FinalSequenceBuilder, AbstractSequenceBuilder, AbstractListBuilderMoveProxy)
};
/**
* @ingroup RTIFlatBuildersModule
* @brief Builds a sequence of primitive members
*
* The elements can be added one by one with add_next() or all at once with
* add_n().
*/
template <typename T>
class PrimitiveSequenceBuilder
: public AbstractSequenceBuilder<
typename detail::primitive_sequence_dheader_gen<T>::type> {
public:
typedef PrimitiveSequenceOffset<T> Offset;
typedef AbstractSequenceBuilder<
typename detail::primitive_sequence_dheader_gen<T>::type>
Base;
using Base::is_valid;
using Base::stream;
using typename Base::nested_tag_t;
#if !defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
using typename Base::AbstractListBuilderMoveProxy;
#endif
PrimitiveSequenceBuilder()
{
}
protected:
friend class AbstractBuilder; // to allow access to the constructor
PrimitiveSequenceBuilder(
nested_tag_t,
AbstractBuilder& parent,
unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
: Base(nested_tag_t(), parent, alignment)
{
}
public:
/**
* @brief Adds the next element
*
* @param value The primitive element to add
*/
PrimitiveSequenceBuilder& add_next(T value)
{
RTI_FLAT_BUILDER_CHECK_VALID(return *this);
if (!stream().template serialize<T>(value)) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
}
Base::element_count_++;
return *this;
}
/**
* @brief Adds all the elements in an array
*
* @param array The array containing the values to add
* @param count The size of the array
*
* @pre array must not be NULL
*/
PrimitiveSequenceBuilder& add_n(const T *array, unsigned int count)
{
RTI_FLAT_BUILDER_CHECK_VALID(return *this);
RTI_FLAT_ASSERT(array != NULL, return *this);
if (RTIXCdrUnsignedLong_MAX / static_cast<unsigned int>(sizeof(T))
< count) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
}
if (!stream().check_size(static_cast<unsigned int>(sizeof(T)) * count)) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
}
if (stream().needs_byte_swap() && sizeof(T) > 1) {
for (unsigned int i = 0; i < count; i++) {
stream().template serialize_fast<T>(array[i]);
}
} else {
stream().serialize_fast((void *) array, count * static_cast<unsigned int>(sizeof(T)));
}
Base::element_count_ += count;
return *this;
}
/**
* @brief Adds a number of elements with the same value
*
* This overload initializes all the elements to a value.
*
* @note This operation is O(\p count). The other overloads,
* add_n(unsigned int) and add_n(const T*, unsigned int), are more
* efficient
*
*
* @param count The number of elements to add
* @param value The value to set for each element
*/
PrimitiveSequenceBuilder& add_n(unsigned int count, T value)
{
RTI_FLAT_BUILDER_CHECK_VALID(return *this);
if (RTIXCdrUnsignedLong_MAX / static_cast<unsigned int>(sizeof(T))
< count) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
}
if (!stream().check_size(static_cast<unsigned int>(sizeof(T)) * count)) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
}
for (unsigned int i = 0; i < count; i++) {
stream().template serialize_fast<T>(value);
}
Base::element_count_ += count;
return *this;
}
/**
* @brief Adds a number of uninitialized elements
*
* This operation is O(1), since it leaves the elements uninitialized.
* They can be initialized using the Offset returned by finish() and
* rti::flat::plain_cast(). For example:
*
* \code
* MyFlatMutableBuilder builder = ...;
* auto seq_builder = builder.build_my_primitive_seq();
* seq_builder.add_n(1000);
* auto seq_offset = seq_builder.finish();
* int32_t *elements = rti::flat::plain_cast(seq_offset);
* for (int i = 0; i < 1000; i++) {
* elements[i] = ...;
* }
* \endcode
*
* @param count The number of elements to add
*/
PrimitiveSequenceBuilder& add_n(unsigned int count)
{
RTI_FLAT_BUILDER_CHECK_VALID(return *this);
if (RTIXCdrUnsignedLong_MAX / static_cast<unsigned int>(sizeof(T))
< count) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
}
if (!stream().skip(static_cast<unsigned int>(sizeof(T)) * count)) {
RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
}
Base::element_count_ += count;
return *this;
}
/**
* @brief Finishes building the sequence
*
* @return An Offset to the member that has been built.
* @see discard()
*/
Offset finish()
{
this->finish_dheader();
return Base::template finish_impl<Offset>();
}
private:
RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
PrimitiveSequenceBuilder, Base, AbstractListBuilderMoveProxy)
};
/**
* @ingroup RTIFlatBuildersModule
* @brief Builds a string
*
* A StringBuilder only provides one method, set_string(), so it can be
* typically used as follows:
*
* \code
* MyFlatMutableBuilder my_builder = ...;
* my_builder.build_my_string().set_string("Hello!");
* \endcode
*
* Note that by relying on the builder destructor, there is no need to call
* finish() on the object returned by build_my_string().
*/
class StringBuilder : public PrimitiveSequenceBuilder<char> {
public:
typedef StringOffset Offset;
typedef PrimitiveSequenceBuilder<char> Base;
using Base::is_valid;
using Base::stream;
using typename Base::nested_tag_t;
StringBuilder()
{
}
private:
friend class AbstractBuilder; // to allow access to the constructor
StringBuilder(
nested_tag_t,
AbstractBuilder& parent,
unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
: Base(nested_tag_t(), parent, alignment)
{
}
public:
/**
* @brief Sets the string value
*
* @param value The string value to set.
*
* @pre value must not be NULL.
*/
StringBuilder& set_string(const char *value)
{
RTI_FLAT_BUILDER_CHECK_VALID(return *this);
RTI_FLAT_ASSERT(value != NULL, return *this);
// if set_string is called more than once we override the string
// that was set before
if (Base::element_count_ != 0) {
stream().current_position(begin_position());
stream().serialize_fast<rti::xcdr::length_t>(0);
Base::element_count_ = 0;
}
unsigned int length =
static_cast<unsigned int>(RTIXCdrString_getLength(value)) + 1;
add_n(value, length); // if this fail, error has been reported
return *this;
}
/**
* @brief Finishes building the string
*
* @return An Offset to the member that has been built.
* @see discard()
*/
Offset finish()
{
RTI_FLAT_BUILDER_CHECK_VALID(return Offset());
if (element_count_ == 0) {
add_next('\0'); // build empty string if no string was built
}
Base::finish_dheader();
return finish_impl<Offset>();
}
RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
StringBuilder, Base, AbstractListBuilderMoveProxy)
};
// Wide strings are treated as a sequence of octets
typedef PrimitiveSequenceBuilder<unsigned char> WStringBuilder;
} }
#endif // RTI_DDS_FLAT_SEQUENCEBUILDERS_HPP_
@@ -0,0 +1,345 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
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_DDS_FLAT_SEQUENCEITERATOR_HPP_
#define RTI_DDS_FLAT_SEQUENCEITERATOR_HPP_
#include <iterator>
#include "rti/flat/Offset.hpp"
namespace rti { namespace flat {
/**
* @ingroup RTIFlatOffsetsModule
* @brief Iterator for collections of Offsets
*
* @tparam E The Offset type of the elements
* @tparam OffsetKind (implementation detail)
*
* @note This type should not be declared directly. For example, for a
* SequenceOffset, use SequenceOffset::iterator (or simply \p auto).
*
* A SequenceIterator moves through the Offset to elements of a sequence or
* array \ref RTIFlatOffsetsModule "Offset", and provides the functionality of
* a standard \p forward_iterator.
*
* Note that a dereferenced SequenceIterator returns <b>by value</b> the Offset
* to the current element; it doesn't return it by reference.
*
* \if CPP_LANGUAGE_ONLY
* Since the Traditional C++ API doesn't use exceptions, it is recommended
* to use the function advance() instead of operator++ to check for errors
* \endif
*
*/
template <typename E, typename OffsetKind>
class SequenceIterator {
public:
/**
* @brief The iterator category
*/
typedef std::forward_iterator_tag iterator_category;
/**
* @brief The element type
*/
typedef E value_type;
/**
* @brief The reference type is the same as the value type, an Offset
*/
typedef value_type reference;
/**
* @brief The pointer type is the same as the value type, an Offset
*/
typedef value_type pointer;
/**
* @brief The difference type
*/
typedef std::ptrdiff_t difference_type;
/**
* @brief Constructs an invalid iterator
*/
SequenceIterator() : sample_(NULL), current_offset_(0), max_offset_(0)
{
}
SequenceIterator(
rti::flat::SampleBase *sample,
offset_t initial_offset,
offset_t max_offset)
: sample_(sample),
current_offset_(initial_offset),
max_offset_(max_offset)
{
RTI_FLAT_ASSERT(sample != NULL, return);
}
/**
* @brief Returns whether the iterator is invalid
*/
bool is_null() const
{
return sample_ == NULL;
}
/**
* @brief Returns the Offset of the current element
*
* @return The Offset to the current element. Note that this function returns
* by value, not by reference. This Offset may be
* \ref rti::flat::OffsetBase::is_null "null" if the iterator has surpassed
* the length of the collection. See \ref OffsetErrorManagement.
*/
value_type operator*() const
{
return get_impl(OffsetKind());
}
/**
* @brief Returns the Offset of the current element
*/
value_type operator->() const
{
return get_impl(OffsetKind());
}
/**
* @brief Advances to the next element, reporting any errors by returning false
*
* \if CPP_LANGUAGE_ONLY
* Since the Traditional C++ API doesn't support exceptions, this function
* is recommended instead of operator++.
* \endif
* \if CPP2_LANGUAGE_ONLY
* Unlike operator++, which throws an exception in case of error, advance()
* returns false
* \endif
*
* @return True if the function succeeds, or false if there was an error
*/
bool advance()
{
// Unlike operator++, advance() allows checking for errors when
// exceptions are disabled (traditional C++)
return advance_impl(OffsetKind());
}
/**
* @brief Advances to the next element
*
* \if CPP_LANGUAGE_ONLY
* @warning Since the Traditional C++ API doesn't use exceptions, use
* advance() instead of this operator to check for errors.
* \endif
*/
SequenceIterator& operator++()
{
bool can_advance_iter = advance_impl(OffsetKind());
RTI_FLAT_CHECK_PRECONDITION(can_advance_iter, return *this);
return *this;
}
/**
* @brief Advances to the next element
*
* \if CPP_LANGUAGE_ONLY
* @warning Since the Traditional C++ API doesn't use exceptions, use
* advance() instead of this operator to check for errors.
* \endif
*/
SequenceIterator operator++(int)
{
SequenceIterator tmp(*this);
++(*this);
return tmp;
}
/**
* @brief Compares two iterators
*/
friend bool operator<(
const SequenceIterator & s1,
const SequenceIterator & s2)
{
return s1.get_position() < s2.get_position();
}
/**
* @brief Compares two iterators
*/
friend bool operator > (
const SequenceIterator & s1,
const SequenceIterator & s2)
{
return s1.get_position() > s2.get_position();
}
/**
* @brief Compares two iterators
*/
friend bool operator <= (
const SequenceIterator & s1,
const SequenceIterator & s2)
{
return s1.get_position() <= s2.get_position();
}
/**
* @brief Compares two iterators
*/
friend bool operator >= (
const SequenceIterator & s1,
const SequenceIterator & s2)
{
return s1.get_position() >= s2.get_position();
}
/**
* @brief Compares two iterators
*/
friend bool operator == (
const SequenceIterator & s1,
const SequenceIterator & s2)
{
return s1.get_position() == s2.get_position();
}
/**
* @brief Compares two iterators
*/
friend bool operator != (
const SequenceIterator & s1,
const SequenceIterator & s2)
{
return !(s1 == s2);
}
unsigned char * get_position() const
{
if (is_null()) {
return NULL;
} else {
return sample_->get_buffer() + current_offset_;
}
}
private:
E get_impl(variable_size_type_tag_t) const
{
if (is_null()) {
return E();
}
// The iterator points to the end of the previous element. If elements
// need padding, we have to add it here (required alignment is 4 because
// mutable types (variable_size_type_tag_t) are always aligned to 4)
offset_t offset = RTIXCdrAlignment_alignSizeUp(current_offset_, 4);
if (offset >= max_offset_) {
return E();
}
// Calculate the size of the current element; if E is a struct type,
// this will be quick (just deserialize the DHeader); if we're itearating
// over an array of sequences (E is a sequence), this will require
// skipping over the current sequence.
offset_t size = E::Helper::calculate_serialized_size(
sample_,
offset,
max_offset_);
// size 0 indicates an error; a variable-size type E cannot have size
// zero because it will always have a header (DHeader for mutable structs,
// length for sequences)
if (size == 0) {
return E();
}
return E(sample_, offset, size);
}
E get_impl(fixed_size_type_tag_t) const
{
if (is_null()) {
return E();
}
// The iterator points to the end of the previous element. If elements
// need padding, we have to add it here.
offset_t offset = RTIXCdrAlignment_alignSizeUp(
current_offset_,
E::required_alignment);
if (offset >= max_offset_) {
return E();
}
return E(sample_, offset);
}
bool advance_impl(variable_size_type_tag_t)
{
if (is_null()) {
return false;
}
current_offset_ = RTIXCdrAlignment_alignSizeUp(current_offset_, 4);
offset_t size = E::Helper::calculate_serialized_size(
sample_, // beginning of the buffer
current_offset_, // absolute offset to the current element
max_offset_); // maximum offset in the list
if (size == 0) {
return false;
}
current_offset_ += size;
if (current_offset_ > max_offset_) {
current_offset_ = max_offset_;
return false;
}
return true;
}
bool advance_impl(fixed_size_type_tag_t)
{
if (is_null()) {
return false;
}
// The iterator points to the end of the previous element. If elements
// need padding, we have to add it here. We do that to keep the end()
// iterator consistent, becuase the last element may not need padding.
current_offset_ = RTIXCdrAlignment_alignSizeUp(
current_offset_,
E::required_alignment);
current_offset_ += E::serialized_size(0);
if (current_offset_ > max_offset_) {
current_offset_ = max_offset_;
return false;
}
return true;
}
rti::flat::SampleBase *sample_;
offset_t current_offset_;
offset_t max_offset_;
};
} }
#endif // RTI_DDS_FLAT_SEQUENCEITERATOR_HPP_
@@ -0,0 +1,844 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
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_DDS_FLAT_SEQUENCEOFFSETS_HPP_
#define RTI_DDS_FLAT_SEQUENCEOFFSETS_HPP_
#include "rti/flat/Offset.hpp"
#include "rti/flat/SequenceIterator.hpp"
namespace rti { namespace flat {
/**
* @ingroup RTIFlatOffsetsModule
* @brief Base class for Offsets to sequences and arrays of primitive types
*
* @tparam T The primitive type
*
*/
template <typename T>
class AbstractPrimitiveList : public OffsetBase {
public:
typedef T value_type;
protected:
AbstractPrimitiveList()
{
}
AbstractPrimitiveList(
rti::flat::SampleBase *sample,
offset_t offset,
offset_t sequence_size)
: OffsetBase(sample, offset, sequence_size)
{
}
public:
bool is_cpp_compatible() const
{
RTI_FLAT_OFFSET_CHECK_NOT_NULL(return false);
return sizeof(T) == 1 || !stream_.needs_byte_swap();
}
/*@private
* @brief Gets direct access to the elements
*
* Returns a pointer to the elements of this sequence.
*
* @note If the Sample that contains this PrimitiveSequenceOffset has an endianess
* different from the native one, the element bytes may be swapped. This can
* happen if this Sample was published by a DataWriter running on a platform
* with a different endianess and received by a DataReader running locally.
*
* This function is not for public use. See rti::flat::plain_cast() instead.
*/
T * get_elements()
{
return reinterpret_cast<T*>(this->get_buffer());
}
/*@private
* @brief Gets direct access to the array elements
*
* (Const overload)
*/
const T * get_elements() const
{
return reinterpret_cast<const T*>(this->get_buffer());
}
/**
* @brief Returns an element by index
*
* @param i The zero-based index of the element
*
* @see rti::flat::plain_cast() for a method to access all the elements at
* once
*/
T get_element(unsigned int i) const
{
// OffsetBase::serialize only checks this as a debug assertion; in
// a sequence or array we need to do it in release mode too
if (!stream_.check_size((i + 1) * ((unsigned int) sizeof(T)))) {
return T();
}
return OffsetBase::template deserialize<T>(i * (unsigned int) sizeof(T));
}
/**
* @brief Sets an element by index
*
* @param i The zero-based index of the element to set
* @param value The value to set
*
* @return true if it was possible to set the element, or false if this
* collection has less than i - 1 elements.
*
* @see rti::flat::plain_cast() for a method to access all the elements at
* once
*/
bool set_element(unsigned int i, T value)
{
// OffsetBase::serialize only checks this as a debug assertion; in
// a sequence or array we need to do it in release mode too
if (!stream_.check_size((i + 1) * static_cast<unsigned int>(sizeof(T)))) {
return false;
}
return OffsetBase::serialize(i * static_cast<unsigned int>(sizeof(T)), value);
}
};
namespace detail {
template <typename T>
struct PrimitiveSequenceOffsetHelper;
template <typename T, typename Enable = void>
struct primitive_sequence_header_length {
static size_t value()
{
return sizeof(rti::xcdr::length_t);
}
};
} // namespace detail
/**
* @ingroup RTIFlatOffsetsModule
* @brief Offset to a sequence of primitive elements
*
* @tparam T The primitive type
*
*/
template <typename T>
class PrimitiveSequenceOffset : public AbstractPrimitiveList<T> {
public:
typedef variable_size_type_tag_t offset_kind;
typedef detail::PrimitiveSequenceOffsetHelper<T> Helper;
PrimitiveSequenceOffset() : element_count_(0)
{
}
PrimitiveSequenceOffset(
rti::flat::SampleBase *sample,
offset_t offset,
offset_t serialized_size)
: AbstractPrimitiveList<T>(
// passing NULL causes the base constructors to fail
serialized_size >= static_cast<offset_t>(header_length()) ? sample : NULL,
offset + static_cast<offset_t>(header_length()),
serialized_size - static_cast<offset_t>(header_length())),
element_count_(0)
{
#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
if (!this->is_null()) { // without exceptions, we need to check if the base ctor failed
#endif
rti::xcdr::Stream::Memento stream_memento(this->stream_);
this->stream_.skip_back(sizeof(rti::xcdr::length_t));
element_count_ = this->stream_.template deserialize_fast<rti::xcdr::length_t>();
#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
}
#endif
}
/**
* @brief Returns the number of elements
*/
unsigned int element_count() const
{
RTI_FLAT_OFFSET_CHECK_NOT_NULL(return 0);
return element_count_;
}
private:
static size_t header_length()
{
return detail::primitive_sequence_header_length<T>::value();
}
unsigned int element_count_;
};
namespace detail {
template <typename T>
struct PrimitiveSequenceOffsetHelper {
static offset_t calculate_serialized_size(
rti::flat::SampleBase *sample,
offset_t absolute_offset,
offset_t max_size)
{
RTI_FLAT_ASSERT(sample != NULL, return 0);
RTI_FLAT_ASSERT(max_size > sizeof(rti::xcdr::length_t), return 0);
PrimitiveSequenceOffset<T> tmp(sample, absolute_offset, max_size);
// elements + header
if ((RTIXCdrUnsignedLong_MAX
- static_cast<unsigned int>(sizeof(rti::xcdr::length_t)))
/ static_cast<unsigned int>(sizeof(T))
< tmp.element_count()) {
RTI_FLAT_OFFSET_PRECONDITION_ERROR(
"Serialized size of a sequence of primitive elements "
"exceeds maximum representable 32-bit unsigned integer.",
return 0);
}
return (tmp.element_count() * static_cast<unsigned int>(sizeof(T)))
+ static_cast<unsigned int>(sizeof(rti::xcdr::length_t));
}
};
} // namespace detail
/**
* @ingroup RTIFlatOffsetsModule
* @brief Offset to an array of primitive elements
*
* @tparam T The primitive type
* @tparam N The array bound. For multidimensional arrays, \p N is the product
* of each dimension bound.
*
* A PrimitiveArrayOffset may meet the requirements to be cast to an array of
* the equivalent plain C++ element type (see rti::flat::plain_cast()).
*/
template <typename T, unsigned int N>
class PrimitiveArrayOffset : public AbstractPrimitiveList<T> {
public:
typedef fixed_size_type_tag_t offset_kind;
PrimitiveArrayOffset()
{
}
PrimitiveArrayOffset(rti::flat::SampleBase *sample, offset_t offset)
: AbstractPrimitiveList<T>(
sample,
offset + static_cast<offset_t>(header_length()),
serialized_size(0))
{
}
public:
/**
* @brief Returns the number of elements, \p N
*
*/
unsigned int element_count() const
{
return N;
}
static offset_t serialized_size(offset_t)
{
return sizeof(T) * N;
}
private:
static size_t header_length()
{
return detail::primitive_sequence_header_length<T>::value()
- sizeof(rti::xcdr::length_t);
}
};
// Note: the modern C++ API defines a PrimitiveArrayOffset specializations for
// safe_enum and wchar_t
struct StringOffsetHelper;
/**
* @ingroup RTIFlatOffsetsModule
* @brief Offset to a string
*
*/
class StringOffset : public PrimitiveSequenceOffset<char> {
public:
typedef variable_size_type_tag_t offset_kind;
typedef StringOffsetHelper Helper;
StringOffset()
{
}
StringOffset(
SampleBase *sample,
offset_t absolute_offset,
offset_t serialized_size)
: PrimitiveSequenceOffset<char>(
sample,
absolute_offset,
serialized_size)
{
}
/**
* @brief Gets the string
*
* The string returned can be modified as long as its size doesn't change.
*/
char * get_string()
{
return reinterpret_cast<char*>(this->get_buffer());
}
/**
* @brief Gets the string (const)
*
*/
const char * get_string() const
{
return reinterpret_cast<const char*>(this->get_buffer());
}
/**
* @brief Returns the number of characters
*
* This number doesn't include the null terminating character.
*/
unsigned int element_count() const
{
RTI_FLAT_CHECK_PRECONDITION(
PrimitiveSequenceOffset<char>::element_count() > 0,
return 0);
return PrimitiveSequenceOffset<char>::element_count() - 1;
}
};
struct StringOffsetHelper {
static offset_t calculate_serialized_size(
rti::flat::SampleBase *sample,
offset_t absolute_offset,
offset_t max_size)
{
StringOffset tmp(sample, absolute_offset, max_size);
return tmp.element_count()
+ 1 // null terminator
+ (unsigned int) sizeof(rti::xcdr::length_t); // length header
}
};
// Wide strings are treated as a sequence of octets
typedef PrimitiveSequenceOffset<unsigned char> WStringOffset;
// The base class of SequenceOffset, and FinalAlignedArrayOffset
//
// This encapsulates the functionality that allows iterating through a list
// of elements (a sequence or an array). The list must be always aligned to 4
// (that excludes FinalArrayOffset)
//
/**
* @ingroup RTIFlatOffsetsModule
* @brief Base class of Offsets to sequences and arrays of non-primitive members
*
* @tparam ElementOffset The Offset type of the elements
*/
template <typename ElementOffset>
class AbstractAlignedList : public OffsetBase {
public:
/**
* @brief The iterator type, SequenceIterator
*/
typedef SequenceIterator<ElementOffset, typename ElementOffset::offset_kind>
iterator;
protected:
AbstractAlignedList()
{
}
AbstractAlignedList(
rti::flat::SampleBase *sample,
offset_t offset,
offset_t sequence_size)
: OffsetBase(
sample,
offset,
sequence_size)
{
}
public:
bool is_cpp_compatible() const // override
{
RTI_FLAT_OFFSET_CHECK_NOT_NULL(return false);
return !stream_.needs_byte_swap()
&& rti::xcdr::has_cpp_friendly_cdr_layout_collection<
typename rti::flat::flat_type_traits<ElementOffset>::flat_type>();
}
ElementOffset get_element(unsigned int i)
{
RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
return get_element_impl<ElementOffset>(
i,
typename ElementOffset::offset_kind());
}
/**
* @brief Gets an iterator to the first Offset
*
* begin() and end() enable the use of range-for loops, for example:
* \code
* SequenceOffset<MyFlatMutableOffset> sequence_offset = my_type_offset.my_sequence();
* for (auto element : sequence_offset) {
* std::cout << element.x() << std::endl;
* }
* \endcode
*
*/
iterator begin()
{
RTI_FLAT_OFFSET_CHECK_NOT_NULL(return iterator(NULL, 0, 0));
return iterator(
sample_,
absolute_offset_,
absolute_offset_ + get_buffer_size());
}
/**
* @brief Gets an iterator to the past-the-end element
*/
iterator end()
{
RTI_FLAT_OFFSET_CHECK_NOT_NULL(return iterator(NULL, 0, 0));
return iterator(
sample_,
absolute_offset_ + get_buffer_size(),
absolute_offset_ + get_buffer_size());
}
private:
// for variable size types we skip element by element
template <typename E>
E get_element_impl(unsigned int i, variable_size_type_tag_t)
{
iterator it = begin();
while (it != end() && i > 0) {
if (!it.advance()) {
return E();
}
i--;
}
return *it;
}
// for fixed-size types we support random access
template <typename E>
E get_element_impl(unsigned int i, fixed_size_type_tag_t)
{
offset_t size = i * E::serialized_size_w_padding();
// Ensure that the stream has space for i + 1 elements
if (!stream_.check_size(size + E::serialized_size(0))) {
return E();
}
return E(this->sample_, this->absolute_offset_ + size);
}
};
template <typename ElementOffset>
struct SequenceOffsetHelper;
/**
* @ingroup RTIFlatOffsetsModule
* @brief Offset to a sequence of non-primitive elements
*
* @tparam ElementOffset The Offset type, for example MyFlatMutableOffset,
* MyFlatFinalOffset, or StringOffset.
*
* Represents an Offset to a sequence member and allows getting an Offset to
* each of its elements.
*
* A SequenceOffset may meet the requirements to be cast to an array of
* the equivalent plain C++ element type (see rti::flat::plain_cast), if the
* \p ElementOffset is a final type.
*/
template <typename ElementOffset>
class SequenceOffset : public AbstractAlignedList<ElementOffset> {
public:
typedef variable_size_type_tag_t offset_kind;
typedef SequenceOffsetHelper<ElementOffset> Helper;
SequenceOffset() : element_count_(0)
{
}
SequenceOffset(
rti::flat::SampleBase *sample,
offset_t offset,
offset_t sequence_size)
: AbstractAlignedList<ElementOffset>(
// Member size in bytes must be > 4, otherwise let base ctor
// fail
sequence_size >= header_length() ? sample : NULL,
// The offset begins after any padding to align to 4;
// padding may be needed for example for an array of
// sequence of final types; the end position of the previous
// sequence may not be aligned
RTIXCdrAlignment_alignSizeUp(
offset,
RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
+ header_length(),
sequence_size - header_length()),
element_count_(0)
{
#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
if (!this->is_null()) { // without exceptions, we need to check if the base ctor failed
#endif
rti::xcdr::Stream::Memento stream_memento(this->stream_);
this->stream_.skip_back(sizeof(rti::xcdr::length_t));
element_count_ = this->stream_.template deserialize_fast<rti::xcdr::length_t>();
#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
}
#endif
}
/**
* @brief Gets the Offset to an element
*
* @param i The zero-based index to the element
* @return The Offset to the element in the i-th position
*/
ElementOffset get_element(unsigned int i)
{
RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
if (i >= element_count_) {
return ElementOffset();
}
return AbstractAlignedList<ElementOffset>::get_element(i);
}
/**
* @brief The number of elements
*/
unsigned int element_count() const
{
RTI_FLAT_OFFSET_CHECK_NOT_NULL(return 0);
return element_count_;
}
private:
static offset_t header_length()
{
return static_cast<offset_t>(
detail::collection_dheader_traits<false>::dheader_size()
+ sizeof(rti::xcdr::length_t));
}
unsigned int element_count_;
};
template <typename E>
struct SequenceOffsetHelper {
// Calculates the serialized size of a Sequence by skipping each element
static offset_t calculate_serialized_size(
rti::flat::SampleBase *sample,
offset_t absolute_offset,
offset_t max_offset)
{
// Create a SequenceOffset beginning at sample + absolute_offset,
// with a size we don't know, but no greater than
// max_offset - absolute_offset
SequenceOffset<E> tmp(
sample,
absolute_offset,
max_offset - absolute_offset);
unsigned int count = tmp.element_count();
typename SequenceOffset<E>::iterator it = tmp.begin();
for (unsigned int i = 0; i < count; i++) {
if (!it.advance()) {
return 0; // error
}
}
return detail::ptrdiff(it.get_position(), sample->get_buffer())
- absolute_offset;
}
};
/**
* @ingroup RTIFlatOffsetsModule
* @brief Offset to an array of variable-size elements
*
* @tparam ElementOffset An Offset for a type of variable size, such as a
* mutable struct (MyFlatMutableOffset), union, or StringOffset.
* @tparam N The array bound. For multidimensional arrays, \p N is the product
* of each dimension bound.
*
* Represents an Offset to an array member and allows getting an Offset to
* each of its elements.
*
* @see FinalArrayOffset encapsulates arrays of fixed-size elements
*/
template <typename ElementOffset, unsigned int N>
class MutableArrayOffset : public AbstractAlignedList<ElementOffset> {
public:
typedef variable_size_type_tag_t offset_kind;
MutableArrayOffset()
{
}
MutableArrayOffset(
rti::flat::SampleBase *sample,
offset_t offset,
offset_t sequence_size)
: AbstractAlignedList<ElementOffset>(
sequence_size >= header_length() ? sample : NULL,
offset + header_length(),
sequence_size - header_length())
{
}
/**
* @brief Gets the Offset to an element
*
* @param i The zero-based index to the element
* @return The Offset to the element in the i-th position
*/
ElementOffset get_element(unsigned int i)
{
if (i >= N) {
return ElementOffset();
}
return AbstractAlignedList<ElementOffset>::get_element(i);
}
private:
static offset_t header_length()
{
return static_cast<offset_t>(
detail::collection_dheader_traits<false>::dheader_size());
}
};
/**
* @ingroup RTIFlatOffsetsModule
* @brief Offset to an array of final elements
*
* @tparam ElementOffset A final struct Offset, such as MyFlatFinalOffset.
* @tparam N The array bound. For multidimensional arrays, \p N is the product
* of each dimension bound.
*
* Represents an Offset to an array member and allows getting an Offset to
* each of its elements.
*
* FinalArrayOffset and FinalAlignedArrayOffset provide the same
* interface, but have different implementation details. FinalArrayOffset is
* used when the array member is part of a final type too, whereas
* FinalAlignedArrayOffset corresponds to an array inside a mutable type.
*
* A FinalArrayOffset may meet the requirements to be cast to an array of
* the equivalent plain C++ element type (see rti::flat::plain_cast()).
*/
template <typename ElementOffset, unsigned int N>
class FinalArrayOffset : public OffsetBase {
public:
typedef fixed_size_type_tag_t offset_kind;
FinalArrayOffset()
{
}
// Constructor used when this array is part of a fixed-size type, and
// therefore it's initial alignment is not known ahead of time
FinalArrayOffset(
rti::flat::SampleBase *sample,
offset_t absolute_offset,
offset_t first_element_size,
offset_t element_size)
: OffsetBase(
sample,
absolute_offset,
first_element_size + element_size * (N - 1)),
first_element_size_(first_element_size),
element_size_(element_size)
{
}
/**
* @brief Gets the Offset to an element
*
* @param i The zero-based index to the element
* @return The Offset to the element in the i-th position
*/
ElementOffset get_element(unsigned int i)
{
RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
if (i >= N) {
return ElementOffset(); // null offset
}
offset_t element_offset = this->absolute_offset_;
if (i > 0) {
element_offset += this->first_element_size_
+ (i - 1) * this->element_size_;
}
return ElementOffset(this->sample_, element_offset);
}
private:
offset_t first_element_size_;
offset_t element_size_;
};
/**
* @ingroup RTIFlatOffsetsModule
* @brief Offset to an array of final elements
*
* @tparam ElementOffset A final struct Offset, such as MyFlatFinalOffset.
* @tparam N The array bound. For multidimensional arrays, \p N is the product
* of each dimension bound.
*
* Represents an Offset to an array member and allows getting an Offset to
* each of its elements.
*
* The following code shows how to use a FinalAlignedArrayOffset to initialize
* an array member with MyFlatMutableBuilder:
*
* \code
* MyFlatMutableBuilder builder = rti::flat::build_data(writer);
* auto array_offset = builder.add_my_final_array();
* for (MyFlatFinalOffset element_offset : array_offset) {
* element_offset.my_primitive(3);
* // ...
* }
*
* // Or access an element directly:
* auto element_offset = array_offset.get_element(3);
* element_offset.my_primitive(3);
* \endcode
*
* A more efficient way to access a final array, provided it complies with
* the required preconditions, is through rti::flat::plain_cast().
*
* FinalArrayOffset and FinalAlignedArrayOffset provide the same
* interface, but have different implementation details. FinalArrayOffset is
* used when the array member is part of a final type too, whereas
* FinalAlignedArrayOffset corresponds to an array inside a mutable type.
*
* A FinalAlignedArrayOffset may meet the requirements to be cast to an array of
* the equivalent plain C++ element type (see rti::flat::plain_cast()).
*
* @see MutableArrayOffset encapsulates arrays of variable-size elements
*/
template <typename ElementOffset, unsigned int N>
class FinalAlignedArrayOffset : public AbstractAlignedList<ElementOffset> {
public:
typedef fixed_size_type_tag_t offset_kind;
FinalAlignedArrayOffset()
{
}
// Constructor used when this array is part of a mutable type, and
// therefore it's aligned to 4 always
FinalAlignedArrayOffset(
rti::flat::SampleBase *sample,
offset_t absolute_offset)
: AbstractAlignedList<ElementOffset>(
sample,
absolute_offset
+ detail::collection_dheader_traits<
false>::dheader_size(),
serialized_size(0))
{ }
// serialized_size() only works when this array is part of a mutable type
// and we know it's aligned to 4
static offset_t serialized_size(offset_t)
{
// [element1][pad][element2][pad]...[elementN]
return ElementOffset::serialized_size_w_padding() * (N - 1)
+ ElementOffset::serialized_size(0);
}
/**
* @brief Gets the Offset to an element
*
* @param i The zero-based index to the element
* @return The Offset to the element in the i-th position
*
* @see rti::flat::plain_cast() for a method to access all the elements at
* once
*/
ElementOffset get_element(unsigned int i)
{
RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
if (i >= N) {
return ElementOffset();
}
return AbstractAlignedList<ElementOffset>::get_element(i);
}
};
namespace detail {
// Arrays of complex elements may need a DHEADER
template <typename T, unsigned int N>
struct is_fixed_type_w_dheader<FinalAlignedArrayOffset<T, N> > {
static bool value()
{
return is_dheader_required_in_non_primitive_collections();
}
};
} // namespace detail
}} // namespace rti::flat
#endif // RTI_DDS_FLAT_SEQUENCEOFFSETS_HPP_
@@ -0,0 +1,171 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
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.
*/
// Note: this file shouldn't be included directly. Include the header for the
// corresponding C++ API:
//
// - Modern C++ API: "rti/topic/flat/FlatData.hpp"
// - Traditional C++ API: "ndds/ndds_flat_data_cpp.h"
#ifndef RTI_DDS_FLAT_RTIFLAT_HPP_
#define RTI_DDS_FLAT_RTIFLAT_HPP_
/**
* @defgroup RTIFlatDataModule FlatData Topic-Types
* @ingroup DDSTopicModule
* @brief @st_ext FlatData Language Binding for IDL topic-types
*
* @note For a complete description of the FlatData language binding and its
* benefits, and a tutorial, see the "Sending Large Data" chapter in the
* <b>\ndds User's Manual</b>.
*
* @note For buildable <b>code examples</b>,
* see https://community.rti.com/kb/flatdata-and-zerocopy-examples.
*
* @note The FlatData language binding is available in the Traditional C++ API
* and in the Modern C++ API.
*
* RTI FlatData&trade; is a language binding for IDL types in which the in-memory
* representation of a sample matches the wire representation. Therefore, the
* cost of serialization/deserialization is zero.
*
* To select FlatData as the language binding of a type, annotate it with
* \p \@language_binding(FLAT_DATA) in IDL or apply the attribute
* \p languageBinding="flat_data" in XML.
*
* There are some restrictions regarding the kinds of types to which the
* FlatData language binding can be applied.
*
* - For final types, the FlatData language binding can be applied only to
* fixed-size types. A fixed-size type is a type whose wire representation
* always has the same size. This includes primitive types, arrays of
* fixed-size types, and structs containing only members of fixed-size types.
* Unions are not fixed-size types.
* - For mutable types, any member is permitted.
* - Extensible types cannot be marked as FlatData.
*
* Final types are more efficient, but more restrictive. In general, a good
* compromise is to define mutable top-level types, but making sure their
* largest data members are final.
*
* When a type is marked with the FlatData language binding, its mapping into
* C++ is different than that of a regular type (plain language binding). Rather
* than a single C++ class with direct access to its members, for a FlatData
* type \nddsgen generates the following:
*
* \li A \ref RTIFlatSampleModule "Sample", the data in serialized format
* \li An \ref RTIFlatOffsetsModule "Offset", which allows reading the data
* members of that type inside a Sample, and modifying them without changing
* the size
* \li A \ref RTIFlatBuildersModule "Builder", if the type is mutable, which
* allows creating a variable-size Sample
*
* For example, for the IDL types \ref MyFlatFinal and \ref MyFlatMutable
* \nddsgen generates the following C++ types:
* \li The Sample types \ref MyFlatFinal and \ref MyFlatMutable
* \li The Offset types MyFlatFinalOffset and MyFlatMutableOffset.
* \li The Builder type MyFlatMutableBuilder.
*
* @section PublishingFlatData Publishing FlatData
* The typical way to publish FlatData samples includes the following steps:
* - Create a \idref_FooDataWriter as you would for a non-FlatData (plain)
* topic-type (see \ref DDSWriterExampleModule_writer_setup).
*
* (For final topic-types such as \ref MyFlatFinal)
* - Obtain a FlatData sample with \idref_FooDataWriter_get_loan.
* \code
* MyFlatFinal *foo_sample = writer.get_loan();
* \endcode
*
* - Initialize the sample, starting from the \ref rti::flat::Sample::root "root()" offset.
* \code
* MyFlatFinalOffset foo_root = foo_sample->root();
* foo_root.my_primitive(3);
* auto my_complex_offset = foo_root.my_complex();
* // ... initialize my_complex_offset
* \endcode
*
* (For mutable topic-types such as \ref MyFlatMutable)
* - Obtain a \ref RTIFlatBuildersModule "Builder" to create a variable-size
* sample with rti::flat::build_data().
* \code
* MyFlatMutableBuilder foo_builder = rti::flat::build_data(writer);
* \endcode
*
* - Use this builder (and possibly nested member builders) to initialize the
* members.
* \code
* foo_builder.add_my_primitive(3);
* auto my_mutable_builder = foo_builder.build_my_mutable();
* // ... build 'my_mutable' (a member with a mutable type)
* my_mutable_builder.finish(); // completes a member
* auto my_final_offset = foo_builder.add_my_final();
* // ... initialize 'my_final' (a member with a final type)
* \endcode
*
* - Obtain the completed sample with MyFlatMutableBuilder::finish_sample(). After
* that, the builder is no longer usable, and the sample size cannot change.
* \code
* MyFlatMutable *foo_sample = foo_builder.finish_sample();
* \endcode
* - Optionally, it is possible to change the values of the sample accessing
* its root(), as long as the size doesn't change. For example, if the sample
* was built with a sequence member with two elements, it is possible to modify
* any of those elements, but it's not possible to add a third element.
*
* (For both final and mutable topic-types)
* - Write the sample with \idref_FooDataWriter_write.
* \code
* writer.write(*foo_sample);
* \endcode
*
* After write, the DataWriter owns the FlatData sample. This allows avoiding
* additional copies, the main goal of the FlatData language binding. This
* means that the sample cannot be reused. The DataWriter will return it to the
* sample pool when appropriate, as described in \idref_FooDataWriter_get_loan.
*
* @section SubscribingFlatData Subscribing to FlatData
*
* To subscribe to a topic using a FlatData topic-type:
* - Create a \idref_FooDataReader normally (see
* \ref DDSReaderExampleModule_reader_setup).
* - Read or take the samples using a loaning operation, such as
* \idref_FooDataReader_take (copying read/take operations cannot be used
* with FlatData types).
* - Access the \ref rti::flat::Sample::root "root()" offset, and any of the
* sample's members from there.
*
* Note that the language binding is a local concept. It is possible
* to publish with a FlatData topic-type and subscribe to it with a <b>plain</b>
* topic-type with the same (or assignable) definition. It is also possible to
* use a plain topic-type on the publisher side and subscribe to it using FlatData.
* The DataWriter or DataReader of the plain topic-type has to use
* \idref_XCDR2_DATA_REPRESENTATION in \idref_DataRepresentationQosPolicy.
*
*/
#ifdef DOXYGEN_DOCUMENTATION_ONLY
namespace rti {
/**
* @brief \st_ext Support for \ref RTIFlatDataModule
*/
namespace flat {
}
}
#endif
#include "rti/flat/ExceptionHelper.hpp"
#include "rti/flat/FlatSample.hpp"
#include "rti/flat/FlatTypeTraits.hpp"
#include "rti/flat/SequenceBuilders.hpp"
#endif // RTI_DDS_FLAT_RTIFLAT_HPP_
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,925 @@
/*
WARNING: THIS FILE IS AUTO-GENERATED. DO NOT MODIFY.
This file was generated from RecordingServiceTypes.idl
using RTI Code Generator (rtiddsgen) version 4.7.0.
The rtiddsgen tool is part of the RTI Connext DDS distribution.
For more information, type 'rtiddsgen -help' at a command shell
or consult the Code Generator User's Manual.
*/
#ifndef RecordingServiceTypes_164879555_hpp
#define RecordingServiceTypes_164879555_hpp
#include <iosfwd>
#if defined(NDDS_USER_DLL_EXPORT_RECORDER_SERVICE_ADMINISTRATION) && defined(RTI_WIN32)
#undef RTIUSERDllExport
#define RTIUSERDllExport __declspec(dllexport)
#endif
#if !defined(RTI_WIN32) && defined(NDDS_USER_SYMBOL_EXPORT)
#undef RTIUSERDllExport
#define RTIUSERDllExport __attribute__((visibility("default")))
#endif
#include "dds/core/SafeEnumeration.hpp"
#include "dds/core/String.hpp"
#include "dds/core/array.hpp"
#include "dds/core/vector.hpp"
#include "dds/core/External.hpp"
#include "rti/core/LongDouble.hpp"
#include "rti/core/Pointer.hpp"
#include "rti/core/array.hpp"
#include "rti/topic/TopicTraits.hpp"
#include "omg/types/string_view.hpp"
#include "rti/core/BoundedSequence.hpp"
#include "dds/core/Optional.hpp"
#ifndef NDDS_STANDALONE_TYPE
#include "cdr/cdr_typeCode.h"
#include "dds/domain/DomainParticipant.hpp"
#include "dds/topic/TopicTraits.hpp"
#include "dds/core/xtypes/DynamicType.hpp"
#include "dds/core/xtypes/StructType.hpp"
#include "dds/core/xtypes/UnionType.hpp"
#include "dds/core/xtypes/EnumType.hpp"
#include "dds/core/xtypes/AliasType.hpp"
#include "rti/util/StreamFlagSaver.hpp"
#include "rti/domain/PluginSupport.hpp"
#endif
#if defined(NDDS_USER_DLL_EXPORT_RECORDER_SERVICE_ADMINISTRATION) || defined(NDDS_USER_SYMBOL_EXPORT)
#undef RTIUSERDllExport
#define RTIUSERDllExport
#endif
#if defined(NDDS_USER_DLL_EXPORT_RECORDER_SERVICE_ADMINISTRATION) && defined(RTI_WIN32)
#undef NDDSUSERDllExport
#define NDDSUSERDllExport __declspec(dllexport)
#endif
#if !defined(RTI_WIN32) && defined(NDDS_USER_SYMBOL_EXPORT)
#undef NDDSUSERDllExport
#define NDDSUSERDllExport __attribute__((visibility("default")))
#endif
namespace RTI {
namespace RecordingService {
static const int32_t DATA_TAG_MAX_STRING_SIZE = 256L;
class NDDSUSERDllExport DataTagParams {
public:
DataTagParams();
DataTagParams(float m_timestamp_offset__,const std::string& m_tag_name__,const std::string& m_tag_description__);
float& timestamp_offset() noexcept {
return m_timestamp_offset_;
}
const float& timestamp_offset() const noexcept {
return m_timestamp_offset_;
}
void timestamp_offset(float value) {
m_timestamp_offset_ = value;
}
std::string& tag_name() noexcept {
return m_tag_name_;
}
const std::string& tag_name() const noexcept {
return m_tag_name_;
}
void tag_name(const std::string& value) {
m_tag_name_ = value;
}
void tag_name(std::string&& value) {
m_tag_name_ = std::move(value);
}
std::string& tag_description() noexcept {
return m_tag_description_;
}
const std::string& tag_description() const noexcept {
return m_tag_description_;
}
void tag_description(const std::string& value) {
m_tag_description_ = value;
}
void tag_description(std::string&& value) {
m_tag_description_ = std::move(value);
}
bool operator == (const DataTagParams& other_) const;
bool operator != (const DataTagParams& other_) const;
void swap(DataTagParams& other_) noexcept ;
private:
float m_timestamp_offset_;
std::string m_tag_name_;
std::string m_tag_description_;
};
inline void swap(DataTagParams& a, DataTagParams& b) noexcept
{
a.swap(b);
}
NDDSUSERDllExport std::ostream& operator<<(std::ostream& o, const DataTagParams& sample);
enum class BreakpointFormat {
TIMESTAMP = 0,
TAG_NAME
};
NDDSUSERDllExport std::ostream& operator << (std::ostream& o,const BreakpointFormat& sample);
class NDDSUSERDllExport BreakpointUnion {
public:
BreakpointUnion();
::RTI::RecordingService::BreakpointFormat& _d() {
return m_d_;
}
const ::RTI::RecordingService::BreakpointFormat& _d() const {
return m_d_;
}
void _d(::RTI::RecordingService::BreakpointFormat value) {
m_d_ = value;
}
int64_t& timestamp_nanos() {
if (_d() != (RTI::RecordingService::BreakpointFormat::TIMESTAMP) ) {
throw ::dds::core::PreconditionNotMetError(
"::RTI::RecordingService::BreakpointUnion::timestamp_nanos not selected by the discriminator" );
}
return m_u_.m_timestamp_nanos_;
}
const int64_t& timestamp_nanos() const {
if (_d() != (RTI::RecordingService::BreakpointFormat::TIMESTAMP) ) {
throw ::dds::core::PreconditionNotMetError(
"::RTI::RecordingService::BreakpointUnion::timestamp_nanos not selected by the discriminator" );
}
return m_u_.m_timestamp_nanos_;
}
void timestamp_nanos(int64_t value) {
m_u_.m_timestamp_nanos_ = value;
m_d_= (RTI::RecordingService::BreakpointFormat::TIMESTAMP);
}
std::string& tag_name() {
if (_d() != (RTI::RecordingService::BreakpointFormat::TAG_NAME) ) {
throw ::dds::core::PreconditionNotMetError(
"::RTI::RecordingService::BreakpointUnion::tag_name not selected by the discriminator" );
}
return m_u_.m_tag_name_;
}
const std::string& tag_name() const {
if (_d() != (RTI::RecordingService::BreakpointFormat::TAG_NAME) ) {
throw ::dds::core::PreconditionNotMetError(
"::RTI::RecordingService::BreakpointUnion::tag_name not selected by the discriminator" );
}
return m_u_.m_tag_name_;
}
void tag_name(const std::string& value) {
m_u_.m_tag_name_ = value;
m_d_= (RTI::RecordingService::BreakpointFormat::TAG_NAME);
}
void tag_name(std::string&& value) {
m_u_.m_tag_name_ = std::move(value);
m_d_= (RTI::RecordingService::BreakpointFormat::TAG_NAME);
}
bool operator == (const BreakpointUnion& other_) const;
bool operator != (const BreakpointUnion& other_) const;
static ::RTI::RecordingService::BreakpointFormat default_discriminator();
void swap(BreakpointUnion& other_) noexcept ;
private:
::RTI::RecordingService::BreakpointFormat m_d_;
struct NDDSUSERDllExport Union_ {
int64_t m_timestamp_nanos_;
std::string m_tag_name_;
Union_();
Union_(int64_t m_timestamp_nanos__,const std::string& m_tag_name__);
};
Union_ m_u_;
};
inline void swap(BreakpointUnion& a, BreakpointUnion& b) noexcept
{
a.swap(b);
}
NDDSUSERDllExport std::ostream& operator<<(std::ostream& o, const BreakpointUnion& sample);
class NDDSUSERDllExport BreakpointParams {
public:
BreakpointParams();
BreakpointParams(const ::dds::core::optional< std::string >& m_label__,const ::RTI::RecordingService::BreakpointUnion& m_value__);
::dds::core::optional< std::string >& label() noexcept {
return m_label_;
}
const ::dds::core::optional< std::string >& label() const noexcept {
return m_label_;
}
void label(const ::dds::core::optional< std::string >& value) {
m_label_ = value;
}
void label(::dds::core::optional< std::string >&& value) {
m_label_ = std::move(value);
}
::RTI::RecordingService::BreakpointUnion& value() noexcept {
return m_value_;
}
const ::RTI::RecordingService::BreakpointUnion& value() const noexcept {
return m_value_;
}
void value(const ::RTI::RecordingService::BreakpointUnion& value) {
m_value_ = value;
}
void value(::RTI::RecordingService::BreakpointUnion&& value) {
m_value_ = std::move(value);
}
bool operator == (const BreakpointParams& other_) const;
bool operator != (const BreakpointParams& other_) const;
void swap(BreakpointParams& other_) noexcept ;
private:
::dds::core::optional< std::string > m_label_;
::RTI::RecordingService::BreakpointUnion m_value_;
};
inline void swap(BreakpointParams& a, BreakpointParams& b) noexcept
{
a.swap(b);
}
NDDSUSERDllExport std::ostream& operator<<(std::ostream& o, const BreakpointParams& sample);
enum class ContinueFormat {
OFFSET = 0,
SLICE
};
NDDSUSERDllExport std::ostream& operator << (std::ostream& o,const ContinueFormat& sample);
class NDDSUSERDllExport ContinueUnion {
public:
ContinueUnion();
::RTI::RecordingService::ContinueFormat& _d() {
return m_d_;
}
const ::RTI::RecordingService::ContinueFormat& _d() const {
return m_d_;
}
void _d(::RTI::RecordingService::ContinueFormat value) {
m_d_ = value;
}
int64_t& offset() {
if (_d() != (RTI::RecordingService::ContinueFormat::OFFSET) ) {
throw ::dds::core::PreconditionNotMetError(
"::RTI::RecordingService::ContinueUnion::offset not selected by the discriminator" );
}
return m_u_.m_offset_;
}
const int64_t& offset() const {
if (_d() != (RTI::RecordingService::ContinueFormat::OFFSET) ) {
throw ::dds::core::PreconditionNotMetError(
"::RTI::RecordingService::ContinueUnion::offset not selected by the discriminator" );
}
return m_u_.m_offset_;
}
void offset(int64_t value) {
m_u_.m_offset_ = value;
m_d_= (RTI::RecordingService::ContinueFormat::OFFSET);
}
int64_t& slices() {
if (_d() != (RTI::RecordingService::ContinueFormat::SLICE) ) {
throw ::dds::core::PreconditionNotMetError(
"::RTI::RecordingService::ContinueUnion::slices not selected by the discriminator" );
}
return m_u_.m_slices_;
}
const int64_t& slices() const {
if (_d() != (RTI::RecordingService::ContinueFormat::SLICE) ) {
throw ::dds::core::PreconditionNotMetError(
"::RTI::RecordingService::ContinueUnion::slices not selected by the discriminator" );
}
return m_u_.m_slices_;
}
void slices(int64_t value) {
m_u_.m_slices_ = value;
m_d_= (RTI::RecordingService::ContinueFormat::SLICE);
}
bool operator == (const ContinueUnion& other_) const;
bool operator != (const ContinueUnion& other_) const;
static ::RTI::RecordingService::ContinueFormat default_discriminator();
void swap(ContinueUnion& other_) noexcept ;
private:
::RTI::RecordingService::ContinueFormat m_d_;
struct NDDSUSERDllExport Union_ {
int64_t m_offset_;
int64_t m_slices_;
Union_();
Union_(int64_t m_offset__,int64_t m_slices__);
};
Union_ m_u_;
};
inline void swap(ContinueUnion& a, ContinueUnion& b) noexcept
{
a.swap(b);
}
NDDSUSERDllExport std::ostream& operator<<(std::ostream& o, const ContinueUnion& sample);
class NDDSUSERDllExport ContinueParams {
public:
ContinueParams();
explicit ContinueParams(const ::RTI::RecordingService::ContinueUnion& m_value__);
::RTI::RecordingService::ContinueUnion& value() noexcept {
return m_value_;
}
const ::RTI::RecordingService::ContinueUnion& value() const noexcept {
return m_value_;
}
void value(const ::RTI::RecordingService::ContinueUnion& value) {
m_value_ = value;
}
void value(::RTI::RecordingService::ContinueUnion&& value) {
m_value_ = std::move(value);
}
bool operator == (const ContinueParams& other_) const;
bool operator != (const ContinueParams& other_) const;
void swap(ContinueParams& other_) noexcept ;
private:
::RTI::RecordingService::ContinueUnion m_value_;
};
inline void swap(ContinueParams& a, ContinueParams& b) noexcept
{
a.swap(b);
}
NDDSUSERDllExport std::ostream& operator<<(std::ostream& o, const ContinueParams& sample);
enum class TimerState {
WORKING = 0,
PAUSED,
BREAKPOINT
};
NDDSUSERDllExport std::ostream& operator << (std::ostream& o,const TimerState& sample);
class NDDSUSERDllExport DebugStatus {
public:
DebugStatus();
explicit DebugStatus(const ::RTI::RecordingService::TimerState& m_status__);
::RTI::RecordingService::TimerState& status() noexcept {
return m_status_;
}
const ::RTI::RecordingService::TimerState& status() const noexcept {
return m_status_;
}
void status(const ::RTI::RecordingService::TimerState& value) {
m_status_ = value;
}
void status(::RTI::RecordingService::TimerState&& value) {
m_status_ = std::move(value);
}
bool operator == (const DebugStatus& other_) const;
bool operator != (const DebugStatus& other_) const;
void swap(DebugStatus& other_) noexcept ;
private:
::RTI::RecordingService::TimerState m_status_;
};
inline void swap(DebugStatus& a, DebugStatus& b) noexcept
{
a.swap(b);
}
NDDSUSERDllExport std::ostream& operator<<(std::ostream& o, const DebugStatus& sample);
class NDDSUSERDllExport TimestampHolder {
public:
TimestampHolder();
explicit TimestampHolder(int64_t m_timestamp_nanos__);
int64_t& timestamp_nanos() noexcept {
return m_timestamp_nanos_;
}
const int64_t& timestamp_nanos() const noexcept {
return m_timestamp_nanos_;
}
void timestamp_nanos(int64_t value) {
m_timestamp_nanos_ = value;
}
bool operator == (const TimestampHolder& other_) const;
bool operator != (const TimestampHolder& other_) const;
void swap(TimestampHolder& other_) noexcept ;
private:
int64_t m_timestamp_nanos_;
};
inline void swap(TimestampHolder& a, TimestampHolder& b) noexcept
{
a.swap(b);
}
NDDSUSERDllExport std::ostream& operator<<(std::ostream& o, const TimestampHolder& sample);
} // namespace RecordingService
} // namespace RTI
#ifdef NDDS_STANDALONE_TYPE
namespace rti {
namespace topic {
template <>
struct default_enumerator< ::RTI::RecordingService::BreakpointFormat>
{
static const ::RTI::RecordingService::BreakpointFormat value;
};
template <>
struct default_enumerator< ::RTI::RecordingService::ContinueFormat>
{
static const ::RTI::RecordingService::ContinueFormat value;
};
template <>
struct default_enumerator< ::RTI::RecordingService::TimerState>
{
static const ::RTI::RecordingService::TimerState value;
};
}
}
#else
namespace rti {
namespace flat {
namespace topic {
}
}
}
namespace dds {
namespace topic {
template<>
struct topic_type_name< ::RTI::RecordingService::DataTagParams > {
NDDSUSERDllExport static std::string value() {
return "RTI::RecordingService::DataTagParams";
}
};
template<>
struct is_topic_type< ::RTI::RecordingService::DataTagParams > : public ::dds::core::true_type {};
template<>
struct topic_type_support< ::RTI::RecordingService::DataTagParams > {
NDDSUSERDllExport
static void register_type(
::dds::domain::DomainParticipant& participant,
const std::string & type_name);
NDDSUSERDllExport
static std::vector<char>& to_cdr_buffer(
std::vector<char>& buffer,
const ::RTI::RecordingService::DataTagParams& sample,
::dds::core::policy::DataRepresentationId representation
= ::dds::core::policy::DataRepresentation::auto_id());
NDDSUSERDllExport
static void from_cdr_buffer(::RTI::RecordingService::DataTagParams& sample, const std::vector<char>& buffer);
NDDSUSERDllExport
static void reset_sample(::RTI::RecordingService::DataTagParams& sample);
NDDSUSERDllExport
static void allocate_sample(::RTI::RecordingService::DataTagParams& sample, int, int);
static const ::rti::topic::TypePluginKind::type type_plugin_kind =
::rti::topic::TypePluginKind::STL;
};
template<>
struct topic_type_name< ::RTI::RecordingService::BreakpointUnion > {
NDDSUSERDllExport static std::string value() {
return "RTI::RecordingService::BreakpointUnion";
}
};
template<>
struct topic_type_support< ::RTI::RecordingService::BreakpointUnion > {
NDDSUSERDllExport
static void reset_sample(::RTI::RecordingService::BreakpointUnion& sample);
NDDSUSERDllExport
static void allocate_sample(::RTI::RecordingService::BreakpointUnion& sample, int, int);
static const ::rti::topic::TypePluginKind::type type_plugin_kind =
::rti::topic::TypePluginKind::STL;
};
template<>
struct topic_type_name< ::RTI::RecordingService::BreakpointParams > {
NDDSUSERDllExport static std::string value() {
return "RTI::RecordingService::BreakpointParams";
}
};
template<>
struct is_topic_type< ::RTI::RecordingService::BreakpointParams > : public ::dds::core::true_type {};
template<>
struct topic_type_support< ::RTI::RecordingService::BreakpointParams > {
NDDSUSERDllExport
static void register_type(
::dds::domain::DomainParticipant& participant,
const std::string & type_name);
NDDSUSERDllExport
static std::vector<char>& to_cdr_buffer(
std::vector<char>& buffer,
const ::RTI::RecordingService::BreakpointParams& sample,
::dds::core::policy::DataRepresentationId representation
= ::dds::core::policy::DataRepresentation::auto_id());
NDDSUSERDllExport
static void from_cdr_buffer(::RTI::RecordingService::BreakpointParams& sample, const std::vector<char>& buffer);
NDDSUSERDllExport
static void reset_sample(::RTI::RecordingService::BreakpointParams& sample);
NDDSUSERDllExport
static void allocate_sample(::RTI::RecordingService::BreakpointParams& sample, int, int);
static const ::rti::topic::TypePluginKind::type type_plugin_kind =
::rti::topic::TypePluginKind::STL;
};
template<>
struct topic_type_name< ::RTI::RecordingService::ContinueUnion > {
NDDSUSERDllExport static std::string value() {
return "RTI::RecordingService::ContinueUnion";
}
};
template<>
struct topic_type_support< ::RTI::RecordingService::ContinueUnion > {
NDDSUSERDllExport
static void reset_sample(::RTI::RecordingService::ContinueUnion& sample);
NDDSUSERDllExport
static void allocate_sample(::RTI::RecordingService::ContinueUnion& sample, int, int);
static const ::rti::topic::TypePluginKind::type type_plugin_kind =
::rti::topic::TypePluginKind::STL;
};
template<>
struct topic_type_name< ::RTI::RecordingService::ContinueParams > {
NDDSUSERDllExport static std::string value() {
return "RTI::RecordingService::ContinueParams";
}
};
template<>
struct is_topic_type< ::RTI::RecordingService::ContinueParams > : public ::dds::core::true_type {};
template<>
struct topic_type_support< ::RTI::RecordingService::ContinueParams > {
NDDSUSERDllExport
static void register_type(
::dds::domain::DomainParticipant& participant,
const std::string & type_name);
NDDSUSERDllExport
static std::vector<char>& to_cdr_buffer(
std::vector<char>& buffer,
const ::RTI::RecordingService::ContinueParams& sample,
::dds::core::policy::DataRepresentationId representation
= ::dds::core::policy::DataRepresentation::auto_id());
NDDSUSERDllExport
static void from_cdr_buffer(::RTI::RecordingService::ContinueParams& sample, const std::vector<char>& buffer);
NDDSUSERDllExport
static void reset_sample(::RTI::RecordingService::ContinueParams& sample);
NDDSUSERDllExport
static void allocate_sample(::RTI::RecordingService::ContinueParams& sample, int, int);
static const ::rti::topic::TypePluginKind::type type_plugin_kind =
::rti::topic::TypePluginKind::STL;
};
template<>
struct topic_type_name< ::RTI::RecordingService::DebugStatus > {
NDDSUSERDllExport static std::string value() {
return "RTI::RecordingService::DebugStatus";
}
};
template<>
struct is_topic_type< ::RTI::RecordingService::DebugStatus > : public ::dds::core::true_type {};
template<>
struct topic_type_support< ::RTI::RecordingService::DebugStatus > {
NDDSUSERDllExport
static void register_type(
::dds::domain::DomainParticipant& participant,
const std::string & type_name);
NDDSUSERDllExport
static std::vector<char>& to_cdr_buffer(
std::vector<char>& buffer,
const ::RTI::RecordingService::DebugStatus& sample,
::dds::core::policy::DataRepresentationId representation
= ::dds::core::policy::DataRepresentation::auto_id());
NDDSUSERDllExport
static void from_cdr_buffer(::RTI::RecordingService::DebugStatus& sample, const std::vector<char>& buffer);
NDDSUSERDllExport
static void reset_sample(::RTI::RecordingService::DebugStatus& sample);
NDDSUSERDllExport
static void allocate_sample(::RTI::RecordingService::DebugStatus& sample, int, int);
static const ::rti::topic::TypePluginKind::type type_plugin_kind =
::rti::topic::TypePluginKind::STL;
};
template<>
struct topic_type_name< ::RTI::RecordingService::TimestampHolder > {
NDDSUSERDllExport static std::string value() {
return "RTI::RecordingService::TimestampHolder";
}
};
template<>
struct is_topic_type< ::RTI::RecordingService::TimestampHolder > : public ::dds::core::true_type {};
template<>
struct topic_type_support< ::RTI::RecordingService::TimestampHolder > {
NDDSUSERDllExport
static void register_type(
::dds::domain::DomainParticipant& participant,
const std::string & type_name);
NDDSUSERDllExport
static std::vector<char>& to_cdr_buffer(
std::vector<char>& buffer,
const ::RTI::RecordingService::TimestampHolder& sample,
::dds::core::policy::DataRepresentationId representation
= ::dds::core::policy::DataRepresentation::auto_id());
NDDSUSERDllExport
static void from_cdr_buffer(::RTI::RecordingService::TimestampHolder& sample, const std::vector<char>& buffer);
NDDSUSERDllExport
static void reset_sample(::RTI::RecordingService::TimestampHolder& sample);
NDDSUSERDllExport
static void allocate_sample(::RTI::RecordingService::TimestampHolder& sample, int, int);
static const ::rti::topic::TypePluginKind::type type_plugin_kind =
::rti::topic::TypePluginKind::STL;
};
}
}
namespace rti {
namespace topic {
template<>
struct dynamic_type< ::RTI::RecordingService::DataTagParams > {
typedef ::dds::core::xtypes::StructType type;
NDDSUSERDllExport static const ::dds::core::xtypes::StructType& get();
};
template <>
struct extensibility< ::RTI::RecordingService::DataTagParams > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
template <>
struct default_enumerator< ::RTI::RecordingService::BreakpointFormat>
{
static const ::RTI::RecordingService::BreakpointFormat value;
};
template<>
struct dynamic_type< ::RTI::RecordingService::BreakpointFormat > {
typedef ::dds::core::xtypes::EnumType type;
NDDSUSERDllExport static const ::dds::core::xtypes::EnumType& get();
};
template <>
struct extensibility< ::RTI::RecordingService::BreakpointFormat > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
template<>
struct dynamic_type< ::RTI::RecordingService::BreakpointUnion > {
typedef ::dds::core::xtypes::UnionType type;
NDDSUSERDllExport static const ::dds::core::xtypes::UnionType& get();
};
template <>
struct extensibility< ::RTI::RecordingService::BreakpointUnion > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
template<>
struct dynamic_type< ::RTI::RecordingService::BreakpointParams > {
typedef ::dds::core::xtypes::StructType type;
NDDSUSERDllExport static const ::dds::core::xtypes::StructType& get();
};
template <>
struct extensibility< ::RTI::RecordingService::BreakpointParams > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
template <>
struct default_enumerator< ::RTI::RecordingService::ContinueFormat>
{
static const ::RTI::RecordingService::ContinueFormat value;
};
template<>
struct dynamic_type< ::RTI::RecordingService::ContinueFormat > {
typedef ::dds::core::xtypes::EnumType type;
NDDSUSERDllExport static const ::dds::core::xtypes::EnumType& get();
};
template <>
struct extensibility< ::RTI::RecordingService::ContinueFormat > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
template<>
struct dynamic_type< ::RTI::RecordingService::ContinueUnion > {
typedef ::dds::core::xtypes::UnionType type;
NDDSUSERDllExport static const ::dds::core::xtypes::UnionType& get();
};
template <>
struct extensibility< ::RTI::RecordingService::ContinueUnion > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
template<>
struct dynamic_type< ::RTI::RecordingService::ContinueParams > {
typedef ::dds::core::xtypes::StructType type;
NDDSUSERDllExport static const ::dds::core::xtypes::StructType& get();
};
template <>
struct extensibility< ::RTI::RecordingService::ContinueParams > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
template <>
struct default_enumerator< ::RTI::RecordingService::TimerState>
{
static const ::RTI::RecordingService::TimerState value;
};
template<>
struct dynamic_type< ::RTI::RecordingService::TimerState > {
typedef ::dds::core::xtypes::EnumType type;
NDDSUSERDllExport static const ::dds::core::xtypes::EnumType& get();
};
template <>
struct extensibility< ::RTI::RecordingService::TimerState > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
template<>
struct dynamic_type< ::RTI::RecordingService::DebugStatus > {
typedef ::dds::core::xtypes::StructType type;
NDDSUSERDllExport static const ::dds::core::xtypes::StructType& get();
};
template <>
struct extensibility< ::RTI::RecordingService::DebugStatus > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
template<>
struct dynamic_type< ::RTI::RecordingService::TimestampHolder > {
typedef ::dds::core::xtypes::StructType type;
NDDSUSERDllExport static const ::dds::core::xtypes::StructType& get();
};
template <>
struct extensibility< ::RTI::RecordingService::TimestampHolder > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
}
}
#endif // NDDS_STANDALONE_TYPE
#if defined(NDDS_USER_DLL_EXPORT_RECORDER_SERVICE_ADMINISTRATION) || defined(NDDS_USER_SYMBOL_EXPORT)
#undef NDDSUSERDllExport
#define NDDSUSERDllExport
#endif
#endif // RecordingServiceTypes_164879555_hpp
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,534 @@
/*
WARNING: THIS FILE IS AUTO-GENERATED. DO NOT MODIFY.
This file was generated from ServiceAdmin.idl
using RTI Code Generator (rtiddsgen) version 4.7.0.
The rtiddsgen tool is part of the RTI Connext DDS distribution.
For more information, type 'rtiddsgen -help' at a command shell
or consult the Code Generator User's Manual.
*/
#ifndef ServiceAdmin_1325755560_hpp
#define ServiceAdmin_1325755560_hpp
#include <iosfwd>
#if defined(NDDS_USER_DLL_EXPORT_ROUTER_SERVICE_ADMIN) && defined(RTI_WIN32)
#undef RTIUSERDllExport
#define RTIUSERDllExport __declspec(dllexport)
#endif
#if !defined(RTI_WIN32) && defined(NDDS_USER_SYMBOL_EXPORT)
#undef RTIUSERDllExport
#define RTIUSERDllExport __attribute__((visibility("default")))
#endif
#include "dds/core/SafeEnumeration.hpp"
#include "dds/core/String.hpp"
#include "dds/core/array.hpp"
#include "dds/core/vector.hpp"
#include "dds/core/External.hpp"
#include "rti/core/LongDouble.hpp"
#include "rti/core/Pointer.hpp"
#include "rti/core/array.hpp"
#include "rti/topic/TopicTraits.hpp"
#include "omg/types/string_view.hpp"
#include "rti/core/BoundedSequence.hpp"
#include "dds/core/Optional.hpp"
#ifndef NDDS_STANDALONE_TYPE
#include "cdr/cdr_typeCode.h"
#include "dds/domain/DomainParticipant.hpp"
#include "dds/topic/TopicTraits.hpp"
#include "dds/core/xtypes/DynamicType.hpp"
#include "dds/core/xtypes/StructType.hpp"
#include "dds/core/xtypes/UnionType.hpp"
#include "dds/core/xtypes/EnumType.hpp"
#include "dds/core/xtypes/AliasType.hpp"
#include "rti/util/StreamFlagSaver.hpp"
#include "rti/domain/PluginSupport.hpp"
#endif
#if defined(NDDS_USER_DLL_EXPORT_ROUTER_SERVICE_ADMIN) || defined(NDDS_USER_SYMBOL_EXPORT)
#undef RTIUSERDllExport
#define RTIUSERDllExport
#endif
#if defined(NDDS_USER_DLL_EXPORT_ROUTER_SERVICE_ADMIN) && defined(RTI_WIN32)
#undef NDDSUSERDllExport
#define NDDSUSERDllExport __declspec(dllexport)
#endif
#if !defined(RTI_WIN32) && defined(NDDS_USER_SYMBOL_EXPORT)
#undef NDDSUSERDllExport
#define NDDSUSERDllExport __attribute__((visibility("default")))
#endif
#if defined(NDDS_USER_DLL_EXPORT_ROUTER_SERVICE_ADMIN) || defined(NDDS_USER_SYMBOL_EXPORT)
#undef NDDSUSERDllExport
#define NDDSUSERDllExport
#endif
#include "ServiceCommon.hpp"
#if defined(NDDS_USER_DLL_EXPORT_ROUTER_SERVICE_ADMIN) && defined(RTI_WIN32)
#undef NDDSUSERDllExport
#define NDDSUSERDllExport __declspec(dllexport)
#endif
#if !defined(RTI_WIN32) && defined(NDDS_USER_SYMBOL_EXPORT)
#undef NDDSUSERDllExport
#define NDDSUSERDllExport __attribute__((visibility("default")))
#endif
namespace RTI {
namespace Service {
namespace Admin {
static const std::string COMMAND_REQUEST_TOPIC_NAME = "rti/service/admin/command_request";
static const std::string COMMAND_REPLY_TOPIC_NAME = "rti/service/admin/command_reply";
static const int32_t NAME_LENGTH_MAX = (RTI::Service::BOUNDED_STRING_LENGTH_MAX);
typedef std::string EntityName;
struct EntityName_AliasTag_t {};
static const int32_t RESOURCE_IDENTIFIER_LENGTH_MAX = (RTI::Service::RESOURCE_IDENTIFIER_LENGTH_MAX);
typedef std::string ResourceIdentifier;
struct ResourceIdentifier_AliasTag_t {};
typedef std::string StringBody;
struct StringBody_AliasTag_t {};
#if (defined(RTI_WIN32) || defined (RTI_WINCE)) && defined(NDDS_USER_DLL_EXPORT_ROUTER_SERVICE_ADMIN)
// On Windows, dll-export template instantiations of standard types used by
// other dll-exported types
template class NDDSUSERDllExport std::allocator< uint8_t >;
template class NDDSUSERDllExport std::vector< uint8_t >;
#endif
typedef std::vector< uint8_t > OctetBody;
struct OctetBody_AliasTag_t {};
enum class CommandActionKind {
CREATE_ACTION,
GET_ACTION,
UPDATE_ACTION,
DELETE_ACTION
};
NDDSUSERDllExport std::ostream& operator << (std::ostream& o,const CommandActionKind& sample);
enum class CommandReplyRetcode {
OK_RETCODE,
ERROR_RETCODE
};
NDDSUSERDllExport std::ostream& operator << (std::ostream& o,const CommandReplyRetcode& sample);
class NDDSUSERDllExport CommandRequest {
public:
CommandRequest();
CommandRequest(int32_t m_instance_id__,const ::dds::core::optional< std::string >& m_application_name__,const ::RTI::Service::Admin::CommandActionKind& m_action__,const std::string& m_resource_identifier__,const std::string& m_string_body__,const ::RTI::Service::Admin::OctetBody& m_octet_body__);
int32_t& instance_id() noexcept {
return m_instance_id_;
}
const int32_t& instance_id() const noexcept {
return m_instance_id_;
}
void instance_id(int32_t value) {
m_instance_id_ = value;
}
::dds::core::optional< std::string >& application_name() noexcept {
return m_application_name_;
}
const ::dds::core::optional< std::string >& application_name() const noexcept {
return m_application_name_;
}
void application_name(const ::dds::core::optional< std::string >& value) {
m_application_name_ = value;
}
void application_name(::dds::core::optional< std::string >&& value) {
m_application_name_ = std::move(value);
}
::RTI::Service::Admin::CommandActionKind& action() noexcept {
return m_action_;
}
const ::RTI::Service::Admin::CommandActionKind& action() const noexcept {
return m_action_;
}
void action(const ::RTI::Service::Admin::CommandActionKind& value) {
m_action_ = value;
}
void action(::RTI::Service::Admin::CommandActionKind&& value) {
m_action_ = std::move(value);
}
std::string& resource_identifier() noexcept {
return m_resource_identifier_;
}
const std::string& resource_identifier() const noexcept {
return m_resource_identifier_;
}
void resource_identifier(const std::string& value) {
m_resource_identifier_ = value;
}
void resource_identifier(std::string&& value) {
m_resource_identifier_ = std::move(value);
}
std::string& string_body() noexcept {
return m_string_body_;
}
const std::string& string_body() const noexcept {
return m_string_body_;
}
void string_body(const std::string& value) {
m_string_body_ = value;
}
void string_body(std::string&& value) {
m_string_body_ = std::move(value);
}
::RTI::Service::Admin::OctetBody& octet_body() noexcept {
return m_octet_body_;
}
const ::RTI::Service::Admin::OctetBody& octet_body() const noexcept {
return m_octet_body_;
}
void octet_body(const ::RTI::Service::Admin::OctetBody& value) {
m_octet_body_ = value;
}
void octet_body(::RTI::Service::Admin::OctetBody&& value) {
m_octet_body_ = std::move(value);
}
bool operator == (const CommandRequest& other_) const;
bool operator != (const CommandRequest& other_) const;
void swap(CommandRequest& other_) noexcept ;
private:
int32_t m_instance_id_;
::dds::core::optional< std::string > m_application_name_;
::RTI::Service::Admin::CommandActionKind m_action_;
std::string m_resource_identifier_;
std::string m_string_body_;
::RTI::Service::Admin::OctetBody m_octet_body_;
};
inline void swap(CommandRequest& a, CommandRequest& b) noexcept
{
a.swap(b);
}
NDDSUSERDllExport std::ostream& operator<<(std::ostream& o, const CommandRequest& sample);
class NDDSUSERDllExport CommandReply {
public:
CommandReply();
CommandReply(const ::RTI::Service::Admin::CommandReplyRetcode& m_retcode__,int32_t m_native_retcode__,const std::string& m_string_body__,const ::RTI::Service::Admin::OctetBody& m_octet_body__);
::RTI::Service::Admin::CommandReplyRetcode& retcode() noexcept {
return m_retcode_;
}
const ::RTI::Service::Admin::CommandReplyRetcode& retcode() const noexcept {
return m_retcode_;
}
void retcode(const ::RTI::Service::Admin::CommandReplyRetcode& value) {
m_retcode_ = value;
}
void retcode(::RTI::Service::Admin::CommandReplyRetcode&& value) {
m_retcode_ = std::move(value);
}
int32_t& native_retcode() noexcept {
return m_native_retcode_;
}
const int32_t& native_retcode() const noexcept {
return m_native_retcode_;
}
void native_retcode(int32_t value) {
m_native_retcode_ = value;
}
std::string& string_body() noexcept {
return m_string_body_;
}
const std::string& string_body() const noexcept {
return m_string_body_;
}
void string_body(const std::string& value) {
m_string_body_ = value;
}
void string_body(std::string&& value) {
m_string_body_ = std::move(value);
}
::RTI::Service::Admin::OctetBody& octet_body() noexcept {
return m_octet_body_;
}
const ::RTI::Service::Admin::OctetBody& octet_body() const noexcept {
return m_octet_body_;
}
void octet_body(const ::RTI::Service::Admin::OctetBody& value) {
m_octet_body_ = value;
}
void octet_body(::RTI::Service::Admin::OctetBody&& value) {
m_octet_body_ = std::move(value);
}
bool operator == (const CommandReply& other_) const;
bool operator != (const CommandReply& other_) const;
void swap(CommandReply& other_) noexcept ;
private:
::RTI::Service::Admin::CommandReplyRetcode m_retcode_;
int32_t m_native_retcode_;
std::string m_string_body_;
::RTI::Service::Admin::OctetBody m_octet_body_;
};
inline void swap(CommandReply& a, CommandReply& b) noexcept
{
a.swap(b);
}
NDDSUSERDllExport std::ostream& operator<<(std::ostream& o, const CommandReply& sample);
} // namespace Admin
} // namespace Service
} // namespace RTI
#ifdef NDDS_STANDALONE_TYPE
namespace rti {
namespace topic {
template <>
struct default_enumerator< ::RTI::Service::Admin::CommandActionKind>
{
static const ::RTI::Service::Admin::CommandActionKind value;
};
template <>
struct default_enumerator< ::RTI::Service::Admin::CommandReplyRetcode>
{
static const ::RTI::Service::Admin::CommandReplyRetcode value;
};
}
}
#else
namespace rti {
namespace flat {
namespace topic {
}
}
}
namespace dds {
namespace topic {
template<>
struct topic_type_name< ::RTI::Service::Admin::CommandRequest > {
NDDSUSERDllExport static std::string value() {
return "RTI::Service::Admin::CommandRequest";
}
};
template<>
struct is_topic_type< ::RTI::Service::Admin::CommandRequest > : public ::dds::core::true_type {};
template<>
struct topic_type_support< ::RTI::Service::Admin::CommandRequest > {
NDDSUSERDllExport
static void register_type(
::dds::domain::DomainParticipant& participant,
const std::string & type_name);
NDDSUSERDllExport
static std::vector<char>& to_cdr_buffer(
std::vector<char>& buffer,
const ::RTI::Service::Admin::CommandRequest& sample,
::dds::core::policy::DataRepresentationId representation
= ::dds::core::policy::DataRepresentation::auto_id());
NDDSUSERDllExport
static void from_cdr_buffer(::RTI::Service::Admin::CommandRequest& sample, const std::vector<char>& buffer);
NDDSUSERDllExport
static void reset_sample(::RTI::Service::Admin::CommandRequest& sample);
NDDSUSERDllExport
static void allocate_sample(::RTI::Service::Admin::CommandRequest& sample, int, int);
static const ::rti::topic::TypePluginKind::type type_plugin_kind =
::rti::topic::TypePluginKind::STL;
};
template<>
struct topic_type_name< ::RTI::Service::Admin::CommandReply > {
NDDSUSERDllExport static std::string value() {
return "RTI::Service::Admin::CommandReply";
}
};
template<>
struct is_topic_type< ::RTI::Service::Admin::CommandReply > : public ::dds::core::true_type {};
template<>
struct topic_type_support< ::RTI::Service::Admin::CommandReply > {
NDDSUSERDllExport
static void register_type(
::dds::domain::DomainParticipant& participant,
const std::string & type_name);
NDDSUSERDllExport
static std::vector<char>& to_cdr_buffer(
std::vector<char>& buffer,
const ::RTI::Service::Admin::CommandReply& sample,
::dds::core::policy::DataRepresentationId representation
= ::dds::core::policy::DataRepresentation::auto_id());
NDDSUSERDllExport
static void from_cdr_buffer(::RTI::Service::Admin::CommandReply& sample, const std::vector<char>& buffer);
NDDSUSERDllExport
static void reset_sample(::RTI::Service::Admin::CommandReply& sample);
NDDSUSERDllExport
static void allocate_sample(::RTI::Service::Admin::CommandReply& sample, int, int);
static const ::rti::topic::TypePluginKind::type type_plugin_kind =
::rti::topic::TypePluginKind::STL;
};
}
}
namespace rti {
namespace topic {
template<>
struct dynamic_type< ::RTI::Service::Admin::EntityName_AliasTag_t > {
typedef ::dds::core::xtypes::AliasType type;
NDDSUSERDllExport static const ::dds::core::xtypes::AliasType& get();
};
template<>
struct dynamic_type< ::RTI::Service::Admin::ResourceIdentifier_AliasTag_t > {
typedef ::dds::core::xtypes::AliasType type;
NDDSUSERDllExport static const ::dds::core::xtypes::AliasType& get();
};
template<>
struct dynamic_type< ::RTI::Service::Admin::StringBody_AliasTag_t > {
typedef ::dds::core::xtypes::AliasType type;
NDDSUSERDllExport static const ::dds::core::xtypes::AliasType& get();
};
template<>
struct dynamic_type< ::RTI::Service::Admin::OctetBody_AliasTag_t > {
typedef ::dds::core::xtypes::AliasType type;
NDDSUSERDllExport static const ::dds::core::xtypes::AliasType& get();
};
template <>
struct default_enumerator< ::RTI::Service::Admin::CommandActionKind>
{
static const ::RTI::Service::Admin::CommandActionKind value;
};
template<>
struct dynamic_type< ::RTI::Service::Admin::CommandActionKind > {
typedef ::dds::core::xtypes::EnumType type;
NDDSUSERDllExport static const ::dds::core::xtypes::EnumType& get();
};
template <>
struct extensibility< ::RTI::Service::Admin::CommandActionKind > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
template <>
struct default_enumerator< ::RTI::Service::Admin::CommandReplyRetcode>
{
static const ::RTI::Service::Admin::CommandReplyRetcode value;
};
template<>
struct dynamic_type< ::RTI::Service::Admin::CommandReplyRetcode > {
typedef ::dds::core::xtypes::EnumType type;
NDDSUSERDllExport static const ::dds::core::xtypes::EnumType& get();
};
template <>
struct extensibility< ::RTI::Service::Admin::CommandReplyRetcode > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
template<>
struct dynamic_type< ::RTI::Service::Admin::CommandRequest > {
typedef ::dds::core::xtypes::StructType type;
NDDSUSERDllExport static const ::dds::core::xtypes::StructType& get();
};
template <>
struct extensibility< ::RTI::Service::Admin::CommandRequest > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
template<>
struct dynamic_type< ::RTI::Service::Admin::CommandReply > {
typedef ::dds::core::xtypes::StructType type;
NDDSUSERDllExport static const ::dds::core::xtypes::StructType& get();
};
template <>
struct extensibility< ::RTI::Service::Admin::CommandReply > {
static const ::dds::core::xtypes::ExtensibilityKind::type kind =
::dds::core::xtypes::ExtensibilityKind::EXTENSIBLE; };
}
}
#endif // NDDS_STANDALONE_TYPE
#if defined(NDDS_USER_DLL_EXPORT_ROUTER_SERVICE_ADMIN) || defined(NDDS_USER_SYMBOL_EXPORT)
#undef NDDSUSERDllExport
#define NDDSUSERDllExport
#endif
#endif // ServiceAdmin_1325755560_hpp
@@ -0,0 +1,834 @@
/*
WARNING: THIS FILE IS AUTO-GENERATED. DO NOT MODIFY.
This file was generated from ServiceAdmin.idl
using RTI Code Generator (rtiddsgen) version 4.7.0.
The rtiddsgen tool is part of the RTI Connext DDS distribution.
For more information, type 'rtiddsgen -help' at a command shell
or consult the Code Generator User's Manual.
*/
#ifndef ServiceAdminPlugin_1325755560_h
#define ServiceAdminPlugin_1325755560_h
#include "ServiceAdmin.hpp"
struct RTICdrStream;
#ifndef pres_typePlugin_h
#include "pres/pres_typePlugin.h"
#endif
#include "ServiceCommonPlugin.hpp"
#if defined(NDDS_USER_DLL_EXPORT_ROUTER_SERVICE_ADMIN) && defined(RTI_WIN32)
#undef NDDSUSERDllExport
#define NDDSUSERDllExport __declspec(dllexport)
#endif
#if !defined(RTI_WIN32) && defined(NDDS_USER_SYMBOL_EXPORT)
#undef NDDSUSERDllExport
#define NDDSUSERDllExport __attribute__((visibility("default")))
#endif
namespace RTI {
namespace Service {
namespace Admin {
#define EntityNamePlugin_get_sample PRESTypePluginDefaultEndpointData_getSample
#define EntityNamePlugin_get_buffer PRESTypePluginDefaultEndpointData_getBuffer
#define EntityNamePlugin_return_buffer PRESTypePluginDefaultEndpointData_returnBuffer
#define EntityNamePlugin_create_sample PRESTypePluginDefaultEndpointData_createSample
#define EntityNamePlugin_destroy_sample PRESTypePluginDefaultEndpointData_deleteSample
/* --------------------------------------------------------------------------------------
Support functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern EntityName*
EntityNamePluginSupport_create_data_w_params(
const struct DDS_TypeAllocationParams_t * alloc_params);
NDDSUSERDllExport extern EntityName*
EntityNamePluginSupport_create_data_ex(RTIBool allocate_pointers);
NDDSUSERDllExport extern EntityName*
EntityNamePluginSupport_create_data(void);
NDDSUSERDllExport extern RTIBool
EntityNamePluginSupport_copy_data(
EntityName *out,
const EntityName *in);
NDDSUSERDllExport extern void
EntityNamePluginSupport_destroy_data_w_params(
EntityName *sample,
const struct DDS_TypeDeallocationParams_t * dealloc_params);
NDDSUSERDllExport extern void
EntityNamePluginSupport_destroy_data_ex(
EntityName *sample,RTIBool deallocate_pointers);
NDDSUSERDllExport extern void
EntityNamePluginSupport_destroy_data(
EntityName *sample);
NDDSUSERDllExport extern void
EntityNamePluginSupport_print_data(
const EntityName *sample,
const char *desc,
unsigned int indent);
/* ----------------------------------------------------------------------------
Callback functions:
* ---------------------------------------------------------------------------- */
NDDSUSERDllExport extern RTIBool
EntityNamePlugin_copy_sample(
PRESTypePluginEndpointData endpoint_data,
EntityName *out,
const EntityName *in);
/* ----------------------------------------------------------------------------
(De)Serialize functions:
* ------------------------------------------------------------------------- */
NDDSUSERDllExport extern unsigned int
EntityNamePlugin_get_serialized_sample_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
/* --------------------------------------------------------------------------------------
Key Management functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern PRESTypePluginKeyKind
EntityNamePlugin_get_key_kind(void);
NDDSUSERDllExport extern unsigned int
EntityNamePlugin_get_serialized_key_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
NDDSUSERDllExport extern unsigned int
EntityNamePlugin_get_serialized_key_max_size_for_keyhash(
PRESTypePluginEndpointData endpoint_data,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
#define ResourceIdentifierPlugin_get_sample PRESTypePluginDefaultEndpointData_getSample
#define ResourceIdentifierPlugin_get_buffer PRESTypePluginDefaultEndpointData_getBuffer
#define ResourceIdentifierPlugin_return_buffer PRESTypePluginDefaultEndpointData_returnBuffer
#define ResourceIdentifierPlugin_create_sample PRESTypePluginDefaultEndpointData_createSample
#define ResourceIdentifierPlugin_destroy_sample PRESTypePluginDefaultEndpointData_deleteSample
/* --------------------------------------------------------------------------------------
Support functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern ResourceIdentifier*
ResourceIdentifierPluginSupport_create_data_w_params(
const struct DDS_TypeAllocationParams_t * alloc_params);
NDDSUSERDllExport extern ResourceIdentifier*
ResourceIdentifierPluginSupport_create_data_ex(RTIBool allocate_pointers);
NDDSUSERDllExport extern ResourceIdentifier*
ResourceIdentifierPluginSupport_create_data(void);
NDDSUSERDllExport extern RTIBool
ResourceIdentifierPluginSupport_copy_data(
ResourceIdentifier *out,
const ResourceIdentifier *in);
NDDSUSERDllExport extern void
ResourceIdentifierPluginSupport_destroy_data_w_params(
ResourceIdentifier *sample,
const struct DDS_TypeDeallocationParams_t * dealloc_params);
NDDSUSERDllExport extern void
ResourceIdentifierPluginSupport_destroy_data_ex(
ResourceIdentifier *sample,RTIBool deallocate_pointers);
NDDSUSERDllExport extern void
ResourceIdentifierPluginSupport_destroy_data(
ResourceIdentifier *sample);
NDDSUSERDllExport extern void
ResourceIdentifierPluginSupport_print_data(
const ResourceIdentifier *sample,
const char *desc,
unsigned int indent);
/* ----------------------------------------------------------------------------
Callback functions:
* ---------------------------------------------------------------------------- */
NDDSUSERDllExport extern RTIBool
ResourceIdentifierPlugin_copy_sample(
PRESTypePluginEndpointData endpoint_data,
ResourceIdentifier *out,
const ResourceIdentifier *in);
/* ----------------------------------------------------------------------------
(De)Serialize functions:
* ------------------------------------------------------------------------- */
NDDSUSERDllExport extern unsigned int
ResourceIdentifierPlugin_get_serialized_sample_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
/* --------------------------------------------------------------------------------------
Key Management functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern PRESTypePluginKeyKind
ResourceIdentifierPlugin_get_key_kind(void);
NDDSUSERDllExport extern unsigned int
ResourceIdentifierPlugin_get_serialized_key_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
NDDSUSERDllExport extern unsigned int
ResourceIdentifierPlugin_get_serialized_key_max_size_for_keyhash(
PRESTypePluginEndpointData endpoint_data,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
#define StringBodyPlugin_get_sample PRESTypePluginDefaultEndpointData_getSample
#define StringBodyPlugin_get_buffer PRESTypePluginDefaultEndpointData_getBuffer
#define StringBodyPlugin_return_buffer PRESTypePluginDefaultEndpointData_returnBuffer
#define StringBodyPlugin_create_sample PRESTypePluginDefaultEndpointData_createSample
#define StringBodyPlugin_destroy_sample PRESTypePluginDefaultEndpointData_deleteSample
/* --------------------------------------------------------------------------------------
Support functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern StringBody*
StringBodyPluginSupport_create_data_w_params(
const struct DDS_TypeAllocationParams_t * alloc_params);
NDDSUSERDllExport extern StringBody*
StringBodyPluginSupport_create_data_ex(RTIBool allocate_pointers);
NDDSUSERDllExport extern StringBody*
StringBodyPluginSupport_create_data(void);
NDDSUSERDllExport extern RTIBool
StringBodyPluginSupport_copy_data(
StringBody *out,
const StringBody *in);
NDDSUSERDllExport extern void
StringBodyPluginSupport_destroy_data_w_params(
StringBody *sample,
const struct DDS_TypeDeallocationParams_t * dealloc_params);
NDDSUSERDllExport extern void
StringBodyPluginSupport_destroy_data_ex(
StringBody *sample,RTIBool deallocate_pointers);
NDDSUSERDllExport extern void
StringBodyPluginSupport_destroy_data(
StringBody *sample);
NDDSUSERDllExport extern void
StringBodyPluginSupport_print_data(
const StringBody *sample,
const char *desc,
unsigned int indent);
/* ----------------------------------------------------------------------------
Callback functions:
* ---------------------------------------------------------------------------- */
NDDSUSERDllExport extern RTIBool
StringBodyPlugin_copy_sample(
PRESTypePluginEndpointData endpoint_data,
StringBody *out,
const StringBody *in);
/* ----------------------------------------------------------------------------
(De)Serialize functions:
* ------------------------------------------------------------------------- */
NDDSUSERDllExport extern unsigned int
StringBodyPlugin_get_serialized_sample_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
/* --------------------------------------------------------------------------------------
Key Management functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern PRESTypePluginKeyKind
StringBodyPlugin_get_key_kind(void);
NDDSUSERDllExport extern unsigned int
StringBodyPlugin_get_serialized_key_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
NDDSUSERDllExport extern unsigned int
StringBodyPlugin_get_serialized_key_max_size_for_keyhash(
PRESTypePluginEndpointData endpoint_data,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
#define OctetBodyPlugin_get_sample PRESTypePluginDefaultEndpointData_getSample
#define OctetBodyPlugin_get_buffer PRESTypePluginDefaultEndpointData_getBuffer
#define OctetBodyPlugin_return_buffer PRESTypePluginDefaultEndpointData_returnBuffer
#define OctetBodyPlugin_create_sample PRESTypePluginDefaultEndpointData_createSample
#define OctetBodyPlugin_destroy_sample PRESTypePluginDefaultEndpointData_deleteSample
/* --------------------------------------------------------------------------------------
Support functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern OctetBody*
OctetBodyPluginSupport_create_data_w_params(
const struct DDS_TypeAllocationParams_t * alloc_params);
NDDSUSERDllExport extern OctetBody*
OctetBodyPluginSupport_create_data_ex(RTIBool allocate_pointers);
NDDSUSERDllExport extern OctetBody*
OctetBodyPluginSupport_create_data(void);
NDDSUSERDllExport extern RTIBool
OctetBodyPluginSupport_copy_data(
OctetBody *out,
const OctetBody *in);
NDDSUSERDllExport extern void
OctetBodyPluginSupport_destroy_data_w_params(
OctetBody *sample,
const struct DDS_TypeDeallocationParams_t * dealloc_params);
NDDSUSERDllExport extern void
OctetBodyPluginSupport_destroy_data_ex(
OctetBody *sample,RTIBool deallocate_pointers);
NDDSUSERDllExport extern void
OctetBodyPluginSupport_destroy_data(
OctetBody *sample);
NDDSUSERDllExport extern void
OctetBodyPluginSupport_print_data(
const OctetBody *sample,
const char *desc,
unsigned int indent);
/* ----------------------------------------------------------------------------
Callback functions:
* ---------------------------------------------------------------------------- */
NDDSUSERDllExport extern RTIBool
OctetBodyPlugin_copy_sample(
PRESTypePluginEndpointData endpoint_data,
OctetBody *out,
const OctetBody *in);
/* ----------------------------------------------------------------------------
(De)Serialize functions:
* ------------------------------------------------------------------------- */
NDDSUSERDllExport extern unsigned int
OctetBodyPlugin_get_serialized_sample_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
/* --------------------------------------------------------------------------------------
Key Management functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern PRESTypePluginKeyKind
OctetBodyPlugin_get_key_kind(void);
NDDSUSERDllExport extern unsigned int
OctetBodyPlugin_get_serialized_key_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
NDDSUSERDllExport extern unsigned int
OctetBodyPlugin_get_serialized_key_max_size_for_keyhash(
PRESTypePluginEndpointData endpoint_data,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
/* ----------------------------------------------------------------------------
(De)Serialize functions:
* ------------------------------------------------------------------------- */
NDDSUSERDllExport extern unsigned int
CommandActionKindPlugin_get_serialized_sample_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
/* --------------------------------------------------------------------------------------
Key Management functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern unsigned int
CommandActionKindPlugin_get_serialized_key_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
NDDSUSERDllExport extern unsigned int
CommandActionKindPlugin_get_serialized_key_max_size_for_keyhash(
PRESTypePluginEndpointData endpoint_data,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
/* ----------------------------------------------------------------------------
Support functions:
* ---------------------------------------------------------------------------- */
NDDSUSERDllExport extern void
CommandActionKindPluginSupport_print_data(
const CommandActionKind *sample,
const char *desc,
unsigned int indent_level);
/* ----------------------------------------------------------------------------
(De)Serialize functions:
* ------------------------------------------------------------------------- */
NDDSUSERDllExport extern unsigned int
CommandReplyRetcodePlugin_get_serialized_sample_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
/* --------------------------------------------------------------------------------------
Key Management functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern unsigned int
CommandReplyRetcodePlugin_get_serialized_key_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
NDDSUSERDllExport extern unsigned int
CommandReplyRetcodePlugin_get_serialized_key_max_size_for_keyhash(
PRESTypePluginEndpointData endpoint_data,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
/* ----------------------------------------------------------------------------
Support functions:
* ---------------------------------------------------------------------------- */
NDDSUSERDllExport extern void
CommandReplyRetcodePluginSupport_print_data(
const CommandReplyRetcode *sample,
const char *desc,
unsigned int indent_level);
/* The type used to store keys for instances of type struct
* AnotherSimple.
*
* By default, this type is struct CommandRequest
* itself. However, if for some reason this choice is not practical for your
* system (e.g. if sizeof(struct CommandRequest)
* is very large), you may redefine this typedef in terms of another type of
* your choosing. HOWEVER, if you define the KeyHolder type to be something
* other than struct AnotherSimple, the
* following restriction applies: the key of struct
* CommandRequest must consist of a
* single field of your redefined KeyHolder type and that field must be the
* first field in struct CommandRequest.
*/
typedef class CommandRequest CommandRequestKeyHolder;
#define CommandRequestPlugin_get_sample PRESTypePluginDefaultEndpointData_getSample
#define CommandRequestPlugin_get_buffer PRESTypePluginDefaultEndpointData_getBuffer
#define CommandRequestPlugin_return_buffer PRESTypePluginDefaultEndpointData_returnBuffer
#define CommandRequestPlugin_get_key PRESTypePluginDefaultEndpointData_getKey
#define CommandRequestPlugin_return_key PRESTypePluginDefaultEndpointData_returnKey
#define CommandRequestPlugin_create_sample PRESTypePluginDefaultEndpointData_createSample
#define CommandRequestPlugin_destroy_sample PRESTypePluginDefaultEndpointData_deleteSample
/* --------------------------------------------------------------------------------------
Support functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern CommandRequest*
CommandRequestPluginSupport_create_data_w_params(
const struct DDS_TypeAllocationParams_t * alloc_params);
NDDSUSERDllExport extern CommandRequest*
CommandRequestPluginSupport_create_data_ex(RTIBool allocate_pointers);
NDDSUSERDllExport extern CommandRequest*
CommandRequestPluginSupport_create_data(void);
NDDSUSERDllExport extern RTIBool
CommandRequestPluginSupport_copy_data(
CommandRequest *out,
const CommandRequest *in);
NDDSUSERDllExport extern void
CommandRequestPluginSupport_destroy_data_w_params(
CommandRequest *sample,
const struct DDS_TypeDeallocationParams_t * dealloc_params);
NDDSUSERDllExport extern void
CommandRequestPluginSupport_destroy_data_ex(
CommandRequest *sample,RTIBool deallocate_pointers);
NDDSUSERDllExport extern void
CommandRequestPluginSupport_destroy_data(
CommandRequest *sample);
NDDSUSERDllExport extern void
CommandRequestPluginSupport_print_data(
const CommandRequest *sample,
const char *desc,
unsigned int indent);
NDDSUSERDllExport extern CommandRequest*
CommandRequestPluginSupport_create_key_ex(RTIBool allocate_pointers);
NDDSUSERDllExport extern CommandRequest*
CommandRequestPluginSupport_create_key(void);
NDDSUSERDllExport extern void
CommandRequestPluginSupport_destroy_key_ex(
CommandRequestKeyHolder *key,RTIBool deallocate_pointers);
NDDSUSERDllExport extern void
CommandRequestPluginSupport_destroy_key(
CommandRequestKeyHolder *key);
/* ----------------------------------------------------------------------------
Callback functions:
* ---------------------------------------------------------------------------- */
NDDSUSERDllExport extern PRESTypePluginParticipantData
CommandRequestPlugin_on_participant_attached(
void *registration_data,
const struct PRESTypePluginParticipantInfo *participant_info,
RTIBool top_level_registration,
void *container_plugin_context,
RTICdrTypeCode *typeCode);
NDDSUSERDllExport extern void
CommandRequestPlugin_on_participant_detached(
PRESTypePluginParticipantData participant_data);
NDDSUSERDllExport extern PRESTypePluginEndpointData
CommandRequestPlugin_on_endpoint_attached(
PRESTypePluginParticipantData participant_data,
const struct PRESTypePluginEndpointInfo *endpoint_info,
RTIBool top_level_registration,
void *container_plugin_context);
NDDSUSERDllExport extern void
CommandRequestPlugin_on_endpoint_detached(
PRESTypePluginEndpointData endpoint_data);
NDDSUSERDllExport extern void
CommandRequestPlugin_return_sample(
PRESTypePluginEndpointData endpoint_data,
CommandRequest *sample,
void *handle);
NDDSUSERDllExport extern RTIBool
CommandRequestPlugin_copy_sample(
PRESTypePluginEndpointData endpoint_data,
CommandRequest *out,
const CommandRequest *in);
/* ----------------------------------------------------------------------------
(De)Serialize functions:
* ------------------------------------------------------------------------- */
NDDSUSERDllExport extern RTIBool
CommandRequestPlugin_serialize_to_cdr_buffer(
char * buffer,
unsigned int * length,
const CommandRequest *sample,
::dds::core::policy::DataRepresentationId representation
= ::dds::core::policy::DataRepresentation::xcdr());
NDDSUSERDllExport extern RTIBool
CommandRequestPlugin_deserialize(
PRESTypePluginEndpointData endpoint_data,
CommandRequest **sample,
RTIBool * drop_sample,
struct RTICdrStream *cdrStream,
RTIBool deserialize_encapsulation,
RTIBool deserialize_sample,
void *endpoint_plugin_qos);
NDDSUSERDllExport extern RTIBool
CommandRequestPlugin_deserialize_from_cdr_buffer(
CommandRequest *sample,
const char * buffer,
unsigned int length);
NDDSUSERDllExport extern unsigned int
CommandRequestPlugin_get_serialized_sample_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
/* --------------------------------------------------------------------------------------
Key Management functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern PRESTypePluginKeyKind
CommandRequestPlugin_get_key_kind(void);
NDDSUSERDllExport extern unsigned int
CommandRequestPlugin_get_serialized_key_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
NDDSUSERDllExport extern unsigned int
CommandRequestPlugin_get_serialized_key_max_size_for_keyhash(
PRESTypePluginEndpointData endpoint_data,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
NDDSUSERDllExport extern RTIBool
CommandRequestPlugin_deserialize_key(
PRESTypePluginEndpointData endpoint_data,
CommandRequest ** sample,
RTIBool * drop_sample,
struct RTICdrStream *cdrStream,
RTIBool deserialize_encapsulation,
RTIBool deserialize_key,
void *endpoint_plugin_qos);
NDDSUSERDllExport extern RTIBool
CommandRequestPlugin_instance_to_key(
PRESTypePluginEndpointData endpoint_data,
CommandRequestKeyHolder *key,
const CommandRequest *instance);
NDDSUSERDllExport extern RTIBool
CommandRequestPlugin_key_to_instance(
PRESTypePluginEndpointData endpoint_data,
CommandRequest *instance,
const CommandRequestKeyHolder *key);
NDDSUSERDllExport extern RTIBool
CommandRequestPlugin_serialized_sample_to_keyhash(
PRESTypePluginEndpointData endpoint_data,
struct RTICdrStream *cdrStream,
DDS_KeyHash_t *keyhash,
RTIBool deserialize_encapsulation,
void *endpoint_plugin_qos);
/* Plugin Functions */
NDDSUSERDllExport extern struct PRESTypePlugin*
CommandRequestPlugin_new(void);
NDDSUSERDllExport extern void
CommandRequestPlugin_delete(struct PRESTypePlugin *);
#define CommandReplyPlugin_get_sample PRESTypePluginDefaultEndpointData_getSample
#define CommandReplyPlugin_get_buffer PRESTypePluginDefaultEndpointData_getBuffer
#define CommandReplyPlugin_return_buffer PRESTypePluginDefaultEndpointData_returnBuffer
#define CommandReplyPlugin_create_sample PRESTypePluginDefaultEndpointData_createSample
#define CommandReplyPlugin_destroy_sample PRESTypePluginDefaultEndpointData_deleteSample
/* --------------------------------------------------------------------------------------
Support functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern CommandReply*
CommandReplyPluginSupport_create_data_w_params(
const struct DDS_TypeAllocationParams_t * alloc_params);
NDDSUSERDllExport extern CommandReply*
CommandReplyPluginSupport_create_data_ex(RTIBool allocate_pointers);
NDDSUSERDllExport extern CommandReply*
CommandReplyPluginSupport_create_data(void);
NDDSUSERDllExport extern RTIBool
CommandReplyPluginSupport_copy_data(
CommandReply *out,
const CommandReply *in);
NDDSUSERDllExport extern void
CommandReplyPluginSupport_destroy_data_w_params(
CommandReply *sample,
const struct DDS_TypeDeallocationParams_t * dealloc_params);
NDDSUSERDllExport extern void
CommandReplyPluginSupport_destroy_data_ex(
CommandReply *sample,RTIBool deallocate_pointers);
NDDSUSERDllExport extern void
CommandReplyPluginSupport_destroy_data(
CommandReply *sample);
NDDSUSERDllExport extern void
CommandReplyPluginSupport_print_data(
const CommandReply *sample,
const char *desc,
unsigned int indent);
/* ----------------------------------------------------------------------------
Callback functions:
* ---------------------------------------------------------------------------- */
NDDSUSERDllExport extern PRESTypePluginParticipantData
CommandReplyPlugin_on_participant_attached(
void *registration_data,
const struct PRESTypePluginParticipantInfo *participant_info,
RTIBool top_level_registration,
void *container_plugin_context,
RTICdrTypeCode *typeCode);
NDDSUSERDllExport extern void
CommandReplyPlugin_on_participant_detached(
PRESTypePluginParticipantData participant_data);
NDDSUSERDllExport extern PRESTypePluginEndpointData
CommandReplyPlugin_on_endpoint_attached(
PRESTypePluginParticipantData participant_data,
const struct PRESTypePluginEndpointInfo *endpoint_info,
RTIBool top_level_registration,
void *container_plugin_context);
NDDSUSERDllExport extern void
CommandReplyPlugin_on_endpoint_detached(
PRESTypePluginEndpointData endpoint_data);
NDDSUSERDllExport extern void
CommandReplyPlugin_return_sample(
PRESTypePluginEndpointData endpoint_data,
CommandReply *sample,
void *handle);
NDDSUSERDllExport extern RTIBool
CommandReplyPlugin_copy_sample(
PRESTypePluginEndpointData endpoint_data,
CommandReply *out,
const CommandReply *in);
/* ----------------------------------------------------------------------------
(De)Serialize functions:
* ------------------------------------------------------------------------- */
NDDSUSERDllExport extern RTIBool
CommandReplyPlugin_serialize_to_cdr_buffer(
char * buffer,
unsigned int * length,
const CommandReply *sample,
::dds::core::policy::DataRepresentationId representation
= ::dds::core::policy::DataRepresentation::xcdr());
NDDSUSERDllExport extern RTIBool
CommandReplyPlugin_deserialize(
PRESTypePluginEndpointData endpoint_data,
CommandReply **sample,
RTIBool * drop_sample,
struct RTICdrStream *cdrStream,
RTIBool deserialize_encapsulation,
RTIBool deserialize_sample,
void *endpoint_plugin_qos);
NDDSUSERDllExport extern RTIBool
CommandReplyPlugin_deserialize_from_cdr_buffer(
CommandReply *sample,
const char * buffer,
unsigned int length);
NDDSUSERDllExport extern unsigned int
CommandReplyPlugin_get_serialized_sample_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
/* --------------------------------------------------------------------------------------
Key Management functions:
* -------------------------------------------------------------------------------------- */
NDDSUSERDllExport extern PRESTypePluginKeyKind
CommandReplyPlugin_get_key_kind(void);
NDDSUSERDllExport extern unsigned int
CommandReplyPlugin_get_serialized_key_max_size(
PRESTypePluginEndpointData endpoint_data,
RTIBool include_encapsulation,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
NDDSUSERDllExport extern unsigned int
CommandReplyPlugin_get_serialized_key_max_size_for_keyhash(
PRESTypePluginEndpointData endpoint_data,
RTIEncapsulationId encapsulation_id,
unsigned int current_alignment);
NDDSUSERDllExport extern RTIBool
CommandReplyPlugin_deserialize_key(
PRESTypePluginEndpointData endpoint_data,
CommandReply ** sample,
RTIBool * drop_sample,
struct RTICdrStream *cdrStream,
RTIBool deserialize_encapsulation,
RTIBool deserialize_key,
void *endpoint_plugin_qos);
/* Plugin Functions */
NDDSUSERDllExport extern struct PRESTypePlugin*
CommandReplyPlugin_new(void);
NDDSUSERDllExport extern void
CommandReplyPlugin_delete(struct PRESTypePlugin *);
} /* namespace Admin */
} /* namespace Service */
} /* namespace RTI */
#if defined(NDDS_USER_DLL_EXPORT_ROUTER_SERVICE_ADMIN) || defined(NDDS_USER_SYMBOL_EXPORT)
#undef NDDSUSERDllExport
#define NDDSUSERDllExport
#endif
#endif /* ServiceAdminPlugin_1325755560_h */
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,6 @@
#ifndef RTI_MONITORING_COLLECTOR_SERVICE_HPP_
#define RTI_MONITORING_COLLECTOR_SERVICE_HPP_
#include <rti/monitoring/collector/Service.hpp>
#endif // RTI_MONITORING_COLLECTOR_SERVICE_HPP_
@@ -0,0 +1,40 @@
/*
* (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 monitoringcollector_dll_h
#define monitoringcollector_dll_h
#if defined(RTI_WIN32) || defined(RTI_WINCE) || defined(RTI_INTIME)
#if defined(RTI_collectorservice_DLL_EXPORT)
#define COLLECTORSERVICEDllExport __declspec( dllexport )
#else
#define COLLECTORSERVICEDllExport
#endif /* RTI_collectorservice_DLL_EXPORT */
#if defined(RTI_collectorservice_DLL_VARIABLE)
#if defined(RTI_collectorservice_DLL_EXPORT)
#define COLLECTORSERVICEDllVariable __declspec( dllexport )
#else
#define COLLECTORSERVICEDllVariable __declspec( dllimport )
#endif /* RTI_collectorservice_DLL_EXPORT */
#else
#define COLLECTORSERVICEDllVariable
#endif /* RTI_collectorservice_DLL_VARIABLE */
#elif defined(RTI_VISIBILITY_HIDDEN)
#define COLLECTORSERVICEDllExport __attribute__((visibility("default")))
#define COLLECTORSERVICEDllVariable __attribute__((visibility("default")))
#else
#define COLLECTORSERVICEDllExport
#define COLLECTORSERVICEDllVariable
#endif /* RTI_WIN32 || RTI_WINCE || RTI_INTIME */
#endif /* monitoringcollector_dll_h */
@@ -0,0 +1,85 @@
/*
* (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 monitoringcollector_log_h
#define monitoringcollector_log_h
#ifndef monitoringcollector_dll_h
#include <rti/monitoring/collector/Dll.h>
#endif
#ifndef log_common_h
#include "log/log_common.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*i \ingroup COLLECTORSERVICELogModule
Submodule ID for Monitoring Collector Configuration submodule
*/
#define SUBMODULE_COLLECTORSERVICE_CONFIG (0x1000)
/*i \ingroup COLLECTORSERVICELogModule
Submodule ID for Monitoring Collector service submodule
*/
#define SUBMODULE_COLLECTORSERVICE_SERVICE (0x2000)
/*i \ingroup COLLECTORSERVICELogModule
Submodule ID for Monitoring Collector Adapters submodule
*/
#define SUBMODULE_COLLECTORSERVICE_ADAPTERS (0x3000)
/*i \ingroup COLLECTORSERVICELogModule
Submodule ID for Monitoring Collector wrapper application submodule
*/
#define SUBMODULE_COLLECTORSERVICE_APP (0x4000)
/*i \ingroup COLLECTORSERVICELogModule
Submodule ID for Monitoring Collector processor submodule
*/
#define SUBMODULE_COLLECTORSERVICE_PROCESSORS (0x5000)
/*i \ingroup COLLECTORSERVICELogModule
Mask for turning on logging for only the Monitoring Collector Configuration submodule
*/
#define COLLECTORSERVICE_SUBMODULE_MASK_CONFIG (0x0001)
/*i \ingroup COLLECTORSERVICELogModule
Mask for turning on logging for only the Monitoring Collector Configuration submodule
*/
#define COLLECTORSERVICE_SUBMODULE_MASK_SERVICE (0x0002)
/*i \ingroup COLLECTORSERVICELogModule
Mask for turning on logging for only the Monitoring Collector Adapters submodule
*/
#define COLLECTORSERVICE_SUBMODULE_MASK_ADAPTERS (0x0004)
/*i \ingroup COLLECTORSERVICELogModule
Mask for turning on logging for only the Monitoring Collector Application submodule
*/
#define COLLECTORSERVICE_SUBMODULE_MASK_APP (0x0008)
/*i \ingroup COLLECTORSERVICELogModule
Mask for turning on logging for only the Monitoring Collector Application submodule
*/
#define COLLECTORSERVICE_SUBMODULE_MASK_PROCESSORS (0x000A)
/*i \ingroup COLLECTORSERVICELogModule
Mask for turning on logging for all submodules
*/
#define COLLECTORSERVICE_SUBMODULE_MASK_ALL RTI_LOG_SUBMODULE_MASK_ALL
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* monitoringcollector_log_h */
@@ -0,0 +1,172 @@
/*
* (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_MONITORING_COLLECTOR_LOGGER_HPP_
#define RTI_MONITORING_COLLECTOR_LOGGER_HPP_
#include <rti/monitoring/collector/Dll.h>
#include <dds/core/Reference.hpp>
#include <rti/config/Logger.hpp>
namespace rti { namespace monitoring { namespace collector {
/** \ingroup RTI_MonitoringCollectorServiceLibModule
*
* @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();
/**
* @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);
/**
* @brief overload of error(const std::string& msg)
*/
void error(const char *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::monitoring::collector::Logger::error
*
*/
void warn(const std::string& msg);
/**
* @brief overload of warn(const std::string& msg)
*/
void warn(const char *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::monitoring::collector::Logger::error
*
*/
void local(const std::string& msg);
/**
* @brief overload of local(const std::string& msg)
*/
void local(const char *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::monitoring::collector::Logger::error
*
*/
void remote(const std::string& msg);
/**
* @brief overload of remote(const std::string& msg)
*/
void remote(const char *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::monitoring::collector::Logger::error
*
*/
void debug(const std::string& msg);
/**
* @brief overload of debug(const std::string& msg)
*/
void debug(const char *msg);
/**
* @brief Sets the verbosity for the log messages generated at the
* @product level.
*
* @param[in] verbosity
* The verbosity of the service logs
*/
void service_verbosity(rti::config::Verbosity verbosity);
/**
* @brief Getter for the same attribute
*
* @see verbosity(rti::config::Verbosity)
*/
rti::config::Verbosity service_verbosity();
/**
* @deprecated
* @see service_verbosity
*/
void verbosity(rti::config::Verbosity verbosity);
/**
* @deprecated
* @see service_verbosity
*/
rti::config::Verbosity verbosity();
virtual ~Logger();
private:
void message(const rti::config::LogLevel& level, const char* msg);
Logger();
// Disable copy
Logger(const Logger&);
Logger& operator=(const Logger&);
};
} } }
#endif // RTI_MONITORING_COLLECTOR_LOGGER_HPP_
@@ -0,0 +1,13 @@
#ifndef RTI_COLLECTOR_PROPERTYSET_HPP
#define RTI_COLLECTOR_PROPERTYSET_HPP
#include <rti/routing/PropertySet.hpp>
namespace rti { namespace monitoring { namespace collector {
typedef rti::routing::PropertySet PropertySet;
} } }
#endif /* RTI_COLLECTOR_PROPERTYSET_HPP */
@@ -0,0 +1,209 @@
/*
* (c) Copyright, Real-Time Innovations, 2022.
* 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_COLLECTOR_SERVICE_HPP_
#define RTI_COLLECTOR_SERVICE_HPP_
#include <dds/core/Reference.hpp>
#include <rti/config/Logger.hpp>
#include <rti/monitoring/collector/Logger.hpp>
#include <rti/monitoring/collector/ServiceProperty.hpp>
#include <rti/monitoring/collector/detail/CollectorServiceImpl.hpp>
namespace rti { namespace monitoring { namespace collector {
/*e \defgroup RTI_CollectorServiceLibModule RTI Monitoring Collector API
*
* @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::monitoring::collector::Service service(
* rti::monitoring::collector::ServiceProperty()
* .cfg_file("MyCollectorService.xml")
* .service_name("MyCollectorService"));
* ...
*
* service.start();
*
* while(keep_running) {
* sleep();
* ...
* }
*
* return 0;
* }
*
* \endcode
*
* Instead of a file, you can use XML strings to configure @product.
* See ServiceProperty for more information.
* <p>
* To build your application you need to link with the @product native library
* in <b> &lt;@ndds home&gt;/bin/&lt;architecture&gt;/ </b>.
*
* ### Development Requirements
*
* | | Linux Systems | Windows Systems |
* | --------------: | :----------------: | :-------------: |
* | Shared Libraries| libnddscpp2.so | nddscpp2.dll |
* | Shared Libraries| librtiroutingservice.so | rtiroutingservice.dll |
* | ^ | librtirsinfrastructure.so | rtirsinfrastructure.dll |
* | ^ | librticollectorservice.so | rticollectorservice.dll |
* | ^ | librtidlc.so | rtidlc.dll |
* | ^ | libnddsmetp.so | nddsmetp.dll |
* | ^ | libnddsc.so | nddsc.dll |
* | ^ | librtixml2.so | rtixml2.dll |
* | ^ | libnddscore.so | nddscore.dll |
* | Headers | rti/monitoring/collector/RecordingService.hpp ||
*
*/
/** \ingroup RTI_CollectorServiceLibModule
*
* @brief The @product.
*
*/
class Service : public dds::core::Reference<ServiceImpl> {
public:
typedef dds::core::Reference<ServiceImpl> Base;
OMG_DDS_REF_TYPE_NOTYPENAME(
Service,
dds::core::Reference,
ServiceImpl);
/**
* @brief Creates a @product instance
*
* @param[in] property
* 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 ServiceImpl(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 implmentation
* struct FlagShutdownHook {
* public:
* FlagShutdownHook(bool& the_flag) : flag(the_flag)
* {
* flag = false;
* }
* void operator()() {
* the_flag = true;
* }
*
* bool& flag;
* };
*
* // Instantiate service with hook
* bool my_flag;
* rti::monitoring::collector::Service collector_service_instance(
* property,
* FlagShutdownHook(my_flag));
* ...
*
*
* \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>
explicit Service(
const ServiceProperty& property,
const HookFunc& shutdown_hook)
: Base(new ServiceImpl(
property,
new rti::routing::detail::ShutdownHookForwarder<HookFunc>(
shutdown_hook)))
{
this->delegate()->remember_reference(this->delegate());
}
explicit Service(Base::DELEGATE_REF_T reference) : Base(reference)
{
if (this->delegate()) {
this->delegate()->remember_reference(this->delegate());
}
}
virtual ~Service() = default;
/**
* @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();
}
};
typedef Service CollectorService;
} } }
#endif // RTI_COLLECTOR_SERVICE_HPP_
@@ -0,0 +1,316 @@
/*
* (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 HPP_SERVICE_SERVICEPROPERTY_HPP_
#define HPP_SERVICE_SERVICEPROPERTY_HPP_
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstdint>
#include <map>
#include "osapi/osapi_type.h"
#include "routingservice/routingservice_infrastructure.h"
#include "routingservice/routingservice_service.h"
#include <dds/core/SafeEnumeration.hpp>
#include <rti/monitoring/collector/PropertySet.hpp>
namespace rti { namespace monitoring { namespace collector {
typedef rti::routing::PropertySet PropertySet;
/** \ingroup RTI_MonitoringCollectorLibModule
*
* @brief Configuration for a @product object.
*
*/
class ServiceProperty {
public:
/**
* @brief Creates a property object with default settings.
*/
ServiceProperty() :
cfg_file_(""),
service_name_(""),
application_name_(""),
domain_id_base_(0),
enable_service_monitoring_(false),
service_monitoring_domain_id_(0),
enforce_xsd_validation_(true),
ignore_default_files_(false)
{
}
static ServiceProperty default_property()
{
ServiceProperty default_property;
default_property.service_name("default");
return default_property;
}
/**
* @brief Getter (see setter with the same name)
*/
const std::string& cfg_file() const
{
return cfg_file_;
}
/**
* @brief Path to an @product configuration file
*
* @default empty string.
*/
ServiceProperty& cfg_file(const std::string & cfg_file)
{
cfg_file_ = cfg_file;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
const std::string & service_name() const
{
return service_name_;
}
/**
* @brief The name of the @product configuration to run.
*
* This is the name used to find the 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 & service_name)
{
service_name_ = service_name;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
const std::string & application_name() const
{
return 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 & application_name)
{
application_name_ = application_name;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
int32_t domain_id_base() const
{
return domain_id_base_;
}
/**
* @brief Getter (see setter with the same name)
*/
bool enforce_xsd_validation() const
{
return enforce_xsd_validation_;
}
/**
* @brief Controls whether the service applies XSD validation to the loaded
* configuration.
*
* @default true
*/
ServiceProperty& enforce_xsd_validation(bool enforce)
{
enforce_xsd_validation_ = enforce;
return *this;
}
/**
* @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(int32_t domain_id)
{
domain_id_base_ = domain_id;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool enable_service_monitoring() const
{
return enable_service_monitoring_;
}
/**
* @brief Set it to true to enable remote monitoring
* or false to disable it.
*
* @default false
*/
ServiceProperty& enable_service_monitoring(bool enable_monitoring)
{
enable_service_monitoring_ = enable_monitoring;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
int32_t service_monitoring_domain_id() const
{
return service_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& service_monitoring_domain_id(int32_t domain_id)
{
service_monitoring_domain_id_ = domain_id;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool ignore_default_files() const
{
return ignore_default_files_;
}
/**
* @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& ignore_default_files(bool ignore)
{
ignore_default_files_ = ignore;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
const std::string& license_file() const
{
return license_file_;
}
/**
* @brief Path to an RTI Connext license file. This parameter is only used
* if your installation requires a license file.
*
* @default empty string.
*/
ServiceProperty& license_file(const std::string& license_file)
{
license_file_ = license_file;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
const PropertySet& user_environment() const
{
return user_env_;
}
/**
* @brief Non-const getter for modification that can be used to add
* elements individually. (see setter with the same name)
*/
PropertySet& user_environment()
{
return user_env_;
}
/**
* @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 PropertySet& user_environment)
{
user_env_ = user_environment;
return *this;
}
private:
std::string cfg_file_;
std::string service_name_;
std::string application_name_;
int32_t domain_id_base_;
bool enable_service_monitoring_;
int32_t service_monitoring_domain_id_;
bool enforce_xsd_validation_;
bool ignore_default_files_;
std::string license_file_;
PropertySet user_env_;
};
} } } /* namespace rti::monitoring::collector */
#endif /* HPP_SERVICE_SERVICEPROPERTY_HPP_ */
@@ -0,0 +1,63 @@
/*
* (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_MONITORING_COLLECTOR_SERVICE_IMPL_HPP_
#define RTI_MONITORING_COLLECTOR_SERVICE_IMPL_HPP_
#include <rti/monitoring/collector/Dll.h>
#include <dds/core/refmacros.hpp>
#include <rti/core/detail/SelfReference.hpp>
#include <rti/monitoring/collector/ServiceProperty.hpp>
#include <rti/routing/detail/ShutdownHookForwarder.hpp>
namespace rti { namespace monitoring { namespace collector {
namespace service {
class Service;
}
namespace detail {
typedef rti::routing::detail::AbstractShutdownHookForwarder
AbstractShutdownHookForwarder;
}
class Application;
// class COLLECTORSERVICEDllExport ServiceImpl
class COLLECTORSERVICEDllExport ServiceImpl
: public rti::core::detail::RetainableType<ServiceImpl> {
public:
explicit ServiceImpl(const ServiceProperty& property);
ServiceImpl(
const ServiceProperty& property,
detail::AbstractShutdownHookForwarder *hook_forwarder);
virtual ~ServiceImpl();
void start();
void stop();
private:
friend class rti::monitoring::collector::Application;
rti::monitoring::collector::service::Service *impl_;
detail::AbstractShutdownHookForwarder *shutdown_forwarder_fwd_;
};
} } }
#endif // RTI_MONITORING_COLLECTOR_SERVICE_IMPL_HPP_
@@ -0,0 +1,174 @@
/*
* (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_RECORDING_LOGGER_HPP_
#define RTI_RECORDING_LOGGER_HPP_
#include "recordingservice/recordingservice_dll.h"
#include <dds/core/Reference.hpp>
#include <rti/config/Logger.hpp>
namespace rti { namespace recording {
/** \ingroup RTI_RecordingServiceLibModule
*
* @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 RECORDERDllExport Logger
{
public:
typedef rti::config::Verbosity Verbosity;
typedef rti::config::LogCategory LogCategory;
typedef rti::config::PrintFormat PrintFormat;
static Logger& instance();
/**
* @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);
/**
* @brief overload of error(const std::string& msg)
*/
void error(const char *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::recording::Logger::error
*
*/
void warn(const std::string& msg);
/**
* @brief overload of warn(const std::string& msg)
*/
void warn(const char *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::recording::Logger::error
*
*/
void local(const std::string& msg);
/**
* @brief overload of local(const std::string& msg)
*/
void local(const char *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::recording::Logger::error
*
*/
void remote(const std::string& msg);
/**
* @brief overload of remote(const std::string& msg)
*/
void remote(const char *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::recording::Logger::error
*
*/
void debug(const std::string& msg);
/**
* @brief overload of debug(const std::string& msg)
*/
void debug(const char *msg);
/**
* @brief Sets the verbosity for the log messages generated at the
* @product level.
*
* @param[in] verbosity
* The verbosity of the service logs
*/
void service_verbosity(rti::config::Verbosity verbosity);
/**
* @brief Getter for the same attribute
*
* @see verbosity(rti::config::Verbosity)
*/
rti::config::Verbosity service_verbosity();
/**
* @deprecated
* @see service_verbosity
*/
void verbosity(rti::config::Verbosity verbosity);
/**
* @deprecated
* @see service_verbosity
*/
rti::config::Verbosity verbosity();
virtual ~Logger();
private:
void message(const rti::config::LogLevel& level, const char* msg);
Logger();
// Disable copy
Logger(const Logger&);
Logger& operator=(const Logger&);
};
}}
#endif // RTI_RECORDING_LOGGER_HPP_
@@ -0,0 +1,13 @@
#ifndef RTI_RECORDING_PROPERTYSET_HPP
#define RTI_RECORDING_PROPERTYSET_HPP
#include <rti/routing/PropertySet.hpp>
namespace rti { namespace recording {
typedef rti::routing::PropertySet PropertySet;
}}
#endif /* RTI_RECORDING_PROPERTYSET_HPP */
@@ -0,0 +1,6 @@
#ifndef RTI_RECORDING_RECORDING_SERVICE_HPP_
#define RTI_RECORDING_RECORDING_SERVICE_HPP_
#include <rti/recording/Service.hpp>
#endif
@@ -0,0 +1,295 @@
/*
* (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_RECORDING_SERVICE_HPP_
#define RTI_RECORDING_SERVICE_HPP_
#include <dds/core/Reference.hpp>
#include <rti/config/Logger.hpp>
#include <rti/recording/Logger.hpp>
#include <rti/recording/ServiceProperty.hpp>
#include <rti/recording/detail/RecordingServiceImpl.hpp>
namespace rti { namespace recording {
/*e \defgroup RTI_RecordingServiceLibModule RTI Recording Library API
*
* @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::recording::Service service(
* rti::recording::ServiceProperty()
* .cfg_file("MyRecorder.xml")
* .service_name("MyRecorder"));
* ...
*
* service.start();
*
* while(keep_running) {
* sleep();
* ...
* }
*
* return 0;
* }
*
* \endcode
*
* Instead of a file, you can use XML strings to configure @product.
* See ServiceProperty for more information.
* <p>
* To build your application you need to link with the @product native library
* in <b> &lt;@ndds home&gt;/bin/&lt;architecture&gt;/ </b>.
*
* ### Development Requirements
*
* | | Linux Systems | Windows Systems |
* | --------------: | :----------------: | :-------------: |
* | Shared Libraries| libnddscpp2.so | nddscpp2.dll |
* | Shared Libraries| librtiroutingservice.so | rtiroutingservice.dll |
* | ^ | librtirsinfrastructure.so | rtirsinfrastructure.dll |
* | ^ | librtirecordingservicecore.so | rtirecordingservicecore.dll |
* | ^ | librtidlc.so | rtidlc.dll |
* | ^ | libnddsmetp.so | nddsmetp.dll |
* | ^ | libnddsc.so | nddsc.dll |
* | ^ | librtixml2.so | rtixml2.dll |
* | ^ | libnddscore.so | nddscore.dll |
* | Headers | rti/recording/RecordingService.hpp ||
*
*/
/** \ingroup RTI_RecordingServiceLibModule
*
* @brief The @product.
*
*/
class Service : public dds::core::Reference<RecordingServiceImpl> {
public:
typedef RTI::Service::Admin::CommandRequest CommandRequest;
typedef RTI::Service::Admin::CommandReply CommandReply;
typedef dds::core::Reference<RecordingServiceImpl> Base;
OMG_DDS_REF_TYPE_NOTYPENAME(
Service,
dds::core::Reference,
RecordingServiceImpl);
/**
* @brief Creates a @product instance
*
* @param[in] property
* 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 RecordingServiceImpl(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 or upon execution
* termination in the case of the REPLAY role. 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;
* rti::recording::Service recording_service(
* property,
* FlagShutdownHook(my_flag));
* ...
*
*
* \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>
explicit Service(
const ServiceProperty& property,
HookFunc& shutdown_hook)
: Base(new RecordingServiceImpl(
property,
new rti::routing::detail::ShutdownHookForwarder<HookFunc>(
shutdown_hook)))
{
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 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::recording;
* using namespace RTI::Service;
* using namespace RTI::Service::Admin;
*
* // Instantiate a RecordingService
* RecordingService service(...);
*
* // Prepare a request for any command, for example stop the service
* CommandRequest request;
* request.action(CommandActionKind::UPDATE_ACTION);
* request.resource_identifier("/recording_services/MyRecorder");
* 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::recording::Logger::instance().warn(
"Calling 'rti::recording::Service::finalize_globals()' is no "
"longer necessary and the function will be removed in future "
"versions");
}
};
typedef Service RecordingService;
}}
#endif // RTI_RECORDING_SERVICE_HPP_
@@ -0,0 +1,579 @@
/*
* $Id$
*
* (c) Copyright, Real-Time Innovations, 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 HPP_SERVICE_SERVICEPROPERTY_HPP_
#define HPP_SERVICE_SERVICEPROPERTY_HPP_
#include "stdio.h"
#include "stdlib.h"
#include <string>
#include <stdint.h>
#include <map>
#include "osapi/osapi_type.h"
#include "routingservice/routingservice_infrastructure.h"
#include "routingservice/routingservice_service.h"
#include <dds/core/SafeEnumeration.hpp>
#include <rti/recording/PropertySet.hpp>
namespace rti { namespace recording {
/** \ingroup RTI_RecordingServiceLibModule
*
* The definition of the rti::recording::ApplicationRoleKind
*
* It indicates the operation mode of @product.
*/
struct ApplicationRoleKind_def {
/**
* @brief The underlying \p enum type
*/
enum type {
/**
* @brief Record mode
*/
RECORD_APPLICATION,
/**
* @brief Replay mode
*/
REPLAY_APPLICATION,
/**
* @brief Converter mode
*/
CONVERTER_APPLICATION,
/*i
* @brief Internal use only
*/
XML_CONVERTER_APPLICATION,
/*i
* @brief Indexer mode. To be used internally by our command-line tool.
*/
INDEX_APPLICATION,
/*i
*/
count_
};
};
typedef dds::core::safe_enum<ApplicationRoleKind_def> ApplicationRoleKind;
/*i
* @brief Internal use only
*/
struct XmlConverterRoleKind_def {
enum type {
RECORD_CONVERT,
REPLAY_CONVERT,
count_
};
};
typedef dds::core::safe_enum<XmlConverterRoleKind_def> XmlConverterRoleKind;
/*i
* @brief Indexer mode enumeration, used by the index application (offline
* indexing)
*/
struct IndexerModeKind_def {
enum type {
INSTANCE_INDEXING,
SQLITE_INDEXING,
count_
};
};
typedef dds::core::safe_enum<IndexerModeKind_def> IndexerModeKind;
typedef rti::routing::PropertySet PropertySet;
/** \ingroup RTI_RecordingServiceLibModule
*
* @brief Configuration for a @product object.
*
*/
class ServiceProperty {
public:
/**
* @brief Creates a property object with default settings.
*/
ServiceProperty() :
cfg_file_(""),
service_name_(""),
application_name_(""),
domain_id_base_(0),
enable_administration_(false),
administration_domain_id_(0),
enable_monitoring_(false),
monitoring_domain_id_(0),
application_role_(ApplicationRoleKind::RECORD_APPLICATION),
enforce_xsd_validation_(true),
ignore_default_files_(false),
output_cfg_file_(""),
debug_mode_(false),
reverse_mode_(false),
xml_converter_role_(XmlConverterRoleKind::RECORD_CONVERT),
indexer_mode_(IndexerModeKind::INSTANCE_INDEXING),
user_env_()
{
}
/**
* @brief Getter (see setter with the same name)
*/
const std::string& cfg_file() const
{
return cfg_file_;
}
/**
* @brief Path to an @product configuration file
*
* @default empty string.
*/
ServiceProperty& cfg_file(const std::string & cfg_file)
{
cfg_file_ = cfg_file;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
const std::string & service_name() const
{
return service_name_;
}
/**
* @brief The name of the @product configuration to run.
*
* This is the name used to find the 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 & service_name)
{
service_name_ = service_name;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
const std::string & application_name() const
{
return 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 & application_name)
{
application_name_ = application_name;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
int32_t domain_id_base() const
{
return domain_id_base_;
}
/**
* @brief Getter (see setter with the same name)
*/
bool enforce_xsd_validation() const
{
return enforce_xsd_validation_;
}
/**
* @brief Controls whether the service applies XSD validation to the loaded
* configuration.
*
* @default true
*/
ServiceProperty& enforce_xsd_validation(bool enforce)
{
enforce_xsd_validation_ = enforce;
return *this;
}
/**
* @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(int32_t domain_id)
{
domain_id_base_ = domain_id;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool enable_administration() const
{
return enable_administration_;
}
/**
* @brief Set this to true to enable remote administration
* or false to disable it.
*
* @default false
*/
ServiceProperty& enable_administration(bool enable_administration)
{
enable_administration_ = enable_administration;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
int32_t administration_domain_id() const
{
return 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(int32_t domain_id)
{
administration_domain_id_ = domain_id;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool enable_monitoring() const
{
return enable_monitoring_;
}
/**
* @brief Set it to true to enable remote monitoring
* or false to disable it.
*
* @default false
*/
ServiceProperty& enable_monitoring(bool enable_monitoring)
{
enable_monitoring_ = enable_monitoring;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
int32_t monitoring_domain_id() const
{
return 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(int32_t domain_id)
{
monitoring_domain_id_ = domain_id;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
const ApplicationRoleKind& application_role() const
{
return application_role_;
}
/**
* @brief Selects the operation mode of the service
*
* @see ApplicationRoleKind
*/
ServiceProperty& application_role(ApplicationRoleKind application_role)
{
application_role_ = application_role;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool ignore_default_files() const
{
return ignore_default_files_;
}
/**
* @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& ignore_default_files(bool ignore)
{
ignore_default_files_ = ignore;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
const std::string& license_file() const
{
return license_file_;
}
/**
* @brief Path to an RTI Connext license file. This parameter is only used
* if your installation requires a license file.
*
* @default empty string.
*/
ServiceProperty& license_file(const std::string& license_file)
{
license_file_ = license_file;
return *this;
}
/*i
* @brief Internal use only
*/
const std::string output_cfg_file() const
{
return output_cfg_file_;
}
/*i
* @brief Internal use only
*/
ServiceProperty& output_cfg_file(
const std::string & output_cfg_file)
{
output_cfg_file_ = output_cfg_file;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool debug_mode() const
{
return debug_mode_;
}
/**
* @brief Set this to true to enable debug mode
* or false to disable it.
*
* @default false
*/
ServiceProperty& debug_mode(bool debug_mode)
{
debug_mode_ = debug_mode;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool reverse_mode() const
{
return reverse_mode_;
}
/**
* @brief Set this to true to enable reverse mode
* or false to disable it.
*
* @default false
*/
ServiceProperty& reverse_mode(bool reverse_mode)
{
reverse_mode_ = reverse_mode;
return *this;
}
/*i
* @brief Internal use only
*/
XmlConverterRoleKind xml_converter_role() const
{
return xml_converter_role_;
}
/*i
* @brief Internal use only
*/
ServiceProperty& xml_converter_role(
const XmlConverterRoleKind & xml_converter_role)
{
xml_converter_role_ = xml_converter_role;
return *this;
}
/*i
* @brief The indexer application mode. Defined by the IndexerModeKind.
* Internal use only
*/
IndexerModeKind indexer_mode() const
{
return indexer_mode_;
}
/*i
* @brief Set the indexer application mode. Defined by the IndexerModeKind.
* Internal use only
*/
ServiceProperty& indexer_mode(const IndexerModeKind& indexer_mode)
{
indexer_mode_ = indexer_mode;
return *this;
}
/*i
* @brief The indexer database directory.
* Internal use only
*/
const std::string& db_directory() const
{
return db_directory_;
}
/*i
* @brief Set the indexer database directory.
* Internal use only
*/
ServiceProperty& db_directory(const std::string& db_directory)
{
db_directory_ = db_directory;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
const PropertySet& user_environment() const
{
return user_env_;
}
/**
* @brief Non-const getter for modification that can be used to add
* elements individually. (see setter with the same name)
*/
PropertySet& user_environment()
{
return user_env_;
}
/**
* @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 PropertySet& user_environment)
{
user_env_ = user_environment;
return *this;
}
private:
std::string cfg_file_;
//std::string cfg_strings[] ?
std::string service_name_;
std::string application_name_;
int32_t domain_id_base_;
bool enable_administration_;
int32_t administration_domain_id_;
bool enable_monitoring_;
int32_t monitoring_domain_id_;
ApplicationRoleKind application_role_;
bool enforce_xsd_validation_;
bool ignore_default_files_;
std::string license_file_;
// Specific to XML conversion
std::string output_cfg_file_;
bool debug_mode_;
bool reverse_mode_;
XmlConverterRoleKind xml_converter_role_;
IndexerModeKind indexer_mode_;
std::string db_directory_;
PropertySet user_env_;
};
} } /* namespace rti::recording */
#endif /* HPP_SERVICE_SERVICEPROPERTY_HPP_ */
@@ -0,0 +1,13 @@
#ifndef RTI_RECORDING_STREAM_INFO_HPP_
#define RTI_RECORDING_STREAM_INFO_HPP_
#include <rti/routing/StreamInfo.hpp>
namespace rti { namespace recording {
typedef rti::routing::StreamInfo StreamInfo;
}}
#endif /* RTI_RECORDING_STREAM_INFO_HPP_ */
@@ -0,0 +1,72 @@
/*
* (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_RECORDING_RECORDING_SERVICE_IMPL_HPP_
#define RTI_RECORDING_RECORDING_SERVICE_IMPL_HPP_
#include "recordingservice/recordingservice_dll.h"
#include <dds/core/refmacros.hpp>
#include <rti/core/detail/SelfReference.hpp>
#include <rti/idlgen/ServiceAdmin.hpp>
#include <rti/recording/ServiceProperty.hpp>
#include <rti/routing/detail/ShutdownHookForwarder.hpp>
namespace rti { namespace recording {
namespace service {
class Service;
}
namespace detail {
typedef rti::routing::detail::AbstractShutdownHookForwarder
AbstractShutdownHookForwarder;
}
class Application;
class RECORDERDllExport RecordingServiceImpl
: public rti::core::detail::RetainableType<RecordingServiceImpl> {
public:
typedef RTI::Service::Admin::CommandRequest CommandRequest;
typedef RTI::Service::Admin::CommandReply CommandReply;
explicit RecordingServiceImpl(const ServiceProperty& property);
RecordingServiceImpl(
const ServiceProperty& property,
detail::AbstractShutdownHookForwarder *hook_forwarder);
~RecordingServiceImpl();
void start();
void stop();
CommandReply execute_command(const CommandRequest& request);
CommandReply& execute_command(
CommandReply& reply,
const CommandRequest& request);
private:
friend class rti::recording::Application;
rti::recording::service::Service *impl_;
detail::AbstractShutdownHookForwarder *shutdown_forwarder_fwd_;
};
}}
#endif // RTI_RECORDING_RECORDING_SERVICE_IMPL_HPP_
@@ -0,0 +1,145 @@
/*
* (c) Copyright, Real-Time Innovations, 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 HPP_RTI_RECORDING_STORAGE_ESTORAGEFORMAT_HPP_
#define HPP_RTI_RECORDING_STORAGE_ESTORAGEFORMAT_HPP_
#include <stdint.h>
#include "reda/reda_string.h"
#include "dds_c/dds_c_infrastructure.h"
#include "dds/core/Exception.hpp"
namespace rti { namespace recording { namespace storage {
class EStorageFormat {
public:
static const DDS_DataRepresentationId_t INVALID_REPRESENTATION =
static_cast<DDS_DataRepresentationId_t>(
RTI_CDR_ENCAPSULATION_ID_INVALID);
static const EStorageFormat XCDR() {
static const EStorageFormat XCDR(
0,
"XCDR",
DDS_XCDR_DATA_REPRESENTATION);
return XCDR;
}
static const EStorageFormat XCDR2() {
static const EStorageFormat XCDR2(
1,
"XCDR2",
DDS_XCDR2_DATA_REPRESENTATION);
return XCDR2;
}
static const EStorageFormat XCDR_AUTO() {
static const EStorageFormat XCDR_AUTO(
2,
"XCDR_AUTO",
DDS_AUTO_DATA_REPRESENTATION);
return XCDR_AUTO;
}
static const EStorageFormat JSON_SQLITE() {
static const EStorageFormat JSON_SQLITE(
3,
"JSON_SQLITE",
INVALID_REPRESENTATION);
return JSON_SQLITE;
}
/**
* This format is only used by the legacy DB plugins, for the moment.
*/
static const EStorageFormat DESERIALIZED() {
static const EStorageFormat DESERIALIZED(
4,
"DESERIALIZED",
INVALID_REPRESENTATION);
return DESERIALIZED;
}
static EStorageFormat from_string_ignore_case(const std::string& value)
{
if (REDAString_iCompare(
value.c_str(),
XCDR().enum_value().c_str()) == 0) {
return XCDR();
} else if (REDAString_iCompare(
value.c_str(),
XCDR2().enum_value().c_str()) == 0) {
return XCDR2();
} else if (REDAString_iCompare(
value.c_str(),
XCDR_AUTO().enum_value().c_str()) == 0) {
return XCDR_AUTO();
} else if (REDAString_iCompare(
value.c_str(),
JSON_SQLITE().enum_value().c_str()) == 0) {
return JSON_SQLITE();
} else {
throw dds::core::UnsupportedError(
"Unrecognized DB Format value, must be one of "
"{XCDR,XCDR2,XCDR_AUTO,JSON_SQLITE}");
}
}
EStorageFormat(const EStorageFormat& other)
: enum_value_(other.enum_value_),
enum_string_(other.enum_string_),
data_rep_id_(other.data_rep_id_){}
void operator =(const EStorageFormat& other)
{
enum_value_ = other.enum_value_;
enum_string_ = other.enum_string_;
data_rep_id_ = other.data_rep_id_;
}
bool operator ==(const EStorageFormat& other) const
{
return enum_value_ == other.enum_value_;
}
bool operator !=(const EStorageFormat& other) const
{
return enum_value_ != other.enum_value_;
}
uint32_t value() const { return enum_value_; }
const std::string& enum_value() const { return enum_string_; }
/**
* This function returns the associated data representation when it applies.
* In the cases it doesn't, it returns the value INVALID_REPRESENTATION
*/
DDS_DataRepresentationId_t data_representation() const
{
return data_rep_id_;
}
private:
uint32_t enum_value_;
std::string enum_string_;
DDS_DataRepresentationId_t data_rep_id_;
EStorageFormat(
const uint32_t value,
const std::string& enum_string,
const DDS_DataRepresentationId_t rep_id) :
enum_value_(value),
enum_string_(enum_string),
data_rep_id_(rep_id) {}
};
} } } /* namespace rti::recording::storage */
#endif /* HPP_RTI_RECORDING_STORAGE_ESTORAGEFORMAT_HPP_ */
@@ -0,0 +1,250 @@
/*
* (c) Copyright, Real-Time Innovations, 2018-.
* 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_RTI_RECORDING_STORAGE_SAMPLESELECTOR_HPP_
#define HPP_RTI_RECORDING_STORAGE_SAMPLESELECTOR_HPP_
#include "dds/dds.hpp"
#include "rti/core/NativeValueType.hpp"
#include "rti/core/constants.hpp"
#include "rti/apputils/util/Utils.hpp"
#include "recordingservice/recordingservice_storagereader.h"
namespace rti { namespace recording { namespace storage {
class SelectorState;
/**
* Adapter class for the native type RTI_RecordingServiceSelectorState.
*/
class SelectorStateAdapter {
public:
typedef RTI_RecordingServiceSelectorState native_type;
static void initialize(native_type& native_value)
{
RTI_RecordingServiceSelectorState native_state =
RTI_RecordingServiceSelectorState_INITIALIZER;
memcpy(&native_value, &native_state, sizeof(native_state));
}
static void finalize(native_type&)
{
}
static void copy(native_type& destination, const native_type& source)
{
destination.sample_state = source.sample_state;
destination.time_range_start = source.time_range_start;
destination.time_range_end = source.time_range_end;
destination.max_samples = source.max_samples;
destination.instance_history = source.instance_history;
}
static bool equals(const native_type& first, const native_type& second)
{
if (first.sample_state != second.sample_state) {
return false;
}
if (first.max_samples != second.max_samples) {
return false;
}
if (!DDS_Time_t_equals(
first.time_range_start,
second.time_range_start)) {
return false;
}
if (!DDS_Time_t_equals(
first.time_range_end,
second.time_range_end)) {
return false;
}
return first.instance_history.depth == second.instance_history.depth;
}
};
} }
/*
* Type native_type_traits needs to be defined in the rti::core namespace.
*/
namespace core {
template <>
struct native_type_traits<rti::recording::storage::SelectorState> {
typedef rti::recording::storage::SelectorStateAdapter adapter_type;
typedef RTI_RecordingServiceSelectorState native_type;
};
}
namespace recording { namespace storage {
/** \ingroup RTI_RecordingServiceStorageModule
*
* @brief This class is used by \replay_product or \converter_product when
* asking the storage plugin for data. It specifies whether the samples should
* be 'not read' samples, that haven't been returned before, or that 'any'
* sample state is needed. It also allows to specify the time range the samples
* returned have to lay within (upper and lower limit).
*/
class SelectorState : public rti::core::NativeValueType<SelectorState> {
public:
RTI_NATIVE_VALUE_TYPE_DEFINE_DEFAULT_MOVE_OPERATIONS(SelectorState)
typedef rti::core::NativeValueType<SelectorState> Base;
SelectorState()
{
}
SelectorState(const RTI_RecordingServiceSelectorState &native) :
Base(native)
{
}
/**
* @brief Returns the sample state. This is used to represent the state of
* the samples asked for, whether they have been already read or not.
* When this value is set to:
* - Not read: the storage plugin should provide samples that hasn't
* provided before. This implies that the storage plugin has to
* keep track of what samples it has already returned and what
* samples it hasn't.
* - Any: the storage plugin should provide all the samples within
* the specified time range, no matter their read state. This
* implies a stateless read, the storage plugin is not supposed to
* keep track of what samples have been read or not in this case.
* - Read: in the current version, this sample state is not used by
* \replay_product or \converter_product.
*/
inline dds::sub::status::SampleState sample_state() const
{
return dds::sub::status::SampleState(native().sample_state);
}
/**
* @brief Sets the sample state.
*/
SelectorState& sample_state(const dds::sub::status::SampleState& state)
{
native().sample_state =
static_cast<RTI_RecordingServiceSampleStateMask>(
state.to_ulong());
return *this;
}
/**
* @brief Returns the time that represents the lower limit (inclusive) of
* the time range the retrieved data samples should lay within. When
* retrieving stateful samples (not read), this parameter becomes
* irrelevant as the lower limit should be the time-stamp of the
* latest sample returned.
*/
inline dds::core::Time time_range_start() const
{
return dds::core::Time(
native().time_range_start.sec,
native().time_range_start.nanosec);
}
/**
* @brief Like the time_range_start() method, but returns the timestamp in
* long long (int-64) format
*/
inline int64_t timestamp_range_start() const
{
return rti::apputils::util::convert_uint64_into_int64(
rti::apputils::util::to_nanosecs(time_range_start()));
}
/**
* @brief Sets the lower limit of the time range.
*/
SelectorState& time_range_start(const dds::core::Time& time_range_start)
{
native().time_range_start.sec = time_range_start.sec();
native().time_range_start.nanosec =
(DDS_UnsignedLong) time_range_start.nanosec();
return *this;
}
/**
* @brief Returns the time that represents the upper limit (inclusive) of
* the time range the retrieved samples should lay within. This
* parameter is always relevant, as samples should be returned in
* increasing time-stamp order.
*/
inline dds::core::Time time_range_end() const
{
return dds::core::Time(
native().time_range_end.sec,
native().time_range_end.nanosec);
}
/**
* @brief Like the time_range_end() method, but returns the timestamp in
* long long (int-64) format
*/
inline int64_t timestamp_range_end() const
{
return rti::apputils::util::convert_uint64_into_int64(
rti::apputils::util::to_nanosecs(time_range_end()));
}
/**
* @brief Sets the upper limit of the time range.
*/
SelectorState& time_range_end(const dds::core::Time& time_range_end)
{
native().time_range_end.sec = time_range_end.sec();
native().time_range_end.nanosec =
static_cast<DDS_UnsignedLong>(time_range_end.nanosec());
return *this;
}
/**
* @brief Returns the maximum number of samples to be returned by a single
* read() call, when the value is positive.
* A negative value indicates an unlimited number of samples.
*/
inline int32_t max_samples() const
{
return native().max_samples;
}
/**
* @brief Sets the maximum number of samples to be returned by a single call
* to read().
*/
SelectorState& max_samples(const int32_t max_samples)
{
native().max_samples = (int) max_samples;
return *this;
}
inline int32_t instance_history_depth() const
{
return native().instance_history.depth;
}
SelectorState& instance_history_depth(const int32_t depth)
{
native().instance_history.depth = (int) depth;
return *this;
}
};
} } } /* namespace rti::recording::storage */
#endif /* HPP_RTI_RECORDING_STORAGE_SAMPLESELECTOR_HPP_ */
@@ -0,0 +1,251 @@
/*
* (c) Copyright, Real-Time Innovations, 2018-.
* 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_RTI_RECORDING_STORAGE_STORAGEDEFS_HPP_
#define HPP_RTI_RECORDING_STORAGE_STORAGEDEFS_HPP_
#include <sstream>
#include <memory>
#ifndef dds_c_builtin_h
#include "dds_c/dds_c_builtin.h"
#endif
#include <rti/core/Exception.hpp>
#include "rti/recording/PropertySet.hpp"
#include "recordingservice/recordingservice_storagereader.h"
#include "recordingservice/recordingservice_storagewriter.h"
namespace rti { namespace recording {
// Writer-related defines
typedef std::shared_ptr<RTI_RecordingServiceStorageWriter>
StorageWriterSharedPtr;
typedef std::shared_ptr<RTI_RecordingServiceStorageStreamWriter>
StorageStreamWriterSharedPtr;
typedef std::shared_ptr<RTI_RecordingServiceStorageParticipantWriter>
StorageParticipantWriterSharedPtr;
typedef std::shared_ptr<RTI_RecordingServiceStoragePublicationWriter>
StoragePublicationWriterSharedPtr;
typedef std::shared_ptr<RTI_RecordingServiceStorageSubscriptionWriter>
StorageSubscriptionWriterSharedPtr;
// Reader-related defines
typedef std::shared_ptr<RTI_RecordingServiceStorageReader>
StorageReaderSharedPtr;
typedef std::shared_ptr<RTI_RecordingServiceStorageStreamReader>
StorageStreamReaderSharedPtr;
typedef std::shared_ptr<RTI_RecordingServiceStorageStreamInfoReader>
StorageStreamInfoReaderSharedPtr;
/*
* Helper classes to be used with the pointer definitions above, to create the
* smart pointers and use this class as a deleter (pointing to the () operator)
*/
class NativeStorageStreamWriterDeleter {
public:
NativeStorageStreamWriterDeleter(
RTI_RecordingServiceStorageWriter *storage_writer_parent)
: storage_writer_parent_(storage_writer_parent)
{
RTI_CHECK_PRECONDITION(storage_writer_parent != NULL);
}
void operator ()(RTI_RecordingServiceStorageStreamWriter *instance)
{
if (instance != NULL) {
storage_writer_parent_->delete_stream_writer(
storage_writer_parent_,
instance);
}
}
void operator ()(RTI_RecordingServiceStorageParticipantWriter *instance)
{
// The delete participant writer operation is not required, better be
// safe than sorry
if (instance != NULL
&& storage_writer_parent_->delete_participant_writer != NULL) {
storage_writer_parent_->delete_participant_writer(
storage_writer_parent_,
instance);
}
}
void operator ()(RTI_RecordingServiceStoragePublicationWriter *instance)
{
// The delete publication writer operation is not required, better be
// safe than sorry
if (instance != NULL
&& storage_writer_parent_->delete_publication_writer != NULL) {
storage_writer_parent_->delete_publication_writer(
storage_writer_parent_,
instance);
}
}
void operator ()(RTI_RecordingServiceStorageSubscriptionWriter *instance)
{
// The delete subscription writer operation is not required, better be
// safe than sorry
if (instance != NULL
&& storage_writer_parent_->delete_subscription_writer != NULL) {
storage_writer_parent_->delete_subscription_writer(
storage_writer_parent_,
instance);
}
}
private:
RTI_RecordingServiceStorageWriter *storage_writer_parent_;
};
class NativeStorageStreamInfoReaderDeleter {
public:
NativeStorageStreamInfoReaderDeleter(
RTI_RecordingServiceStorageReader *storage_reader_parent)
: storage_reader_parent_(storage_reader_parent)
{
RTI_CHECK_PRECONDITION(storage_reader_parent != NULL);
}
void operator ()(RTI_RecordingServiceStorageStreamInfoReader *instance)
{
if (instance != NULL) {
storage_reader_parent_->delete_stream_info_reader(
storage_reader_parent_,
instance);
}
}
private:
RTI_RecordingServiceStorageReader *storage_reader_parent_;
};
class NativeStorageStreamReaderDeleter {
public:
NativeStorageStreamReaderDeleter(
RTI_RecordingServiceStorageReader *storage_reader_parent)
: storage_reader_parent_(storage_reader_parent)
{
RTI_CHECK_PRECONDITION(storage_reader_parent != NULL);
}
void operator ()(RTI_RecordingServiceStorageStreamReader *instance)
{
if (instance != NULL) {
storage_reader_parent_->delete_stream_reader(
storage_reader_parent_,
instance);
}
}
private:
RTI_RecordingServiceStorageReader *storage_reader_parent_;
};
inline bool is_discovery_stream(const std::string& stream_name)
{
if (stream_name.compare(DDS_PARTICIPANT_TOPIC_NAME) == 0
|| stream_name.compare(DDS_PUBLICATION_TOPIC_NAME) == 0
|| stream_name.compare(DDS_SUBSCRIPTION_TOPIC_NAME) == 0) {
return true;
}
return false;
}
inline std::string domain_id_property_name()
{
return RTI_RECORDING_SERVICE_DOMAIN_ID_PROPERTY_NAME;
}
inline std::string start_timestamp_property_name()
{
return RTI_RECORDING_SERVICE_START_TIMESTAMP_PROPERTY_NAME;
}
inline std::string end_timestamp_property_name()
{
return RTI_RECORDING_SERVICE_END_TIMESTAMP_PROPERTY_NAME;
}
inline std::string jump_timestamp_property_name()
{
return RTI_RECORDING_SERVICE_JUMP_TIMESTAMP_PROPERTY_NAME;
}
inline std::string sample_order_property_name()
{
return RTI_RECORDING_SERVICE_PLAYBACK_SAMPLE_ORDER_PROPERTY_NAME;
}
inline std::string reverse_mode_property_name()
{
return RTI_RECORDING_SERVICE_PLAYBACK_REVERSE_MODE_PROPERTY_NAME;
}
template <typename T>
inline T get_from_properties(
const rti::recording::PropertySet& properties,
const std::string& property_name)
{
rti::recording::PropertySet::const_iterator found =
properties.find(property_name);
if (found == properties.end()) {
throw dds::core::Error(
"!found property with name=" + property_name);
}
T value;
std::stringstream str_stream(found->second);
str_stream >> value;
if (str_stream.fail()) {
throw dds::core::Error(
"!parse value from property with name=" + property_name);
}
return value;
}
template <typename T>
inline void add_to_properties(
rti::recording::PropertySet& properties,
const std::string& property_name,
const T value)
{
rti::recording::PropertySet::const_iterator found =
properties.find(property_name);
if (found != properties.end()) {
return;
}
std::stringstream str_stream;
str_stream << value;
if (str_stream.fail()) {
throw dds::core::Error(
"!add value for property with name=" + property_name);
}
properties[property_name] = str_stream.str();
}
namespace detail {
#define RecorderPrint_exception(...) \
RTILogMessage_print( \
RTI_LOG_PRINT_FORMAT_MASK_ALL, \
RTI_LOG_BIT_EXCEPTION, \
MODULE_RECORDER, \
__VA_ARGS__)
} /* namespace rti::recording::detail */
} } /* namespace rti::recording */
#endif /* HPP_RTI_RECORDING_STORAGE_STORAGEDEFS_HPP_ */
@@ -0,0 +1,56 @@
/*
* (c) Copyright, Real-Time Innovations, 2018-.
* 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_RECORDING_STORAGE_STORAGEDISCOVERYSTREAMWRITER_HPP_
#define RTI_RECORDING_STORAGE_STORAGEDISCOVERYSTREAMWRITER_HPP_
#include <vector>
#include "dds/dds.hpp"
#include "rti/recording/storage/StorageStreamWriter.hpp"
#include "rti/routing/detail/ForwarderUtils.hpp"
namespace rti { namespace recording { namespace storage {
/** \ingroup RTI_RecordingServiceStorageModule
*
* @brief Convenience definition of typed StorageStreamWriter that requires
* dds::core::xtypes::DynamicData for data samples and dds::sub::SampleInfo
* for info samples.
*
*/
typedef TStorageStreamWriter<
dds::topic::ParticipantBuiltinTopicData,
dds::sub::SampleInfo> ParticipantStorageWriter;
/** \ingroup RTI_RecordingServiceStorageModule
* @brief Convenience definition of typed StorageStreamWriter that requires
* dds::core::xtypes::DynamicData for data samples and dds::sub::SampleInfo
* for info samples.
*
*/
typedef TStorageStreamWriter<
dds::topic::PublicationBuiltinTopicData,
dds::sub::SampleInfo> PublicationStorageWriter;
/** \ingroup RTI_RecordingServiceStorageModule
* @brief Convenience definition of typed StorageStreamWriter that requires
* dds::core::xtypes::DynamicData for data samples and dds::sub::SampleInfo
* for info samples.
*
*/
typedef TStorageStreamWriter<
dds::topic::SubscriptionBuiltinTopicData,
dds::sub::SampleInfo> SubscriptionStorageWriter;
} } } // namespace rti::recording::storage
#endif /* RTI_RECORDING_STORAGE_STORAGEDISCOVERYSTREAMWRITER_HPP_ */
@@ -0,0 +1,239 @@
/*
* (c) Copyright, Real-Time Innovations, 2018-.
* 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_RECORDER_DB_REPLAYPLUGIN_HPP_
#define HPP_RECORDER_DB_REPLAYPLUGIN_HPP_
#include "dds/dds.hpp"
#include "rti/recording/PropertySet.hpp"
#include "rti/recording/StreamInfo.hpp"
#include "StorageStreamInfoReader.hpp"
#include "rti/recording/storage/StorageStreamReader.hpp"
/** @file
* @brief \product Pluggable Storage Reader API
*
* These APIs define a plugin that can be used by \replay_product and
* \converter_product to retrieve data from storage.
*/
/**
* @brief The RTI namespace.
*
*/
namespace rti {
/**
* @brief The \product namespace.
*
* The \product namespace includes all public classes of \product
*/
namespace recording {
/**
* @brief The \product storage namespace.
*
* The \product namespace includes all classes needed to plug in custom storage.
*/
namespace storage {
/** \ingroup RTI_RecordingServiceStorageModule
* class rti::recording::storage::StorageReader
* @brief Storage reader
*
* This class creates and deletes:
* - StreamInfoReaders, that will be used to query discovery data from
* storage and provide it to \replay_product and \converter_product
* - StreamReaders, that will be used to query user data from storage and
* provide it to \replay_product and \converter_product
*/
class StorageReader {
public:
typedef void* SampleType;
typedef void* InfoType;
typedef std::vector<SampleType> SampleSeqType;
typedef std::vector<InfoType> InfoSeqType;
/**
* @memberof rti::recording::storage::StorageReader
* @brief Constructor.
*
* Creates a StorageReader object.
*
* @param properties Routing Service PropertySet. Contains name/value
* pairs that can be passed to the plugin in the XML, using the
* following snippet:
\verbatim
<replay_service name="ExampleReplay>
<storage>
<plugin plugin_name="StorageLibrary::ExamplePlugin">
<!-- Storage properties. These are passed to the plugin in the
plugin_library -->
<property>
<value>
<element>
<name>example.filename</name>
<value>PluggableStorage.dat</value>
</element>
</value>
</property>
</plugin>
</storage>
</replay_service>
\endverbatim
*/
StorageReader(const rti::recording::PropertySet& properties)
{
RTI_UNUSED_PARAMETER(properties);
}
/**
* @brief Virtual destructor
*/
virtual ~StorageReader()
{
}
/**
* @brief \replay_product calls this to create a stream in charge of
* discovering information about the available user-data streams in the
* storage, and read them.
*
* @param properties A collection of name-value properties. They include
* some built-in values, like:
* 1) name='rti.recording_service.start_timestamp'
* value=the initial timestamp of the selected time range (64-bit
* integer in text format) for this stream info reader to query
* data
* 2) name='rti.recording_service.end_timestamp'
* value=the final timestamp of the selected time range (64-bit
* integer in text format) for this stream info reader to query
* data
* 3) name='rti.recording_service.playback_settings.sample_order'
* value=the sample order (enum label in text format) for this
* stream info reader to query data.
* The possible values are: RECEPTION_TIMESTAMP, SOURCE_TIMESTAMP.
* 4) name='rti.recording_service.playback_settings.reverse_mode'
* value= the status of the reverse mode (ENABLED or DISABLED)
* for this stream info reader to query data.
* The possible values are: true, false.
*/
virtual StorageStreamInfoReader * create_stream_info_reader(
const rti::recording::PropertySet& properties) = 0;
/**
* @brief \replay_product calls this to delete a stream information reader
*
* @param stream_info_reader Stream information reader to be deleted.
*/
virtual void delete_stream_info_reader(
StorageStreamInfoReader *stream_info_reader) = 0;
/**
* @brief \replay_product calls this to create a user-data stream reader.
*
* @param stream_info Information about the stream (DDS topic) this stream
* reader will query from the database.
* @param properties A collection of name-value properties. They include
* some built-in values, like:
* 1) name='rti.recording_service.domain_id'
* value=the DDS domain ID the stream was found in (32-bit integer
* as text)
* 2) name='rti.recording_service.start_timestamp'
* value=the initial timestamp of the selected time range (64-bit
* integer in text format) for this stream info reader to query
* data
* 3) name='rti.recording_service.end_timestamp'
* value=the final timestamp of the selected time range (64-bit
* integer in text format) for this stream info reader to query
* data
* 4) name='rti.recording_service.playback_settings.sample_order'
* value=the sample order (enum label in text format) for this
* stream info reader to query data.
* The possible values are: RECEPTION_TIMESTAMP, SOURCE_TIMESTAMP.
* 5) name='rti.recording_service.playback_settings.reverse_mode'
* value= the status of the reverse mode (ENABLED or DISABLED)
* for this stream info reader to query data.
* The possible values are: true, false.
*/
virtual StorageStreamReader * create_stream_reader(
const rti::recording::StreamInfo& stream_info,
const rti::recording::PropertySet& properties) = 0;
/**
* @brief \replay_product calls this to delete a stream reader.
*
* @param stream_reader Stream reader to be deleted.
*/
virtual void delete_stream_reader(StorageStreamReader *stream_reader) = 0;
private:
StorageReader() {}
};
} } } /* namespace rti::recording::storage */
#include "rti/recording/storage/detail/StorageReaderForwarder.hpp"
#include "rti/routing/ServiceProperty.hpp"
#include "rti/routing/detail/ForwarderUtils.hpp"
/** \ingroup RTI_RecordingServiceStorageModule
* @def RTI_RECORDING_STORAGE_READER_CREATE_DECL
* @brief Convenience macro to declare the C-style function that will be called
* by \replay_product and \converter_product to create your class
*
* This macro automatically declares a C wrapper function for your class
* creation. \replay_product and \converter_product must be initialized
* with the name of this function. For example if your StorageReader class is
* 'FileStorageReader' this creates wrapper function called
* 'FileStorageReader_get_storage_reader' that you must specify in your XML
* file, such as:
*
* \verbatim
<plugin_library name="StorageLibrary">
<storage_plugin name="ExamplePlugin">
<dll>FileStorageReader</dll>
<create_function>FileStorageReader_get_storage_reader</create_function>
</storage_plugin>
</plugin_library>
\endverbatim
*/
#define RTI_RECORDING_STORAGE_READER_CREATE_DECL(STORAGE_READER_CLASS) \
extern "C" RTI_USER_DLL_EXPORT \
struct RTI_RecordingServiceStorageReader * \
STORAGE_READER_CLASS ## _get_storage_reader( \
const struct RTI_RoutingServiceProperties *);
/** \ingroup RTI_RecordingServiceStorageModule
* @brief Convenience macro to implement the C-style function that will be
* called by \replay_product and \converter_product to create your class
*
* This macro automatically defines a C wrapper function for your class
* creation. \replay_product and \converter_product must be initialized
* with the name of this function.
*/
#define RTI_RECORDING_STORAGE_READER_CREATE_DEF(STORAGE_READER_CLASS) \
struct RTI_RecordingServiceStorageReader * \
STORAGE_READER_CLASS ## _get_storage_reader( \
const struct RTI_RoutingServiceProperties *native_properties) \
{ \
rti::recording::PropertySet properties; \
rti::routing::PropertyAdapter::add_properties_from_native( \
properties, \
native_properties); \
return new rti::recording::storage::detail::StorageReaderForwarder( \
new STORAGE_READER_CLASS(properties)); \
}
#endif /* HPP_RECORDER_DB_REPLAYPLUGIN_HPP_ */
@@ -0,0 +1,110 @@
/******************************************************************************
* (c) Copyright, Real-Time Innovations, 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 HPP_RTI_RECORDING_STORAGE_DISCOVERYSTREAMREADER_HPP_
#define HPP_RTI_RECORDING_STORAGE_DISCOVERYSTREAMREADER_HPP_
#include "dds/dds.hpp"
#include "rti/recording/StreamInfo.hpp"
#include "SelectorState.hpp"
namespace rti { namespace recording { namespace storage {
/** \ingroup RTI_RecordingServiceStorageModule
* class rti::recording::storage::StorageStreamInfoReader
* @brief Storage discovery stream reader
*
* This class is used by the \replay_product and \converter_product to query
* the contents of storage to be replayed or converted, including:
* - The names of streams that are stored, and their associated type
* representations, when recorded.
* - The domain IDs associated with those streams.
* - The first and last timestamps in the stored data.
*/
class StorageStreamInfoReader {
public:
/**
* @brief Virtual destructor
*
*/
virtual ~StorageStreamInfoReader() {}
/**
* @brief Retrieve stream information data from storage. This operation
* should behave differently depending on the product's needs, stated in the
* SelectorState object passed as a parameter. The stream info samples have
* to be provided in increasing time-stamp order (reception time-stamp).
*
* \replay_product and \converter_product will call this method to
* retrieve discovery data from the plugins. Discovery data describes which
* streams are available from storage.
*
* @param sample_seq Vector of SampleType data. A SampleType is
* an rti::recording::StreamInfo.
* @param selector Provides the statefulness and constraints of the data
* queried by \replay_product or \converter_product. When the
* selector's sample state is set to 'any', it means its asking for
* stateless information (it doesn't care whether the data has been
* read before or not). When the selector's sample state is set to
* 'not read' then it's a stateful read, and only samples that
* weren't given to the application before have to be provided.
* Note: for the moment, \replay_product or
* \converter_product won't ask for data with sample state equal to
* 'read', so this state can be ignored.
*
* When Replay Service is on reverse mode, it will set the selector's
* start timestamp to 0. In this mode, Replay Service will burst all
* the discovery information at the beginning of the replay.
* After this burst of samples, the discovery stream reader will wait
* until the end of the replay.
*/
virtual void read(
std::vector<rti::recording::StreamInfo *>& sample_seq,
const SelectorState& selector) = 0;
/**
* @brief Notifies plugin it can release the read stream information objects
*
* @param sample_seq A vector of stream info objects that the plugin can
* now release resources for.
*/
virtual void return_loan(
std::vector<rti::recording::StreamInfo *>& sample_seq) = 0;
/**
* @brief The time within the recorded time range that can be considered
* time zero of the recording
*/
virtual int64_t service_start_time() = 0;
/**
* @brief The time relative to the recorded time range that can be
* considered the final recording time of the recording
*/
virtual int64_t service_stop_time() = 0;
/**
* @brief Whether this discovery stream has finished with all discovery data
* or not.
*/
virtual bool finished() = 0;
/**
* @brief Method used by \replay_product when looping, to start over. After
* this method is called, the stream reader should be ready to start reading
* data from the beginning of the stream, again.
*/
virtual void reset() = 0;
};
} } } /* namespace rti::recording::storage */
#endif /* HPP_RTI_RECORDING_STORAGE_DISCOVERYSTREAMREADER_HPP_ */
@@ -0,0 +1,199 @@
/*
* (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_RTI_RECORDING_STORAGE_STREAMREADER_HPP_
#define HPP_RTI_RECORDING_STORAGE_STREAMREADER_HPP_
#include <vector>
#include "dds/dds.hpp"
#include "rti/routing/detail/ForwarderUtils.hpp"
#include "rti/recording/storage/SelectorState.hpp"
namespace rti { namespace recording { namespace storage {
/** \ingroup RTI_RecordingServiceStorageModule
* class rti::recording::storage::StorageStreamReader
* @brief Storage stream reader
*
* This class retrieves user data from storage.
*/
class StorageStreamReader {
public:
typedef void* SamplePtr;
typedef void* InfoPtr;
/**
* @brief Virtual destructor
*/
virtual ~StorageStreamReader()
{
}
/**
* @brief Method called by \replay_product and \converter_product
* to retrieve samples from storage for a particular stream
* (DDS topic). The data samples retrieved have to be provided in
* increasing time-stamp order (reception time-stamp).
*
* @param sample_seq A vector of data samples that \replay_product or
* \converter_product will replay or convert to a new format.
* A SampleType is a DDS_DynamicData * cast as a void *
* @param info_seq A vector of sample information about the samples,
* such as recorded timestamps of the sample data. An InfoType is
* a DDS_SampleInfo * cast as a void *.
* @param selector Provides the statefulness and constraints of the data
* queried by \replay_product or \converter_product. When the
* selector's sample state is set to 'any', it means its asking for
* stateless information (it doesn't care whether the data has been
* read before or not). When the selector's sample state is set to
* 'not read' then it's a stateful read, and only samples that
* weren't given to the application before have to be provided.
* Note: for the moment, \replay_product or
* \converter_product won't ask for data with sample state equal to
* 'read', so this state can be ignored.
*
* When the selector's start timestamp is set to a value different
* than 0, it means that Replay Service is on a jumping process.
* The StreamReader should then prepare its statement with this
* new start timestamp. Also, if the selector's maximum samples is
* set to 0, it means that Replay Service is on a jumping breakpoint process
* instead of a standard jumping process. In this case, the StreamReader
* should also prepare the statement but it should not read any sample.
*/
virtual void read(
std::vector<SamplePtr>& sample_seq,
std::vector<InfoPtr>& info_seq,
const SelectorState& selector) = 0;
/**
* @brief Method for releasing resources related to the queried data
* samples.
*
* This is called back when the \replay_product or \converter_product has
* finished with the data samples queried in the take() function, and
* wants to notify the plugin that it can free any related resources.
*
* @param sample_seq A vector of sample objects that the plugin can
* now free.
* @param info_seq A vector of sample_info objects that the plugin can
* now free.
*
*/
virtual void return_loan(
std::vector<SamplePtr>& sample_seq,
std::vector<InfoPtr>& info_seq) = 0;
/**
* @brief Method for querying whether there are no more samples for this
* stream.
*
* @return true if there is no more data available for this stream,
* false otherwise.
*
*/
virtual bool finished() = 0;
/**
* @brief Method used by \replay_product when looping, to start over. After
* this method is called, the stream reader should be ready to start reading
* data from the beginning of the stream, again.
*/
virtual void reset() = 0;
};
/** \ingroup RTI_RecordingServiceStorageModule
* class rti::recording::storage::TStorageStreamReader
* @brief A templatized wrapping implementation of StorageStreamReader,
* providing a strongly-typed interface regarding data and info representations.
*
* 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 TStorageStreamReader : public StorageStreamReader {
public:
/**
* @brief The data type
*/
typedef Data DataRep;
/**
* @brief The info type
*/
typedef Info InfoRep;
using StorageStreamReader::read;
using StorageStreamReader::return_loan;
/**
* @brief Performs the conversion between the vector of data and info
* pointers to strongly-typed pointers.
*/
void read(
std::vector<SamplePtr>& sample_seq,
std::vector<InfoPtr>& info_seq,
const SelectorState& selector) RTI_FINAL
{
read(sample_seq_, info_seq_, selector);
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(sample_seq, sample_seq_);
RTI_ROUTING_SAMPLE_VECTOR_COPY_PTRS(info_seq, info_seq_);
}
/**
* @brief Performs the conversion between the vector of data and info
* pointers to strongly-typed 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();
}
virtual void read(
std::vector<Data *>& sample_seq,
std::vector<Info *>& info_seq,
const SelectorState& selector) = 0;
virtual void return_loan(
std::vector<Data *>& sample_seq,
std::vector<Info *>& info_seq) = 0;
/*
* @brief Virtual destructor
*/
virtual ~TStorageStreamReader() {}
private:
std::vector<Data*> sample_seq_;
std::vector<Info*> info_seq_;
};
/** \ingroup RTI_RecordingServiceStorageModule
* @brief Convenience definition of typed StorageStreamReader that requires
* dds::core::xtypes::DynamicData for data samples and dds::sub::SampleInfo
* for info samples.
*/
typedef TStorageStreamReader<
dds::core::xtypes::DynamicData,
dds::sub::SampleInfo> DynamicDataStorageStreamReader;
} } } // namespace rti::recording::storage
#endif /* HPP_RTI_RECORDING_STORAGE_STREAMREADER_HPP_ */
@@ -0,0 +1,128 @@
/*
* (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_RECORDING_STORAGE_STORAGESTREAMWRITER_HPP_
#define RTI_RECORDING_STORAGE_STORAGESTREAMWRITER_HPP_
#include <vector>
#include "dds/dds.hpp"
#include "rti/routing/detail/ForwarderUtils.hpp"
namespace rti { namespace recording { namespace storage {
/** \ingroup RTI_RecordingServiceStorageModule
* class rti::recording::storage::StorageStreamWriter
* @brief Storage stream writer
*
* Inherit from this class and implement the store method to store data to
* the storage of your choice.
*/
class StorageStreamWriter {
public:
typedef void* SamplePtr;
typedef void* InfoPtr;
/**
* @brief Virtual destructor
*/
virtual ~StorageStreamWriter() {}
/**
* @brief Implement this method to store data in the storage of your choice.
*
* @param sample_seq Vector of SamplePtr objects containing the data to
* store. A SamplePtr is generally a DDS_DynamicData *, unless
* this is a discovery stream, in which case this is the builtin
* discovery type. Check the stream name to determine if this is a
* discovery stream.
* @param info_seq Vector of InfoType objects. An InfoType is a
* DDS_SampleInfo * cast to a void *.
*/
virtual void store(
const std::vector<SamplePtr>& sample_seq,
const std::vector<InfoPtr>& info_seq) = 0;
};
/** \ingroup RTI_RecordingServiceStorageModule
* class rti::recording::storage::TStorageStreamWriter
* @brief A templatized wrapping implementation of StorageStreamWriter,
* providing a strongly-typed interface regarding data and info representations.
*
* 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 TStorageStreamWriter : public StorageStreamWriter {
public:
/**
* @brief The data type
*/
typedef Data DataRep;
/**
* @brief The info type
*/
typedef Info InfoRep;
using StorageStreamWriter::store;
/**
* @brief Performs the conversion between the vector of data and info
* pointers to strongly-typed pointers.
*/
void store(
const std::vector<SamplePtr>& sample_seq,
const 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);
store(sample_seq_, info_seq_);
}
/**
* @brief Interface redefinition
*
* @see StorageStreamWriter::store
*/
virtual void store(
const std::vector<Data *>& sample_seq,
const std::vector<Info *>& info_seq) = 0;
/**
* @brief Virtual destructor
*/
virtual ~TStorageStreamWriter()
{
}
private:
std::vector<Data *> sample_seq_;
std::vector<Info *> info_seq_;
};
/** \ingroup RTI_RecordingServiceStorageModule
* @brief Convenience definition of typed StorageStreamWriter that requires
* dds::core::xtypes::DynamicData for data samples and dds::sub::SampleInfo
* for info samples.
*
*/
typedef TStorageStreamWriter<
dds::core::xtypes::DynamicData,
dds::sub::SampleInfo> DynamicDataStorageStreamWriter;
} } } // namespace rti::recording::storage
#endif /* HPP_RTI_RECORDING_STORAGE_STORAGESTREAMWRITER_HPP_ */
@@ -0,0 +1,201 @@
/*
* (c) Copyright, Real-Time Innovations, 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.
*/
#include "rti/recording/PropertySet.hpp"
#include "rti/recording/StreamInfo.hpp"
#include "rti/recording/storage/StorageStreamWriter.hpp"
#include "rti/recording/storage/StorageDiscoveryStreamWriter.hpp"
#include "dds/dds.hpp"
#ifndef HPP_RTI_RECORDING_STORAGE_STORAGEWRITER_HPP_
#define HPP_RTI_RECORDING_STORAGE_STORAGEWRITER_HPP_
/** @file
* @brief \product Pluggable Storage Writer API
*
* These APIs define a plugin that can be used by \product
* to store data.
*/
namespace rti { namespace recording { namespace storage {
/** \ingroup RTI_RecordingServiceStorageModule
* class rti::recording::storage::StorageWriter
* @brief Storage writer
*
* This class is responsible for creating StorageStreamWriters when notified
* that a new stream has been discovered. A stream is defined by a Topic/type
* combination
*/
class StorageWriter {
public:
/**
* @brief Constructor.
*
* Creates a StorageWriter object.
*
* @param properties Routing Service PropertySet. Contains name/value
* pairs that can be passed to the plugin in the XML, using the
* following snippet:
\verbatim
<recording_service name="ExampleRecorder">
<storage>
<plugin plugin_name="StorageLibrary::ExamplePlugin">
<!-- Storage properties. These are passed to the plugin in the
plugin_library -->
<property>
<value>
<element>
<name>example.filename</name>
<value>PluggableStorage.dat</value>
</element>
</value>
</property>
</plugin>
</storage>
</recording_service>
\endverbatim
*/
StorageWriter(const rti::recording::PropertySet& properties)
{
RTI_UNUSED_PARAMETER(properties);
}
/**
* @brief Virtual destructor
*/
virtual ~StorageWriter() {}
/**
* @brief \product calls this to create a user-data stream writer.
* The built-in DDS discovery topics can be recorded, however,
* \product will use the create_discovery_stream_writer() call to
* obtain a stream writer for those types.
* @param stream_info Information about the stream to be created, such as
* stream name (DDS topic name).
* @param properties A collection of value-pair properties. They include
* some built-in values, like:
* 1) name='rti.recording_service.domain_id'
* value=the DDS domain ID the stream was found in (32-bit integer
* as text)
*
* @see create_discovery_stream_writer
*/
virtual StorageStreamWriter * create_stream_writer(
const rti::recording::StreamInfo& stream_info,
const rti::recording::PropertySet& properties) = 0;
/**
* @brief \product calls this to create a stream writer for the DDS built-in
* topic DCPSParticipant.
* In order for the stream writer to be created, this function has to
* be implemented. Otherwise, no DCPSParticipant data will be
* recorded.
* @see ParticipantStorageWriter
*/
virtual ParticipantStorageWriter * create_participant_writer()
{
return NULL;
}
/**
* @brief \product calls this to create a stream writer for the DDS built-in
* topic DCPSPublication.
* In order for the stream writer to be created, this function has to
* be implemented. Otherwise, no DCPSPublication data will be
* recorded.
* @see PublicationStorageWriter
*/
virtual PublicationStorageWriter * create_publication_writer()
{
return NULL;
}
/**
* @brief \product calls this to create a stream writer for the DDS built-in
* topic DCPSSubscription.
* In order for the stream writer to be created, this function has to
* be implemented. Otherwise, no DCPSSubscription data will be
* recorded.
* @see SubscriptionStorageWriter
*/
virtual SubscriptionStorageWriter * create_subscription_writer()
{
return NULL;
}
/**
* @brief \product calls this to delete a stream writer. This method should
* be able to work with any stream, user-data or discovery.
*
* @param writer Stream Writer to be deleted.
*/
virtual void delete_stream_writer(StorageStreamWriter *writer) = 0;
private:
StorageWriter() {}
};
} } } /* namespace rti::recording::storage */
#include "rti/recording/storage/detail/StorageWriterForwarder.hpp"
#include "rti/routing/ServiceProperty.hpp"
#include "rti/routing/detail/ForwarderUtils.hpp"
/** \ingroup RTI_RecordingServiceStorageModule
* @def RTI_RECORDING_STORAGE_WRITER_CREATE_DECL
* @brief Convenience macro to declare the C-style function that will be called
* by \product to create your class
*
* This macro automatically declares a C wrapper function for your class
* creation. \product must be initialized
* with the name of this function. For example if your StorageWriter class is
* 'FileStorageWriter' this creates wrapper function called
* 'FileStorageWriter_get_storage_writer' that you must specify in your XML
* file, such as:
*
* \verbatim
<plugin_library name="StorageLibrary">
<storage_plugin name="ExamplePlugin">
<dll>FileStorageWriter</dll>
<create_function>FileStorageWriter_get_storage_writer</create_function>
</storage_plugin>
</plugin_library>
\endverbatim
*/
#define RTI_RECORDING_STORAGE_WRITER_CREATE_DECL(STORAGE_WRITER_CLASS) \
extern "C" RTI_USER_DLL_EXPORT \
struct RTI_RecordingServiceStorageWriter * \
STORAGE_WRITER_CLASS ## _get_storage_writer( \
const struct RTI_RoutingServiceProperties *);
/** \ingroup RTI_RecordingServiceStorageModule
* @brief Convenience macro to implement the C-style function that will be
* called by \product to create your class
*
* This macro automatically defines a C wrapper function for your class
* creation. \product must be initialized
* with the name of this function.
*/
#define RTI_RECORDING_STORAGE_WRITER_CREATE_DEF(STORAGE_WRITER_CLASS) \
struct RTI_RecordingServiceStorageWriter * \
STORAGE_WRITER_CLASS ## _get_storage_writer( \
const struct RTI_RoutingServiceProperties *native_properties) \
{ \
rti::recording::PropertySet properties; \
rti::routing::PropertyAdapter::add_properties_from_native( \
properties, \
native_properties); \
return new rti::recording::storage::detail::StorageWriterForwarder( \
new STORAGE_WRITER_CLASS(properties)); \
}
#endif /* HPP_RTI_RECORDING_STORAGE_STORAGEWRITER_HPP_ */
@@ -0,0 +1,177 @@
/*
* (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_RECORDING_STORAGE_DETAIL_STORAGE_READER_FORWARDER_HPP_
#define RTI_RECORDING_STORAGE_DETAIL_STORAGE_READER_FORWARDER_HPP_
#include "log/log_common.h"
#include "rti/routing/detail/ForwarderUtils.hpp"
#include "rti/routing/ServiceProperty.hpp"
#include "recordingservice/recordingservice_storagereader.h"
#include "rti/recording/storage/detail/StorageStreamReaderForwarder.hpp"
#include "StorageStreamInfoReaderForwarder.hpp"
namespace rti { namespace recording { namespace storage { namespace detail {
class StorageReaderForwarder : public RTI_RecordingServiceStorageReader {
public:
StorageReaderForwarder(StorageReader *storage_reader)
: storage_reader_(storage_reader)
{
create_stream_reader = StorageReaderForwarder::create_stream_reader_fwd;
delete_stream_reader = StorageReaderForwarder::delete_stream_reader_fwd;
create_stream_info_reader =
StorageReaderForwarder::create_stream_info_reader_fwd;
delete_stream_info_reader =
StorageReaderForwarder::delete_stream_info_reader_fwd;
delete_instance = StorageReaderForwarder::delete_instance_fwd;
storage_reader_data = this;
}
~StorageReaderForwarder()
{
}
static void delete_instance_fwd(
struct RTI_RecordingServiceStorageReader *storage_reader)
{
try {
StorageReaderForwarder *forwarder =
static_cast<StorageReaderForwarder *>(storage_reader);
delete forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
static RTI_RecordingServiceStorageStreamReader * create_stream_reader_fwd(
void *storage_reader,
const struct RTI_RoutingServiceStreamInfo *native_stream_info,
const struct RTI_RoutingServiceProperties *native_properties)
{
try {
StorageReaderForwarder *forwarder =
static_cast<StorageReaderForwarder *>(storage_reader);
rti::routing::StreamInfo stream_info(*native_stream_info);
rti::routing::PropertySet properties;
rti::routing::PropertyAdapter::add_properties_from_native(
properties,
native_properties);
StorageStreamReaderForwarder *stream_reader_forwarder =
new StorageStreamReaderForwarder(
forwarder->storage_reader_->create_stream_reader(
stream_info,
properties),
forwarder->storage_reader_.get());
return stream_reader_forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
return NULL;
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
return NULL;
}
static void delete_stream_reader_fwd(
void *,
RTI_RecordingServiceStorageStreamReader *storage_stream_reader)
{
try {
StorageStreamReaderForwarder *stream_reader_forwarder =
static_cast<StorageStreamReaderForwarder *>(
storage_stream_reader);
delete stream_reader_forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
static RTI_RecordingServiceStorageStreamInfoReader *
create_stream_info_reader_fwd(
void *storage_reader_data,
const struct RTI_RoutingServiceProperties *native_properties)
{
try {
StorageReaderForwarder *forwarder =
static_cast<StorageReaderForwarder *>(storage_reader_data);
rti::routing::PropertySet properties;
rti::routing::PropertyAdapter::add_properties_from_native(
properties,
native_properties);
StorageStreamInfoReaderForwarder *disc_reader_forwarder =
new StorageStreamInfoReaderForwarder(
forwarder->storage_reader_->create_stream_info_reader(
properties),
forwarder->storage_reader_.get());
return disc_reader_forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
return NULL;
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
return NULL;
}
static void delete_stream_info_reader_fwd(
void *,
RTI_RecordingServiceStorageStreamInfoReader *stream_info_reader)
{
try {
StorageStreamInfoReaderForwarder *disc_reader_forwarder =
static_cast<StorageStreamInfoReaderForwarder *>(
stream_info_reader);
delete disc_reader_forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
private:
std::shared_ptr<StorageReader> storage_reader_;
};
} } } }
#endif // RTI_RECORDING_STORAGE_DETAIL_STORAGE_WRITER_FORWARDER_HPP_
@@ -0,0 +1,239 @@
/*
* (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_RECORDING_STORAGE_DETAIL_STORAGE_DISC_STREAM_READER_FORWARDER_HPP_
#define RTI_RECORDING_STORAGE_DETAIL_STORAGE_DISC_STREAM_READER_FORWARDER_HPP_
#include <map>
#include <string>
#include "rti/recording/storage/StorageStreamInfoReader.hpp"
#include "log/log_common.h"
#include "recordingservice/recordingservice_storagereader.h"
#include <memory>
#include "rti/routing/detail/ForwarderUtils.hpp"
namespace rti { namespace recording { namespace storage { namespace detail {
/**
* The following class is a helper to be able to fully associate the life
* of the StorageStreamInfoReader object to a shared pointer, which will provide
* us with RAII capabilities.
*/
class StorageStreamInfoReaderDeleter {
public:
StorageStreamInfoReaderDeleter(StorageReader *storage_reader_parent)
: storage_reader_parent_(storage_reader_parent)
{
RTI_CHECK_PRECONDITION(storage_reader_parent != NULL);
}
void operator ()(StorageStreamInfoReader *stream_reader_instance)
{
RTI_CHECK_PRECONDITION(stream_reader_instance != NULL);
storage_reader_parent_->delete_stream_info_reader(
stream_reader_instance);
}
private:
StorageReader *storage_reader_parent_;
};
class StorageStreamInfoReaderForwarder :
public RTI_RecordingServiceStorageStreamInfoReader {
public:
StorageStreamInfoReaderForwarder(
StorageStreamInfoReader *stream_reader,
StorageReader *storage_reader_parent)
: storage_stream_reader_(
stream_reader,
StorageStreamInfoReaderDeleter(storage_reader_parent))
{
read = StorageStreamInfoReaderForwarder::read_fwd;
return_loan = StorageStreamInfoReaderForwarder::return_loan_fwd;
get_service_start_time =
StorageStreamInfoReaderForwarder::get_service_start_time_fwd;
get_service_stop_time =
StorageStreamInfoReaderForwarder::get_service_stop_time_fwd;
finished = StorageStreamInfoReaderForwarder::finished_fwd;
reset = StorageStreamInfoReaderForwarder::reset_fwd;
stream_reader_data = this;
}
~StorageStreamInfoReaderForwarder()
{
}
static void read_fwd(
void *stream_reader_data,
RTI_RoutingServiceStreamInfo ***stream_info_array,
int *array_length,
const struct RTI_RecordingServiceSelectorState *native_selector)
{
try {
StorageStreamInfoReaderForwarder *forwarder =
static_cast<StorageStreamInfoReaderForwarder *>(
stream_reader_data);
forwarder->storage_stream_reader_->read(
forwarder->sample_seq_,
SelectorState(*native_selector));
*array_length = static_cast<int>(forwarder->sample_seq_.size());
if (*array_length > 0) {
forwarder->native_sample_seq_.resize(*array_length);
for (size_t i = 0; i < forwarder->sample_seq_.size(); i++) {
forwarder->native_sample_seq_[i] =
&(forwarder->sample_seq_[i]->native());
}
*stream_info_array =
reinterpret_cast<RTI_RoutingServiceStreamInfo **>(
forwarder->native_sample_seq_.data());
}
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
static void return_loan_fwd(
void *stream_reader_data,
struct RTI_RoutingServiceStreamInfo **stream_info_array,
int array_length)
{
RTIOsapiUtility_unusedParameter(stream_info_array);
RTIOsapiUtility_unusedParameter(array_length);
try {
StorageStreamInfoReaderForwarder *forwarder =
static_cast<StorageStreamInfoReaderForwarder *>(
stream_reader_data);
// Deleting what's inside the vectors (dynamic data objects) and any
// related objects is responsability of the implementation
forwarder->storage_stream_reader_->return_loan(
forwarder->sample_seq_);
// Clear our internal containers
forwarder->sample_seq_.clear();
forwarder->native_sample_seq_.clear();
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
static long long get_service_start_time_fwd(void *stream_reader_data)
{
try {
StorageStreamInfoReaderForwarder *forwarder =
static_cast<StorageStreamInfoReaderForwarder *>(
stream_reader_data);
return (long long)
forwarder->storage_stream_reader_->service_start_time();
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
return 0;
}
static long long get_service_stop_time_fwd(void *stream_reader_data)
{
try {
StorageStreamInfoReaderForwarder *forwarder =
static_cast<StorageStreamInfoReaderForwarder *>(
stream_reader_data);
return (long long)
forwarder->storage_stream_reader_->service_stop_time();
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
return 0;
}
static int finished_fwd(void *stream_reader_data)
{
try {
StorageStreamInfoReaderForwarder *forwarder =
static_cast<StorageStreamInfoReaderForwarder *>(
stream_reader_data);
return (forwarder->storage_stream_reader_->finished() ?
RTI_TRUE :
RTI_FALSE);
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
return RTI_FALSE;
}
static void reset_fwd(void *stream_reader_data)
{
try {
StorageStreamInfoReaderForwarder *forwarder =
static_cast<StorageStreamInfoReaderForwarder *>(
stream_reader_data);
forwarder->storage_stream_reader_->reset();
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
StorageStreamInfoReader * stream_reader()
{
return storage_stream_reader_.get();
}
private:
std::shared_ptr<StorageStreamInfoReader> storage_stream_reader_;
std::vector<rti::routing::StreamInfo *> sample_seq_;
std::vector<RTI_RoutingServiceStreamInfo *> native_sample_seq_;
std::vector<int32_t> domain_id_seq_;
};
} } } } // rti::recording::storage::detail
#endif // RTI_RECORDING_STORAGE_DETAIL_STORAGE_DISC_STREAM_READER_FORWARDER_HPP_
@@ -0,0 +1,194 @@
/*
* (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_RECORDING_STORAGE_DETAIL_STORAGE_STREAM_READER_FORWARDER_HPP_
#define RTI_RECORDING_STORAGE_DETAIL_STORAGE_STREAM_READER_FORWARDER_HPP_
#include <map>
#include <string>
#include "log/log_common.h"
#include "recordingservice/recordingservice_storagereader.h"
#include <memory>
#include "rti/routing/detail/ForwarderUtils.hpp"
#include "rti/recording/storage/StorageDefs.hpp"
#include "rti/recording/storage/StorageStreamReader.hpp"
#include "rti/recording/storage/SelectorState.hpp"
namespace rti { namespace recording { namespace storage { namespace detail {
/**
* The following class is a helper to be able to fully associate the life
* of the StorageStreamReader object to a shared pointer, which will provide
* us with RAII capabilities.
*/
class StorageStreamReaderDeleter {
public:
StorageStreamReaderDeleter(StorageReader *storage_reader_parent)
: storage_reader_parent_(storage_reader_parent)
{
RTI_CHECK_PRECONDITION(storage_reader_parent != NULL);
}
void operator ()(StorageStreamReader *stream_reader_instance)
{
RTI_CHECK_PRECONDITION(stream_reader_instance != NULL);
storage_reader_parent_->delete_stream_reader(
stream_reader_instance);
}
private:
StorageReader *storage_reader_parent_;
};
class StorageStreamReaderForwarder :
public RTI_RecordingServiceStorageStreamReader {
public:
StorageStreamReaderForwarder(
StorageStreamReader *stream_reader,
StorageReader *storage_reader_parent)
: storage_stream_reader_(
stream_reader,
StorageStreamReaderDeleter(storage_reader_parent))
{
read = StorageStreamReaderForwarder::read_fwd;
return_loan = StorageStreamReaderForwarder::return_loan_fwd;
finished = StorageStreamReaderForwarder::finished_fwd;
reset = StorageStreamReaderForwarder::reset_fwd;
stream_reader_data = this;
}
~StorageStreamReaderForwarder()
{
}
static void read_fwd(
void *stream_reader_data,
RTI_RoutingServiceSample **sample_array,
RTI_RoutingServiceSampleInfo **sample_info_array,
int *array_length,
const struct RTI_RecordingServiceSelectorState *native_selector)
{
try {
StorageStreamReaderForwarder *forwarder =
static_cast<StorageStreamReaderForwarder *>(
stream_reader_data);
forwarder->storage_stream_reader_->read(
forwarder->sample_seq_,
forwarder->info_seq_,
SelectorState(*native_selector));
*array_length = static_cast<int>(forwarder->sample_seq_.size());
if (*array_length > 0) {
*sample_array = forwarder->sample_seq_.data();
*sample_info_array = forwarder->info_seq_.data();
}
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
static void return_loan_fwd(
void *stream_reader_data,
RTI_RoutingServiceSample *sample_array,
RTI_RoutingServiceSampleInfo *sample_info_array,
int array_length)
{
RTIOsapiUtility_unusedParameter(sample_array);
RTIOsapiUtility_unusedParameter(sample_info_array);
RTIOsapiUtility_unusedParameter(array_length);
try {
StorageStreamReaderForwarder *forwarder =
static_cast<StorageStreamReaderForwarder *>(
stream_reader_data);
// Deleting what's inside the vectors (dynamic data objects) and any
// related objects is responsability of the implementation
forwarder->storage_stream_reader_->return_loan(
forwarder->sample_seq_,
forwarder->info_seq_);
// Clear our internal containers
forwarder->sample_seq_.clear();
forwarder->info_seq_.clear();
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
static int finished_fwd(void *stream_reader_data)
{
try {
StorageStreamReaderForwarder *forwarder =
static_cast<StorageStreamReaderForwarder *>(
stream_reader_data);
return (forwarder->storage_stream_reader_->finished() ?
RTI_TRUE :
RTI_FALSE);
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
return RTI_FALSE;
}
static void reset_fwd(void *stream_reader_data)
{
try {
StorageStreamReaderForwarder *forwarder =
static_cast<StorageStreamReaderForwarder *>(
stream_reader_data);
forwarder->storage_stream_reader_->reset();
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
StorageStreamReader * stream_reader()
{
return storage_stream_reader_.get();
}
private:
std::shared_ptr<StorageStreamReader> storage_stream_reader_;
std::vector<StorageStreamReader::SamplePtr> sample_seq_;
std::vector<StorageStreamReader::InfoPtr> info_seq_;
};
} } } } // rti::recording::storage::detail
#endif // RTI_RECORDING_STORAGE_DETAIL_STORAGE_STREAM_READER_FORWARDER_HPP_
@@ -0,0 +1,268 @@
/*
* (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_RECORDING_STORAGE_DETAIL_STORAGE_STREAM_WRITER_FORWARDER_HPP_
#define RTI_RECORDING_STORAGE_DETAIL_STORAGE_STREAM_WRITER_FORWARDER_HPP_
#include <map>
#include <string>
#include "log/log_common.h"
#include "recordingservice/recordingservice_storagewriter.h"
#include <memory>
#include "rti/routing/detail/ForwarderUtils.hpp"
#include "rti/recording/storage/StorageStreamWriter.hpp"
namespace rti { namespace recording { namespace storage { namespace detail {
/**
* The following class is a helper to be able to fully associate the life
* of the StorageStreamWriter object to a shared pointer, which will provide
* us with RAII capabilities.
*/
class StorageStreamWriterDeleter {
public:
StorageStreamWriterDeleter(StorageWriter *storage_writer_parent)
: storage_writer_parent_(storage_writer_parent)
{
RTI_CHECK_PRECONDITION(storage_writer_parent != NULL);
}
void operator ()(StorageStreamWriter *stream_writer_instance)
{
if (stream_writer_instance != NULL) {
storage_writer_parent_->delete_stream_writer(
stream_writer_instance);
}
}
private:
StorageWriter *storage_writer_parent_;
};
class StorageStreamWriterForwarder :
public RTI_RecordingServiceStorageStreamWriter {
public:
StorageStreamWriterForwarder(
StorageStreamWriter *stream_writer,
StorageWriter *storage_writer_parent)
: storage_stream_writer_(
stream_writer,
StorageStreamWriterDeleter(storage_writer_parent))
{
store = StorageStreamWriterForwarder::store_fwd;
stream_writer_data = this;
}
~StorageStreamWriterForwarder()
{
}
static void store_fwd(
void *stream_writer_data,
const RTI_RoutingServiceSample *samples,
const RTI_RoutingServiceSampleInfo *sample_infos,
const int count)
{
try {
StorageStreamWriterForwarder *forwarder =
static_cast<StorageStreamWriterForwarder *>(
stream_writer_data);
// Fill in internal vector with incoming samples
forwarder->sample_seq_.assign(samples, samples + count);
// Fill in internal vector with incoming sample infos, the sample
// info array is optional so check for validity before doing
// anything
if (sample_infos != NULL) {
forwarder->info_seq_.assign(sample_infos, sample_infos + count);
}
// Forward the call to the StorageStreamWriter implementation
forwarder->storage_stream_writer_->store(
forwarder->sample_seq_,
forwarder->info_seq_);
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
StorageStreamWriter * stream_writer()
{
return storage_stream_writer_.get();
}
private:
std::shared_ptr<StorageStreamWriter> storage_stream_writer_;
std::vector<StorageStreamWriter::SamplePtr> sample_seq_;
std::vector<StorageStreamWriter::InfoPtr> info_seq_;
};
/**
* This generic forwarding wrapper class defines a store method that forwards a
* call to a native stream writer's store method to a C++ stream writer
* specialisation.
* Two template parameters:
* - NativeStreamWriterType: one of the native stream writer types defined
* in recordingservice_storagewriter.h. These types have to implement a
* store() method to store the samples.
* - NativeStoredType: the type passed in to the store() method.
*/
template<typename NativeStreamWriterType, typename NativeStoredType>
class StorageGenericStreamWriterForwarder : public NativeStreamWriterType {
public:
StorageGenericStreamWriterForwarder(
StorageStreamWriter *stream_writer,
StorageWriter *storage_writer_parent)
: storage_stream_writer_(
stream_writer,
StorageStreamWriterDeleter(storage_writer_parent))
{
}
~StorageGenericStreamWriterForwarder()
{
}
static void store_fwd(
void *stream_writer_data,
const NativeStoredType **samples,
const RTI_RoutingServiceSampleInfo *sample_infos,
const int count)
{
try {
StorageGenericStreamWriterForwarder *forwarder =
static_cast<StorageGenericStreamWriterForwarder *>(
stream_writer_data);
/*
* In the case of the generic stream writer forwarder, used for the
* built-in DDS discovery topics, we are not guaranteed that the
* stream writer will not be null. This can happen if the user
* doesn't override the default implementations, which return null.
* The user may not have interest in recording one or any of the
* topics. We should account for that case.
*/
if (forwarder->storage_stream_writer_.get() == NULL) {
return;
}
// Fill in internal vector with incoming samples
StorageStreamWriter::SamplePtr *untyped_samples =
(StorageStreamWriter::SamplePtr *) samples;
forwarder->sample_seq_.assign(
untyped_samples,
untyped_samples + count);
/*
* Fill in internal vector with incoming sample infos, the sample
* info array is optional so check for validity before doing
* anything
*/
if (sample_infos != NULL) {
forwarder->info_seq_.assign(sample_infos, sample_infos + count);
}
// Forward the call to the StorageStreamWriter implementation
forwarder->storage_stream_writer_->store(
forwarder->sample_seq_,
forwarder->info_seq_);
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
StorageStreamWriter * stream_writer()
{
return storage_stream_writer_.get();
}
private:
std::shared_ptr<StorageStreamWriter> storage_stream_writer_;
std::vector<StorageStreamWriter::SamplePtr> sample_seq_;
std::vector<StorageStreamWriter::InfoPtr> info_seq_;
};
class StorageParticipantWriterForwarder :
public StorageGenericStreamWriterForwarder<
RTI_RecordingServiceStorageParticipantWriter,
DDS_ParticipantBuiltinTopicData> {
public:
StorageParticipantWriterForwarder(
StorageStreamWriter *stream_writer,
StorageWriter *storage_writer_parent) :
StorageGenericStreamWriterForwarder<
RTI_RecordingServiceStorageParticipantWriter,
DDS_ParticipantBuiltinTopicData>(
stream_writer,
storage_writer_parent)
{
store = store_fwd;
stream_writer_data = this;
}
};
class StoragePublicationWriterForwarder :
public StorageGenericStreamWriterForwarder<
RTI_RecordingServiceStoragePublicationWriter,
DDS_PublicationBuiltinTopicData> {
public:
StoragePublicationWriterForwarder(
StorageStreamWriter *stream_writer,
StorageWriter *storage_writer_parent) :
StorageGenericStreamWriterForwarder<
RTI_RecordingServiceStoragePublicationWriter,
DDS_PublicationBuiltinTopicData>(
stream_writer,
storage_writer_parent)
{
store = store_fwd;
stream_writer_data = this;
}
};
class StorageSubscriptionWriterForwarder :
public StorageGenericStreamWriterForwarder<
RTI_RecordingServiceStorageSubscriptionWriter,
DDS_SubscriptionBuiltinTopicData> {
public:
StorageSubscriptionWriterForwarder(
StorageStreamWriter *stream_writer,
StorageWriter *storage_writer_parent) :
StorageGenericStreamWriterForwarder<
RTI_RecordingServiceStorageSubscriptionWriter,
DDS_SubscriptionBuiltinTopicData>(
stream_writer,
storage_writer_parent)
{
store = store_fwd;
stream_writer_data = this;
}
};
} } } } // rti::recording::storage::detail
#endif // RTI_RECORDING_STORAGE_DETAIL_STORAGE_STREAM_WRITER_FORWARDER_HPP_
@@ -0,0 +1,270 @@
/*
* (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_RECORDING_STORAGE_DETAIL_STORAGE_WRITER_FORWARDER_HPP_
#define RTI_RECORDING_STORAGE_DETAIL_STORAGE_WRITER_FORWARDER_HPP_
#include <map>
#include <string>
#include "log/log_common.h"
#include "rti/routing/detail/ForwarderUtils.hpp"
#include "rti/routing/ServiceProperty.hpp"
#include "recordingservice/recordingservice_storagewriter.h"
#include "rti/recording/storage/StorageDefs.hpp"
#include "rti/recording/storage/detail/StorageStreamWriterForwarder.hpp"
namespace rti { namespace recording { namespace storage { namespace detail {
class StorageWriterForwarder : public RTI_RecordingServiceStorageWriter {
public:
StorageWriterForwarder(StorageWriter *storage_writer) :
storage_writer_(storage_writer)
{
// User-data stream creation function
create_stream_writer = StorageWriterForwarder::create_stream_writer_fwd;
// Discovery stream creation functions
create_participant_writer =
StorageWriterForwarder::create_participant_writer_fwd;
create_publication_writer =
StorageWriterForwarder::create_publication_writer_fwd;
create_subscription_writer =
StorageWriterForwarder::create_subscription_writer_fwd;
// User-data stream deletion function
delete_stream_writer = StorageWriterForwarder::delete_stream_writer_fwd;
// Discovery stream deletion functions
delete_participant_writer =
StorageWriterForwarder::delete_participant_writer_fwd;
delete_publication_writer =
StorageWriterForwarder::delete_publication_writer_fwd;
delete_subscription_writer =
StorageWriterForwarder::delete_subscription_writer_fwd;
// Delete storage writer instance method
delete_instance = StorageWriterForwarder::delete_instance_fwd;
storage_writer_data = this;
}
~StorageWriterForwarder()
{
}
static void delete_instance_fwd(
struct RTI_RecordingServiceStorageWriter *storage_writer)
{
try {
StorageWriterForwarder *forwarder =
static_cast<StorageWriterForwarder *>(storage_writer);
delete forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
static RTI_RecordingServiceStorageStreamWriter * create_stream_writer_fwd(
void *storage_writer,
const RTI_RoutingServiceStreamInfo *native_stream_info,
const RTI_RoutingServiceProperties *native_properties)
{
RTI_CHECK_PRECONDITION(!rti::recording::is_discovery_stream(
std::string(native_stream_info->stream_name)));
try {
StorageWriterForwarder *forwarder =
static_cast<StorageWriterForwarder *>(storage_writer);
rti::routing::StreamInfo stream_info(*native_stream_info);
rti::routing::PropertySet properties;
rti::routing::PropertyAdapter::add_properties_from_native(
properties,
native_properties);
StorageStreamWriterForwarder *stream_writer_forwarder =
new StorageStreamWriterForwarder(
forwarder->storage_writer_->create_stream_writer(
stream_info,
properties),
forwarder->storage_writer_.get());
return stream_writer_forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
return NULL;
}
static RTI_RecordingServiceStorageParticipantWriter *
create_participant_writer_fwd(void *storage_writer)
{
try {
StorageWriterForwarder *forwarder =
static_cast<StorageWriterForwarder *>(storage_writer);
StorageParticipantWriterForwarder *stream_writer_forwarder =
new StorageParticipantWriterForwarder(
forwarder->storage_writer_->create_participant_writer(),
forwarder->storage_writer_.get());
return stream_writer_forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
return NULL;
}
static RTI_RecordingServiceStoragePublicationWriter *
create_publication_writer_fwd(void *storage_writer)
{
try {
StorageWriterForwarder *forwarder =
static_cast<StorageWriterForwarder *>(storage_writer);
StoragePublicationWriterForwarder *stream_writer_forwarder =
new StoragePublicationWriterForwarder(
forwarder->storage_writer_->create_publication_writer(),
forwarder->storage_writer_.get());
return stream_writer_forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
return NULL;
}
static RTI_RecordingServiceStorageSubscriptionWriter *
create_subscription_writer_fwd(void *storage_writer)
{
try {
StorageWriterForwarder *forwarder =
static_cast<StorageWriterForwarder *>(storage_writer);
StorageSubscriptionWriterForwarder *stream_writer_forwarder =
new StorageSubscriptionWriterForwarder(
forwarder->storage_writer_->create_subscription_writer(),
forwarder->storage_writer_.get());
return stream_writer_forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
return NULL;
}
static void delete_stream_writer_fwd(
void *,
RTI_RecordingServiceStorageStreamWriter *storage_stream_writer)
{
try {
StorageStreamWriterForwarder *stream_writer_forwarder =
static_cast<StorageStreamWriterForwarder *>(
storage_stream_writer);
delete stream_writer_forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
static void delete_participant_writer_fwd(
void *,
RTI_RecordingServiceStorageParticipantWriter *stream_writer)
{
try {
StorageParticipantWriterForwarder *forwarder =
static_cast<StorageParticipantWriterForwarder *>(
stream_writer);
delete forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
static void delete_publication_writer_fwd(
void *,
RTI_RecordingServiceStoragePublicationWriter *stream_writer)
{
try {
StoragePublicationWriterForwarder *forwarder =
static_cast<StoragePublicationWriterForwarder *>(
stream_writer);
delete forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
static void delete_subscription_writer_fwd(
void *,
RTI_RecordingServiceStorageSubscriptionWriter *stream_writer)
{
try {
StorageSubscriptionWriterForwarder *forwarder =
static_cast<StorageSubscriptionWriterForwarder *>(
stream_writer);
delete forwarder;
} catch (const std::exception& ex) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
ex.what());
} catch (...) {
RecorderPrint_exception(
&RTI_LOG_ANY_s,
"unknown exception");
}
}
private:
std::shared_ptr<StorageWriter> storage_writer_;
};
} } } } // rti::recording::storage::namespace
#endif // RTI_RECORDING_STORAGE_DETAIL_STORAGE_WRITER_FORWARDER_HPP_
@@ -0,0 +1,426 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_ENTITY_LISTENER_HPP_
#define RTI_ROUTING_ENTITY_LISTENER_HPP_
#include "routingservice/routingservice_service_impl.h"
#include <rti/apputils/ServiceException.hpp>
#include <rti/apputils/log/LogConfig.hpp>
#include <rti/routing/StreamInfo.hpp>
namespace rti { namespace routing {
/**
*/
struct EntityKind_def {
/**
* @brief The underlying \p enum type
*/
enum type {
SERVICE = RTI_ROUTING_SERVICE_SERVICE_ENTITY,
DOMAIN_ROUTE = RTI_ROUTING_SERVICE_DOMAIN_ROUTE_ENTITY,
CONNECTION = RTI_ROUTING_SERVICE_CONNECTION_ENTITY,
SESSION = RTI_ROUTING_SERVICE_SESSION_ENTITY,
AUTO_TOPIC_ROUTE = RTI_ROUTING_SERVICE_AUTO_TOPIC_ROUTE_ENTITY,
TOPIC_ROUTE = RTI_ROUTING_SERVICE_TOPIC_ROUTE_ENTITY,
INPUT = RTI_ROUTING_SERVICE_INPUT_ENTITY,
OUTPUT = RTI_ROUTING_SERVICE_OUTPUT_ENTITY,
count_
};
};
/**
*/
typedef dds::core::safe_enum<EntityKind_def> EntityKind;
/**
*/
struct EntityStateKind_def {
/**
* @brief The underlying \p enum type
*/
enum type {
INVALID = RTI_SERVICE_INVALID_ENTITY_STATE,
ENABLED = RTI_SERVICE_ENABLED_ENTITY_STATE,
DISABLED = RTI_SERVICE_DISABLED_ENTITY_STATE,
STARTED = RTI_SERVICE_STARTED_ENTITY_STATE,
STOPPED = RTI_SERVICE_STOPPED_ENTITY_STATE,
RUNNING = RTI_SERVICE_RUNNING_ENTITY_STATE,
PAUSED = RTI_SERVICE_PAUSED_ENTITY_STATE
};
};
typedef dds::core::safe_enum<EntityStateKind_def> EntityStateKind;
/*
* @brief string representation of EntityStateKind
*/
inline
const std::string to_string(const rti::routing::EntityStateKind& kind)
{
static const char * ENTITY_STATE_KIND_AS_STRING[] = {
"INVALID",
"ENABLED",
"DISABLED",
"STARTED",
"STOPPED",
"RUNNING",
"PAUSED"
};
return ENTITY_STATE_KIND_AS_STRING[kind.underlying()];
}
inline
const char* to_action_native_string(const rti::routing::EntityStateKind& kind)
{
static const char * ENTITY_STATE_ACTION_AS_STRING[] = {
"INVALID",
"ENABLE",
"DISABLE",
"START",
"STOP",
"RUN",
"PAUSE"
""
};
return ENTITY_STATE_ACTION_AS_STRING[kind.underlying()];
}
inline
const std::string to_action_string(const rti::routing::EntityStateKind& kind)
{
return to_action_native_string(kind);
}
class EntityListener {
public:
class Context {
public:
friend EntityListener::Context from_native(
RTI_RoutingServiceEntityListenerContext*);
const rti::routing::EntityKind& entity_kind() const
{
return entity_kind_;
}
const std::string& entity_name() const
{
return entity_name_;
}
const rti::routing::EntityStateKind& entity_state_kind() const
{
return entity_state_kind_;
}
bool ok()
{
return ok_;
}
rti::advlog::Entries logging_context_entries()
{
return logging_context_entries_;
}
private:
rti::routing::EntityKind entity_kind_;
std::string entity_name_;
rti::routing::EntityStateKind entity_state_kind_;
bool ok_;
/*
* We need to keep the entries of the context because they are entered
* in a function and left in another function.
* The number of entries is two:
* - An entry for the resource.
* - An entry for the activity.
*
* Recorder:
* - The entries are entered into the context using the macro
* RTI_ENTITY_LISTENER_CONTEXT_ENTER_ON_BEFORE in a function.
* - The entries are left using the macro
* RTI_ENTITY_LISTENER_CONTEXT_LEAVE_ON_AFTER in another function.
*
* For example:
* - Enter in EntityListener::on_before_create
* - Leave in EntityListener::on_after_create
*/
rti::advlog::Entries logging_context_entries_;
};
virtual void on_before_create( EntityListener::Context&)
{
}
virtual void on_after_create(EntityListener::Context&)
{
}
virtual void on_before_state_change(EntityListener::Context&)
{
}
virtual void on_after_state_change(EntityListener::Context&)
{
}
virtual void on_before_delete(EntityListener::Context&)
{
}
virtual void on_after_delete(EntityListener::Context&)
{
}
virtual void on_before_stream_event(
EntityListener::Context&,
const rti::routing::StreamInfo&)
{
}
virtual void on_after_stream_event(
EntityListener::Context&,
const rti::routing::StreamInfo&)
{
}
virtual ~EntityListener() {}
};
inline
EntityListener::Context from_native(
RTI_RoutingServiceEntityListenerContext *native)
{
EntityListener::Context context;
context.entity_kind_ = static_cast<EntityKind::type> (
native->entity_kind);
context.entity_name_ = native->entity_name;
context.entity_state_kind_ = static_cast<EntityStateKind::type> (
native->entity_state_kind);
context.ok_ = native->ok ? true : false;
context.logging_context_entries_.from_native(
native->logging_context_entries,
native->logging_context_params);
return context;
}
class EntityListenerForwarder {
public:
typedef RTI_RoutingServiceEntityListener native;
static native create(
EntityListener *listener)
{
native native_listener = RTI_RoutingServiceEntityListener_INITIALIZER;
native_listener.on_before_create =
on_before_create_forwarder;
native_listener.on_after_create =
on_after_create_forwarder;
native_listener.on_before_state_change =
on_before_state_change_forwarder;
native_listener.on_after_state_change =
on_after_state_change_forwarder;
native_listener.on_before_delete =
on_before_delete_forwarder;
native_listener.on_after_delete =
on_after_delete_forwarder;
native_listener.on_before_stream_event =
on_before_stream_event_forwarder;
native_listener.on_after_stream_event =
on_after_stream_event_forwarder;
native_listener.listener_data = static_cast<void*>(listener);
return native_listener;
}
private:
static void on_before_create_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_before_create(context);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_after_create_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_after_create(context);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_before_state_change_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_before_state_change(context);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_after_state_change_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_after_state_change(context);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_before_delete_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_before_delete(context);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_after_delete_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_after_delete(context);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_before_stream_event_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native,
const RTI_RoutingServiceStreamInfo *stream_info)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_before_stream_event(
context,
*stream_info);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
static void on_after_stream_event_forwarder(
void *listener_data,
RTI_RoutingServiceEntityListenerContext *context_native,
const RTI_RoutingServiceStreamInfo *stream_info)
{
EntityListener *listener =
static_cast<EntityListener *>(listener_data);
try {
EntityListener::Context context =
rti::routing::from_native(context_native);
listener->on_after_stream_event(
context,
*stream_info);
} catch (rti::apputils::ServiceException& ex) {
SERVICELog_fromException(ex);
} catch (std::exception& ex) {
SERVICELog_exception(&RTI_LOG_ANY_s, ex.what());
} catch (...) {
SERVICELog_exception(&RTI_LOG_UNEXPECTED_EXCEPTION);
}
}
};
}}
#endif // RTI_ROUTING_ENTITY_LISTENER_HPP_
@@ -0,0 +1,219 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_LOGGER_HPP_
#define RTI_ROUTING_LOGGER_HPP_
#include <dds/core/Reference.hpp>
#include <rti/config/Logger.hpp>
#include "routingservice/routingservice_log.h"
#include "routingservice/routingservice_service.h"
namespace rti { namespace routing {
/** \ingroup RTI_RoutingServiceLibModule
*
* @brief The singleton type used to configure @product verbosity
*
* For configuring other aspects such as output file, print format or
* RTI Connext specific logging, use rti::config::Logger.
*/
class Logger
{
public:
typedef rti::config::Verbosity Verbosity;
typedef rti::config::LogCategory LogCategory;
typedef rti::config::PrintFormat PrintFormat;
static Logger& instance()
{
static Logger singleton;
return singleton;
}
/**
* @brief Sets the verbosity for the log messages generated at the
* @product level.
*
* @param verbosity
* @rs_st_in The verbosity of the service logs
*/
void service_verbosity(rti::config::Verbosity verbosity)
{
NDDS_Config_Logger_set_verbosity_by_service(
NDDS_Config_Logger_get_instance(),
NDDS_CONFIG_LOG_SERVICE_ROUTING,
static_cast<NDDS_Config_LogVerbosity>(verbosity.underlying()));
}
/**
* @brief Getter for the same attribute
*
* @see service_verbosity(rti::config::Verbosity)
*/
rti::config::Verbosity service_verbosity()
{
RTILogBitmap instrumentation_mask =
NDDS_Config_Logger_get_verbosity_by_service(
NDDS_Config_Logger_get_instance(),
NDDS_CONFIG_LOG_SERVICE_ROUTING);
return static_cast<rti::config::Verbosity::type>(instrumentation_mask);
}
/**
* @brief Logs as message with EXCEPTION level
*
* The generated log will be part of logging stream of the running service
* if the service verbosity contains EXCEPTION messages. The result log
* message may include additional information according to the
* Connext logging configuration, such as Advlog Context, thread ID,
* line number, etc. Additionally, the result log message will contain a
* newline character at the end, so the format does not need to contain it.
*
* @param[in] msg Message to be logged
*/
void error(const std::string& msg)
{
this->error(msg.c_str());
}
/**
* @brief overload of error(const std::string& msg)
*/
void error(const char *msg)
{
this->message(rti::config::LogLevel::EXCEPTION, msg);
}
/**
* @brief Logs as message with WARNING level
*
* This operation behaves similar to error() except the log level is
* WARNING.
*
* @param[in] msg Message to be logged
*
* @see rti::routing::Logger::error
*
*/
void warn(const std::string& msg)
{
this->warn(msg.c_str());
}
/**
* @brief overload of warn(const std::string& msg)
*/
void warn(const char *msg)
{
this->message(rti::config::LogLevel::WARNING, msg);
}
/**
* @brief Logs as message with WARNING level
*
* This operation behaves similar to error() except the log level is
* STATUS_LOCAL.
*
* @param[in] msg Message to be logged
*
* @see rti::routing::Logger::error
*
*/
void local(const std::string& msg)
{
this->local(msg.c_str());
}
/**
* @brief overload of local(const std::string& msg)
*/
void local(const char *msg)
{
this->message(rti::config::LogLevel::STATUS_LOCAL, msg);
}
/**
* @brief Logs as message with WARNING level
*
* This operation behaves similar to error() except the log level is
* STATUS_REMOTE.
*
* @param[in] msg Message to be logged
*
* @see rti::routing::Logger::error
*
*/
void remote(const std::string& msg)
{
this->remote(msg.c_str());
}
/**
* @brief overload of remote(const std::string& msg)
*/
void remote(const char *msg)
{
this->message(rti::config::LogLevel::STATUS_REMOTE, msg);
}
/**
* @brief Logs as message with WARNING level
*
* This operation behaves similar to error() except the log level is
* STATUS_DEBUG.
*
* @param[in] msg Message to be logged
*
* @see rti::routing::Logger::error
*
*/
void debug(const std::string& msg)
{
this->debug(msg.c_str());
}
/**
* @brief overload of debug(const std::string& msg)
*/
void debug(const char *msg)
{
this->message(rti::config::LogLevel::STATUS_ALL, msg);
}
virtual ~Logger()
{
}
private:
void message(const rti::config::LogLevel& level, const char* msg)
{
RTI_RoutingServiceLogger_log(
static_cast<NDDS_Config_LogLevel> (level.underlying()),
"%s",
msg);
}
Logger()
{
}
// Disable copy
Logger(const Logger&);
Logger& operator=(const Logger&);
};
}}
#endif // RTI_ROUTING_LOGGER_HPP_
@@ -0,0 +1,64 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_PROPERTY_SET_HPP_
#define RTI_ROUTING_PROPERTY_SET_HPP_
#include <map>
#include "routingservice/routingservice_infrastructure.h"
#include <rti/config/Version.hpp>
namespace rti { namespace routing {
inline
std::string app_name_property_name()
{
return RTI_ROUTING_SERVICE_APP_NAME_PROPERTY_NAME;
}
inline
std::string group_name_property_name()
{
return RTI_ROUTING_SERVICE_GROUP_PROPERTY_NAME;
}
inline
std::string version_property_name()
{
return RTI_ROUTING_SERVICE_VERSION_PROPERTY_NAME;
}
inline
std::string verbosity_property_name()
{
return RTI_ROUTING_SERVICE_VERBOSITY_PROPERTY_NAME;
}
inline
std::string entity_resource_name_property_name()
{
return RTI_ROUTING_SERVICE_ENTITY_RESOURCE_NAME_PROPERTY_NAME;
}
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
* @brief The definition of a pluggable entity’s configuration properties.
*
* Configuration properties for an entity are obtained as a result of parsing
* the &lt;property&gt; corresponding to each pluggable entity. The result is a
* map keyed by property name, represented as std::string, whose values are
* the property values, also represented as std::string. Hence, a property name
* shall be unique for each set of entity properties.
*/
typedef std::map<std::string,std::string> PropertySet;
}}
#endif // RTI_ROUTING_PROPERTY_SET_HPP_
@@ -0,0 +1,17 @@
/*
* (c) Copyright, Real-Time Innovations, 2021.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_ROUTING_SERVICE_HPP_
#define RTI_ROUTING_ROUTING_SERVICE_HPP_
#include <rti/routing/Service.hpp>
#endif // RTI_ROUTING_ROUTING_SERVICE_HPP_
@@ -0,0 +1,404 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_SERVICE_HPP_
#define RTI_ROUTING_SERVICE_HPP_
#include <dds/core/Reference.hpp>
#include <rti/config/Logger.hpp>
#include "routingservice/routingservice_adapter_new.h"
#include <rti/routing/Logger.hpp>
#include <rti/routing/ServiceProperty.hpp>
#include <rti/routing/detail/RoutingServiceImpl.hpp>
#include <rti/routing/adapter/AdapterPlugin.hpp>
#include <rti/routing/processor/ProcessorPlugin.hpp>
namespace rti { namespace routing {
/*e \defgroup RTI_RoutingServiceLibModule RTI Routing Library API
* \ingroup ROUTER
*
* @brief @product can be deployed as a native library linked into your
* application in select architectures.
*
* This API allows you to create, configure and start @product instances from
* your application.
*
* The following code shows the typical use of the API:
*
* \code
*
* int main ()
* {
* rti::routing::Service service(
* rti::routing::ServiceProperty()
* .cfg_file("MyRouter.xml")
* .cfg_name("MyRouter"));
* ...
*
* service.start();
*
* while(keep_running) {
* sleep();
* ...
* }
*
* return 0;
* }
*
* \endcode
*
* Instead of a file, you can use XML strings to configure @product.
* See ServiceProperty for more information.
* <p>
* To build your application you need to link with the @product native library
* in <b> &lt;@ndds home&gt;/bin/&lt;architecture&gt;/ </b>.
*
* ### Development Requirements
*
* | | Linux/macOS Systems | Windows Systems |
* | --------------: | :----------------: | :-------------: |
* | Shared Libraries| libnddscpp2.so | nddscpp2.dll |
* | ^ | librtirsinfrastructure.so | rtirsinfrastructure.dll |
* | ^ | librtiserviceadmincpp.so | rtiserviceadmincpp.dll |
* | ^ | librtidlc.so | rtidlc.dll |
* | ^ | librtiapputilsc.so | rtiapputilsc.dll |
* | ^ | libnddsmetp.so | nddsmetp.dll |
* | ^ | librticonnextmsgc.so | rticonnextmsgc.dll |
* | ^ | libnddsc.so | nddsc.dll |
* | ^ | librtixml2.so | rtixml2.dll |
* | ^ | libnddscore.so | nddscore.dll |
* | Headers | rti/routing/RoutingService.hpp ||
*
*/
/** \ingroup RTI_RoutingServiceLibModule
*
* @brief The @product.
*
*/
class Service : public dds::core::Reference<RoutingServiceImpl> {
public:
typedef RTI::Service::Admin::CommandRequest CommandRequest;
typedef RTI::Service::Admin::CommandReply CommandReply;
typedef dds::core::Reference<RoutingServiceImpl> Base;
OMG_DDS_REF_TYPE_NOTYPENAME(
Service,
dds::core::Reference,
RoutingServiceImpl);
/**
* @brief Creates a @product instance
*
* @param property
* @rs_st_in The property to configure @product instance.
*
* @mtsafety On non-Linux, non-Windows systems (i.e. VxWorks):
* UNSAFE for multiple threads to simultaneously make the FIRST
* call to any of the Service constructors. Subsequent calls are
* thread safe.
* On Windows and Linux systems, these calls are thread-safe.
*/
explicit Service(const ServiceProperty& property)
: Base(new RoutingServiceImpl(property))
{
this->delegate()->remember_reference(this->delegate());
}
/**
* @brief Creates a @product instance
*
* A callable shutdown hook can optionally be provided to handle the
* shutdown command received through remote administration. Upon reception
* of this command, @product will notify the installed hook.
*
* The following example shows simple implementation of a shutdown hook
* that sets a boolean flag to true when invoked:
*
* \code
*
* // Hook implementation
* struct FlagShutdownHook {
* public:
* FlagShutdownHook(bool& the_flag) : flag(the_flag) {
* flag = false;
* }
* void operator()() {
* flag = true;
* }
*
* bool& flag;
* };
*
* // Instantiate service with hook
* bool my_flag;
* FlagShutdownHook my_hook(my_flag)
* rti::routing::Service routing_service(
* property,
* my_hook);
* ...
*
*
* \endcode
*
*
* @param[in] property
* The property to configure @product instance.
*
* @param[in] shutdown_hook
* Callable object to handle the shutdown command. The expected
* type is a void operator()() (C++11 equivalent is
* std::function<void()>)
*
* @mtsafety On non-Linux, non-Windows systems (i.e. VxWorks):
* UNSAFE for multiple threads to simultaneously make the FIRST
* call to any of the Service constructors. Subsequent calls are
* thread safe.
* On Windows and Linux systems, these calls are thread-safe.
*/
template <typename HookFunc>
Service(
const ServiceProperty& property,
HookFunc& shutdown_hook)
: Base(new RoutingServiceImpl(property, shutdown_hook))
{
this->delegate()->remember_reference(this->delegate());
}
Service(const RTI_RoutingServiceProperty& property)
: Base(new RoutingServiceImpl(property))
{
this->delegate()->remember_reference(this->delegate());
}
explicit Service(Base::DELEGATE_REF_T reference) : Base(reference)
{
if (this->delegate()) {
this->delegate()->remember_reference(this->delegate());
}
}
/**
* @brief Starts @product.
*
* This is a non-blocking operation. @product will create its own set of
* threads to perform its tasks.
*/
void start()
{
this->delegate()->start();
}
/**
* @brief Stops @product.
*
* This operation will bloc the instance is fully stopped.
*/
void stop()
{
this->delegate()->stop();
}
/**
* @brief Attaches an Adapter plugin to be used by @product when it is
* started.
*
* By using this function an adapter can be statically compiled, created
* in your application and have the service load it, instead of registering
* a shared library and a create function in the configuration.
*
* The name passed in this function is the name that has to be used in the
* configuration to instantiate connections from the plugin.
*
* Example:
*
* \code
*
* rti::routing::RoutingService service(property);
*
* service.attach_adapter_plugin(myAdapter, "MyAdapter");
*
* service.start();
* ...
*
* \endcode
*
* And our configuration would look like this:
*
* \code
* <dds>
* <!-- No need to register the plugin in
* <plugin_library><adapter_plugin>
* -->
* <routing_service name="example">
* <domain_route name="myadapter_to_dds">
*
* <connection name="MyConnection" plugin_name="MyAdapter">
* ...
* </connection>
*
* ...
* </domain_route>
* </routing_service>
* </dds>
*
* \endcode
*
* This function can be called as many times as desired to attach
* several plugins.
*
* @pre Routing Service must not be started
*
* @param adapter_plugin
* @rs_st_in The adapter plugin object to be attached. The object
* shall remain alive during the execution of the service. Once the
* plugin is attached, the memory is owned by @product and will delete
* it upon service stop.
*
* @param plugin_name
* @rs_st_in
* The name used for this plugin in the &lt;connection&gt;
* tag in the configuration.
*
*/
void attach_adapter_plugin(
rti::routing::adapter::AdapterPlugin *adapter_plugin,
const std::string& plugin_name)
{
this->delegate()->attach_adapter_plugin(
adapter_plugin,
plugin_name);
}
/**
* @brief Attaches a Processor plugin to be used by @product when it is
* started.
*
* @see attach_adapter_plugin
*/
void attach_processor_plugin(
rti::routing::processor::ProcessorPlugin *processor_plugin,
const std::string& plugin_name)
{
this->delegate()->attach_processor_plugin(
processor_plugin,
plugin_name);
}
/**
* @brief Attaches a Transformation plugin to be used by @product when it
* is started.
*
* @see attach_adapter_plugin
*/
void attach_transformation_plugin(
rti::routing::transf::TransformationPlugin *transformation_plugin,
const std::string& plugin_name)
{
this->delegate()->attach_transformation_plugin(
transformation_plugin,
plugin_name);
}
/**
* @brief Executes an Administration command on this service.
*
* This operation directly executes the specified \p request in this
* service as if it was directly received from an administration requester.
*
* The request can represent any of the available administration operations
* as documented in the Administration chapter in the user's manual. This
* operation gives you an alternative way to control the service using
* the same remote administration interface but allowing you to call
* the operation directly.
*
* This operation can also throw an exception if an internal error
* occurs.
*
* Example:
*
* \code
*
* using namespace rti::routing;
* using namespace RTI::Service;
* using namespace RTI::Service::Admin;
*
* // Instantiate a RoutingServicee
* RoutingService service(...);
*
* // Prepare a request for any command, for example stop the service
* CommandRequest request;
* request.action(CommandActionKind::UPDATE_ACTION);
* request.resource_identifier("/routing_services/MyRouter");
* dds::topic::topic_type_support<EntityState>::to_cdr_buffer(
* reinterpret_cast<std::vector<char> &>(request.octet_body()),
* EntityState(EntityStateKind::DISABLED));
* // Execute and check result
* CommandReply reply = service.execute_command(request);
* if (reply.retcode().underlying() != CommandReplyRetcode::OK_RETCODE) {
* Logger.instance().error(
* std::string("Command returned: ") + reply.string_body());
* //handle
* ...
* }
*
* \endcode
*
* @param[in] request Representation of the command to be executed
* @return The reply with the result of the command execution.
*
*/
CommandReply execute_command(const CommandRequest& request)
{
return this->delegate()->execute_command(request);
}
/**
* @brief Executes an Administration command on this service.
*
* Similar to execute_command(const CommandRequest& request) except
* the caller provides the CommandReply object.
*
* @param[out] reply Representation of the reply containing the result of
* the operation
* @param[in] request Representation of the command to be executed
*
* @return A reference to the same reply object provided as a parameter
*/
CommandReply& execute_command(
CommandReply& reply,
const CommandRequest& request)
{
return this->delegate()->execute_command(reply, request);
}
/**
* @deprecated Calling this function at the end of the application is no
* longer necessary. It will be removed in future versions.
*/
static void finalize_globals()
{
rti::routing::Logger::instance().warn(
"Calling 'rti::routing::Service::finalize_globals()' is no "
"longer necessary and the function will be removed in future "
"versions");
}
};
typedef Service RoutingService;
}}
#endif // RTI_ROUTING_SERVICE_HPP_
@@ -0,0 +1,563 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_ROUTING_SERVICE_PROPERTY_HPP_
#define RTI_ROUTING_ROUTING_SERVICE_PROPERTY_HPP_
// IMPORTANT: macros.hpp must be the first RTI header included in every header
// file so that symbols are exported correctly on Windows
#include <dds/core/macros.hpp>
#include <rti/core/NativeValueType.hpp>
#include "routingservice/routingservice_service.h"
#include <rti/routing/detail/ForwarderUtils.hpp>
namespace rti { namespace routing {
class PropertyAdapter {
public:
typedef RTI_RoutingServiceProperty native_type;
static void initialize(native_type& native_value)
{
static const native_type DEFAULT
= RTI_RoutingServiceProperty_INITIALIZER;
native_value = DEFAULT;
native_value.service_verbosity = -1;
native_value.dds_verbosity = -1;
}
static void finalize(native_type& native_value)
{
if (native_value.cfg_strings != NULL) {
RTIOsapiHeap_freeArray(native_value.cfg_strings);
native_value.cfg_strings = NULL;
}
RTI_RoutingServiceProperty_finalize(&native_value);
}
static void copy(native_type& destination, const native_type& source)
{
RTIOsapiUtility_unusedParameter(destination);
RTIOsapiUtility_unusedParameter(source);
throw dds::core::UnsupportedError("Unsupported operation: copy");
}
static bool equals(const native_type& first, const native_type& second)
{
RTIOsapiUtility_unusedParameter(first);
RTIOsapiUtility_unusedParameter(second);
throw dds::core::UnsupportedError("Unsupported operation: equals");
}
static void add_properties_from_native(
std::map<std::string, std::string>& properties,
const RTI_RoutingServiceProperties *native_properties)
{
for (int i = 0; i < native_properties->count; i++) {
properties[native_properties->properties[i].name] =
(const char *) native_properties->properties[i].value;
}
}
static void add_properties_to_native(
RTI_RoutingServiceProperties *native_properties,
const std::map<std::string, std::string>& properties)
{
RTI_RoutingServiceProperties_finalize(native_properties);
RTI_RoutingServiceProperties_initialize(native_properties);
std::map<std::string, std::string>::const_iterator it = properties.begin();
for (; it != properties.end(); ++it) {
if (!RTI_RoutingServiceProperties_add(
native_properties,
it->first.c_str(),
it->second.c_str())) {
throw dds::core::Error("failed to add native property");
}
}
}
};
class ServiceProperty;
}
namespace core {
template<>
struct native_type_traits<rti::routing::ServiceProperty> {
typedef rti::routing::PropertyAdapter adapter_type;
typedef RTI_RoutingServiceProperty native_type;
};
}
namespace routing {
/** \ingroup RTI_RoutingServiceLibModule
*
* @brief Configuration for a @product object.
*
*/
class ServiceProperty : public rti::core::NativeValueType<ServiceProperty> {
public:
RTI_NATIVE_VALUE_TYPE_DEFINE_DEFAULT_MOVE_OPERATIONS(ServiceProperty)
typedef rti::core::NativeValueType<ServiceProperty> Base;
/**
* @brief Creates a property object with default settings.
*/
ServiceProperty(): Base()
{
}
ServiceProperty(const struct RTI_RoutingServiceProperty &native_property)
: Base(native_property)
{
}
/**
* @brief Getter (see setter with the same name)
*/
std::string cfg_file() const
{
return native().cfg_file == NULL ? "" : native().cfg_file;
}
/**
* @brief Path to an @product configuration file
*
* @default empty string.
*/
ServiceProperty& cfg_file(const std::string& filename)
{
DDS_String_replace(
&native().cfg_file,
filename.c_str());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
const std::vector<std::string>& cfg_strings() const
{
return cfg_strings_;
}
/**
* @brief XML configuration represented as strings
*
* An array of strings that altogether make up an
* XML document to configure @product. This parameter is used
* only if ServiceProperty::cfg_file is empty.
*
* The reason for using an array instead of one single string is to
* get around the limited size of literal strings.
* In general, if you create the XML string dynamically
* the vector needs only one element.
*
* @default empty.
*/
ServiceProperty& cfg_strings(
const std::vector<std::string>& the_cfg_strings)
{
cfg_strings_ = the_cfg_strings;
if (cfg_strings_.size() > 0) {
if (!RTIOsapiHeap_reallocateArray(
(char ***) &native().cfg_strings,
cfg_strings_.size(),
char *)) {
throw dds::core::OutOfResourcesError("cfg_strings native array");
}
for (uint32_t i = 0; i < cfg_strings_.size(); i++) {
native().cfg_strings[i] = cfg_strings_[i].c_str();
}
}
native().cfg_strings_count = static_cast<int>(cfg_strings_.size());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string service_name() const
{
return native().service_name == NULL ? "" : native().service_name;
}
/**
* @brief The name of the @product configuration to run.
*
* This is the name used to find the &lt;routing_service&gt;
* XML tag in the configuration file; the name that will
* be used to refer to this execution in remote administration and
* monitoring.
*
* @default empty string.
*/
ServiceProperty& service_name(const std::string& name)
{
DDS_String_replace(
&native().service_name,
name.c_str());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string application_name() const
{
return native().application_name;
}
/**
* @brief Assigns a name to the execution of the @product.
*
* Remote commands and status information will refer to the service using
* this name.
*
* In addition, the name of DomainParticipants created by @product will be
* based on this name.
*
* @default empty string.
* If no application name is specified, @product will use
* ServiceProperty::service_name.
*
*/
ServiceProperty& application_name(const std::string& name)
{
DDS_String_replace(
&native().application_name,
name.c_str());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool enforce_xsd_validation() const
{
return (native().enforce_xsd_validation == DDS_BOOLEAN_TRUE)
? true
: false;
}
/**
* @brief Controls whether the service applies XSD validation to the loaded
* configuration.
*
* @default true
*/
ServiceProperty& enforce_xsd_validation(const bool enforce_xsd_validation)
{
native().enforce_xsd_validation = enforce_xsd_validation;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
int domain_id_base() const
{
return native().domain_id_base;
}
/*e
* @brief Value that is added to the domain IDs of the
* domain routes in the XML configuration.
*
* By using this, an XML file can use relative domain IDs.
*
* @default 0
*/
ServiceProperty& domain_id_base(const int domain_id)
{
native().domain_id_base = domain_id;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string plugin_search_path() const
{
return native().plugin_search_path == NULL
? ""
: native().plugin_search_path;
}
/**
* @brief This path is used to look for plugin libraries.
*
* If the plugin class libraries specified in the XML file don't
* contain a full path, @product looks for them in this
* directory if not NULL.
*
* @default "." (working directory)
*/
ServiceProperty& plugin_search_path(const std::string& path)
{
DDS_String_replace(
&native().plugin_search_path,
path.c_str());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool dont_start_service() const
{
return (native().dont_start_service == DDS_BOOLEAN_TRUE)
? true
: false;
}
/**
* @brief Set this to true to if you do not want @product enabled when
* RoutingServcie::start is called.
*
* @product can be enabled afterwards through remote administration.
*
* @default false
*/
ServiceProperty& dont_start_service(const bool not_start)
{
native().dont_start_service = not_start
? DDS_BOOLEAN_TRUE
: DDS_BOOLEAN_FALSE;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool enable_administration() const
{
return (native().enable_administration == DDS_BOOLEAN_TRUE)
? true
: false;
}
/**
* @brief Set this to true to enable remote administration
* or false to disable it.
*
* @default false
*/
ServiceProperty& enable_administration(const bool enable)
{
native().enable_administration = enable
? DDS_BOOLEAN_TRUE
: DDS_BOOLEAN_FALSE;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
int administration_domain_id() const
{
return native().administration_domain_id;
}
/**
* @brief If ServiceProperty::enable_administration is true, this is
* the domain ID to use for remote administration.
*
* Takes precedence over the XML configuration.
* If ServiceProperty::enable_administration is false, this value is not used
* even if remote administration is enabled in the XML configuration.
*
* @default 0
*/
ServiceProperty& administration_domain_id(const int domain_id)
{
native().administration_domain_id = domain_id;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool enable_monitoring() const
{
return native().enable_monitoring == DDS_BOOLEAN_TRUE
? true
: false;
}
/**
* @brief Set it to true to enable remote monitoring
* or false to disable it.
*
* @default false
*/
ServiceProperty& enable_monitoring(const bool& enable)
{
native().enable_monitoring = enable
? DDS_BOOLEAN_TRUE
: DDS_BOOLEAN_FALSE;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
int monitoring_domain_id() const
{
return native().monitoring_domain_id;
}
/**
* @brief If ServiceProperty::enable_monitoring is true, this is
* the domain ID to use for remote monitoring.
*
* Takes precedence over the XML configuration.
* If ServiceProperty::enable_monitoring is false, this value is not used,
* even if remote monitoring is enabled in the XML configuration.
*
* @default 0
*/
ServiceProperty& monitoring_domain_id(const int& domain_id)
{
native().monitoring_domain_id = domain_id;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool skip_default_files() const
{
return (native().skip_default_files == DDS_BOOLEAN_TRUE)
? true
: false;
}
/**
* @brief Set it to true to avoid loading the
* standard files usually loaded by @product.
*
* Only the configuration in ServiceProperty::cfg_file or
* ServiceProperty::cfg_strings will be loaded.
*
* @default false
*/
ServiceProperty& skip_default_files(const bool& skip)
{
native().skip_default_files = skip
? DDS_BOOLEAN_TRUE
: DDS_BOOLEAN_FALSE;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
bool identify_execution() const
{
return (native().identify_execution == DDS_BOOLEAN_TRUE)
? true
: false;
}
/**
* @brief Set this to true to append the host name and process ID
* to the @product execution name.
*
* Used to get unique names for remote administration and monitoring.
*
* @default false
*/
ServiceProperty& identify_execution(const bool& identify)
{
native().identify_execution = identify
? DDS_BOOLEAN_TRUE
: DDS_BOOLEAN_FALSE;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string license_file_name() const
{
return native().license_file_name == NULL? ""
: native().license_file_name;
}
/**
* @brief Path to an @product license file.
*
* If not empty, this file is checked for a valid license; otherwise,
* default location will be used. This parameter is only used if your
* installation requires a license file.
*
* @default empty string.
*/
ServiceProperty& license_file_name(const std::string& filename)
{
DDS_String_replace(
&native().license_file_name,
filename.c_str());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::map<std::string, std::string> user_environment() const
{
std::map<std::string, std::string> properties;
PropertyAdapter::add_properties_from_native(
properties,
&native().user_environment);
return properties;
}
/**
* @brief Dictionary of user variables.
* The dictionary provides a parallel way to expand XML configuration
* variables in the form $(my_var), when they are not defined in the
* environment.
*
* @default empty
*/
ServiceProperty& user_environment(
const std::map<std::string, std::string>& user_environment)
{
rti::routing::PropertyAdapter::add_properties_to_native(
&native().user_environment,
user_environment);
return *this;
}
private:
std::vector<std::string> cfg_strings_;
};
}}
#endif // RTI_ROUTING_ROUTING_SERVICE_PROPERTY_HPP_
@@ -0,0 +1,210 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_ADAPTER_STREAM_INFO_HPP_
#define RTI_ROUTING_ADAPTER_STREAM_INFO_HPP_
// IMPORTANT: macros.hpp must be the first RTI header included in every header
// file so that symbols are exported correctly on Windows
#include <dds/core/macros.hpp>
#include <routingservice/routingservice_infrastructure.h>
#include <dds/core/Value.hpp>
#include <dds/core/Exception.hpp>
#include <rti/core/NativeValueType.hpp>
#include <rti/routing/TypeInfo.hpp>
namespace rti { namespace routing {
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
*/
class StreamInfoAdapter {
public:
typedef RTI_RoutingServiceStreamInfo native_type;
static void initialize(native_type& native_value)
{
RTIOsapiMemory_zero(
&native_value,
sizeof (RTI_RoutingServiceStreamInfo));
}
static void finalize(native_type& native_value)
{
TypeInfoAdapter::finalize(native_value.type_info);
if (native_value.stream_name != NULL) {
DDS_String_free(native_value.stream_name);
native_value.stream_name = NULL;
}
}
static void copy(native_type& destination, const native_type& source)
{
char *result = DDS_String_replace(
&destination.stream_name,
source.stream_name);
if (source.stream_name != NULL && result == NULL) {
throw std::bad_alloc();
}
destination.disposed = source.disposed;
TypeInfoAdapter::copy(
destination.type_info,
source.type_info);
}
static bool equals(const native_type& first, const native_type& second)
{
if (strcmp(first.stream_name, second.stream_name) != 0) {
return false;
}
if (first.disposed != second.disposed) {
return false;
}
return TypeInfoAdapter::equals(first.type_info, second.type_info);
}
};
class StreamInfo;
}
// native_type_traits needs to be defined in rti::core
namespace core {
template <>
struct native_type_traits<rti::routing::StreamInfo> {
typedef rti::routing::StreamInfoAdapter adapter_type;
typedef RTI_RoutingServiceStreamInfo native_type;
};
}
namespace routing {
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
* @class rti::routing::StreamInfo
*
* @brief Definition of the stream information that @product needs to manage
* user data streams.
*
* A stream in @product is a typed data channel to consume/produce data
* in a data domain.
*
*/
class StreamInfo : public rti::core::NativeValueType<StreamInfo> {
public:
RTI_NATIVE_VALUE_TYPE_DEFINE_DEFAULT_MOVE_OPERATIONS(StreamInfo)
typedef rti::core::NativeValueType<StreamInfo> Base;
public:
/**
* @brief Constructs a StreamInfo with the minimum required information.
*
* @param the_stream_name
* @rs_st_in The name of the stream.
* @param the_type_name
* @rs_st_in The name of the type associated with the data in the
* stream.
*/
StreamInfo(
const std::string& the_stream_name,
const std::string& the_type_name)
{
stream_name(the_stream_name);
type_info().type_name(the_type_name);
}
StreamInfo(const RTI_RoutingServiceStreamInfo &native_stream_info)
: Base(native_stream_info)
{
}
/**
* @brief Getter (see setter with the same name)
*/
bool disposed() const
{
return native().disposed ? true : false;
}
/**
* @brief Sets the dispose flag in this object.
*
* Indicates whether the stream is a newly discovered stream or a
* disposed stream that no longer exists.
*
* @param the_disposed
* @rs_st_in true if the stream is marked as disposed or false
* otherwise.
*/
StreamInfo& disposed(bool the_disposed)
{
native().disposed = the_disposed ? 1 : 0;
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
std::string stream_name() const
{
return native().stream_name;
}
/**
* @brief Sets the name of the stream
*
* @param the_stream_name
* @rs_st_in Name of the stream.
*/
StreamInfo& stream_name(const std::string& the_stream_name)
{
if (DDS_String_replace(
&native().stream_name,
the_stream_name.c_str()) == NULL) {
throw std::bad_alloc();
}
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
TypeInfo& type_info()
{
using namespace rti::core::native_conversions;
return cast_from_native<TypeInfo>(native().type_info);
}
/**
* @brief Sets the type information associated with the stream.
*
* @see TypeInfo.
*/
const TypeInfo& type_info() const
{
using namespace rti::core::native_conversions;
return cast_from_native<TypeInfo>(native().type_info);
}
};
}}
#endif // RTI_ROUTING_ADAPTER_STREAM_INFO_HPP_
@@ -0,0 +1,322 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_ADAPTER_TYPE_INFOHPP_
#define RTI_ROUTING_ADAPTER_TYPE_INFOHPP_
// IMPORTANT: macros.hpp must be the first RTI header included in every header
// file so that symbols are exported correctly on Windows
#include <dds/core/macros.hpp>
#include <routingservice/routingservice_infrastructure.h>
#include <dds/core/Value.hpp>
#include <dds/core/SafeEnumeration.hpp>
#include <dds/core/xtypes/DynamicType.hpp>
#include <rti/core/NativeValueType.hpp>
namespace rti { namespace routing {
/**
* @ingroup RTI_RoutingServiceInfrastructureModule
*
*/
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
* @class TypeRepresentationKind_def
*
* @brief The definition of the rti::routing::TypeRepresentationKind
*
* The range [0-100] is reserved for RTI use. Within that range are some
* predefined type representations.
*
*/
struct TypeRepresentationKind_def {
/**
* @brief Definition of all the possible type representation kinds
*/
enum type {
/**
* @brief Dynamic type representation.
*
* Types with this representation are provided as \ndds TypeCodes.
*
* For more information about TypeCodes, see Chapter 3 in the
* RTI Core Libraries and Utilities User's Manual.
*/
DYNAMIC_TYPE = RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_DYNAMIC_TYPE,
/**
* @brief @not_supported XML type representation.
*
* Types with this representation are provided as XML strings.
* The XML schema is the \ndds XML schema for type representation.
*
* For more information about XML representation,
* see Chapter 3 in the RTI Core Libraries and Utilities User's Manual.
*/
XML = RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_XML,
/**
* @brief @not_supported Java object type representation.
*
* Types with this representation are provided as Java objects.
*/
JAVA_OBJECT = RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_JAVA_OBJECT,
/**
* @brief @not_supported Custom type representation.
*
* Types with this representation are specific to a concrete
* adapter implementation
*/
CUSTOM = RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_FIRST_CUSTOM_REPRESENTATION
};
};
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
* @class TypeRepresentationKind
*
* @brief valid type representations that @product accepts.
*
* @see rti::routing::TypeRepresentationKind_def
*/
typedef dds::core::safe_enum<TypeRepresentationKind_def> TypeRepresentationKind;
class TypeInfoAdapter {
public:
typedef RTI_RoutingServiceTypeInfo native_type;
static void initialize(native_type& native_value)
{
static const native_type default_value = {
NULL,
DDS_BOOLEAN_TRUE,
RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_DYNAMIC_TYPE,
NULL};
native_value = default_value;
}
static void finalize(native_type& native_value)
{
if (native_value.type_name != NULL) {
RTIOsapiHeap_freeString(native_value.type_name);
native_value.type_name = NULL;
}
}
static void copy(native_type& destination, const native_type& source)
{
char *result = DDS_String_replace(
&destination.type_name,
source.type_name);
if (source.type_name != NULL && result == NULL) {
throw std::bad_alloc();
}
destination.can_be_optimized = source.can_be_optimized;
destination.type_representation_kind =
source.type_representation_kind;
destination.type_representation =
source.type_representation;
}
static bool equals(const native_type& first, const native_type& second)
{
if (strcmp(first.type_name, second.type_name) != 0) {
return false;
}
if (first.type_representation_kind
!= second.type_representation_kind) {
return false;
}
return first.type_representation == second.type_representation;
}
};
class TypeInfo;
}
// native_type_traits needs to be defined in rti::core
namespace core {
template <>
struct native_type_traits<rti::routing::TypeInfo> {
typedef rti::routing::TypeInfoAdapter adapter_type;
typedef RTI_RoutingServiceTypeInfo native_type;
};
}
namespace routing {
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
* @class rti::routing::TypeInfo
*
* @brief Definition of the type information associated with a @product
* stream.
*
* @see StreamInfo.
*
*/
class TypeInfo : public rti::core::NativeValueType<TypeInfo> {
public:
RTI_NATIVE_VALUE_TYPE_DEFINE_DEFAULT_MOVE_OPERATIONS(TypeInfo)
typedef rti::core::NativeValueType<TypeInfo> Base;
/**
* @brief Type representation defined as an opaque pointer.
*
* How this opaque is interpreted depends on the TypeRepresentationKind.
*/
typedef RTI_RoutingServiceTypeRepresentation TypeRepresentationType;
public:
/**
* @brief Constructs a TypeInfo with the minimum required information.
*
* @param the_type_name
* @rs_st_in Registered name of the type associated with the data.
* @param the_type_representation_kind
* @rs_st_in Indicates the representation of the object that
* describes the type. Default: TypeRepresentationKind::DYNAMIC_TYPE.
*/
TypeInfo(
const std::string& the_type_name,
TypeRepresentationKind the_type_representation_kind =
TypeRepresentationKind::DYNAMIC_TYPE)
{
type_name(the_type_name);
type_representation_kind(the_type_representation_kind);
native().can_be_optimized = DDS_BOOLEAN_TRUE;
}
TypeInfo(const struct RTI_RoutingServiceTypeInfo &native_stream_info)
: Base(native_stream_info)
{
}
/**
* @brief Getter (see setter with the same name)
*/
std::string type_name() const
{
return native().type_name;
}
/**
* @brief Sets the registered name of the type associated with the data.
*
* @product uses the type name to provide the right type information to
* StreamReader and StreamWriter. Namely, a type match is performed by
* comparing this type name with the value specified in the tag
* &lt;registered_type_name&gt; within the &lt;input&gt; and &lt;output&gt;
* tags.
*/
TypeInfo& type_name(const std::string& the_type_name)
{
if (DDS_String_replace(
&native().type_name,
the_type_name.c_str()) == NULL) {
throw std::bad_alloc();
}
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
TypeRepresentationKind type_representation_kind() const
{
return static_cast<TypeRepresentationKind::type>(
native().type_representation_kind);
}
/**
* @brief Sets the type representation kind.
*
* This member indicates how to interpret the type representation.
*
* @see TypeRepresentationKind
*/
TypeInfo& type_representation_kind(
TypeRepresentationKind the_type_representation_kind)
{
native().type_representation_kind = static_cast<int>(
the_type_representation_kind.underlying());
return *this;
}
/**
* @brief Getter (see setter with the same name)
*/
TypeRepresentationType type_representation() const
{
return native().type_representation;
}
/**
* @brief Sets the type representation value.
*
* This member is defined as an opaque pointer that can hold any type
* representation. How to interpret this pointer is determined by the
* TypeRepresentationKind, which shall be consistent with the object set
* in this member.
*/
TypeInfo& type_representation(TypeRepresentationType the_type_representation)
{
native().type_representation = the_type_representation;
return *this;
}
/**
* @brief Returns the type_representation as DynamicType object
*
* The operation throws if type_representation_kind is not DYNAMIC_TYPE
*
*/
const dds::core::xtypes::DynamicType& dynamic_type() const
{
if (type_representation_kind() != TypeRepresentationKind::DYNAMIC_TYPE) {
throw dds::core::IllegalOperationError(
"type representation is not dynamic type");
}
const DDS_TypeCode *native_typecode = reinterpret_cast<DDS_TypeCode*>(
type_representation());
return rti::core::native_conversions::cast_from_native<
dds::core::xtypes::DynamicType>(*native_typecode);
}
/**
* @brief Sets the type representation value as DynamicType object
*
* The provided DynamicType pointer must point to an object that remains
* valid until the StreamInfo object is destroyed.
*
* @see type_representation(TypeRepresentationType the_type_representation)
*/
void dynamic_type(const dds::core::xtypes::DynamicType *dynamic_type)
{
DDS_TypeCode *native_typecode = const_cast<DDS_TypeCode*>(
reinterpret_cast<const DDS_TypeCode *>(dynamic_type));
type_representation(static_cast<TypeRepresentationType>(native_typecode));
type_representation_kind(TypeRepresentationKind::DYNAMIC_TYPE);
}
};
}}
#endif // RTI_ROUTING_ADAPTER_TYPE_INFOHPP_
@@ -0,0 +1,60 @@
/*
* (c) Copyright, Real-Time Innovations, 2017.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef RTI_ROUTING_UPDATABLE_ENTITY_HPP_
#define RTI_ROUTING_UPDATABLE_ENTITY_HPP_
#include <map>
#include <string>
namespace rti { namespace routing {
/** @ingroup RTI_RoutingServiceInfrastructureModule
*
* @class rti::routing::UpdatableEntity
*
* @brief Defines a common interface for all the pluggable entities that can
* be updated at runtime.
*
* @product allows to update an pluggable entity through remote administration.
*
* @mtsafety Safe
* The UpdatableEntity::update operation is called only for one
* entity at a time. Additionally, no other operations can be made
* concurrently on a pluggable entity during the
* UpdatableEntity::update call.
*/
class UpdatableEntity {
public:
/**
* @brief Updates a pluggable entity.
*
* @param properties
* @rs_st_in The new configuration properties, obtained as result
* of parsing the elements within the &lt;property&gt; tag
* corresponding to the entity being updated.
*/
virtual void update(const std::map<std::string, std::string>& properties)
{
(void) properties;
}
/**
* @brief Virtual destructor.
*/
virtual ~UpdatableEntity()
{
}
};
}}
#endif // RTI_ROUTING_UPDATABLE_ENTITY_HPP_
Loaded 100 of 2395 files, more files were not shown because too many files have changed in this diff. Show more