OpenWalnut  1.4.0
WModuleFactory.cpp
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 #include <algorithm>
26 #include <iostream>
27 #include <set>
28 #include <string>
29 #include <typeinfo>
30 #include <vector>
31 
32 #include "../common/WLogger.h"
33 #include "combiner/WApplyCombiner.h"
34 #include "exceptions/WPrototypeNotUnique.h"
35 #include "exceptions/WPrototypeUnknown.h"
36 #include "WModule.h"
37 #include "WModuleCombiner.h"
38 #include "WModuleFactory.h"
39 
40 // factory instance as singleton
41 boost::shared_ptr< WModuleFactory > WModuleFactory::m_instance = boost::shared_ptr< WModuleFactory >();
42 
44  m_prototypes(),
45  m_moduleLoader( new WModuleLoader() )
46 {
47  // initialize members
48 }
49 
51 {
52  // cleanup
53 }
54 
55 boost::shared_ptr< WModuleLoader > WModuleFactory::getModuleLoader()
56 {
57  return WModuleFactory::getModuleFactory()->m_moduleLoader;
58 }
59 
61 {
62  // load modules
63  WLogger::getLogger()->addLogMessage( "Loading Modules", "ModuleFactory", LL_INFO );
64 
65  // operation must be exclusive
67 
68  // Load the dynamic modules here:
69  m_moduleLoader->load( l );
70 
71  // initialize every module in the set
72  std::set< std::string > names; // helper to find duplicates
73  PrototypeContainerIteratorType listIter = l->get().begin();
74  while( listIter != l->get().end() )
75  {
76  WLogger::getLogger()->addLogMessage( "Initializing module prototype: \"" + ( *listIter )->getName() + "\"", "ModuleFactory", LL_DEBUG );
77 
78  // that should not happen. Names should not occur multiple times since they are unique
79  if( names.count( ( *listIter )->getName() ) )
80  {
81  WLogger::getLogger()->addLogMessage( std::string( "Module \"" + ( *listIter )->getName() +
82  "\" is not unique. Modules have to have a unique name. Ignoring this module." ),
83  "ModuleFactory", LL_ERROR );
84  // we remove the module from the prototype list
85  l->get().erase( listIter++ );
86  continue;
87  }
88  else
89  {
90  names.insert( ( *listIter )->getName() );
91  initializeModule( ( *listIter ) );
92  ++listIter;
93  }
94  }
95  WLogger::getLogger()->addLogMessage( "Loading Modules Done", "ModuleFactory", LL_INFO );
96 }
97 
98 bool WModuleFactory::isPrototype( boost::shared_ptr< WModule > module )
99 {
100  // for this a read lock is sufficient, gets unlocked if it looses scope
101  PrototypeSharedContainerType::ReadTicket l = getModuleFactory()->m_prototypes.getReadTicket();
102  return getModuleFactory()->checkPrototype( module, l );
103 }
104 
105 bool WModuleFactory::checkPrototype( boost::shared_ptr< WModule > module, PrototypeSharedContainerType::ReadTicket ticket )
106 {
107  return ( ticket->get().count( module ) != 0 );
108 }
109 
110 boost::shared_ptr< WModule > WModuleFactory::create( boost::shared_ptr< WModule > prototype, std::string uuid )
111 {
112  wlog::debug( "ModuleFactory" ) << "Creating new instance of prototype \"" << prototype->getName() << "\".";
113 
114  // for this a read lock is sufficient, gets unlocked if it looses scope
116 
117  // ensure this one is a prototype and nothing else
118  if( !checkPrototype( prototype, l ) )
119  {
120  throw WPrototypeUnknown( std::string( "Could not clone module \"" + prototype->getName() + "\" since it is no prototype." ) );
121  }
122 
123  // explicitly unlock
124  l.reset();
125 
126  // call prototypes factory function
127  boost::shared_ptr< WModule > clone = boost::shared_ptr< WModule >( prototype->factory() );
128  // set uuid and keep track of it
129  clone->setUUID( uuid );
130  m_uuidModuleMap.insert( UuidModuleMap::value_type( clone->getUUID(), clone ) );
131 
132  // init module
133  clone->setLocalPath( prototype->getLocalPath() ); // prototype and clone have the same local path.
134  initializeModule( clone );
135 
136  return clone;
137 }
138 
139 void WModuleFactory::initializeModule( boost::shared_ptr< WModule > module )
140 {
141  module->initialize();
142 }
143 
144 boost::shared_ptr< WModuleFactory > WModuleFactory::getModuleFactory()
145 {
146  if( !m_instance )
147  {
148  m_instance = boost::shared_ptr< WModuleFactory >( new WModuleFactory() );
149  }
150 
151  return m_instance;
152 }
153 
154 
155 const boost::shared_ptr< WModule > WModuleFactory::isPrototypeAvailable( std::string name )
156 {
157  // for this a read lock is sufficient, gets unlocked if it looses scope
159 
160  // find first and only prototype (ensured during load())
161  boost::shared_ptr< WModule > ret = boost::shared_ptr< WModule >();
162  for( std::set< boost::shared_ptr< WModule > >::const_iterator listIter = l->get().begin(); listIter != l->get().end();
163  ++listIter )
164  {
165  if( ( *listIter )->getName() == name )
166  {
167  ret = ( *listIter );
168  break;
169  }
170  }
171 
172  return ret;
173 }
174 
175 const boost::shared_ptr< WModule > WModuleFactory::getPrototypeByName( std::string name )
176 {
177  boost::shared_ptr< WModule > ret = isPrototypeAvailable( name );
178 
179  // if not found -> throw
180  if( ret == boost::shared_ptr< WModule >() )
181  {
182  throw WPrototypeUnknown( std::string( "Could not find prototype \"" + name + "\"." ) );
183  }
184 
185  return ret;
186 }
187 
188 const boost::shared_ptr< WModule > WModuleFactory::getPrototypeByInstance( boost::shared_ptr< WModule > instance )
189 {
190  return getPrototypeByName( instance->getName() );
191 }
192 
193 std::vector< WModule::ConstSPtr > WModuleFactory::getPrototypesByType( MODULE_TYPE type )
194 {
195  std::vector< WModule::ConstSPtr > ret;
196 
197  // for this a read lock is sufficient, gets unlocked if it looses scope
199 
200  // find first and only prototype (ensured during load())
201  for( std::set< boost::shared_ptr< WModule > >::const_iterator listIter = l->get().begin(); listIter != l->get().end();
202  ++listIter )
203  {
204  if( ( *listIter )->getType() == type )
205  {
206  ret.push_back( *listIter );
207  }
208  }
209 
210  return ret;
211 }
212 
214 {
215  return m_prototypes.getReadTicket();
216 }
217 
218 WCombinerTypes::WCompatiblesList WModuleFactory::getCompatiblePrototypes( boost::shared_ptr< WModule > module )
219 {
220  WCombinerTypes::WCompatiblesList compatibles;
221 
222  // for this a read lock is sufficient, gets unlocked if it looses scope
224 
225  // has the module an output? If not, return.
226  bool addModulesWithoutInput = !module;
227 
228  if( addModulesWithoutInput )
229  {
230  // First, add all modules with no input connector.
231  for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
232  ++listIter )
233  {
234  // get connectors of this prototype
235  WModule::InputConnectorList pcons = ( *listIter )->getInputConnectors();
236  if( pcons.size() == 0 )
237  {
238  // the modules which match every time need their own groups
239  WCombinerTypes::WOneToOneCombiners lComp;
240 
241  // NOTE: it is OK here to use the variable module even if it is NULL as the combiner in this case only adds the specified module
242  lComp.push_back( boost::shared_ptr< WApplyCombiner >( new WApplyCombiner( module, "", *listIter, "" ) ) );
243 
244  // add this list
245  compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
246  }
247  }
248  }
249 
250  // if NULL was specified, only return all modules without any inputs
251  if( module )
252  {
253  // go through every prototype
254  for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
255  ++listIter )
256  {
257  WCombinerTypes::WOneToOneCombiners lComp = WApplyCombiner::createCombinerList< WApplyCombiner >( module, ( *listIter ) );
258 
259  // add the group
260  if( lComp.size() != 0 )
261  {
262  compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
263  }
264  }
265  }
266 
267  // unlock. No locking needed for further steps.
268  l.reset();
269 
270  // sort the compatibles
271  std::sort( compatibles.begin(), compatibles.end(), WCombinerTypes::compatiblesSort );
272 
273  return compatibles;
274 }
275 
276 WCombinerTypes::WCompatiblesList WModuleFactory::getAllPrototypes()
277 {
278  WCombinerTypes::WCompatiblesList compatibles;
279 
280  // for this a read lock is sufficient, gets unlocked if it looses scope
282 
283  // Add all modules.
284  for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
285  ++listIter )
286  {
287  // the modules which match every time need their own groups
288  WCombinerTypes::WOneToOneCombiners lComp;
289 
290  // NOTE: it is OK here to use the variable module even if it is NULL as the combiner in this case only adds the specified module
291  lComp.push_back( boost::shared_ptr< WApplyCombiner >( new WApplyCombiner( *listIter ) ) );
292 
293  // add this list
294  compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
295  }
296 
297  // unlock. No locking needed for further steps.
298  l.reset();
299 
300  // sort the compatibles
301  std::sort( compatibles.begin(), compatibles.end(), WCombinerTypes::compatiblesSort );
302 
303  return compatibles;
304 }
305 
307 {
308  SPtr f = getModuleFactory();
309  // unlocked upon destruction
311 
312  // find
313  UuidModuleMap::const_iterator it = r->get().find( uuid );
314  if( it != r->get().end() )
315  {
316  // found. Return locked weak_ptr.
317  boost::weak_ptr< WModule > m = ( *it ).second;
318  return m.lock();
319  }
320  else
321  {
322  return WModule::SPtr();
323  }
324 }
325 
boost::shared_ptr< WSharedObjectTicketWrite< PrototypeContainerType > > WriteTicket
Type for write tickets.
Definition: WSharedObject.h:67
const boost::shared_ptr< WModule > getPrototypeByInstance(boost::shared_ptr< WModule > instance)
Finds a prototype using an instance of a module.
const boost::shared_ptr< WModule > getPrototypeByName(std::string name)
Finds a prototype using the specified name.
WCombinerTypes::WCompatiblesList getAllPrototypes()
Creates a list of WApplyCombiner for all modules known by the factory.
std::set< boost::shared_ptr< WModule > >::iterator PrototypeContainerIteratorType
Iterator for the prototype set.
static boost::shared_ptr< WModuleFactory > m_instance
Singleton instance of WModuleFactory.
boost::shared_ptr< WModule > create(boost::shared_ptr< WModule > prototype, std::string uuid="")
Create a new and initialized module using the specified prototype.
std::pair< Iterator, bool > insert(const value_type &x)
Inserts the specified element.
Loads module prototypes from shared objects in a given directory and injects it into the module facto...
Definition: WModuleLoader.h:43
static WLogger * getLogger()
Returns pointer to the currently running logger instance.
Definition: WLogger.cpp:64
void addLogMessage(std::string message, std::string source="", LogLevel level=LL_DEBUG)
Appends a log message to the logging queue.
Definition: WLogger.cpp:84
static bool isPrototype(boost::shared_ptr< WModule > module)
Checks whether the specified module is a prototype or an instantiated module.
WModuleLoader::SPtr m_moduleLoader
Loader class managing dynamically loaded modules in OpenWalnut.
static boost::shared_ptr< WModuleLoader > getModuleLoader()
Returns instance of the module loader.
static WModule::SPtr findByUUID(std::string uuid)
Find a module instance by UUID.
ReadTicket getReadTicket() const
Returns a ticket to get read access to the contained data.
boost::shared_ptr< WModuleFactory > SPtr
Shared pointer to a WModule.
PrototypeSharedContainerType::ReadTicket getPrototypes() const
This method gives read access to the list of all prototypes.
WriteTicket getWriteTicket(bool suppressNotify=false) const
Returns a ticket to get write access to the contained data.
virtual ~WModuleFactory()
Destructor.
WModuleFactory()
Constructors are protected because this is a Singleton.
boost::shared_ptr< WModule > SPtr
Shared pointer to a WModule.
Definition: WModule.h:109
static SPtr getModuleFactory()
Returns instance of the module factory to use to create modules.
static void initializeModule(boost::shared_ptr< WModule > module)
This method uses a newly created instance of WModule and initializes it properly. ...
std::vector< WModule::ConstSPtr > getPrototypesByType(MODULE_TYPE type)
Finds a prototype using an type.
std::vector< boost::shared_ptr< WModuleInputConnector > > InputConnectorList
The type for the list of input connectors.
Definition: WModule.h:99
This class provides a common interface for thread-safe access to associative containers (set...
std::set< boost::shared_ptr< WModule > >::const_iterator PrototypeContainerConstIteratorType
Const iterator for the prototype set.
Base class for all combiners which apply one connection between two connectors of two modules...
Thrown whenever an unknown prototype is specified.
WSharedAssociativeContainer< UuidModuleMap > m_uuidModuleMap
Keep track of uuids of each created module.
void load()
Loads the modules and creates prototypes.
PrototypeSharedContainerType m_prototypes
The module prototypes available.
const boost::shared_ptr< WModule > isPrototypeAvailable(std::string name)
Searches a prototype by name.
bool checkPrototype(boost::shared_ptr< WModule > module, PrototypeSharedContainerType::ReadTicket ticket)
Checks whether the specified module is a prototype or an instantiated module.
WStreamedLogger debug(const std::string &source)
Logging a debug message.
Definition: WLogger.h:331
boost::shared_ptr< WSharedObjectTicketRead< PrototypeContainerType > > ReadTicket
Type for read tickets.
Definition: WSharedObject.h:62
WCombinerTypes::WCompatiblesList getCompatiblePrototypes(boost::shared_ptr< WModule > module=boost::shared_ptr< WModule >())
Returns a set of module combiners with module combinations compatible with the specified one...