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