00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <iostream>
00026 #include <list>
00027 #include <string>
00028 #include <sstream>
00029 #include <set>
00030
00031 #include <boost/version.hpp>
00032 #if ( BOOST_VERSION >= 104200 ) // exception.hpp is deprecated in Boost 1.42
00033 #include <boost/exception/all.hpp>
00034 #else
00035 #include <boost/exception.hpp>
00036 #endif
00037
00038 #include <boost/signals2/signal.hpp>
00039 #include <boost/signals2/connection.hpp>
00040
00041 #include "WModule.h"
00042 #include "WModuleConnectorSignals.h"
00043 #include "WModuleContainer.h"
00044 #include "WModuleInputConnector.h"
00045 #include "WModuleOutputConnector.h"
00046 #include "combiner/WDisconnectCombiner.h"
00047 #include "exceptions/WModuleConnectionFailed.h"
00048 #include "exceptions/WModuleConnectionInvalid.h"
00049 #include "exceptions/WModuleConnectorsIncompatible.h"
00050 #include "exceptions/WModuleDisconnectFailed.h"
00051 #include "exceptions/WModuleSignalSubscriptionFailed.h"
00052 #include "exceptions/WModuleConnectorModuleLockFailed.h"
00053
00054 #include "WModuleConnector.h"
00055
00056 WModuleConnector::WModuleConnector( boost::shared_ptr< WModule > module, std::string name, std::string description ):
00057 boost::enable_shared_from_this<WModuleConnector>()
00058 {
00059
00060 m_module = module;
00061 m_moduleName = module->getName();
00062
00063 m_name = name;
00064 m_description = description;
00065
00066
00067
00068
00069 subscribeSignal( CONNECTION_ESTABLISHED, boost::bind( &WModuleConnector::notifyConnectionEstablished, this, _1, _2 ) );
00070 subscribeSignal( CONNECTION_CLOSED, boost::bind( &WModuleConnector::notifyConnectionClosed, this, _1, _2 ) );
00071
00072 signal_ConnectionEstablished.connect( getSignalHandler( CONNECTION_ESTABLISHED ) );
00073 signal_ConnectionClosed.connect( getSignalHandler( CONNECTION_CLOSED ) );
00074 }
00075
00076 WModuleConnector::~WModuleConnector()
00077 {
00078 disconnectAll();
00079
00080
00081 signal_ConnectionEstablished.disconnect_all_slots();
00082 signal_ConnectionClosed.disconnect_all_slots();
00083 }
00084
00085 bool WModuleConnector::isConnectedTo( boost::shared_ptr<WModuleConnector> con )
00086 {
00087 boost::shared_lock<boost::shared_mutex> slock;
00088 slock = boost::shared_lock<boost::shared_mutex>( m_connectionListLock );
00089 int c1 = m_connected.count( con );
00090 slock.unlock();
00091
00092 slock = boost::shared_lock<boost::shared_mutex>( con->m_connectionListLock );
00093 int c2 = con->m_connected.count( shared_from_this() );
00094 slock.unlock();
00095
00096
00097 if( c1 != c2 )
00098 {
00099 std::ostringstream s;
00100 s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed.";
00101 throw WModuleConnectionInvalid( s.str() );
00102 }
00103
00104 return ( c1 == 1 );
00105 }
00106
00107 unsigned int WModuleConnector::isConnected()
00108 {
00109 boost::shared_lock<boost::shared_mutex> slock = boost::shared_lock<boost::shared_mutex>( m_connectionListLock );
00110 int count = m_connected.size();
00111 slock.unlock();
00112 return count;
00113 }
00114
00115 void WModuleConnector::connect( boost::shared_ptr<WModuleConnector> con )
00116 {
00117 boost::shared_ptr< WModule > module = m_module.lock();
00118 std::string containerName = "Unknown";
00119 if( module )
00120 {
00121 boost::shared_ptr< WModuleContainer > container;
00122 container = module->getAssociatedContainer();
00123 containerName = container.get() ? container->getName() : "Unknown";
00124 }
00125 WLogger::getLogger()->addLogMessage( "Connecting " + con->getCanonicalName() + " with " + getCanonicalName(),
00126 "ModuleContainer (" + containerName + ")", LL_INFO );
00127
00128
00129 if( !( con->connectable( shared_from_this() ) && connectable( con ) ) )
00130 {
00131 std::ostringstream s;
00132 s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed.";
00133 throw WModuleConnectorsIncompatible( s.str() );
00134 }
00135
00136
00137 if( isConnectedTo( con ) )
00138 {
00139 WLogger::getLogger()->addLogMessage( con->getCanonicalName() + " and " + getCanonicalName() + " are already connected.",
00140 "ModuleContainer (" + containerName + ")", LL_INFO );
00141 return;
00142 }
00143
00144 boost::unique_lock<boost::shared_mutex> lock;
00145 boost::unique_lock<boost::shared_mutex> lockRemote;
00146 try
00147 {
00148
00149 lock = boost::unique_lock<boost::shared_mutex>( m_connectionListLock );
00150 lockRemote = boost::unique_lock<boost::shared_mutex>( con->m_connectionListLock );
00151
00152
00153 if( ( isInputConnector() && m_connected.size() ) || ( con->isInputConnector() && con->m_connected.size() ) )
00154 {
00155 throw WModuleConnectionFailed( std::string( "Input connector already connected. Disconnect it first." ) );
00156 }
00157
00158 m_connected.insert( con );
00159 con->m_connected.insert( shared_from_this() );
00160
00161 lock.unlock();
00162 lockRemote.unlock();
00163 }
00164 catch( const WException& e )
00165 {
00166 lock.unlock();
00167 lockRemote.unlock();
00168
00169
00170 m_connected.erase( con );
00171 con->m_connected.erase( con );
00172
00173 throw e;
00174 }
00175 catch( const std::exception& e )
00176 {
00177 lock.unlock();
00178 lockRemote.unlock();
00179
00180
00181 m_connected.erase( con );
00182 con->m_connected.erase( con );
00183
00184 std::ostringstream s;
00185 s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed.";
00186 throw WModuleConnectionFailed( s.str() );
00187 }
00188 catch( const boost::exception& e )
00189 {
00190 lock.unlock();
00191 lockRemote.unlock();
00192
00193
00194 m_connected.erase( con );
00195 con->m_connected.erase( con );
00196
00197 std::ostringstream s;
00198 s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed.";
00199 throw WModuleConnectionFailed( s.str() );
00200 }
00201
00202
00203 connectSignals( con );
00204 con->connectSignals( shared_from_this() );
00205
00206
00207 signal_ConnectionEstablished( shared_from_this(), con );
00208
00209 con->signal_ConnectionEstablished( con, shared_from_this() );
00210 }
00211
00212 void WModuleConnector::connectSignals( boost::shared_ptr<WModuleConnector> )
00213 {
00214
00215
00216
00217 }
00218
00219 void WModuleConnector::disconnectSignals( boost::shared_ptr<WModuleConnector> )
00220 {
00221
00222 }
00223
00224 boost::signals2::connection WModuleConnector::subscribeSignal( MODULE_CONNECTOR_SIGNAL signal,
00225 t_GenericSignalHandlerType notifier )
00226 {
00227 switch (signal)
00228 {
00229 case CONNECTION_ESTABLISHED:
00230 return signal_ConnectionEstablished.connect( notifier );
00231 case CONNECTION_CLOSED:
00232 return signal_ConnectionClosed.connect( notifier );
00233 default:
00234 std::ostringstream s;
00235 s << "Could not subscribe to unknown signal. You need to implement this signal type explicitly.";
00236 throw WModuleSignalSubscriptionFailed( s.str() );
00237 break;
00238 }
00239 }
00240
00241 const t_GenericSignalHandlerType WModuleConnector::getSignalHandler( MODULE_CONNECTOR_SIGNAL signal )
00242 {
00243
00244 boost::shared_ptr< WModule > module = m_module.lock();
00245 if( !module )
00246 {
00247 throw WModuleConnectorModuleLockFailed();
00248 }
00249 return module->getSignalHandler( signal );
00250 }
00251
00252 boost::shared_ptr< WModule > WModuleConnector::getModule() const
00253 {
00254 return m_module.lock();
00255 }
00256
00257 void WModuleConnector::disconnect( boost::shared_ptr<WModuleConnector> con, bool removeFromOwnList )
00258 {
00259 boost::shared_ptr< WModule > module = m_module.lock();
00260 std::string containerName = "Unknown";
00261 if( module )
00262 {
00263 boost::shared_ptr< WModuleContainer > container;
00264 container = module->getAssociatedContainer();
00265 containerName = container.get() ? container->getName() : "Unknown";
00266 }
00267
00268 if( !isConnectedTo( con ) )
00269 {
00270 WLogger::getLogger()->addLogMessage( "Could not disconnect " + con->getCanonicalName() + " from " + getCanonicalName() + " as they are"+
00271 " not connected.", "ModuleContainer (" + containerName + ")", LL_INFO );
00272 return;
00273 }
00274
00275 WLogger::getLogger()->addLogMessage( "Disconnecting " + con->getCanonicalName() + " from " + getCanonicalName(),
00276 "ModuleContainer (" + containerName + ")", LL_INFO );
00277
00278
00279 boost::unique_lock<boost::shared_mutex> lock;
00280 try
00281 {
00282
00283 con->disconnectSignals( shared_from_this() );
00284 disconnectSignals( con );
00285
00286
00287 if( removeFromOwnList )
00288 {
00289 lock = boost::unique_lock<boost::shared_mutex>( m_connectionListLock );
00290
00291 m_connected.erase( con );
00292 lock.unlock();
00293 }
00294
00295
00296 lock = boost::unique_lock<boost::shared_mutex>( con->m_connectionListLock );
00297 con->m_connected.erase( shared_from_this() );
00298 lock.unlock();
00299
00300
00301
00302
00303 signal_ConnectionClosed( shared_from_this(), con );
00304 con->signal_ConnectionClosed( shared_from_this(), con );
00305 }
00306 catch( const std::exception& e )
00307 {
00308 lock.unlock();
00309
00310 std::ostringstream s;
00311 s << "Unable to disconnect " << getCanonicalName() << " from " << con->getCanonicalName() << ".";
00312 throw WModuleDisconnectFailed( s.str() );
00313 }
00314 catch( const boost::exception& e )
00315 {
00316 lock.unlock();
00317
00318 std::ostringstream s;
00319 s << "Unable to disconnect " << getCanonicalName() << " from " << con->getCanonicalName() << ".";
00320 throw WModuleDisconnectFailed( s.str() );
00321 }
00322 }
00323
00324 void WModuleConnector::disconnectAll()
00325 {
00326
00327
00328
00329 boost::shared_lock<boost::shared_mutex> rlock( m_connectionListLock );
00330
00331
00332 for( std::set<boost::shared_ptr<WModuleConnector> >::iterator listIter = m_connected.begin(); listIter != m_connected.end();
00333 ++listIter )
00334 {
00335 disconnect( *listIter, false );
00336 }
00337 rlock.unlock();
00338
00339
00340 boost::unique_lock<boost::shared_mutex> lock( m_connectionListLock );
00341 m_connected.clear();
00342 lock.unlock();
00343 }
00344
00345 const std::string WModuleConnector::getDescription() const
00346 {
00347 return m_description;
00348 }
00349
00350 const std::string WModuleConnector::getName() const
00351 {
00352 return m_name;
00353 }
00354
00355 const std::string WModuleConnector::getCanonicalName() const
00356 {
00357 std::ostringstream s;
00358 s << m_moduleName << ":" << getName();
00359
00360 return s.str();
00361 }
00362
00363 void WModuleConnector::setDescription( std::string desc )
00364 {
00365 m_description = desc;
00366 }
00367
00368 void WModuleConnector::setName( std::string name )
00369 {
00370 m_name = name;
00371 }
00372
00373 WCombinerTypes::WOneToOneCombiners WModuleConnector::getPossibleDisconnections()
00374 {
00375 WCombinerTypes::WOneToOneCombiners l;
00376
00377
00378 boost::shared_lock<boost::shared_mutex> rlock( m_connectionListLock );
00379
00380
00381 for( std::set<boost::shared_ptr<WModuleConnector> >::iterator listIter = m_connected.begin(); listIter != m_connected.end(); ++listIter )
00382 {
00383
00384 l.push_back( boost::shared_ptr< WDisconnectCombiner >( new WDisconnectCombiner( shared_from_this(), ( *listIter ) ) ) );
00385 }
00386 rlock.unlock();
00387
00388 return l;
00389 }
00390
00391 void WModuleConnector::notifyConnectionEstablished( boost::shared_ptr<WModuleConnector> , boost::shared_ptr<WModuleConnector> )
00392 {
00393
00394 }
00395
00396 void WModuleConnector::notifyConnectionClosed( boost::shared_ptr<WModuleConnector> , boost::shared_ptr<WModuleConnector> )
00397 {
00398
00399 }
00400
00401 boost::shared_ptr< WModuleInputConnector > WModuleConnector::toInputConnector()
00402 {
00403 return boost::shared_dynamic_cast< WModuleInputConnector >( shared_from_this() );
00404 }
00405
00406 boost::shared_ptr< WModuleOutputConnector > WModuleConnector::toOutputConnector()
00407 {
00408 return boost::shared_dynamic_cast< WModuleOutputConnector >( shared_from_this() );
00409 }
00410