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 "../ArmarXManager.h"
30 #include "../Component.h" // for Component
31 #include "../logging/Logging.h"
32 #include "../system/ArmarXDataPath.h"
33 #include "../system/ImportExport.h" // for ARMARXCORE_IMPORT_EXPORT
34 #include "../system/cmake/CMakePackageFinder.h"
35 #include "ApplicationOptions.h"
36 #include "ApplicationNetworkStats.h" // for ApplicationNetworkStatsPtr
37 #include "ArmarXCore/core/ArmarXFwd.h" // for ArmarXManagerPtr
40 #include "ArmarXCore/core/exceptions/Exception.h" // for LocalException
41 #include "properties/PropertyUser.h" // for PropertyDefinitionsPtr, etc
42 
43 #include <Ice/Application.h> // for Application
44 #include <Ice/BuiltinSequences.h> // for StringSeq
45 #include <Ice/PropertiesF.h> // for PropertiesPtr
46 #include <IceUtil/Handle.h> // for Handle, HandleBase
47 
48 #include <string> // for string
49 #include <vector> // for vector
50 #include <mutex>
51 
52 
53 namespace 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 
66 namespace std
67 {
68  class thread;
69 }
70 
71 namespace 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  */
108  ApplicationPropertyDefinitions(std::string prefix);
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  */
194  public Ice::Application,
195  public PropertyUser
196  {
197  public:
198  /**
199  * @brief Application initalizes the Ice::Application base class.
200  */
201  Application();
202  /**
203  * Creates the one application instance of type T. T is usually the
204  * type of a sublass as defined in a specific component. This method is
205  * called from the automatically generated main.cpp.
206  *
207  * @return shared pointer to the application
208  */
209  template <class T, typename ...Args>
210  static ApplicationPtr 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 GetVersion()
235  {
236 #ifdef ARMARX_VERSION
237  return xstr(ARMARX_VERSION);
238 #else
239  return "undefined";
240 #endif
241  }
242 
243  /**
244  * Ice::Application replacement for the main function.
245  */
246  int run(int argc, char* argv[]) override;
247 
248  /**
249  * Set name of the application. Called from main.cpp.
250  * This method has an effect only if it is called before Application::main()
251  *
252  * @param application name
253  */
254  void setName(const std::string& name);
255 
256  /**
257  * Retrieve name of the application
258  *
259  * @return application name
260  */
261  std::string getName() const;
262 
263  /**
264  * Cleans up connections with IceStorm before terminating the app
265  *
266  * @param signal The signal send to the application
267  */
268  void interruptCallback(int signal) override;
269 
270  void registerDataPathsFromDependencies(std::string dependencies);
271 
272  /**
273  * @brief getDefaultPackageNames returns the value of the ArmarX.DefaultPackages property
274  * It splits the string by , and returns the elements as a vector.
275  * @return
276  */
277  std::vector<std::string> getArmarXPackageNames();
278 
279  bool isPackageAutoDiscoveryEnabled();
280 
281  static std::string GetArmarXConfigDefaultPath(bool envVarExpanded = true);
282  static Ice::StringSeq GetDefaultsPaths();
283  static void LoadDefaultConfig(Ice::PropertiesPtr properties);
284  static const std::string& GetProjectName();
285  static const Ice::StringSeq& GetProjectDependencies();
286 
287  /**
288  * Overrides PropertyUser::setIceProperties() which is called internally.
289  * Additionally it calls Component::updateIceProperties().
290  */
291  void setIceProperties(Ice::PropertiesPtr properties) override;
292 
293  void updateIceProperties(const Ice::PropertyDict& properties) override;
294 
295  void icePropertiesUpdated(const std::set<std::string>& changedProperties) override;
296  static const std::string ArmarXUserConfigDirEnvVar;
297 
298  const ThreadPoolPtr& getThreadPool() const;
299  bool getForbidThreadCreation() const;
300  void setForbidThreadCreation(bool value);
301  void enableLibLoading(bool enable = true);
302 
303  void storeCommandLineArguments(int argc, char* argv[]);
304  const std::vector<std::string>& getCommandLineArguments() const;
305  protected:
306  /**
307  * @see PropertyUser::createPropertyDefinitions()
308  */
309  PropertyDefinitionsPtr createPropertyDefinitions() override;
310 
311  /**
312  * Setup method to be implemented by user applications
313  *
314  * Use this method to add all required ManagedIceObject to the application
315  * @see void ManagedIceObjectRegistryInterfacePtr::addObject(ManagedIceObjectPtr object)
316  */
317  virtual void setup(const ManagedIceObjectRegistryInterfacePtr& registry, Ice::PropertiesPtr properties) = 0;
318 
319  /**
320  * Exec method is the main process of the application. The default
321  * implementation only calls
322  *
323  * <code>
324  * armarXManager->waitForShutdown();
325  * </code>
326  *
327  * If you need to do something in the main process (e.g. processing QT
328  * guis) overwrite this method.
329  *
330  * @return program exit status
331  */
332  virtual int exec(const ArmarXManagerPtr& armarXManager);
333 
334  /**
335  * @brief Ice::Application::doMain() is called by Ice::Application::main() and does setup of Ice::Communicator before calling the virtual Ice::Application::run() method
336  * @param argc
337  * @param argv
338  * @param initData
339  * @return
340  */
341  int doMain(int argc, char* argv[], const Ice::InitializationData& initData, Ice::Int i) override;
342 
343  void loadDefaultConfig(int argc, char* argv[], const Ice::InitializationData& initData);
344 
345  void loadDependentProjectDatapaths();
346 
347  /**
348  * Retrieve the domain name used for property parsing. Overwrite this in your subclass in order to
349  * use another domain name then "ArmarX".
350  * The domain name is the first part of the property identifier where each part is separated via a "." (e.g. ArmarX.some.property).
351  *
352  * @return domain name. Defaults to "ArmarX".
353  */
354  virtual std::string getDomainName();
355 
356  /**
357  * @return an instance of armarx::ArmarXManagerPtr
358  */
359  ArmarXManagerPtr getArmarXManager();
360 
361 
362 
363  /**
364  * Print help onto the screen or into a file
365  */
366  void showHelp(ApplicationOptions::Options& options);
367 
368  /**
369  * Parse options given on the commandline and merge them into the regular properties
370  */
371  Ice::PropertiesPtr parseOptionsMergeProperties(int argc, char* argv[]);
372 
373 
374  /**
375  * @brief handlerInterrupt handles interrupt signals sent to the application (Linux)
376  * @param sig
377  */
378  static void HandlerInterrupt(int sig);
379 
380 
381  /**
382  * @brief handlerFault handles signals sendt to the application such as SIGSEGF or SIGABRT (Linux)
383  * @param sig
384  */
385  static void HandlerFault(int sig);
386 
387  private:
388 
389  void loadLibrariesFromProperties();
390 
391  /**
392  * Application singleton instance
393  */
394  static ApplicationPtr instance;
395 
396  /**
397  * Application instance instantiation and access mutex
398  */
399  static std::mutex instanceMutex;
400 
401  /**
402  * Application instance name
403  */
404  std::string applicationName;
405 
406  /**
407  * the ArmarXManager
408  */
409  ArmarXManagerPtr armarXManager;
410 
411  ApplicationNetworkStatsPtr applicationNetworkStats;
412 
413  std::shared_ptr<std::thread> shutdownThread;
414 
415  static std::string ProjectName;
416  static Ice::StringSeq ProjectDependendencies;
417 
418  ThreadPoolPtr threadPool;
419  bool forbidThreadCreation = false;
420  bool libLoadingEnabled = false;
421 
422  std::vector<std::string> commandLineArguments;
423  };
424 
426  {
427  // Application interface
428  protected:
429  void setup(const ManagedIceObjectRegistryInterfacePtr& registry, Ice::PropertiesPtr properties) override
430  {
431  }
432  };
433 }
434 
436 {
437  template<class ComponentT, class AppT>
438  /**
439  * @see runSimpleComponentApp<ComponentT, AppT>.
440  * @brief Used by runSimpleComponentApp<ComponentT, AppT>.
441  * This class can't be defined in function, since this causes problems with gcc and c++03
442  */
443  class SimpleSingleComponentApp : virtual public AppT
444  {
445  void setup(const ManagedIceObjectRegistryInterfacePtr& registry, Ice::PropertiesPtr properties) override
446  {
447  registry->addObject(Component::create<ComponentT>(properties, "", appConfigDomain));
448  }
449 
450  public:
451  std::string appConfigName;
452  std::string appConfigDomain;
453  };
454 }
455 
456 namespace armarx
457 {
458  /**
459  * @brief Creates and runs an application (of AppT) for the given component (ComponentT).
460  * @param argc CL parameter count
461  * @param argv CL parameters
462  * @param appName The application's name.
463  * @param configName The config name, passed to the create call.
464  * @param configDomain The config domain, passed to the create call.
465  * @return The application's return code (app->main(argc, argv))
466  *
467  * For a component COMP the following application is created
468  * \code{.cpp}
469  * class SimpleSingleComponentApp : virtual public Application
470  * {
471  * void setup(const ManagedIceObjectRegistryInterfacePtr& registry, Ice::PropertiesPtr properties)
472  * {
473  * registry->addObject(Component::create<COMP>(properties));
474  * }
475  * };
476  * \endcode
477  * Following code is executed
478  * \code{.cpp}
479  * armarx::ApplicationPtr app = armarx::Application::createInstance<SimpleSingleComponentApp>() ;
480  * app->setName(appName);
481  * return app->main(argc, argv);
482  * \endcode
483  */
484  template<class ComponentT, class AppT = armarx::Application>
485  int runSimpleComponentApp(int argc, char* argv[], std::string appName, const std::string& configName = "", const std::string& configDomain = "ArmarX", bool enableLibLoading = false)
486  {
487  armarx::ApplicationPtr app = AppT::template createInstance<internal::SimpleSingleComponentApp<ComponentT, AppT> >();
488 
490  sApp->appConfigDomain = configDomain;
491  sApp->appConfigName = configName;
492  app->enableLibLoading(enableLibLoading);
493  app->setName(appName);
494  app->storeCommandLineArguments(argc, argv);
495  return app->main(argc, argv);
496  }
497 
498  /**
499  * @brief Do not use! Use \ref armarx::runMultipleComponentsApp()
500  */
502  {
503  public:
504  MultipleComponentsApplication(std::vector<ComponentPtr> components) :
505  components(components) {}
506 
507  private:
508  std::vector<ComponentPtr> components;
509 
510  // Application interface
511  protected:
512  void setup(const ManagedIceObjectRegistryInterfacePtr& registry, Ice::PropertiesPtr properties) override
513  {
514  for (ComponentPtr comp : components)
515  {
516  registry->addObject(comp);
517  }
518  }
519  };
520 
521  template<class ComponentType>
522  std::vector<ComponentPtr> createComponents(ComponentType comp)
523  {
524  return {comp};
525  }
526 
527  template<class ComponentType, class... ComponentTypes >
528  std::vector<ComponentPtr> createComponents(ComponentType comp, ComponentTypes... components)
529  {
530  std::vector<ComponentPtr> result {comp};
531  std::vector<ComponentPtr> tempResult = createComponents(components...);
532  result.insert(result.end(), tempResult.begin(), tempResult.end());
533  return result;
534  }
535 
536  template<class... ComponentTypes >
537  std::vector<ComponentPtr> createComponentsUtil(ComponentTypes&& ... components)
538  {
539  std::vector<ComponentPtr> result;
540  std::vector<ComponentPtr> tempResult = createComponents(components...);
541  result.insert(result.end(), tempResult.begin(), tempResult.end());
542  return result;
543  }
544 
545  /**
546  * Convenience function to create an app with multiple components easily.
547  *
548  * Usage:
549  * \code{.cpp}
550  * main(int argc, char * argv[])
551  * {
552  * armarx::ApplicationPtr app;
553  * std::vector<ComponentPtr> components;
554  * std::tie(app, components) = runMultipleComponentsApp < ConditionHandler, SystemObserver, DebugObserver > (argc, argv, "ArmarXCoreApps");
555  * return app->main(argc, argv);
556  * }
557  * \endcode
558  *
559  * \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.
560  */
561  template<class... ComponentTypes >
562  std::tuple<armarx::ApplicationPtr, std::vector<ComponentPtr> > runMultipleComponentsApp(int argc, char* argv[], std::string appName, const std::string& configDomain = "ArmarX")
563  {
564  Ice::PropertiesPtr props = Ice::createProperties(argc, argv);
565  std::vector<ComponentPtr> comps = createComponentsUtil(Component::create<ComponentTypes>(props, "", configDomain)...);
567 
568  app->setName(appName);
569  return std::make_tuple(app, comps);
570  }
571 
572 }
armarx::internal::SimpleSingleComponentApp::appConfigName
std::string appConfigName
Definition: Application.h:451
armarx::internal
Definition: Application.h:435
armarx::runMultipleComponentsApp
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.
Definition: Application.h:562
ApplicationOptions.h
armarx::ThreadPoolPtr
std::shared_ptr< ThreadPool > ThreadPoolPtr
Definition: Application.h:76
xstr
#define xstr(s)
Definition: Application.h:58
IceInternal::Handle< ::Ice::Properties >
armarx::ApplicationNetworkStats
The ApplicationNetworkStats class implements the Ice::Instrumentation::CommunicatorObserver interface...
Definition: ApplicationNetworkStats.h:51
armarx::createComponentsUtil
std::vector< ComponentPtr > createComponentsUtil(ComponentTypes &&... components)
Definition: Application.h:537
armarx::createComponents
std::vector< ComponentPtr > createComponents(ComponentType comp)
Definition: Application.h:522
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:926
armarx::MultipleComponentsApplication::setup
void setup(const ManagedIceObjectRegistryInterfacePtr &registry, Ice::PropertiesPtr properties) override
Setup method to be implemented by user applications.
Definition: Application.h:512
Ice::createProperties
Ice::PropertiesPtr createProperties()
PropertyUser.h
armarx::DummyApplication
Definition: Application.h:425
armarx::ApplicationOptions::Options
Stucture containing the parsed options of the application.
Definition: ApplicationOptions.h:76
ApplicationNetworkStats.h
armarx::runSimpleComponentApp
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).
Definition: Application.h:485
armarx::ApplicationPtr
IceUtil::Handle< Application > ApplicationPtr
Definition: Application.h:93
armarx::PropertyDefinitionContainer
PropertyDefinitionContainer.
Definition: PropertyDefinitionContainer.h:53
armarx::Application
Baseclass for all ArmarX applications.
Definition: Application.h:193
armarx::ApplicationPropertyDefinitions
Application property definition container.
Definition: Application.h:101
armarx::internal::SimpleSingleComponentApp::appConfigDomain
std::string appConfigDomain
Definition: Application.h:452
armarx::internal::SimpleSingleComponentApp
Used by runSimpleComponentApp<ComponentT, AppT>. This class can't be defined in function,...
Definition: Application.h:443
ArmarXFwd.h
Ice
Definition: DBTypes.cpp:64
armarx::DummyApplication::setup
void setup(const ManagedIceObjectRegistryInterfacePtr &registry, Ice::PropertiesPtr properties) override
Setup method to be implemented by user applications.
Definition: Application.h:429
PropertyDefinitionContainer.h
std
Definition: Application.h:66
IceUtil::Handle< ApplicationNetworkStats >
armarx::Application::createInstance
static ApplicationPtr createInstance(Args &&... args)
Creates the one application instance of type T.
Definition: Application.h:210
armarx::VariantType::Int
const VariantTypeId Int
Definition: Variant.h:916
ManagedIceObjectRegistryInterface.h
armarx::Application::GetVersion
static std::string GetVersion()
Definition: Application.h:234
armarx::MultipleComponentsApplication::MultipleComponentsApplication
MultipleComponentsApplication(std::vector< ComponentPtr > components)
Definition: Application.h:504
ARMARXCORE_IMPORT_EXPORT
#define ARMARXCORE_IMPORT_EXPORT
Definition: ImportExport.h:38
armarx::MultipleComponentsApplication
Do not use! Use armarx::runMultipleComponentsApp()
Definition: Application.h:501
T
float T
Definition: UnscentedKalmanFilterTest.cpp:35
armarx::ApplicationOptions::showHelp
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.
Definition: ApplicationOptions.cpp:169
armarx::PropertyUser
Abstract PropertyUser class.
Definition: PropertyUser.h:62
armarx::Application::ArmarXUserConfigDirEnvVar
static const std::string ArmarXUserConfigDirEnvVar
Definition: Application.h:296
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
Exception.h