44 #include <Ice/Communicator.h>
45 #include <Ice/Initialize.h>
46 #include <Ice/LocalException.h>
47 #include <Ice/NativePropertiesAdmin.h>
48 #include <Ice/ObjectF.h>
49 #include <Ice/Process.h>
50 #include <Ice/Properties.h>
51 #include <Ice/Properties.h>
52 #include <Ice/PropertiesAdmin.h>
53 #include <Ice/PropertiesAdmin.h>
54 #include <IceUtil/Time.h>
56 #include <SimoxUtility/algorithm/string/string_tools.h>
71 #include "ArmarXCore/interface/core/Log.h"
72 #include "ArmarXCore/interface/core/Profiler.h"
77 #include "../logging/ArmarXLogBuf.h"
99 std::mutex Application::instanceMutex;
101 Ice::StringSeq Application::ProjectDependendencies;
102 std::string Application::ProjectName;
104 std::string
errormsg =
"Segmentation fault - Backtrace: \n";
120 std::array<void*, 20> array;
122 size = backtrace(array.data(), 20);
124 #pragma GCC diagnostic push
125 #pragma GCC diagnostic ignored "-Wunused-result"
127 #pragma GCC diagnostic pop
128 backtrace_symbols_fd(array.data(), size, STDERR_FILENO);
133 std::stringstream
str;
135 if (sig == SIGABRT) {
136 str <<
"Error: Abort\nBacktrace:\n";
138 str <<
"Error: signal " << sig;
150 s <<
"qtcreator -debug " << getpid();
152 res = system(
s.str().c_str());
168 Application::loadLibrariesFromProperties()
170 auto loadLibString = getProperty<std::string>(
"LoadLibraries").getValue();
171 if (!loadLibString.empty())
173 if (!libLoadingEnabled)
175 throw LocalException(
"Loading of dynamic libraries is not enabled in this application. "
176 "The Application needs to call enableLibLoading()");
178 auto entries =
armarx::Split(loadLibString,
";",
true,
true);
179 for (
auto& entry : entries)
183 std::filesystem::path path;
190 auto elements =
Split(entry,
":");
192 std::string libFileName =
"lib" + elements.at(1) +
"." +
197 std::filesystem::path testPath(libDir);
198 testPath /= libFileName;
199 if (std::filesystem::exists(testPath))
208 <<
"' in any of the following paths: " << p.getLibraryPaths();
229 return forbidThreadCreation;
235 forbidThreadCreation =
value;
236 if (forbidThreadCreation)
238 ARMARX_INFO <<
"Thread creation with RunningTask and PeriodicTask is now forbidden in this "
243 ARMARX_INFO <<
"Thread creation with RunningTask and PeriodicTask is now allowed again in "
251 this->libLoadingEnabled = enable;
258 <<
"Command line arguments were already set: " <<
VAROUT(commandLineArguments);
259 commandLineArguments.reserve(argc);
260 for (
int i = 0; i < argc; ++i)
262 commandLineArguments.emplace_back(argv[i]);
266 const std::vector<std::string>&
269 return commandLineArguments;
291 std::unique_lock lock(instanceMutex);
299 std::unique_lock lock(instanceMutex);
313 armarXManager->setComponentIceProperties(properties);
326 armarXManager->updateComponentIceProperties(properties);
336 if (changedProperties.count(
"DisableLogging") &&
337 getProperty<bool>(
"DisableLogging").isSet())
340 armarXManager->enableLogging(!getProperty<bool>(
"DisableLogging").getValue());
343 if (changedProperties.count(
"EnableProfiling"))
345 armarXManager->enableProfiling(getProperty<bool>(
"EnableProfiling").getValue());
347 if (changedProperties.count(
"Verbosity"))
349 armarXManager->setGlobalMinimumLoggingLevel(
350 getProperty<MessageTypeT>(
"Verbosity").getValue());
399 std::cout <<
"Version: " <<
GetVersion() << std::endl;
411 const Ice::PropertyDict& env_props =
414 for (
const auto& [name,
value] : env_props)
416 const std::string short_name = name.substr(4);
417 ARMARX_INFO <<
"Setting environment variable '" << short_name <<
"' to value '" <<
value
419 setenv(short_name.c_str(),
value.c_str(), 1);
423 if (getProperty<std::uint64_t>(
"SecondsStartupDelay").isSet())
425 const auto delay = getProperty<std::uint64_t>(
"SecondsStartupDelay").getValue();
426 ARMARX_INFO <<
"startup delay: " << delay <<
" seconds";
427 std::this_thread::sleep_for(std::chrono::seconds{delay});
435 if (getProperty<std::string>(
"ApplicationName").isSet())
437 applicationName = getProperty<std::string>(
"ApplicationName").getValue();
442 const bool redirectStdout = getProperty<bool>(
"RedirectStdout").getValue();
445 std::streambuf* cout_sbuf =
nullptr;
446 std::streambuf* cerr_sbuf =
nullptr;
449 cout_sbuf = std::cout.rdbuf();
450 cerr_sbuf = std::cerr.rdbuf();
451 std::cout.rdbuf(&buf);
452 std::cerr.rdbuf(&errbuf);
459 std::cout.rdbuf(cout_sbuf);
460 std::cerr.rdbuf(cerr_sbuf);
464 int result = EXIT_SUCCESS;
466 threadPool.reset(
new ThreadPool(getProperty<unsigned int>(
"ThreadPoolSize").getValue()));
470 armarXManager =
new ArmarXManager(applicationName, communicator());
472 catch (Ice::ConnectFailedException&)
477 armarXManager->setDataPaths(getProperty<std::string>(
"DataPath").getValue());
486 callbackOnInterrupt();
490 if (applicationNetworkStats)
492 ProfilerListenerPrx profilerTopic =
493 armarXManager->getIceManager()->getTopic<ProfilerListenerPrx>(
494 armarx::Profiler::PROFILER_TOPIC_NAME);
495 applicationNetworkStats->start(profilerTopic, applicationName);
498 loadLibrariesFromProperties();
503 setup(armarXManager, properties);
508 armarXManager->shutdown();
512 result =
exec(armarXManager);
518 shutdownThread->join();
531 armarXManager->waitForShutdown();
547 std::string configFiles = communicator()->getProperties()->getProperty(
"ArmarX.Config");
553 if (!configFiles.empty() && configFiles.compare(
"1") != 0)
557 for (std::string configFile : configFileList)
559 if (!configFile.empty())
561 properties->load(configFile);
585 std::ofstream out(options.
outfile);
595 std::cout <<
"Could not write to file " << options.
outfile << std::endl;
610 this->applicationName = name;
616 return applicationName;
623 if (applicationNetworkStats)
625 applicationNetworkStats->stopTask();
628 shutdownThread.reset(
new std::thread{[
this]
631 this->armarXManager->shutdown();
640 dependencies = simox::alg::replace_all(dependencies,
"\"",
"");
643 for (
size_t i = 0; i < resultList.size(); i++)
653 ARMARX_INFO_S <<
"loading took " << (IceUtil::Time::now() - start).toMilliSeconds();
658 const std::string autodiscoverPropertyName =
"AutodiscoverPackages";
662 ARMARX_VERBOSE <<
"`" << autodiscoverPropertyName <<
"` property available.";
663 return getProperty<bool>(autodiscoverPropertyName).getValue();
669 std::vector<std::string>
681 Ice::StringSeq result = getProperty<Ice::StringSeq>(
"DefaultPackages").getValue();
682 Ice::StringSeq additional = getProperty<Ice::StringSeq>(
"AdditionalPackages").getValue();
683 result.insert(result.end(), additional.begin(), additional.end());
691 char* env_armarx_workspace = getenv(
"ARMARX_WORKSPACE");
692 char* env_armarx_default_config_dir_name = getenv(
"ARMARX_CONFIG_DIR_NAME");
694 std::filesystem::path armarx_workspace;
695 std::filesystem::path armarx_config_dir;
697 if (env_armarx_workspace)
699 armarx_workspace = std::filesystem::path(env_armarx_workspace);
703 char* home = getenv(
"HOME");
707 armarx_workspace = std::filesystem::path(home);
711 armarx_workspace =
"~/";
715 if (env_armarx_default_config_dir_name)
717 armarx_config_dir = std::filesystem::path(env_armarx_default_config_dir_name);
721 if (env_armarx_workspace)
723 armarx_config_dir =
"armarx_config";
728 armarx_config_dir =
".armarx";
734 return (armarx_workspace / armarx_config_dir).string();
738 if (env_armarx_workspace)
740 return "${ARMARX_WORKSPACE}/" + armarx_config_dir.string();
745 return "${HOME}/" + armarx_config_dir.string();
753 return armarXManager;
762 Ice::InitializationData id(initData);
767 if (
id.properties->getProperty(
"Ice.Admin.InstanceName").empty())
769 id.properties->setProperty(
"Ice.Admin.InstanceName", this->
getName());
771 if (
id.properties->getProperty(
"Ice.Admin.Endpoints").empty())
773 id.properties->setProperty(
"Ice.Admin.Endpoints",
"tcp -h 127.0.0.1");
776 if (initData.properties->getProperty(
"ArmarX.NetworkStats") ==
"1")
779 id.observer = applicationNetworkStats;
781 const auto oldFacets = initData.properties->getPropertyAsList(
"Ice.Admin.Facets");
782 if (oldFacets.empty())
784 initData.properties->setProperty(
"Ice.Admin.Facets",
"Metrics");
786 else if (std::find(oldFacets.begin(), oldFacets.end(),
"Metrics") == oldFacets.end())
788 std::stringstream
str;
790 for (
const auto& facet : oldFacets)
794 initData.properties->setProperty(
"Ice.Admin.Facets",
str.str());
796 initData.properties->setProperty(
"IceMX.Metrics.NetworkStats.GroupBy",
"none");
799 return Ice::Application::doMain(argc, argv,
id, i);
806 const std::string configFileName =
"default.cfg";
807 const std::string generatedConfigFileName =
"default.generated.cfg";
808 Ice::StringSeq defaultsPaths;
810 std::filesystem::path absBasePath;
813 absBasePath = defaultsPathVar;
819 defaultsPaths.push_back((absBasePath / configFileName).
string());
820 defaultsPaths.push_back((absBasePath / generatedConfigFileName).
string());
821 return defaultsPaths;
837 for (std::string path : defaultsPath)
843 Ice::PropertyDict defaultCfg = p->getPropertiesForPrefix(
"");
846 for (
auto e : defaultCfg)
848 if (properties->getProperty(e.first).empty())
850 properties->setProperty(e.first, e.second);
854 catch (Ice::FileException& e)
869 const Ice::StringSeq&
872 return ProjectDependendencies;
886 std::string dependenciesConfig =
getIceProperties()->getProperty(
"ArmarX.DependenciesConfig");
888 if (!dependenciesConfig.empty())
890 if (std::filesystem::exists(dependenciesConfig))
893 prop->load(dependenciesConfig);
895 ProjectName = prop->getProperty(
"ArmarX.ProjectName");
896 std::string dependencies = prop->getProperty(
"ArmarX.ProjectDependencies");
913 defineOptionalProperty<std::string>(
914 "Config",
"",
"Comma-separated list of configuration files ");
915 defineOptionalProperty<std::string>(
916 "DependenciesConfig",
917 "./config/dependencies.cfg",
918 "Path to the (usually generated) config file containing all data paths of all dependent "
919 "projects. This property usually does not need to be edited.");
920 defineOptionalProperty<Ice::StringSeq>(
927 "RobotSkillTemplates",
933 "List of ArmarX packages which are accessible by default. Comma separated List. If you "
934 "want to add your own packages and use all default ArmarX packages, use the property "
935 "'AdditionalPackages'.");
936 defineOptionalProperty<Ice::StringSeq>(
937 "AdditionalPackages",
939 "List of additional ArmarX packages which should be in the list of default packages. If "
940 "you have custom packages, which should be found by the gui or other apps, specify them "
941 "here. Comma separated List.");
943 defineOptionalProperty<bool>(
"AutodiscoverPackages",
true,
"If enabled, will discover all ArmarX packages based on the environment variables. Otherwise, the `DefaultPackages` and `AdditionalPackages` properties are used.");
945 defineOptionalProperty<std::string>(
"ApplicationName",
"",
"Application name");
947 defineOptionalProperty<bool>(
"DisableLogging",
949 "Turn logging off in whole application",
952 defineOptionalProperty<MessageTypeT>(
"Verbosity",
954 "Global logging level for whole application",
957 defineOptionalProperty<std::string>(
960 "The logging group is transmitted with every ArmarX log message over Ice in order to group "
961 "the message in the GUI.");
964 defineOptionalProperty<std::string>(
965 "DataPath",
"",
"Semicolon-separated search list for data files");
967 defineOptionalProperty<std::string>(
970 std::string(
"Path for cache files. If relative path AND env. variable ") +
972 " is set, the cache path will be made relative to " +
974 ". Otherwise if relative it will be relative to the default ArmarX config dir (" +
977 defineOptionalProperty<bool>(
"EnableProfiling",
979 "Enable profiling of CPU load produced by this application",
982 defineOptionalProperty<bool>(
983 "RedirectStdout",
true,
"Redirect std::cout and std::cerr to ArmarXLog");
985 defineOptionalProperty<std::string>(
988 "Suffix appended to all topic names for outgoing topics. This is mainly used to direct all "
989 "topics to another name for TopicReplaying purposes.");
991 defineOptionalProperty<bool>(
992 "UseTimeServer",
false,
"Enable using a global Timeserver (e.g. from ArmarXSimulator)");
994 defineOptionalProperty<unsigned int>(
995 "RemoteHandlesDeletionTimeout",
997 "The timeout (in ms) before a remote handle deletes the managed object after the use count "
998 "reached 0. This time can be used by a client to increment the count again (may be "
999 "required when transmitting remote handles)");
1000 defineOptionalProperty<bool>(
"StartDebuggerOnCrash",
1002 "If this application crashes (segmentation fault) qtcreator will "
1003 "attach to this process and start the debugger.");
1004 defineOptionalProperty<unsigned int>(
1005 "ThreadPoolSize", 1,
"Size of the ArmarX ThreadPool that is always running.");
1006 defineOptionalProperty<std::string>(
1009 "Libraries to load at start up of the application. Must be enabled by the Application with "
1010 "enableLibLoading(). Format: PackageName:LibraryName;... or /absolute/path/to/library;...");
1011 defineOptionalProperty<std::uint64_t>(
1012 "SecondsStartupDelay",
1014 "The startup will be delayed by this number of seconds (useful for debugging)");