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>
72#include "ArmarXCore/interface/core/Log.h"
73#include "ArmarXCore/interface/core/Profiler.h"
101std::mutex Application::instanceMutex;
103Ice::StringSeq Application::ProjectDependendencies;
104std::string Application::ProjectName;
106std::string
errormsg =
"Segmentation fault - Backtrace: \n";
121 std::array<void*, 20> array;
123 size = backtrace(array.data(), 20);
125#pragma GCC diagnostic push
126#pragma GCC diagnostic ignored "-Wunused-result"
128#pragma GCC diagnostic pop
129 backtrace_symbols_fd(array.data(), size, STDERR_FILENO);
135 std::stringstream
str;
139 str <<
"Error: Abort\nBacktrace:\n";
143 str <<
"Error: signal " << sig;
182 s <<
"qtcreator -debug " << getpid();
184 res = system(s.str().c_str());
201Application::loadLibrariesFromProperties()
204 if (!loadLibString.empty())
206 if (!libLoadingEnabled)
208 throw LocalException(
"Loading of dynamic libraries is not enabled in this application. "
209 "The Application needs to call enableLibLoading()");
211 auto entries =
armarx::Split(loadLibString,
";",
true,
true);
212 for (
auto& entry : entries)
216 std::filesystem::path path;
223 auto elements =
Split(entry,
":");
226 CMakePackageFinder p(elements.at(0));
230 std::string libFileName =
"lib" + elements.at(1) +
"." +
234 std::filesystem::path testPath(libDir);
235 testPath /= libFileName;
236 if (std::filesystem::exists(testPath))
246 std::string libFileName =
"lib" + elements.at(0) +
"_" + elements.at(1) +
251 std::filesystem::path testPath(libDir);
252 testPath /= libFileName;
253 if (std::filesystem::exists(testPath))
264 <<
"' in any of the following paths: " << p.getLibraryPaths();
285 return forbidThreadCreation;
291 forbidThreadCreation = value;
292 if (forbidThreadCreation)
294 ARMARX_INFO <<
"Thread creation with RunningTask and PeriodicTask is now forbidden in this "
299 ARMARX_INFO <<
"Thread creation with RunningTask and PeriodicTask is now allowed again in "
307 this->libLoadingEnabled = enable;
314 <<
"Command line arguments were already set: " <<
VAROUT(commandLineArguments);
315 commandLineArguments.reserve(argc);
316 for (
int i = 0; i < argc; ++i)
318 commandLineArguments.emplace_back(argv[i]);
322const std::vector<std::string>&
325 return commandLineArguments;
345 std::unique_lock lock(instanceMutex);
353 std::unique_lock lock(instanceMutex);
366 armarXManager->setComponentIceProperties(properties);
378 armarXManager->updateComponentIceProperties(properties);
387 if (changedProperties.count(
"DisableLogging") &&
394 if (changedProperties.count(
"EnableProfiling"))
398 if (changedProperties.count(
"Verbosity"))
400 armarXManager->setGlobalMinimumLoggingLevel(
449 std::cout <<
"Version: " <<
GetVersion() << std::endl;
461 const Ice::PropertyDict& env_props =
464 for (
const auto& [name, value] : env_props)
466 const std::string short_name = name.substr(4);
470 ARMARX_INFO <<
"Setting environment variable '" << short_name <<
"' to value '" << envVarResolved
472 setenv(short_name.c_str(), envVarResolved.c_str(), 1);
479 ARMARX_INFO <<
"startup delay: " << delay <<
" seconds";
480 std::this_thread::sleep_for(std::chrono::seconds{delay});
494#if ARMARX_PLOG_SUPPORT
495 armarx::RegisterPlogArmarXAppender();
502 std::streambuf* cout_sbuf =
nullptr;
503 std::streambuf* cerr_sbuf =
nullptr;
506 cout_sbuf = std::cout.rdbuf();
507 cerr_sbuf = std::cerr.rdbuf();
508 std::cout.rdbuf(&buf);
509 std::cerr.rdbuf(&errbuf);
516 std::cout.rdbuf(cout_sbuf);
517 std::cerr.rdbuf(cerr_sbuf);
521 int result = EXIT_SUCCESS;
527 armarXManager =
new ArmarXManager(applicationName, communicator());
529 catch (Ice::ConnectFailedException&)
543 callbackOnInterrupt();
547 if (applicationNetworkStats)
549 ProfilerListenerPrx profilerTopic =
550 armarXManager->getIceManager()->getTopic<ProfilerListenerPrx>(
551 armarx::Profiler::PROFILER_TOPIC_NAME);
552 applicationNetworkStats->start(profilerTopic, applicationName);
555 loadLibrariesFromProperties();
560 setup(armarXManager, properties);
565 armarXManager->shutdown();
569 result =
exec(armarXManager);
575 shutdownThread->join();
588 armarXManager->waitForShutdown();
603 std::string configFiles = communicator()->getProperties()->getProperty(
"ArmarX.Config");
609 if (!configFiles.empty() && configFiles.compare(
"1") != 0)
611 std::vector<std::string> configFileList = simox::alg::split(configFiles,
",");
613 for (std::string configFile : configFileList)
615 if (!configFile.empty())
617 properties->load(configFile);
640 std::ofstream out(options.
outfile);
650 std::cout <<
"Could not write to file " << options.
outfile << std::endl;
664 this->applicationName = name;
670 return applicationName;
677 if (applicationNetworkStats)
679 applicationNetworkStats->stopTask();
682 shutdownThread.reset(
new std::thread{[
this]
685 this->armarXManager->shutdown();
692 IceUtil::Time start = IceUtil::Time::now();
694 dependencies = simox::alg::replace_all(dependencies,
"\"",
"");
695 Ice::StringSeq resultList = simox::alg::split(dependencies,
"/");
697 for (
size_t i = 0; i < resultList.size(); i++)
707 ARMARX_INFO_S <<
"loading took " << (IceUtil::Time::now() - start).toMilliSeconds();
713 const std::string autodiscoverPropertyName =
"AutodiscoverPackages";
717 ARMARX_VERBOSE <<
"`" << autodiscoverPropertyName <<
"` property available.";
724std::vector<std::string>
738 result.insert(result.end(), additional.begin(), additional.end());
746 char* env_armarx_workspace = getenv(
"ARMARX_WORKSPACE");
747 char* env_armarx_default_config_dir_name = getenv(
"ARMARX_CONFIG_DIR_NAME");
749 std::filesystem::path armarx_workspace;
750 std::filesystem::path armarx_config_dir;
752 if (env_armarx_workspace)
754 armarx_workspace = std::filesystem::path(env_armarx_workspace);
758 char* home = getenv(
"HOME");
762 armarx_workspace = std::filesystem::path(home);
766 armarx_workspace =
"~/";
770 if (env_armarx_default_config_dir_name)
772 armarx_config_dir = std::filesystem::path(env_armarx_default_config_dir_name);
776 if (env_armarx_workspace)
778 armarx_config_dir =
"armarx_config";
783 armarx_config_dir =
".armarx";
789 return (armarx_workspace / armarx_config_dir).string();
793 if (env_armarx_workspace)
795 return "${ARMARX_WORKSPACE}/" + armarx_config_dir.string();
800 return "${HOME}/" + armarx_config_dir.string();
808 return armarXManager;
816 Ice::InitializationData id(initData);
821 if (
id.properties->getProperty(
"Ice.Admin.InstanceName").empty())
823 id.properties->setProperty(
"Ice.Admin.InstanceName", this->
getName());
825 if (
id.properties->getProperty(
"Ice.Admin.Endpoints").empty())
827 id.properties->setProperty(
"Ice.Admin.Endpoints",
"tcp -h 127.0.0.1");
830 if (initData.properties->getProperty(
"ArmarX.NetworkStats") ==
"1")
833 id.observer = applicationNetworkStats;
835 const auto oldFacets = initData.properties->getPropertyAsList(
"Ice.Admin.Facets");
836 if (oldFacets.empty())
838 initData.properties->setProperty(
"Ice.Admin.Facets",
"Metrics");
840 else if (std::find(oldFacets.begin(), oldFacets.end(),
"Metrics") == oldFacets.end())
842 std::stringstream
str;
844 for (
const auto& facet : oldFacets)
848 initData.properties->setProperty(
"Ice.Admin.Facets",
str.str());
850 initData.properties->setProperty(
"IceMX.Metrics.NetworkStats.GroupBy",
"none");
853 return Ice::Application::doMain(argc, argv,
id, i);
859 const std::string configFileName =
"default.cfg";
860 const std::string generatedConfigFileName =
"default.generated.cfg";
861 Ice::StringSeq defaultsPaths;
863 std::filesystem::path absBasePath;
866 absBasePath = defaultsPathVar;
872 defaultsPaths.push_back((absBasePath / configFileName).
string());
873 defaultsPaths.push_back((absBasePath / generatedConfigFileName).
string());
874 return defaultsPaths;
889 for (std::string path : defaultsPath)
895 Ice::PropertyDict defaultCfg = p->getPropertiesForPrefix(
"");
898 for (
auto e : defaultCfg)
900 if (properties->getProperty(e.first).empty())
902 properties->setProperty(e.first, e.second);
906 catch (Ice::FileException& e)
922 return ProjectDependendencies;
934 std::string dependenciesConfig =
getIceProperties()->getProperty(
"ArmarX.DependenciesConfig");
936 if (!dependenciesConfig.empty())
938 if (std::filesystem::exists(dependenciesConfig))
941 prop->load(dependenciesConfig);
943 ProjectName = prop->getProperty(
"ArmarX.ProjectName");
944 std::string dependencies = prop->getProperty(
"ArmarX.ProjectDependencies");
945 ProjectDependendencies = simox::alg::split(dependencies,
";");
961 "Config",
"",
"Comma-separated list of configuration files ");
963 "DependenciesConfig",
964 "./config/dependencies.cfg",
965 "Path to the (usually generated) config file containing all data paths of all dependent "
966 "projects. This property usually does not need to be edited.");
974 "RobotSkillTemplates",
980 "List of ArmarX packages which are accessible by default. Comma separated List. If you "
981 "want to add your own packages and use all default ArmarX packages, use the property "
982 "'AdditionalPackages'.");
984 "AdditionalPackages",
986 "List of additional ArmarX packages which should be in the list of default packages. If "
987 "you have custom packages, which should be found by the gui or other apps, specify them "
988 "here. Comma separated List.");
991 "AutodiscoverPackages",
993 "If enabled, will discover all ArmarX packages based on the environment variables. "
994 "Otherwise, the `DefaultPackages` and `AdditionalPackages` properties are used.");
1000 "Turn logging off in whole application",
1005 "Global logging level for whole application",
1011 "The logging group is transmitted with every ArmarX log message over Ice in order to group "
1012 "the message in the GUI.");
1016 "DataPath",
"",
"Semicolon-separated search list for data files");
1021 std::string(
"Path for cache files. If relative path AND env. variable ") +
1023 " is set, the cache path will be made relative to " +
1025 ". Otherwise if relative it will be relative to the default ArmarX config dir (" +
1030 "Enable profiling of CPU load produced by this application",
1034 "RedirectStdout",
true,
"Redirect std::cout and std::cerr to ArmarXLog");
1039 "Suffix appended to all topic names for outgoing topics. This is mainly used to direct all "
1040 "topics to another name for TopicReplaying purposes.");
1043 "UseTimeServer",
false,
"Enable using a global Timeserver (e.g. from ArmarXSimulator)");
1046 "RemoteHandlesDeletionTimeout",
1048 "The timeout (in ms) before a remote handle deletes the managed object after the use count "
1049 "reached 0. This time can be used by a client to increment the count again (may be "
1050 "required when transmitting remote handles)");
1053 "If this application crashes (segmentation fault) qtcreator will "
1054 "attach to this process and start the debugger.");
1056 "ThreadPoolSize", 1,
"Size of the ArmarX ThreadPool that is always running.");
1060 "Libraries to load at start up of the application. Must be enabled by the Application with "
1061 "enableLibLoading(). Format: PackageName:LibraryName;... or /absolute/path/to/library;...");
1063 "SecondsStartupDelay",
1065 "The startup will be delayed by this number of seconds (useful for debugging)");
The ApplicationNetworkStats class implements the Ice::Instrumentation::CommunicatorObserver interface...
Application property definition container.
ApplicationPropertyDefinitions(std::string prefix)
static void HandlerInterrupt(int sig)
handlerInterrupt handles interrupt signals sent to the application (Linux)
void loadDefaultConfig(int argc, char *argv[], const Ice::InitializationData &initData)
int run(int argc, char *argv[]) override
Ice::Application replacement for the main function.
void icePropertiesUpdated(const std::set< std::string > &changedProperties) override
This method is called when new Properties are set via setIceProperties().
std::vector< std::string > getArmarXPackageNames()
getDefaultPackageNames returns the value of the ArmarX.DefaultPackages property It splits the string ...
int doMain(int argc, char *argv[], const Ice::InitializationData &initData, Ice::Int i) override
Ice::Application::doMain() is called by Ice::Application::main() and does setup of Ice::Communicator ...
void updateIceProperties(const Ice::PropertyDict &properties) override
const std::vector< std::string > & getCommandLineArguments() const
virtual std::string getDomainName()
Retrieve the domain name used for property parsing.
static void LoadDefaultConfig(Ice::PropertiesPtr properties)
static void HandlerFault(int sig)
handlerFault handles signals sendt to the application such as SIGSEGF or SIGABRT (Linux)
std::string getName() const
Retrieve name of the application.
void showHelp(ApplicationOptions::Options &options)
Print help onto the screen or into a file.
ArmarXManagerPtr getArmarXManager()
const ThreadPoolPtr & getThreadPool() const
void setName(const std::string &name)
Set name of the application.
static void setInstance(ApplicationPtr const &inst)
void loadDependentProjectDatapaths()
PropertyDefinitionsPtr createPropertyDefinitions() override
void registerDataPathsFromDependencies(std::string dependencies)
static ApplicationPtr getInstance()
Retrieve shared pointer to the application object.
bool getForbidThreadCreation() const
void enableLibLoading(bool enable=true)
static const std::string & GetProjectName()
static const std::string ArmarXUserConfigDirEnvVar
void interruptCallback(int signal) override
Cleans up connections with IceStorm before terminating the app.
virtual void setup(const ManagedIceObjectRegistryInterfacePtr ®istry, Ice::PropertiesPtr properties)=0
Setup method to be implemented by user applications.
static Ice::StringSeq GetDefaultsPaths()
void storeCommandLineArguments(int argc, char *argv[])
void setForbidThreadCreation(bool value)
Ice::PropertiesPtr parseOptionsMergeProperties(int argc, char *argv[])
Parse options given on the commandline and merge them into the regular properties.
static std::string GetArmarXConfigDefaultPath(bool envVarExpanded=true)
static const Ice::StringSeq & GetProjectDependencies()
bool isPackageAutoDiscoveryEnabled()
Application()
Application initalizes the Ice::Application base class.
void setIceProperties(Ice::PropertiesPtr properties) override
Overrides PropertyUser::setIceProperties() which is called internally.
virtual int exec(const ArmarXManagerPtr &armarXManager)
Exec method is the main process of the application.
static std::string GetVersion()
static void addDataPaths(const std::string &dataPathList)
Handles help and documentation generation but does not provide Ice functionality.
Main class of an ArmarX process.
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
bool packageFound() const
Returns whether or not this package was found with cmake.
static std::vector< std::string > FindAllArmarXSourcePackages()
std::string getIncludePaths() const
Returns the include paths separated by semi-colons.
void setUnloadOnDestruct(bool unload)
void load(std::filesystem::path libPath)
Loads a shared library from the specified path.
static std::string GetSharedLibraryFileExtension()
static Ice::PropertiesPtr create(const Ice::PropertiesPtr &iceProperties=nullptr)
static std::string CreateBackTrace(int linesToSkip=1)
static void SetLoggingGroup(const std::string &loggingGroup)
static void SetSendLoggingActivated(bool activated=true)
static void SetLoggingActivated(bool activated=true, bool showMessage=true)
setLoggingActivated() is used to activate or disable the logging facilities in the whole application
PropertyDefinitionContainer(const std::string &prefix)
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
PropertyDefinition< PropertyType > & defineOptionalProperty(const std::string &name, PropertyType defaultValue, const std::string &description="", PropertyDefinitionBase::PropertyConstness constness=PropertyDefinitionBase::eConstant)
bool removeQuotes() const
Ice::PropertiesPtr getIceProperties() const
Returns the set of Ice properties.
PropertyDefinitionsPtr getPropertyDefinitions()
Returns the component's property definition container.
bool hasProperty(const std::string &name)
virtual void updateIceProperties(const std::map< std::string, std::string > &changes)
virtual void setIceProperties(Ice::PropertiesPtr properties)
Sets the Ice properties.
Property< PropertyType > getProperty(const std::string &name)
Property creation and retrieval.
static std::string expandVariables(const std::string &value)
#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_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
#define ARMARX_INFO
The normal logging level.
#define ARMARX_FATAL_S
The logging level for unexpected behaviour, that will lead to a seriously malfunctioning program and ...
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_VERBOSE
The logging level for verbose information.
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_ON_SCOPE_EXIT
Executes given code when the enclosing scope is left.
::IceInternal::Handle<::Ice::Properties > PropertiesPtr
Options parseHelpOptions(Ice::PropertiesPtr properties, int argc, char *argv[])
Parse the help options.
Ice::PropertiesPtr mergeProperties(Ice::PropertiesPtr properties, int argc, char *argv[])
Merge command line options into properties.
void showHelp(ApplicationPtr application, ArmarXDummyManagerPtr dummyManager, Options options, Ice::PropertiesPtr properties, std::ostream &out=std::cout)
Prints help according to the format selection in options.
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< ArmarXManager > ArmarXManagerPtr
std::vector< std::string > Split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
IceUtil::Handle< Application > ApplicationPtr
std::shared_ptr< ThreadPool > ThreadPoolPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
bool Contains(const ContainerType &container, const ElementType &searchElement)
IceUtil::Handle< ArmarXDummyManager > ArmarXDummyManagerPtr
Stucture containing the parsed options of the application.