OpenWalnut 1.2.5

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