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