Sending and Receiving Custom Data Types

See also

Writing Converters
Writing new converter s instead of registering existing ones.

In principle, projects using RSB can exchange data of arbitrary types. However, in order to send and receive custom data type s, RSB has to know how to serialize and deserialize data of these types. This task is performed by converter s. Converter s are maintained in a repository at runtime. New converter s can be registered to add support for new data type s.

Registering Converters

To add a converter to the repository, the converter object has to be created and the repository object has to be obtained. The following example demonstrates this.

Important

Converter s have to be registered before participant s are created. Otherwise, the participant s can still be created, but do not use the desired converter s.

The function rsb.converter.registerGlobalConverter() is used to register new converters (line 26). After that, the global default participant configuration has to be updated using rsb.setDefaultParticipantConfig() to pick up the newly registered converter (line 37).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import logging

import rsb
import rsb.converter

# Load the generated protocol buffer data holder class from the
# current directory. This would look different if the protocol buffer
# code generation was properly integrated in a build process.
#
# See the comment in SimpleImage.proto for how to manually perform the
# code generation.
import sys
sys.path.append('.')
from SimpleImage_pb2 import SimpleImage

if __name__ == '__main__':
    # Pacify logger.
    logging.basicConfig()

    # Register a protocol buffer converter for SimpleImage:
    # The generated data holder class is
    #   SimepleImage_pb2.SimpleImage
    # The protocol buffer message is called
    #   .tutorial.protobuf_converter.SimpleImage
    converter = rsb.converter.ProtocolBufferConverter(messageClass = SimpleImage)
    rsb.converter.registerGlobalConverter(converter)

    print("Registered converter %s" % converter)
    print("Registered converters:\n%s " % rsb.converter.getGlobalConverterMap(bytearray))

    # After registering one or more converters, it is currently
    # necessary to replace the global default participant
    # configuration with a fresh one which takes into account the
    # newly registered converters.
    #
    # This will hopefully become unnecessary in future RSB versions.
    rsb.setDefaultParticipantConfig(rsb.ParticipantConfig.fromDefaultSources())

Download this example

After creating a converter object (lines 19 and 20), the template function rsb::converter::converterRepository() is used to obtain the converter repository (line 21) and register the converter object via the rsb::converter::Repository::registerConverter method (line 21). The rsb::Factory is obtained only after the converter has been registered, so it can pick up the changed converter set (line 25).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <rsb/Factory.h>

#include <rsb/converter/Repository.h>
#include <rsb/converter/ProtocolBufferConverter.h>

// See ../CMakeLists.txt for the generation of this file.
// The generated file can be found in ${BUILD_DIR}/protobuf_converter
#include <protobuf_converter/SimpleImage.pb.h>

using namespace rsb;

// The generated protocol buffer class is in this namespace.
using namespace tutorial::protobuf_converter;

int main() {
    // Register a specific template instantiation of the
    // ProtocolBufferConverter for our SimpleImage protocol buffer
    // message.
    boost::shared_ptr< rsb::converter::ProtocolBufferConverter<SimpleImage> >
        converter(new rsb::converter::ProtocolBufferConverter<SimpleImage>());
    rsb::converter::converterRepository<std::string>()->registerConverter(converter);

    // After the converter has been registered, the default
    // configuration used by the Factory includes the converter.
    Factory& factory = Factory::getInstance();

    return EXIT_SUCCESS;
}

Download this example

After creating the converter object (lines 16 and 17), it is globally registered using the rsb.converter.ConverterRepository.addConverter method (line 20). The repository is obtained by calling rsb.converter.DefaultConverterRepository.getDefaultConverterRepository (line 20).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package tutorial.protobuf;

import rsb.Factory;

import rsb.converter.DefaultConverterRepository;
import rsb.converter.ProtocolBufferConverter;

import tutorial.protobuf.ImageMessage.SimpleImage;

public class RegistrationExample {

    public static void main(String[] args) throws Throwable {

        // Instantiate generic ProtocolBufferConverter with
        // SimpleImage exemplar.
        ProtocolBufferConverter<SimpleImage> converter
            = new ProtocolBufferConverter<SimpleImage>(SimpleImage.getDefaultInstance());

        // Register converter for the SimpleImage type.
        DefaultConverterRepository.getDefaultConverterRepository().addConverter(converter);

        // The factory now uses the modified set of converters.
        Factory factory = Factory.getInstance();

    }

}

Download this example

Note

In Common Lisp, the mechanism is quite different; will be documented later.