OpenWalnut 1.3.1
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      * Stops all modules inside this container. Note that this function could take some time, since it waits until the last module
00135      * has quit.
00136      */
00137     virtual void stop();
00138 
00139     /**
00140      * Gives back the name of this module.
00141      * \return the module's name.
00142      */
00143     virtual const std::string getName() const;
00144 
00145     /**
00146      * Gives back a description of this module.
00147      * \return description to module.
00148      */
00149     virtual const std::string getDescription() const;
00150 
00151     /**
00152      * Add a specified notifier to the list of default notifiers which get connected to each added module.
00153      *
00154      * \param signal    the signal the notifier should get connected to
00155      * \param notifier  the notifier function
00156      */
00157     virtual void addDefaultNotifier( MODULE_SIGNAL signal, t_ModuleErrorSignalHandlerType notifier );
00158 
00159     /**
00160      * Add a specified notifier to the list of default notifiers which get connected to each added module.
00161      *
00162      * \param signal    the signal the notifier should get connected to
00163      * \param notifier  the notifier function
00164      */
00165     virtual void addDefaultNotifier( MODULE_SIGNAL signal, t_ModuleGenericSignalHandlerType notifier );
00166 
00167     /**
00168      * Add a specified notifier to the list of default notifiers which get connected to each added module. This is especially used for all the
00169      * connector related events like connect and disconnect.
00170      * \note This signal is only called for input connectors!
00171      *
00172      * \param signal    the signal the notifier should get connected to
00173      * \param notifier  the notifier function
00174      */
00175     virtual void addDefaultNotifier( MODULE_CONNECTOR_SIGNAL signal, t_GenericSignalHandlerType notifier );
00176 
00177     /**
00178      * Function combines two modules. This runs synchronously. It might take some time to finish since combination of modules is
00179      * allowed only with modules marked as "ready" which might take some time.
00180      *
00181      * \param applyOn the module which already has to be in the container and to apply the other one on.
00182      * \param what the prototype name of the module to apply on the other one specified.
00183      * \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
00184      *                not exist, the nothing will happen.
00185      *
00186      * \return the newly created module connected with the one specified in applyOn. If the prototype could not be found and tryOnly was set to
00187      *         true it will return NULL.
00188      */
00189     virtual boost::shared_ptr< WModule > applyModule( boost::shared_ptr< WModule > applyOn, std::string what, bool tryOnly = false );
00190 
00191     /**
00192      * Function combines two modules. This runs synchronously. It might take some time to finish since combination of modules is
00193      * allowed only with modules marked as "ready" which might take some time.
00194      *
00195      * \param applyOn the module which already has to be in the container and to apply the other one on.
00196      * \param prototype the prototype of the module to apply on the other one specified.
00197      *
00198      * \return the newly created module connected with the one specified in applyOn.
00199      */
00200     virtual boost::shared_ptr< WModule > applyModule( boost::shared_ptr< WModule > applyOn, boost::shared_ptr< WModule > prototype );
00201 
00202     /**
00203      * Load specified datasets. It immediately returns and starts another thread, which actually loads the data.
00204      *
00205      * \param filenames list of filenames to load. The registered notification handler for the root container will get notified on
00206      * error and success.
00207      * \param suppressColormaps if true, the data modules are instructed to avoid registration of colormaps. This can be very handy if you
00208      * combine multiple data loaders into one new data loader or data set
00209      *
00210      * \return the loader handling the load operation
00211      */
00212     WBatchLoader::SPtr loadDataSets( std::vector< std::string > filenames, bool suppressColormaps = false );
00213 
00214     /**
00215      * Loads the specified files synchronously. The returned batchloader can be queried for the list of data modules that have been added.
00216      *
00217      * \param filenames list of filenames to load. The registered notification handler for the root container will get notified on
00218      * error and success.
00219      * \param suppressColormaps if true, the data modules are instructed to avoid registration of colormaps. This can be very handy if you
00220      * combine multiple data loaders into one new data loader or data set
00221      *
00222      * \return the loader has handled the load operation
00223      */
00224     WBatchLoader::SPtr loadDataSetsSynchronously( std::vector< std::string > filenames, bool suppressColormaps = false );
00225 
00226     /**
00227      * Add the specified thread to the list of pending jobs. Only this ensures, that ALL pending threads get stopped before the
00228      * container gets stopped.
00229      *
00230      * \note use this to register threads whenever you start threads belonging to this container. This avoids shutting down the
00231      * container while other threads depend upon it.
00232      *
00233      * \param thread the thread to add
00234      */
00235     void addPendingThread( boost::shared_ptr< WThreadedRunner > thread );
00236 
00237     /**
00238      * The specified thread has finished and does not longer depend upon this container instance.
00239      *
00240      * \param thread the thread.
00241      */
00242     void finishedPendingThread( boost::shared_ptr< WThreadedRunner > thread );
00243 
00244     /**
00245      * Sets a flag denoting whether the container (which also is a module) should be marked as "crashed" if a nested module crashes.
00246      *
00247      * \param crashIfCrashed true if it also should crash.
00248      */
00249     void setCrashIfModuleCrashes( bool crashIfCrashed = true );
00250 
00251     /**
00252      * Due to the prototype design pattern used to build modules, this method returns a new instance of this method. NOTE: it
00253      * should never be initialized or modified in some other way. A simple new instance is required.
00254      *
00255      * \return the prototype used to create every module in OpenWalnut.
00256      */
00257     virtual boost::shared_ptr< WModule > factory() const;
00258 
00259     /**
00260      * Simple type for WDataModule pointer lists.
00261      */
00262     typedef std::set< boost::shared_ptr< WDataModule > > DataModuleListType;
00263 
00264     /**
00265      * Returns a vector of pointers to the loaded data modules in the container.
00266      *
00267      * \return the list of data modules.
00268      */
00269     DataModuleListType getDataModules();
00270 
00271     /**
00272      * Method returns a read ticket allowing read-access to the list of modules inside the container.
00273      * \note If done, ensure the ticket gets destroyed.
00274      *
00275      * \return the read ticket.
00276      */
00277     ModuleSharedContainerType::ReadTicket getModules() const;
00278 
00279     /**
00280      * Queries the container to find all modules with a given name. This can be useful to check for existence of certain modules inside the
00281      * container.
00282      *
00283      * \param name name of the modules to find
00284      *
00285      * \return the vector of modules. Empty if nothing was found.
00286      */
00287     ModuleVectorType getModules( std::string name ) const;
00288 
00289     /**
00290      * This method creates a list of combiner instances, for each possible connection that can be made between the specified module and the
00291      * module currently inside the container. It might be possible that a module which is contained in the returned list is not associated
00292      * anymore if the combiner gets applied.
00293      *
00294      * \param module the module to which the possible connections should be returned
00295      *
00296      * \return the possible combinations of connectors.
00297      */
00298     WCombinerTypes::WCompatiblesList getPossibleConnections( boost::shared_ptr< WModule > module );
00299 
00300 protected:
00301     /**
00302      * Entry point after loading the module. Runs in separate thread. The module container does not use this method. It simply
00303      * returns.
00304      */
00305     virtual void moduleMain();
00306 
00307     /**
00308      * The modules associated with this container.
00309      */
00310     ModuleSharedContainerType m_modules;
00311 
00312     /**
00313      * Name of the module.
00314      */
00315     std::string m_name;
00316 
00317     /**
00318      * Description of the module.
00319      */
00320     std::string m_description;
00321 
00322     /**
00323      * Lock for error notifiers set.
00324      */
00325     boost::shared_mutex m_errorNotifiersLock;
00326 
00327     /**
00328      * The error notifiers connected to added modules by default.
00329      */
00330     std::list< t_ModuleErrorSignalHandlerType > m_errorNotifiers;
00331 
00332     /**
00333      * Lock for ready notifiers set.
00334      */
00335     boost::shared_mutex m_readyNotifiersLock;
00336 
00337     /**
00338      * The ready notifiers connected to added modules by default.
00339      */
00340     std::list< t_ModuleGenericSignalHandlerType > m_readyNotifiers;
00341 
00342     /**
00343      * Lock for associated notifiers set.
00344      */
00345     boost::shared_mutex m_associatedNotifiersLock;
00346 
00347     /**
00348      * The notifiers connected to added modules by default and fired whenever the module got associated.
00349      */
00350     std::list< t_ModuleGenericSignalHandlerType > m_associatedNotifiers;
00351 
00352     /**
00353      * Lock for remove-notifiers set.
00354      */
00355     boost::shared_mutex m_removedNotifiersLock;
00356 
00357     /**
00358      * The notifiers connected to added modules by default and fired whenever the module got removed again.
00359      */
00360     std::list< t_ModuleGenericSignalHandlerType > m_removedNotifiers;
00361 
00362     /**
00363      * Lock for connector-notifiers set.
00364      */
00365     boost::shared_mutex m_connectorNotifiersLock;
00366 
00367     /**
00368      * The notifiers connected to added modules by default and fired whenever the module connectors got connected.
00369      */
00370     std::list< t_GenericSignalHandlerType > m_connectorEstablishedNotifiers;
00371 
00372     /**
00373      * The notifiers connected to added modules by default and fired whenever the module connectors got disconnected.
00374      */
00375     std::list< t_GenericSignalHandlerType > m_connectorClosedNotifiers;
00376 
00377     /**
00378      * Set of all threads that currently depend upon this container.
00379      */
00380     std::set< boost::shared_ptr< WThreadedRunner > > m_pendingThreads;
00381 
00382     /**
00383      * Lock for m_pendingThreads.
00384      */
00385     boost::shared_mutex m_pendingThreadsLock;
00386 
00387     /**
00388      * This method is called whenever a module inside the container crashes. By default, this method does nothing but forwarding the using
00389      * WModule's signals.
00390      *
00391      * \param module the module that has crashed.
00392      * \param exception the exception.
00393      */
00394     virtual void moduleError( boost::shared_ptr< WModule > module, const WException& exception );
00395 
00396     /**
00397      * This flag denotes whether the whole container should be marked as crashed if one of the contained modules crashes. By default, this is
00398      * true. The root container (the container not nested in any other container) sets this to false explicitly. Modules using the container to
00399      * encapsulate a whole bunch of modules can decide, but by default they crash too.
00400      */
00401     bool m_crashIfModuleCrashes;
00402 
00403 private:
00404     // the following typedefs are for convenience; to help accessing the container in a thread safe way.
00405 
00406     /**
00407      * A type for mapping a module to all its subscriptions
00408      */
00409     typedef std::pair< boost::shared_ptr< WModule >, boost::signals2::connection > ModuleSubscription;
00410 
00411     /**
00412      * For shortening: a type defining a shared vector of subscriptions a module made to a notifier during add().
00413      */
00414     typedef std::multimap< boost::shared_ptr< WModule >, boost::signals2::connection > ModuleSubscriptionsType;
00415 
00416     /**
00417      * The alias for a shared container.
00418      */
00419     typedef WSharedObject< ModuleSubscriptionsType > ModuleSubscriptionsSharedType;
00420 
00421     /**
00422      * The const iterator type of the container.
00423      */
00424     typedef ModuleSubscriptionsType::const_iterator ModuleSubscriptionsConstIterator;
00425 
00426     /**
00427      * The iterator type of the container.
00428      */
00429     typedef ModuleSubscriptionsType::iterator ModuleSubscriptionsIterator;
00430 
00431     /**
00432      * The module's signal subscriptions.
00433      */
00434     ModuleSubscriptionsSharedType m_moduleSubscriptions;
00435 };
00436 
00437 #endif  // WMODULECONTAINER_H
00438