diff --git a/Control/AthToolSupport/AsgServices/AsgServices/AsgService.h b/Control/AthToolSupport/AsgServices/AsgServices/AsgService.h new file mode 100644 index 0000000000000000000000000000000000000000..dd038551ad86898dfc00468a745b9432f0a29f2e --- /dev/null +++ b/Control/AthToolSupport/AsgServices/AsgServices/AsgService.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack +/// @author David Adams <dladams@bnl.gov> (for original implementation for tools) + +#ifndef ASGSERVICES_ASGSERVICE_H +#define ASGSERVICES_ASGSERVICE_H + +#include "AsgServices/IAsgService.h" + +#ifdef XAOD_STANDALONE +#include "AsgMessaging/AsgMessaging.h" +#include "AsgTools/AsgComponent.h" +#else +#include "AthenaBaseComps/AthService.h" +#endif + + +class ISvcLocator; + +namespace asg +{ + // Declare the type name of AsgService's base class +#ifndef XAOD_STANDALONE + typedef ::AthService AsgServiceBase; +#else + typedef AsgComponent AsgServiceBase; +#endif + + /// Base class for the dual-use service implementation classes + /// + /// This class can be used like AthService can be used for + /// Athena-only services. + /// + /// Loosely based on the \ref AsgTool implementation. + + class AsgService : public virtual IAsgService, + public AsgServiceBase + { + public: + AsgService (const std::string& name, + ISvcLocator* pSvcLocator); + + + /// set up/tear down functions + /// \{ + virtual StatusCode initialize (); + virtual StatusCode finalize (); + /// \} + + /// Print the state of the service + virtual void print() const; + + }; // class AsgService + +} // namespace asg + +#endif // ASGSERVICES_ASGSERVICE_H diff --git a/Control/AthToolSupport/AsgServices/AsgServices/AsgServiceConfig.h b/Control/AthToolSupport/AsgServices/AsgServices/AsgServiceConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..1a1ac37804604a5048d97d178dc70757be7e0ada --- /dev/null +++ b/Control/AthToolSupport/AsgServices/AsgServices/AsgServiceConfig.h @@ -0,0 +1,166 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef ASG_SERVICES_ASG_SERVICE_CONFIG_H +#define ASG_SERVICES_ASG_SERVICE_CONFIG_H + +#include <AsgTools/AsgComponentConfig.h> +#include <AsgServices/AsgService.h> +#include <AsgServices/ServiceHandle.h> + +#ifndef XAOD_STANDALONE +#include <GaudiKernel/Service.h> +#endif + +namespace asg +{ + /// \brief an object that can create a \ref AsgService + + class AsgServiceConfig : public asg::AsgComponentConfig + { + // + // public interface + // + + /// \brief standard constructor + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory I + public: + AsgServiceConfig () = default; + + + /// \brief initializing constructor + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + public: + explicit AsgServiceConfig (const std::string& val_typeAndName); + + + /// \brief make a service with the given configuration + /// + /// \warn This is mostly meant as a low level interface to be used + /// in unit tests and internally by framework functions that + /// manage services. As a user you should mostly rely on the + /// python configuration or on passing the AsgServiceConfig object + /// to your framework, which will then create and manage the + /// service for you. + /// + /// \warn Regardless of which function you use, the memory + /// management and cleanup of services differs between stand-alone + /// use and Athena. In EventLoop you receive an owning + /// pointer/handle that can be shared with other users and will + /// release the service when the last reference is deleted. In + /// Athena the framework itself will hold on to the service (or at + /// least its configuration) and release it at the end of the job, + /// even if no user code references it. As a user you should not + /// rely on the service still being around after you destroy the + /// last reference, or on the service being around after framework + /// teardown has started. + /// + /// \par Guarantee + /// strong + /// \par Failures + /// configuration errors\n + /// service creation/initialization errors + /// \{ + public: + template<typename T> ::StatusCode + makeService (std::shared_ptr<T>& service) const; + template<typename T> ::StatusCode + makeService (ServiceHandle<T>& service) const; + /// \} + + + + // + // private interface + // + }; + + + + // + // template methods + // + +#ifdef XAOD_STANDALONE + + template<typename T> ::StatusCode AsgServiceConfig :: + makeService (std::shared_ptr<T>& service) const + { + using namespace msgComponentConfig; + + std::unique_ptr<T> myservice; + ANA_CHECK (makeComponentExpert (myservice, "new %1% (\"%2%\", nullptr)", false, "")); + AsgService *asgService = dynamic_cast<AsgService*>(myservice.get()); + ANA_CHECK (asgService->initialize()); + + service = std::move (myservice); + ANA_CHECK (ServiceStore::put (service)); + + ANA_MSG_DEBUG ("Created component of type " << type()); + return StatusCode::SUCCESS; + } + + template<typename T> ::StatusCode AsgServiceConfig :: + makeService (ServiceHandle<T>& service) const + { + using namespace msgComponentConfig; + + std::shared_ptr<T> myservice; + ANA_CHECK (makeService (myservice)); + service = ServiceHandle (myservice, service.parentName()); + return StatusCode::SUCCESS; + } + +#else + + template<typename T> ::StatusCode AsgServiceConfig :: + makeService (std::shared_ptr<T>& service) const + { + using namespace msgComponentConfig; + + ServiceHandle<T> serviceHandle (typeAndName(), "AsgServiceConfig"); + ANA_CHECK (makeService (serviceHandle)); + + // This creates an unmanaged shared pointer, i.e. a pointer that + // doesn't actually own the pointed to object, it will neither + // guarantee to keep the object around until its own destruction, + // nor will it ever trigger a destruction of the object on its own + // destruction. Since the athena framework will keep the services + // around until the end of the job, that ought to be safe if used + // as advertised. + service = std::shared_ptr<T> (std::shared_ptr<void>(), &*serviceHandle); + + ANA_MSG_DEBUG ("Created component of type " << type()); + return StatusCode::SUCCESS; + } + + template<typename T> ::StatusCode AsgServiceConfig :: + makeService (ServiceHandle<T>& service) const + { + using namespace msgComponentConfig; + + ANA_CHECK (configureComponentExpert ("", false)); + service.setTypeAndName (typeAndName()); + ANA_CHECK (service.retrieve()); + ANA_CHECK (dynamic_cast<::AthService*>(&*service)->sysInitialize()); + + ANA_MSG_DEBUG ("Created component of type " << type()); + return StatusCode::SUCCESS; + } + +#endif + +} + +#endif diff --git a/Control/AthToolSupport/AsgServices/AsgServices/AsgServiceMacros.h b/Control/AthToolSupport/AsgServices/AsgServices/AsgServiceMacros.h new file mode 100644 index 0000000000000000000000000000000000000000..035691534c34310b4cc703a3cb4ec1f180211e33 --- /dev/null +++ b/Control/AthToolSupport/AsgServices/AsgServices/AsgServiceMacros.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack +/// @author David Adams <dladams@bnl.gov> (for original implementation for tools) + +#ifndef AsgServiceMacros_H +#define AsgServiceMacros_H + +/// \file CPP macros that turn ASG services into Athena services. + +#ifndef XAOD_STANDALONE + +// This is used in the body of the service interface class definition, e.g. +// class IMyServiceInterface: +// virtual public IAsgService { +// ASG_SERVICE_INTERFACE(MyServiceInterface) +// . +// . +// . +// }; + +#define ASG_SERVICE_INTERFACE(CLASSNAME) \ +public: \ + static const InterfaceID& interfaceID() { \ + static const InterfaceID myid(#CLASSNAME, 1, 0 ); \ + return myid; \ + } + +// This is used in the body of the service implementation definition, e.g. +// class MyServiceInterface: +// virtual public IMyServiceInterface, public AsgService { +// ASG_SERVICE_INTERFACE(MyServiceInterface,IMyServiceInterface) +// . +// . +// . +// }; + +#define ASG_SERVICE_CLASS1(CLASSNAME,INT1) \ + public: \ + StatusCode queryInterface( const InterfaceID& riid, void** ppvi ) override { \ + if ( ppvi == nullptr ) { return StatusCode::FAILURE ; } \ + if ( INT1::interfaceID() == riid ) { \ + *ppvi = static_cast<INT1*>(this); \ + addRef(); \ + return StatusCode::SUCCESS;} \ + return AthService::queryInterface( riid, ppvi );} + +#else + +#define ASG_SERVICE_INTERFACE(CLASSNAME) +#define ASG_SERVICE_CLASS1(CLASSNAME,INT1) + +#endif + +#endif diff --git a/Control/AthToolSupport/AsgServices/AsgServices/AsgServicesDict.h b/Control/AthToolSupport/AsgServices/AsgServices/AsgServicesDict.h new file mode 100644 index 0000000000000000000000000000000000000000..adf156bcc469d6a3e32767aa728d55851b4ab0ae --- /dev/null +++ b/Control/AthToolSupport/AsgServices/AsgServices/AsgServicesDict.h @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ASGSERVICES_ASGSERVICESDICT_H +#define ASGSERVICES_ASGSERVICESDICT_H + +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +// Local include(s): +#include "AsgServices/IAsgService.h" +#include "AsgServices/AsgService.h" +#include "AsgServices/AsgServiceConfig.h" + +#endif // not ASGSERVICES_ASGSERVICESDICT_H diff --git a/Control/AthToolSupport/AsgServices/AsgServices/AsgServicesStandaloneDict.h b/Control/AthToolSupport/AsgServices/AsgServices/AsgServicesStandaloneDict.h new file mode 100644 index 0000000000000000000000000000000000000000..ac71e7e6d5f6f91a7ac4702dad228b54809f9a94 --- /dev/null +++ b/Control/AthToolSupport/AsgServices/AsgServices/AsgServicesStandaloneDict.h @@ -0,0 +1,15 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ASGSERVICES_ASGSERVICESSTANDALONEDICT_H +#define ASGSERVICES_ASGSERVICESSTANDALONEDICT_H + +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +// Local include(s): +#include "AsgServices/ServiceStore.h" + +#endif // not ASGSERVICES_ASGSERVICESDICT_H diff --git a/Control/AthToolSupport/AsgServices/AsgServices/IAsgService.h b/Control/AthToolSupport/AsgServices/AsgServices/IAsgService.h new file mode 100644 index 0000000000000000000000000000000000000000..4e1450dd20bddb637212b18ddb747612f46f4cae --- /dev/null +++ b/Control/AthToolSupport/AsgServices/AsgServices/IAsgService.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack +/// @author David Adams <dladams@bnl.gov> (for original implementation for tools) + +#ifndef ASGSERVICES_IASGSERVICE_H +#define ASGSERVICES_IASGSERVICE_H + +// System include(s): +#include <string> + +// Local include(s): +#include "AsgServices/AsgServiceMacros.h" +#include "AsgMessaging/INamedInterface.h" + +namespace asg +{ + /// Base class for the dual-use service interface classes + /// + /// Loosely based on IAsgTool class + + class IAsgService + : virtual public INamedInterface + { + public: + + /// Print the state of the service + virtual void print() const = 0; + + }; // class IAsgService + +} // namespace asg + +#endif // ASGSERVICES_IASGSERVICE_H diff --git a/Control/AthToolSupport/AsgServices/AsgServices/ServiceHandle.h b/Control/AthToolSupport/AsgServices/AsgServices/ServiceHandle.h new file mode 100644 index 0000000000000000000000000000000000000000..8f9e87bf09621d768fc38999c1daeb21dbcb0152 --- /dev/null +++ b/Control/AthToolSupport/AsgServices/AsgServices/ServiceHandle.h @@ -0,0 +1,131 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack +/// @author David Adams <dladams@bnl.gov> (for original implementation for tools) +/// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> (for original implementation for tools) + + +#ifndef ASGSERVICES_SERVICEHANDLE_H +#define ASGSERVICES_SERVICEHANDLE_H + +// Local include(s): +#ifndef XAOD_STANDALONE +# include "GaudiKernel/ServiceHandle.h" +#else // not XAOD_STANDALONE + +// System include(s): +#include <string> +#include <iosfwd> + +// Local include(s): +#include "AsgMessaging/StatusCode.h" +#include "AsgServices/ServiceStore.h" + +/// Non-templated base class for the ServiceHandle types +/// +/// This base class takes care of implementing all the functionality of +/// ServiceHandle that doesn't depend on the template parameter of the class. +/// Making the built binaries a bit smaller, and faster. +/// +/// Based on \ref ToolHandleBase + +class ServiceHandleBase +{ +public: + /// Constructor with a type/name string + ServiceHandleBase( const std::string& typeAndName, const std::string& parentName ); + + /// Return the type/name string specified by the user + const std::string& typeAndName() const; + /// Return the service's type name + const std::string& type() const; + /// Return the service's instance name + const std::string& name() const; + /// Return the service's parent service name + const std::string& parentName() const; + + /// Change the handle's type and name + void setTypeAndName(const std::string& typeAndName); + /// Change the handle's name + void setName(const std::string& name); + +protected: + /// The type/name string specified in the constructor + std::string m_typeAndName; + /// The type name of the target service + std::string m_type; + /// The instance name of the target service + std::string m_name; + /// The parent service + std::string m_parentName; + +}; // class ServiceHandleBase + +/// Partial re-implementation of Gaudi's ServiceHandle class +/// +/// This class can be used in a dual-use service to find other +/// dual-use services that have been instantiated by the user. +/// +/// Based on \ref ToolHandle implementation + +template< class T > +class ServiceHandle : public ServiceHandleBase +{ +public: + /// A convenience type declaration + typedef T value_type; + + /// Constructor from a service pointer + ServiceHandle( const std::shared_ptr<T>& pservice, + const std::string& parentName ); + + /// Constructor from a service name. + ServiceHandle( const std::string& servicename, const std::string& parentName); + + /// Constructor declaring a property + template<typename T2> + ServiceHandle (T2 *parent, const std::string& propertyName, + const std::string& serviceName, + const std::string& propertyTitle = ""); + + /// Dereferencing operator + T& operator*(); + /// Dereferencing operator + const T& operator*() const; + /// Dereferencing operator + T* operator->(); + /// Dereferencing operator + const T* operator->() const; + + /// Retrieve service. + /// For compatibility with Gaudi. + /// Returns success if pointer is non-null and of the correct type. + StatusCode retrieve() const; + + /// Clear out the service + void disable () noexcept; + + /// Return true if service has no pointer or name + bool empty() const; + + /// Return if the pointer is set + bool isSet() const; + +private: + /// Pointer to the service + mutable std::shared_ptr<T> m_pservice; + +}; // class ServiceHandle + +/// A convenience operator for printing the values of such objects +template< class T > +std::ostream& operator<< ( std::ostream& out, + const ServiceHandle< T >& handle ); + +// Include the implementation of the code: +#include "AsgServices/ServiceHandle.icc" + +#endif // not XAOD_STANDALONE +#endif // ASGSERVICES_SERVICEHANDLE_H diff --git a/Control/AthToolSupport/AsgServices/AsgServices/ServiceHandle.icc b/Control/AthToolSupport/AsgServices/AsgServices/ServiceHandle.icc new file mode 100644 index 0000000000000000000000000000000000000000..bca4b52f304296140f916f4558c4fdf802da8549 --- /dev/null +++ b/Control/AthToolSupport/AsgServices/AsgServices/ServiceHandle.icc @@ -0,0 +1,182 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack +/// @author David Adams <dladams@bnl.gov> (for original implementation for tools) + + + +#ifndef ASGSERVICES_SERVICEHANDLE_ICC +#define ASGSERVICES_SERVICEHANDLE_ICC + +// System include(s): +#include <stdexcept> +#include <iostream> + +// Local include(s): +#include "AsgServices/ServiceStore.h" + +template< class T > +ServiceHandle< T >::ServiceHandle( const std::shared_ptr<T>& pservice, + const std::string& parentName) + : ServiceHandleBase("",parentName), m_pservice( pservice ) +{ + // Set the name in the base class in case we received a valid pointer: + if( m_pservice ) { + m_name = m_pservice->name(); + } +} + +template< class T > +ServiceHandle< T >::ServiceHandle( const std::string& typeAndName, + const std::string& parentName ) +: ServiceHandleBase( typeAndName , parentName ) +{} + +template<typename T> template<typename T2> +ServiceHandle<T> :: +ServiceHandle (T2 *parent, const std::string& propertyName, + const std::string& serviceName, + const std::string& propertyTitle) + : ServiceHandle (serviceName, parent) +{ + parent->declareProperty (propertyName, *this, propertyTitle); +} + +template< class T > +T& ServiceHandle< T >::operator*() +{ + // Retrieve the service pointer if necessary: + if( ! m_pservice ) + m_pservice = asg::ServiceStore::get< T >( name() ); + + // Check if we succeeded: + if( ! m_pservice ) + throw std::runtime_error( "Couldn't find service with name \"" + + name() + "\"" ); + + // Return a reference to the service: + return *m_pservice; +} + +template< class T > +const T& ServiceHandle< T >::operator*() const +{ + // Retrieve the service pointer if necessary: + if( ! m_pservice ) + m_pservice = asg::ServiceStore::get< T >( name() ); + + // Check if we succeeded: + if( ! m_pservice ) + throw std::runtime_error( "Couldn't find service with name \"" + + name() + "\"" ); + + // Return a reference to the service: + return *m_pservice; +} + +template< class T > +T* ServiceHandle<T>::operator->() +{ + // Retrieve the service pointer if necessary: + if( ! m_pservice ) { + m_pservice = asg::ServiceStore::get< T >( name() ); + } + // Check if we succeeded: + if( ! m_pservice ) { + throw std::runtime_error( "Couldn't find service with name \"" + + name() + "\"" ); + } + + // Return the (possibly null-)pointer to the service: + return m_pservice.get(); +} + +template< class T > +const T* ServiceHandle<T>::operator->() const +{ + + // Retrieve the service pointer if necessary: + if( ! m_pservice ) + m_pservice = asg::ServiceStore::get< T >( name() ); + + // Check if we succeeded: + if( ! m_pservice ) + throw std::runtime_error( "Couldn't find service with name \"" + + name() + "\"" ); + + // Return the (possibly null-)pointer to the service: + return m_pservice.get(); +} + +template< class T > +StatusCode ServiceHandle< T >::retrieve() const +{ + // If we have the service already, there's nothing to do: + if( m_pservice ) + return StatusCode::SUCCESS; + + // Try to retrieve the service: + m_pservice = asg::ServiceStore::get< T >( name() ); + + // Check if it succeeded: + if( m_pservice ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } +} + +template< class T > +void ServiceHandle< T >::disable () noexcept +{ + m_pservice.reset (); +} + +template< class T > +bool ServiceHandle< T >::empty() const +{ + return ( ( m_pservice == nullptr ) && ( name().size() == 0 ) ); +} + +template< class T > +bool ServiceHandle< T >::isSet() const +{ + return ( !( m_pservice == nullptr ) ); +} + +template< class T > +std::ostream& operator<<( std::ostream& out, + const ServiceHandle< T >& handle ) +{ + out << "ASG ServiceHandle with name = \"" << handle.name() << "\", pointer = "; + const T* pservice = nullptr; + if (handle.retrieve()) + pservice = &*handle; + out << pservice; + + // Return the same stream object: + return out; +} + +namespace asg +{ + namespace detail + { + StatusCode packStringSingle (const std::string& value, + std::string& result); + + template<typename T> struct GetStringHelper; + + template<typename T> struct GetStringHelper<ServiceHandle<T> > + { + static StatusCode get (const ServiceHandle<T>& value, + std::string& result) { + return packStringSingle (value.typeAndName(), result); + } + }; + } +} + +#endif // ASGSERVICES_SERVICEHANDLE_ICC diff --git a/Control/AthToolSupport/AsgServices/AsgServices/ServiceStore.h b/Control/AthToolSupport/AsgServices/AsgServices/ServiceStore.h new file mode 100644 index 0000000000000000000000000000000000000000..24941b50d515e999e0e5a9b1163ef0ee210cea9f --- /dev/null +++ b/Control/AthToolSupport/AsgServices/AsgServices/ServiceStore.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack +/// @author David Adams <dladams@bnl.gov> (for original implementation for tools) +/// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> (for original implementation for tools) + + + +#ifndef ASGSERVICES_SERVICESTORE_H +#define ASGSERVICES_SERVICESTORE_H + +#ifndef XAOD_STANDALONE +#error "This header should only be used in XAOD_STANDALONE" +#else + +// System include(s): +#include <memory> +#include <string> + +// Local include(s): +#include "AsgServices/IAsgService.h" +#include "AsgMessaging/StatusCode.h" + +namespace asg +{ + + /// A light-weight store for services in stand-alone analysis + /// + /// In order to allow users to find services through + /// ServiceHandles, just like in Athena, we need a global registry + /// of all of the services that the user instantiates in his/her + /// job. + /// + /// This class does exactly this. Services created via \ref + /// AsgServiceConfig get registered here so that other components + /// can find them. + /// + /// Based on \ref ToolStore + + class ServiceStore final + { + public: + /// Store a named service by its name. + /// The name must be non-blank and not already exist in the store. + static StatusCode put( const std::shared_ptr<IAsgService>& pservice ); + + /// Retrieve a service by name. + static std::shared_ptr<IAsgService> get( const std::string& name, bool silent = false ); + + /// Retrieve a service by name and interface. + template< typename T > + // cppcheck-suppress constStatement; false positive + static std::shared_ptr<T> get( const std::string& name ) + { + return std::dynamic_pointer_cast< T >( get( name ) ); + } + + /// Check whether a service with a given type and name is known in the store + template< typename T > + static bool contains( const std::string& name ) + { + return ( dynamic_cast< T* >( get( name, true ).get() ) != 0 ); + } + + /// dump the service configuration for all services to std::cout + static void dumpServiceConfig (); + + }; // class ServiceStore + +} // namespace asg + +#endif + +#endif // ASGSERVICES_SERVICESTORE_H diff --git a/Control/AthToolSupport/AsgServices/AsgServices/selection.xml b/Control/AthToolSupport/AsgServices/AsgServices/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..89a5d061f071fe4be373c65379407ec6e7cd7de8 --- /dev/null +++ b/Control/AthToolSupport/AsgServices/AsgServices/selection.xml @@ -0,0 +1,14 @@ +<!-- + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration + --> + +<lcgdict> + + <!-- The basic service types: --> + <class name="asg::IAsgService" /> + <class name="asg::AsgService" /> + <class name="asg::AsgServiceConfig" /> + + <!-- Helper types: --> + +</lcgdict> diff --git a/Control/AthToolSupport/AsgServices/AsgServices/selection_standalone.xml b/Control/AthToolSupport/AsgServices/AsgServices/selection_standalone.xml new file mode 100644 index 0000000000000000000000000000000000000000..4133fe59de8339a73037fd96582976b84571f180 --- /dev/null +++ b/Control/AthToolSupport/AsgServices/AsgServices/selection_standalone.xml @@ -0,0 +1,9 @@ +<!-- + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration + --> + +<lcgdict> + + <class name="asg::ServiceStore" /> + +</lcgdict> diff --git a/Control/AthToolSupport/AsgServices/CMakeLists.txt b/Control/AthToolSupport/AsgServices/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..009e5a2f08e8f4bcfedd3f7b52337609719e831b --- /dev/null +++ b/Control/AthToolSupport/AsgServices/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + +# Declare the package name: +atlas_subdir( AsgServices ) + +# Dependencies are taken based on what environment we are in: +if( XAOD_STANDALONE ) + set( libs ) +else() + set( libs ) +endif() + +# Decide which sources to use: +if( XAOD_STANDALONE ) + set( sources Root/*.cxx ) +else() + set( sources Root/AsgService.cxx Root/AsgServiceConfig.cxx ) +endif() + +# Component(s) in the package: +atlas_add_library( AsgServicesLib + AsgServices/*.h AsgServices/*.icc ${sources} + PUBLIC_HEADERS AsgServices + PRIVATE_INCLUDE_DIRS + LINK_LIBRARIES AsgTools ${libs} + PRIVATE_LINK_LIBRARIES ) + +# Select which xml files to use for dictionary generation + +atlas_add_dictionary( AsgServicesDict + AsgServices/AsgServicesDict.h AsgServices/selection.xml + LINK_LIBRARIES AsgServicesLib ) + +if (XAOD_STANDALONE) + atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) + atlas_add_test( AsgServiceConfigUnitTests + SCRIPT python -m unittest AsgServices.AsgServiceConfig ) + atlas_add_dictionary( AsgServicesStandaloneDict + AsgServices/AsgServicesStandaloneDict.h AsgServices/selection_standalone.xml + LINK_LIBRARIES AsgServicesLib ) +endif () diff --git a/Control/AthToolSupport/AsgServices/Root/AsgService.cxx b/Control/AthToolSupport/AsgServices/Root/AsgService.cxx new file mode 100644 index 0000000000000000000000000000000000000000..77683417451129811abf6254d9b5e4326ea2cc20 --- /dev/null +++ b/Control/AthToolSupport/AsgServices/Root/AsgService.cxx @@ -0,0 +1,54 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack +/// @author David Adams <dladams@bnl.gov> (for original implementation for tools) + + + +// Local include(s): +#include "AsgServices/AsgService.h" + +// System include(s): +#include <iostream> + +namespace asg +{ + AsgService :: + AsgService( const std::string& name, + ISvcLocator* pSvcLocator ) + : AsgServiceBase( +#ifndef XAOD_STANDALONE + name, pSvcLocator +#else // not XAOD_STANDALONE + name +#endif // not XAOD_STANDALONE + ) + { + (void) pSvcLocator; + } + + StatusCode AsgService :: + initialize () + { + return StatusCode::SUCCESS; + } + + + + StatusCode AsgService :: + finalize () + { + return StatusCode::SUCCESS; + } + + + + void AsgService::print() const + { + ATH_MSG_INFO( "AsgService " << name() << " @ " << this ); + return; + } + +} // namespace asg diff --git a/Control/AthToolSupport/AsgServices/Root/AsgServiceConfig.cxx b/Control/AthToolSupport/AsgServices/Root/AsgServiceConfig.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9c1be6bb4c1b8e5ac111a49d06d077b03d9ddd1e --- /dev/null +++ b/Control/AthToolSupport/AsgServices/Root/AsgServiceConfig.cxx @@ -0,0 +1,28 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <AsgServices/AsgServiceConfig.h> + +#include <AsgServices/AsgService.h> +#include <AsgTools/MessageCheckAsgTools.h> + +// +// method implementations +// + +namespace asg +{ + AsgServiceConfig :: + AsgServiceConfig (const std::string& val_typeAndName) + : AsgComponentConfig (val_typeAndName) + {} +} diff --git a/Control/AthToolSupport/AsgServices/Root/ServiceHandle.cxx b/Control/AthToolSupport/AsgServices/Root/ServiceHandle.cxx new file mode 100644 index 0000000000000000000000000000000000000000..bfa1fa3b560a62267244dc924de5893fa81dc5d8 --- /dev/null +++ b/Control/AthToolSupport/AsgServices/Root/ServiceHandle.cxx @@ -0,0 +1,77 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack +/// @author David Adams <dladams@bnl.gov> (for original implementation for tools) +/// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> (for original implementation for tools) + + + +// Local include(s): +#include "AsgServices/ServiceHandle.h" +#include "AsgServices/IAsgService.h" + +ServiceHandleBase :: +ServiceHandleBase( const std::string& typeAndName, + const std::string& parentName ) + : m_typeAndName( typeAndName ), m_type(), m_name(), m_parentName(parentName) +{ + setTypeAndName(typeAndName); +} + + + +void ServiceHandleBase::setTypeAndName(const std::string& typeAndName) +{ + m_typeAndName = typeAndName; + // Decode the received string: + size_t pos = 0; + if( ( pos = m_typeAndName.find( '/' ) ) == std::string::npos ) + { + // The user specified a single string, which is used as both the type + // and instance name. + m_type = m_typeAndName; + m_name = m_typeAndName; + } else + { + // The user specified both a type and an instance name. + m_type = m_typeAndName.substr( 0, pos ); + m_name = m_typeAndName.substr( pos + 1 ); + } +} + + + +void ServiceHandleBase::setName(const std::string& name) +{ + m_name = name; +} + + + +const std::string& ServiceHandleBase::typeAndName() const +{ + return m_typeAndName; +} + + + +const std::string& ServiceHandleBase::type() const +{ + return m_type; +} + + + +const std::string& ServiceHandleBase::name() const +{ + return m_name; +} + + + +const std::string& ServiceHandleBase::parentName() const +{ + return m_parentName; +} diff --git a/Control/AthToolSupport/AsgServices/Root/ServiceStore.cxx b/Control/AthToolSupport/AsgServices/Root/ServiceStore.cxx new file mode 100644 index 0000000000000000000000000000000000000000..fbecdd3d1f8376ad780d939ea5dc531530211afb --- /dev/null +++ b/Control/AthToolSupport/AsgServices/Root/ServiceStore.cxx @@ -0,0 +1,136 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack +/// @author David Adams <dladams@bnl.gov> (for original implementation for tools) +/// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> (for original implementation for tools) + + + +// Local include(s): +#include "AsgServices/ServiceStore.h" +#include "AsgServices/AsgService.h" +#include "AsgTools/MessageCheckAsgTools.h" +#include "AsgMessaging/MsgStreamMacros.h" + +// System include(s): +#include <map> +#include <iostream> +#include <mutex> + +/// Convenience type definition +typedef std::map< std::string, std::weak_ptr<asg::IAsgService> > ServiceMap_t; + +namespace +{ + /// The application-wide service registry + static ServiceMap_t s_services ATLAS_THREAD_SAFE; + std::mutex s_serviceMutex; +} + +namespace asg +{ + StatusCode ServiceStore:: + put( const std::shared_ptr<IAsgService>& pservice ) + { + using namespace msgComponentConfig; + + // Start with a little sanity check: + if( ! pservice ) + { + ANA_MSG_ERROR( "asg::ServiceStore::put " << + "Received a null pointer" ); + return StatusCode::FAILURE; + } + + // Get and check the name of the service: + const std::string& name = pservice->name(); + if( ! name.size() ) + { + ANA_MSG_ERROR( "asg::ServiceStore::put " << + "The received service doesn't have a name" ); + return StatusCode::FAILURE; + } + + std::lock_guard<std::mutex> lock (s_serviceMutex); + + auto& currentService = s_services[name]; + if (currentService.lock()) + { + ANA_MSG_ERROR ("Service with name \"" + << name << "\" already registered"); + return StatusCode::FAILURE; + } + + currentService = pservice; + return StatusCode::SUCCESS; + } + + + + std::shared_ptr<IAsgService> ServiceStore:: + get( const std::string& name, bool silent ) + { + using namespace msgToolHandle; + + std::lock_guard<std::mutex> lock (s_serviceMutex); + auto iservice = s_services.find( name ); + + std::shared_ptr<IAsgService> result; + if( iservice != s_services.end() ) + result = iservice->second.lock(); + + if( ! silent && !result ) + ANA_MSG_ERROR ("Service with name \"" << name << "\" not found"); + return result; + } + + + + void ServiceStore::dumpServiceConfig () + { + using namespace asg::msgProperty; + + // I am first putting everything into a map, so that the error + // messages don't interleave the property values + std::map<std::string,std::map<std::string,std::string> > properties; + + std::lock_guard<std::mutex> lock (s_serviceMutex); + for (auto& service : s_services) + { + auto myservice = service.second.lock(); + if (myservice) + { + auto& myproperties = properties[service.first]; + myproperties[""] = std::string (typeid(*myservice).name()) + "/" + service.first; + for (auto& property : dynamic_cast<const AsgService*>(myservice.get())->getPropertyMgr()->getProperties()) + { + std::string asString; + if (property.second->getString (asString).isFailure()) + { + ANA_MSG_ERROR ("on property " << property.first << " for service " << service.first); + myproperties[property.first] = "<<invalid>>"; + } else + myproperties[property.first] = asString; + } + } + } + // Using std::cout here intentionally to bypass the messaging + // system to avoid accidental changes to the formatting. This + // could be updated in the future to allow the user to pass in the + // stream to output to, if desired. + for (const auto& myproperties : properties) + { + for (auto& property : myproperties.second) + { + std::cout << myproperties.first; + if (!property.first.empty()) + std::cout << "." << property.first; + std::cout << " = " << property.second << "\n"; + } + } + std::cout << std::flush; + } + +} // namespace asg