1 /* 2 Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License, version 2.0, 6 as published by the Free Software Foundation. 7 8 This program is also distributed with certain software (including 9 but not limited to OpenSSL) that is licensed under separate terms, 10 as designated in a particular file or component or in included license 11 documentation. The authors of MySQL hereby grant you an additional 12 permission to link the program and your derivative works with the 13 separately licensed software that they have included with MySQL. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program; if not, write to the Free Software 22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 */ 24 25 #ifndef MYSQL_HARNESS_DIMANAGER_INCLUDED 26 #define MYSQL_HARNESS_DIMANAGER_INCLUDED 27 28 #include "harness_export.h" 29 #include "unique_ptr.h" 30 31 #include <functional> 32 #include <mutex> // using fwd declaration + ptr-to-implementation gives build errors on BSD-based systems 33 #include <string> // unfortunately, std::string is a typedef and therefore not easy to forward-declare 34 35 /** @file 36 * @brief Provides simple, yet useful dependency injection mechanism 37 * 38 * # Introduction 39 * 40 * Let's start with showing usage, for example class Foo: 41 * 42 * @code 43 * class Foo { 44 * public: 45 * Foo(); 46 * void do_something(); 47 * }; 48 * @endcode 49 * 50 * We want DIM to make instance(s) of this class available throughout our 51 * application. 52 * 53 * ## Scenario 1: when Foo is a singleton 54 * 55 * @code 56 * void init_code() { 57 * DIM::instance().set_Foo([](){ return new Foo; }); 58 * } 59 * 60 * void use_code() { 61 * Foo& foo = DIM::instance().get_Foo(); 62 * 63 * // each call works on the same object 64 * foo.do_something(); 65 * foo.do_something(); 66 * foo.do_something(); 67 * } 68 * @endcode 69 * 70 * ## Scenario 2: when Foo is not a singleton 71 * 72 * @code 73 * void init_code() { 74 * DIM::instance().set_Foo([](){ return new Foo; }); 75 * } 76 * 77 * void use_code() { 78 * // each call generates a new object 79 * UniquePtr<Foo> foo1 = DIM::instance().new_Foo(); 80 * foo1->do_something(); 81 * 82 * UniquePtr<Foo> foo2 = DIM::instance().new_Foo(); 83 * foo2->do_something(); 84 * 85 * UniquePtr<Foo> foo3 = DIM::instance().new_Foo(); 86 * foo3->do_something(); 87 * } 88 * @endcode 89 * 90 * ## Scenario 3: when Foo already exists (typically used in unit tests) 91 * 92 * @code 93 * Foo foo_that_lives_forever; 94 * 95 * void init_code() { 96 * DIM::instance().set_Foo( 97 * [](){ 98 * return &foo_that_lives_forever; 99 * }, 100 * [](Foo*) {}); // so that DIM does not try to delete it 101 * } 102 * 103 * void use_code() { 104 * Foo& foo = DIM::instance().get_Foo(); 105 * foo.do_something(); 106 * } 107 * @endcode 108 * 109 * Convenient, isn't it? But to make all this happen, class Foo (boilerplate 110 * code) has to be added to DIM class. 111 * 112 * # Usage 113 * 114 * Adding a new managed object is done in 4 steps: 115 * 116 * 1. add class forward declaration 117 * 2. add object factory + deleter setter 118 * 3. add singleton object getter or object creator. Adding both usually makes 119 * no sense 120 * 4. add factory and deleter function objects 121 * 122 * Here is the (relevant part of) class DIM for class Foo: 123 * 124 * 125 * @code 126 * // [step 1] 127 * // forward declarations 128 * class Foo; 129 * 130 * class DIM { 131 * // ... constructors, instance(), other support methods ... 132 * 133 * public: 134 * // [step 2] 135 * // factory + deleter setter 136 * void set_Foo(const std::function<Foo*(void)>& factory, 137 * const std::function<void(Foo*)>& deleter = 138 * std::default_delete<Foo>()) { 139 * factory_Foo_ = factory; deleter_Foo_ = deleter; 140 * } 141 * 142 * // [step 3] 143 * // singleton object getter 144 * // (shown here, but normally mutually-exclusive with next method) 145 * Foo& get_Foo() const { 146 * return get_generic<Foo>(factory_Foo_, deleter_Foo_); 147 * } 148 * 149 * // object creator 150 * // (shown here, but normally mutually-exclusive with previous method) 151 * UniquePtr<Foo> new_Foo() const { 152 * return new_generic(factory_Foo_, deleter_Foo_); 153 * } 154 * 155 * private: 156 * // factory and deleter function objects [step 4] 157 * std::function<Foo*(void)> factory_Foo_; 158 * std::function<void(Foo*)> deleter_Foo_; 159 * }; 160 * @endcode 161 * 162 * 163 * ## Example 164 * 165 * @code 166 * // forward declarations [step 1] 167 * class Foo; 168 * class Bar; 169 * class Baz; 170 * 171 * class DIM { 172 * // ... constructors, instance(), other support methods ... 173 * 174 * // Example: Foo depends on Bar and Baz, 175 * // Bar depends on Baz and some int, 176 * // Baz depends on nothing 177 * 178 * public: 179 * // factory + deleter setters [step 2] 180 * void set_Foo(const std::function<Foo*(void)>& factory, 181 * const std::function<void(Foo*)>& deleter = 182 * std::default_delete<Foo>()) { 183 * factory_Foo_ = factory; deleter_Foo_ = deleter; 184 * } 185 * 186 * void set_Bar(const std::function<Bar*(void)>& factory, 187 * const std::function<void(Bar*)>& deleter = 188 * std::default_delete<Bar>()) { 189 * factory_Bar_ = factory; deleter_Bar_ = deleter; 190 * } 191 * 192 * void set_Baz(const std::function<Baz*(void)>& factory, 193 * const std::function<void(Baz*)>& deleter = 194 * std::default_delete<Baz>()) { 195 * factory_Baz_ = factory; deleter_Baz_ = deleter; 196 * } 197 * 198 * // singleton object getters 199 * // (all are shown, but normally mutually-exclusive 200 * // with next group) [step 3] 201 * Foo& get_Foo() const { 202 * return get_generic<Foo>(factory_Foo_, deleter_Foo_); 203 * } 204 * Bar& get_Bar() const { 205 * return get_generic<Bar>(factory_Bar_, deleter_Bar_); 206 * } 207 * Baz& get_Baz() const { 208 * return get_generic<Baz>(factory_Baz_, deleter_Baz_); 209 * } 210 * 211 * // object creators 212 * // (all are shown, but normally mutually-exclusive 213 * // with previous group) [step 3] 214 * UniquePtr<Foo> new_Foo() const { 215 * return new_generic(factory_Foo_, deleter_Foo_); 216 * } 217 * UniquePtr<Bar> new_Bar() const { 218 * return new_generic(factory_Bar_, deleter_Bar_); 219 * } 220 * UniquePtr<Baz> new_Baz() const { 221 * return new_generic(factory_Baz_, deleter_Baz_); 222 * } 223 * 224 * private: 225 * // factory and deleter function objects [step 4] 226 * std::function<Foo*(void)> factory_Foo_; 227 * std::function<void(Foo*)> deleter_Foo_; 228 * std::function<Bar*(void)> factory_Bar_; 229 * std::function<void(Bar*)> deleter_Bar_; 230 * std::function<Baz*(void)> factory_Baz_; 231 * std::function<void(Baz*)> deleter_Baz_; 232 * }; 233 * 234 * 235 * 236 * // actual classes 237 * struct Baz { 238 * Baz() {} 239 * }; 240 * struct Bar { 241 * Bar(Baz, int) {} 242 * }; 243 * struct Foo { 244 * Foo(Bar, Baz) {} 245 * void do_something() {} 246 * }; 247 * 248 * 249 * 250 * // usage 251 * int main() { 252 * int n = 3306; 253 * 254 * // init code 255 * DIM& dim = DIM::instance(); 256 * dim.set_Foo([&dim]() { 257 * return new Foo(dim.get_Bar(), dim.get_Baz()); }); 258 * dim.set_Bar([&dim, n]() { 259 * return new Bar(dim.get_Baz(), n); }); 260 * dim.set_Baz([]() { 261 * return new Baz; }); 262 * 263 * // use code (as singleton) 264 * // 265 * // will automatically instantiate Bar and Baz as well 266 * dim.get_Foo().do_something(); 267 * 268 * // use code (as new object) 269 * UniquePtr<Foo> foo = dim.new_Foo(); 270 * foo->do_something(); 271 * } 272 * @endcode 273 * 274 * # Object Reset 275 * 276 * There's also an option to reset an object managed by DIM, should you need it. 277 * Normally, on the first call to get_Foo(), it will call the factory_Foo_() to 278 * create the object before returning it. On subsequent calls, it will just 279 * return that Foo object previously created. But what if you needed to reset 280 * that object? And perhaps to create it via another Foo factory method, or with 281 * different parameters? 282 * 283 * For such case, we can define reset_Foo() method, which will reset the Foo 284 * object back to nullptr. The Foo object can no longer be kept inside of 285 * get_Foo(), because it has to be modifiable via reset_Foo(). Here's the code: 286 * 287 * 288 * @code 289 * // Foo-related members. 290 * // 291 * // instance_Foo_ is new here, it now stores the Foo object 292 * // 293 * // (previously, this object was stored as a static variable 294 * // inside of get_Foo() 295 * std::function<Foo*(void)> factory_Foo_; 296 * std::function<void(Foo*)> deleter_Foo_; 297 * UniquePtr<Foo> instance_Foo_; // <---- new member 298 * 299 * // getter now relies on get_external_generic() to manage the Foo object 300 * Foo& get_Foo() { 301 * return get_external_generic(instance_Foo_, 302 * factory_Foo_, 303 * deleter_Foo_); 304 * } 305 * 306 * // this is our new function. 307 * // 308 * // After calling it, set_Foo() can be used again 309 * // to set the factory method, which will be 310 * // triggered on subsequent call to get_Foo() to 311 * // create the new Foo object 312 * void reset_Foo() { reset_generic(instance_Foo_); } 313 * 314 * // set_Foo remains unaltered 315 * void set_Foo(const std::function<Foo*(void)>& factory, 316 * const std::function<void(Foo*)>& deleter = 317 * std::default_delete<Foo>()) { 318 * factory_Foo_ = factory; 319 * deleter_Foo_ = deleter; 320 * } 321 * @endcode 322 * 323 * ## Example 324 * 325 * @code 326 * // init code 327 * DIM& dim = DIM::instance(); 328 * dim.set_Foo([]() { return new Foo(42); }); 329 * 330 * // use code 331 * 332 * // automatically calls set_Foo() which returns new Foo(42) 333 * dim.get_Foo().do_something(); 334 * 335 * // does not call set_Foo() anymore 336 * dim.get_Foo().do_something(); 337 * 338 * // does not call set_Foo() anymore 339 * dim.get_Foo().do_something(); 340 * 341 * // sets new creating function 342 * dim.set_Foo([]() { 343 * return new Foo(555); 344 * }); 345 * // but the new set_Foo() is still not called 346 * dim.get_Foo().do_something(); 347 * 348 * dim.reset_Foo(); 349 * 350 * // automatically calls (new) set_Foo(), which returns new Foo(555) 351 * dim.get_Foo().do_something(); 352 * @endcode 353 * 354 */ 355 356 // forward declarations [step 1] 357 namespace mysqlrouter { 358 class MySQLSession; 359 } 360 namespace mysqlrouter { 361 class Ofstream; 362 } 363 namespace mysql_harness { 364 class RandomGeneratorInterface; 365 } 366 namespace mysql_harness { 367 namespace logging { 368 class Registry; 369 } 370 } // namespace mysql_harness 371 namespace mysql_harness { 372 class LoaderConfig; 373 } 374 namespace mysql_harness { 375 class DynamicState; 376 } 377 378 namespace mysql_harness { 379 380 class HARNESS_EXPORT DIM { // DIM = Dependency Injection Manager 381 382 // this class is a singleton 383 protected: 384 DIM(); 385 ~DIM(); 386 387 public: 388 DIM(const DIM &) = delete; 389 DIM &operator=(const DIM &) = delete; 390 static DIM &instance(); 391 392 // NOTE: once we gain confidence in this DIM and we can treat it as black box, 393 // all the boilerplate stuff (steps 2-4) for each class can be generated 394 // by a macro) 395 396 public: 397 //////////////////////////////////////////////////////////////////////////////// 398 // factory and deleter setters [step 2] 399 //////////////////////////////////////////////////////////////////////////////// 400 401 // Logging Registry reset_LoggingRegistry()402 void reset_LoggingRegistry() { reset_generic(instance_LoggingRegistry_); } set_LoggingRegistry(const std::function<mysql_harness::logging::Registry * (void)> & factory,const std::function<void (mysql_harness::logging::Registry *)> & deleter)403 void set_LoggingRegistry( 404 const std::function<mysql_harness::logging::Registry *(void)> &factory, 405 const std::function<void(mysql_harness::logging::Registry *)> &deleter) { 406 factory_LoggingRegistry_ = factory; 407 deleter_LoggingRegistry_ = deleter; 408 } 409 410 // MySQLSession set_MySQLSession(const std::function<mysqlrouter::MySQLSession * (void)> & factory,const std::function<void (mysqlrouter::MySQLSession *)> & deleter)411 void set_MySQLSession( 412 const std::function<mysqlrouter::MySQLSession *(void)> &factory, 413 const std::function<void(mysqlrouter::MySQLSession *)> &deleter) { 414 factory_MySQLSession_ = factory; 415 deleter_MySQLSession_ = deleter; 416 } 417 418 // Ofstream set_Ofstream(const std::function<mysqlrouter::Ofstream * (void)> & factory,const std::function<void (mysqlrouter::Ofstream *)> & deleter)419 void set_Ofstream( 420 const std::function<mysqlrouter::Ofstream *(void)> &factory, 421 const std::function<void(mysqlrouter::Ofstream *)> &deleter) { 422 factory_Ofstream_ = factory; 423 deleter_Ofstream_ = deleter; 424 } 425 426 // RandomGenerator set_RandomGenerator(const std::function<mysql_harness::RandomGeneratorInterface * (void)> & factory,const std::function<void (mysql_harness::RandomGeneratorInterface *)> & deleter)427 void set_RandomGenerator( 428 const std::function<mysql_harness::RandomGeneratorInterface *(void)> 429 &factory, 430 const std::function<void(mysql_harness::RandomGeneratorInterface *)> 431 &deleter) { 432 factory_RandomGenerator_ = factory; 433 deleter_RandomGenerator_ = deleter; 434 } 435 436 // LoaderConfig reset_Config()437 void reset_Config() { reset_generic(instance_Config_); } set_Config(const std::function<mysql_harness::LoaderConfig * (void)> & factory,const std::function<void (mysql_harness::LoaderConfig *)> & deleter)438 void set_Config( 439 const std::function<mysql_harness::LoaderConfig *(void)> &factory, 440 const std::function<void(mysql_harness::LoaderConfig *)> &deleter) { 441 factory_Config_ = factory; 442 deleter_Config_ = deleter; 443 } 444 445 // DynamicState reset_DynamicState()446 void reset_DynamicState() { reset_generic(instance_DynamicState_); } set_DynamicState(const std::function<mysql_harness::DynamicState * (void)> & factory,const std::function<void (mysql_harness::DynamicState *)> & deleter)447 void set_DynamicState( 448 const std::function<mysql_harness::DynamicState *(void)> &factory, 449 const std::function<void(mysql_harness::DynamicState *)> &deleter) { 450 factory_DynamicState_ = factory; 451 deleter_DynamicState_ = deleter; 452 } 453 454 //////////////////////////////////////////////////////////////////////////////// 455 // object getters [step 3] (used for singleton objects) 456 //////////////////////////////////////////////////////////////////////////////// 457 458 // Logging Registry get_LoggingRegistry()459 mysql_harness::logging::Registry &get_LoggingRegistry() { 460 return get_external_generic(instance_LoggingRegistry_, 461 factory_LoggingRegistry_, 462 deleter_LoggingRegistry_); 463 } 464 465 // RandomGenerator get_RandomGenerator()466 mysql_harness::RandomGeneratorInterface &get_RandomGenerator() const { 467 return get_generic(factory_RandomGenerator_, deleter_RandomGenerator_); 468 } 469 470 // LoaderConfig get_Config()471 mysql_harness::LoaderConfig &get_Config() { 472 return get_external_generic(instance_Config_, factory_Config_, 473 deleter_Config_); 474 } 475 476 // DynamicState is_DynamicState()477 bool is_DynamicState() { return (bool)instance_DynamicState_; } get_DynamicState()478 mysql_harness::DynamicState &get_DynamicState() { 479 return get_external_generic(instance_DynamicState_, factory_DynamicState_, 480 deleter_DynamicState_); 481 } 482 483 //////////////////////////////////////////////////////////////////////////////// 484 // object creators [step 3] (used for non-singleton objects) 485 //////////////////////////////////////////////////////////////////////////////// 486 487 // MySQLSession new_MySQLSession()488 UniquePtr<mysqlrouter::MySQLSession> new_MySQLSession() const { 489 return new_generic(factory_MySQLSession_, deleter_MySQLSession_); 490 } 491 492 // Ofstream new_Ofstream()493 UniquePtr<mysqlrouter::Ofstream> new_Ofstream() const { 494 return new_generic(factory_Ofstream_, deleter_Ofstream_); 495 } 496 497 private: 498 //////////////////////////////////////////////////////////////////////////////// 499 // factory and deleter functions [step 4] 500 //////////////////////////////////////////////////////////////////////////////// 501 502 // Logging Registry 503 std::function<mysql_harness::logging::Registry *(void)> 504 factory_LoggingRegistry_; 505 std::function<void(mysql_harness::logging::Registry *)> 506 deleter_LoggingRegistry_; 507 UniquePtr<mysql_harness::logging::Registry> instance_LoggingRegistry_; 508 509 // MySQLSession 510 std::function<mysqlrouter::MySQLSession *(void)> factory_MySQLSession_; 511 std::function<void(mysqlrouter::MySQLSession *)> deleter_MySQLSession_; 512 513 // Ofstream 514 std::function<mysqlrouter::Ofstream *(void)> factory_Ofstream_; 515 std::function<void(mysqlrouter::Ofstream *)> deleter_Ofstream_; 516 517 // RandomGenerator 518 std::function<mysql_harness::RandomGeneratorInterface *(void)> 519 factory_RandomGenerator_; 520 std::function<void(mysql_harness::RandomGeneratorInterface *)> 521 deleter_RandomGenerator_; 522 523 // LoaderConfig 524 std::function<mysql_harness::LoaderConfig *(void)> factory_Config_; 525 std::function<void(mysql_harness::LoaderConfig *)> deleter_Config_; 526 UniquePtr<mysql_harness::LoaderConfig> instance_Config_; 527 528 // DynamicState 529 std::function<mysql_harness::DynamicState *(void)> factory_DynamicState_; 530 std::function<void(mysql_harness::DynamicState *)> deleter_DynamicState_; 531 UniquePtr<mysql_harness::DynamicState> instance_DynamicState_; 532 533 //////////////////////////////////////////////////////////////////////////////// 534 // utility functions 535 //////////////////////////////////////////////////////////////////////////////// 536 537 protected: 538 template <typename T> get_generic(const std::function<T * (void)> & factory,const std::function<void (T *)> & deleter)539 static T &get_generic(const std::function<T *(void)> &factory, 540 const std::function<void(T *)> &deleter) { 541 static UniquePtr<T> obj = new_generic(factory, deleter); 542 return *obj; 543 } 544 545 // new_generic*() (add more variants if needed, or convert into varargs 546 // template) 547 template <typename T> new_generic(const std::function<T * (void)> & factory,const std::function<void (T *)> & deleter)548 static UniquePtr<T> new_generic(const std::function<T *(void)> &factory, 549 const std::function<void(T *)> &deleter) { 550 return UniquePtr<T>(factory(), 551 [deleter](T *p) { 552 deleter(p); 553 } // [&deleter] would be unsafe if set_T() was called 554 // before this object got erased 555 ); 556 } 557 template <typename T, typename A1> new_generic1(const std::function<T * (A1)> & factory,const std::function<void (T *)> & deleter,const A1 & a1)558 static UniquePtr<T> new_generic1(const std::function<T *(A1)> &factory, 559 const std::function<void(T *)> &deleter, 560 const A1 &a1) { 561 return UniquePtr<T>(factory(a1), 562 [deleter](T *p) { 563 deleter(p); 564 } // [&deleter] would be unsafe if set_T() was called 565 // before this object got erased 566 ); 567 } 568 template <typename T, typename A1, typename A2> new_generic2(const std::function<T * (A1,A2)> & factory,const std::function<void (T *)> & deleter,const A1 & a1,const A2 & a2)569 static UniquePtr<T> new_generic2(const std::function<T *(A1, A2)> &factory, 570 const std::function<void(T *)> &deleter, 571 const A1 &a1, const A2 &a2) { 572 return UniquePtr<T>(factory(a1, a2), 573 [deleter](T *p) { 574 deleter(p); 575 } // [&deleter] would be unsafe if set_T() was called 576 // before this object got erased 577 ); 578 } 579 580 template <typename T> get_external_generic(UniquePtr<T> & object,const std::function<T * ()> & factory,const std::function<void (T *)> & deleter)581 T &get_external_generic(UniquePtr<T> &object, 582 const std::function<T *()> &factory, 583 const std::function<void(T *)> &deleter) { 584 mtx_.lock(); 585 std::shared_ptr<void> exit_trigger(nullptr, [&](void *) { mtx_.unlock(); }); 586 587 if (!object) object = new_generic(factory, deleter); 588 589 return *object; 590 } 591 592 template <typename T> reset_generic(UniquePtr<T> & object)593 void reset_generic(UniquePtr<T> &object) { 594 mtx_.lock(); 595 std::shared_ptr<void> exit_trigger(nullptr, [&](void *) { mtx_.unlock(); }); 596 597 object.reset(); 598 } 599 600 mutable std::recursive_mutex mtx_; 601 602 }; // class DIM 603 604 } // namespace mysql_harness 605 #endif //#ifndef MYSQL_HARNESS_DIMANAGER_INCLUDED 606