1 /*
2 Copyright 2018 Mark Fisher
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 */
22 module dxx.app.extension;
23 
24 private import std.algorithm;
25 private import std.variant;
26 import std.typecons : Proxy;
27 
28 private import hunt.cache;
29 private import witchcraft;
30 
31 private import dxx.util;
32 private import dxx.app.plugin;
33 
34 struct ExtensionPointDesc {
35     string id;
36     string symbolicName;
37     string description;
38     string url;
39     //void*[string] executableExtensions;
40     ConfigurationElement[string] configuration;
41 }
42 
43 interface ExtensionPoint {
44     //const(string) id();
45     inout(ExtensionPointDesc) desc() inout;
46 }
47 
48 struct ConfigurationElement {
49     enum ElementType {
50       STRING_VAL,
51       INT_VAL,
52       FLOAT_VAL,
53       ARRAY_VAL,
54       // the xp parameter is an instance of a given type
55       // hosted by the plugin exposing the extension point.
56       TYPE_VAL,
57       // the xp parameter represents a static method in the exposing plugin.
58       METHOD_VAL
59     }
60     @property
61     ElementType elementType;
62     @property
63     string id;
64     @property
65     Variant[string] attr;
66     @property
67     ConfigurationElement[] children;
68     @property
69     ConfigurationElement* parent;
70     @property
71     ExtensionPointDesc* extensionPoint;
72 }
73 
74 struct ExtensionDesc {
75     string id;
76     string symbolicName;
77     string extensionPoint;
78     string description;
79     string url;
80     //void* delegate(string id) createExecutableExtension;
81     //ConfigurationElement[string] configuration;
82     //void*  createExecutableExtension(string id){
83     //    return null;
84     //}
85     //void*[string] executableExtensions;
86     ConfigurationSetting[] settings;
87 }
88 
89 struct ConfigurationSetting {
90   ExtensionDesc* extension;
91   ConfigurationElement* element;
92   Variant value;
93 }
94 
95 interface Extension {
96     inout(ExtensionDesc) desc() inout;
97 }
98 
99 struct ExtensionEvent {
100     enum Type {
101         Register,Unregister
102     };
103     @property
104     Type eventType;
105     @property
106     string pluginId;
107     @property
108     ExtensionDesc* extension;
109 }
110 
111 interface ExecutableExtensionType {
112   string executableType();
113   //Variant executable();
114   //Variant methods();
115   Method[] methods();
116   Variant create();
117 }
118 
119 interface ExecutableExtension {
120   ExecutableExtensionType executableType();
121   Variant object();
122 }
123 
124 mixin template exportExecutableExtension(T) {
125   void exportExecutableExtension(string id,string pluginId) {
126       // register the export with the injector
127   }
128 }
129 
130 mixin template importExecutableExtension(alias T) {
131   void importExecutableExtension(string id,string pluginId) {
132       // register the import with the injector
133   }
134 }
135 
136 interface ExtensionsManager : NotificationSource {
137   void registerExtensionPoint(ExtensionPointDesc* xp,string pluginId);
138   void registerExecutableExtensionType(ExtensionPointDesc* xp,string pluginId,string id,ConfigurationElement elem);
139   ExecutableExtensionType findExecutableExtensionType(string type,string pluginId);
140   Variant createExecutableExtension(string stype,string pluginId,string id);
141   void unregisterExtensionPoint(ExtensionPointDesc* xp,string pluginId);
142   void registerExtension(ExtensionDesc* x,string pluginId);
143   void unregisterExtension(ExtensionDesc* x,string pluginId);
144 }
145 
146 final class _ExtensionsManager : SyncNotificationSource,ExtensionsManager {
147     static class _Event {
148       ExtensionEvent ev;
149       this(ExtensionEvent.Type evType,string pluginId,ExtensionDesc* x) {
150         ev=ExtensionEvent(evType,pluginId,x);
151       }
152     };
153     class _ExecutableExtension(T) : T,ExecutableExtension {
154       T ext;
155       mixin Witchcraft;
156 
157       string executableType() {
158         return typeid(T);
159       }
160       void* executable() {
161         return &this;
162       }
163       this(T* t,string pluginId) {
164         ext=t;
165 //        executableExtensionTypes[pluginId][typeid(T)] = this;
166       }
167     }
168     class _ExecutableExtensionType(T) : ExecutableExtensionType {
169       string executableType() {
170         return typeid(T);
171       }
172       this(string pluginId) {
173         executableExtensionTypes[pluginId][typeid(T)] = this;
174       }
175     }
176     ExecutableExtensionType[string][string] executableExtensionTypes;
177     Cache xpCache;
178     Cache xCache;
179 
180     void enumerateExtensions(alias T)(string xp) {
181         //extensions.filter!(a => a.desc.extensionPoint == xp).each!(a => T(a));
182     }
183     void enumerateExtensionPoints(alias T)(string xp) {
184     }
185     this() {
186         xpCache = CacheFactory.create();
187         xCache = CacheFactory.create();
188     }
189     void sendExtensionEvent(ExtensionEvent.Type type,string pluginId,ExtensionDesc* x) {
190       auto e = new _Event(type,pluginId,x);
191       //_send!ExtensionEvent(&e.ev);
192       throw new Exception("NYI");
193     }
194     //
195     void registerExtensionPoint(ExtensionPointDesc* xp,string pluginId) {
196         //xpCache.put(pluginId ~ "." ~ xp.id,xp);
197         foreach(k,v;xp.configuration) {
198           switch(v.elementType) {
199             case ConfigurationElement.ElementType.TYPE_VAL:
200               registerExecutableExtensionType(xp,pluginId,k,v);
201             break;
202             default:
203             break;
204           }
205         }
206     }
207     void registerExecutableExtensionType(ExtensionPointDesc* xp,string pluginId,string id,ConfigurationElement elem) {
208         auto elemType = elem.attr["type"];
209 
210     }
211     ExecutableExtensionType findExecutableExtensionType(string type,string pluginId) {
212       return null;
213     }
214     void unregisterExtensionPoint(ExtensionPointDesc* xp,string pluginId) {
215         //xpCache.remove(pluginId ~ "." ~ xp.id);
216     }
217     void registerExtension(ExtensionDesc* x,string pluginId) {
218         //xCache.put(pluginId ~ "." ~ x.id,x);
219         sendExtensionEvent(ExtensionEvent.Type.Register,pluginId,x);
220     }
221     void unregisterExtension(ExtensionDesc* x,string pluginId) {
222         //xCache.remove(pluginId ~ "." ~ x.id);
223         sendExtensionEvent(ExtensionEvent.Type.Unregister,pluginId,x);
224     }
225     Variant createExecutableExtension(string type,string pluginId,string id) {
226       auto n = pluginId in executableExtensionTypes;
227       if(n) {
228         auto m = type in executableExtensionTypes[pluginId];
229         if(m) {
230           return createLocalExexcutable(id,executableExtensionTypes[pluginId][type]);
231         }
232       }
233       return Variant(null);
234     }
235     Variant createLocalExexcutable(string id,ExecutableExtensionType extType) {
236       //executableType
237       return Variant(null);
238     }
239 
240     version(DXX_Plugin) {
241       // The plugin version of the manager is just a stub that reflects to
242       // the host. However it exposes the notification interface to the plugin
243       // and registration events are sent only to the container plugin.
244       // The host receiver gets a notification signal on all registration events.
245       auto getPlugin() {
246         return PluginDefault.getInstance;
247       }
248     } else {
249 
250     }
251 
252 }