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"
46 #include "../system/ArmarXDataPath.h"
47 #include "../system/ImportExport.h" // for ARMARXCORE_IMPORT_EXPORT
48 #include "../system/cmake/CMakePackageFinder.h"
49 #include "ApplicationNetworkStats.h" // for ApplicationNetworkStatsPtr
50 #include "ApplicationOptions.h"
51 #include "properties/PropertyUser.h" // for PropertyDefinitionsPtr, etc
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  */
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  */
311  PropertyDefinitionsPtr createPropertyDefinitions() override;
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 
351  void loadDependentProjectDatapaths();
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  */
365  ArmarXManagerPtr getArmarXManager();
366 
367 
368  /**
369  * Print help onto the screen or into a file
370  */
371  void showHelp(ApplicationOptions::Options& options);
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 
464 namespace 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
armarx::internal::SimpleSingleComponentApp::appConfigName
std::string appConfigName
Definition: Application.h:459
armarx::internal
Definition: Application.h:441
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:585
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:559
armarx::createComponents
std::vector< ComponentPtr > createComponents(ComponentType comp)
Definition: Application.h:542
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:855
armarx::MultipleComponentsApplication::setup
void setup(const ManagedIceObjectRegistryInterfacePtr &registry, Ice::PropertiesPtr properties) override
Setup method to be implemented by user applications.
Definition: Application.h:530
Ice::createProperties
Ice::PropertiesPtr createProperties()
PropertyUser.h
armarx::DummyApplication
Definition: Application.h:429
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:494
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:460
armarx::internal::SimpleSingleComponentApp
Used by runSimpleComponentApp<ComponentT, AppT>. This class can't be defined in function,...
Definition: Application.h:449
ArmarXFwd.h
Ice
Definition: DBTypes.cpp:63
armarx::DummyApplication::setup
void setup(const ManagedIceObjectRegistryInterfacePtr &registry, Ice::PropertiesPtr properties) override
Setup method to be implemented by user applications.
Definition: Application.h:434
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:917
ManagedIceObjectRegistryInterface.h
armarx::Application::GetVersion
static std::string GetVersion()
Definition: Application.h:235
armarx::MultipleComponentsApplication::MultipleComponentsApplication
MultipleComponentsApplication(std::vector< ComponentPtr > components)
Definition: Application.h:520
ARMARXCORE_IMPORT_EXPORT
#define ARMARXCORE_IMPORT_EXPORT
Definition: ImportExport.h:38
armarx::MultipleComponentsApplication
Do not use! Use armarx::runMultipleComponentsApp()
Definition: Application.h:517
T
float T
Definition: UnscentedKalmanFilterTest.cpp:38
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:187
armarx::PropertyUser
Abstract PropertyUser class.
Definition: PropertyUser.h:63
armarx::Application::ArmarXUserConfigDirEnvVar
static const std::string ArmarXUserConfigDirEnvVar
Definition: Application.h:297
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
Exception.h