Skip to content

Commit ffbca3e

Browse files
Martin-Idel-SIKarsten1987
authored andcommitted
Split converters (ros2#70)
* ros2GH-134 Split converter interface into Serializer and Deserializer - Allow plugins which can only read or write - Most important example: plugin for old rosbags * ros2GH-134 Switch to using serializer and deserializer in factory * ros2GH-134 Add test for serializer plugin * ros2GH-134 Try to load Serializer and Deserializer - When loading a serializer, try to load both serializer and converter - Similar for deserializers * ros2GH-134 Fix e2e test after improving error message for missing converters * ros2GH-134 Remove duplicate code in converter factory * ros2GH-134 Change namespace of converter interfaces - adapt namespaces to folder structure - folder structure similar to rosbag2_storage * ros2GH-134 Hide pluginlib import via pimpl - We want to use template functions that require the pluginlib import - The pluginlib import should not be exported (this creates issues with downstream packages) - Similar to the storage factory, use a pimpl * ros2GH-134 Adapt documentation * Minor documentation updates Co-Authored-By: Martin-Idel-SI <external.Martin.Idel@bosch-si.com> * ros2GH-134 Rename converter interface to drop "interface" - already visible from namespace
1 parent 366d750 commit ffbca3e

28 files changed

+424
-115
lines changed

docs/converter_plugin_development.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ To simplify conversion between all formats each plugin provides functions to con
88

99
Rosbag2 is shipped with a default converter plugin to convert between ROS 2 messages and serialized messages in the CDR format (this is the general serialization format specified by DDS).
1010

11-
## Writing converter plugins
11+
## Writing converter plugins for both serialization and deserialization
1212

13-
To write a plugin `MyConverter`, implement the interface `rosbag2::SerializationFormatConverterInterface`.
13+
Most converter plugins are used to convert between a custom serialization format in both directions, i.e. serialization and deserialization.
14+
To write a plugin `MyConverter` supporting conversion to and from a custom serialization format, implement the interface `rosbag2::converter_interfaces::SerializationFormatConverter`.
1415

1516
The plugin interface provides two functions:
1617

@@ -22,7 +23,7 @@ Add the following lines in the `my_converter.cpp`:
2223

2324
```
2425
#include "pluginlib/class_list_macros.hpp"
25-
PLUGINLIB_EXPORT_CLASS(MyConverter, rosbag2::SerializationFormatConverterInterface)
26+
PLUGINLIB_EXPORT_CLASS(MyConverter, rosbag2::converter_interfaces::SerializationFormatConverter)
2627
```
2728

2829
Furthermore, we need some meta-information in the form of a `plugin_description.xml` file.
@@ -32,7 +33,7 @@ In the case of `MyConverter` this would look like:
3233
<class
3334
name="my_storage_format_converter"
3435
type="MyConverter"
35-
base_class_type="rosbag2::SerializationFormatConverterInterface"
36+
base_class_type="rosbag2::converter_interfaces::SerializationFormatConverter"
3637
>
3738
<description>This is a converter plugin for my storage format.</description>
3839
</class>
@@ -48,6 +49,16 @@ pluginlib_export_plugin_description_file(rosbag2 plugin_description.xml)
4849

4950
The first argument `rosbag2` denotes the ament index key we add our plugin to (this will always be `rosbag2` for converter plugins), while the second argument is the path to the plugin description file.
5051

52+
## Writing converter plugins for only serialization or deserialization
53+
54+
It is possible to write a plugin which only supports converting to OR from a custom serialization format.
55+
For example, the default plugin for legacy ROS1 rosbags supports only conversion from a ROS 1 to a ROS 2 message format (deserialization), since rosbag2 is not intended to be used to write rosbags in the old format.
56+
When a similar use case applies, it is possible to provide a plugin which supports only one direction (serialization or deserialization).
57+
58+
In order to write a plugin `MyDeserializer` supporting conversion from a custom serialization format, implement the interface `rosbag2::converter_interfaces::SerializationFormatDeserializer.
59+
This interface only provides the `deserialize` method mentioned above.
60+
Similarly, there exists a `rosbag2::converter_interfaces::SerializationFormatSerializer` for serialization plugins.
61+
5162
## How to choose conversion at runtime
5263

5364
The conversion will be chosen automatically according to the storage format specified in the bagfile or specified by the user.

rosbag2/CMakeLists.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,13 @@ if(BUILD_TESTING)
8282
ament_lint_auto_find_test_dependencies()
8383

8484
add_library(
85-
converter_test_plugin
85+
converter_test_plugins
8686
SHARED
87+
test/rosbag2/serializer_test_plugin.cpp
8788
test/rosbag2/converter_test_plugin.cpp)
88-
target_link_libraries(converter_test_plugin rosbag2)
89+
target_link_libraries(converter_test_plugins rosbag2)
8990
install(
90-
TARGETS converter_test_plugin
91+
TARGETS converter_test_plugins
9192
ARCHIVE DESTINATION lib
9293
LIBRARY DESTINATION lib
9394
RUNTIME DESTINATION bin)

rosbag2/include/rosbag2/converter.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#include "rosbag2/converter_options.hpp"
2424
#include "rosbag2/serialization_format_converter_factory.hpp"
2525
#include "rosbag2/serialization_format_converter_factory_interface.hpp"
26-
#include "rosbag2/serialization_format_converter_interface.hpp"
26+
#include "rosbag2/converter_interfaces/serialization_format_converter.hpp"
2727
#include "rosbag2/types.hpp"
2828
#include "rosbag2/visibility_control.hpp"
2929

@@ -78,8 +78,8 @@ class ROSBAG2_PUBLIC Converter
7878

7979
private:
8080
std::shared_ptr<SerializationFormatConverterFactoryInterface> converter_factory_;
81-
std::unique_ptr<SerializationFormatConverterInterface> input_converter_;
82-
std::unique_ptr<SerializationFormatConverterInterface> output_converter_;
81+
std::unique_ptr<converter_interfaces::SerializationFormatDeserializer> input_converter_;
82+
std::unique_ptr<converter_interfaces::SerializationFormatSerializer> output_converter_;
8383
std::unordered_map<std::string, ConverterTypeSupport> topics_and_types_;
8484
};
8585

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2018, Bosch Software Innovations GmbH.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef ROSBAG2__CONVERTER_INTERFACES__SERIALIZATION_FORMAT_CONVERTER_HPP_
16+
#define ROSBAG2__CONVERTER_INTERFACES__SERIALIZATION_FORMAT_CONVERTER_HPP_
17+
18+
#include <memory>
19+
#include <string>
20+
21+
#include "rosbag2/types/introspection_message.hpp"
22+
#include "rosbag2/types.hpp"
23+
#include "rcutils/types.h"
24+
#include "rosbag2_storage/serialized_bag_message.hpp"
25+
#include "rosidl_typesupport_cpp/message_type_support.hpp"
26+
#include "rosbag2/converter_interfaces/serialization_format_serializer.hpp"
27+
#include "rosbag2/converter_interfaces/serialization_format_deserializer.hpp"
28+
29+
/**
30+
* This is a convenience class for plugin developers. When developing a plugin to both write and
31+
* read a specified serialization format, inherit from this class
32+
*/
33+
namespace rosbag2
34+
{
35+
36+
namespace converter_interfaces
37+
{
38+
39+
class SerializationFormatConverter
40+
: public SerializationFormatSerializer, public SerializationFormatDeserializer
41+
{};
42+
43+
} // namespace converter_interfaces
44+
} // namespace rosbag2
45+
46+
#endif // ROSBAG2__CONVERTER_INTERFACES__SERIALIZATION_FORMAT_CONVERTER_HPP_

rosbag2/include/rosbag2/serialization_format_converter_interface.hpp renamed to rosbag2/include/rosbag2/converter_interfaces/serialization_format_deserializer.hpp

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,33 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
#ifndef ROSBAG2__SERIALIZATION_FORMAT_CONVERTER_INTERFACE_HPP_
16-
#define ROSBAG2__SERIALIZATION_FORMAT_CONVERTER_INTERFACE_HPP_
15+
#ifndef ROSBAG2__CONVERTER_INTERFACES__SERIALIZATION_FORMAT_DESERIALIZER_HPP_
16+
#define ROSBAG2__CONVERTER_INTERFACES__SERIALIZATION_FORMAT_DESERIALIZER_HPP_
1717

1818
#include <memory>
19-
#include <string>
2019

2120
#include "rosbag2/types/introspection_message.hpp"
2221
#include "rosbag2/types.hpp"
23-
#include "rcutils/types.h"
24-
#include "rosbag2_storage/serialized_bag_message.hpp"
25-
#include "rosidl_typesupport_cpp/message_type_support.hpp"
2622

2723
namespace rosbag2
2824
{
2925

30-
class SerializationFormatConverterInterface
26+
namespace converter_interfaces
27+
{
28+
29+
class SerializationFormatDeserializer
3130
{
3231
public:
33-
virtual ~SerializationFormatConverterInterface() = default;
32+
virtual ~SerializationFormatDeserializer() = default;
3433

3534
virtual void deserialize(
3635
std::shared_ptr<const rosbag2::SerializedBagMessage> serialized_message,
3736
const rosidl_message_type_support_t * type_support,
3837
std::shared_ptr<rosbag2_introspection_message_t> ros_message) = 0;
39-
40-
virtual void serialize(
41-
std::shared_ptr<const rosbag2_introspection_message_t> ros_message,
42-
const rosidl_message_type_support_t * type_support,
43-
std::shared_ptr<rosbag2::SerializedBagMessage> serialized_message) = 0;
4438
};
4539

40+
41+
} // namespace converter_interfaces
4642
} // namespace rosbag2
4743

48-
#endif // ROSBAG2__SERIALIZATION_FORMAT_CONVERTER_INTERFACE_HPP_
44+
#endif // ROSBAG2__CONVERTER_INTERFACES__SERIALIZATION_FORMAT_DESERIALIZER_HPP_
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2018, Bosch Software Innovations GmbH.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef ROSBAG2__CONVERTER_INTERFACES__SERIALIZATION_FORMAT_SERIALIZER_HPP_
16+
#define ROSBAG2__CONVERTER_INTERFACES__SERIALIZATION_FORMAT_SERIALIZER_HPP_
17+
18+
#include <memory>
19+
20+
#include "rosbag2/types/introspection_message.hpp"
21+
#include "rosbag2/types.hpp"
22+
23+
namespace rosbag2
24+
{
25+
26+
namespace converter_interfaces
27+
{
28+
29+
class SerializationFormatSerializer
30+
{
31+
public:
32+
virtual ~SerializationFormatSerializer() = default;
33+
34+
virtual void serialize(
35+
std::shared_ptr<const rosbag2_introspection_message_t> ros_message,
36+
const rosidl_message_type_support_t * type_support,
37+
std::shared_ptr<rosbag2::SerializedBagMessage> serialized_message) = 0;
38+
};
39+
40+
} // namespace converter_interfaces
41+
} // namespace rosbag2
42+
43+
#endif // ROSBAG2__CONVERTER_INTERFACES__SERIALIZATION_FORMAT_SERIALIZER_HPP_

rosbag2/include/rosbag2/serialization_format_converter_factory.hpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919

2020
#include <memory>
2121
#include <string>
22+
#include <vector>
2223

23-
#include "rosbag2/serialization_format_converter_interface.hpp"
2424
#include "rosbag2/visibility_control.hpp"
2525

2626
// This is necessary because of using stl types here. It is completely safe, because
@@ -31,17 +31,11 @@
3131
# pragma warning(disable:4251)
3232
#endif
3333

34-
namespace pluginlib
35-
{
36-
37-
template<class T>
38-
class ClassLoader;
39-
40-
} // namespace pluginlib
41-
4234
namespace rosbag2
4335
{
4436

37+
class SerializationFormatConverterFactoryImpl;
38+
4539
class ROSBAG2_PUBLIC SerializationFormatConverterFactory
4640
: public SerializationFormatConverterFactoryInterface
4741
{
@@ -50,11 +44,14 @@ class ROSBAG2_PUBLIC SerializationFormatConverterFactory
5044

5145
~SerializationFormatConverterFactory() override;
5246

53-
std::unique_ptr<SerializationFormatConverterInterface>
54-
load_converter(const std::string & format) override;
47+
std::unique_ptr<converter_interfaces::SerializationFormatDeserializer>
48+
load_deserializer(const std::string & format) override;
49+
50+
std::unique_ptr<converter_interfaces::SerializationFormatSerializer>
51+
load_serializer(const std::string & format) override;
5552

5653
private:
57-
std::unique_ptr<pluginlib::ClassLoader<SerializationFormatConverterInterface>> class_loader_;
54+
std::unique_ptr<SerializationFormatConverterFactoryImpl> impl_;
5855
};
5956

6057
} // namespace rosbag2

rosbag2/include/rosbag2/serialization_format_converter_factory_interface.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include <memory>
1919
#include <string>
2020

21-
#include "rosbag2/serialization_format_converter_interface.hpp"
21+
#include "rosbag2/converter_interfaces/serialization_format_converter.hpp"
2222
#include "rosbag2/visibility_control.hpp"
2323

2424
namespace rosbag2
@@ -29,8 +29,11 @@ class ROSBAG2_PUBLIC SerializationFormatConverterFactoryInterface
2929
public:
3030
virtual ~SerializationFormatConverterFactoryInterface() = default;
3131

32-
virtual std::unique_ptr<SerializationFormatConverterInterface>
33-
load_converter(const std::string & format) = 0;
32+
virtual std::unique_ptr<converter_interfaces::SerializationFormatDeserializer>
33+
load_deserializer(const std::string & format) = 0;
34+
35+
virtual std::unique_ptr<converter_interfaces::SerializationFormatSerializer>
36+
load_serializer(const std::string & format) = 0;
3437
};
3538

3639
} // namespace rosbag2

rosbag2/src/rosbag2/converter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ Converter::Converter(
3939
const rosbag2::ConverterOptions & converter_options,
4040
std::shared_ptr<rosbag2::SerializationFormatConverterFactoryInterface> converter_factory)
4141
: converter_factory_(converter_factory),
42-
input_converter_(converter_factory_->load_converter(
42+
input_converter_(converter_factory_->load_deserializer(
4343
converter_options.input_serialization_format)),
44-
output_converter_(converter_factory_->load_converter(
44+
output_converter_(converter_factory_->load_serializer(
4545
converter_options.output_serialization_format))
4646
{
4747
if (!input_converter_) {

rosbag2/src/rosbag2/serialization_format_converter_factory.cpp

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,45 +16,29 @@
1616

1717
#include <memory>
1818
#include <string>
19+
#include <vector>
1920

20-
#include "pluginlib/class_loader.hpp"
21-
#include "rosbag2/logging.hpp"
21+
#include "./serialization_format_converter_factory_impl.hpp"
2222

2323
namespace rosbag2
2424
{
2525

2626
SerializationFormatConverterFactory::SerializationFormatConverterFactory()
27-
{
28-
try {
29-
class_loader_ = std::make_unique<pluginlib::ClassLoader<SerializationFormatConverterInterface>>(
30-
"rosbag2", "rosbag2::SerializationFormatConverterInterface");
31-
} catch (const std::exception & e) {
32-
ROSBAG2_LOG_ERROR_STREAM("Unable to create class loader instance: " << e.what());
33-
throw e;
34-
}
35-
}
27+
: impl_(std::make_unique<SerializationFormatConverterFactoryImpl>())
28+
{}
3629

3730
SerializationFormatConverterFactory::~SerializationFormatConverterFactory() = default;
3831

39-
std::unique_ptr<SerializationFormatConverterInterface>
40-
SerializationFormatConverterFactory::load_converter(const std::string & format)
32+
std::unique_ptr<converter_interfaces::SerializationFormatDeserializer>
33+
SerializationFormatConverterFactory::load_deserializer(const std::string & format)
34+
{
35+
return impl_->load_deserializer(format);
36+
}
37+
38+
std::unique_ptr<converter_interfaces::SerializationFormatSerializer>
39+
SerializationFormatConverterFactory::load_serializer(const std::string & format)
4140
{
42-
auto converter_id = format + "_converter";
43-
44-
const auto & registered_classes = class_loader_->getDeclaredClasses();
45-
auto class_exists = std::find(registered_classes.begin(), registered_classes.end(), converter_id);
46-
if (class_exists == registered_classes.end()) {
47-
ROSBAG2_LOG_ERROR_STREAM("Requested converter id '" << converter_id << "' does not exist");
48-
return nullptr;
49-
}
50-
51-
try {
52-
return std::unique_ptr<SerializationFormatConverterInterface>(
53-
class_loader_->createUnmanagedInstance(converter_id));
54-
} catch (const std::runtime_error & ex) {
55-
ROSBAG2_LOG_ERROR_STREAM("Unable to load instance of converter interface: " << ex.what());
56-
return nullptr;
57-
}
41+
return impl_->load_serializer(format);
5842
}
5943

6044
} // namespace rosbag2

0 commit comments

Comments
 (0)