Application.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 ArmarXCore::core
19 * @author Nils Adermann (naderman at naderman dot de)
20 * @author Kai Welke (welke at kit dot edu)
21 * @author Jan Issac (jan dot issac at gmail dot com)
22 * @author Mirko Waechter (waechter at kit dot edu)
23 * @author Manfred Kroehnert (manfred dot kroehnert at kit dot edu)
24 * @date 2010
25 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
26 * GNU General Public License
27 */
28
29#include "Application.h"
30
31#include <stddef.h> // for size_t
32#include <stdlib.h> // for NULL, getenv, system, exit, etc
33
34#include <filesystem>
35#include <fstream>
36#include <iostream> // for operator<<, ostream, etc
37#include <sstream> // for basic_stringbuf<>::int_type, etc
38#include <thread>
39#include <thread> // for thread
40#include <utility> // for pair, move
41
42#include <unistd.h> // for getpid
43
44#include <Ice/Communicator.h> // for Communicator, etc
45#include <Ice/Initialize.h> // for InitializationData
46#include <Ice/LocalException.h> // for FileException, etc
47#include <Ice/NativePropertiesAdmin.h>
48#include <Ice/ObjectF.h> // for upCast
49#include <Ice/Process.h> // for ProcessPtr, Process
50#include <Ice/Properties.h> // for Properties, PropertiesPtr
51#include <Ice/Properties.h>
52#include <Ice/PropertiesAdmin.h> // for PropertyDict
53#include <Ice/PropertiesAdmin.h>
54#include <IceUtil/Time.h> // for Time
55
56#include <SimoxUtility/algorithm/string/string_tools.h>
57
58#include "ArmarXCore/core/IceManager.h" // for IceManager
69#include "ArmarXCore/core/logging/LogSender.h" // for LogSender
70#include "ArmarXCore/core/logging/Logging.h" // for ARMARX_INFO_S, etc
71#include "ArmarXCore/interface/core/Log.h" // for MessageType, etc
72#include "ArmarXCore/interface/core/Profiler.h"
77
78#include "../logging/ArmarXLogBuf.h" // for ArmarXLogBuf
79#include "ApplicationNetworkStats.h" // for ApplicationNetworkStatsPtr
80#include "ApplicationOptions.h" // for Options, showHelp, etc
81#include "ApplicationProcessFacet.h" // for ArmarXManagerPtr, etc
82#include "properties/IceProperties.h" // for IceProperties
83
84#ifndef WIN32
85#include <signal.h> // for signal, SIGABRT, SIGSEGV, etc
86
87#include <cstdio>
88
89#include <ArmarXCore/core/util/OnScopeExit.h> // for ARMARX_ON_SCOPE_EXIT
90
91#include <execinfo.h>
92#endif
93
94#include <stdlib.h>
95
96
97using namespace armarx;
98
99// static members for the one application instance (maybe not required anymore???)
100std::mutex Application::instanceMutex;
101ApplicationPtr Application::instance;
102Ice::StringSeq Application::ProjectDependendencies;
103std::string Application::ProjectName;
104const std::string Application::ArmarXUserConfigDirEnvVar = "ARMARX_CONFIG_DIR";
105std::string errormsg = "Segmentation fault - Backtrace: \n";
106bool crashed = false;
107
108void
110{
111 if (crashed)
112 {
113 return;
114 }
115 crashed = true;
116
117 // dont allocate memory in segfault
118 if (sig == SIGSEGV)
119 {
120 std::array<void*, 20> array;
121 size_t size;
122 size = backtrace(array.data(), 20);
123
124#pragma GCC diagnostic push
125#pragma GCC diagnostic ignored "-Wunused-result"
126 write(STDERR_FILENO, errormsg.data(), errormsg.size());
127#pragma GCC diagnostic pop
128 backtrace_symbols_fd(array.data(), size, STDERR_FILENO);
129 exit(EXIT_FAILURE);
130 }
131 // print out all the frames to stderr
132 try
133 {
134 std::stringstream str;
135
136 if (sig == SIGABRT)
137 {
138 str << "Error: Abort\nBacktrace:\n";
139 }
140 else
141 {
142 str << "Error: signal " << sig;
143 }
144
145 ARMARX_FATAL_S << str.str() << "\nBacktrace:\n" << LogSender::CreateBackTrace();
146 if ((sig == SIGSEGV || sig == SIGABRT) && Application::getInstance() &&
147 Application::getInstance()->getProperty<bool>("StartDebuggerOnCrash").getValue())
148 {
149 std::stringstream s;
150 int res;
151 // res = system("which qtcreator");
152 // res = WEXITSTATUS(res);
153 // if (res == EXIT_SUCCESS)
154 {
155 s << "qtcreator -debug " << getpid();
156 ARMARX_IMPORTANT << s.str();
157 res = system(s.str().c_str());
158 res++; // suppress warning
159 }
160 // else
161 // {
162 // ARMARX_INFO_S << "Could not find qtcreator";
163 // }
164 }
165 }
166 catch (...)
167 {
168 // do nothing
169 }
170 exit(EXIT_FAILURE);
171}
172
173void
174Application::loadLibrariesFromProperties()
175{
176 auto loadLibString = getProperty<std::string>("LoadLibraries").getValue();
177 if (!loadLibString.empty())
178 {
179 if (!libLoadingEnabled)
180 {
181 throw LocalException("Loading of dynamic libraries is not enabled in this application. "
182 "The Application needs to call enableLibLoading()");
183 }
184 auto entries = armarx::Split(loadLibString, ";", true, true);
185 for (auto& entry : entries)
186 {
187 try
188 {
189 std::filesystem::path path;
190 if (armarx::Contains(entry, "/"))
191 {
192 path = entry;
193 }
194 else
195 {
196 auto elements = Split(entry, ":");
197 ARMARX_CHECK_EQUAL(elements.size(), 2);
198
199 CMakePackageFinder p(elements.at(0));
200
201 // case entry ^= `package_name`::`package_name`_`lib_name`
202 {
203 std::string libFileName = "lib" + elements.at(1) + "." +
205 for (auto& libDir : armarx::Split(p.getLibraryPaths(), ";"))
206 {
207 std::filesystem::path testPath(libDir);
208 testPath /= libFileName;
209 if (std::filesystem::exists(testPath))
210 {
211 path = testPath;
212 break;
213 }
214 }
215 }
216 // case entry ^= `package_name`::`lib_name`
217 {
218 // the filename is known to be "lib`package_name`_`lib_name`.so"
219 std::string libFileName = "lib" + elements.at(0) + "_" + elements.at(1) +
220 "." +
222 for (auto& libDir : armarx::Split(p.getLibraryPaths(), ";"))
223 {
224 std::filesystem::path testPath(libDir);
225 testPath /= libFileName;
226 if (std::filesystem::exists(testPath))
227 {
228 path = testPath;
229 break;
230 }
231 }
232 }
233
234 if (path.empty())
235 {
236 ARMARX_ERROR << "Could find library '" << entry
237 << "' in any of the following paths: " << p.getLibraryPaths();
238 continue;
239 }
240 }
241 ARMARX_CHECK_EXPRESSION(!path.empty());
242 DynamicLibrary lib;
243 lib.setUnloadOnDestruct(false);
244 ARMARX_VERBOSE << "Loading library " << path.string();
245 lib.load(path);
246 }
247 catch (...)
248 {
250 }
251 }
252 }
253}
254
255bool
257{
258 return forbidThreadCreation;
259}
260
261void
263{
264 forbidThreadCreation = value;
265 if (forbidThreadCreation)
266 {
267 ARMARX_INFO << "Thread creation with RunningTask and PeriodicTask is now forbidden in this "
268 "process.";
269 }
270 else
271 {
272 ARMARX_INFO << "Thread creation with RunningTask and PeriodicTask is now allowed again in "
273 "this process.";
274 }
275}
276
277void
279{
280 this->libLoadingEnabled = enable;
281}
282
283void
285{
286 ARMARX_CHECK_EXPRESSION(commandLineArguments.empty())
287 << "Command line arguments were already set: " << VAROUT(commandLineArguments);
288 commandLineArguments.reserve(argc);
289 for (int i = 0; i < argc; ++i)
290 {
291 commandLineArguments.emplace_back(argv[i]);
292 }
293}
294
295const std::vector<std::string>&
297{
298 return commandLineArguments;
299}
300
301void
303{
305 {
306 Application::getInstance()->interruptCallback(sig);
307 }
308}
309
310// main entry point of Ice::Application
312{
313}
314
317{
318 std::unique_lock lock(instanceMutex);
319
320 return instance;
321}
322
323void
325{
326 std::unique_lock lock(instanceMutex);
327
328 instance = inst;
329}
330
331void
333{
334 // call base class method
336 // set the properties of all components
337 if (armarXManager)
338 {
339 armarXManager->setComponentIceProperties(properties);
340 }
341}
342
343void
344Application::updateIceProperties(const Ice::PropertyDict& properties)
345{
346 // call base class method
348 // update the properties of all components
349 if (armarXManager)
350 {
351 armarXManager->updateComponentIceProperties(properties);
352 }
353}
354
355void
356Application::icePropertiesUpdated(const std::set<std::string>& changedProperties)
357{
358 if (armarXManager)
359 {
360 if (changedProperties.count("DisableLogging") &&
361 getProperty<bool>("DisableLogging").isSet())
362 {
363 // ARMARX_INFO << "Logging disabled: " << getProperty<bool>("DisableLogging").getValue();
364 armarXManager->enableLogging(!getProperty<bool>("DisableLogging").getValue());
365 }
366
367 if (changedProperties.count("EnableProfiling"))
368 {
369 armarXManager->enableProfiling(getProperty<bool>("EnableProfiling").getValue());
370 }
371 if (changedProperties.count("Verbosity"))
372 {
373 armarXManager->setGlobalMinimumLoggingLevel(
374 getProperty<MessageTypeT>("Verbosity").getValue());
375 }
376 }
377}
378
379const ThreadPoolPtr&
381{
382 return threadPool;
383}
384
385int
386Application::run(int argc, char* argv[])
387{
388#ifndef WIN32
389 // register signal handler
390 signal(SIGILL, Application::HandlerFault);
391 signal(SIGSEGV, Application::HandlerFault);
392 signal(SIGABRT, Application::HandlerFault);
393
394 signal(SIGHUP, Application::HandlerInterrupt);
395 signal(SIGINT, Application::HandlerInterrupt);
396 signal(SIGTERM, Application::HandlerInterrupt);
397#endif
398
400
401 // parse options and merge these with properties passed via Ice.Config
402 Ice::PropertiesPtr properties = parseOptionsMergeProperties(argc, argv);
403
404 // parse help options
406
408 ApplicationOptions::parseHelpOptions(properties, argc, argv);
409
410 if (options.error)
411 {
412 // error in options
413 return EXIT_FAILURE;
414 }
415 else if (options.showHelp) // display help
416 {
417 showHelp(options);
418 return EXIT_SUCCESS;
419 }
420 else if (options.showVersion)
421 {
422 std::cout << "Version: " << GetVersion() << std::endl;
423 return EXIT_SUCCESS;
424 }
425
427
428 setIceProperties(properties);
429
430 // Override environment variables if set.
431 {
433
434 const Ice::PropertyDict& env_props =
435 getPropertyDefinitions()->getProperties()->getPropertiesForPrefix("env");
436
437 for (const auto& [name, value] : env_props)
438 {
439 const std::string short_name = name.substr(4); // Cut "env.".
440
441 const auto envVarResolved = armarx::core::system::EnvExpander::expandVariables(value);
442
443 ARMARX_INFO << "Setting environment variable '" << short_name << "' to value '" << envVarResolved
444 << "'.";
445 setenv(short_name.c_str(), envVarResolved.c_str(), 1);
446 }
447 }
448
449 if (getProperty<std::uint64_t>("SecondsStartupDelay").isSet())
450 {
451 const auto delay = getProperty<std::uint64_t>("SecondsStartupDelay").getValue();
452 ARMARX_INFO << "startup delay: " << delay << " seconds";
453 std::this_thread::sleep_for(std::chrono::seconds{delay});
454 }
455 else
456 {
457 ARMARX_DEBUG << "startup delay is not set";
458 }
459
460 // extract application name
461 if (getProperty<std::string>("ApplicationName").isSet())
462 {
463 applicationName = getProperty<std::string>("ApplicationName").getValue();
464 }
465 LogSender::SetLoggingGroup(getProperty<std::string>("LoggingGroup").getValue());
466
467 // Redirect std::cout and std::cerr
468 const bool redirectStdout = getProperty<bool>("RedirectStdout").getValue();
469 ArmarXLogBuf buf("std::cout", MessageTypeT::INFO, false);
470 ArmarXLogBuf errbuf("std::cerr", MessageTypeT::WARN, true);
471 std::streambuf* cout_sbuf = nullptr;
472 std::streambuf* cerr_sbuf = nullptr;
473 if (redirectStdout)
474 {
475 cout_sbuf = std::cout.rdbuf();
476 cerr_sbuf = std::cerr.rdbuf();
477 std::cout.rdbuf(&buf);
478 std::cerr.rdbuf(&errbuf);
479 }
481 {
482 //reset std::cout and std::cerr to original stream
483 if (redirectStdout)
484 {
485 std::cout.rdbuf(cout_sbuf);
486 std::cerr.rdbuf(cerr_sbuf);
487 }
488 };
489
490 int result = EXIT_SUCCESS;
491
492 threadPool.reset(new ThreadPool(getProperty<unsigned int>("ThreadPoolSize").getValue()));
493 // create the ArmarXManager and set its properties
494 try
495 {
496 armarXManager = new ArmarXManager(applicationName, communicator());
497 }
498 catch (Ice::ConnectFailedException&)
499 {
500 return EXIT_FAILURE;
501 }
502
503 armarXManager->setDataPaths(getProperty<std::string>("DataPath").getValue());
504
505 // set the properties again, since the armarx manager is now available
506 setIceProperties(properties);
507
509
510#ifdef WIN32
511 // register interrupt handler
512 callbackOnInterrupt();
513#endif
514
515
516 if (applicationNetworkStats)
517 {
518 ProfilerListenerPrx profilerTopic =
519 armarXManager->getIceManager()->getTopic<ProfilerListenerPrx>(
520 armarx::Profiler::PROFILER_TOPIC_NAME);
521 applicationNetworkStats->start(profilerTopic, applicationName);
522 }
523
524 loadLibrariesFromProperties();
525
526 try
527 {
528 // calls virtual setup in order to allow subclass to add components to the application
529 setup(armarXManager, properties);
530 }
531 catch (...)
532 {
534 armarXManager->shutdown();
535 }
536
537 // calls exec implementation
538 result = exec(armarXManager);
540
541 if (shutdownThread)
542 {
543 ARMARX_VERBOSE << "joining shutdown thread!";
544 shutdownThread->join();
545 }
546 ARMARX_VERBOSE << "Application run finished";
547 return result;
548}
549
550/*
551 * the default exec implementation. Exec is always blocking and waits for
552 * shutdown
553 */
554int
556{
557 armarXManager->waitForShutdown();
558
559 return 0;
560}
561
564{
565 // parse options and merge these with properties passed via Ice.Config
566 // Here, use armarx::IceProperties instead of Ice::Properties
567 // to support property inheritance.
569 ApplicationOptions::mergeProperties(communicator()->getProperties()->clone(), argc, argv));
570
571 // Load config files passed via ArmarX.Config
572 std::string configFiles = communicator()->getProperties()->getProperty("ArmarX.Config");
573
574 PropertyDefinition<std::string>::removeQuotes(configFiles, configFiles);
575
576 // if not set, size is zero
577 // if set with out value (== "1" as TRUE), size is one
578 if (!configFiles.empty() && configFiles.compare("1") != 0)
579 {
580 std::vector<std::string> configFileList = simox::alg::split(configFiles, ",");
581
582 for (std::string configFile : configFileList)
583 {
584 if (!configFile.empty())
585 {
586 properties->load(configFile);
587 }
588 }
589 }
590 return properties;
591}
592
593void
595{
596 // perform dummy setup to register ManagedIceObjects
597 ArmarXDummyManagerPtr dummyManager = new ArmarXDummyManager();
598
599 LogSender::SetLoggingActivated(false, false);
600
601 setup(dummyManager, getIceProperties());
602
603 if (options.outfile.empty())
604 {
605 ApplicationOptions::showHelp(this, dummyManager, options, nullptr);
606 }
607 else
608 {
609 std::ofstream out(options.outfile);
610 if (out.is_open())
611 {
612 ApplicationOptions::showHelp(this, dummyManager, options, nullptr, out);
613 }
614 else
615 {
617 ApplicationOptions::showHelp(this, dummyManager, options, nullptr);
618
619 std::cout << "Could not write to file " << options.outfile << std::endl;
620 }
621 }
622}
623
624std::string
626{
627 return "ArmarX";
628}
629
630void
631Application::setName(const std::string& name)
632{
633 this->applicationName = name;
634}
635
636std::string
638{
639 return applicationName;
640}
641
642void
644{
645 ARMARX_INFO_S << "Interrupt received: " << signal;
646 if (applicationNetworkStats)
647 {
648 applicationNetworkStats->stopTask();
649 }
650 if (!shutdownThread)
651 shutdownThread.reset(new std::thread{[this]
652 {
653 if (armarXManager)
654 this->armarXManager->shutdown();
655 }});
656}
657
658void
660{
661 IceUtil::Time start = IceUtil::Time::now();
662 ARMARX_INFO_S << "Deps: " << dependencies;
663 dependencies = simox::alg::replace_all(dependencies, "\"", "");
664 Ice::StringSeq resultList = simox::alg::split(dependencies, "/");
665
666 for (size_t i = 0; i < resultList.size(); i++)
667 {
668 CMakePackageFinder pack(resultList[i]);
669
670 if (pack.packageFound())
671 {
673 }
674 }
675
676 ARMARX_INFO_S << "loading took " << (IceUtil::Time::now() - start).toMilliSeconds();
677}
678
679bool
681{
682 const std::string autodiscoverPropertyName = "AutodiscoverPackages";
683
684 if (hasProperty(autodiscoverPropertyName))
685 {
686 ARMARX_VERBOSE << "`" << autodiscoverPropertyName << "` property available.";
687 return getProperty<bool>(autodiscoverPropertyName).getValue();
688 }
689
690 return true; // Property not available. Default: use autodiscovery
691}
692
693std::vector<std::string>
695{
697 {
698 ARMARX_VERBOSE << "ArmarX package autodiscovery activated.";
700 }
701
702 ARMARX_VERBOSE << "ArmarX package autodiscovery not activated.";
703
704 // legacy: use only those packages listed in the config file (e.g. default.cfg)
705 Ice::StringSeq result = getProperty<Ice::StringSeq>("DefaultPackages").getValue();
706 Ice::StringSeq additional = getProperty<Ice::StringSeq>("AdditionalPackages").getValue();
707 result.insert(result.end(), additional.begin(), additional.end());
708
709 return result;
710}
711
712std::string
714{
715 char* env_armarx_workspace = getenv("ARMARX_WORKSPACE");
716 char* env_armarx_default_config_dir_name = getenv("ARMARX_CONFIG_DIR_NAME");
717
718 std::filesystem::path armarx_workspace;
719 std::filesystem::path armarx_config_dir;
720
721 if (env_armarx_workspace)
722 {
723 armarx_workspace = std::filesystem::path(env_armarx_workspace);
724 }
725 else
726 {
727 char* home = getenv("HOME");
728
729 if (home)
730 {
731 armarx_workspace = std::filesystem::path(home);
732 }
733 else
734 {
735 armarx_workspace = "~/";
736 }
737 }
738
739 if (env_armarx_default_config_dir_name)
740 {
741 armarx_config_dir = std::filesystem::path(env_armarx_default_config_dir_name);
742 }
743 else
744 {
745 if (env_armarx_workspace)
746 {
747 armarx_config_dir = "armarx_config";
748 }
749 // Legacy mode.
750 else
751 {
752 armarx_config_dir = ".armarx";
753 }
754 }
755
756 if (envVarExpanded)
757 {
758 return (armarx_workspace / armarx_config_dir).string();
759 }
760 else
761 {
762 if (env_armarx_workspace)
763 {
764 return "${ARMARX_WORKSPACE}/" + armarx_config_dir.string();
765 }
766 // Legacy mode.
767 else
768 {
769 return "${HOME}/" + armarx_config_dir.string();
770 }
771 }
772}
773
776{
777 return armarXManager;
778}
779
780int
781Application::doMain(int argc, char* argv[], const Ice::InitializationData& initData, Ice::Int i)
782{
783 // create copy of initData so the stats object can be added
784 // using const_cast leads to unexpected errors
785 Ice::InitializationData id(initData);
786 loadDefaultConfig(argc, argv, id);
787
788 // enable the PropertyAdmin ObjectAdapter
789 // https://doc.zeroc.com/display/Ice35/The+Administrative+Object+Adapter
790 if (id.properties->getProperty("Ice.Admin.InstanceName").empty())
791 {
792 id.properties->setProperty("Ice.Admin.InstanceName", this->getName());
793 }
794 if (id.properties->getProperty("Ice.Admin.Endpoints").empty())
795 {
796 id.properties->setProperty("Ice.Admin.Endpoints", "tcp -h 127.0.0.1");
797 }
798
799 if (initData.properties->getProperty("ArmarX.NetworkStats") == "1")
800 {
801 applicationNetworkStats = new ApplicationNetworkStats();
802 id.observer = applicationNetworkStats;
803
804 const auto oldFacets = initData.properties->getPropertyAsList("Ice.Admin.Facets");
805 if (oldFacets.empty())
806 {
807 initData.properties->setProperty("Ice.Admin.Facets", "Metrics");
808 }
809 else if (std::find(oldFacets.begin(), oldFacets.end(), "Metrics") == oldFacets.end())
810 {
811 std::stringstream str;
812 str << "Metrics";
813 for (const auto& facet : oldFacets)
814 {
815 str << "," << facet;
816 }
817 initData.properties->setProperty("Ice.Admin.Facets", str.str());
818 }
819 initData.properties->setProperty("IceMX.Metrics.NetworkStats.GroupBy", "none");
820 }
821
822 return Ice::Application::doMain(argc, argv, id, i);
823}
824
825Ice::StringSeq
827{
828 const std::string configFileName = "default.cfg";
829 const std::string generatedConfigFileName = "default.generated.cfg";
830 Ice::StringSeq defaultsPaths;
831 char* defaultsPathVar = getenv(ArmarXUserConfigDirEnvVar.c_str());
832 std::filesystem::path absBasePath;
833 if (defaultsPathVar)
834 {
835 absBasePath = defaultsPathVar;
836 }
837 else
838 {
839 absBasePath = std::filesystem::path(GetArmarXConfigDefaultPath());
840 }
841 defaultsPaths.push_back((absBasePath / configFileName).string());
842 defaultsPaths.push_back((absBasePath / generatedConfigFileName).string());
843 return defaultsPaths;
844}
845
846void
847Application::loadDefaultConfig(int argc, char* argv[], const Ice::InitializationData& initData)
848{
849 LoadDefaultConfig(initData.properties);
850}
851
852void
854{
855 const Ice::StringSeq defaultsPath = GetDefaultsPaths();
857
858 for (std::string path : defaultsPath)
859 {
860 try
861 {
862 p->load(path);
863
864 Ice::PropertyDict defaultCfg = p->getPropertiesForPrefix("");
865
866 // copy default config into current config (if values are not already there)
867 for (auto e : defaultCfg)
868 {
869 if (properties->getProperty(e.first).empty())
870 {
871 properties->setProperty(e.first, e.second);
872 }
873 }
874 }
875 catch (Ice::FileException& e)
876 {
877 ARMARX_WARNING_S << "Loading default config failed: " << e.what();
878 }
879 }
880}
881
882const std::string&
884{
885 return ProjectName;
886}
887
888const Ice::StringSeq&
890{
891 return ProjectDependendencies;
892}
893
899
900void
902{
903 std::string dependenciesConfig = getIceProperties()->getProperty("ArmarX.DependenciesConfig");
904
905 if (!dependenciesConfig.empty())
906 {
907 if (std::filesystem::exists(dependenciesConfig))
908 {
910 prop->load(dependenciesConfig);
911 ArmarXDataPath::addDataPaths(prop->getProperty("ArmarX.ProjectDatapath"));
912 ProjectName = prop->getProperty("ArmarX.ProjectName");
913 std::string dependencies = prop->getProperty("ArmarX.ProjectDependencies");
914 ProjectDependendencies = simox::alg::split(dependencies, ";");
915 }
916 else
917 {
918 /*
919 ARMARX_WARNING_S << "The given project datapath config file '" << datapathConfig << "', that this app depends on, could not be found. \
920 Relative paths to subprojects are not available. Set the property ArmarX.ProjectDatapath to empty, if you do not need the paths.";
921 */
922 }
923 }
924}
925
928{
930 "Config", "", "Comma-separated list of configuration files ");
932 "DependenciesConfig",
933 "./config/dependencies.cfg",
934 "Path to the (usually generated) config file containing all data paths of all dependent "
935 "projects. This property usually does not need to be edited.");
937 "DefaultPackages",
938 {"ArmarXCore",
939 "ArmarXGui",
940 "MemoryX",
941 "RobotAPI",
942 "RobotComponents",
943 "RobotSkillTemplates",
944 "ArmarXSimulation",
945 "VisionX",
946 "SpeechX",
947 "Armar3",
948 "Spoac"},
949 "List of ArmarX packages which are accessible by default. Comma separated List. If you "
950 "want to add your own packages and use all default ArmarX packages, use the property "
951 "'AdditionalPackages'.");
953 "AdditionalPackages",
954 {},
955 "List of additional ArmarX packages which should be in the list of default packages. If "
956 "you have custom packages, which should be found by the gui or other apps, specify them "
957 "here. Comma separated List.");
958
960 "AutodiscoverPackages",
961 true,
962 "If enabled, will discover all ArmarX packages based on the environment variables. "
963 "Otherwise, the `DefaultPackages` and `AdditionalPackages` properties are used.");
964
965 defineOptionalProperty<std::string>("ApplicationName", "", "Application name");
966
967 defineOptionalProperty<bool>("DisableLogging",
968 false,
969 "Turn logging off in whole application",
971
974 "Global logging level for whole application",
976
978 "LoggingGroup",
979 "",
980 "The logging group is transmitted with every ArmarX log message over Ice in order to group "
981 "the message in the GUI.");
982
983
985 "DataPath", "", "Semicolon-separated search list for data files");
986
988 "CachePath",
989 "mongo/.cache",
990 std::string("Path for cache files. If relative path AND env. variable ") +
992 " is set, the cache path will be made relative to " +
994 ". Otherwise if relative it will be relative to the default ArmarX config dir (" +
996
997 defineOptionalProperty<bool>("EnableProfiling",
998 false,
999 "Enable profiling of CPU load produced by this application",
1001
1003 "RedirectStdout", true, "Redirect std::cout and std::cerr to ArmarXLog");
1004
1006 "TopicSuffix",
1007 "",
1008 "Suffix appended to all topic names for outgoing topics. This is mainly used to direct all "
1009 "topics to another name for TopicReplaying purposes.");
1010
1012 "UseTimeServer", false, "Enable using a global Timeserver (e.g. from ArmarXSimulator)");
1013
1015 "RemoteHandlesDeletionTimeout",
1016 3000,
1017 "The timeout (in ms) before a remote handle deletes the managed object after the use count "
1018 "reached 0. This time can be used by a client to increment the count again (may be "
1019 "required when transmitting remote handles)");
1020 defineOptionalProperty<bool>("StartDebuggerOnCrash",
1021 false,
1022 "If this application crashes (segmentation fault) qtcreator will "
1023 "attach to this process and start the debugger.");
1025 "ThreadPoolSize", 1, "Size of the ArmarX ThreadPool that is always running.");
1027 "LoadLibraries",
1028 "",
1029 "Libraries to load at start up of the application. Must be enabled by the Application with "
1030 "enableLibLoading(). Format: PackageName:LibraryName;... or /absolute/path/to/library;...");
1032 "SecondsStartupDelay",
1033 0,
1034 "The startup will be delayed by this number of seconds (useful for debugging)");
1035}
#define VAROUT(x)
std::string str(const T &t)
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 &registry, 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
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)
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.
The ThreadPool class.
Definition ThreadPool.h:46
static std::string expandVariables(const std::string &value)
bool crashed
std::string errormsg
#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.
Definition Logging.h:181
#define ARMARX_FATAL_S
The logging level for unexpected behaviour, that will lead to a seriously malfunctioning program and ...
Definition Logging.h:219
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_INFO_S
Definition Logging.h:202
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:213
#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
void handleExceptions()
std::vector< std::string > Split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
IceUtil::Handle< Application > ApplicationPtr
Definition Application.h:93
std::shared_ptr< ThreadPool > ThreadPoolPtr
Definition Application.h:76
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
bool Contains(const ContainerType &container, const ElementType &searchElement)
Definition algorithm.h:330
IceUtil::Handle< ArmarXDummyManager > ArmarXDummyManagerPtr
Stucture containing the parsed options of the application.
#define ARMARX_TRACE
Definition trace.h:77