00001
00002
00003
00004 #include "GaudiKernel/MsgStream.h"
00005 #include "GaudiKernel/Service.h"
00006 #include "GaudiKernel/SvcFactory.h"
00007 #include "GaudiKernel/ISvcLocator.h"
00008 #include "GaudiKernel/IAlgorithm.h"
00009 #include "GaudiKernel/GaudiException.h"
00010 #include "GaudiKernel/AlgTool.h"
00011 #include "GaudiKernel/IHistorySvc.h"
00012 #include "GaudiKernel/ToolFactory.h"
00013 #include "ToolSvc.h"
00014 #include <algorithm>
00015 #include <map>
00016 #include <string>
00017 #include <cassert>
00018 #ifdef __ICC
00019
00020
00021 #pragma warning(disable:177)
00022 #endif
00023 #include "boost/lambda/bind.hpp"
00024 #ifdef __ICC
00025
00026 #pragma warning(enable:177)
00027 #endif
00028
00029
00030
00031 DECLARE_SERVICE_FACTORY(ToolSvc)
00032
00033 using ROOT::Reflex::PluginService;
00034 namespace bl = boost::lambda;
00035
00036
00037 ToolSvc::ToolSvc( const std::string& name, ISvcLocator* svc )
00038
00039 : base_class(name, svc),
00040 m_pHistorySvc(0)
00041 { }
00042
00043
00044 ToolSvc::~ToolSvc()
00045
00046 {
00047
00048 }
00049
00050
00051 StatusCode ToolSvc::initialize()
00052
00053 {
00054
00055
00056 StatusCode status = Service::initialize();
00057 if ( status.isFailure() )
00058 {
00059 MsgStream log( msgSvc(), name() );
00060 log << MSG::ERROR << "Unable to initialize the Service" << endmsg;
00061 return status;
00062 }
00063
00064
00065 if (setProperties().isFailure()) {
00066 MsgStream log( msgSvc(), name() );
00067 log << MSG::ERROR << "Unable to set base properties" << endmsg;
00068 return StatusCode::FAILURE;
00069 }
00070
00071 return status;
00072 }
00073
00074
00075 StatusCode ToolSvc::finalize()
00076
00077 {
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00102 MsgStream log( msgSvc(), name() );
00103 ListTools finalizedTools;
00104 log << MSG::INFO << "Removing all tools created by ToolSvc" << endmsg;
00105
00106
00107 log << MSG::DEBUG << " Tool List : ";
00108 for ( ListTools::const_iterator iTool = m_instancesTools.begin();
00109 iTool != m_instancesTools.end(); ++iTool ) {
00110 log << (*iTool)->name() << ":" << refCountTool( *iTool ) << " ";
00111 }
00112 log << endmsg;
00113
00114
00115
00116
00129 bool fail(false);
00130 size_t toolCount = m_instancesTools.size();
00131 unsigned long startRefCount = 0;
00132 unsigned long endRefCount = totalToolRefCount();
00133 unsigned long startMinRefCount = 0;
00134 unsigned long endMinRefCount = minimumToolRefCount();
00135 while ( toolCount > 0 &&
00136 endRefCount > 0 &&
00137 (endRefCount != startRefCount || endMinRefCount != startMinRefCount) ) {
00138 if ( endMinRefCount != startMinRefCount ) {
00139 log << MSG::DEBUG << toolCount << " tools left to finalize. Summed refCounts: "
00140 << endRefCount << endmsg;
00141 log << MSG::DEBUG << "Will finalize tools with refCount <= "
00142 << endMinRefCount << endmsg;
00143 }
00144 startMinRefCount = endMinRefCount;
00145 startRefCount = endRefCount;
00146 unsigned long maxLoop = toolCount + 1;
00147 while ( --maxLoop > 0 && m_instancesTools.size() > 0 ) {
00148 IAlgTool* pTool = m_instancesTools.back();
00149
00150 m_instancesTools.pop_back();
00151 unsigned long count = refCountTool( pTool );
00152
00153 std::string toolName = pTool->name();
00154 if ( count <= startMinRefCount ) {
00155 log << MSG::DEBUG << " Performing finalization of " << toolName
00156 << " (refCount " << count << ")" << endmsg;
00157
00158
00159 if (!finalizeTool(pTool).isSuccess()) fail = true;
00160
00161 finalizedTools.push_back(pTool);
00162 } else {
00163
00164
00165 log << MSG::DEBUG << " Delaying finalization of " << toolName
00166 << " (refCount " << count << ")" << endmsg;
00167 m_instancesTools.push_front(pTool);
00168 }
00169 }
00170 toolCount = m_instancesTools.size();
00171 endRefCount = totalToolRefCount();
00172 endMinRefCount = minimumToolRefCount();
00173 };
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 log << MSG::DEBUG << "Deleting " << finalizedTools.size() << " finalized tools" << endmsg;
00188 unsigned long maxLoop = totalToolRefCount( finalizedTools ) + 1;
00189 while ( --maxLoop > 0 && finalizedTools.size() > 0 ) {
00190 IAlgTool* pTool = finalizedTools.front();
00191 finalizedTools.pop_front();
00192 unsigned long count = refCountTool( pTool );
00193 if ( count == 1 ) {
00194 log << MSG::DEBUG << " Performing deletion of " << pTool->name() << endmsg;
00195 } else {
00196 log << MSG::VERBOSE << " Delaying deletion of " << pTool->name()
00197 << " (refCount " << count << ")" << endmsg;
00198
00199 finalizedTools.push_back(pTool);
00200 }
00201
00202 pTool->release();
00203 }
00204
00205
00206 if ( !m_instancesTools.empty() ) {
00207 log << MSG::ERROR << "Unable to finalize and delete the following tools : ";
00208 for ( ListTools::const_iterator iTool = m_instancesTools.begin();
00209 iTool != m_instancesTools.end(); ++iTool ) {
00210 log << (*iTool)->name() << ": " << refCountTool( *iTool ) << " ";
00211 }
00212 log << endmsg;
00213 }
00214
00215
00216 if ( finalizedTools.size() > 0 ) {
00217 log << MSG::ERROR << "Failed to delete the following " << finalizedTools.size()
00218 << " finalized tools. Bug in ToolSvc::finalize()?: ";
00219 for ( ListTools::const_iterator iTool = finalizedTools.begin();
00220 iTool != finalizedTools.end(); ++iTool ) {
00221 log << (*iTool)->name() << ": " << refCountTool( *iTool ) << " ";
00222 }
00223 log << endmsg;
00224 }
00225
00226 if ( 0 != m_pHistorySvc ) {
00227 m_pHistorySvc->release();
00228 }
00229
00230
00231 if (! Service::finalize().isSuccess() || fail) {
00232 return StatusCode::FAILURE;
00233 } else {
00234 return StatusCode::SUCCESS;
00235 }
00236
00237
00238 }
00239
00240
00244
00245 namespace
00246 {
00247 const std::string s_PUBLIC = ":PUBLIC" ;
00248 }
00249
00250
00251 StatusCode ToolSvc::retrieve ( const std::string& tooltype ,
00252 const InterfaceID& iid ,
00253 IAlgTool*& tool ,
00254 const IInterface* parent ,
00255 bool createIf )
00256
00257 {
00258
00259
00260 if ( tooltype.empty() ) {
00261 MsgStream log( msgSvc(), name() );
00262 log << MSG::ERROR << "retrieve(): No Tool Type/Name given" << endmsg;
00263 return StatusCode::FAILURE;
00264 }
00265
00266 {
00267
00268 const std::string::size_type pos = tooltype.find ( s_PUBLIC ) ;
00269 if ( std::string::npos != pos )
00270 {
00271
00272 parent = this ;
00273 return retrieve ( std::string( tooltype , 0 , pos ) ,
00274 iid , tool , parent , createIf ) ;
00275 }
00276 }
00277
00278 const std::string::size_type pos = tooltype.find('/');
00279 if( std::string::npos == pos )
00280 { return retrieve ( tooltype , tooltype , iid , tool , parent , createIf );}
00281 const std::string newtype ( tooltype , 0 , pos ) ;
00282 const std::string newname ( tooltype , pos + 1 , std::string::npos ) ;
00283 return retrieve ( newtype , newname , iid , tool , parent , createIf ) ;
00284 }
00285
00286
00287
00288
00289 StatusCode ToolSvc::retrieve ( const std::string& tooltype ,
00290 const std::string& toolname ,
00291 const InterfaceID& iid ,
00292 IAlgTool*& tool ,
00293 const IInterface* parent ,
00294 bool createIf )
00295
00296 {
00297 MsgStream log( msgSvc(), name() );
00298
00299
00300
00301 if( toolname.empty() || (std::string::npos != tooltype.find('/')) )
00302 { return retrieve ( tooltype , iid , tool , parent , createIf ) ; }
00303
00304 {
00305
00306 const std::string::size_type pos = toolname.find ( s_PUBLIC ) ;
00307 if ( std::string::npos != pos )
00308 {
00309
00310 parent = this ;
00311 return retrieve ( tooltype , std::string( toolname , 0 , pos ) ,
00312 iid , tool , parent , createIf ) ;
00313 }
00314 }
00315
00316 IAlgTool* itool = 0;
00317 StatusCode sc(StatusCode::FAILURE);
00318
00319 tool = 0;
00320
00321
00322 if( 0 == parent ) {
00323 parent = this;
00324 }
00325 const std::string fullname = nameTool( toolname, parent );
00326
00327
00328
00329 ListTools::const_iterator it;
00330 for( it = m_instancesTools.begin(); it != m_instancesTools.end(); ++it ) {
00331 if( (*it)->name() == fullname ) {
00332 log << MSG::DEBUG << "Retrieved tool " << toolname << endmsg;
00333 itool = *it;
00334 break;
00335 }
00336 }
00337
00338 if ( 0 == itool ) {
00339
00340
00341 if( !createIf ) {
00342 log << MSG::WARNING << "Tool " << toolname
00343 << " not found and creation not requested" << endmsg;
00344 return sc;
00345 }
00346 else {
00347 sc = create( tooltype, toolname, parent, itool );
00348 if ( sc.isFailure() ) { return sc; }
00349 }
00350 }
00351
00352
00353 sc = itool->queryInterface( iid, (void**)&tool);
00354 if( sc.isFailure() ) {
00355 log << MSG::ERROR << "Tool " << toolname
00356 << " either does not implement the correct interface, or its version is incompatible"
00357 << endmsg;
00358 return sc;
00359 }
00363 if (!m_observers.empty()) {
00364 std::for_each( m_observers.begin(),
00365 m_observers.end(),
00366 bl::bind(&IToolSvc::Observer::onRetrieve,
00367 bl::_1,
00368 itool));
00369 }
00370
00371 return sc;
00372 }
00373
00374 std::vector<std::string> ToolSvc::getInstances( const std::string& toolType )
00375
00376 {
00377
00378 std::vector<std::string> tools;
00379
00380 ListTools::const_iterator it;
00381 for (it = m_instancesTools.begin(); it != m_instancesTools.end(); ++it) {
00382 if ((*it)->type() == toolType) {
00383 tools.push_back( (*it)->name() );
00384 }
00385 }
00386
00387 return tools;
00388
00389 }
00390
00391 StatusCode ToolSvc::releaseTool( IAlgTool* tool )
00392
00393 {
00394 StatusCode sc(StatusCode::SUCCESS);
00395
00396 if ( m_instancesTools.rend() != std::find( m_instancesTools.rbegin(),
00397 m_instancesTools.rend(),
00398 tool ) ) {
00399 unsigned long count = refCountTool(tool);
00400 if ( count == 1 ) {
00401 MsgStream log( msgSvc(), name() );
00402
00403
00404 if ( Gaudi::StateMachine::OFFLINE == m_targetState ) {
00405
00406
00407 log << MSG::DEBUG << " Performing finalization of " << tool->name()
00408 << " (refCount " << count << ")" << endmsg;
00409
00410 log << MSG::DEBUG << " Performing deletion of " << tool->name() << endmsg;
00411 } else {
00412 log << MSG::DEBUG << "Performing finalization and deletion of " << tool->name() << endmsg;
00413 }
00414 sc = finalizeTool(tool);
00415
00416 m_instancesTools.remove(tool);
00417 }
00418 tool->release();
00419 }
00420
00421 return sc;
00422 }
00423
00424
00425 StatusCode ToolSvc::create(const std::string& tooltype,
00426 const IInterface* parent,
00427 IAlgTool*& tool)
00428
00429 {
00430 const std::string & toolname = tooltype;
00431 return create( tooltype, toolname, parent, tool);
00432 }
00433
00434 namespace {
00437 class ToolCreateGuard {
00438 public:
00439 ToolCreateGuard(ToolSvc::ListTools &listTools):
00440 m_list(listTools),
00441 m_tool(0)
00442 {}
00444 void set(IAlgTool* tool) {
00445 if (m_tool) {
00446 m_list.remove(m_tool);
00447 delete m_tool;
00448 }
00449 if (tool) {
00450 m_tool = tool;
00451 m_list.push_back(m_tool);
00452 }
00453 }
00454 ToolCreateGuard& operator=(IAlgTool* tool) {
00455 set(tool);
00456 return *this;
00457 }
00459 IAlgTool* get() {
00460 return m_tool;
00461 }
00462 IAlgTool* operator->() const {
00463 assert(m_tool != 0);
00464 return m_tool;
00465 }
00467 IAlgTool* release() {
00468 IAlgTool* tool = m_tool;
00469 m_tool = 0;
00470 return tool;
00471 }
00473 ~ToolCreateGuard(){
00474 set(0);
00475 }
00476 private:
00478 ToolSvc::ListTools& m_list;
00480 IAlgTool* m_tool;
00481 };
00482 }
00483
00484 StatusCode ToolSvc::create(const std::string& tooltype,
00485 const std::string& toolname,
00486 const IInterface* parent,
00487 IAlgTool*& tool)
00488
00489 {
00490 MsgStream log( msgSvc(), name() );
00491
00492 if ( tooltype.empty() ) {
00493 log << MSG::ERROR << "create(): No Tool Type given" << endmsg;
00494 return StatusCode::FAILURE;
00495 }
00496
00497
00498 if ( 0 == parent ) parent = this;
00499
00500 tool = 0;
00501
00502
00503 ToolCreateGuard toolguard(m_instancesTools);
00504
00505
00506 const std::string fullname = nameTool(toolname, parent);
00507 if( existsTool( fullname ) ) {
00508 log << MSG::ERROR << "Tool " << fullname << " already exists" << endmsg;
00509 return StatusCode::FAILURE;
00510 }
00511
00512 try {
00513 toolguard = PluginService::Create<IAlgTool*>(tooltype, tooltype, fullname, parent);
00514 if ( ! toolguard.get() ){
00515 log << MSG::ERROR
00516 << "Cannot create tool " << tooltype << " (No factory found)" << endmsg;
00517 return StatusCode::FAILURE;
00518 }
00519 }
00520 catch ( const GaudiException& Exception ) {
00521
00522 log << MSG::FATAL << "Exception with tag=" << Exception.tag()
00523 << " is caught whilst instantiating tool '" << tooltype << "'" << endmsg;
00524
00525
00526 log << MSG::FATAL << Exception << endmsg;
00527 return StatusCode::FAILURE;
00528 }
00529 catch( const std::exception& Exception ) {
00530
00531 log << MSG::FATAL
00532 << "Standard std::exception is caught whilst instantiating tool '"
00533 << tooltype << "'" << endmsg;
00534
00535
00536 log << MSG::FATAL << Exception.what() << endmsg;
00537 return StatusCode::FAILURE;
00538 }
00539 catch(...) {
00540
00541 log << MSG::FATAL << "UNKNOWN Exception is caught whilst instantiating tool '"
00542 << tooltype << "'" << endmsg;
00543 return StatusCode::FAILURE;
00544 }
00545 log << MSG::VERBOSE << "Created tool " << tooltype << "/" << fullname << endmsg;
00546
00547
00548
00549
00550 AlgTool* mytool = dynamic_cast<AlgTool*> (toolguard.get());
00551 if ( mytool != 0 ) {
00552 StatusCode sc = mytool->setProperties();
00553 if ( sc.isFailure() ) {
00554 log << MSG::ERROR << "Error setting properties for tool '"
00555 << fullname << "'" << endmsg;
00556 return sc;
00557 }
00558 }
00559
00560
00561 StatusCode sc (StatusCode::FAILURE,true);
00562 try { sc = toolguard->sysInitialize(); }
00563
00564
00565 catch ( const GaudiException & Exception )
00566 {
00567 log << MSG::ERROR
00568 << "GaudiException with tag=" << Exception.tag()
00569 << " caught whilst initializing tool '" << fullname << "'" << endmsg
00570 << Exception << endmsg;
00571 return StatusCode::FAILURE;
00572 }
00573 catch( const std::exception & Exception )
00574 {
00575 log << MSG::ERROR
00576 << "Standard std::exception caught whilst initializing tool '"
00577 << fullname << "'" << endmsg << Exception.what() << endmsg;
00578 return StatusCode::FAILURE;
00579 }
00580 catch (...)
00581 {
00582 log << MSG::ERROR
00583 << "UNKNOWN Exception caught whilst initializing tool '"
00584 << fullname << "'" << endmsg;
00585 return StatusCode::FAILURE;
00586 }
00587
00588
00589 if ( sc.isFailure() ) {
00590 log << MSG::ERROR << "Error initializing tool '" << fullname << "'" << endmsg;
00591 return sc;
00592 }
00593
00594
00595 if (m_state == Gaudi::StateMachine::RUNNING) {
00596 sc = toolguard->sysStart();
00597
00598 if (sc.isFailure()) {
00599 log << MSG::ERROR << "Error starting tool '" << fullname << "'" << endmsg;
00600 return sc;
00601 }
00602 }
00603
00604
00605
00606
00607 tool = toolguard.release();
00608
00612 if (!m_observers.empty()) {
00613 std::for_each( m_observers.begin(),
00614 m_observers.end(),
00615 bl::bind(&IToolSvc::Observer::onCreate,
00616 bl::_1,
00617 tool));
00618 }
00619
00620
00621 if (m_pHistorySvc != 0 ||
00622 service("HistorySvc",m_pHistorySvc,false).isSuccess() ) {
00623 m_pHistorySvc->registerAlgTool(*tool).ignore();
00624 }
00625
00626 return StatusCode::SUCCESS;
00627
00628 }
00629
00630
00631 std::string ToolSvc::nameTool( const std::string& toolname,
00632 const IInterface* parent )
00633
00634 {
00635
00636 std::string fullname = "";
00637 if ( parent == 0 ) { return this->name() + "." + toolname; }
00638
00639
00640 IInterface* cparent = const_cast<IInterface*>( parent ) ;
00641
00642 INamedInterface* _p = 0 ;
00643 StatusCode sc = cparent->queryInterface( INamedInterface::interfaceID() , pp_cast<void>(&_p) ) ;
00644 if ( sc.isSuccess() )
00645 {
00646 fullname = _p->name() + "." + toolname ;
00647 _p->release() ;
00648 return fullname ;
00649 }
00650
00651 MsgStream log ( msgSvc(), name() );
00652 log << MSG::ERROR
00653 << "Private Tools only allowed for components implementing INamedInterface"
00654 << endmsg;
00655
00656 return "." + toolname ;
00657 }
00658
00659
00660 bool ToolSvc::existsTool( const std::string& fullname) const
00661
00662 {
00663 for ( ListTools::const_iterator it = m_instancesTools.begin();
00664 it != m_instancesTools.end(); ++it ) {
00665 if ( (*it)->name() == fullname ) { return true; }
00666 }
00667 return false;
00668 }
00669
00670
00671 StatusCode ToolSvc::finalizeTool( IAlgTool* itool ) const
00672
00673 {
00674
00675
00676 const std::string toolName = itool->name();
00677 StatusCode sc;
00678
00679
00680 try { sc = itool->sysFinalize(); }
00681
00682
00683 catch ( const GaudiException & Exception )
00684 {
00685 MsgStream msg ( msgSvc(), name() );
00686 msg << MSG::ERROR
00687 << "GaudiException with tag=" << Exception.tag()
00688 << " caught whilst finalizing tool '" << toolName << "'" << endmsg
00689 << Exception << endmsg;
00690 sc = StatusCode::FAILURE;
00691 }
00692 catch( const std::exception & Exception )
00693 {
00694 MsgStream msg ( msgSvc(), name() );
00695 msg << MSG::ERROR
00696 << "Standard std::exception caught whilst finalizing tool '"
00697 << toolName << "'" << endmsg << Exception.what() << endmsg;
00698 sc = StatusCode::FAILURE;
00699 }
00700 catch (...)
00701 {
00702 MsgStream msg ( msgSvc(), name() );
00703 msg << MSG::ERROR
00704 << "UNKNOWN Exception caught whilst finalizing tool '"
00705 << toolName << "'" << endmsg;
00706 sc = StatusCode::FAILURE;
00707 }
00708
00709 return sc;
00710
00711 }
00712
00713
00714 unsigned long ToolSvc::totalToolRefCount( const ToolSvc::ListTools& toolList ) const
00715
00716 {
00717 unsigned long count = 0;
00718 for ( ListTools::const_iterator iTool = toolList.begin();
00719 iTool != toolList.end(); ++iTool ) {
00720 count += refCountTool( *iTool );
00721 }
00722 return count;
00723 }
00724
00725
00726 unsigned long ToolSvc::totalToolRefCount() const
00727
00728 {
00729 return totalToolRefCount( m_instancesTools );
00730 }
00731
00732 unsigned long ToolSvc::minimumToolRefCount() const
00733
00734 {
00735 unsigned long count = 0;
00736 if ( m_instancesTools.size() > 0 ) {
00737 ListTools::const_iterator iTool = m_instancesTools.begin();
00738
00739 count = refCountTool( *iTool );
00740
00741 for( ++iTool; iTool != m_instancesTools.end(); ++iTool ) {
00742 count = std::min( count, refCountTool( *iTool ) );
00743 }
00744 }
00745 return count;
00746 }
00747
00748 void ToolSvc::registerObserver(IToolSvc::Observer* obs) {
00749 if ( 0 == obs )
00750 throw GaudiException( "Received NULL pointer", this->name() + "::registerObserver", StatusCode::FAILURE );
00751 m_observers.push_back(obs);
00752 }
00753
00754 void ToolSvc::unRegisterObserver(IToolSvc::Observer* obs) {
00755 std::vector<IToolSvc::Observer*>::iterator i =
00756 find(m_observers.begin(),m_observers.end(),obs);
00757 if (i!=m_observers.end()) m_observers.erase(i);
00758 }
00759
00760
00761 StatusCode
00762 ToolSvc::start()
00763
00764 {
00765
00766 MsgStream log( msgSvc(), name() );
00767 log << MSG::DEBUG << "START transition for AlgTools" << endmsg;
00768
00769 bool fail(false);
00770 for ( ListTools::const_iterator iTool = m_instancesTools.begin();
00771 iTool != m_instancesTools.end(); ++iTool ) {
00772 log << MSG::VERBOSE << (*iTool)->name() << "::start()" << endmsg;
00773
00774 if (!(*iTool)->sysStart().isSuccess()) {
00775 fail = true;
00776 log << MSG::ERROR << (*iTool)->name() << " failed to start()" << endmsg;
00777 }
00778
00779 }
00780
00781 if (fail) {
00782 log << MSG::ERROR << "One or more AlgTools failed to start()" << endmsg;
00783 return StatusCode::FAILURE;
00784 } else {
00785 return StatusCode::SUCCESS;
00786 }
00787
00788 }
00789
00790
00791 StatusCode
00792 ToolSvc::stop()
00793
00794 {
00795
00796 MsgStream log( msgSvc(), name() );
00797 log << MSG::DEBUG << "STOP transition for AlgTools" << endmsg;
00798
00799 bool fail(false);
00800 for ( ListTools::const_iterator iTool = m_instancesTools.begin();
00801 iTool != m_instancesTools.end(); ++iTool ) {
00802 log << MSG::VERBOSE << (*iTool)->name() << "::stop()" << endmsg;
00803
00804 if (!(*iTool)->sysStop().isSuccess()) {
00805 fail = true;
00806 log << MSG::ERROR << (*iTool)->name() << " failed to stop()" << endmsg;
00807 }
00808
00809 }
00810
00811 if (fail) {
00812 log << MSG::ERROR << "One or more AlgTools failed to stop()" << endmsg;
00813 return StatusCode::FAILURE;
00814 } else {
00815 return StatusCode::SUCCESS;
00816 }
00817
00818 }