VariantInfo.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package
19 * @author
20 * @date
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24#include "VariantInfo.h"
25
26#include <filesystem>
27
28#include <SimoxUtility/algorithm/string.h>
29
35#include <ArmarXCore/interface/observers/VariantContainers.h>
39
40namespace armarx
41{
45
46 std::vector<VariantInfo::LibEntryPtr>
48 const std::string& packagePath,
49 const std::string& packageName)
50 {
51 std::vector<LibEntryPtr> libs;
52 if (packagePaths.find(packagePath) != packagePaths.end())
53 {
54 ARMARX_DEBUG_S << "path '" << packagePath << "' already in there.";
55 return libs;
56 }
57
58 packagePaths[(packagePath)] = packageName;
59 RapidXmlReaderNode node = reader->getRoot("VariantInfo");
60 for (RapidXmlReaderNode libNode = node.first_node("Lib"); libNode.is_valid();
61 libNode = libNode.next_sibling("Lib"))
62 {
63 LibEntryPtr lib(new LibEntry(libNode, packageName));
64 this->libs.push_back(lib);
65 libs.push_back(lib);
66
67 for (VariantEntryPtr e : lib->variants)
68 {
69 variantToLibMap.insert(std::make_pair(e->baseTypeName, lib));
70 variantMap.insert(std::make_pair(e->baseTypeName, e));
71 humanNameToVariantMap.insert(std::make_pair(e->humanName, e));
72 }
73
74 for (ProxyEntryPtr p : lib->proxies)
75 {
76 proxyMap.insert(std::make_pair(lib->name + "." + p->memberName, p));
77 }
78 }
79 return libs;
80 }
81
83 VariantInfo::findLibByVariant(std::string variantTypeName) const
84 {
85 std::map<std::string, LibEntryPtr>::const_iterator it =
86 variantToLibMap.find(variantTypeName);
87
88 if (it == variantToLibMap.end())
89 {
90 return LibEntryPtr();
91 }
92 else
93 {
94 return it->second;
95 }
96 }
97
99 VariantInfo::findLibByProxy(std::string proxyTypeName) const
100 {
102 {
103 std::string libName = lib->getName();
104 for (VariantInfo::ProxyEntryPtr proxy : lib->getProxies())
105 {
106 if (proxy->getMemberName() == proxyTypeName)
107 {
108 return lib;
109 }
110 }
111 }
112 return LibEntryPtr();
113 }
114
115 Ice::StringSeq
116 VariantInfo::findLibNames(const Ice::StringSeq& variantTypeNames,
117 const Ice::StringSeq& proxyTypeNames) const
118 {
119 Ice::StringSeq result;
120 for (const LibEntryPtr& lib : findLibs(variantTypeNames, proxyTypeNames))
121 {
122 if (lib)
123 {
124 result.push_back(lib->getName());
125 }
126 }
127 return result;
128 }
129
130 std::set<VariantInfo::LibEntryPtr>
131 VariantInfo::findLibs(const Ice::StringSeq& variantTypeNames,
132 const Ice::StringSeq& proxyTypeNames) const
133 {
134 std::set<VariantInfo::LibEntryPtr> result;
135 for (auto& var : variantTypeNames)
136 {
137 auto lib = findLibByVariant(var);
138 if (lib)
139 {
140 result.insert(lib);
141 }
142 }
143 for (auto& proxy : proxyTypeNames)
144 {
145 auto lib = findLibByProxy(proxy);
146 if (lib)
147 {
148 result.insert(lib);
149 }
150 }
151 return result;
152 }
153
154 std::string
155 VariantInfo::getDataTypeName(std::string variantBaseTypeName)
156 {
157 std::map<std::string, VariantEntryPtr>::const_iterator it =
158 variantMap.find(variantBaseTypeName);
159
160 if (it == variantMap.end())
161 {
162 return "NOT_FOUND";
163 }
164 else
165 {
166 return it->second->dataTypeName;
167 }
168 }
169
170 std::string
171 VariantInfo::getReturnTypeName(std::string variantBaseTypeName)
172 {
173 std::map<std::string, VariantEntryPtr>::const_iterator it =
174 variantMap.find(variantBaseTypeName);
175
176 if (it == variantMap.end())
177 {
178 return "NOT_FOUND";
179 }
180 else
181 {
182 // NOTE: Here a typedef in the form of "typedef IceInternal::Handle<[VariantDataType]> [VariantDataType]Ptr;" is assumed.
183 // If this typedef is missing, the statechart code generator WILL GENERATE INVALID CODE.
184 VariantEntryPtr e = it->second;
185 return e->basic ? e->dataTypeName : e->dataTypeName + "Ptr";
186 }
187 }
188
189 bool
190 VariantInfo::isBasic(std::string variantBaseTypeName)
191 {
192 std::map<std::string, VariantEntryPtr>::const_iterator it =
193 variantMap.find(variantBaseTypeName);
194
195 if (it == variantMap.end())
196 {
197 return false;
198 }
199 else
200 {
201 VariantEntryPtr e = it->second;
202 return e->basic;
203 }
204 }
205
206 std::vector<VariantInfo::LibEntryPtr>
208 {
209 return libs;
210 }
211
213 VariantInfo::getProxyEntry(std::string proxyId)
214 {
215 std::map<std::string, ProxyEntryPtr>::const_iterator it = proxyMap.find(proxyId);
216
217 if (it == proxyMap.end())
218 {
219 return ProxyEntryPtr();
220 }
221 else
222 {
223 return it->second;
224 }
225 }
226
228 VariantInfo::getVariantByName(std::string variantBaseTypeName)
229 {
230 std::map<std::string, VariantEntryPtr>::const_iterator it =
231 variantMap.find(variantBaseTypeName);
232
233 if (it == variantMap.end())
234 {
235 return VariantEntryPtr();
236 }
237 else
238 {
239 return it->second;
240 }
241 }
242
245 {
246 std::map<std::string, VariantEntryPtr>::const_iterator it =
247 humanNameToVariantMap.find(humanName);
248
249 if (it == humanNameToVariantMap.end())
250 {
251 return VariantEntryPtr();
252 }
253 else
254 {
255 return it->second;
256 }
257 }
258
259 std::string
260 VariantInfo::getNestedHumanNameFromBaseName(std::string variantBaseTypeName)
261 {
262 ContainerTypePtr containerInfo = VariantContainerType::FromString(variantBaseTypeName);
263 std::stringstream containers;
264 std::stringstream parenthesis;
265
266 while (containerInfo->subType)
267 {
268 if (containerInfo->typeId == SingleTypeVariantList::getTypePrefix())
269 {
270 containers << "List(";
271 }
272 else if (containerInfo->typeId == StringValueMap::getTypePrefix())
273 {
274 containers << "Map(";
275 }
276 else
277 {
278 return "";
279 }
280
281 parenthesis << ")";
282 containerInfo = containerInfo->subType;
283 }
284
285 VariantEntryPtr entry = getVariantByName(containerInfo->typeId);
286
287 if (!entry)
288 {
289 return "";
290 }
291
292 return containers.str() + entry->humanName + parenthesis.str();
293 }
294
295 std::string
297 {
298 ContainerTypePtr containerInfo = VariantContainerType::FromString(humanName);
299 std::stringstream containers;
300 std::stringstream parenthesis;
301
302 while (containerInfo->subType)
303 {
304 if (containerInfo->typeId == "List")
305 {
306 containers << SingleTypeVariantList::getTypePrefix() << "(";
307 }
308 else if (containerInfo->typeId == "Map")
309 {
310 containers << StringValueMap::getTypePrefix() << "(";
311 }
312 else
313 {
314 return "";
315 }
316
317 parenthesis << ")";
318 containerInfo = containerInfo->subType;
319 }
320
321 VariantEntryPtr entry = getVariantByHumanName(containerInfo->typeId);
322
323 if (!entry)
324 {
325 return "";
326 }
327
328 return containers.str() + entry->baseTypeName + parenthesis.str();
329 }
330
331 const std::map<std::string, std::string>&
333 {
334 return packagePaths;
335 }
336
337 bool
338 VariantInfo::isPackageLoaded(const std::string packageName) const
339 {
340 for (const auto& p : packagePaths)
341 {
342 if (p.second == packageName)
343 {
344 return true;
345 }
346 }
347 return false;
348 }
349
350 std::string
352 {
353 std::stringstream ss;
354
355 for (const LibEntryPtr& e : libs)
356 {
357 ss << e->getName() << "\n";
358
359 for (const VariantEntryPtr& v : e->variants)
360 {
361 ss << " " << v->getHumanName() << ": " << v->dataTypeName << "\n";
362 }
363
364 for (const ProxyEntryPtr& p : e->getProxies())
365 {
366 ss << " " << p->getHumanName() << ": " << p->getIncludePath() << "\n";
367 }
368 }
369
370 return ss.str();
371 }
372
374 VariantInfo::ReadInfoFilesRecursive(const std::string& eventuallyNamespacedPackage,
375 const std::string& rootPackagePath,
376 bool showErrors,
377 VariantInfoPtr variantInfo)
378 {
379 if (!variantInfo)
380 {
381 variantInfo.reset(new VariantInfo());
382 }
383
384 const std::string cmakePackageName =
385 simox::alg::replace_all(eventuallyNamespacedPackage, "::", "_");
386
387
388 auto finder = CMakePackageFinderCache::GlobalCache.findPackage(
389 cmakePackageName, rootPackagePath, false, true);
390 ;
391 ARMARX_CHECK_EXPRESSION(finder.packageFound()) << cmakePackageName << " at "
392 << "'" << rootPackagePath << "'\n";
393
394 std::filesystem::path variantInfoFile(finder.getDataDir().c_str());
395 variantInfoFile /= cmakePackageName;
396 variantInfoFile /= "VariantInfo-" + cmakePackageName + ".xml";
397
398 if (std::filesystem::exists(variantInfoFile))
399 {
400 if (!variantInfo->isPackageLoaded(cmakePackageName))
401 {
402 try
403 {
404 RapidXmlReaderPtr xmlReader =
405 RapidXmlReader::FromFile(variantInfoFile.string());
406 variantInfo->readVariantInfo(xmlReader, rootPackagePath, cmakePackageName);
407 ARMARX_DEBUG_S << "Read " << variantInfoFile.string();
408 }
409 catch (std::exception& e)
410 {
411 ARMARX_ERROR_S << "Reading " << variantInfoFile.string()
412 << " failed: " << e.what();
413 }
414 }
415 }
416 else if (showErrors)
417 {
418 ARMARX_WARNING_S << "VariantInfo File not found for project " << cmakePackageName
419 << ": " << variantInfoFile.string();
420 }
421
422 if (finder.packageFound())
423 {
424 auto depPaths = finder.getDependencyPaths();
425
426 for (auto& depPath : depPaths)
427 {
428 if (variantInfo->getPackagePaths().find(depPath.second) !=
429 variantInfo->getPackagePaths().end())
430 {
431 continue;
432 }
433
434 if (!depPath.first.empty() && !depPath.second.empty())
435 {
436 std::string packagePath;
437
438 if (!depPath.second.empty() && std::filesystem::exists(depPath.second))
439 {
440 packagePath = depPath.second;
441 }
442
443 variantInfo =
444 ReadInfoFilesRecursive(depPath.first, packagePath, showErrors, variantInfo);
445 }
446 }
447 }
448
449 return variantInfo;
450 }
451
453 VariantInfo::ReadInfoFiles(const std::vector<std::string>& packages,
454 bool showErrors,
455 bool throwOnError)
456 {
457 VariantInfoPtr variantInfo(new VariantInfo());
458
459 for (std::string package : packages)
460 {
461 auto finder = CMakePackageFinderCache::GlobalCache.findPackage(package);
462 if (throwOnError)
463 {
464 ARMARX_CHECK_EXPRESSION(finder.packageFound()) << package;
465 }
466 std::filesystem::path variantInfoFile(finder.getDataDir().c_str());
467 variantInfoFile /= package;
468 variantInfoFile /= "VariantInfo-" + package + ".xml";
469
470 if (std::filesystem::exists(variantInfoFile))
471 {
472 try
473 {
474 RapidXmlReaderPtr xmlReader =
475 RapidXmlReader::FromFile(variantInfoFile.string());
476 std::vector<LibEntryPtr> libs =
477 variantInfo->readVariantInfo(xmlReader, finder.getConfigDir(), package);
478 ARMARX_INFO_S << "Read " << variantInfoFile.string();
479 std::stringstream ss;
480 for (LibEntryPtr e : libs)
481 {
482 ss << "Lib " << e->getName() << "\n";
483
484 for (const VariantEntryPtr& v : e->variants)
485 {
486 ss << " Variant " << v->getHumanName() << ": " << v->dataTypeName
487 << "\n";
488 }
489
490 for (const ProxyEntryPtr& p : e->getProxies())
491 {
492 ss << " Proxy " << p->getHumanName() << ": " << p->getIncludePath()
493 << "\n";
494 }
495 }
496 ARMARX_DEBUG_S << "VariantInfo for " << package << ":\n" << ss.str();
497 }
498 catch (std::exception& e)
499 {
500 ARMARX_ERROR_S << "Reading " << variantInfoFile.string()
501 << " failed: " << e.what();
502 }
503 }
504 else if (showErrors)
505 {
506 ARMARX_WARNING_S << "VariantInfo File not found for project " << package << ": "
507 << variantInfoFile.string();
508 }
509 }
510
511 return variantInfo;
512 }
513
515 VariantInfo::loadLibraryOfVariant(std::string variantTypeName) const
516 {
517 DynamicLibraryPtr result(new DynamicLibrary());
518 auto lib = findLibByVariant(variantTypeName);
519 if (!lib)
520 {
521 ARMARX_WARNING << "Could not find lib for variant " << variantTypeName;
522 return DynamicLibraryPtr();
523 }
524 ARMARX_INFO_S << "Loading lib " << lib->getAbsoluteLibPath();
525 result->load(lib->getAbsoluteLibPath());
526 if (result->isLibraryLoaded())
527 {
528 return result;
529 }
530 else
531 {
532 return DynamicLibraryPtr();
533 }
534 }
535
536 VariantInfo::LibEntry::LibEntry(RapidXmlReaderNode node, const std::string& packageName) :
537 packageName(packageName)
538 {
539 this->name = node.attribute_value("name");
540
541 for (RapidXmlReaderNode includeNode = node.first_node("VariantFactory");
542 includeNode.is_valid();
543 includeNode = includeNode.next_sibling("VariantFactory"))
544 {
545 factoryIncludes.push_back(includeNode.attribute_value("include"));
546 }
547
548 for (RapidXmlReaderNode variantNode = node.first_node("Variant"); variantNode.is_valid();
549 variantNode = variantNode.next_sibling("Variant"))
550 {
551 VariantEntryPtr entry(new VariantEntry(variantNode));
552 variants.push_back(entry);
553 }
554
555 for (RapidXmlReaderNode proxyNode : node.nodes())
556 {
557 if (proxyNode.name() == "Proxy" || proxyNode.name() == "Topic")
558 {
559 ProxyEntryPtr proxy(new ProxyEntry(proxyNode));
560 proxies.push_back(proxy);
561 }
562 }
563 }
564
565 std::vector<std::string>
567 {
568 return factoryIncludes;
569 }
570
571 std::vector<std::string>
572 VariantInfo::LibEntry::getVariantIncludes(const std::string& variantBaseTypeName) const
573 {
574 auto it = std::find_if(variants.begin(),
575 variants.end(),
576 [&](const VariantEntryPtr& entry)
577 { return entry->getBaseTypeName() == variantBaseTypeName; });
578 if (it != variants.end() && (*it)->getIncludePath())
579 {
580 return {*(*it)->getIncludePath()};
581 }
582 else
583 {
584 return factoryIncludes;
585 }
586 }
587
588 std::string
590 {
591 return packageName;
592 }
593
594 std::string
596 {
597 CMakePackageFinder finder = CMakePackageFinderCache::GlobalCache.findPackage(packageName);
598 if (!finder.packageFound())
599 {
600 throw LocalException() << "Could not find package '" << packageName << "'!";
601 }
602 if (finder.getLibraryPaths().empty())
603 {
604 throw LocalException() << "Library path for package '" << packageName << "' is empty!";
605 }
606 std::filesystem::path path = finder.getLibraryPaths();
607 path /= "lib" + getName() + "." + DynamicLibrary::GetSharedLibraryFileExtension();
608 if (!std::filesystem::exists(path))
609 {
610 throw LocalException() << "Library path '" << path.string() << "' does not exist!";
611 }
612 return path.string();
613 }
614
615 std::string
617 {
618 return name;
619 }
620
621 std::vector<VariantInfo::ProxyEntryPtr>
623 {
624 return proxies;
625 }
626
627 const std::vector<VariantInfo::VariantEntryPtr>&
629 {
630 return variants;
631 }
632
634 {
635 baseTypeName = node.attribute_value("baseType");
636 dataTypeName = node.attribute_value("dataType");
637 humanName = node.attribute_value("humanName");
638 if (node.has_attribute("include"))
639 {
640 includePath = node.attribute_value("include");
641 }
642 basic = node.attribute_as_optional_bool("basic", "true", "false", false);
643 }
644
645 const std::string&
647 {
648 return humanName;
649 }
650
651 const std::string&
653 {
654 return baseTypeName;
655 }
656
657 const std::string&
659 {
660 return dataTypeName;
661 }
662
663 const std::optional<std::string>&
665 {
666 return includePath;
667 }
668
669 void
670 VariantInfo::ProxyEntry::readVector(RapidXmlReaderNode node,
671 const char* name,
672 std::vector<std::string>& vec)
673 {
674 for (RapidXmlReaderNode n : node.nodes(name))
675 {
676 vec.push_back(n.value());
677 }
678 }
679
681 {
682 includePath = node.attribute_value("include");
683 humanName = node.attribute_value("humanName");
684 typeName = node.attribute_value("typeName");
685 memberName = node.attribute_value("memberName");
686 getterName = node.attribute_value("getterName");
687 propertyName = node.attribute_value("propertyName");
688 propertyIsOptional =
689 node.attribute_as_optional_bool("propertyIsOptional", "true", "false", false);
690 propertyDefaultValue = node.attribute_value_or_default("propertyDefaultValue", "");
691 proxyType = node.name() == "Topic" ? Topic : SingleProxy;
692
693 readVector(node, "include", includes);
694 readVector(node, "library", libraries);
695 readVector(node, "member", members);
696 readVector(node, "onInit", onInit);
697 readVector(node, "onConnect", onConnect);
698
699 for (RapidXmlReaderNode n : node.nodes("method"))
700 {
701 methods.push_back(std::make_pair(n.attribute_value("header"), n.value()));
702 }
703
704 for (RapidXmlReaderNode n : node.nodes("stateMethod"))
705 {
706 stateMethods.push_back(std::make_pair(n.attribute_value("header"), n.value()));
707 }
708 }
709} // namespace armarx
for(;yybottom<=yytop;yybottom++)
Definition Grammar.cpp:705
static CMakePackageFinderCache GlobalCache
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
std::string getLibraryPaths() const
Returns the library paths seperated by semi-colons.
bool packageFound() const
Returns whether or not this package was found with cmake.
The DynamicLibrary class provides a mechanism to load libraries at runtime.
static std::string GetSharedLibraryFileExtension()
RapidXmlReaderNode first_node(const char *name=nullptr) const
std::string name() const
std::vector< RapidXmlReaderNode > nodes(const char *name=nullptr) const
bool has_attribute(const char *attrName) const
std::string attribute_value(const char *attrName) const
bool attribute_as_optional_bool(const char *name, const std::string &trueValue, const std::string &falseValue, bool defaultValue) const
std::string attribute_value_or_default(const char *attrName, const std::string &defaultValue) const
static RapidXmlReaderPtr FromFile(const std::string &path)
static std::string getTypePrefix()
static ContainerTypePtr FromString(const std::string &typeStr)
std::vector< std::string > getVariantIncludes(const std::string &variantBaseTypeName) const
Returns a list of includes for a specific variant (usually only one).
std::vector< ProxyEntryPtr > getProxies() const
LibEntry(RapidXmlReaderNode node, const std::string &packageName)
std::string getAbsoluteLibPath() const
std::string getPackageName() const
std::string getName() const
std::vector< std::string > getFactoryIncludes() const
const std::vector< VariantEntryPtr > & getVariants() const
ProxyEntry(RapidXmlReaderNode node)
const std::string & getBaseTypeName() const
const std::string & getDataTypeName() const
const std::string & getHumanName() const
const std::optional< std::string > & getIncludePath() const
VariantEntry(RapidXmlReaderNode node)
std::vector< LibEntryPtr > readVariantInfo(RapidXmlReaderPtr reader, const std::string &packagePath, const std::string &packageName)
static VariantInfoPtr ReadInfoFilesRecursive(const std::string &rootPackageName, const std::string &rootPackagePath, bool showErrors, VariantInfoPtr variantInfo=VariantInfoPtr())
const std::map< std::string, std::string > & getPackagePaths() const
armarx::DynamicLibraryPtr loadLibraryOfVariant(std::string variantTypeName) const
bool isPackageLoaded(const std::string packageName) const
VariantEntryPtr getVariantByName(std::string variantBaseTypeName)
LibEntryPtr findLibByVariant(std::string variantTypeName) const
ProxyEntryPtr getProxyEntry(std::string proxyId)
VariantEntryPtr getVariantByHumanName(std::string humanName)
static VariantInfoPtr ReadInfoFiles(const std::vector< std::string > &packages, bool showErrors=true, bool throwOnError=true)
Ice::StringSeq findLibNames(const Ice::StringSeq &variantTypeNames, const Ice::StringSeq &proxyTypeNames={}) const
std::vector< LibEntryPtr > getLibs() const
std::string getReturnTypeName(std::string variantBaseTypeName)
std::shared_ptr< LibEntry > LibEntryPtr
std::shared_ptr< VariantEntry > VariantEntryPtr
Definition VariantInfo.h:48
std::string getDataTypeName(std::string variantBaseTypeName)
std::string getDebugInfo() const
LibEntryPtr findLibByProxy(std::string proxyTypeName) const
std::string getNestedHumanNameFromBaseName(std::string variantBaseTypeName)
bool isBasic(std::string variantBaseTypeName)
std::set< LibEntryPtr > findLibs(const Ice::StringSeq &variantTypeNames, const Ice::StringSeq &proxyTypeNames={}) const
std::string getNestedBaseNameFromHumanName(std::string humanName)
std::shared_ptr< ProxyEntry > ProxyEntryPtr
Definition VariantInfo.h:76
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_DEBUG_S
The logging level for output that is only interesting while debugging.
Definition Logging.h:205
#define ARMARX_ERROR_S
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:216
#define ARMARX_INFO_S
Definition Logging.h:202
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:213
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::shared_ptr< RapidXmlReader > RapidXmlReaderPtr
std::shared_ptr< VariantInfo > VariantInfoPtr
Definition VariantInfo.h:39
std::shared_ptr< DynamicLibrary > DynamicLibraryPtr