OpenWalnut  1.3.1
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()
46 {
47  // initialize members
48 }
49 
51 {
52  // cleanup
53 }
54 
56 {
57  // load modules
58  WLogger::getLogger()->addLogMessage( "Loading Modules", "ModuleFactory", LL_INFO );
59 
60  // operation must be exclusive
62 
63  // Load the dynamic modules here:
64  m_moduleLoader.load( l );
65 
66  // initialize every module in the set
67  std::set< std::string > names; // helper to find duplicates
68  PrototypeContainerIteratorType listIter = l->get().begin();
69  while( listIter != l->get().end() )
70  {
71  WLogger::getLogger()->addLogMessage( "Initializing module prototype: \"" + ( *listIter )->getName() + "\"", "ModuleFactory", LL_DEBUG );
72 
73  // that should not happen. Names should not occur multiple times since they are unique
74  if( names.count( ( *listIter )->getName() ) )
75  {
76  WLogger::getLogger()->addLogMessage( std::string( "Module \"" + ( *listIter )->getName() +
77  "\" is not unique. Modules have to have a unique name. Ignoring this module." ),
78  "ModuleFactory", LL_ERROR );
79  // we remove the module from the prototype list
80  l->get().erase( listIter++ );
81  continue;
82  }
83  else
84  {
85  names.insert( ( *listIter )->getName() );
86  initializeModule( ( *listIter ) );
87  ++listIter;
88  }
89  }
90  WLogger::getLogger()->addLogMessage( "Loading Modules Done", "ModuleFactory", LL_INFO );
91 }
92 
93 bool WModuleFactory::isPrototype( boost::shared_ptr< WModule > module )
94 {
95  // for this a read lock is sufficient, gets unlocked if it looses scope
96  PrototypeSharedContainerType::ReadTicket l = getModuleFactory()->m_prototypes.getReadTicket();
97  return getModuleFactory()->checkPrototype( module, l );
98 }
99 
100 bool WModuleFactory::checkPrototype( boost::shared_ptr< WModule > module, PrototypeSharedContainerType::ReadTicket ticket )
101 {
102  return ( ticket->get().count( module ) != 0 );
103 }
104 
105 boost::shared_ptr< WModule > WModuleFactory::create( boost::shared_ptr< WModule > prototype )
106 {
107  wlog::debug( "ModuleFactory" ) << "Creating new instance of prototype \"" << prototype->getName() << "\".";
108 
109  // for this a read lock is sufficient, gets unlocked if it looses scope
111 
112  // ensure this one is a prototype and nothing else
113  if( !checkPrototype( prototype, l ) )
114  {
115  throw WPrototypeUnknown( std::string( "Could not clone module \"" + prototype->getName() + "\" since it is no prototype." ) );
116  }
117 
118  // explicitly unlock
119  l.reset();
120 
121  // call prototypes factory function
122  boost::shared_ptr< WModule > clone = boost::shared_ptr< WModule >( prototype->factory() );
123  clone->setLocalPath( prototype->getLocalPath() ); // prototype and clone have the same local path.
124  initializeModule( clone );
125 
126  return clone;
127 }
128 
129 void WModuleFactory::initializeModule( boost::shared_ptr< WModule > module )
130 {
131  module->initialize();
132 }
133 
134 boost::shared_ptr< WModuleFactory > WModuleFactory::getModuleFactory()
135 {
136  if( !m_instance )
137  {
138  m_instance = boost::shared_ptr< WModuleFactory >( new WModuleFactory() );
139  }
140 
141  return m_instance;
142 }
143 
144 
145 const boost::shared_ptr< WModule > WModuleFactory::isPrototypeAvailable( std::string name )
146 {
147  // for this a read lock is sufficient, gets unlocked if it looses scope
149 
150  // find first and only prototype (ensured during load())
151  boost::shared_ptr< WModule > ret = boost::shared_ptr< WModule >();
152  for( std::set< boost::shared_ptr< WModule > >::const_iterator listIter = l->get().begin(); listIter != l->get().end();
153  ++listIter )
154  {
155  if( ( *listIter )->getName() == name )
156  {
157  ret = ( *listIter );
158  break;
159  }
160  }
161 
162  return ret;
163 }
164 
165 const boost::shared_ptr< WModule > WModuleFactory::getPrototypeByName( std::string name )
166 {
167  boost::shared_ptr< WModule > ret = isPrototypeAvailable( name );
168 
169  // if not found -> throw
170  if( ret == boost::shared_ptr< WModule >() )
171  {
172  throw WPrototypeUnknown( std::string( "Could not find prototype \"" + name + "\"." ) );
173  }
174 
175  return ret;
176 }
177 
178 const boost::shared_ptr< WModule > WModuleFactory::getPrototypeByInstance( boost::shared_ptr< WModule > instance )
179 {
180  return getPrototypeByName( instance->getName() );
181 }
182 
183 std::vector< WModule::ConstSPtr > WModuleFactory::getPrototypesByType( MODULE_TYPE type )
184 {
185  std::vector< WModule::ConstSPtr > ret;
186 
187  // for this a read lock is sufficient, gets unlocked if it looses scope
189 
190  // find first and only prototype (ensured during load())
191  for( std::set< boost::shared_ptr< WModule > >::const_iterator listIter = l->get().begin(); listIter != l->get().end();
192  ++listIter )
193  {
194  if( ( *listIter )->getType() == type )
195  {
196  ret.push_back( *listIter );
197  }
198  }
199 
200  return ret;
201 }
202 
204 {
205  return m_prototypes.getReadTicket();
206 }
207 
208 WCombinerTypes::WCompatiblesList WModuleFactory::getCompatiblePrototypes( boost::shared_ptr< WModule > module )
209 {
210  WCombinerTypes::WCompatiblesList compatibles;
211 
212  // for this a read lock is sufficient, gets unlocked if it looses scope
214 
215  // has the module an output? If not, return.
216  bool addModulesWithoutInput = !module;
217 
218  if( addModulesWithoutInput )
219  {
220  // First, add all modules with no input connector.
221  for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
222  ++listIter )
223  {
224  // get connectors of this prototype
225  WModule::InputConnectorList pcons = ( *listIter )->getInputConnectors();
226  if( pcons.size() == 0 )
227  {
228  // the modules which match every time need their own groups
229  WCombinerTypes::WOneToOneCombiners lComp;
230 
231  // 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
232  lComp.push_back( boost::shared_ptr< WApplyCombiner >( new WApplyCombiner( module, "", *listIter, "" ) ) );
233 
234  // add this list
235  compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
236  }
237  }
238  }
239 
240  // if NULL was specified, only return all modules without any inputs
241  if( module )
242  {
243  // go through every prototype
244  for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
245  ++listIter )
246  {
247  WCombinerTypes::WOneToOneCombiners lComp = WApplyCombiner::createCombinerList< WApplyCombiner >( module, ( *listIter ) );
248 
249  // add the group
250  if( lComp.size() != 0 )
251  {
252  compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
253  }
254  }
255  }
256 
257  // unlock. No locking needed for further steps.
258  l.reset();
259 
260  // sort the compatibles
261  std::sort( compatibles.begin(), compatibles.end(), WCombinerTypes::compatiblesSort );
262 
263  return compatibles;
264 }
265 
266 WCombinerTypes::WCompatiblesList WModuleFactory::getAllPrototypes()
267 {
268  WCombinerTypes::WCompatiblesList compatibles;
269 
270  // for this a read lock is sufficient, gets unlocked if it looses scope
272 
273  // Add all modules.
274  for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
275  ++listIter )
276  {
277  // the modules which match every time need their own groups
278  WCombinerTypes::WOneToOneCombiners lComp;
279 
280  // 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
281  lComp.push_back( boost::shared_ptr< WApplyCombiner >( new WApplyCombiner( *listIter ) ) );
282 
283  // add this list
284  compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
285  }
286 
287  // unlock. No locking needed for further steps.
288  l.reset();
289 
290  // sort the compatibles
291  std::sort( compatibles.begin(), compatibles.end(), WCombinerTypes::compatiblesSort );
292 
293  return compatibles;
294 }
295