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