TypeObject and TypeCode

TypeObject and TypeCode support in RTI Connext DDS

During the matching process, RTI Connext DDS compares the structure of the topic types provided by the DataWriters and DataReaders to determine if they can communicate. To do so, the TypeObject or TypeCode is needed. If the TypeObject or TypeCode is not available, matching is done based on the topic name only.

Earlier versions of RTI Connext DDS (4.5f and lower) use TypeCodes as the wire representation to communicate types over the network and the TypeCode API to introspect and manipulate the types at run time.

RTI Connext DDS 5.x releases include partial support for the “Extensible and Dynamic Topic Types for DDS” (DDS-XTYPES) specification from the Object Management Group (OMG). This is achieved by means of TypeObjects, which is an evolution of TypeCodes. TypeObjects allow systems to define data types in a more flexible way and to evolve data types over time without giving up portability, interoperability, or the expressiveness of the DDS type system.

The XTYPES specification uses TypeObjects as the wire representation. This specification also uses the DynamicType API to introspect and manipulate the types. However, RTI Connext DDS versions before 5.3.1 do not support the DynamicType API. Therefore, you must continue using the TypeCode API to introspect the types at run time for versions before 5.3.1.

Furthermore, RTI Connext DDS 5.x still supports propagation of TypeCodes in order to maintain backward compatibility with previous releases.

However, support for TypeCodes for introspecting the types at run time may be discontinued in future releases. 

Differences between TypeObjects and TypeCodes

One important limitation of using TypeCodes as the wire representation is that their serialized size is limited to 65 KB. This is a problem for services and tools that depend on the discovered types, such as RTI Routing Service and RTI Spreadsheet Add-in for Microsoft Excel. With the introduction of TypeObjects, this limitation is removed since the size of the serialized representation is unbounded.

The following table summarizes the differences between TypeCodes and TypeObjects:
 
 

RTI Connext DDS 6.x/5.x

RTI Connext DDS 4.5f and Earlier

Wire representation

TypeObjects or TypeCodes (for backwards compatibility)

TypeCodes

For introspection at run time

TypeCode API

TypeCode API

Maximum size of serialized representation

When using TypeObjects: Unbounded

When using Typecodes: 65 KB

65 KB

For more information, see the documentation about Type Representation.

Configuring TypeObjects and TypeCodes

The DomainParticipantResourceLimitsQosPolicy includes fields that control resource utilization when TypeObjects in a DomainParticipant are stored and propagated. Note that memory usage is optimized; only one instance of a TypeObject will be stored, even if multiple local or remote DataReaders or DataWriters use it.

By default, RTI Connext DDS will propagate both the pre-standard TypeCode and the new standard TypeObject. It is also possible to send either or none of them:

<participant_qos>
    <resource_limits>
        <type_code_max_serialized_length>0</type_code_max_serialized_length>
    </resource_limits>
</participant_qos>  
<participant_qos>
    <resource_limits>
        <type_object_max_serialized_length>0</type_object_max_serialized_length>
    </resource_limits>
</participant_qos>  

When running RTI Code Generator in 5.x or below, you may use the option -notypecode  to disable the generation of TypeCode information. In 6.x, support for this option has been removed. 

Those QoS policies can also be used to change the size of the TypeObjects or TypeCodes. In order to see the possible scenarios refer to this solution .

If the default size is changed, it affects the system performance because the endpoint discovery messages will be bigger. Also, if the types are bigger than 65KB (it will use TypeObject), the writing will be asynchronous, and it will impact the performace:

It is important to note that using asynchronous writing has other impacts, like longer time for writes (depending on flow controller settings), additional thread creation and complexity. Therefore, this mode should only be used when necessary.

 

Comments

Hi,

Is there any API to access to serialized TypeObjects and use it to reconstruct TypeCode or IDL representation? It'd be nice if I can save the serialized TypeObjects to a file and later reconstruct a TypeCode from reading out TypeObject from the file.

I'm using Connext Pro 6.0.1.

I am also interested in this. I am wondering if this is why I am not able to extract TypeCode from some of the message Topic types i am seeing messages for. 

I desperately want to avoid having to generate thousands of Java classes from IDLs when I am only interesting in managing the persistence of them and general statistics. 

 

Al

Hello

It is possible to serialize TypeCodes or TypeObjects, store them, and deserialize them later to use them as TypesCode or TypeObjects. I’m attaching three snippets of code to show how to serialize and deserialize a TypeCode object in Java, C++11, and C/C++98

