AutoAPMS
Streamlining behaviors in ROS 2
Loading...
Searching...
No Matches
resource.hpp
1// Copyright 2024 Robin Müller
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#pragma once
16
17#include <map>
18#include <set>
19#include <string>
20#include <type_traits>
21#include <vector>
22
23#include "auto_apms_util/container.hpp"
24#include "auto_apms_util/exceptions.hpp"
25#include "auto_apms_util/string.hpp"
26#include "pluginlib/class_loader.hpp"
27
28namespace auto_apms_util
29{
30
33
44std::set<std::string> getPackagesWithResourceType(
45 const std::string & resource_type, const std::set<std::string> & exclude_packages = {});
46
56std::set<std::string> getPackagesWithPluginResources(const std::set<std::string> & exclude_packages = {});
57
69std::string getPluginXMLPath(const std::string & package);
70
82std::vector<std::string> collectPluginXMLPaths(const std::set<std::string> & exclude_packages = {});
83
85
86// clang-format off
109// clang-format on
110template <typename BaseT>
111class PluginClassLoader : public pluginlib::ClassLoader<BaseT>
112{
113public:
129 const std::string & base_package, const std::string & base_class,
130 const std::set<std::string> & exclude_packages = {});
131
156 const std::string & base_package, const std::string & base_class,
157 const std::set<std::string> & exclude_packages = {},
158 const std::map<std::string, std::string> & reserved_names = {});
159
179 const std::string & base_package, const std::string & base_class,
180 const std::set<std::string> & exclude_packages = {},
181 const std::map<std::string, std::string> & reserved_names = {});
182
187 std::map<std::string, std::string> getClassPackageMap();
188};
189
190// #####################################################################################################################
191// ################################ DEFINITIONS ##############################################
192// #####################################################################################################################
193
194template <typename BaseT>
196 const std::string & base_package, const std::string & base_class, const std::set<std::string> & exclude_packages)
197: pluginlib::ClassLoader<BaseT>(base_package, base_class, "", collectPluginXMLPaths(exclude_packages))
198{
199}
200
201template <typename BaseT>
203 const std::string & base_package, const std::string & base_class, const std::set<std::string> & exclude_packages,
204 const std::map<std::string, std::string> & reserved_names)
205{
206 verifyUnambiguousClassNames(base_package, base_class, exclude_packages, reserved_names);
207 return {base_package, base_class, exclude_packages};
208}
209
210template <typename BaseT>
212 const std::string & base_package, const std::string & base_class, const std::set<std::string> & exclude_packages,
213 const std::map<std::string, std::string> & reserved_names)
214{
215 std::map<std::string, std::vector<std::string>> packages_for_class_name;
216 const std::set<std::string> packages = getPackagesWithPluginResources(exclude_packages);
217 for (const auto & package : packages) {
218 auto single_package_loader =
219 pluginlib::ClassLoader<BaseT>(base_package, base_class, "", {getPluginXMLPath(package)});
220 for (const auto & class_name : single_package_loader.getDeclaredClasses()) {
221 packages_for_class_name[class_name].push_back(package);
222 }
223 }
224
225 // Reserved class names are considered as registered
226 for (const auto & [class_name, package] : reserved_names) {
227 packages_for_class_name[class_name].push_back(package);
228 }
229
230 // Determine if there are duplicate class names
231 std::vector<std::string> error_details;
232 for (const auto & [class_name, packages] : packages_for_class_name) {
233 if (packages.size() > 1) {
234 error_details.push_back(
235 "- Class '" + class_name + "' found in packages ['" + auto_apms_util::join(packages, "', '") + "'].");
236 }
237 }
238 if (!error_details.empty()) {
239 throw exceptions::ResourceError(
240 "Ambiguous class names found! PluginClassLoader (Base: " + base_class +
241 ") verified with verifyUnambiguousClassNames() won't register resources from packages "
242 "that use already existing lookup names. Found the following duplicates:\n" +
243 auto_apms_util::join(error_details, "\n"));
244 }
245}
246
247template <typename BaseT>
248inline std::map<std::string, std::string> PluginClassLoader<BaseT>::getClassPackageMap()
249{
250 std::map<std::string, std::string> map;
251 for (const std::string & class_name : this->getDeclaredClasses()) {
252 map[class_name] = this->getClassPackage(class_name);
253 }
254 return map;
255}
256
257} // namespace auto_apms_util
static PluginClassLoader makeUnambiguousPluginClassLoader(const std::string &base_package, const std::string &base_class, const std::set< std::string > &exclude_packages={}, const std::map< std::string, std::string > &reserved_names={})
Parse all associated plugin manifest files registered with the ament resource index and instantiate a...
Definition resource.hpp:202
static void verifyUnambiguousClassNames(const std::string &base_package, const std::string &base_class, const std::set< std::string > &exclude_packages={}, const std::map< std::string, std::string > &reserved_names={})
Perform the ambiguity check of makeUnambiguousPluginClassLoader without creating a PluginClassLoader.
Definition resource.hpp:211
std::map< std::string, std::string > getClassPackageMap()
Retrieve a map that contains information about which package a plugin class belongs to.
Definition resource.hpp:248
PluginClassLoader(const std::string &base_package, const std::string &base_class, const std::set< std::string > &exclude_packages={})
Standard PluginClassLoader constructor.
Definition resource.hpp:195
std::vector< std::string > collectPluginXMLPaths(const std::set< std::string > &exclude_packages={})
Collect the paths of plugins.xml manifest files generated by AutoAPMS.
Definition resource.cpp:64
std::string getPluginXMLPath(const std::string &package)
Get the path of a specific plugins.xml manifest file generated by AutoAPMS.
Definition resource.cpp:46
std::set< std::string > getPackagesWithResourceType(const std::string &resource_type, const std::set< std::string > &exclude_packages={})
Get a list of all package names that register a certain type of ament_index resources.
Definition resource.cpp:28
std::set< std::string > getPackagesWithPluginResources(const std::set< std::string > &exclude_packages={})
Get a list of all package names that register AutoAPMS plugin resources.
Definition resource.cpp:41
Fundamental helper classes and utility functions.