1 /*******************************************************************************
2 
3     Mixin for classes that support extensions.
4 
5     Copyright:
6         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
7         All rights reserved.
8 
9     License:
10         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
11         Alternatively, this file may be distributed under the terms of the Tango
12         3-Clause BSD License (see LICENSE_BSD.txt for details).
13 
14 *******************************************************************************/
15 
16 module ocean.util.app.model.ExtensibleClassMixin;
17 
18 /*******************************************************************************
19 
20     Mixin for classes that support extensions.
21 
22     It just provides a simple container for extensions (ordered in the order
23     provided by BaseExtension.order()) registering of extensions, and getting an
24     extension based on its type.
25 
26     Typical usage:
27 
28     ---
29 
30     interface ISomeExtension : IExtension
31     {
32         void someMethod ( );
33     }
34 
35     class SomeExtensibleClass
36     {
37         mixin ExtensibleClassMixin!(ISomeExtension);
38 
39         void something ( )
40         {
41             foreach (ext; this.extensions)
42             {
43                 ext.someMethod();
44             }
45         }
46     }
47 
48     ---
49 
50     TODO: Assert that ExtensionClass is derived from IExtension
51 
52 *******************************************************************************/
53 
54 template ExtensibleClassMixin ( ExtensionClass )
55 {
56 
57     /*******************************************************************************
58 
59         Unfortunatelly template mixins needs to have all the symbols they use
60         available in the code making the mixing. For that reason, symbols
61         needed by this template are made public inside the template as the less
62         ugly solution. The class namespace will be polluted with the import
63         symbols but nothing else. The symbols imported are prepended with
64         mixin_ to make clear where they came from and to avoid accidental name
65         clashing.
66 
67      *******************************************************************************/
68 
69     import ocean.core.Array : mixin_sort = sort;
70 
71 
72     /***************************************************************************
73 
74         List of extensions. Will be kept sorted by extension order when using
75         the registerExtension() method.
76 
77     ***************************************************************************/
78 
79     ExtensionClass[] extensions;
80 
81 
82     /***************************************************************************
83 
84         Register a new extension, keeping extensions list sorted.
85 
86         Extensions are considered unique by type, so is invalid to register
87         2 extensions with the exact same type.
88 
89         Params:
90             ext = new extension to register
91 
92     ***************************************************************************/
93 
94     public void registerExtension ( ExtensionClass ext )
95     {
96         // TODO: Assert that we don't already have an extension of the same type
97 
98         this.extensions ~= ext;
99         mixin_sort(this.extensions,
100             ( ExtensionClass e1, ExtensionClass e2 )
101             {
102                 return e1.order < e2.order;
103             });
104     }
105 
106 
107     /***************************************************************************
108 
109         Get an extension based on its type.
110 
111         Returns:
112             the instance of the extension of the type Ext, or null if not found
113 
114     ***************************************************************************/
115 
116     public Ext getExtension ( Ext ) ( )
117     {
118         // TODO: Assert that Ext is derived from ExtensionClass
119         foreach (e; this.extensions)
120         {
121             Ext ext = cast(Ext) e;
122             if ( ext !is null )
123             {
124                 return ext;
125             }
126         }
127 
128         return null;
129     }
130 
131 }
132