Application.h
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* @date 2010
23* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
24* GNU General Public License
25*/
26
27#pragma once
28
29#include <mutex>
30#include <string> // for string
31#include <vector> // for vector
32
33#include <Ice/Application.h> // for Application
34#include <Ice/BuiltinSequences.h> // for StringSeq
35#include <Ice/PropertiesF.h> // for PropertiesPtr
36#include <IceUtil/Handle.h> // for Handle, HandleBase
37
38#include "ArmarXCore/core/ArmarXFwd.h" // for ArmarXManagerPtr
41#include "ArmarXCore/core/exceptions/Exception.h" // for LocalException
42
43#include "../ArmarXManager.h"
44#include "../Component.h" // for Component
45#include "../logging/Logging.h"
47#include "../system/ImportExport.h" // for ARMARXCORE_IMPORT_EXPORT
49#include "ApplicationNetworkStats.h" // for ApplicationNetworkStatsPtr
50#include "ApplicationOptions.h"
51#include "properties/PropertyUser.h" // for PropertyDefinitionsPtr, etc
52
53namespace Ice
54{
55 struct InitializationData;
56} // namespace Ice
57
58#define xstr(s) stringify(s)
59#define stringify(s) #s
60
61/**
62 \defgroup Application ArmarX Application
63 \ingroup DistributedProcessingGrp
64 */
65
66namespace std
67{
68 class thread;
69}
70
71namespace armarx
72{
73 // forward declarations
74 class ManagedIceObjectRegistryInterface;
75 class ThreadPool;
76 using ThreadPoolPtr = std::shared_ptr<ThreadPool>;
79
80 /**
81 * \typedef ManagedIceObjectRegistryInterfacePtr shared pointer for armarx::ManagedIceObjectRegistryInterface
82 */
84
85 /**
86 * armarx::Application smart pointer
87 */
88 class Application;
89
90 /**
91 * \typedef ApplicationPtr shared pointer for armarx::Application
92 */
94
95 /**
96 \class ApplicationPropertyDefinitions
97 \brief Application property definition container.
98 \ingroup Application
99 \see properties
100 */
103 {
104 public:
105 /**
106 * @see armarx::PropertyDefinitionContainer::PropertyDefinitionContainer()
107 */
109 };
110
111 /**
112 \class Application
113 \brief Baseclass for all ArmarX applications.
114 \ingroup Application
115
116 \li helper class for ArmarX main programs
117 \li creates an instance of ArmarXManager
118 \li generates properties from commandline parameters
119 \li provides help and automatic generation of properties
120
121 Implements the run method from the Ice::Application interface
122 which is called by the automatically generated main.cpp.
123 In order to start writing an ArmarX application, inherit from armarx::Application
124 and implement the setup method to setup and add the required ManagedIceObjects.
125
126 \code
127 class ExampleApp :
128 virtual public armarx::Application
129 {
130 void setup(const ManagedIceObjectRegistryInterfacePtr& registry,
131 Ice::PropertiesPtr properties)
132 {
133 registry->addObject(Component::create<Example>(properties));
134 };
135 }
136 \endcode
137
138 The application automatically loads a default config file
139 (usually ~/.armarx/default.cfg), which is needed to connect to IceGrid etc.
140 This function is also available as a static version: LoadDefaultConfig()
141
142 If you only want to use one component (as above), you can use \ref armarx::runSimpleComponentApp.
143 In this case, your main function would look like this:
144
145 \code
146 int main(int argc, char* argv[])
147 {
148 return armarx::runSimpleComponentApp<ExampleComponent, ApplicationType>(argc, argv, "ExampleAppName", "ExampleComponentConfigName", "ExampleComponentDomain");
149 }
150 \endcode
151
152 If you are using the defaults for ApplicationType (\ref armarx::Application)
153 ExampleComponentConfigName (\ref armarx::Component::getDefaultName()) and
154 ExampleComponentDomain ("ArmarX"), your main function looks like this:
155
156 \code
157 int main(int argc, char* argv[])
158 {
159 return armarx::runSimpleComponentApp<ExampleComponent>(argc, argv, "ExampleAppName");
160 }
161 \endcode
162
163 Application specific configuration files can be passed to the application
164 by using the Ice.Config commandline parameter.
165 The used configuration file format is those of regular Ice configuration files.
166
167 Each entry in Ice configuration files is prefixed with a "DomainName"
168 which is "ArmarX" by default.
169 This "DomainName" can be changed by overriding armarx::Application::getDomainName()
170 to return a different string.
171
172 Sometimes it is not possible to pass configuration files via the Ice.Config parameter
173 (e.g. when using IceGrid XML deployment files where this paramter is overriden by IceGrid).
174 In this case, the commandline parameter ArmarX.Config can be used.
175 All files specified in this parameter will be merged into the standard properties
176 available inside the armarx::Application.
177
178 Special properties:
179
180 \li ArmarX.Config
181 \li ArmarX.NetworkStats: set to "1" to enable logging of network statistics (use armarx::ProfilerObserver to collect the data)
182 \li ArmarX.DependenciesConfig
183 \li ArmarX.ProjectDatapath
184 \li ArmarX.ProjectName
185 \li ArmarX.ProjectDependencies
186 \li <DomainName>.DisableLogging
187 \li <DomainName>.Verbosity
188 \li <DomainName>.DataPath
189
190 Internally, an armarx::Application contains an armarx::ArmarXManger which is responsible
191 for managing they lifecycle of all components inside an application.
192 */
193 class ARMARXCORE_IMPORT_EXPORT Application : public Ice::Application, public PropertyUser
194 {
195 public:
196 /**
197 * @brief Application initalizes the Ice::Application base class.
198 */
199 Application();
200
201 /**
202 * Creates the one application instance of type T. T is usually the
203 * type of a sublass as defined in a specific component. This method is
204 * called from the automatically generated main.cpp.
205 *
206 * @return shared pointer to the application
207 */
208 template <class T, typename... Args>
209 static ApplicationPtr
210 createInstance(Args&&... args)
211 {
212 std::unique_lock lock(instanceMutex);
213
214 if (instance)
215 {
216 throw LocalException("Application instance already created");
217 }
218
219 instance = ApplicationPtr(new T(std::forward<Args>(args)...));
220
221 return instance;
222 }
223
224 /**
225 * Retrieve shared pointer to the application object. Use this in order
226 * to access is called from the automatically generated main.cpp.
227 *
228 * @return shared pointer to the application
229 */
230 static ApplicationPtr getInstance();
231
232 static void setInstance(ApplicationPtr const& inst);
233
234 static std::string
236 {
237#ifdef ARMARX_VERSION
238 return xstr(ARMARX_VERSION);
239#else
240 return "undefined";
241#endif
242 }
243
244 /**
245 * Ice::Application replacement for the main function.
246 */
247 int run(int argc, char* argv[]) override;
248
249 /**
250 * Set name of the application. Called from main.cpp.
251 * This method has an effect only if it is called before Application::main()
252 *
253 * @param application name
254 */
255 void setName(const std::string& name);
256
257 /**
258 * Retrieve name of the application
259 *
260 * @return application name
261 */
262 std::string getName() const;
263
264 /**
265 * Cleans up connections with IceStorm before terminating the app
266 *
267 * @param signal The signal send to the application
268 */
269 void interruptCallback(int signal) override;
270
271 void registerDataPathsFromDependencies(std::string dependencies);
272
273 /**
274 * @brief getDefaultPackageNames returns the value of the ArmarX.DefaultPackages property
275 * It splits the string by , and returns the elements as a vector.
276 * @return
277 */
278 std::vector<std::string> getArmarXPackageNames();
279
280 bool isPackageAutoDiscoveryEnabled();
281
282 static std::string GetArmarXConfigDefaultPath(bool envVarExpanded = true);
283 static Ice::StringSeq GetDefaultsPaths();
284 static void LoadDefaultConfig(Ice::PropertiesPtr properties);
285 static const std::string& GetProjectName();
286 static const Ice::StringSeq& GetProjectDependencies();
287
288 /**
289 * Overrides PropertyUser::setIceProperties() which is called internally.
290 * Additionally it calls Component::updateIceProperties().
291 */
292 void setIceProperties(Ice::PropertiesPtr properties) override;
293
294 void updateIceProperties(const Ice::PropertyDict& properties) override;
295
296 void icePropertiesUpdated(const std::set<std::string>& changedProperties) override;
297 static const std::string ArmarXUserConfigDirEnvVar;
298
299 const ThreadPoolPtr& getThreadPool() const;
300 bool getForbidThreadCreation() const;
301 void setForbidThreadCreation(bool value);
302 void enableLibLoading(bool enable = true);
303
304 void storeCommandLineArguments(int argc, char* argv[]);
305 const std::vector<std::string>& getCommandLineArguments() const;
306
307 protected:
308 /**
309 * @see PropertyUser::createPropertyDefinitions()
310 */
312
313 /**
314 * Setup method to be implemented by user applications
315 *
316 * Use this method to add all required ManagedIceObject to the application
317 * @see void ManagedIceObjectRegistryInterfacePtr::addObject(ManagedIceObjectPtr object)
318 */
319 virtual void setup(const ManagedIceObjectRegistryInterfacePtr& registry,
320 Ice::PropertiesPtr properties) = 0;
321
322 /**
323 * Exec method is the main process of the application. The default
324 * implementation only calls
325 *
326 * <code>
327 * armarXManager->waitForShutdown();
328 * </code>
329 *
330 * If you need to do something in the main process (e.g. processing QT
331 * guis) overwrite this method.
332 *
333 * @return program exit status
334 */
335 virtual int exec(const ArmarXManagerPtr& armarXManager);
336
337 /**
338 * @brief Ice::Application::doMain() is called by Ice::Application::main() and does setup of Ice::Communicator before calling the virtual Ice::Application::run() method
339 * @param argc
340 * @param argv
341 * @param initData
342 * @return
343 */
344 int doMain(int argc,
345 char* argv[],
346 const Ice::InitializationData& initData,
347 Ice::Int i) override;
348
349 void loadDefaultConfig(int argc, char* argv[], const Ice::InitializationData& initData);
350
352
353 /**
354 * Retrieve the domain name used for property parsing. Overwrite this in your subclass in order to
355 * use another domain name then "ArmarX".
356 * The domain name is the first part of the property identifier where each part is separated via a "." (e.g. ArmarX.some.property).
357 *
358 * @return domain name. Defaults to "ArmarX".
359 */
360 virtual std::string getDomainName();
361
362 /**
363 * @return an instance of armarx::ArmarXManagerPtr
364 */
366
367
368 /**
369 * Print help onto the screen or into a file
370 */
372
373 /**
374 * Parse options given on the commandline and merge them into the regular properties
375 */
376 Ice::PropertiesPtr parseOptionsMergeProperties(int argc, char* argv[]);
377
378
379 /**
380 * @brief handlerInterrupt handles interrupt signals sent to the application (Linux)
381 * @param sig
382 */
383 static void HandlerInterrupt(int sig);
384
385
386 /**
387 * @brief handlerFault handles signals sendt to the application such as SIGSEGF or SIGABRT (Linux)
388 * @param sig
389 */
390 static void HandlerFault(int sig);
391
392 private:
393 void loadLibrariesFromProperties();
394
395 /**
396 * Application singleton instance
397 */
398 static ApplicationPtr instance;
399
400 /**
401 * Application instance instantiation and access mutex
402 */
403 static std::mutex instanceMutex;
404
405 /**
406 * Application instance name
407 */
408 std::string applicationName;
409
410 /**
411 * the ArmarXManager
412 */
413 ArmarXManagerPtr armarXManager;
414
415 ApplicationNetworkStatsPtr applicationNetworkStats;
416
417 std::shared_ptr<std::thread> shutdownThread;
418
419 static std::string ProjectName;
420 static Ice::StringSeq ProjectDependendencies;
421
422 ThreadPoolPtr threadPool;
423 bool forbidThreadCreation = false;
424 bool libLoadingEnabled = false;
425
426 std::vector<std::string> commandLineArguments;
427 };
428
430 {
431 // Application interface
432 protected:
433 void
435 Ice::PropertiesPtr properties) override
436 {
437 }
438 };
439} // namespace armarx
440
442{
443 template <class ComponentT, class AppT>
444 /**
445 * @see runSimpleComponentApp<ComponentT, AppT>.
446 * @brief Used by runSimpleComponentApp<ComponentT, AppT>.
447 * This class can't be defined in function, since this causes problems with gcc and c++03
448 */
449 class SimpleSingleComponentApp : virtual public AppT
450 {
451 void
452 setup(const ManagedIceObjectRegistryInterfacePtr& registry,
453 Ice::PropertiesPtr properties) override
454 {
455 registry->addObject(Component::create<ComponentT>(properties, "", appConfigDomain));
456 }
457
458 public:
459 std::string appConfigName;
460 std::string appConfigDomain;
461 };
462} // namespace armarx::internal
463
464namespace armarx
465{
466 /**
467 * @brief Creates and runs an application (of AppT) for the given component (ComponentT).
468 * @param argc CL parameter count
469 * @param argv CL parameters
470 * @param appName The application's name.
471 * @param configName The config name, passed to the create call.
472 * @param configDomain The config domain, passed to the create call.
473 * @return The application's return code (app->main(argc, argv))
474 *
475 * For a component COMP the following application is created
476 * \code{.cpp}
477 * class SimpleSingleComponentApp : virtual public Application
478 * {
479 * void setup(const ManagedIceObjectRegistryInterfacePtr& registry, Ice::PropertiesPtr properties)
480 * {
481 * registry->addObject(Component::create<COMP>(properties));
482 * }
483 * };
484 * \endcode
485 * Following code is executed
486 * \code{.cpp}
487 * armarx::ApplicationPtr app = armarx::Application::createInstance<SimpleSingleComponentApp>() ;
488 * app->setName(appName);
489 * return app->main(argc, argv);
490 * \endcode
491 */
492 template <class ComponentT, class AppT = armarx::Application>
493 int
495 char* argv[],
496 std::string appName,
497 const std::string& configName = "",
498 const std::string& configDomain = "ArmarX",
499 bool enableLibLoading = false)
500 {
502 AppT::template createInstance<internal::SimpleSingleComponentApp<ComponentT, AppT>>();
503
504 auto sApp =
506 sApp->appConfigDomain = configDomain;
507 sApp->appConfigName = configName;
508 app->enableLibLoading(enableLibLoading);
509 app->setName(appName);
510 app->storeCommandLineArguments(argc, argv);
511 return app->main(argc, argv);
512 }
513
514 /**
515 * @brief Do not use! Use \ref armarx::runMultipleComponentsApp()
516 */
518 {
519 public:
520 MultipleComponentsApplication(std::vector<ComponentPtr> components) : components(components)
521 {
522 }
523
524 private:
525 std::vector<ComponentPtr> components;
526
527 // Application interface
528 protected:
529 void
531 Ice::PropertiesPtr properties) override
532 {
533 for (ComponentPtr comp : components)
534 {
535 registry->addObject(comp);
536 }
537 }
538 };
539
540 template <class ComponentType>
541 std::vector<ComponentPtr>
542 createComponents(ComponentType comp)
543 {
544 return {comp};
545 }
546
547 template <class ComponentType, class... ComponentTypes>
548 std::vector<ComponentPtr>
549 createComponents(ComponentType comp, ComponentTypes... components)
550 {
551 std::vector<ComponentPtr> result{comp};
552 std::vector<ComponentPtr> tempResult = createComponents(components...);
553 result.insert(result.end(), tempResult.begin(), tempResult.end());
554 return result;
555 }
556
557 template <class... ComponentTypes>
558 std::vector<ComponentPtr>
559 createComponentsUtil(ComponentTypes&&... components)
560 {
561 std::vector<ComponentPtr> result;
562 std::vector<ComponentPtr> tempResult = createComponents(components...);
563 result.insert(result.end(), tempResult.begin(), tempResult.end());
564 return result;
565 }
566
567 /**
568 * Convenience function to create an app with multiple components easily.
569 *
570 * Usage:
571 * \code{.cpp}
572 * main(int argc, char * argv[])
573 * {
574 * armarx::ApplicationPtr app;
575 * std::vector<ComponentPtr> components;
576 * std::tie(app, components) = runMultipleComponentsApp < ConditionHandler, SystemObserver, DebugObserver > (argc, argv, "ArmarXCoreApps");
577 * return app->main(argc, argv);
578 * }
579 * \endcode
580 *
581 * \return returns a tuple of the created Application and a vector of the created components. The order of the components is the same as the template parameter list.
582 */
583 template <class... ComponentTypes>
584 std::tuple<armarx::ApplicationPtr, std::vector<ComponentPtr>>
586 char* argv[],
587 std::string appName,
588 const std::string& configDomain = "ArmarX")
589 {
590 Ice::PropertiesPtr props = Ice::createProperties(argc, argv);
591 std::vector<ComponentPtr> comps =
592 createComponentsUtil(Component::create<ComponentTypes>(props, "", configDomain)...);
594
595 app->setName(appName);
596 return std::make_tuple(app, comps);
597 }
598
599} // namespace armarx
#define ARMARXCORE_IMPORT_EXPORT
The ApplicationNetworkStats class implements the Ice::Instrumentation::CommunicatorObserver interface...
ApplicationPropertyDefinitions(std::string prefix)
Baseclass for all ArmarX applications.
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 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 ...
const std::vector< std::string > & getCommandLineArguments() const
virtual std::string getDomainName()
Retrieve the domain name used for property parsing.
static void HandlerFault(int sig)
handlerFault handles signals sendt to the application such as SIGSEGF or SIGABRT (Linux)
void showHelp(ApplicationOptions::Options &options)
Print help onto the screen or into a file.
ArmarXManagerPtr getArmarXManager()
const ThreadPoolPtr & getThreadPool() const
static ApplicationPtr createInstance(Args &&... args)
Creates the one application instance of type T.
void loadDependentProjectDatapaths()
PropertyDefinitionsPtr createPropertyDefinitions() override
bool getForbidThreadCreation() const
void enableLibLoading(bool enable=true)
static const std::string ArmarXUserConfigDirEnvVar
virtual void setup(const ManagedIceObjectRegistryInterfacePtr &registry, Ice::PropertiesPtr properties)=0
Setup method to be implemented by user applications.
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.
Application()
Application initalizes the Ice::Application base class.
virtual int exec(const ArmarXManagerPtr &armarXManager)
Exec method is the main process of the application.
static std::string GetVersion()
static TPtr create(Ice::PropertiesPtr properties=Ice::createProperties(), const std::string &configName="", const std::string &configDomain="ArmarX")
Factory method for a component.
Definition Component.h:116
void setup(const ManagedIceObjectRegistryInterfacePtr &registry, Ice::PropertiesPtr properties) override
Setup method to be implemented by user applications.
MultipleComponentsApplication(std::vector< ComponentPtr > components)
void setup(const ManagedIceObjectRegistryInterfacePtr &registry, Ice::PropertiesPtr properties) override
Setup method to be implemented by user applications.
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
Used by runSimpleComponentApp<ComponentT, AppT>. This class can't be defined in function,...
#define xstr(s)
Definition Application.h:58
Ice::PropertiesPtr createProperties()
::IceInternal::Handle<::Ice::Properties > PropertiesPtr
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< ArmarXManager > ArmarXManagerPtr
IceUtil::Handle< ManagedIceObjectRegistryInterface > ManagedIceObjectRegistryInterfacePtr
Definition Application.h:83
::IceUtil::Handle< ApplicationNetworkStats > ApplicationNetworkStatsPtr
Definition Application.h:78
std::vector< ComponentPtr > createComponents(ComponentType comp)
std::vector< ComponentPtr > createComponentsUtil(ComponentTypes &&... components)
int runSimpleComponentApp(int argc, char *argv[], std::string appName, const std::string &configName="", const std::string &configDomain="ArmarX", bool enableLibLoading=false)
Creates and runs an application (of AppT) for the given component (ComponentT).
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.
std::tuple< armarx::ApplicationPtr, std::vector< ComponentPtr > > runMultipleComponentsApp(int argc, char *argv[], std::string appName, const std::string &configDomain="ArmarX")
Convenience function to create an app with multiple components easily.
IceInternal::Handle< Component > ComponentPtr
Component smart pointer type.
Definition ArmarXFwd.h:45
Stucture containing the parsed options of the application.