Line data Source code
1 : //* This file is part of the MOOSE framework 2 : //* https://mooseframework.inl.gov 3 : //* 4 : //* All rights reserved, see COPYRIGHT for full restrictions 5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT 6 : //* 7 : //* Licensed under LGPL 2.1, please see LICENSE for details 8 : //* https://www.gnu.org/licenses/lgpl-2.1.html 9 : 10 : #pragma once 11 : 12 : #include <string> 13 : #include <map> 14 : #include <type_traits> 15 : #include <typeindex> 16 : 17 : #include "MooseError.h" 18 : #include "MooseUtils.h" 19 : 20 : #include "minijson/minijson.h" 21 : 22 : class WebServerControl; 23 : 24 : namespace Moose 25 : { 26 : /** 27 : * A static registry used to register and build values of different types for the WebServerControl 28 : * 29 : * Needed due to the complexities of parsing parameter types from generic JSON received 30 : * by the web server. 31 : */ 32 : class WebServerControlTypeRegistry 33 : { 34 : public: 35 : /** 36 : * @return The WebServerControlTypeRegistry singleton 37 : */ 38 : static WebServerControlTypeRegistry & getRegistry(); 39 : 40 : /** 41 : * The base class for a value that is produced by this registry. 42 : */ 43 : class ValueBase 44 : { 45 : public: 46 : /** 47 : * Constructor. 48 : * @param name The name that the value is for (typically a controllable path) 49 : * @param type The string representationg of the type 50 : */ 51 190 : ValueBase(const std::string & name, const std::string & type) : _name(name), _type(type) {} 52 190 : virtual ~ValueBase() {} 53 : 54 : /** 55 : * @return The name that the value is for 56 : */ 57 318 : const std::string & name() const { return _name; } 58 : /** 59 : * @return The string representation of the type 60 : */ 61 128 : const std::string & type() const { return _type; } 62 : 63 : /** 64 : * Sets the controllable value given the name and type via the controllable 65 : * interface in \p control. 66 : * 67 : * Will broadcast the value for setting it. 68 : */ 69 : virtual void setControllableValue(WebServerControl & control) = 0; 70 : 71 : /** 72 : * Common exception for parsing related errors in converting JSON to a value. 73 : */ 74 : struct Exception : public std::exception 75 : { 76 : public: 77 0 : Exception(const std::string & message) : _message(message) {} 78 0 : virtual const char * what() const noexcept override final { return _message.c_str(); } 79 : 80 : private: 81 : const std::string _message; 82 : }; 83 : 84 : private: 85 : /// The name that the value is for 86 : const std::string _name; 87 : /// The string representation of the type 88 : const std::string _type; 89 : }; 90 : 91 : /** 92 : * Registers a type with string name \p type_name and the given derived type. 93 : */ 94 : template <typename DerivedValueType> 95 447224 : static char add(const std::string & type_name) 96 : { 97 : static_assert(std::is_base_of_v<ValueBase, DerivedValueType>, "Is not derived from ValueBase"); 98 : using value_type = typename DerivedValueType::value_type; 99 447224 : static const std::type_index index = typeid(value_type); 100 447224 : if (!getRegistry() 101 894448 : ._name_map.emplace(type_name, std::make_unique<Type<DerivedValueType>>(type_name)) 102 447224 : .second) 103 0 : ::mooseError("WebServerControlTypeRegistry: The string type \"", 104 : type_name, 105 : "\" is already registered."); 106 447224 : if (!getRegistry()._value_types.insert(index).second) 107 0 : ::mooseError("WebServerControlRegistry: The type \"", 108 : MooseUtils::prettyCppType<value_type>(), 109 : "\" is already registered"); 110 447224 : return 0; 111 : } 112 : 113 : /** 114 : * @return Whether or not the type \p type is registered. 115 : */ 116 128 : static bool isRegistered(const std::string & type) { return getRegistry()._name_map.count(type); } 117 : 118 : /** 119 : * Builds a value with the type \p type, name \p name, and a default value. 120 : */ 121 62 : static std::unique_ptr<ValueBase> build(const std::string & type, const std::string & name) 122 : { 123 62 : return get(type).build(name); 124 : } 125 : /** 126 : * Builds a value with the type \p type, name \p name, and a value parsed from \p json_value. 127 : * 128 : * Will throw ValueBase::Exception on a parsing error. 129 : */ 130 : static std::unique_ptr<ValueBase> 131 128 : build(const std::string & type, const std::string & name, const miniJson::Json & json_value) 132 : { 133 128 : return get(type).build(name, json_value); 134 : } 135 : 136 : private: 137 : /** 138 : * Base registry class for a type that is used to build values. 139 : */ 140 : class TypeBase 141 : { 142 : public: 143 447224 : TypeBase(const std::string & type) : _type(type) {} 144 0 : virtual ~TypeBase() {} 145 : 146 : /** 147 : * @return The string representation of the type 148 : */ 149 190 : const std::string & type() const { return _type; } 150 : /** 151 : * Builds a value with the given type, name \p name, and JSON value \p json_value. 152 : * 153 : * This will parse the JSON value into the underlying type and will be called 154 : * on only rank 0 where server listens. 155 : */ 156 : virtual std::unique_ptr<ValueBase> build(const std::string & name, 157 : const miniJson::Json & json_value) const = 0; 158 : /** 159 : * Builds a value with the given type, name \p name, and a default value. 160 : * 161 : * This will be called on processors that are not rank 0 for cloning. 162 : */ 163 : virtual std::unique_ptr<ValueBase> build(const std::string & name) const = 0; 164 : 165 : private: 166 : /// The string representation of the underlying type 167 : const std::string _type; 168 : }; 169 : 170 : template <class DerivedValueType> 171 : struct Type : public TypeBase 172 : { 173 447224 : Type(const std::string & type) : TypeBase(type) {} 174 : 175 : using value_type = typename DerivedValueType::value_type; 176 : 177 62 : virtual std::unique_ptr<ValueBase> build(const std::string & name) const override final 178 : { 179 62 : return std::make_unique<DerivedValueType>(name, type()); 180 : } 181 128 : virtual std::unique_ptr<ValueBase> build(const std::string & name, 182 : const miniJson::Json & json_value) const override final 183 : { 184 128 : return std::make_unique<DerivedValueType>(name, type(), json_value); 185 : } 186 : }; 187 : 188 : /** 189 : * Internal getter for the registration object for type \p type. 190 : */ 191 190 : static const TypeBase & get(const std::string & type) 192 : { 193 190 : auto & registry = getRegistry(); 194 190 : const auto it = registry._name_map.find(type); 195 190 : if (it == registry._name_map.end()) 196 0 : mooseError("WebServerControlTypeRegistry: The type '", type, "' is not registered"); 197 380 : return *it->second; 198 : } 199 : 200 : /// The registration data 201 : std::map<std::string, std::unique_ptr<TypeBase>> _name_map; 202 : /// The registered value types, to avoid registering the same underlying 203 : /// value type multiple times 204 : std::set<std::type_index> _value_types; 205 : }; 206 : }