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
152 /*
153 const char* envEditor = std::getenv("ARMARX_DEBUGGER");
154
155 const std::string editorName = [&]() -> std::string
156 {
157 if (envEditor == nullptr)
158 {
159 return DEFAULT_EDITOR;
160 }
161
162 const std::string editor = std::string(envEditor);
163 if (editors.count(editor) > 0)
164 {
165 return editor;
166 }
167
168 ARMARX_WARNING << "The editor '" << editor << "' is not registered. "
169 << "Check the config '" << EDITORFILEOPENER_CONFIGFILE << "'";
170
171 return DEFAULT_EDITOR;
172 }();
173
174 */
175
176
177 // res = system("which qtcreator");
178 // res = WEXITSTATUS(res);
179 // if (res == EXIT_SUCCESS)
180 {
181 s << "qtcreator -debug " << getpid();
182 ARMARX_IMPORTANT << s.str();
183 res = system(s.str().c_str());
184 res++; // suppress warning
185 }
186 // else
187 // {
188 // ARMARX_INFO_S << "Could not find qtcreator";
189 // }
190 }
191 }
192 catch (...)
193 {
194 // do nothing
195 }
196 exit(EXIT_FAILURE);
197}
198
199void
200Application::loadLibrariesFromProperties()
201{
202 auto loadLibString = getProperty<std::string>("LoadLibraries").getValue();
203 if (!loadLibString.empty())
204 {
205 if (!libLoadingEnabled)
206 {
207 throw LocalException("Loading of dynamic libraries is not enabled in this application. "
208 "The Application needs to call enableLibLoading()");
209 }
210 auto entries = armarx::Split(loadLibString, ";", true, true);
211 for (auto& entry : entries)
212 {
213 try
214 {
215 std::filesystem::path path;
216 if (armarx::Contains(entry, "/"))
217 {
218 path = entry;
219 }
220 else
221 {
222 auto elements = Split(entry, ":");
223 ARMARX_CHECK_EQUAL(elements.size(), 2);
224
225 CMakePackageFinder p(elements.at(0));
226
227 // case entry ^= `package_name`::`package_name`_`lib_name`
228 {
229 std::string libFileName = "lib" + elements.at(1) + "." +
231 for (auto& libDir : armarx::Split(p.getLibraryPaths(), ";"))
232 {
233 std::filesystem::path testPath(libDir);
234 testPath /= libFileName;
235 if (std::filesystem::exists(testPath))
236 {
237 path = testPath;
238 break;
239 }
240 }
241 }
242 // case entry ^= `package_name`::`lib_name`
243 {
244 // the filename is known to be "lib`package_name`_`lib_name`.so"
245 std::string libFileName = "lib" + elements.at(0) + "_" + elements.at(1) +
246 "." +
248 for (auto& libDir : armarx::Split(p.getLibraryPaths(), ";"))
249 {
250 std::filesystem::path testPath(libDir);
251 testPath /= libFileName;
252 if (std::filesystem::exists(testPath))
253 {
254 path = testPath;
255 break;
256 }
257 }
258 }
259
260 if (path.empty())
261 {
262 ARMARX_ERROR << "Could find library '" << entry
263 << "' in any of the following paths: " << p.getLibraryPaths();
264 continue;
265 }
266 }
267 ARMARX_CHECK_EXPRESSION(!path.empty());
268 DynamicLibrary lib;
269 lib.setUnloadOnDestruct(false);
270 ARMARX_VERBOSE << "Loading library " << path.string();
271 lib.load(path);
272 }
273 catch (...)
274 {
276 }
277 }
278 }
279}
280
281bool
283{
284 return forbidThreadCreation;
285}
286
287void
289{
290 forbidThreadCreation = value;
291 if (forbidThreadCreation)
292 {
293 ARMARX_INFO << "Thread creation with RunningTask and PeriodicTask is now forbidden in this "
294 "process.";
295 }
296 else
297 {
298 ARMARX_INFO << "Thread creation with RunningTask and PeriodicTask is now allowed again in "
299 "this process.";
300 }
301}
302
303void
305{
306 this->libLoadingEnabled = enable;
307}
308
309void
311{
312 ARMARX_CHECK_EXPRESSION(commandLineArguments.empty())
313 << "Command line arguments were already set: " << VAROUT(commandLineArguments);
314 commandLineArguments.reserve(argc);
315 for (int i = 0; i < argc; ++i)
316 {
317 commandLineArguments.emplace_back(argv[i]);
318 }
319}
320
321const std::vector<std::string>&
323{
324 return commandLineArguments;
325}
326
327void
329{
331 {
332 Application::getInstance()->interruptCallback(sig);
333 }
334}
335
336// main entry point of Ice::Application
338{
339}
340
343{
344 std::unique_lock lock(instanceMutex);
345
346 return instance;
347}
348
349void
351{
352 std::unique_lock lock(instanceMutex);
353
354 instance = inst;
355}
356
357void
359{
360 // call base class method
362 // set the properties of all components
363 if (armarXManager)
364 {
365 armarXManager->setComponentIceProperties(properties);
366 }
367}
368
369void
370Application::updateIceProperties(const Ice::PropertyDict& properties)
371{
372 // call base class method
374 // update the properties of all components
375 if (armarXManager)
376 {
377 armarXManager->updateComponentIceProperties(properties);
378 }
379}
380
381void
382Application::icePropertiesUpdated(const std::set<std::string>& changedProperties)
383{
384 if (armarXManager)
385 {
386 if (changedProperties.count("DisableLogging") &&
387 getProperty<bool>("DisableLogging").isSet())
388 {
389 // ARMARX_INFO << "Logging disabled: " << getProperty<bool>("DisableLogging").getValue();
390 armarXManager->enableLogging(!getProperty<bool>("DisableLogging").getValue());
391 }
392
393 if (changedProperties.count("EnableProfiling"))
394 {
395 armarXManager->enableProfiling(getProperty<bool>("EnableProfiling").getValue());
396 }
397 if (changedProperties.count("Verbosity"))
398 {
399 armarXManager->setGlobalMinimumLoggingLevel(
400 getProperty<MessageTypeT>("Verbosity").getValue());
401 }
402 }
403}
404
405const ThreadPoolPtr&
407{
408 return threadPool;
409}
410
411int
412Application::run(int argc, char* argv[])
413{
414#ifndef WIN32
415 // register signal handler
416 signal(SIGILL, Application::HandlerFault);
417 signal(SIGSEGV, Application::HandlerFault);
418 signal(SIGABRT, Application::HandlerFault);
419
420 signal(SIGHUP, Application::HandlerInterrupt);
421 signal(SIGINT, Application::HandlerInterrupt);
422 signal(SIGTERM, Application::HandlerInterrupt);
423#endif
424
426
427 // parse options and merge these with properties passed via Ice.Config
428 Ice::PropertiesPtr properties = parseOptionsMergeProperties(argc, argv);
429
430 // parse help options
432
434 ApplicationOptions::parseHelpOptions(properties, argc, argv);
435
436 if (options.error)
437 {
438 // error in options
439 return EXIT_FAILURE;
440 }
441 else if (options.showHelp) // display help
442 {
443 showHelp(options);
444 return EXIT_SUCCESS;
445 }
446 else if (options.showVersion)
447 {
448 std::cout << "Version: " << GetVersion() << std::endl;
449 return EXIT_SUCCESS;
450 }
451
453
454 setIceProperties(properties);
455
456 // Override environment variables if set.
457 {
459
460 const Ice::PropertyDict& env_props =
461 getPropertyDefinitions()->getProperties()->getPropertiesForPrefix("env");
462
463 for (const auto& [name, value] : env_props)
464 {
465 const std::string short_name = name.substr(4); // Cut "env.".
466
467 const auto envVarResolved = armarx::core::system::EnvExpander::expandVariables(value);
468
469 ARMARX_INFO << "Setting environment variable '" << short_name << "' to value '" << envVarResolved
470 << "'.";
471 setenv(short_name.c_str(), envVarResolved.c_str(), 1);
472 }
473 }
474
475 if (getProperty<std::uint64_t>("SecondsStartupDelay").isSet())
476 {
477 const auto delay = getProperty<std::uint64_t>("SecondsStartupDelay").getValue();
478 ARMARX_INFO << "startup delay: " << delay << " seconds";
479 std::this_thread::sleep_for(std::chrono::seconds{delay});
480 }
481 else
482 {
483 ARMARX_DEBUG << "startup delay is not set";
484 }
485
486 // extract application name
487 if (getProperty<std::string>("ApplicationName").isSet())
488 {
489 applicationName = getProperty<std::string>("ApplicationName").getValue();
490 }
491 LogSender::SetLoggingGroup(getProperty<std::string>("LoggingGroup").getValue());
492
493 // Redirect std::cout and std::cerr
494 const bool redirectStdout = getProperty<bool>("RedirectStdout").getValue();
495 ArmarXLogBuf buf("std::cout", MessageTypeT::INFO, false);
496 ArmarXLogBuf errbuf("std::cerr", MessageTypeT::WARN, true);
497 std::streambuf* cout_sbuf = nullptr;
498 std::streambuf* cerr_sbuf = nullptr;
499 if (redirectStdout)
500 {
501 cout_sbuf = std::cout.rdbuf();
502 cerr_sbuf = std::cerr.rdbuf();
503 std::cout.rdbuf(&buf);
504 std::cerr.rdbuf(&errbuf);
505 }
507 {
508 //reset std::cout and std::cerr to original stream
509 if (redirectStdout)
510 {
511 std::cout.rdbuf(cout_sbuf);
512 std::cerr.rdbuf(cerr_sbuf);
513 }
514 };
515
516 int result = EXIT_SUCCESS;
517
518 threadPool.reset(new ThreadPool(getProperty<unsigned int>("ThreadPoolSize").getValue()));
519 // create the ArmarXManager and set its properties
520 try
521 {
522 armarXManager = new ArmarXManager(applicationName, communicator());
523 }
524 catch (Ice::ConnectFailedException&)
525 {
526 return EXIT_FAILURE;
527 }
528
529 armarXManager->setDataPaths(getProperty<std::string>("DataPath").getValue());
530
531 // set the properties again, since the armarx manager is now available
532 setIceProperties(properties);
533
535
536#ifdef WIN32
537 // register interrupt handler
538 callbackOnInterrupt();
539#endif
540
541
542 if (applicationNetworkStats)
543 {
544 ProfilerListenerPrx profilerTopic =
545 armarXManager->getIceManager()->getTopic<ProfilerListenerPrx>(
546 armarx::Profiler::PROFILER_TOPIC_NAME);
547 applicationNetworkStats->start(profilerTopic, applicationName);
548 }
549
550 loadLibrariesFromProperties();
551
552 try
553 {
554 // calls virtual setup in order to allow subclass to add components to the application
555 setup(armarXManager, properties);
556 }
557 catch (...)
558 {
560 armarXManager->shutdown();
561 }
562
563 // calls exec implementation
564 result = exec(armarXManager);
566
567 if (shutdownThread)
568 {
569 ARMARX_VERBOSE << "joining shutdown thread!";
570 shutdownThread->join();
571 }
572 ARMARX_VERBOSE << "Application run finished";
573 return result;
574}
575
576/*
577 * the default exec implementation. Exec is always blocking and waits for
578 * shutdown
579 */
580int
582{
583 armarXManager->waitForShutdown();
584
585 return 0;
586}
587
590{
591 // parse options and merge these with properties passed via Ice.Config
592 // Here, use armarx::IceProperties instead of Ice::Properties
593 // to support property inheritance.
595 ApplicationOptions::mergeProperties(communicator()->getProperties()->clone(), argc, argv));
596
597 // Load config files passed via ArmarX.Config
598 std::string configFiles = communicator()->getProperties()->getProperty("ArmarX.Config");
599
600 PropertyDefinition<std::string>::removeQuotes(configFiles, configFiles);
601
602 // if not set, size is zero
603 // if set with out value (== "1" as TRUE), size is one
604 if (!configFiles.empty() && configFiles.compare("1") != 0)
605 {
606 std::vector<std::string> configFileList = simox::alg::split(configFiles, ",");
607
608 for (std::string configFile : configFileList)
609 {
610 if (!configFile.empty())
611 {
612 properties->load(configFile);
613 }
614 }
615 }
616 return properties;
617}
618
619void
621{
622 // perform dummy setup to register ManagedIceObjects
623 ArmarXDummyManagerPtr dummyManager = new ArmarXDummyManager();
624
625 LogSender::SetLoggingActivated(false, false);
626
627 setup(dummyManager, getIceProperties());
628
629 if (options.outfile.empty())
630 {
631 ApplicationOptions::showHelp(this, dummyManager, options, nullptr);
632 }
633 else
634 {
635 std::ofstream out(options.outfile);
636 if (out.is_open())
637 {
638 ApplicationOptions::showHelp(this, dummyManager, options, nullptr, out);
639 }
640 else
641 {
643 ApplicationOptions::showHelp(this, dummyManager, options, nullptr);
644
645 std::cout << "Could not write to file " << options.outfile << std::endl;
646 }
647 }
648}
649
650std::string
652{
653 return "ArmarX";
654}
655
656void
657Application::setName(const std::string& name)
658{
659 this->applicationName = name;
660}
661
662std::string
664{
665 return applicationName;
666}
667
668void
670{
671 ARMARX_INFO_S << "Interrupt received: " << signal;
672 if (applicationNetworkStats)
673 {
674 applicationNetworkStats->stopTask();
675 }
676 if (!shutdownThread)
677 shutdownThread.reset(new std::thread{[this]
678 {
679 if (armarXManager)
680 this->armarXManager->shutdown();
681 }});
682}
683
684void
686{
687 IceUtil::Time start = IceUtil::Time::now();
688 ARMARX_INFO_S << "Deps: " << dependencies;
689 dependencies = simox::alg::replace_all(dependencies, "\"", "");
690 Ice::StringSeq resultList = simox::alg::split(dependencies, "/");
691
692 for (size_t i = 0; i < resultList.size(); i++)
693 {
694 CMakePackageFinder pack(resultList[i]);
695
696 if (pack.packageFound())
697 {
699 }
700 }
701
702 ARMARX_INFO_S << "loading took " << (IceUtil::Time::now() - start).toMilliSeconds();
703}
704
705bool
707{
708 const std::string autodiscoverPropertyName = "AutodiscoverPackages";
709
710 if (hasProperty(autodiscoverPropertyName))
711 {
712 ARMARX_VERBOSE << "`" << autodiscoverPropertyName << "` property available.";
713 return getProperty<bool>(autodiscoverPropertyName).getValue();
714 }
715
716 return true; // Property not available. Default: use autodiscovery
717}
718
719std::vector<std::string>
721{
723 {
724 ARMARX_VERBOSE << "ArmarX package autodiscovery activated.";
726 }
727
728 ARMARX_VERBOSE << "ArmarX package autodiscovery not activated.";
729
730 // legacy: use only those packages listed in the config file (e.g. default.cfg)
731 Ice::StringSeq result = getProperty<Ice::StringSeq>("DefaultPackages").getValue();
732 Ice::StringSeq additional = getProperty<Ice::StringSeq>("AdditionalPackages").getValue();
733 result.insert(result.end(), additional.begin(), additional.end());
734
735 return result;
736}
737
738std::string
740{
741 char* env_armarx_workspace = getenv("ARMARX_WORKSPACE");
742 char* env_armarx_default_config_dir_name = getenv("ARMARX_CONFIG_DIR_NAME");
743
744 std::filesystem::path armarx_workspace;
745 std::filesystem::path armarx_config_dir;
746
747 if (env_armarx_workspace)
748 {
749 armarx_workspace = std::filesystem::path(env_armarx_workspace);
750 }
751 else
752 {
753 char* home = getenv("HOME");
754
755 if (home)
756 {
757 armarx_workspace = std::filesystem::path(home);
758 }
759 else
760 {
761 armarx_workspace = "~/";
762 }
763 }
764
765 if (env_armarx_default_config_dir_name)
766 {
767 armarx_config_dir = std::filesystem::path(env_armarx_default_config_dir_name);
768 }
769 else
770 {
771 if (env_armarx_workspace)
772 {
773 armarx_config_dir = "armarx_config";
774 }
775 // Legacy mode.
776 else
777 {
778 armarx_config_dir = ".armarx";
779 }
780 }
781
782 if (envVarExpanded)
783 {
784 return (armarx_workspace / armarx_config_dir).string();
785 }
786 else
787 {
788 if (env_armarx_workspace)
789 {
790 return "${ARMARX_WORKSPACE}/" + armarx_config_dir.string();
791 }
792 // Legacy mode.
793 else
794 {
795 return "${HOME}/" + armarx_config_dir.string();
796 }
797 }
798}
799
802{
803 return armarXManager;
804}
805
806int
807Application::doMain(int argc, char* argv[], const Ice::InitializationData& initData, Ice::Int i)
808{
809 // create copy of initData so the stats object can be added
810 // using const_cast leads to unexpected errors
811 Ice::InitializationData id(initData);
812 loadDefaultConfig(argc, argv, id);
813
814 // enable the PropertyAdmin ObjectAdapter
815 // https://doc.zeroc.com/display/Ice35/The+Administrative+Object+Adapter
816 if (id.properties->getProperty("Ice.Admin.InstanceName").empty())
817 {
818 id.properties->setProperty("Ice.Admin.InstanceName", this->getName());
819 }
820 if (id.properties->getProperty("Ice.Admin.Endpoints").empty())
821 {
822 id.properties->setProperty("Ice.Admin.Endpoints", "tcp -h 127.0.0.1");
823 }
824
825 if (initData.properties->getProperty("ArmarX.NetworkStats") == "1")
826 {
827 applicationNetworkStats = new ApplicationNetworkStats();
828 id.observer = applicationNetworkStats;
829
830 const auto oldFacets = initData.properties->getPropertyAsList("Ice.Admin.Facets");
831 if (oldFacets.empty())
832 {
833 initData.properties->setProperty("Ice.Admin.Facets", "Metrics");
834 }
835 else if (std::find(oldFacets.begin(), oldFacets.end(), "Metrics") == oldFacets.end())
836 {
837 std::stringstream str;
838 str << "Metrics";
839 for (const auto& facet : oldFacets)
840 {
841 str << "," << facet;
842 }
843 initData.properties->setProperty("Ice.Admin.Facets", str.str());
844 }
845 initData.properties->setProperty("IceMX.Metrics.NetworkStats.GroupBy", "none");
846 }
847
848 return Ice::Application::doMain(argc, argv, id, i);
849}
850
851Ice::StringSeq
853{
854 const std::string configFileName = "default.cfg";
855 const std::string generatedConfigFileName = "default.generated.cfg";
856 Ice::StringSeq defaultsPaths;
857 char* defaultsPathVar = getenv(ArmarXUserConfigDirEnvVar.c_str());
858 std::filesystem::path absBasePath;
859 if (defaultsPathVar)
860 {
861 absBasePath = defaultsPathVar;
862 }
863 else
864 {
865 absBasePath = std::filesystem::path(GetArmarXConfigDefaultPath());
866 }
867 defaultsPaths.push_back((absBasePath / configFileName).string());
868 defaultsPaths.push_back((absBasePath / generatedConfigFileName).string());
869 return defaultsPaths;
870}
871
872void
873Application::loadDefaultConfig(int argc, char* argv[], const Ice::InitializationData& initData)
874{
875 LoadDefaultConfig(initData.properties);
876}
877
878void
880{
881 const Ice::StringSeq defaultsPath = GetDefaultsPaths();
883
884 for (std::string path : defaultsPath)
885 {
886 try
887 {
888 p->load(path);
889
890 Ice::PropertyDict defaultCfg = p->getPropertiesForPrefix("");
891
892 // copy default config into current config (if values are not already there)
893 for (auto e : defaultCfg)
894 {
895 if (properties->getProperty(e.first).empty())
896 {
897 properties->setProperty(e.first, e.second);
898 }
899 }
900 }
901 catch (Ice::FileException& e)
902 {
903 ARMARX_WARNING_S << "Loading default config failed: " << e.what();
904 }
905 }
906}
907
908const std::string&
910{
911 return ProjectName;
912}
913
914const Ice::StringSeq&
916{
917 return ProjectDependendencies;
918}
919
925
926void
928{
929 std::string dependenciesConfig = getIceProperties()->getProperty("ArmarX.DependenciesConfig");
930
931 if (!dependenciesConfig.empty())
932 {
933 if (std::filesystem::exists(dependenciesConfig))
934 {
936 prop->load(dependenciesConfig);
937 ArmarXDataPath::addDataPaths(prop->getProperty("ArmarX.ProjectDatapath"));
938 ProjectName = prop->getProperty("ArmarX.ProjectName");
939 std::string dependencies = prop->getProperty("ArmarX.ProjectDependencies");
940 ProjectDependendencies = simox::alg::split(dependencies, ";");
941 }
942 else
943 {
944 /*
945 ARMARX_WARNING_S << "The given project datapath config file '" << datapathConfig << "', that this app depends on, could not be found. \
946 Relative paths to subprojects are not available. Set the property ArmarX.ProjectDatapath to empty, if you do not need the paths.";
947 */
948 }
949 }
950}
951
954{
956 "Config", "", "Comma-separated list of configuration files ");
958 "DependenciesConfig",
959 "./config/dependencies.cfg",
960 "Path to the (usually generated) config file containing all data paths of all dependent "
961 "projects. This property usually does not need to be edited.");
963 "DefaultPackages",
964 {"ArmarXCore",
965 "ArmarXGui",
966 "MemoryX",
967 "RobotAPI",
968 "RobotComponents",
969 "RobotSkillTemplates",
970 "ArmarXSimulation",
971 "VisionX",
972 "SpeechX",
973 "Armar3",
974 "Spoac"},
975 "List of ArmarX packages which are accessible by default. Comma separated List. If you "
976 "want to add your own packages and use all default ArmarX packages, use the property "
977 "'AdditionalPackages'.");
979 "AdditionalPackages",
980 {},
981 "List of additional ArmarX packages which should be in the list of default packages. If "
982 "you have custom packages, which should be found by the gui or other apps, specify them "
983 "here. Comma separated List.");
984
986 "AutodiscoverPackages",
987 true,
988 "If enabled, will discover all ArmarX packages based on the environment variables. "
989 "Otherwise, the `DefaultPackages` and `AdditionalPackages` properties are used.");
990
991 defineOptionalProperty<std::string>("ApplicationName", "", "Application name");
992
993 defineOptionalProperty<bool>("DisableLogging",
994 false,
995 "Turn logging off in whole application",
997
1000 "Global logging level for whole application",
1002
1004 "LoggingGroup",
1005 "",
1006 "The logging group is transmitted with every ArmarX log message over Ice in order to group "
1007 "the message in the GUI.");
1008
1009
1011 "DataPath", "", "Semicolon-separated search list for data files");
1012
1014 "CachePath",
1015 "mongo/.cache",
1016 std::string("Path for cache files. If relative path AND env. variable ") +
1018 " is set, the cache path will be made relative to " +
1020 ". Otherwise if relative it will be relative to the default ArmarX config dir (" +
1022
1023 defineOptionalProperty<bool>("EnableProfiling",
1024 false,
1025 "Enable profiling of CPU load produced by this application",
1027
1029 "RedirectStdout", true, "Redirect std::cout and std::cerr to ArmarXLog");
1030
1032 "TopicSuffix",
1033 "",
1034 "Suffix appended to all topic names for outgoing topics. This is mainly used to direct all "
1035 "topics to another name for TopicReplaying purposes.");
1036
1038 "UseTimeServer", false, "Enable using a global Timeserver (e.g. from ArmarXSimulator)");
1039
1041 "RemoteHandlesDeletionTimeout",
1042 3000,
1043 "The timeout (in ms) before a remote handle deletes the managed object after the use count "
1044 "reached 0. This time can be used by a client to increment the count again (may be "
1045 "required when transmitting remote handles)");
1046 defineOptionalProperty<bool>("StartDebuggerOnCrash",
1047 false,
1048 "If this application crashes (segmentation fault) qtcreator will "
1049 "attach to this process and start the debugger.");
1051 "ThreadPoolSize", 1, "Size of the ArmarX ThreadPool that is always running.");
1053 "LoadLibraries",
1054 "",
1055 "Libraries to load at start up of the application. Must be enabled by the Application with "
1056 "enableLibLoading(). Format: PackageName:LibraryName;... or /absolute/path/to/library;...");
1058 "SecondsStartupDelay",
1059 0,
1060 "The startup will be delayed by this number of seconds (useful for debugging)");
1061}
#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