OpenWalnut  1.2.5
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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( m_prototypeAccess );
65 
66  // unlock as read lock is sufficient for the further steps
67  m_prototypeAccess.reset();
68 
69  // for this a read lock is sufficient, gets unlocked if it looses scope
71 
72  // initialize every module in the set
73  std::set< std::string > names; // helper to find duplicates
74  for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
75  ++listIter )
76  {
77  WLogger::getLogger()->addLogMessage( "Initializing module prototype: \"" + ( *listIter )->getName() + "\"", "ModuleFactory", LL_DEBUG );
78 
79  // that should not happen. Names should not occur multiple times since they are unique
80  if( names.count( ( *listIter )->getName() ) )
81  {
82  throw WPrototypeNotUnique( std::string( "Module \"" + ( *listIter )->getName()
83  + "\" is not unique. Modules have to have a unique name." ) );
84  }
85  names.insert( ( *listIter )->getName() );
86 
87  initializeModule( ( *listIter ) );
88  }
89 }
90 
91 bool WModuleFactory::isPrototype( boost::shared_ptr< WModule > module )
92 {
93  // for this a read lock is sufficient, gets unlocked if it looses scope
94  PrototypeSharedContainerType::ReadTicket l = getModuleFactory()->m_prototypes.getReadTicket();
95  return getModuleFactory()->checkPrototype( module, l );
96 }
97 
98 bool WModuleFactory::checkPrototype( boost::shared_ptr< WModule > module, PrototypeSharedContainerType::ReadTicket ticket )
99 {
100  return ( ticket->get().count( module ) != 0 );
101 }
102 
103 boost::shared_ptr< WModule > WModuleFactory::create( boost::shared_ptr< WModule > prototype )
104 {
105  wlog::debug( "ModuleFactory" ) << "Creating new instance of prototype \"" << prototype->getName() << "\".";
106 
107  // for this a read lock is sufficient, gets unlocked if it looses scope
109 
110  // ensure this one is a prototype and nothing else
111  if( !checkPrototype( prototype, l ) )
112  {
113  throw WPrototypeUnknown( std::string( "Could not clone module \"" + prototype->getName() + "\" since it is no prototype." ) );
114  }
115 
116  // explicitly unlock
117  l.reset();
118 
119  // call prototypes factory function
120  boost::shared_ptr< WModule > clone = boost::shared_ptr< WModule >( prototype->factory() );
121  clone->setLocalPath( prototype->getLocalPath() ); // prototype and clone have the same local path.
122  initializeModule( clone );
123 
124  return clone;
125 }
126 
127 void WModuleFactory::initializeModule( boost::shared_ptr< WModule > module )
128 {
129  module->initialize();
130 }
131 
132 boost::shared_ptr< WModuleFactory > WModuleFactory::getModuleFactory()
133 {
134  if( !m_instance )
135  {
136  m_instance = boost::shared_ptr< WModuleFactory >( new WModuleFactory() );
137  }
138 
139  return m_instance;
140 }
141 
142 
143 const boost::shared_ptr< WModule > WModuleFactory::isPrototypeAvailable( std::string name )
144 {
145  // for this a read lock is sufficient, gets unlocked if it looses scope
147 
148  // find first and only prototype (ensured during load())
149  boost::shared_ptr< WModule > ret = boost::shared_ptr< WModule >();
150  for( std::set< boost::shared_ptr< WModule > >::const_iterator listIter = l->get().begin(); listIter != l->get().end();
151  ++listIter )
152  {
153  if( ( *listIter )->getName() == name )
154  {
155  ret = ( *listIter );
156  break;
157  }
158  }
159 
160  return ret;
161 }
162 
163 const boost::shared_ptr< WModule > WModuleFactory::getPrototypeByName( std::string name )
164 {
165  boost::shared_ptr< WModule > ret = isPrototypeAvailable( name );
166 
167  // if not found -> throw
168  if( ret == boost::shared_ptr< WModule >() )
169  {
170  throw WPrototypeUnknown( std::string( "Could not find prototype \"" + name + "\"." ) );
171  }
172 
173  return ret;
174 }
175 
176 const boost::shared_ptr< WModule > WModuleFactory::getPrototypeByInstance( boost::shared_ptr< WModule > instance )
177 {
178  return getPrototypeByName( instance->getName() );
179 }
180 
181 std::vector< WModule::ConstSPtr > WModuleFactory::getPrototypesByType( MODULE_TYPE type )
182 {
183  std::vector< WModule::ConstSPtr > ret;
184 
185  // for this a read lock is sufficient, gets unlocked if it looses scope
187 
188  // find first and only prototype (ensured during load())
189  for( std::set< boost::shared_ptr< WModule > >::const_iterator listIter = l->get().begin(); listIter != l->get().end();
190  ++listIter )
191  {
192  if( ( *listIter )->getType() == type )
193  {
194  ret.push_back( *listIter );
195  }
196  }
197 
198  return ret;
199 }
200 
202 {
203  return m_prototypes.getReadTicket();
204 }
205 
206 WCombinerTypes::WCompatiblesList WModuleFactory::getCompatiblePrototypes( boost::shared_ptr< WModule > module )
207 {
208  WCombinerTypes::WCompatiblesList compatibles;
209 
210  // for this a read lock is sufficient, gets unlocked if it looses scope
212 
213  // First, add all modules with no input connector.
214  for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
215  ++listIter )
216  {
217  // get connectors of this prototype
218  WModule::InputConnectorList pcons = ( *listIter )->getInputConnectors();
219  if( pcons.size() == 0 )
220  {
221  // the modules which match every time need their own groups
222  WCombinerTypes::WOneToOneCombiners lComp;
223 
224  // 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
225  lComp.push_back( boost::shared_ptr< WApplyCombiner >( new WApplyCombiner( module, "", *listIter, "" ) ) );
226 
227  // add this list
228  compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
229  }
230  }
231 
232  // if NULL was specified, only return all modules without any inputs
233  if( module )
234  {
235  // go through every prototype
236  for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
237  ++listIter )
238  {
239  WCombinerTypes::WOneToOneCombiners lComp = WApplyCombiner::createCombinerList< WApplyCombiner >( module, ( *listIter ) );
240 
241  // add the group
242  if( lComp.size() != 0 )
243  {
244  compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
245  }
246  }
247  }
248 
249  // unlock. No locking needed for further steps.
250  l.reset();
251 
252  // sort the compatibles
253  std::sort( compatibles.begin(), compatibles.end(), WCombinerTypes::compatiblesSort );
254 
255  return compatibles;
256 }