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