Adds immediate migration results
This commit is contained in:
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
|
||||
+177
@@ -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
|
||||
+84
@@ -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
|
||||
+320
@@ -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_
|
||||
+209
@@ -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
|
||||
+165
@@ -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
|
||||
+63
@@ -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> <@ndds home>/bin/<architecture>/ </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 <cloud_discovery_service>
|
||||
* 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™ 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
+2958
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> <@ndds home>/bin/<architecture>/ </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_ */
|
||||
+63
@@ -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> <@ndds home>/bin/<architecture>/ </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_ */
|
||||
+56
@@ -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_ */
|
||||
|
||||
+110
@@ -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_ */
|
||||
+177
@@ -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_
|
||||
+239
@@ -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_
|
||||
+194
@@ -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_
|
||||
+268
@@ -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_
|
||||
+270
@@ -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 <property> corresponding to each pluggable entity. The result is a
|
||||
* map keyed by property name, represented as std::string, whose values are
|
||||
* the property values, also represented as std::string. Hence, a property name
|
||||
* shall be unique for each set of entity properties.
|
||||
*/
|
||||
typedef std::map<std::string,std::string> PropertySet;
|
||||
|
||||
}}
|
||||
|
||||
#endif // RTI_ROUTING_PROPERTY_SET_HPP_
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* (c) Copyright, Real-Time Innovations, 2021.
|
||||
* All rights reserved.
|
||||
*
|
||||
* No duplications, whole or partial, manual or electronic, may be made
|
||||
* without express written permission. Any such copies, or
|
||||
* revisions thereof, must display this notice unaltered.
|
||||
* This code contains trade secrets of Real-Time Innovations, Inc.
|
||||
*/
|
||||
|
||||
#ifndef RTI_ROUTING_ROUTING_SERVICE_HPP_
|
||||
#define RTI_ROUTING_ROUTING_SERVICE_HPP_
|
||||
|
||||
#include <rti/routing/Service.hpp>
|
||||
|
||||
|
||||
#endif // RTI_ROUTING_ROUTING_SERVICE_HPP_
|
||||
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* (c) Copyright, Real-Time Innovations, 2017.
|
||||
* All rights reserved.
|
||||
*
|
||||
* No duplications, whole or partial, manual or electronic, may be made
|
||||
* without express written permission. Any such copies, or
|
||||
* revisions thereof, must display this notice unaltered.
|
||||
* This code contains trade secrets of Real-Time Innovations, Inc.
|
||||
*/
|
||||
|
||||
#ifndef RTI_ROUTING_SERVICE_HPP_
|
||||
#define RTI_ROUTING_SERVICE_HPP_
|
||||
|
||||
#include <dds/core/Reference.hpp>
|
||||
#include <rti/config/Logger.hpp>
|
||||
|
||||
#include "routingservice/routingservice_adapter_new.h"
|
||||
|
||||
#include <rti/routing/Logger.hpp>
|
||||
#include <rti/routing/ServiceProperty.hpp>
|
||||
#include <rti/routing/detail/RoutingServiceImpl.hpp>
|
||||
#include <rti/routing/adapter/AdapterPlugin.hpp>
|
||||
#include <rti/routing/processor/ProcessorPlugin.hpp>
|
||||
|
||||
namespace rti { namespace routing {
|
||||
|
||||
/*e \defgroup RTI_RoutingServiceLibModule RTI Routing Library API
|
||||
* \ingroup ROUTER
|
||||
*
|
||||
* @brief @product can be deployed as a native library linked into your
|
||||
* application in select architectures.
|
||||
*
|
||||
* This API allows you to create, configure and start @product instances from
|
||||
* your application.
|
||||
*
|
||||
* The following code shows the typical use of the API:
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* int main ()
|
||||
* {
|
||||
* rti::routing::Service service(
|
||||
* rti::routing::ServiceProperty()
|
||||
* .cfg_file("MyRouter.xml")
|
||||
* .cfg_name("MyRouter"));
|
||||
* ...
|
||||
*
|
||||
* service.start();
|
||||
*
|
||||
* while(keep_running) {
|
||||
* sleep();
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* Instead of a file, you can use XML strings to configure @product.
|
||||
* See ServiceProperty for more information.
|
||||
* <p>
|
||||
* To build your application you need to link with the @product native library
|
||||
* in <b> <@ndds home>/bin/<architecture>/ </b>.
|
||||
*
|
||||
* ### Development Requirements
|
||||
*
|
||||
* | | Linux/macOS Systems | Windows Systems |
|
||||
* | --------------: | :----------------: | :-------------: |
|
||||
* | Shared Libraries| libnddscpp2.so | nddscpp2.dll |
|
||||
* | ^ | librtirsinfrastructure.so | rtirsinfrastructure.dll |
|
||||
* | ^ | librtiserviceadmincpp.so | rtiserviceadmincpp.dll |
|
||||
* | ^ | librtidlc.so | rtidlc.dll |
|
||||
* | ^ | librtiapputilsc.so | rtiapputilsc.dll |
|
||||
* | ^ | libnddsmetp.so | nddsmetp.dll |
|
||||
* | ^ | librticonnextmsgc.so | rticonnextmsgc.dll |
|
||||
* | ^ | libnddsc.so | nddsc.dll |
|
||||
* | ^ | librtixml2.so | rtixml2.dll |
|
||||
* | ^ | libnddscore.so | nddscore.dll |
|
||||
* | Headers | rti/routing/RoutingService.hpp ||
|
||||
*
|
||||
*/
|
||||
|
||||
/** \ingroup RTI_RoutingServiceLibModule
|
||||
*
|
||||
* @brief The @product.
|
||||
*
|
||||
*/
|
||||
class Service : public dds::core::Reference<RoutingServiceImpl> {
|
||||
public:
|
||||
|
||||
typedef RTI::Service::Admin::CommandRequest CommandRequest;
|
||||
typedef RTI::Service::Admin::CommandReply CommandReply;
|
||||
|
||||
typedef dds::core::Reference<RoutingServiceImpl> Base;
|
||||
OMG_DDS_REF_TYPE_NOTYPENAME(
|
||||
Service,
|
||||
dds::core::Reference,
|
||||
RoutingServiceImpl);
|
||||
|
||||
/**
|
||||
* @brief Creates a @product instance
|
||||
*
|
||||
* @param property
|
||||
* @rs_st_in The property to configure @product instance.
|
||||
*
|
||||
* @mtsafety On non-Linux, non-Windows systems (i.e. VxWorks):
|
||||
* UNSAFE for multiple threads to simultaneously make the FIRST
|
||||
* call to any of the Service constructors. Subsequent calls are
|
||||
* thread safe.
|
||||
* On Windows and Linux systems, these calls are thread-safe.
|
||||
*/
|
||||
explicit Service(const ServiceProperty& property)
|
||||
: Base(new RoutingServiceImpl(property))
|
||||
{
|
||||
this->delegate()->remember_reference(this->delegate());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a @product instance
|
||||
*
|
||||
* A callable shutdown hook can optionally be provided to handle the
|
||||
* shutdown command received through remote administration. Upon reception
|
||||
* of this command, @product will notify the installed hook.
|
||||
*
|
||||
* The following example shows simple implementation of a shutdown hook
|
||||
* that sets a boolean flag to true when invoked:
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* // Hook implementation
|
||||
* struct FlagShutdownHook {
|
||||
* public:
|
||||
* FlagShutdownHook(bool& the_flag) : flag(the_flag) {
|
||||
* flag = false;
|
||||
* }
|
||||
* void operator()() {
|
||||
* flag = true;
|
||||
* }
|
||||
*
|
||||
* bool& flag;
|
||||
* };
|
||||
*
|
||||
* // Instantiate service with hook
|
||||
* bool my_flag;
|
||||
* FlagShutdownHook my_hook(my_flag)
|
||||
* rti::routing::Service routing_service(
|
||||
* property,
|
||||
* my_hook);
|
||||
* ...
|
||||
*
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
*
|
||||
* @param[in] property
|
||||
* The property to configure @product instance.
|
||||
*
|
||||
* @param[in] shutdown_hook
|
||||
* Callable object to handle the shutdown command. The expected
|
||||
* type is a void operator()() (C++11 equivalent is
|
||||
* std::function<void()>)
|
||||
*
|
||||
* @mtsafety On non-Linux, non-Windows systems (i.e. VxWorks):
|
||||
* UNSAFE for multiple threads to simultaneously make the FIRST
|
||||
* call to any of the Service constructors. Subsequent calls are
|
||||
* thread safe.
|
||||
* On Windows and Linux systems, these calls are thread-safe.
|
||||
*/
|
||||
template <typename HookFunc>
|
||||
Service(
|
||||
const ServiceProperty& property,
|
||||
HookFunc& shutdown_hook)
|
||||
: Base(new RoutingServiceImpl(property, shutdown_hook))
|
||||
{
|
||||
this->delegate()->remember_reference(this->delegate());
|
||||
}
|
||||
|
||||
Service(const RTI_RoutingServiceProperty& property)
|
||||
: Base(new RoutingServiceImpl(property))
|
||||
{
|
||||
this->delegate()->remember_reference(this->delegate());
|
||||
}
|
||||
|
||||
explicit Service(Base::DELEGATE_REF_T reference) : Base(reference)
|
||||
{
|
||||
if (this->delegate()) {
|
||||
this->delegate()->remember_reference(this->delegate());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts @product.
|
||||
*
|
||||
* This is a non-blocking operation. @product will create its own set of
|
||||
* threads to perform its tasks.
|
||||
*/
|
||||
void start()
|
||||
{
|
||||
this->delegate()->start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops @product.
|
||||
*
|
||||
* This operation will bloc the instance is fully stopped.
|
||||
*/
|
||||
void stop()
|
||||
{
|
||||
this->delegate()->stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attaches an Adapter plugin to be used by @product when it is
|
||||
* started.
|
||||
*
|
||||
* By using this function an adapter can be statically compiled, created
|
||||
* in your application and have the service load it, instead of registering
|
||||
* a shared library and a create function in the configuration.
|
||||
*
|
||||
* The name passed in this function is the name that has to be used in the
|
||||
* configuration to instantiate connections from the plugin.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* rti::routing::RoutingService service(property);
|
||||
*
|
||||
* service.attach_adapter_plugin(myAdapter, "MyAdapter");
|
||||
*
|
||||
* service.start();
|
||||
* ...
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* And our configuration would look like this:
|
||||
*
|
||||
* \code
|
||||
* <dds>
|
||||
* <!-- No need to register the plugin in
|
||||
* <plugin_library><adapter_plugin>
|
||||
* -->
|
||||
* <routing_service name="example">
|
||||
* <domain_route name="myadapter_to_dds">
|
||||
*
|
||||
* <connection name="MyConnection" plugin_name="MyAdapter">
|
||||
* ...
|
||||
* </connection>
|
||||
*
|
||||
* ...
|
||||
* </domain_route>
|
||||
* </routing_service>
|
||||
* </dds>
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* This function can be called as many times as desired to attach
|
||||
* several plugins.
|
||||
*
|
||||
* @pre Routing Service must not be started
|
||||
*
|
||||
* @param adapter_plugin
|
||||
* @rs_st_in The adapter plugin object to be attached. The object
|
||||
* shall remain alive during the execution of the service. Once the
|
||||
* plugin is attached, the memory is owned by @product and will delete
|
||||
* it upon service stop.
|
||||
*
|
||||
* @param plugin_name
|
||||
* @rs_st_in
|
||||
* The name used for this plugin in the <connection>
|
||||
* tag in the configuration.
|
||||
*
|
||||
*/
|
||||
void attach_adapter_plugin(
|
||||
rti::routing::adapter::AdapterPlugin *adapter_plugin,
|
||||
const std::string& plugin_name)
|
||||
{
|
||||
this->delegate()->attach_adapter_plugin(
|
||||
adapter_plugin,
|
||||
plugin_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attaches a Processor plugin to be used by @product when it is
|
||||
* started.
|
||||
*
|
||||
* @see attach_adapter_plugin
|
||||
*/
|
||||
void attach_processor_plugin(
|
||||
rti::routing::processor::ProcessorPlugin *processor_plugin,
|
||||
const std::string& plugin_name)
|
||||
{
|
||||
this->delegate()->attach_processor_plugin(
|
||||
processor_plugin,
|
||||
plugin_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attaches a Transformation plugin to be used by @product when it
|
||||
* is started.
|
||||
*
|
||||
* @see attach_adapter_plugin
|
||||
*/
|
||||
void attach_transformation_plugin(
|
||||
rti::routing::transf::TransformationPlugin *transformation_plugin,
|
||||
const std::string& plugin_name)
|
||||
{
|
||||
this->delegate()->attach_transformation_plugin(
|
||||
transformation_plugin,
|
||||
plugin_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Executes an Administration command on this service.
|
||||
*
|
||||
* This operation directly executes the specified \p request in this
|
||||
* service as if it was directly received from an administration requester.
|
||||
*
|
||||
* The request can represent any of the available administration operations
|
||||
* as documented in the Administration chapter in the user's manual. This
|
||||
* operation gives you an alternative way to control the service using
|
||||
* the same remote administration interface but allowing you to call
|
||||
* the operation directly.
|
||||
*
|
||||
* This operation can also throw an exception if an internal error
|
||||
* occurs.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* using namespace rti::routing;
|
||||
* using namespace RTI::Service;
|
||||
* using namespace RTI::Service::Admin;
|
||||
*
|
||||
* // Instantiate a RoutingServicee
|
||||
* RoutingService service(...);
|
||||
*
|
||||
* // Prepare a request for any command, for example stop the service
|
||||
* CommandRequest request;
|
||||
* request.action(CommandActionKind::UPDATE_ACTION);
|
||||
* request.resource_identifier("/routing_services/MyRouter");
|
||||
* dds::topic::topic_type_support<EntityState>::to_cdr_buffer(
|
||||
* reinterpret_cast<std::vector<char> &>(request.octet_body()),
|
||||
* EntityState(EntityStateKind::DISABLED));
|
||||
* // Execute and check result
|
||||
* CommandReply reply = service.execute_command(request);
|
||||
* if (reply.retcode().underlying() != CommandReplyRetcode::OK_RETCODE) {
|
||||
* Logger.instance().error(
|
||||
* std::string("Command returned: ") + reply.string_body());
|
||||
* //handle
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* @param[in] request Representation of the command to be executed
|
||||
* @return The reply with the result of the command execution.
|
||||
*
|
||||
*/
|
||||
CommandReply execute_command(const CommandRequest& request)
|
||||
{
|
||||
return this->delegate()->execute_command(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Executes an Administration command on this service.
|
||||
*
|
||||
* Similar to execute_command(const CommandRequest& request) except
|
||||
* the caller provides the CommandReply object.
|
||||
*
|
||||
* @param[out] reply Representation of the reply containing the result of
|
||||
* the operation
|
||||
* @param[in] request Representation of the command to be executed
|
||||
*
|
||||
* @return A reference to the same reply object provided as a parameter
|
||||
*/
|
||||
CommandReply& execute_command(
|
||||
CommandReply& reply,
|
||||
const CommandRequest& request)
|
||||
{
|
||||
return this->delegate()->execute_command(reply, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Calling this function at the end of the application is no
|
||||
* longer necessary. It will be removed in future versions.
|
||||
*/
|
||||
static void finalize_globals()
|
||||
{
|
||||
rti::routing::Logger::instance().warn(
|
||||
"Calling 'rti::routing::Service::finalize_globals()' is no "
|
||||
"longer necessary and the function will be removed in future "
|
||||
"versions");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
typedef Service RoutingService;
|
||||
|
||||
}}
|
||||
|
||||
#endif // RTI_ROUTING_SERVICE_HPP_
|
||||
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
* (c) Copyright, Real-Time Innovations, 2017.
|
||||
* All rights reserved.
|
||||
*
|
||||
* No duplications, whole or partial, manual or electronic, may be made
|
||||
* without express written permission. Any such copies, or
|
||||
* revisions thereof, must display this notice unaltered.
|
||||
* This code contains trade secrets of Real-Time Innovations, Inc.
|
||||
*/
|
||||
|
||||
#ifndef RTI_ROUTING_ROUTING_SERVICE_PROPERTY_HPP_
|
||||
#define RTI_ROUTING_ROUTING_SERVICE_PROPERTY_HPP_
|
||||
|
||||
// IMPORTANT: macros.hpp must be the first RTI header included in every header
|
||||
// file so that symbols are exported correctly on Windows
|
||||
#include <dds/core/macros.hpp>
|
||||
#include <rti/core/NativeValueType.hpp>
|
||||
|
||||
#include "routingservice/routingservice_service.h"
|
||||
#include <rti/routing/detail/ForwarderUtils.hpp>
|
||||
|
||||
namespace rti { namespace routing {
|
||||
|
||||
class PropertyAdapter {
|
||||
public:
|
||||
typedef RTI_RoutingServiceProperty native_type;
|
||||
|
||||
static void initialize(native_type& native_value)
|
||||
{
|
||||
static const native_type DEFAULT
|
||||
= RTI_RoutingServiceProperty_INITIALIZER;
|
||||
native_value = DEFAULT;
|
||||
native_value.service_verbosity = -1;
|
||||
native_value.dds_verbosity = -1;
|
||||
}
|
||||
|
||||
static void finalize(native_type& native_value)
|
||||
{
|
||||
if (native_value.cfg_strings != NULL) {
|
||||
RTIOsapiHeap_freeArray(native_value.cfg_strings);
|
||||
native_value.cfg_strings = NULL;
|
||||
}
|
||||
|
||||
RTI_RoutingServiceProperty_finalize(&native_value);
|
||||
}
|
||||
|
||||
static void copy(native_type& destination, const native_type& source)
|
||||
{
|
||||
RTIOsapiUtility_unusedParameter(destination);
|
||||
RTIOsapiUtility_unusedParameter(source);
|
||||
|
||||
throw dds::core::UnsupportedError("Unsupported operation: copy");
|
||||
}
|
||||
|
||||
static bool equals(const native_type& first, const native_type& second)
|
||||
{
|
||||
RTIOsapiUtility_unusedParameter(first);
|
||||
RTIOsapiUtility_unusedParameter(second);
|
||||
|
||||
throw dds::core::UnsupportedError("Unsupported operation: equals");
|
||||
}
|
||||
|
||||
static void add_properties_from_native(
|
||||
std::map<std::string, std::string>& properties,
|
||||
const RTI_RoutingServiceProperties *native_properties)
|
||||
{
|
||||
for (int i = 0; i < native_properties->count; i++) {
|
||||
properties[native_properties->properties[i].name] =
|
||||
(const char *) native_properties->properties[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
static void add_properties_to_native(
|
||||
RTI_RoutingServiceProperties *native_properties,
|
||||
const std::map<std::string, std::string>& properties)
|
||||
{
|
||||
RTI_RoutingServiceProperties_finalize(native_properties);
|
||||
RTI_RoutingServiceProperties_initialize(native_properties);
|
||||
|
||||
std::map<std::string, std::string>::const_iterator it = properties.begin();
|
||||
for (; it != properties.end(); ++it) {
|
||||
if (!RTI_RoutingServiceProperties_add(
|
||||
native_properties,
|
||||
it->first.c_str(),
|
||||
it->second.c_str())) {
|
||||
throw dds::core::Error("failed to add native property");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class ServiceProperty;
|
||||
|
||||
}
|
||||
|
||||
namespace core {
|
||||
|
||||
template<>
|
||||
struct native_type_traits<rti::routing::ServiceProperty> {
|
||||
typedef rti::routing::PropertyAdapter adapter_type;
|
||||
typedef RTI_RoutingServiceProperty native_type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace routing {
|
||||
|
||||
/** \ingroup RTI_RoutingServiceLibModule
|
||||
*
|
||||
* @brief Configuration for a @product object.
|
||||
*
|
||||
*/
|
||||
class ServiceProperty : public rti::core::NativeValueType<ServiceProperty> {
|
||||
public:
|
||||
RTI_NATIVE_VALUE_TYPE_DEFINE_DEFAULT_MOVE_OPERATIONS(ServiceProperty)
|
||||
|
||||
typedef rti::core::NativeValueType<ServiceProperty> Base;
|
||||
|
||||
/**
|
||||
* @brief Creates a property object with default settings.
|
||||
*/
|
||||
ServiceProperty(): Base()
|
||||
{
|
||||
}
|
||||
|
||||
ServiceProperty(const struct RTI_RoutingServiceProperty &native_property)
|
||||
: Base(native_property)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
std::string cfg_file() const
|
||||
{
|
||||
return native().cfg_file == NULL ? "" : native().cfg_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Path to an @product configuration file
|
||||
*
|
||||
* @default empty string.
|
||||
*/
|
||||
ServiceProperty& cfg_file(const std::string& filename)
|
||||
{
|
||||
DDS_String_replace(
|
||||
&native().cfg_file,
|
||||
filename.c_str());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
const std::vector<std::string>& cfg_strings() const
|
||||
{
|
||||
return cfg_strings_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief XML configuration represented as strings
|
||||
*
|
||||
* An array of strings that altogether make up an
|
||||
* XML document to configure @product. This parameter is used
|
||||
* only if ServiceProperty::cfg_file is empty.
|
||||
*
|
||||
* The reason for using an array instead of one single string is to
|
||||
* get around the limited size of literal strings.
|
||||
* In general, if you create the XML string dynamically
|
||||
* the vector needs only one element.
|
||||
*
|
||||
* @default empty.
|
||||
*/
|
||||
ServiceProperty& cfg_strings(
|
||||
const std::vector<std::string>& the_cfg_strings)
|
||||
{
|
||||
cfg_strings_ = the_cfg_strings;
|
||||
if (cfg_strings_.size() > 0) {
|
||||
if (!RTIOsapiHeap_reallocateArray(
|
||||
(char ***) &native().cfg_strings,
|
||||
cfg_strings_.size(),
|
||||
char *)) {
|
||||
throw dds::core::OutOfResourcesError("cfg_strings native array");
|
||||
}
|
||||
for (uint32_t i = 0; i < cfg_strings_.size(); i++) {
|
||||
native().cfg_strings[i] = cfg_strings_[i].c_str();
|
||||
}
|
||||
}
|
||||
native().cfg_strings_count = static_cast<int>(cfg_strings_.size());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
std::string service_name() const
|
||||
{
|
||||
return native().service_name == NULL ? "" : native().service_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The name of the @product configuration to run.
|
||||
*
|
||||
* This is the name used to find the <routing_service>
|
||||
* XML tag in the configuration file; the name that will
|
||||
* be used to refer to this execution in remote administration and
|
||||
* monitoring.
|
||||
*
|
||||
* @default empty string.
|
||||
*/
|
||||
ServiceProperty& service_name(const std::string& name)
|
||||
{
|
||||
DDS_String_replace(
|
||||
&native().service_name,
|
||||
name.c_str());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
std::string application_name() const
|
||||
{
|
||||
return native().application_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a name to the execution of the @product.
|
||||
*
|
||||
* Remote commands and status information will refer to the service using
|
||||
* this name.
|
||||
*
|
||||
* In addition, the name of DomainParticipants created by @product will be
|
||||
* based on this name.
|
||||
*
|
||||
* @default empty string.
|
||||
* If no application name is specified, @product will use
|
||||
* ServiceProperty::service_name.
|
||||
*
|
||||
*/
|
||||
ServiceProperty& application_name(const std::string& name)
|
||||
{
|
||||
DDS_String_replace(
|
||||
&native().application_name,
|
||||
name.c_str());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
bool enforce_xsd_validation() const
|
||||
{
|
||||
return (native().enforce_xsd_validation == DDS_BOOLEAN_TRUE)
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Controls whether the service applies XSD validation to the loaded
|
||||
* configuration.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
ServiceProperty& enforce_xsd_validation(const bool enforce_xsd_validation)
|
||||
{
|
||||
native().enforce_xsd_validation = enforce_xsd_validation;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
int domain_id_base() const
|
||||
{
|
||||
return native().domain_id_base;
|
||||
}
|
||||
|
||||
/*e
|
||||
* @brief Value that is added to the domain IDs of the
|
||||
* domain routes in the XML configuration.
|
||||
*
|
||||
* By using this, an XML file can use relative domain IDs.
|
||||
*
|
||||
* @default 0
|
||||
*/
|
||||
ServiceProperty& domain_id_base(const int domain_id)
|
||||
{
|
||||
native().domain_id_base = domain_id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
std::string plugin_search_path() const
|
||||
{
|
||||
return native().plugin_search_path == NULL
|
||||
? ""
|
||||
: native().plugin_search_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This path is used to look for plugin libraries.
|
||||
*
|
||||
* If the plugin class libraries specified in the XML file don't
|
||||
* contain a full path, @product looks for them in this
|
||||
* directory if not NULL.
|
||||
*
|
||||
* @default "." (working directory)
|
||||
*/
|
||||
ServiceProperty& plugin_search_path(const std::string& path)
|
||||
{
|
||||
DDS_String_replace(
|
||||
&native().plugin_search_path,
|
||||
path.c_str());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
bool dont_start_service() const
|
||||
{
|
||||
return (native().dont_start_service == DDS_BOOLEAN_TRUE)
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set this to true to if you do not want @product enabled when
|
||||
* RoutingServcie::start is called.
|
||||
*
|
||||
* @product can be enabled afterwards through remote administration.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
ServiceProperty& dont_start_service(const bool not_start)
|
||||
{
|
||||
native().dont_start_service = not_start
|
||||
? DDS_BOOLEAN_TRUE
|
||||
: DDS_BOOLEAN_FALSE;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
bool enable_administration() const
|
||||
{
|
||||
return (native().enable_administration == DDS_BOOLEAN_TRUE)
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set this to true to enable remote administration
|
||||
* or false to disable it.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
ServiceProperty& enable_administration(const bool enable)
|
||||
{
|
||||
native().enable_administration = enable
|
||||
? DDS_BOOLEAN_TRUE
|
||||
: DDS_BOOLEAN_FALSE;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
int administration_domain_id() const
|
||||
{
|
||||
return native().administration_domain_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief If ServiceProperty::enable_administration is true, this is
|
||||
* the domain ID to use for remote administration.
|
||||
*
|
||||
* Takes precedence over the XML configuration.
|
||||
* If ServiceProperty::enable_administration is false, this value is not used
|
||||
* even if remote administration is enabled in the XML configuration.
|
||||
*
|
||||
* @default 0
|
||||
*/
|
||||
ServiceProperty& administration_domain_id(const int domain_id)
|
||||
{
|
||||
native().administration_domain_id = domain_id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
bool enable_monitoring() const
|
||||
{
|
||||
return native().enable_monitoring == DDS_BOOLEAN_TRUE
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set it to true to enable remote monitoring
|
||||
* or false to disable it.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
ServiceProperty& enable_monitoring(const bool& enable)
|
||||
{
|
||||
native().enable_monitoring = enable
|
||||
? DDS_BOOLEAN_TRUE
|
||||
: DDS_BOOLEAN_FALSE;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
int monitoring_domain_id() const
|
||||
{
|
||||
return native().monitoring_domain_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief If ServiceProperty::enable_monitoring is true, this is
|
||||
* the domain ID to use for remote monitoring.
|
||||
*
|
||||
* Takes precedence over the XML configuration.
|
||||
* If ServiceProperty::enable_monitoring is false, this value is not used,
|
||||
* even if remote monitoring is enabled in the XML configuration.
|
||||
*
|
||||
* @default 0
|
||||
*/
|
||||
ServiceProperty& monitoring_domain_id(const int& domain_id)
|
||||
{
|
||||
native().monitoring_domain_id = domain_id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
bool skip_default_files() const
|
||||
{
|
||||
return (native().skip_default_files == DDS_BOOLEAN_TRUE)
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set it to true to avoid loading the
|
||||
* standard files usually loaded by @product.
|
||||
*
|
||||
* Only the configuration in ServiceProperty::cfg_file or
|
||||
* ServiceProperty::cfg_strings will be loaded.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
ServiceProperty& skip_default_files(const bool& skip)
|
||||
{
|
||||
native().skip_default_files = skip
|
||||
? DDS_BOOLEAN_TRUE
|
||||
: DDS_BOOLEAN_FALSE;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
bool identify_execution() const
|
||||
{
|
||||
return (native().identify_execution == DDS_BOOLEAN_TRUE)
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set this to true to append the host name and process ID
|
||||
* to the @product execution name.
|
||||
*
|
||||
* Used to get unique names for remote administration and monitoring.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
ServiceProperty& identify_execution(const bool& identify)
|
||||
{
|
||||
native().identify_execution = identify
|
||||
? DDS_BOOLEAN_TRUE
|
||||
: DDS_BOOLEAN_FALSE;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
std::string license_file_name() const
|
||||
{
|
||||
return native().license_file_name == NULL? ""
|
||||
: native().license_file_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Path to an @product license file.
|
||||
*
|
||||
* If not empty, this file is checked for a valid license; otherwise,
|
||||
* default location will be used. This parameter is only used if your
|
||||
* installation requires a license file.
|
||||
*
|
||||
* @default empty string.
|
||||
*/
|
||||
ServiceProperty& license_file_name(const std::string& filename)
|
||||
{
|
||||
DDS_String_replace(
|
||||
&native().license_file_name,
|
||||
filename.c_str());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
std::map<std::string, std::string> user_environment() const
|
||||
{
|
||||
std::map<std::string, std::string> properties;
|
||||
|
||||
PropertyAdapter::add_properties_from_native(
|
||||
properties,
|
||||
&native().user_environment);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dictionary of user variables.
|
||||
* The dictionary provides a parallel way to expand XML configuration
|
||||
* variables in the form $(my_var), when they are not defined in the
|
||||
* environment.
|
||||
*
|
||||
* @default empty
|
||||
*/
|
||||
ServiceProperty& user_environment(
|
||||
const std::map<std::string, std::string>& user_environment)
|
||||
{
|
||||
rti::routing::PropertyAdapter::add_properties_to_native(
|
||||
&native().user_environment,
|
||||
user_environment);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> cfg_strings_;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif // RTI_ROUTING_ROUTING_SERVICE_PROPERTY_HPP_
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* (c) Copyright, Real-Time Innovations, 2017.
|
||||
* All rights reserved.
|
||||
*
|
||||
* No duplications, whole or partial, manual or electronic, may be made
|
||||
* without express written permission. Any such copies, or
|
||||
* revisions thereof, must display this notice unaltered.
|
||||
* This code contains trade secrets of Real-Time Innovations, Inc.
|
||||
*/
|
||||
|
||||
#ifndef RTI_ROUTING_ADAPTER_STREAM_INFO_HPP_
|
||||
#define RTI_ROUTING_ADAPTER_STREAM_INFO_HPP_
|
||||
|
||||
// IMPORTANT: macros.hpp must be the first RTI header included in every header
|
||||
// file so that symbols are exported correctly on Windows
|
||||
#include <dds/core/macros.hpp>
|
||||
|
||||
|
||||
#include <routingservice/routingservice_infrastructure.h>
|
||||
#include <dds/core/Value.hpp>
|
||||
#include <dds/core/Exception.hpp>
|
||||
#include <rti/core/NativeValueType.hpp>
|
||||
#include <rti/routing/TypeInfo.hpp>
|
||||
|
||||
namespace rti { namespace routing {
|
||||
|
||||
/** @ingroup RTI_RoutingServiceInfrastructureModule
|
||||
*
|
||||
*/
|
||||
|
||||
class StreamInfoAdapter {
|
||||
public:
|
||||
typedef RTI_RoutingServiceStreamInfo native_type;
|
||||
|
||||
static void initialize(native_type& native_value)
|
||||
{
|
||||
RTIOsapiMemory_zero(
|
||||
&native_value,
|
||||
sizeof (RTI_RoutingServiceStreamInfo));
|
||||
}
|
||||
|
||||
static void finalize(native_type& native_value)
|
||||
{
|
||||
TypeInfoAdapter::finalize(native_value.type_info);
|
||||
if (native_value.stream_name != NULL) {
|
||||
DDS_String_free(native_value.stream_name);
|
||||
native_value.stream_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void copy(native_type& destination, const native_type& source)
|
||||
{
|
||||
char *result = DDS_String_replace(
|
||||
&destination.stream_name,
|
||||
source.stream_name);
|
||||
if (source.stream_name != NULL && result == NULL) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
destination.disposed = source.disposed;
|
||||
TypeInfoAdapter::copy(
|
||||
destination.type_info,
|
||||
source.type_info);
|
||||
}
|
||||
|
||||
static bool equals(const native_type& first, const native_type& second)
|
||||
{
|
||||
if (strcmp(first.stream_name, second.stream_name) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (first.disposed != second.disposed) {
|
||||
return false;
|
||||
}
|
||||
return TypeInfoAdapter::equals(first.type_info, second.type_info);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class StreamInfo;
|
||||
|
||||
}
|
||||
|
||||
// native_type_traits needs to be defined in rti::core
|
||||
namespace core {
|
||||
|
||||
template <>
|
||||
struct native_type_traits<rti::routing::StreamInfo> {
|
||||
typedef rti::routing::StreamInfoAdapter adapter_type;
|
||||
typedef RTI_RoutingServiceStreamInfo native_type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace routing {
|
||||
|
||||
/** @ingroup RTI_RoutingServiceInfrastructureModule
|
||||
*
|
||||
* @class rti::routing::StreamInfo
|
||||
*
|
||||
* @brief Definition of the stream information that @product needs to manage
|
||||
* user data streams.
|
||||
*
|
||||
* A stream in @product is a typed data channel to consume/produce data
|
||||
* in a data domain.
|
||||
*
|
||||
*/
|
||||
class StreamInfo : public rti::core::NativeValueType<StreamInfo> {
|
||||
public:
|
||||
RTI_NATIVE_VALUE_TYPE_DEFINE_DEFAULT_MOVE_OPERATIONS(StreamInfo)
|
||||
|
||||
typedef rti::core::NativeValueType<StreamInfo> Base;
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructs a StreamInfo with the minimum required information.
|
||||
*
|
||||
* @param the_stream_name
|
||||
* @rs_st_in The name of the stream.
|
||||
* @param the_type_name
|
||||
* @rs_st_in The name of the type associated with the data in the
|
||||
* stream.
|
||||
*/
|
||||
StreamInfo(
|
||||
const std::string& the_stream_name,
|
||||
const std::string& the_type_name)
|
||||
{
|
||||
stream_name(the_stream_name);
|
||||
type_info().type_name(the_type_name);
|
||||
}
|
||||
|
||||
StreamInfo(const RTI_RoutingServiceStreamInfo &native_stream_info)
|
||||
: Base(native_stream_info)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
bool disposed() const
|
||||
{
|
||||
return native().disposed ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the dispose flag in this object.
|
||||
*
|
||||
* Indicates whether the stream is a newly discovered stream or a
|
||||
* disposed stream that no longer exists.
|
||||
*
|
||||
* @param the_disposed
|
||||
* @rs_st_in true if the stream is marked as disposed or false
|
||||
* otherwise.
|
||||
*/
|
||||
StreamInfo& disposed(bool the_disposed)
|
||||
{
|
||||
native().disposed = the_disposed ? 1 : 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
std::string stream_name() const
|
||||
{
|
||||
return native().stream_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the name of the stream
|
||||
*
|
||||
* @param the_stream_name
|
||||
* @rs_st_in Name of the stream.
|
||||
*/
|
||||
StreamInfo& stream_name(const std::string& the_stream_name)
|
||||
{
|
||||
if (DDS_String_replace(
|
||||
&native().stream_name,
|
||||
the_stream_name.c_str()) == NULL) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
TypeInfo& type_info()
|
||||
{
|
||||
using namespace rti::core::native_conversions;
|
||||
|
||||
return cast_from_native<TypeInfo>(native().type_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the type information associated with the stream.
|
||||
*
|
||||
* @see TypeInfo.
|
||||
*/
|
||||
const TypeInfo& type_info() const
|
||||
{
|
||||
using namespace rti::core::native_conversions;
|
||||
|
||||
return cast_from_native<TypeInfo>(native().type_info);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_STREAM_INFO_HPP_
|
||||
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* (c) Copyright, Real-Time Innovations, 2017.
|
||||
* All rights reserved.
|
||||
*
|
||||
* No duplications, whole or partial, manual or electronic, may be made
|
||||
* without express written permission. Any such copies, or
|
||||
* revisions thereof, must display this notice unaltered.
|
||||
* This code contains trade secrets of Real-Time Innovations, Inc.
|
||||
*/
|
||||
|
||||
#ifndef RTI_ROUTING_ADAPTER_TYPE_INFOHPP_
|
||||
#define RTI_ROUTING_ADAPTER_TYPE_INFOHPP_
|
||||
|
||||
// IMPORTANT: macros.hpp must be the first RTI header included in every header
|
||||
// file so that symbols are exported correctly on Windows
|
||||
#include <dds/core/macros.hpp>
|
||||
|
||||
#include <routingservice/routingservice_infrastructure.h>
|
||||
#include <dds/core/Value.hpp>
|
||||
#include <dds/core/SafeEnumeration.hpp>
|
||||
#include <dds/core/xtypes/DynamicType.hpp>
|
||||
#include <rti/core/NativeValueType.hpp>
|
||||
|
||||
namespace rti { namespace routing {
|
||||
|
||||
/**
|
||||
* @ingroup RTI_RoutingServiceInfrastructureModule
|
||||
*
|
||||
*/
|
||||
|
||||
/** @ingroup RTI_RoutingServiceInfrastructureModule
|
||||
*
|
||||
* @class TypeRepresentationKind_def
|
||||
*
|
||||
* @brief The definition of the rti::routing::TypeRepresentationKind
|
||||
*
|
||||
* The range [0-100] is reserved for RTI use. Within that range are some
|
||||
* predefined type representations.
|
||||
*
|
||||
*/
|
||||
struct TypeRepresentationKind_def {
|
||||
/**
|
||||
* @brief Definition of all the possible type representation kinds
|
||||
*/
|
||||
enum type {
|
||||
/**
|
||||
* @brief Dynamic type representation.
|
||||
*
|
||||
* Types with this representation are provided as \ndds TypeCodes.
|
||||
*
|
||||
* For more information about TypeCodes, see Chapter 3 in the
|
||||
* RTI Core Libraries and Utilities User's Manual.
|
||||
*/
|
||||
DYNAMIC_TYPE = RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_DYNAMIC_TYPE,
|
||||
/**
|
||||
* @brief @not_supported XML type representation.
|
||||
*
|
||||
* Types with this representation are provided as XML strings.
|
||||
* The XML schema is the \ndds XML schema for type representation.
|
||||
*
|
||||
* For more information about XML representation,
|
||||
* see Chapter 3 in the RTI Core Libraries and Utilities User's Manual.
|
||||
*/
|
||||
XML = RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_XML,
|
||||
/**
|
||||
* @brief @not_supported Java object type representation.
|
||||
*
|
||||
* Types with this representation are provided as Java objects.
|
||||
*/
|
||||
JAVA_OBJECT = RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_JAVA_OBJECT,
|
||||
/**
|
||||
* @brief @not_supported Custom type representation.
|
||||
*
|
||||
* Types with this representation are specific to a concrete
|
||||
* adapter implementation
|
||||
*/
|
||||
CUSTOM = RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_FIRST_CUSTOM_REPRESENTATION
|
||||
};
|
||||
};
|
||||
|
||||
/** @ingroup RTI_RoutingServiceInfrastructureModule
|
||||
*
|
||||
* @class TypeRepresentationKind
|
||||
*
|
||||
* @brief valid type representations that @product accepts.
|
||||
*
|
||||
* @see rti::routing::TypeRepresentationKind_def
|
||||
*/
|
||||
typedef dds::core::safe_enum<TypeRepresentationKind_def> TypeRepresentationKind;
|
||||
|
||||
|
||||
class TypeInfoAdapter {
|
||||
public:
|
||||
typedef RTI_RoutingServiceTypeInfo native_type;
|
||||
|
||||
static void initialize(native_type& native_value)
|
||||
{
|
||||
static const native_type default_value = {
|
||||
NULL,
|
||||
DDS_BOOLEAN_TRUE,
|
||||
RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_DYNAMIC_TYPE,
|
||||
NULL};
|
||||
native_value = default_value;
|
||||
}
|
||||
|
||||
static void finalize(native_type& native_value)
|
||||
{
|
||||
if (native_value.type_name != NULL) {
|
||||
RTIOsapiHeap_freeString(native_value.type_name);
|
||||
native_value.type_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void copy(native_type& destination, const native_type& source)
|
||||
{
|
||||
char *result = DDS_String_replace(
|
||||
&destination.type_name,
|
||||
source.type_name);
|
||||
if (source.type_name != NULL && result == NULL) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
destination.can_be_optimized = source.can_be_optimized;
|
||||
destination.type_representation_kind =
|
||||
source.type_representation_kind;
|
||||
destination.type_representation =
|
||||
source.type_representation;
|
||||
}
|
||||
|
||||
static bool equals(const native_type& first, const native_type& second)
|
||||
{
|
||||
if (strcmp(first.type_name, second.type_name) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (first.type_representation_kind
|
||||
!= second.type_representation_kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return first.type_representation == second.type_representation;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class TypeInfo;
|
||||
|
||||
}
|
||||
|
||||
// native_type_traits needs to be defined in rti::core
|
||||
namespace core {
|
||||
|
||||
template <>
|
||||
struct native_type_traits<rti::routing::TypeInfo> {
|
||||
typedef rti::routing::TypeInfoAdapter adapter_type;
|
||||
typedef RTI_RoutingServiceTypeInfo native_type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace routing {
|
||||
|
||||
/** @ingroup RTI_RoutingServiceInfrastructureModule
|
||||
*
|
||||
* @class rti::routing::TypeInfo
|
||||
*
|
||||
* @brief Definition of the type information associated with a @product
|
||||
* stream.
|
||||
*
|
||||
* @see StreamInfo.
|
||||
*
|
||||
*/
|
||||
class TypeInfo : public rti::core::NativeValueType<TypeInfo> {
|
||||
public:
|
||||
RTI_NATIVE_VALUE_TYPE_DEFINE_DEFAULT_MOVE_OPERATIONS(TypeInfo)
|
||||
|
||||
typedef rti::core::NativeValueType<TypeInfo> Base;
|
||||
|
||||
/**
|
||||
* @brief Type representation defined as an opaque pointer.
|
||||
*
|
||||
* How this opaque is interpreted depends on the TypeRepresentationKind.
|
||||
*/
|
||||
typedef RTI_RoutingServiceTypeRepresentation TypeRepresentationType;
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructs a TypeInfo with the minimum required information.
|
||||
*
|
||||
* @param the_type_name
|
||||
* @rs_st_in Registered name of the type associated with the data.
|
||||
* @param the_type_representation_kind
|
||||
* @rs_st_in Indicates the representation of the object that
|
||||
* describes the type. Default: TypeRepresentationKind::DYNAMIC_TYPE.
|
||||
*/
|
||||
TypeInfo(
|
||||
const std::string& the_type_name,
|
||||
TypeRepresentationKind the_type_representation_kind =
|
||||
TypeRepresentationKind::DYNAMIC_TYPE)
|
||||
{
|
||||
type_name(the_type_name);
|
||||
type_representation_kind(the_type_representation_kind);
|
||||
native().can_be_optimized = DDS_BOOLEAN_TRUE;
|
||||
}
|
||||
|
||||
TypeInfo(const struct RTI_RoutingServiceTypeInfo &native_stream_info)
|
||||
: Base(native_stream_info)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
std::string type_name() const
|
||||
{
|
||||
return native().type_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the registered name of the type associated with the data.
|
||||
*
|
||||
* @product uses the type name to provide the right type information to
|
||||
* StreamReader and StreamWriter. Namely, a type match is performed by
|
||||
* comparing this type name with the value specified in the tag
|
||||
* <registered_type_name> within the <input> and <output>
|
||||
* tags.
|
||||
*/
|
||||
TypeInfo& type_name(const std::string& the_type_name)
|
||||
{
|
||||
|
||||
if (DDS_String_replace(
|
||||
&native().type_name,
|
||||
the_type_name.c_str()) == NULL) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
TypeRepresentationKind type_representation_kind() const
|
||||
{
|
||||
return static_cast<TypeRepresentationKind::type>(
|
||||
native().type_representation_kind);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the type representation kind.
|
||||
*
|
||||
* This member indicates how to interpret the type representation.
|
||||
*
|
||||
* @see TypeRepresentationKind
|
||||
*/
|
||||
TypeInfo& type_representation_kind(
|
||||
TypeRepresentationKind the_type_representation_kind)
|
||||
{
|
||||
native().type_representation_kind = static_cast<int>(
|
||||
the_type_representation_kind.underlying());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter (see setter with the same name)
|
||||
*/
|
||||
TypeRepresentationType type_representation() const
|
||||
{
|
||||
return native().type_representation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the type representation value.
|
||||
*
|
||||
* This member is defined as an opaque pointer that can hold any type
|
||||
* representation. How to interpret this pointer is determined by the
|
||||
* TypeRepresentationKind, which shall be consistent with the object set
|
||||
* in this member.
|
||||
*/
|
||||
TypeInfo& type_representation(TypeRepresentationType the_type_representation)
|
||||
{
|
||||
native().type_representation = the_type_representation;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the type_representation as DynamicType object
|
||||
*
|
||||
* The operation throws if type_representation_kind is not DYNAMIC_TYPE
|
||||
*
|
||||
*/
|
||||
const dds::core::xtypes::DynamicType& dynamic_type() const
|
||||
{
|
||||
if (type_representation_kind() != TypeRepresentationKind::DYNAMIC_TYPE) {
|
||||
throw dds::core::IllegalOperationError(
|
||||
"type representation is not dynamic type");
|
||||
}
|
||||
|
||||
const DDS_TypeCode *native_typecode = reinterpret_cast<DDS_TypeCode*>(
|
||||
type_representation());
|
||||
return rti::core::native_conversions::cast_from_native<
|
||||
dds::core::xtypes::DynamicType>(*native_typecode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the type representation value as DynamicType object
|
||||
*
|
||||
* The provided DynamicType pointer must point to an object that remains
|
||||
* valid until the StreamInfo object is destroyed.
|
||||
*
|
||||
* @see type_representation(TypeRepresentationType the_type_representation)
|
||||
*/
|
||||
void dynamic_type(const dds::core::xtypes::DynamicType *dynamic_type)
|
||||
{
|
||||
DDS_TypeCode *native_typecode = const_cast<DDS_TypeCode*>(
|
||||
reinterpret_cast<const DDS_TypeCode *>(dynamic_type));
|
||||
type_representation(static_cast<TypeRepresentationType>(native_typecode));
|
||||
type_representation_kind(TypeRepresentationKind::DYNAMIC_TYPE);
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif // RTI_ROUTING_ADAPTER_TYPE_INFOHPP_
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* (c) Copyright, Real-Time Innovations, 2017.
|
||||
* All rights reserved.
|
||||
*
|
||||
* No duplications, whole or partial, manual or electronic, may be made
|
||||
* without express written permission. Any such copies, or
|
||||
* revisions thereof, must display this notice unaltered.
|
||||
* This code contains trade secrets of Real-Time Innovations, Inc.
|
||||
*/
|
||||
|
||||
#ifndef RTI_ROUTING_UPDATABLE_ENTITY_HPP_
|
||||
#define RTI_ROUTING_UPDATABLE_ENTITY_HPP_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace rti { namespace routing {
|
||||
|
||||
/** @ingroup RTI_RoutingServiceInfrastructureModule
|
||||
*
|
||||
* @class rti::routing::UpdatableEntity
|
||||
*
|
||||
* @brief Defines a common interface for all the pluggable entities that can
|
||||
* be updated at runtime.
|
||||
*
|
||||
* @product allows to update an pluggable entity through remote administration.
|
||||
*
|
||||
* @mtsafety Safe
|
||||
* The UpdatableEntity::update operation is called only for one
|
||||
* entity at a time. Additionally, no other operations can be made
|
||||
* concurrently on a pluggable entity during the
|
||||
* UpdatableEntity::update call.
|
||||
*/
|
||||
class UpdatableEntity {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Updates a pluggable entity.
|
||||
*
|
||||
* @param properties
|
||||
* @rs_st_in The new configuration properties, obtained as result
|
||||
* of parsing the elements within the <property> tag
|
||||
* corresponding to the entity being updated.
|
||||
*/
|
||||
virtual void update(const std::map<std::string, std::string>& properties)
|
||||
{
|
||||
(void) properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Virtual destructor.
|
||||
*/
|
||||
virtual ~UpdatableEntity()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif // RTI_ROUTING_UPDATABLE_ENTITY_HPP_
|
||||
Loaded 100 of 2395 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user