To get the TypeCode or TypeObject used by other DataWriters or DataReaders we need to subscribe to the Publication or Subscription Builtin Topic. Depending on the Types we want to gather.

Using the Java API is the easiest way since TypeCode Class implements the Serializable interface, so it is as easy as writing the object to a FileOutputStream to serialize and store, and later you can read the object from an ObjectInputStream to deserialize it and recover the typeCode.

SubscriptionBuiltinTopicData subscription_builtin_topic_data = 
        (SubscriptionBuiltinTopicData) _dataSeq.get(i);

//Extract type_code from the builtin topic
TypeCode type_code = subscription_builtin_topic_data.type_code;
TypeCode type_code_deserialize;
try{
    // Serializing 'type_code'
    FileOutputStream fos = new FileOutputStream("example_file.txt");
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    oos.writeObject(type_code);
    // De-serializing 'type_code'
    FileInputStream fis = new FileInputStream("example_file.txt");
    ObjectInputStream ois = new ObjectInputStream(fis);
    try {
        type_code_deserialize = (TypeCode)ois.readObject();
    } catch (ClassNotFoundException ex1) {
        return;
    }
} catch (IOException ex2) {
    return;
}

if (type_code.equals(type_code_deserialize)) {
    System.out.println("TypeObjects are equal");
} else {
    System.out.println("TypeObjects are not equal");
}

 

If you are using the modern C++ API, the traditional C++ API, or the C API, it will not be as easy When using these APIs, you have to use functions from the underlying C API which are not publicly documented and may change without previous notice.

In C++98 or C the serialization and deserialization could be done as shown below: 

// Get TypeObject from the sample
DDS_TypeObject * type_object = data_seq[i].type;
DDS_TypeObjectFactory * type_object_factory = DDS_TypeObjectFactory_new();

// Create a buffer to store the serialized typeObject
unsigned int buffer_size = DDS_TypeObject_get_serialized_size(type_object);
char * buffer = new char[buffer_size];
DDS_TypeObject_serialize(type_object,buffer,&buffer_size);

// Deserialize the typeObject
DDS_TypeObject * deserialize_type_object = 
        DDS_TypeObjectFactory_create_typeobject_from_serialize_buffer(
                type_object_factory, 
                buffer, buffer_size);

delete buffer;
DDS_TypeObjectFactory_delete(type_object_factory);

// Compare the original TypeObject with the deserialized one
if (DDS_TypeObject_equal(deserialize_type_object,type_object)) {
    std::cout << "TypeObjects are equal" << std::endl;
} else {
    std::cout << "TypeObjects are not equal" << std::endl;
}

// Lastly, we could convert the TypeObject to TypeCode if required
// const DDS_TypeCode * type_code = 
//         DDS_TypeObject_convert_to_typecode(deserialize_type_object);

 

C++11 is so similar to C++98 but first, we should extract TypeCode from a DynamicType as the type information received by the built-in topics (SubscriptionBuiltinTopicData or PublicationBuiltinTopicData) is in the DynamicType format:

// Get Dynamic type and convert it to TypeCode
rti::core::xtypes::DynamicTypeImpl dynamic_type = 
        sample.data()->type().get();
const DDS_TypeCode type_code = dynamic_type.native();

// Convert TypeCode to TypeObject
DDS_TypeObject * type_object;
type_object = DDS_TypeObject_create_from_typecode(&type_code);

// Create a TypeObject factory
DDS_TypeObjectFactory * type_object_factory = DDS_TypeObjectFactory_new();

// Create a buffer to store serialize typeObject and serialize it
unsigned int buffer_size = DDS_TypeObject_get_serialized_size(type_object);
char * buffer = new char[buffer_size];
DDS_TypeObject_serialize(type_object,buffer,&buffer_size);

// Deserialize the typeObject
DDS_TypeObject * deserialize_type_object = 
        DDS_TypeObjectFactory_create_typeobject_from_serialize_buffer(
                type_object_factory, 
                buffer, buffer_size);
delete buffer;

// Compare the original TypeObject with the deserialized one
if(DDS_TypeObject_equal(deserialize_type_object,type_object)) {
    std::cout << "TypeObjects are equal" << std::endl;
} else {
    std::cout << "TypeObjects are not equal" << std::endl;
}

// We could convert the TypeObject to TypeCode
// const DDS_TypeCode * new_type_code = DDS_TypeObject_convert_to_typecode(deserialize_type_object);

 

Regards,

Alberto