WModuleFactory.cpp 8.28 KB
Newer Older
1 2
//---------------------------------------------------------------------------
//
ledig's avatar
ledig committed
3
// Project: OpenWalnut ( http://www.openwalnut.org )
4
//
ledig's avatar
ledig committed
5 6
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
7
//
ledig's avatar
ledig committed
8
// This file is part of OpenWalnut.
9
//
ledig's avatar
ledig committed
10 11 12 13
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
14
//
ledig's avatar
ledig committed
15 16 17 18
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
19
//
ledig's avatar
ledig committed
20 21
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 23 24
//
//---------------------------------------------------------------------------

ledig's avatar
ledig committed
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
#include <algorithm>
#include <iostream>
#include <set>
#include <string>
#include <typeinfo>
#include <vector>

#include "WModule.h"
#include "WModuleCombiner.h"
#include "../common/WLogger.h"
#include "combiner/WApplyCombiner.h"
#include "exceptions/WPrototypeNotUnique.h"
#include "exceptions/WPrototypeUnknown.h"
#include "WModuleFactory.h"

// factory instance as singleton
boost::shared_ptr< WModuleFactory > WModuleFactory::m_instance = boost::shared_ptr< WModuleFactory >();
42

43
WModuleFactory::WModuleFactory():
44
    m_prototypes(),
45
    m_moduleLoader()
46
{
ledig's avatar
ledig committed
47
    // initialize members
48 49 50 51
}

WModuleFactory::~WModuleFactory()
{
ledig's avatar
ledig committed
52
    // cleanup
53 54
}

55 56 57
void WModuleFactory::load()
{
    // load modules
ledig's avatar
ledig committed
58 59 60 61 62
    WLogger::getLogger()->addLogMessage( "Loading Modules", "ModuleFactory", LL_INFO );

    // operation must be exclusive
    PrototypeSharedContainerType::WriteTicket m_prototypeAccess = m_prototypes.getWriteTicket();

63
    // These modules need to be added by hand. They are special, obviously.
ledig's avatar
ledig committed
64 65 66
    m_prototypeAccess->get().insert( boost::shared_ptr< WModule >( new WMData() ) );
    m_prototypeAccess->get().insert( boost::shared_ptr< WModule >( new WMFiberDisplay() ) );
    m_prototypeAccess->get().insert( boost::shared_ptr< WModule >( new WMNavSlices() ) );
67

68 69
    // Load the dynamic modules here:
    m_moduleLoader.load( m_prototypeAccess );
ledig's avatar
ledig committed
70 71

    // unlock as read lock is sufficient for the further steps
72
    m_prototypeAccess.reset();
73

ledig's avatar
ledig committed
74 75 76 77 78 79
    // for this a read lock is sufficient, gets unlocked if it looses scope
    PrototypeSharedContainerType::ReadTicket l = m_prototypes.getReadTicket();

    // initialize every module in the set
    std::set< std::string > names;  // helper to find duplicates
    for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
80
            ++listIter )
81
    {
82
        WLogger::getLogger()->addLogMessage( "Initializing module prototype: \"" + ( *listIter )->getName() + "\"", "ModuleFactory", LL_INFO );
ledig's avatar
ledig committed
83 84 85

        // that should not happen. Names should not occur multiple times since they are unique
        if ( names.count( ( *listIter )->getName() ) )
86
        {
ledig's avatar
ledig committed
87
            throw WPrototypeNotUnique( "Module \"" + ( *listIter )->getName() + "\" is not unique. Modules have to have a unique name." );
88
        }
ledig's avatar
ledig committed
89
        names.insert( ( *listIter )->getName() );
90

ledig's avatar
ledig committed
91
        initializeModule( ( *listIter ) );
92 93 94
    }
}

95 96
bool WModuleFactory::isPrototype( boost::shared_ptr< WModule > module )
{
ledig's avatar
ledig committed
97 98 99
    // for this a read lock is sufficient, gets unlocked if it looses scope
    PrototypeSharedContainerType::ReadTicket l = getModuleFactory()->m_prototypes.getReadTicket();
    return getModuleFactory()->checkPrototype( module, l );
100 101
}

ledig's avatar
ledig committed
102
bool WModuleFactory::checkPrototype( boost::shared_ptr< WModule > module, PrototypeSharedContainerType::ReadTicket ticket )
103
{
ledig's avatar
ledig committed
104
    return ( ticket->get().count( module ) != 0 );
105 106
}

107 108
boost::shared_ptr< WModule > WModuleFactory::create( boost::shared_ptr< WModule > prototype )
{
ledig's avatar
ledig committed
109 110 111 112 113 114
    wlog::debug( "ModuleFactory" ) << "Creating new instance of prototype \"" << prototype->getName() << "\".";

    // for this a read lock is sufficient, gets unlocked if it looses scope
    PrototypeSharedContainerType::ReadTicket l = m_prototypes.getReadTicket();

    // ensure this one is a prototype and nothing else
115
    if ( !checkPrototype( prototype, l ) )
116
    {
ledig's avatar
ledig committed
117
        throw WPrototypeUnknown( "Could not clone module \"" + prototype->getName() + "\" since it is no prototype." );
118 119
    }

ledig's avatar
ledig committed
120
    // explicitly unlock
121
    l.reset();
122

ledig's avatar
ledig committed
123 124 125
    // call prototypes factory function
    boost::shared_ptr< WModule > clone = boost::shared_ptr< WModule >( prototype->factory() );
    initializeModule( clone );
ledig's avatar
ledig committed
126

ledig's avatar
ledig committed
127
    return clone;
128 129
}

