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