| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* This file is a part of NA64SW software. | ||
| 2 | * Copyright (C) 2015-2022 NA64 Collaboration, CERN | ||
| 3 | * | ||
| 4 | * NA64SW is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 3 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #include "na64util/str-fmt.hh" | ||
| 20 | |||
| 21 | namespace na64dp { | ||
| 22 | namespace calib { class Manager; } // fwd | ||
| 23 | class iEvProcInfo; // fwd | ||
| 24 | |||
| 25 | /**\brief A base class for (loadable) extension instance | ||
| 26 | * | ||
| 27 | * User handlers may bring some additional dependencies of global/singleton | ||
| 28 | * objects that have to be initialized/bound to NA64SW infrastructure in other | ||
| 29 | * way as other handlers. | ||
| 30 | * | ||
| 31 | * Typical example is ROOT objects like geometry manager, event display window | ||
| 32 | * or other common singletons. This base class provides a way to register such | ||
| 33 | * objects, initialize and access them further with single entry point | ||
| 34 | * (`na64dp::Extensions`). | ||
| 35 | * */ | ||
| 36 | struct iRuntimeExtension { | ||
| 37 | virtual ~iRuntimeExtension() {} | ||
| 38 | virtual void init(calib::Manager &, iEvProcInfo * epi) = 0; | ||
| 39 | //virtual std::unordered_map<std::string, std::string> parameters() const = 0; | ||
| 40 | virtual void finalize() {} | ||
| 41 | virtual void set_parameter(const std::string &, const std::string &) = 0; | ||
| 42 | |||
| 43 | /// Helper method, shortcut for `dynamic_cast<>()` | ||
| 44 | template<typename T> T & as() { | ||
| 45 | T * p = dynamic_cast<T*>(this); | ||
| 46 | if(!p) { | ||
| 47 | // TODO: details (demangled RTTI type, etc) | ||
| 48 | NA64DP_RUNTIME_ERROR("Bad cast for extension."); | ||
| 49 | } | ||
| 50 | return *p; | ||
| 51 | } | ||
| 52 | }; | ||
| 53 | |||
| 54 | /**\brief An entry point for runtime extensions | ||
| 55 | * | ||
| 56 | * Manages instances of (loadable) extension classes (subclasses of | ||
| 57 | * `iRuntimeExtension`). Implied lifecycle: | ||
| 58 | * 1. Loadable modules adds their extension objects with `add()` method | ||
| 59 | * 2. After logging, monitor and calibration manager are instantiated, an | ||
| 60 | * `init()` method called forwarding calls to extension requested. | ||
| 61 | * 3. After app is done, it calls `shutdown()` method to clear resources used | ||
| 62 | * by extensions. | ||
| 63 | * Note, that some extensions may not create objects to be used during | ||
| 64 | * `init()`, depending on their configuration. | ||
| 65 | * */ | ||
| 66 | class Extensions : private std::unordered_map<std::string, iRuntimeExtension *> { | ||
| 67 | private: | ||
| 68 | static Extensions * _self; | ||
| 69 | /// Private ctr invoked by `self()` | ||
| 70 | Extensions(); | ||
| 71 | public: | ||
| 72 | /// Returns instance (singleton) | ||
| 73 | static Extensions & self(); | ||
| 74 | |||
| 75 | ///\brief Adds runtime extension to be managed by this registry | ||
| 76 | /// | ||
| 77 | ///\throws `DuplicateExtensionName` if extension name is not unique | ||
| 78 | ///\note Delegates ownershit to `Extensions`; assumed to be allocated | ||
| 79 | /// with `new`. | ||
| 80 | bool add(const std::string &, iRuntimeExtension *); | ||
| 81 | /// Returns ref to named `iRuntimeExtension` subclass instance previously | ||
| 82 | /// added with `add()` | ||
| 83 | iRuntimeExtension & operator[](const std::string &); | ||
| 84 | |||
| 85 | /// Sets an extension's parameter | ||
| 86 | void set_parameter(const std::string &, const std::string &); | ||
| 87 | /// Forwars execution to `iExtension::init()` | ||
| 88 | void init( calib::Manager & | ||
| 89 | , iEvProcInfo * epi | ||
| 90 | ); | ||
| 91 | /// Called after application done with data processing | ||
| 92 | void finalize(); | ||
| 93 | /// Deletes all instantiated extensions | ||
| 94 | void shutdown(); | ||
| 95 | }; // class Extensions | ||
| 96 | |||
| 97 | namespace errors { | ||
| 98 | |||
| 99 | class NoExtension : public GenericRuntimeError { | ||
| 100 | public: | ||
| 101 | const std::string extName; | ||
| 102 | |||
| 103 | ✗ | NoExtension( const std::string & extName_ ) | |
| 104 | ✗ | : GenericRuntimeError( util::format("Extension \"%s\" is not loaded." | |
| 105 | , extName_.c_str() ).c_str() ) | ||
| 106 | ✗ | , extName(extName_) {} | |
| 107 | }; | ||
| 108 | |||
| 109 | class DuplicateExtensionName : public GenericRuntimeError { | ||
| 110 | public: | ||
| 111 | const std::string extName; | ||
| 112 | |||
| 113 | ✗ | DuplicateExtensionName( const std::string & extName_ ) | |
| 114 | ✗ | : GenericRuntimeError( util::format("Extension name \"%s\" is" | |
| 115 | " already taken (repeated instantiation?)." | ||
| 116 | , extName_.c_str() ).c_str() ) | ||
| 117 | ✗ | , extName(extName_) {} | |
| 118 | }; | ||
| 119 | |||
| 120 | } // namespace ::na64dp::errors | ||
| 121 | } // namespace na64dp | ||
| 122 | |||
| 123 | /**\brief Registers new runtime extension | ||
| 124 | * \ingroup vctr-defs | ||
| 125 | * | ||
| 126 | * Registers subclasses of `iRuntimeExtension` managed with `Extensions`. | ||
| 127 | * | ||
| 128 | * \param clsName The name of the extension instance | ||
| 129 | */ | ||
| 130 | # define REGISTER_EXTENSION( clsName ) \ | ||
| 131 | static bool _regResult_ ## clsName = \ | ||
| 132 | ::na64dp::Extensions::self().add( # clsName, new clsName ); | ||
| 133 | |||
| 134 |