ledig's avatar
ledig committed
130
void WModuleFactory::initializeModule( boost::shared_ptr< WModule > module )
131
{
ledig's avatar
ledig committed
132
    module->initialize();
133 134
}

135 136
boost::shared_ptr< WModuleFactory > WModuleFactory::getModuleFactory()
{
ledig's avatar
ledig committed
137
    if ( !m_instance )
138
    {
ledig's avatar
ledig committed
139
        m_instance = boost::shared_ptr< WModuleFactory >( new WModuleFactory() );
140 141
    }

ledig's avatar
ledig committed
142
    return m_instance;
143 144
}

145

ledig's avatar
ledig committed
146
const boost::shared_ptr< WModule > WModuleFactory::isPrototypeAvailable( std::string name )
147
{
ledig's avatar
ledig committed
148 149 150 151
    // for this a read lock is sufficient, gets unlocked if it looses scope
    PrototypeSharedContainerType::ReadTicket l = m_prototypes.getReadTicket();

    // find first and only prototype (ensured during load())
152
    boost::shared_ptr< WModule > ret = boost::shared_ptr< WModule >();
ledig's avatar
ledig committed
153
    for( std::set< boost::shared_ptr< WModule > >::const_iterator listIter = l->get().begin(); listIter != l->get().end();
154 155
            ++listIter )
    {
ledig's avatar
ledig committed
156
        if ( ( *listIter )->getName() == name )
157 158 159 160 161 162
        {
            ret = ( *listIter );
            break;
        }
    }

ledig's avatar
ledig committed
163
    return ret;
164 165
}

ledig's avatar
ledig committed
166
const boost::shared_ptr< WModule > WModuleFactory::getPrototypeByName( std::string name )
167
{
ledig's avatar
ledig committed
168
    boost::shared_ptr< WModule > ret = isPrototypeAvailable( name );
169

ledig's avatar
ledig committed
170
    // if not found -> throw
171 172
    if ( ret == boost::shared_ptr< WModule >() )
    {
ledig's avatar
ledig committed
173
        throw WPrototypeUnknown( "Could not find prototype \"" + name + "\"." );
174 175
    }

ledig's avatar
ledig committed
176
    return ret;
177 178
}

ledig's avatar
ledig committed
179
const boost::shared_ptr< WModule > WModuleFactory::getPrototypeByInstance( boost::shared_ptr< WModule > instance )
180
{
ledig's avatar
ledig committed
181
    return getPrototypeByName( instance->getName() );
182 183
}

ledig's avatar
ledig committed
184
WModuleFactory::PrototypeSharedContainerType::ReadTicket WModuleFactory::getPrototypes() const
185
{
ledig's avatar
ledig committed
186
    return m_prototypes.getReadTicket();
187 188
}

ledig's avatar
ledig committed
189
WCombinerTypes::WCompatiblesList WModuleFactory::getCompatiblePrototypes( boost::shared_ptr< WModule > module )
190
{
ledig's avatar
ledig committed
191
    WCombinerTypes::WCompatiblesList compatibles;
ledig's avatar
ledig committed
192

ledig's avatar
ledig committed
193 194
    // for this a read lock is sufficient, gets unlocked if it looses scope
    PrototypeSharedContainerType::ReadTicket l = m_prototypes.getReadTicket();
ledig's avatar
ledig committed
195

ledig's avatar
ledig committed
196 197 198 199 200 201 202
    // First, add all modules with no input connector.
    for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
            ++listIter )
    {
        // get connectors of this prototype
        WModule::InputConnectorList pcons = ( *listIter )->getInputConnectors();
        if(  pcons.size() == 0  )
ledig's avatar
ledig committed
203
        {
ledig's avatar
ledig committed
204 205 206 207 208
            // the modules which match every time need their own groups
            WCombinerTypes::WOneToOneCombiners lComp;

            // 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
            lComp.push_back( boost::shared_ptr< WApplyCombiner >( new WApplyCombiner( module, "", *listIter, "" ) ) );
209 210

            // add this list
ledig's avatar
ledig committed
211
            compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
212 213 214
        }
    }

ledig's avatar
ledig committed
215
    // if NULL was specified, only return all modules without any inputs
216 217
    if ( !module )
    {
ledig's avatar
ledig committed
218
        return compatibles;
219 220
    }

221
    // go through every prototype
ledig's avatar
ledig committed
222
    for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
223
            ++listIter )
224
    {
ledig's avatar
ledig committed
225
        WCombinerTypes::WOneToOneCombiners lComp = WApplyCombiner::createCombinerList< WApplyCombiner >( module, ( *listIter ) );
226 227 228 229

        // add the group
        if ( lComp.size() != 0 )
        {
ledig's avatar
ledig committed
230
            compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
231
        }
232 233
    }

ledig's avatar
ledig committed
234
    // unlock. No locking needed for further steps.
235
    l.reset();
236

237
    // sort the compatibles
ledig's avatar
ledig committed
238
    std::sort( compatibles.begin(), compatibles.end(), WCombinerTypes::compatiblesSort );
239

ledig's avatar
ledig committed
240
    return compatibles;
241
}