Sending and Receiving Custom Data Types

See also

Writing Converters Writing new converters 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 types, RSB has to know how to serialize and deserialize data of these types. This task is performed by converters. Converters are maintained in a repository at runtime. New converters can be registered to add support for new data types.

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

Converters have to be registered before participants are created. Otherwise, the participants can still be created, but do not use the desired converters.

The function rsb.converter.registerGlobalConverter() is used to register new converters (line 26).

 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
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))

Note

In previous versions of RSB the default participant configuration had to be recreated after adding a converter by calling rsb.setDefaultParticipantConfig(rsb.ParticipantConfig.fromDefaultSources()). This is not required anymore starting with RSB 0.9. Additionally, it is explicitly discouraged now since multiple libraries using this strategy might conflict by erasing converters previously registered by other libraries. Please remove these lines from your existing code.

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 = getFactory();

    return EXIT_SUCCESS;
}

Download this example

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

 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(final String[] args) throws Throwable {

        // Instantiate generic ProtocolBufferConverter with
        // SimpleImage exemplar.
        final 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.
        @SuppressWarnings("unused")
        final Factory factory = Factory.getInstance();

    }

}

Download this example

Note

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