OpenWalnut  1.4.0
WModuleContainer.h
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #ifndef WMODULECONTAINER_H
00026 #define WMODULECONTAINER_H
00027 
00028 #include <list>
00029 #include <map>
00030 #include <set>
00031 #include <string>
00032 #include <utility>
00033 #include <vector>
00034 
00035 #include <boost/function.hpp>
00036 #include <boost/shared_ptr.hpp>
00037 #include <boost/signals2/signal.hpp>
00038 #include <boost/thread.hpp>
00039 
00040 #include "../common/WSharedObject.h"
00041 
00042 #include "WModule.h"
00043 #include "WModuleCombinerTypes.h"
00044 #include "WModuleConnectorSignals.h"
00045 #include "WModuleSignals.h"
00046 #include "WBatchLoader.h"
00047 
00048 class WThreadedRunner;
00049 class WDataModule;
00050 
00051 
00052 
00053 /**
00054  * Class able to contain other modules. It manages several tasks like finding appropriate modules, managing data modules and
00055  * module initialization.
00056  *
00057  * \ingroup Kernel
00058  */
00059 class  WModuleContainer: public WModule
00060 {
00061 public:
00062     // the following typedefs are for convenience; to help accessing the container in a thread safe way.
00063 
00064     /**
00065      * A vector of modules
00066      */
00067     typedef std::vector< boost::shared_ptr< WModule > > ModuleVectorType;
00068 
00069     /**
00070      * For shortening: a type defining a shared vector of WModule pointers.
00071      */
00072     typedef std::set< boost::shared_ptr< WModule > > ModuleContainerType;
00073 
00074     /**
00075      * The alias for a shared container.
00076      */
00077     typedef WSharedObject< ModuleContainerType > ModuleSharedContainerType;
00078 
00079     /**
00080      * The const iterator type of the container.
00081      */
00082     typedef ModuleContainerType::const_iterator ModuleConstIterator;
00083 
00084     /**
00085      * The iterator type of the container.
00086      */
00087     typedef ModuleContainerType::iterator ModuleIterator;
00088 
00089 
00090     /**
00091      * Constructor. Initializes container.
00092      *
00093      * \param name  name of the container
00094      * \param description short description.
00095      */
00096     WModuleContainer( std::string name = "Unnamed Module Container",
00097                       std::string description = "Used as container for several modules." );
00098 
00099     /**
00100      * Destructor.
00101      */
00102     virtual ~WModuleContainer();
00103 
00104     /**
00105      * Add a module to this container and start it. Please note, that a module can be added only once. If it already is
00106      * associated with this container nothing happens.
00107      *
00108      * \param module the module to add.
00109      * \param run true when the module should be run automatically after adding it.
00110      * \throw WModuleUninitialized thrown whenever someone wants to add a module not yet initialized.
00111      */
00112     virtual void add( boost::shared_ptr< WModule > module, bool run = true );
00113 
00114     /**
00115      * Convenience method to create a module instance with a given name and automatically add it to the container.
00116      *
00117      * \param name the prototype name to create
00118      *
00119      * \return the created and added module
00120      */
00121     virtual WModule::SPtr createAndAdd( std::string name );
00122 
00123     /**
00124      * Remove the given module from this container if it is associated with it. It only provides flat removal. It does not remove depending
00125      * modules. Please be aware that this method does NOT stop the module. It just removes it from the container. If you release the shared
00126      * pointer after removing from the container, the instance gets freed although it still might run. To also wait for the module to quit, use
00127      * module->wait( true ).
00128      *
00129      * \param module the module to remove.
00130      */
00131     virtual void remove( boost::shared_ptr< WModule > module );
00132 
00133     /**
00134      * Removes all modules from this container. It uses a relatively laborious iterative approach
00135      * becausewe can not delete modules recursively so far.
00136      */
00137     virtual void removeAll();
00138 
00139     /**
00140      * Stops all modules inside this container. Note that this function could take some time, since it waits until the last module
00141      * has quit.
00142      */
00143     virtual void stop();
00144 
00145     /**
00146      * Gives back the name of this module.
00147      * \return the module's name.
00148      */
00149     virtual const std::string getName() const;
00150 
00151     /**
00152      * Gives back a description of this module.
00153      * \return description to module.
00154      */
00155     virtual const std::string getDescription() const;
00156 
00157     /**
00158      * Add a specified notifier to the list of default notifiers which get connected to each added module.
00159      *
00160      * \param signal    the signal the notifier should get connected to
00161      * \param notifier  the notifier function
00162      */
00163     virtual void addDefaultNotifier( MODULE_SIGNAL signal, t_ModuleErrorSignalHandlerType notifier );
00164 
00165     /**
00166      * Add a specified notifier to the list of default notifiers which get connected to each added module.
00167      *
00168      * \param signal    the signal the notifier should get connected to
00169      * \param notifier  the notifier function
00170      */
00171     virtual void addDefaultNotifier( MODULE_SIGNAL signal, t_ModuleGenericSignalHandlerType notifier );
00172 
00173     /**
00174      * Add a specified notifier to the list of default notifiers which get connected to each added module. This is especially used for all the
00175      * connector related events like connect and disconnect.
00176      * \note This signal is only called for input connectors!
00177      *
00178      * \param signal    the signal the notifier should get connected to
00179      * \param notifier  the notifier function
00180      */
00181     virtual void addDefaultNotifier( MODULE_CONNECTOR_SIGNAL signal, t_GenericSignalHandlerType notifier );
00182 
00183     /**
00184      * Function combines two modules. This runs synchronously. It might take some time to finish since combination of modules is
00185      * allowed only with modules marked as "ready" which might take some time.
00186      *
00187      * \param applyOn the module which already has to be in the container and to apply the other one on.
00188      * \param what the prototype name of the module to apply on the other one specified.
00189      * \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
00190      *                not exist, the nothing will happen.
00191      *
00192      * \return the newly created module connected with the one specified in applyOn. If the prototype could not be found and tryOnly was set to
00193      *         true it will return NULL.
00194      */
00195     virtual boost::shared_ptr< WModule > applyModule( boost::shared_ptr< WModule > applyOn, std::string what, bool tryOnly = false );
00196 
00197     /**
00198      * Function combines two modules. This runs synchronously. It might take some time to finish since combination of modules is
00199      * allowed only with modules marked as "ready" which might take some time.
00200      *
00201      * \param applyOn the module which already has to be in the container and to apply the other one on.
00202      * \param prototype the prototype of the module to apply on the other one specified.
00203      *
00204      * \return the newly created module connected with the one specified in applyOn.
00205      */
00206     virtual boost::shared_ptr< WModule > applyModule( boost::shared_ptr< WModule > applyOn, boost::shared_ptr< WModule > prototype );
00207 
00208     /**
00209      * Load specified datasets. It immediately returns and starts another thread, which actually loads the data.
00210      *
00211      * \param filenames list of filenames to load. The registered notification handler for the root container will get notified on
00212      * error and success.
00213      * \param suppressColormaps if true, the data modules are instructed to avoid registration of colormaps. This can be very handy if you
00214      * combine multiple data loaders into one new data loader or data set
00215      *
00216      * \return the loader handling the load operation
00217      */
00218     WBatchLoader::SPtr loadDataSets( std::vector< std::string > filenames, bool suppressColormaps = false );
00219 
00220     /**
00221      * Loads the specified files synchronously. The returned batchloader can be queried for the list of data modules that have been added.
00222      *
00223      * \param filenames list of filenames to load. The registered notification handler for the root container will get notified on
00224      * error and success.
00225      * \param suppressColormaps if true, the data modules are instructed to avoid registration of colormaps. This can be very handy if you
00226      * combine multiple data loaders into one new data loader or data set
00227      *
00228      * \return the loader has handled the load operation
00229      */
00230     WBatchLoader::SPtr loadDataSetsSynchronously( std::vector< std::string > filenames, bool suppressColormaps = false );
00231 
00232     /**
00233      * Add the specified thread to the list of pending jobs. Only this ensures, that ALL pending threads get stopped before the
00234      * container gets stopped.
00235      *
00236      * \note use this to register threads whenever you start threads belonging to this container. This avoids shutting down the
00237      * container while other threads depend upon it.
00238      *
00239      * \param thread the thread to add
00240      */
00241     void addPendingThread( boost::shared_ptr< WThreadedRunner > thread );
00242 
00243     /**
00244      * The specified thread has finished and does not longer depend upon this container instance.
00245      *
00246      * \param thread the thread.
00247      */
00248     void finishedPendingThread( boost::shared_ptr< WThreadedRunner > thread );
00249 
00250     /**
00251      * Sets a flag denoting whether the container (which also is a module) should be marked as "crashed" if a nested module crashes.
00252      *
00253      * \param crashIfCrashed true if it also should crash.
00254      */
00255     void setCrashIfModuleCrashes( bool crashIfCrashed = true );
00256 
00257     /**
00258      * Due to the prototype design pattern used to build modules, this method returns a new instance of this method. NOTE: it
00259      * should never be initialized or modified in some other way. A simple new instance is required.
00260      *
00261      * \return the prototype used to create every module in OpenWalnut.
00262      */
00263     virtual boost::shared_ptr< WModule > factory() const;
00264 
00265     /**
00266      * Simple type for WDataModule pointer lists.
00267      */
00268     typedef std::set< boost::shared_ptr< WDataModule > > DataModuleListType;
00269 
00270     /**
00271      * Returns a vector of pointers to the loaded data modules in the container.
00272      *
00273      * \return the list of data modules.
00274      */
00275     DataModuleListType getDataModules();
00276 
00277     /**
00278      * Method returns a read ticket allowing read-access to the list of modules inside the container.
00279      * \note If done, ensure the ticket gets destroyed.
00280      *
00281      * \return the read ticket.
00282      */
00283     ModuleSharedContainerType::ReadTicket getModules() const;
00284 
00285     /**
00286      * Queries the container to find all modules with a given name. This can be useful to check for existence of certain modules inside the
00287      * container.
00288      *
00289      * \param name name of the modules to find
00290      *
00291      * \return the vector of modules. Empty if nothing was found.
00292      */
00293     ModuleVectorType getModules( std::string name ) const;
00294 
00295     /**
00296      * This method creates a list of combiner instances, for each possible connection that can be made between the specified module and the
00297      * module currently inside the container. It might be possible that a module which is contained in the returned list is not associated
00298      * anymore if the combiner gets applied.
00299      *
00300      * \param module the module to which the possible connections should be returned
00301      *
00302      * \return the possible combinations of connectors.
00303      */
00304     WCombinerTypes::WCompatiblesList getPossibleConnections( boost::shared_ptr< WModule > module );
00305 
00306 protected:
00307     /**
00308      * Entry point after loading the module. Runs in separate thread. The module container does not use this method. It simply
00309      * returns.
00310      */
00311     virtual void moduleMain();
00312 
00313     /**
00314      * The modules associated with this container.
00315      */
00316     ModuleSharedContainerType m_modules;
00317 
00318     /**
00319      * Name of the module.
00320      */
00321     std::string m_name;
00322 
00323     /**
00324      * Description of the module.
00325      */
00326     std::string m_description;
00327 
00328     /**
00329      * Lock for error notifiers set.
00330      */
00331     boost::shared_mutex m_errorNotifiersLock;
00332 
00333     /**
00334      * The error notifiers connected to added modules by default.
00335      */
00336     std::list< t_ModuleErrorSignalHandlerType > m_errorNotifiers;
00337 
00338     /**
00339      * Lock for ready notifiers set.
00340      */
00341     boost::shared_mutex m_readyNotifiersLock;
00342 
00343     /**
00344      * The ready notifiers connected to added modules by default.
00345      */
00346     std::list< t_ModuleGenericSignalHandlerType > m_readyNotifiers;
00347 
00348     /**
00349      * Lock for associated notifiers set.
00350      */
00351     boost::shared_mutex m_associatedNotifiersLock;
00352 
00353     /**
00354      * The notifiers connected to added modules by default and fired whenever the module got associated.
00355      */
00356     std::list< t_ModuleGenericSignalHandlerType > m_associatedNotifiers;
00357 
00358     /**
00359      * Lock for remove-notifiers set.
00360      */
00361     boost::shared_mutex m_removedNotifiersLock;
00362 
00363     /**
00364      * The notifiers connected to added modules by default and fired whenever the module got removed again.
00365      */
00366     std::list< t_ModuleGenericSignalHandlerType > m_removedNotifiers;
00367 
00368     /**
00369      * Lock for connector-notifiers set.
00370      */
00371     boost::shared_mutex m_connectorNotifiersLock;
00372 
00373     /**
00374      * The notifiers connected to added modules by default and fired whenever the module connectors got connected.
00375      */
00376     std::list< t_GenericSignalHandlerType > m_connectorEstablishedNotifiers;
00377 
00378     /**
00379      * The notifiers connected to added modules by default and fired whenever the module connectors got disconnected.
00380      */
00381     std::list< t_GenericSignalHandlerType > m_connectorClosedNotifiers;
00382 
00383     /**
00384      * Set of all threads that currently depend upon this container.
00385      */
00386     std::set< boost::shared_ptr< WThreadedRunner > > m_pendingThreads;
00387 
00388     /**
00389      * Lock for m_pendingThreads.
00390      */
00391     boost::shared_mutex m_pendingThreadsLock;
00392 
00393     /**
00394      * This method is called whenever a module inside the container crashes. By default, this method does nothing but forwarding the using
00395      * WModule's signals.
00396      *
00397      * \param module the module that has crashed.
00398      * \param exception the exception.
00399      */
00400     virtual void moduleError( boost::shared_ptr< WModule > module, const WException& exception );
00401 
00402     /**
00403      * This flag denotes whether the whole container should be marked as crashed if one of the contained modules crashes. By default, this is
00404      * true. The root container (the container not nested in any other container) sets this to false explicitly. Modules using the container to
00405      * encapsulate a whole bunch of modules can decide, but by default they crash too.
00406      */
00407     bool m_crashIfModuleCrashes;
00408 
00409 private:
00410     // the following typedefs are for convenience; to help accessing the container in a thread safe way.
00411 
00412     /**
00413      * A type for mapping a module to all its subscriptions
00414      */
00415     typedef std::pair< boost::shared_ptr< WModule >, boost::signals2::connection > ModuleSubscription;
00416 
00417     /**
00418      * For shortening: a type defining a shared vector of subscriptions a module made to a notifier during add().
00419      */
00420     typedef std::multimap< boost::shared_ptr< WModule >, boost::signals2::connection > ModuleSubscriptionsType;
00421 
00422     /**
00423      * The alias for a shared container.
00424      */
00425     typedef WSharedObject< ModuleSubscriptionsType > ModuleSubscriptionsSharedType;
00426 
00427     /**
00428      * The const iterator type of the container.
00429      */
00430     typedef ModuleSubscriptionsType::const_iterator ModuleSubscriptionsConstIterator;
00431 
00432     /**
00433      * The iterator type of the container.
00434      */
00435     typedef ModuleSubscriptionsType::iterator ModuleSubscriptionsIterator;
00436 
00437     /**
00438      * The module's signal subscriptions.
00439      */
00440     ModuleSubscriptionsSharedType m_moduleSubscriptions;
00441 };
00442 
00443 #endif  // WMODULECONTAINER_H
00444