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/core/logging/PlogArmarXAppender.h" // for RegisterPlogArmarXAppender
72#include "ArmarXCore/interface/core/Log.h" // for MessageType, etc
73#include "ArmarXCore/interface/core/Profiler.h"
78
79#include "../logging/ArmarXLogBuf.h" // for ArmarXLogBuf
80#include "ApplicationNetworkStats.h" // for ApplicationNetworkStatsPtr
81#include "ApplicationOptions.h" // for Options, showHelp, etc
82#include "ApplicationProcessFacet.h" // for ArmarXManagerPtr, etc
83#include "properties/IceProperties.h" // for IceProperties
84
85#ifndef WIN32
86#include <signal.h> // for signal, SIGABRT, SIGSEGV, etc
87
88#include <cstdio>
89
90#include <ArmarXCore/core/util/OnScopeExit.h> // for ARMARX_ON_SCOPE_EXIT
91
92#include <execinfo.h>
93#endif
94
95#include <stdlib.h>
96
97
98using namespace armarx;
99
100// static members for the one application instance (maybe not required anymore???)
101std::mutex Application::instanceMutex;
102ApplicationPtr Application::instance;
103Ice::StringSeq Application::ProjectDependendencies;
104std::string Application::ProjectName;
105const std::string Application::ArmarXUserConfigDirEnvVar = "ARMARX_CONFIG_DIR";
106std::string errormsg = "Segmentation fault - Backtrace: \n";
107bool crashed = false;
108
109void
111{
112 if (crashed)
113 {
114 return;
115 }
116 crashed = true;
117
118 // dont allocate memory in segfault
119 if (sig == SIGSEGV)
120 {
121 std::array<void*, 20> array;
122 size_t size;
123 size = backtrace(array.data(), 20);
124
125#pragma GCC diagnostic push
126#pragma GCC diagnostic ignored "-Wunused-result"
127 write(STDERR_FILENO, errormsg.data(), errormsg.size());
128#pragma GCC diagnostic pop
129 backtrace_symbols_fd(array.data(), size, STDERR_FILENO);
130 exit(EXIT_FAILURE);
131 }
132 // print out all the frames to stderr
133 try
134 {
135 std::stringstream str;
136
137 if (sig == SIGABRT)
138 {
139 str << "Error: Abort\nBacktrace:\n";
140 }
141 else
142 {
143 str << "Error: signal " << sig;
144 }
145
146 ARMARX_FATAL_S << str.str() << "\nBacktrace:\n" << LogSender::CreateBackTrace();
147 if ((sig == SIGSEGV || sig == SIGABRT) && Application::getInstance() &&
148 Application::getInstance()->getProperty<bool>("StartDebuggerOnCrash").getValue())
149 {
150 std::stringstream s;
151 int res;
152
153 /*
154 const char* envEditor = std::getenv("ARMARX_DEBUGGER");
155
156 const std::string editorName = [&]() -> std::string
157 {
158 if (envEditor == nullptr)
159 {
160 return DEFAULT_EDITOR;
161 }
162
163 const std::string editor = std::string(envEditor);
164 if (editors.count(editor) > 0)
165 {
166 return editor;
167 }
168
169 ARMARX_WARNING << "The editor '" << editor << "' is not registered. "
170 << "Check the config '" << EDITORFILEOPENER_CONFIGFILE << "'";
171
172 return DEFAULT_EDITOR;
173 }();
174
175 */
176
177
178 // res = system("which qtcreator");
179 // res = WEXITSTATUS(res);
180 // if (res == EXIT_SUCCESS)
181 {
182 s << "qtcreator -debug " << getpid();
183 ARMARX_IMPORTANT << s.str();
184 res = system(s.str().c_str());
185 res++; // suppress warning
186 }
187 // else
188 // {
189 // ARMARX_INFO_S << "Could not find qtcreator";
190 // }
191 }
192 }
193 catch (...)
194 {
195 // do nothing
196 }
197 exit(EXIT_FAILURE);
198}
199
200void
201Application::loadLibrariesFromProperties()
202{
203 auto loadLibString = getProperty<std::string>("LoadLibraries").getValue();
204 if (!loadLibString.empty())
205 {
206 if (!libLoadingEnabled)
207 {
208 throw LocalException("Loading of dynamic libraries is not enabled in this application. "
209 "The Application needs to call enableLibLoading()");
210 }
211 auto entries = armarx::Split(loadLibString, ";", true, true);
212 for (auto& entry : entries)
213 {
214 try
215 {
216 std::filesystem::path path;
217 if (armarx::Contains(entry, "/"))
218 {
219 path = entry;
220 }
221 else
222 {
223 auto elements = Split(entry, ":");
224 ARMARX_CHECK_EQUAL(elements.size(), 2);
225
226 CMakePackageFinder p(elements.at(0));
227
228 // case entry ^= `package_name`::`package_name`_`lib_name`
229 {
230 std::string libFileName = "lib" + elements.at(1) + "." +
232 for (auto& libDir : armarx::Split(p.getLibraryPaths(), ";"))
233 {
234 std::filesystem::path testPath(libDir);
235 testPath /= libFileName;
236 if (std::filesystem::exists(testPath))
237 {
238 path = testPath;
239 break;
240 }
241 }
242 }
243 // case entry ^= `package_name`::`lib_name`
244 {
245 // the filename is known to be "lib`package_name`_`lib_name`.so"
246 std::string libFileName = "lib" + elements.at(0) + "_" + elements.at(1) +
247 "." +
249 for (auto& libDir : armarx::Split(p.getLibraryPaths(), ";"))
250 {
251 std::filesystem::path testPath(libDir);
252 testPath /= libFileName;
253 if (std::filesystem::exists(testPath))
254 {
255 path = testPath;
256 break;
257 }
258 }
259 }
260
261 if (path.empty())
262 {
263 ARMARX_ERROR << "Could find library '" << entry
264 << "' in any of the following paths: " << p.getLibraryPaths();
265 continue;
266 }
267 }
268 ARMARX_CHECK_EXPRESSION(!path.empty());
269 DynamicLibrary lib;
270 lib.setUnloadOnDestruct(false);
271 ARMARX_VERBOSE << "Loading library " << path.string();
272 lib.load(path);
273 }
274 catch (...)
275 {
277 }
278 }
279 }
280}
281
282bool
284{
285 return forbidThreadCreation;
286}
287
288void
290{
291 forbidThreadCreation = value;
292 if (forbidThreadCreation)
293 {
294 ARMARX_INFO << "Thread creation with RunningTask and PeriodicTask is now forbidden in this "
295 "process.";
296 }
297 else
298 {
299 ARMARX_INFO << "Thread creation with RunningTask and PeriodicTask is now allowed again in "
300 "this process.";
301 }
302}
303
304void
306{
307 this->libLoadingEnabled = enable;
308}
309
310void
312{
313 ARMARX_CHECK_EXPRESSION(commandLineArguments.empty())
314 << "Command line arguments were already set: " << VAROUT(commandLineArguments);
315 commandLineArguments.reserve(argc);
316 for (int i = 0; i < argc; ++i)
317 {
318 commandLineArguments.emplace_back(argv[i]);
319 }
320}
321
322const std::vector<std::string>&
324{
325 return commandLineArguments;
326}
327
328void
330{
332 {
333 Application::getInstance()->interruptCallback(sig);
334 }
335}
336
337// main entry point of Ice::Application
339{
340}
341
344{
345 std::unique_lock lock(instanceMutex);
346
347 return instance;
348}
349
350void
352{
353 std::unique_lock lock(instanceMutex);
354
355 instance = inst;
356}
357
358void
360{
361 // call base class method
363 // set the properties of all components
364 if (armarXManager)
365 {
366 armarXManager->setComponentIceProperties(properties);
367 }
368}
369
370void
371Application::updateIceProperties(const Ice::PropertyDict& properties)
372{
373 // call base class method
375 // update the properties of all components
376 if (armarXManager)
377 {
378 armarXManager->updateComponentIceProperties(properties);
379 }
380}
381
382void
383Application::icePropertiesUpdated(const std::set<std::string>& changedProperties)
384{
385 if (armarXManager)
386 {
387 if (changedProperties.count("DisableLogging") &&
388 getProperty<bool>("DisableLogging").isSet())
389 {
390 // ARMARX_INFO << "Logging disabled: " << getProperty<bool>("DisableLogging").getValue();
391 armarXManager->enableLogging(!getProperty<bool>("DisableLogging").getValue());
392 }
393
394 if (changedProperties.count("EnableProfiling"))
395 {
396 armarXManager->enableProfiling(getProperty<bool>("EnableProfiling").getValue());
397 }
398 if (changedProperties.count("Verbosity"))
399 {
400 armarXManager->setGlobalMinimumLoggingLevel(
401 getProperty<MessageTypeT>("Verbosity").getValue());
402 }
403 }
404}
405
406const ThreadPoolPtr&
408{
409 return threadPool;
410}
411
412int
413Application::run(int argc, char* argv[])
414{
415#ifndef WIN32
416 // register signal handler
417 signal(SIGILL, Application::HandlerFault);
418 signal(SIGSEGV, Application::HandlerFault);
419 signal(SIGABRT, Application::HandlerFault);
420
421 signal(SIGHUP, Application::HandlerInterrupt);
422 signal(SIGINT, Application::HandlerInterrupt);
423 signal(SIGTERM, Application::HandlerInterrupt);
424#endif
425
427
428 // parse options and merge these with properties passed via Ice.Config
429 Ice::PropertiesPtr properties = parseOptionsMergeProperties(argc, argv);
430
431 // parse help options
433
435 ApplicationOptions::parseHelpOptions(properties, argc, argv);
436
437 if (options.error)
438 {
439 // error in options
440 return EXIT_FAILURE;
441 }
442 else if (options.showHelp) // display help
443 {
444 showHelp(options);
445 return EXIT_SUCCESS;
446 }
447 else if (options.showVersion)
448 {
449 std::cout << "Version: " << GetVersion() << std::endl;
450 return EXIT_SUCCESS;
451 }
452
454
455 setIceProperties(properties);
456
457 // Override environment variables if set.
458 {
460
461 const Ice::PropertyDict& env_props =
462 getPropertyDefinitions()->getProperties()->getPropertiesForPrefix("env");
463
464 for (const auto& [name, value] : env_props)
465 {
466 const std::string short_name = name.substr(4); // Cut "env.".
467
468 const auto envVarResolved = armarx::core::system::EnvExpander::expandVariables(value);
469
470 ARMARX_INFO << "Setting environment variable '" << short_name << "' to value '" << envVarResolved
471 << "'.";
472 setenv(short_name.c_str(), envVarResolved.c_str(), 1);
473 }
474 }
475
476 if (getProperty<std::uint64_t>("SecondsStartupDelay").isSet())
477 {
478 const auto delay = getProperty<std::uint64_t>("SecondsStartupDelay").getValue();
479 ARMARX_INFO << "startup delay: " << delay << " seconds";
480 std::this_thread::sleep_for(std::chrono::seconds{delay});
481 }
482 else
483 {
484 ARMARX_DEBUG << "startup delay is not set";
485 }
486
487 // extract application name
488 if (getProperty<std::string>("ApplicationName").isSet())
489 {
490 applicationName = getProperty<std::string>("ApplicationName").getValue();
491 }
492 LogSender::SetLoggingGroup(getProperty<std::string>("LoggingGroup").getValue());
493
494#if ARMARX_PLOG_SUPPORT
495 armarx::RegisterPlogArmarXAppender();
496#endif
497
498 // Redirect std::cout and std::cerr
499 const bool redirectStdout = getProperty<bool>("RedirectStdout").getValue();
500 ArmarXLogBuf buf("std::cout", MessageTypeT::INFO, false);
501 ArmarXLogBuf errbuf("std::cerr", MessageTypeT::WARN, true);
502 std::streambuf* cout_sbuf = nullptr;
503 std::streambuf* cerr_sbuf = nullptr;
504 if (redirectStdout)
505 {
506 cout_sbuf = std::cout.rdbuf();
507 cerr_sbuf = std::cerr.rdbuf();
508 std::cout.rdbuf(&buf);
509 std::cerr.rdbuf(&errbuf);
510 }
512 {
513 //reset std::cout and std::cerr to original stream
514 if (redirectStdout)
515 {
516 std::cout.rdbuf(cout_sbuf);
517 std::cerr.rdbuf(cerr_sbuf);
518 }
519 };
520
521 int result = EXIT_SUCCESS;
522
523 threadPool.reset(new ThreadPool(getProperty<unsigned int>("ThreadPoolSize").getValue()));
524 // create the ArmarXManager and set its properties
525 try
526 {
527 armarXManager = new ArmarXManager(applicationName, communicator());
528 }
529 catch (Ice::ConnectFailedException&)
530 {
531 return EXIT_FAILURE;
532 }
533
534 armarXManager->setDataPaths(getProperty<std::string>("DataPath").getValue());
535
536 // set the properties again, since the armarx manager is now available
537 setIceProperties(properties);
538
540
541#ifdef WIN32
542 // register interrupt handler
543 callbackOnInterrupt();
544#endif
545
546
547 if (applicationNetworkStats)
548 {
549 ProfilerListenerPrx profilerTopic =
550 armarXManager->getIceManager()->getTopic<ProfilerListenerPrx>(
551 armarx::Profiler::PROFILER_TOPIC_NAME);
552 applicationNetworkStats->start(profilerTopic, applicationName);
553 }
554
555 loadLibrariesFromProperties();
556
557 try
558 {
559 // calls virtual setup in order to allow subclass to add components to the application
560 setup(armarXManager, properties);
561 }
562 catch (...)
563 {
565 armarXManager->shutdown();
566 }
567
568 // calls exec implementation
569 result = exec(armarXManager);
571
572 if (shutdownThread)
573 {
574 ARMARX_VERBOSE << "joining shutdown thread!";
575 shutdownThread->join();
576 }
577 ARMARX_VERBOSE << "Application run finished";
578 return result;
579}
580
581/*
582 * the default exec implementation. Exec is always blocking and waits for
583 * shutdown
584 */
585int
587{
588 armarXManager->waitForShutdown();
589
590 return 0;
591}
592
595{
596 // parse options and merge these with properties passed via Ice.Config
597 // Here, use armarx::IceProperties instead of Ice::Properties
598 // to support property inheritance.
600 ApplicationOptions::mergeProperties(communicator()->getProperties()->clone(), argc, argv));
601
602 // Load config files passed via ArmarX.Config
603 std::string configFiles = communicator()->getProperties()->getProperty("ArmarX.Config");
604
605 PropertyDefinition<std::string>::removeQuotes(configFiles, configFiles);
606
607 // if not set, size is zero
608 // if set with out value (== "1" as TRUE), size is one
609 if (!configFiles.empty() && configFiles.compare("1") != 0)
610 {
611 std::vector<std::string> configFileList = simox::alg::split(configFiles, ",");
612
613 for (std::string configFile : configFileList)
614 {
615 if (!configFile.empty())
616 {
617 properties->load(configFile);
618 }
619 }
620 }
621 return properties;
622}
623
624void
626{
627 // perform dummy setup to register ManagedIceObjects
628 ArmarXDummyManagerPtr dummyManager = new ArmarXDummyManager();
629
630 LogSender::SetLoggingActivated(false, false);
631
632 setup(dummyManager, getIceProperties());
633
634 if (options.outfile.empty())
635 {
636 ApplicationOptions::showHelp(this, dummyManager, options, nullptr);
637 }
638 else
639 {
640 std::ofstream out(options.outfile);
641 if (out.is_open())
642 {
643 ApplicationOptions::showHelp(this, dummyManager, options, nullptr, out);
644 }
645 else
646 {
648 ApplicationOptions::showHelp(this, dummyManager, options, nullptr);
649
650 std::cout << "Could not write to file " << options.outfile << std::endl;
651 }
652 }
653}
654
655std::string
657{
658 return "ArmarX";
659}
660
661void
662Application::setName(const std::string& name)
663{
664 this->applicationName = name;
665}
666
667std::string
669{
670 return applicationName;
671}
672
673void
675{
676 ARMARX_INFO_S << "Interrupt received: " << signal;
677 if (applicationNetworkStats)
678 {
679 applicationNetworkStats->stopTask();
680 }
681 if (!shutdownThread)
682 shutdownThread.reset(new std::thread{[this]
683 {
684 if (armarXManager)
685 this->armarXManager->shutdown();
686 }});
687}
688
689void
691{
692 IceUtil::Time start = IceUtil::Time::now();
693 ARMARX_INFO_S << "Deps: " << dependencies;
694 dependencies = simox::alg::replace_all(dependencies, "\"", "");
695 Ice::StringSeq resultList = simox::alg::split(dependencies, "/");
696
697 for (size_t i = 0; i < resultList.size(); i++)
698 {
699 CMakePackageFinder pack(resultList[i]);
700
701 if (pack.packageFound())
702 {
704 }
705 }
706
707 ARMARX_INFO_S << "loading took " << (IceUtil::Time::now() - start).toMilliSeconds();
708}
709
710bool
712{
713 const std::string autodiscoverPropertyName = "AutodiscoverPackages";
714
715 if (hasProperty(autodiscoverPropertyName))
716 {
717 ARMARX_VERBOSE << "`" << autodiscoverPropertyName << "` property available.";
718 return getProperty<bool>(autodiscoverPropertyName).getValue();
719 }
720
721 return true; // Property not available. Default: use autodiscovery
722}
723
724std::vector<std::string>
726{
728 {
729 ARMARX_VERBOSE << "ArmarX package autodiscovery activated.";
731 }
732
733 ARMARX_VERBOSE << "ArmarX package autodiscovery not activated.";
734
735 // legacy: use only those packages listed in the config file (e.g. default.cfg)
736 Ice::StringSeq result = getProperty<Ice::StringSeq>("DefaultPackages").getValue();
737 Ice::StringSeq additional = getProperty<Ice::StringSeq>("AdditionalPackages").getValue();
738 result.insert(result.end(), additional.begin(), additional.end());
739
740 return result;
741}
742
743std::string
745{
746 char* env_armarx_workspace = getenv("ARMARX_WORKSPACE");
747 char* env_armarx_default_config_dir_name = getenv("ARMARX_CONFIG_DIR_NAME");
748
749 std::filesystem::path armarx_workspace;
750 std::filesystem::path armarx_config_dir;
751
752 if (env_armarx_workspace)
753 {
754 armarx_workspace = std::filesystem::path(env_armarx_workspace);
755 }
756 else
757 {
758 char* home = getenv("HOME");
759
760 if (home)
761 {
762 armarx_workspace = std::filesystem::path(home);
763 }
764 else
765 {
766 armarx_workspace = "~/";
767 }
768 }
769
770 if (env_armarx_default_config_dir_name)
771 {
772 armarx_config_dir = std::filesystem::path(env_armarx_default_config_dir_name);
773 }
774 else
775 {
776 if (env_armarx_workspace)
777 {
778 armarx_config_dir = "armarx_config";
779 }
780 // Legacy mode.
781 else
782 {
783 armarx_config_dir = ".armarx";
784 }
785 }
786
787 if (envVarExpanded)
788 {
789 return (armarx_workspace / armarx_config_dir).string();
790 }
791 else
792 {
793 if (env_armarx_workspace)
794 {
795 return "${ARMARX_WORKSPACE}/" + armarx_config_dir.string();
796 }
797 // Legacy mode.
798 else
799 {
800 return "${HOME}/" + armarx_config_dir.string();
801 }
802 }
803}
804
807{
808 return armarXManager;
809}
810
811int
812Application::doMain(int argc, char* argv[], const Ice::InitializationData& initData, Ice::Int i)
813{
814 // create copy of initData so the stats object can be added
815 // using const_cast leads to unexpected errors
816 Ice::InitializationData id(initData);
817 loadDefaultConfig(argc, argv, id);
818
819 // enable the PropertyAdmin ObjectAdapter
820 // https://doc.zeroc.com/display/Ice35/The+Administrative+Object+Adapter
821 if (id.properties->getProperty("Ice.Admin.InstanceName").empty())
822 {
823 id.properties->setProperty("Ice.Admin.InstanceName", this->getName());
824 }
825 if (id.properties->getProperty("Ice.Admin.Endpoints").empty())
826 {
827 id.properties->setProperty("Ice.Admin.Endpoints", "tcp -h 127.0.0.1");
828 }
829
830 if (initData.properties->getProperty("ArmarX.NetworkStats") == "1")
831 {
832 applicationNetworkStats = new ApplicationNetworkStats();
833 id.observer = applicationNetworkStats;
834
835 const auto oldFacets = initData.properties->getPropertyAsList("Ice.Admin.Facets");
836 if (oldFacets.empty())
837 {
838 initData.properties->setProperty("Ice.Admin.Facets", "Metrics");
839 }
840 else if (std::find(oldFacets.begin(), oldFacets.end(), "Metrics") == oldFacets.end())
841 {
842 std::stringstream str;
843 str << "Metrics";
844 for (const auto& facet : oldFacets)
845 {
846 str << "," << facet;
847 }
848 initData.properties->setProperty("Ice.Admin.Facets", str.str());
849 }
850 initData.properties->setProperty("IceMX.Metrics.NetworkStats.GroupBy", "none");
851 }
852
853 return Ice::Application::doMain(argc, argv, id, i);
854}
855
856Ice::StringSeq
858{
859 const std::string configFileName = "default.cfg";
860 const std::string generatedConfigFileName = "default.generated.cfg";
861 Ice::StringSeq defaultsPaths;
862 char* defaultsPathVar = getenv(ArmarXUserConfigDirEnvVar.c_str());
863 std::filesystem::path absBasePath;
864 if (defaultsPathVar)
865 {
866 absBasePath = defaultsPathVar;
867 }
868 else
869 {
870 absBasePath = std::filesystem::path(GetArmarXConfigDefaultPath());
871 }
872 defaultsPaths.push_back((absBasePath / configFileName).string());
873 defaultsPaths.push_back((absBasePath / generatedConfigFileName).string());
874 return defaultsPaths;
875}
876
877void
878Application::loadDefaultConfig(int argc, char* argv[], const Ice::InitializationData& initData)
879{
880 LoadDefaultConfig(initData.properties);
881}
882
883void
885{
886 const Ice::StringSeq defaultsPath = GetDefaultsPaths();
888
889 for (std::string path : defaultsPath)
890 {
891 try
892 {
893 p->load(path);
894
895 Ice::PropertyDict defaultCfg = p->getPropertiesForPrefix("");
896
897 // copy default config into current config (if values are not already there)
898 for (auto e : defaultCfg)
899 {
900 if (properties->getProperty(e.first).empty())
901 {
902 properties->setProperty(e.first, e.second);
903 }
904 }
905 }
906 catch (Ice::FileException& e)
907 {
908 ARMARX_WARNING_S << "Loading default config failed: " << e.what();
909 }
910 }
911}
912
913const std::string&
915{
916 return ProjectName;
917}
918
919const Ice::StringSeq&
921{
922 return ProjectDependendencies;
923}
924
930
931void
933{
934 std::string dependenciesConfig = getIceProperties()->getProperty("ArmarX.DependenciesConfig");
935
936 if (!dependenciesConfig.empty())
937 {
938 if (std::filesystem::exists(dependenciesConfig))
939 {
941 prop->load(dependenciesConfig);
942 ArmarXDataPath::addDataPaths(prop->getProperty("ArmarX.ProjectDatapath"));
943 ProjectName = prop->getProperty("ArmarX.ProjectName");
944 std::string dependencies = prop->getProperty("ArmarX.ProjectDependencies");
945 ProjectDependendencies = simox::alg::split(dependencies, ";");
946 }
947 else
948 {
949 /*
950 ARMARX_WARNING_S << "The given project datapath config file '" << datapathConfig << "', that this app depends on, could not be found. \
951 Relative paths to subprojects are not available. Set the property ArmarX.ProjectDatapath to empty, if you do not need the paths.";
952 */
953 }
954 }
955}
956
959{
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.");
968 "DefaultPackages",
969 {"ArmarXCore",
970 "ArmarXGui",
971 "MemoryX",
972 "RobotAPI",
973 "RobotComponents",
974 "RobotSkillTemplates",
975 "ArmarXSimulation",
976 "VisionX",
977 "SpeechX",
978 "Armar3",
979 "Spoac"},
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",
985 {},
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.");
989
991 "AutodiscoverPackages",
992 true,
993 "If enabled, will discover all ArmarX packages based on the environment variables. "
994 "Otherwise, the `DefaultPackages` and `AdditionalPackages` properties are used.");
995
996 defineOptionalProperty<std::string>("ApplicationName", "", "Application name");
997
998 defineOptionalProperty<bool>("DisableLogging",
999 false,
1000 "Turn logging off in whole application",
1002
1005 "Global logging level for whole application",
1007
1009 "LoggingGroup",
1010 "",
1011 "The logging group is transmitted with every ArmarX log message over Ice in order to group "
1012 "the message in the GUI.");
1013
1014
1016 "DataPath", "", "Semicolon-separated search list for data files");
1017
1019 "CachePath",
1020 "mongo/.cache",
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 (" +
1027
1028 defineOptionalProperty<bool>("EnableProfiling",
1029 false,
1030 "Enable profiling of CPU load produced by this application",
1032
1034 "RedirectStdout", true, "Redirect std::cout and std::cerr to ArmarXLog");
1035
1037 "TopicSuffix",
1038 "",
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.");
1041
1043 "UseTimeServer", false, "Enable using a global Timeserver (e.g. from ArmarXSimulator)");
1044
1046 "RemoteHandlesDeletionTimeout",
1047 3000,
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)");
1051 defineOptionalProperty<bool>("StartDebuggerOnCrash",
1052 false,
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.");
1058 "LoadLibraries",
1059 "",
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",
1064 0,
1065 "The startup will be delayed by this number of seconds (useful for debugging)");
1066}
#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:179
#define ARMARX_FATAL_S
The logging level for unexpected behaviour, that will lead to a seriously malfunctioning program and ...
Definition Logging.h:217
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:188
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:194
#define ARMARX_INFO_S
Definition Logging.h:200
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:182
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:185
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:211
#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:75