OpenWalnut  1.3.1
WModuleContainer.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WMODULECONTAINER_H
26 #define WMODULECONTAINER_H
27 
28 #include <list>
29 #include <map>
30 #include <set>
31 #include <string>
32 #include <utility>
33 #include <vector>
34 
35 #include <boost/function.hpp>
36 #include <boost/shared_ptr.hpp>
37 #include <boost/signals2/signal.hpp>
38 #include <boost/thread.hpp>
39 
40 #include "../common/WSharedObject.h"
41 
42 #include "WModule.h"
43 #include "WModuleCombinerTypes.h"
44 #include "WModuleConnectorSignals.h"
45 #include "WModuleSignals.h"
46 #include "WBatchLoader.h"
47 
48 class WThreadedRunner;
49 class WDataModule;
50 
51 
52 
53 /**
54  * Class able to contain other modules. It manages several tasks like finding appropriate modules, managing data modules and
55  * module initialization.
56  *
57  * \ingroup Kernel
58  */
60 {
61 public:
62  // the following typedefs are for convenience; to help accessing the container in a thread safe way.
63 
64  /**
65  * A vector of modules
66  */
67  typedef std::vector< boost::shared_ptr< WModule > > ModuleVectorType;
68 
69  /**
70  * For shortening: a type defining a shared vector of WModule pointers.
71  */
72  typedef std::set< boost::shared_ptr< WModule > > ModuleContainerType;
73 
74  /**
75  * The alias for a shared container.
76  */
78 
79  /**
80  * The const iterator type of the container.
81  */
82  typedef ModuleContainerType::const_iterator ModuleConstIterator;
83 
84  /**
85  * The iterator type of the container.
86  */
87  typedef ModuleContainerType::iterator ModuleIterator;
88 
89 
90  /**
91  * Constructor. Initializes container.
92  *
93  * \param name name of the container
94  * \param description short description.
95  */
96  WModuleContainer( std::string name = "Unnamed Module Container",
97  std::string description = "Used as container for several modules." );
98 
99  /**
100  * Destructor.
101  */
102  virtual ~WModuleContainer();
103 
104  /**
105  * Add a module to this container and start it. Please note, that a module can be added only once. If it already is
106  * associated with this container nothing happens.
107  *
108  * \param module the module to add.
109  * \param run true when the module should be run automatically after adding it.
110  * \throw WModuleUninitialized thrown whenever someone wants to add a module not yet initialized.
111  */
112  virtual void add( boost::shared_ptr< WModule > module, bool run = true );
113 
114  /**
115  * Convenience method to create a module instance with a given name and automatically add it to the container.
116  *
117  * \param name the prototype name to create
118  *
119  * \return the created and added module
120  */
121  virtual WModule::SPtr createAndAdd( std::string name );
122 
123  /**
124  * Remove the given module from this container if it is associated with it. It only provides flat removal. It does not remove depending
125  * modules. Please be aware that this method does NOT stop the module. It just removes it from the container. If you release the shared
126  * pointer after removing from the container, the instance gets freed although it still might run. To also wait for the module to quit, use
127  * module->wait( true ).
128  *
129  * \param module the module to remove.
130  */
131  virtual void remove( boost::shared_ptr< WModule > module );
132 
133  /**
134  * Stops all modules inside this container. Note that this function could take some time, since it waits until the last module
135  * has quit.
136  */
137  virtual void stop();
138 
139  /**
140  * Gives back the name of this module.
141  * \return the module's name.
142  */
143  virtual const std::string getName() const;
144 
145  /**
146  * Gives back a description of this module.
147  * \return description to module.
148  */
149  virtual const std::string getDescription() const;
150 
151  /**
152  * Add a specified notifier to the list of default notifiers which get connected to each added module.
153  *
154  * \param signal the signal the notifier should get connected to
155  * \param notifier the notifier function
156  */
157  virtual void addDefaultNotifier( MODULE_SIGNAL signal, t_ModuleErrorSignalHandlerType notifier );
158 
159  /**
160  * Add a specified notifier to the list of default notifiers which get connected to each added module.
161  *
162  * \param signal the signal the notifier should get connected to
163  * \param notifier the notifier function
164  */
165  virtual void addDefaultNotifier( MODULE_SIGNAL signal, t_ModuleGenericSignalHandlerType notifier );
166 
167  /**
168  * Add a specified notifier to the list of default notifiers which get connected to each added module. This is especially used for all the
169  * connector related events like connect and disconnect.
170  * \note This signal is only called for input connectors!
171  *
172  * \param signal the signal the notifier should get connected to
173  * \param notifier the notifier function
174  */
175  virtual void addDefaultNotifier( MODULE_CONNECTOR_SIGNAL signal, t_GenericSignalHandlerType notifier );
176 
177  /**
178  * Function combines two modules. This runs synchronously. It might take some time to finish since combination of modules is
179  * allowed only with modules marked as "ready" which might take some time.
180  *
181  * \param applyOn the module which already has to be in the container and to apply the other one on.
182  * \param what the prototype name of the module to apply on the other one specified.
183  * \param tryOnly If set to false and the prototype "what" does not exist this will throw an exception. If set to true and the prototype does
184  * not exist, the nothing will happen.
185  *
186  * \return the newly created module connected with the one specified in applyOn. If the prototype could not be found and tryOnly was set to
187  * true it will return NULL.
188  */
189  virtual boost::shared_ptr< WModule > applyModule( boost::shared_ptr< WModule > applyOn, std::string what, bool tryOnly = false );
190 
191  /**
192  * Function combines two modules. This runs synchronously. It might take some time to finish since combination of modules is
193  * allowed only with modules marked as "ready" which might take some time.
194  *
195  * \param applyOn the module which already has to be in the container and to apply the other one on.
196  * \param prototype the prototype of the module to apply on the other one specified.
197  *
198  * \return the newly created module connected with the one specified in applyOn.
199  */
200  virtual boost::shared_ptr< WModule > applyModule( boost::shared_ptr< WModule > applyOn, boost::shared_ptr< WModule > prototype );
201 
202  /**
203  * Load specified datasets. It immediately returns and starts another thread, which actually loads the data.
204  *
205  * \param filenames list of filenames to load. The registered notification handler for the root container will get notified on
206  * error and success.
207  * \param suppressColormaps if true, the data modules are instructed to avoid registration of colormaps. This can be very handy if you
208  * combine multiple data loaders into one new data loader or data set
209  *
210  * \return the loader handling the load operation
211  */
212  WBatchLoader::SPtr loadDataSets( std::vector< std::string > filenames, bool suppressColormaps = false );
213 
214  /**
215  * Loads the specified files synchronously. The returned batchloader can be queried for the list of data modules that have been added.
216  *
217  * \param filenames list of filenames to load. The registered notification handler for the root container will get notified on
218  * error and success.
219  * \param suppressColormaps if true, the data modules are instructed to avoid registration of colormaps. This can be very handy if you
220  * combine multiple data loaders into one new data loader or data set
221  *
222  * \return the loader has handled the load operation
223  */
224  WBatchLoader::SPtr loadDataSetsSynchronously( std::vector< std::string > filenames, bool suppressColormaps = false );
225 
226  /**
227  * Add the specified thread to the list of pending jobs. Only this ensures, that ALL pending threads get stopped before the
228  * container gets stopped.
229  *
230  * \note use this to register threads whenever you start threads belonging to this container. This avoids shutting down the
231  * container while other threads depend upon it.
232  *
233  * \param thread the thread to add
234  */
235  void addPendingThread( boost::shared_ptr< WThreadedRunner > thread );
236 
237  /**
238  * The specified thread has finished and does not longer depend upon this container instance.
239  *
240  * \param thread the thread.
241  */
242  void finishedPendingThread( boost::shared_ptr< WThreadedRunner > thread );
243 
244  /**
245  * Sets a flag denoting whether the container (which also is a module) should be marked as "crashed" if a nested module crashes.
246  *
247  * \param crashIfCrashed true if it also should crash.
248  */
249  void setCrashIfModuleCrashes( bool crashIfCrashed = true );
250 
251  /**
252  * Due to the prototype design pattern used to build modules, this method returns a new instance of this method. NOTE: it
253  * should never be initialized or modified in some other way. A simple new instance is required.
254  *
255  * \return the prototype used to create every module in OpenWalnut.
256  */
257  virtual boost::shared_ptr< WModule > factory() const;
258 
259  /**
260  * Simple type for WDataModule pointer lists.
261  */
262  typedef std::set< boost::shared_ptr< WDataModule > > DataModuleListType;
263 
264  /**
265  * Returns a vector of pointers to the loaded data modules in the container.
266  *
267  * \return the list of data modules.
268  */
270 
271  /**
272  * Method returns a read ticket allowing read-access to the list of modules inside the container.
273  * \note If done, ensure the ticket gets destroyed.
274  *
275  * \return the read ticket.
276  */
278 
279  /**
280  * Queries the container to find all modules with a given name. This can be useful to check for existence of certain modules inside the
281  * container.
282  *
283  * \param name name of the modules to find
284  *
285  * \return the vector of modules. Empty if nothing was found.
286  */
287  ModuleVectorType getModules( std::string name ) const;
288 
289  /**
290  * This method creates a list of combiner instances, for each possible connection that can be made between the specified module and the
291  * module currently inside the container. It might be possible that a module which is contained in the returned list is not associated
292  * anymore if the combiner gets applied.
293  *
294  * \param module the module to which the possible connections should be returned
295  *
296  * \return the possible combinations of connectors.
297  */
298  WCombinerTypes::WCompatiblesList getPossibleConnections( boost::shared_ptr< WModule > module );
299 
300 protected:
301  /**
302  * Entry point after loading the module. Runs in separate thread. The module container does not use this method. It simply
303  * returns.
304  */
305  virtual void moduleMain();
306 
307  /**
308  * The modules associated with this container.
309  */
311 
312  /**
313  * Name of the module.
314  */
315  std::string m_name;
316 
317  /**
318  * Description of the module.
319  */
320  std::string m_description;
321 
322  /**
323  * Lock for error notifiers set.
324  */
325  boost::shared_mutex m_errorNotifiersLock;
326 
327  /**
328  * The error notifiers connected to added modules by default.
329  */
330  std::list< t_ModuleErrorSignalHandlerType > m_errorNotifiers;
331 
332  /**
333  * Lock for ready notifiers set.
334  */
335  boost::shared_mutex m_readyNotifiersLock;
336 
337  /**
338  * The ready notifiers connected to added modules by default.
339  */
340  std::list< t_ModuleGenericSignalHandlerType > m_readyNotifiers;
341 
342  /**
343  * Lock for associated notifiers set.
344  */
345  boost::shared_mutex m_associatedNotifiersLock;
346 
347  /**
348  * The notifiers connected to added modules by default and fired whenever the module got associated.
349  */
350  std::list< t_ModuleGenericSignalHandlerType > m_associatedNotifiers;
351 
352  /**
353  * Lock for remove-notifiers set.
354  */
355  boost::shared_mutex m_removedNotifiersLock;
356 
357  /**
358  * The notifiers connected to added modules by default and fired whenever the module got removed again.
359  */
360  std::list< t_ModuleGenericSignalHandlerType > m_removedNotifiers;
361 
362  /**
363  * Lock for connector-notifiers set.
364  */
365  boost::shared_mutex m_connectorNotifiersLock;
366 
367  /**
368  * The notifiers connected to added modules by default and fired whenever the module connectors got connected.
369  */
370  std::list< t_GenericSignalHandlerType > m_connectorEstablishedNotifiers;
371 
372  /**
373  * The notifiers connected to added modules by default and fired whenever the module connectors got disconnected.
374  */
375  std::list< t_GenericSignalHandlerType > m_connectorClosedNotifiers;
376 
377  /**
378  * Set of all threads that currently depend upon this container.
379  */
380  std::set< boost::shared_ptr< WThreadedRunner > > m_pendingThreads;
381 
382  /**
383  * Lock for m_pendingThreads.
384  */
385  boost::shared_mutex m_pendingThreadsLock;
386 
387  /**
388  * This method is called whenever a module inside the container crashes. By default, this method does nothing but forwarding the using
389  * WModule's signals.
390  *
391  * \param module the module that has crashed.
392  * \param exception the exception.
393  */
394  virtual void moduleError( boost::shared_ptr< WModule > module, const WException& exception );
395 
396  /**
397  * This flag denotes whether the whole container should be marked as crashed if one of the contained modules crashes. By default, this is
398  * true. The root container (the container not nested in any other container) sets this to false explicitly. Modules using the container to
399  * encapsulate a whole bunch of modules can decide, but by default they crash too.
400  */
402 
403 private:
404  // the following typedefs are for convenience; to help accessing the container in a thread safe way.
405 
406  /**
407  * A type for mapping a module to all its subscriptions
408  */
409  typedef std::pair< boost::shared_ptr< WModule >, boost::signals2::connection > ModuleSubscription;
410 
411  /**
412  * For shortening: a type defining a shared vector of subscriptions a module made to a notifier during add().
413  */
414  typedef std::multimap< boost::shared_ptr< WModule >, boost::signals2::connection > ModuleSubscriptionsType;
415 
416  /**
417  * The alias for a shared container.
418  */
420 
421  /**
422  * The const iterator type of the container.
423  */
424  typedef ModuleSubscriptionsType::const_iterator ModuleSubscriptionsConstIterator;
425 
426  /**
427  * The iterator type of the container.
428  */
429  typedef ModuleSubscriptionsType::iterator ModuleSubscriptionsIterator;
430 
431  /**
432  * The module's signal subscriptions.
433  */
435 };
436 
437 #endif // WMODULECONTAINER_H
438