View on GitHub

RefleX

Building DDS Applications without IDL

Download this project as a .zip file Download this project as a tar.gz file

RTI logo

RefleX Logo

RefleX is short for Reflection for DDS-XTypes. The main objective of this library is to create DDS-XTypes compliant types and data directly from native C++ types. RefleX is declarative–i.e., it is not a reflection API. There is no separate code generation step involved (other than compilation). The RefleX library will take your application-level datatypes in C++ and will happily map them to equivalent DDS topic types.

Example

Consider the following simple ShapeType class.

class ShapeType 
{
  std::string color_;
  int x_, y_, shapesize_;

public:
  ShapeType() {}
  ShapeType(const std::string & color,
            int x, int y, int shapesize)
    : color_(color), x_(x), y_(y),
      shapesize_(shapesize)
  {}

  std::string & color() { return color_;     }
  int & x()             { return x_;         }
  int & y()             { return y_;         }
  int & shapesize()     { return shapesize_; }

  const std::string & color() const { return color_;     }
  const int & x()             const { return x_;         }
  const int & y()             const { return y_;         }
  const int & shapesize()     const { return shapesize_; }
};

To send and receive instances of this class using DDS, simply add the REFLEX_ADAPT_STRUCT macro below. Note that color is the key.

#include "reflex.h"

REFLEX_ADAPT_STRUCT(
  ShapeType,
  (std::string, color(), REFLEX_KEY)
  (int,             x())
  (int,             y())
  (int,     shapesize()))

The ShapeType class and its objects can now be used with RTI Connext DDS. Here's the main program that writes a ShapeType objects. GenericDataWriter is an thin shim layer to simplify using DDS DataWriter with RefleX. It is not mandatory, however.

int main (void)
{
  // ... setup participant

  reflex::pub::GenericDataWriter<ShapeType>
      writer(participant, "Square");
  ShapeType shape("BLUE", 10, 20, 30);
  writer.write(shape);
}

RefleX maps the ShapeType class to the following ShapeType IDL, which is inter-operable with the Shapes Demo.

struct ShapeType
{
    string<128> color; //@key
    long x;
    long y;
    long shapesize;
};//@Extensibility EXTENSIBLE_EXTENSIBILITY

Why RefleX?

  1. Use Native C++ Types with DDS (IDL-free): IDL representation of DDS types is no longer necessary. Adapted C++ types declarations in the headers are sufficient. With RefleX, you are free to use C++ standard library types, such as STL containers, custom iterators, shared_ptr, auto_ptr, unique_ptr, etc. The RefleX library has a predefined mapping for each and you can also define your own.

  2. Use Declarative Dynamic Data: DynamicData and TypeCode objects can be created declaratively as opposed to procedurally, which quickly gets laborious and repetitive as the complexity of the type increases. RefleX is based on the principle of Don't Repeat Yourself (DRY). RefleX completely eliminates the repetitive work in using the DynamicData API. Many times, types are known statically but no code generation support is available (e.g., RTI Routing Service adapters). With RefleX, creating a TypeCode and populating a corresponding DynamicData object is never more than one line of code!

  3. Use Third-party Code Generators: Classes generated by third-party code generation tools can be mapped to DDS topic types. The key is that RefleX works directly off of C++ types. The generated types may use a wide variety of types (e.g., boost containers, custom iterators, etc.). RefleX provides a way to map such types directly to a DDS. For example, with RefleX the types generated by a third-party XSD to C++ compiler can be mapped to DDS by adding an RTI_ADAPT_STRUCT macro for each generated type. See an example of mapping OSA-CBM XSD to DDS using the Code Synthesis open-source code generator.

  4. Improve Performance: Users of complex XML vocabularies (e.g., XSD) often serialize data to plain-text XML before writing it out to DDS. Such an approach incurs significant performance penalty as data is serialized twice. RefleX does only one serialization as the underlying DynamicData representation is already serialized.

  5. Avoid Glue code: Glue code must often be written because wire-level types may not always match with the application-level types. RefleX allows direct use of application-level types with DDS. Glue code is nearly eliminated. It's all about avoiding repeating yourself.

What powers RefleX?

The Reflex library uses powerful C++ meta-programming (templates and the preprocessor) machinery to iterate over the members of the user-defined type and synthesizes equivalent TypeObject representation for the type and DynamicData representation for the state. RTI_ADAPT_STRUCT macro acts as a substitute for reflection in C++. The macro uses Boost Fusion internally. It is not the kind of reflection in the Java/C# world. It is a macro, which opens the guts of the specified type to the RefleX library (take a look). The key difference is that the process of reflection happens at compile-time. As a consequence, there is no run-time performance penalty for using reflection. The resulting on-the-wire type description is fully compatible with an equivalent type described in IDL. Needless to say, they interoperate.

Architecture

RefleX is based on a simple layered architecture. DDS applications based on the classic C++ DDS API and the new C++ DDS PSM can make use of RefleX.

Architecture

Native C++ Types Supported by RefleX

Download and Build

Linux

  1. Recommended compilers: g++ 4.8, clang 3.3 or better
  2. export REFLEXHOME, BOOSTHOME (1.46+) and NDDSHOME (5.0.0+)
  3. export ARCH=i86Linux2.6gcc4.8.2, for example.
  4. See make/Makefile* for details
  5. export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$NDDSHOME/lib/$ARCH:$REFLEXHOME/objs/$ARCH
  6. Build: make -f make/Makefile.i86Linux-gcc CXX=g++48 (g++48 must be in your $PATH)
  7. Build tests: make/Makefile.i86Linux-gcc test
  8. Build perf_test: make/Makefile.i86Linux-gcc perf_test
  9. Build property_test: make/Makefile.i86Linux-gcc prop_test CXX=g++5 CXXSTD=c++14 RANDOM=$RANDOM

Windows

  1. Use Visual Studio 2013
  2. Set REFLEXHOME, BOOSTHOME (1.46+), and NDDSHOME (5.1.0+)
  3. Set PATH=%PATH%;%REFLEXHOME%\objs\i86Win32VS2013;%NDDSHOME%\lib\i86Win32VS2012
  4. Run %NDDSHOME%\scripts\rtiddsgen -language C++ -namespace -d test idl\complex.idl
  5. Open win32\reflex-vs2013.sln

Documentation

See RefleX documentation generated using Doxygen.

More reading

License

(c) 2005-2014 Copyright, Real-Time Innovations, Inc. All rights reserved.
RTI grants Licensee a license to use, modify, compile, and create derivative works of the Software. Licensee has the right to distribute object form only for use with RTI products. The Software is provided “as is”, with no warranty of any type, including any warranty for fitness for any purpose. RTI is under no obligation to maintain or support the Software. RTI shall not be liable for any incidental or consequential damages arising out of the use or inability to use the software.

Contact

Sumant Tambe (sumant at RTI d0t com)