1
//---------------------------------------------------------------------------
3
// Project: OpenWalnut ( http://www.openwalnut.org )
5
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6
// For more information see http://www.openwalnut.org/copying
8
// This file is part of OpenWalnut.
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.
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.
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/>.
23
//---------------------------------------------------------------------------
31
#include <boost/version.hpp>
32
#if ( BOOST_VERSION >= 104200 ) // exception.hpp is deprecated in Boost 1.42
33
#include <boost/exception/all.hpp>
35
#include <boost/exception.hpp>
38
#include <boost/signals2/signal.hpp>
39
#include <boost/signals2/connection.hpp>
41
#include "../common/exceptions/WSignalSubscriptionFailed.h"
43
#include "WModuleConnectorSignals.h"
44
#include "WModuleContainer.h"
45
#include "WModuleInputConnector.h"
46
#include "WModuleOutputConnector.h"
47
#include "combiner/WDisconnectCombiner.h"
48
#include "exceptions/WModuleConnectionFailed.h"
49
#include "exceptions/WModuleConnectionInvalid.h"
50
#include "exceptions/WModuleConnectorsIncompatible.h"
51
#include "exceptions/WModuleDisconnectFailed.h"
52
#include "exceptions/WModuleConnectorModuleLockFailed.h"
54
#include "WModuleConnector.h"
56
WModuleConnector::WModuleConnector( boost::shared_ptr< WModule > module, std::string name, std::string description ):
57
boost::enable_shared_from_this<WModuleConnector>()
61
m_moduleName = module->getName();
64
m_description = description;
66
// connect standard signals
67
// NOTE: these signals are NOT emitted by the connector this one is connected to, since a module can't send a "connection
68
// closed" message if the connection is closed.
69
subscribeSignal( CONNECTION_ESTABLISHED, boost::bind( &WModuleConnector::notifyConnectionEstablished, this, _1, _2 ) );
70
subscribeSignal( CONNECTION_CLOSED, boost::bind( &WModuleConnector::notifyConnectionClosed, this, _1, _2 ) );
72
signal_ConnectionEstablished.connect( getSignalHandler( CONNECTION_ESTABLISHED ) );
73
signal_ConnectionClosed.connect( getSignalHandler( CONNECTION_CLOSED ) );
76
WModuleConnector::~WModuleConnector()
81
signal_ConnectionEstablished.disconnect_all_slots();
82
signal_ConnectionClosed.disconnect_all_slots();
85
bool WModuleConnector::isConnectedTo( boost::shared_ptr<WModuleConnector> con )
87
boost::shared_lock<boost::shared_mutex> slock;
88
slock = boost::shared_lock<boost::shared_mutex>( m_connectionListLock );
89
int c1 = m_connected.count( con );
92
slock = boost::shared_lock<boost::shared_mutex>( con->m_connectionListLock );
93
int c2 = con->m_connected.count( shared_from_this() );
96
// if the count is different the connection is invalid
100
s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed.";
101
throw WModuleConnectionInvalid( s.str() );
107
unsigned int WModuleConnector::isConnected()
109
boost::shared_lock<boost::shared_mutex> slock = boost::shared_lock<boost::shared_mutex>( m_connectionListLock );
110
int count = m_connected.size();
115
void WModuleConnector::connect( boost::shared_ptr<WModuleConnector> con )
117
boost::shared_ptr< WModule > module = m_module.lock(); // it is "unlocked" at the end of this function as "module" looses its scope
118
std::string containerName = "Unknown";
121
boost::shared_ptr< WModuleContainer > container;
122
container = module->getAssociatedContainer();
123
containerName = container.get() ? container->getName() : "Unknown";
125
WLogger::getLogger()->addLogMessage( "Connecting " + con->getCanonicalName() + " with " + getCanonicalName(),
126
"ModuleContainer (" + containerName + ")", LL_INFO );
128
// are both partners compatible to each other?
129
if( !( con->connectable( shared_from_this() ) && connectable( con ) ) )
131
std::ostringstream s;
132
s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed.";
133
throw WModuleConnectorsIncompatible( s.str() );
136
// check whether they are already connected
137
if( isConnectedTo( con ) )
139
WLogger::getLogger()->addLogMessage( con->getCanonicalName() + " and " + getCanonicalName() + " are already connected.",
140
"ModuleContainer (" + containerName + ")", LL_INFO );
144
boost::unique_lock<boost::shared_mutex> lock;
145
boost::unique_lock<boost::shared_mutex> lockRemote;
149
lock = boost::unique_lock<boost::shared_mutex>( m_connectionListLock );
150
lockRemote = boost::unique_lock<boost::shared_mutex>( con->m_connectionListLock );
152
// is the input connected already?
153
if( ( isInputConnector() && m_connected.size() ) || ( con->isInputConnector() && con->m_connected.size() ) )
155
throw WModuleConnectionFailed( std::string( "Input connector already connected. Disconnect it first." ) );
158
m_connected.insert( con );
159
con->m_connected.insert( shared_from_this() );
164
catch( const WException& e )
170
m_connected.erase( con );
171
con->m_connected.erase( con );
175
catch( const std::exception& e )
181
m_connected.erase( con );
182
con->m_connected.erase( con );
184
std::ostringstream s;
185
s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed.";
186
throw WModuleConnectionFailed( s.str() );
188
catch( const boost::exception& e )
194
m_connected.erase( con );
195
con->m_connected.erase( con );
197
std::ostringstream s;
198
s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed.";
199
throw WModuleConnectionFailed( s.str() );
202
// let them connect their signals
203
connectSignals( con );
204
con->connectSignals( shared_from_this() );
206
// signal "connection established"
207
signal_ConnectionEstablished( shared_from_this(), con );
208
// signal to my partner, of course with the parameters the other way round
209
con->signal_ConnectionEstablished( con, shared_from_this() );
212
void WModuleConnector::connectSignals( boost::shared_ptr<WModuleConnector> /*con*/ )
214
// Add extra signal- connections here that are COMMON to ALL connectors.
215
// NOTE: connection established and connection closed are not signals to connect, since you can not send an connection closed
216
// signal to somebody with whom you are not connected anymore ;-).
219
void WModuleConnector::disconnectSignals( boost::shared_ptr<WModuleConnector> /*con*/ )
221
// The base module does not subscribe to any signal -> no disconnection needed here
224
boost::signals2::connection WModuleConnector::subscribeSignal( MODULE_CONNECTOR_SIGNAL signal,
225
t_GenericSignalHandlerType notifier )
229
case CONNECTION_ESTABLISHED:
230
return signal_ConnectionEstablished.connect( notifier );
231
case CONNECTION_CLOSED:
232
return signal_ConnectionClosed.connect( notifier );
234
std::ostringstream s;
235
s << "Could not subscribe to unknown signal. You need to implement this signal type explicitly.";
236
throw WSignalSubscriptionFailed( s.str() );
241
const t_GenericSignalHandlerType WModuleConnector::getSignalHandler( MODULE_CONNECTOR_SIGNAL signal )
243
// the module instance knows that
244
boost::shared_ptr< WModule > module = m_module.lock(); // it is "unlocked" at the end of this function as "module" looses its scope
247
throw WModuleConnectorModuleLockFailed();
249
return module->getSignalHandler( signal );
252
boost::shared_ptr< WModule > WModuleConnector::getModule() const
254
return m_module.lock(); // it is "unlocked" at the end of this function as "module" looses its scope
257
void WModuleConnector::disconnect( boost::shared_ptr<WModuleConnector> con, bool removeFromOwnList )
259
boost::shared_ptr< WModule > module = m_module.lock(); // it is "unlocked" at the end of this function as "module" looses its scope
260
std::string containerName = "Unknown";
263
boost::shared_ptr< WModuleContainer > container;
264
container = module->getAssociatedContainer();
265
containerName = container.get() ? container->getName() : "Unknown";
268
if( !isConnectedTo( con ) )
270
WLogger::getLogger()->addLogMessage( "Could not disconnect " + con->getCanonicalName() + " from " + getCanonicalName() + " as they are"+
271
" not connected.", "ModuleContainer (" + containerName + ")", LL_INFO );
275
WLogger::getLogger()->addLogMessage( "Disconnecting " + con->getCanonicalName() + " from " + getCanonicalName(),
276
"ModuleContainer (" + containerName + ")", LL_INFO );
279
boost::unique_lock<boost::shared_mutex> lock;
282
// disconnect all signals
283
con->disconnectSignals( shared_from_this() );
284
disconnectSignals( con );
287
if( removeFromOwnList )
289
lock = boost::unique_lock<boost::shared_mutex>( m_connectionListLock );
290
// since we use shared pointers, erasing the item should be enough
291
m_connected.erase( con );
295
// remove me from his list
296
lock = boost::unique_lock<boost::shared_mutex>( con->m_connectionListLock );
297
con->m_connected.erase( shared_from_this() );
300
// signal "closed connection"
301
// NOTE: at this point, there might be an connected input connector even though we disconnected it. This is because of removeFromOwnList.
302
// The input connectors handle this with an additional member variable denoting their disconnect state
303
signal_ConnectionClosed( shared_from_this(), con );
304
con->signal_ConnectionClosed( shared_from_this(), con );
306
catch( const std::exception& e )
310
std::ostringstream s;
311
s << "Unable to disconnect " << getCanonicalName() << " from " << con->getCanonicalName() << ".";
312
throw WModuleDisconnectFailed( s.str() );
314
catch( const boost::exception& e )
318
std::ostringstream s;
319
s << "Unable to disconnect " << getCanonicalName() << " from " << con->getCanonicalName() << ".";
320
throw WModuleDisconnectFailed( s.str() );
324
void WModuleConnector::disconnectAll()
329
boost::shared_lock<boost::shared_mutex> rlock( m_connectionListLock );
331
// each connector needs to be notified and disconnected properly
332
for( std::set<boost::shared_ptr<WModuleConnector> >::iterator listIter = m_connected.begin(); listIter != m_connected.end();
335
disconnect( *listIter, false );
339
// lock it for writing
340
boost::unique_lock<boost::shared_mutex> lock( m_connectionListLock );
345
const std::string WModuleConnector::getDescription() const
347
return m_description;
350
const std::string WModuleConnector::getName() const
355
const std::string WModuleConnector::getCanonicalName() const
357
std::ostringstream s;
358
s << m_moduleName << ":" << getName();
363
void WModuleConnector::setDescription( std::string desc )
365
m_description = desc;
368
void WModuleConnector::setName( std::string name )
373
WCombinerTypes::WOneToOneCombiners WModuleConnector::getPossibleDisconnections()
375
WCombinerTypes::WOneToOneCombiners l;
378
boost::shared_lock<boost::shared_mutex> rlock( m_connectionListLock );
380
// for each connector
381
for( std::set<boost::shared_ptr<WModuleConnector> >::iterator listIter = m_connected.begin(); listIter != m_connected.end(); ++listIter )
383
// simply create the combiner
384
l.push_back( boost::shared_ptr< WDisconnectCombiner >( new WDisconnectCombiner( shared_from_this(), ( *listIter ) ) ) );
391
void WModuleConnector::notifyConnectionEstablished( boost::shared_ptr<WModuleConnector> /*here*/, boost::shared_ptr<WModuleConnector> /*there*/ )
393
// by default: do nothing.
396
void WModuleConnector::notifyConnectionClosed( boost::shared_ptr<WModuleConnector> /*here*/, boost::shared_ptr<WModuleConnector> /*there*/ )
398
// do nothing by default
401
boost::shared_ptr< WModuleInputConnector > WModuleConnector::toInputConnector()
403
return boost::shared_dynamic_cast< WModuleInputConnector >( shared_from_this() );
406
boost::shared_ptr< WModuleOutputConnector > WModuleConnector::toOutputConnector()
408
return boost::shared_dynamic_cast< WModuleOutputConnector >( shared_from_this() );