Chapter 17 Data Types and DDS Data Samples
Note: Information in this chapter is complemented by information in the RTI Connext Core Libraries Extensible Types Guide.
How data is stored or laid out in memory can vary from language to language, compiler to compiler, operating system to operating system, and processor to processor. This combination of language/compiler/operating system/processor is called a platform. Any modern middleware must be able to take data from one specific platform (say C/gcc 7.3/Linux/Arm v8) and transparently deliver it to another (for example, Java/AdoptOpenJDK 17.0.6/Windows/Pentium). This process is commonly called serialization/deserialization, or marshalling/demarshalling.
Messaging products have typically taken one of two approaches to this problem:
- Do nothing. Messages consist only of opaque streams of bytes. The JMS BytesMessage is an example of this approach.
- Send everything, every time. Self-describing messages are at the opposite extreme, embedding full reflective information, including data types and field names, with each message. The JMS MapMessage and the messages in TIBCO Rendezvous are examples of this approach.
The “do nothing” approach is lightweight on its surface but forces you, the user of the middleware API, to consider all data encoding, alignment, and padding issues. The “send everything” alternative results in large amounts of redundant information being sent with every packet, impacting performance.
Connext takes an intermediate approach. Just as objects in your application program belong to some data type, DDS data samples sent on the same Connext topic share a data type. This type defines the fields that exist in the DDS data samples and what their constituent types are. The middleware stores and propagates this meta-information separately from the individual DDS data samples, allowing it to propagate DDS samples efficiently while handling byte ordering and alignment issues for you.
To publish and/or subscribe to data with Connext, you will carry out the following steps:
- Select a type to describe your data.
- Use a built-in type provided by the middleware.
- Use the RTI Code Generator to define a type at compile-time using a language-independent description language.
Code generation offers two strong benefits not available with dynamic type definition: (1) it allows you to share type definitions across programming languages, and (2) because the structure of the type is known at compile time, it provides rigorous static type safety.
The RTI Code Generator accepts input in the following formats:
- OMG IDL. This format is a standardized component of the DDS specification. It describes data types with a C++-like syntax. A link to the latest specification can be found here: https://www.omg.org/spec/IDL. This format is described in 17.3 Creating User Data Types with IDL.
- XML in a DDS-specific format. This XML format is terser, and therefore easier to read and write by hand, than an XSD file. It offers the general benefits of XML-extensibility and ease of integration, while fully supporting DDS-specific data types and concepts. A link to the latest specification, including a description of the XML format, can be found here: https://www.omg.org/spec/DDS-XTypes/. This format is described in 17.4 Creating User Data Types with Extensible Markup Language (XML).
- XSD format. You can describe data types with XML schemas (XSD). A link to the latest specification, including a description of the XSD format, can be found here: https://www.omg.org/spec/DDS-XTypes/. This format is described in 17.5 Creating User Data Types with XML Schemas (XSD)
- Define a type programmatically at run time.
- Register your type with a logical name.
- Create a Topic using the type name you previously registered.
- Create one or more DataWriters to publish your data and one or more DataReaders to subscribe to it.
You have a number of choices. You can choose one of these options, or you can mix and match them.
This option may be sufficient if your data typing needs are very simple. If your data is highly structured, or you need to be able to examine fields within that data for filtering or other purposes, this option may not be appropriate. The built-in types are described in 17.2 Built-in Data Types.
This method may be appropriate for applications with dynamic data description needs: applications for which types change frequently or cannot be known ahead of time. It is described in 17.8.2 Defining New Types.
If you've chosen to use a built-in type instead of defining your own, you can omit this step; the middleware pre-registers the built-in types for you.
This step is described in the 17.8.2 Defining New Types.
If you've chosen to use a built-in type instead of defining your own, you will use the API constant corresponding to that type's name.
Creating and working with Topics is discussed in Chapter 18 Working with Topics.
The concrete types of these objects depend on the concrete data type you've selected, in order to provide you with a measure of type safety.
Creating and working with DataWriters and DataReaders are described in Part 5: Sending Data with Connext and Chapter 38 Overview of Receiving Data, respectively.
Whether publishing or subscribing to data, you will need to know how to create and delete DDS data samples and how to get and set their fields. These tasks are described in 17.9 Working with DDS Data Samples.