1 /**
2 Copyright: 2018 Mark Fisher
3 
4 License:
5 Permission is hereby granted, free of charge, to any person obtaining a copy of
6 this software and associated documentation files (the "Software"), to deal in
7 the Software without restriction, including without limitation the rights to
8 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 of the Software, and to permit persons to whom the Software is furnished to do
10 so, subject to the following conditions:
11 
12 The above copyright notice and this permission notice shall be included in all
13 copies or substantial portions of the Software.
14 
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 SOFTWARE.
22 **/
23 module dxx.app.platform;
24 
25 private import std.exception;
26 private import std.typecons;
27 private import std.variant;
28 
29 private import aermicioi.aedi;
30 
31 //import hunt.cache;
32 
33 private import dxx.util;
34 private import dxx.app;
35 
36 private import dxx.app.component;
37 private import dxx.app.resource;
38 private import dxx.app.document;
39 private import dxx.app.workbench;
40 private import dxx.app.extension;
41 private import dxx.app.resource.impl.wsmanager;
42 
43 
44 //interface DocumentResourceAdaptor {
45     //DocumentType getDocType(FileResource);
46 //}
47 
48 /++
49 Methods exposed by the platform, accessible via the injector.
50 ++/
51 interface PlatformComponents {
52     URIResolver getURIResolver();
53     ResourceValidator getResourceValidator();
54     ResourceContentProvider getResourceContentProvider();
55     //DocumentResourceAdaptor getDocumentResourceAdaptor();
56 
57     public WorkflowRunner getWorkflowRunner();
58     public PluginLoader getPluginLoader();
59     public ExtensionsManager getExtensionsManager();
60     //public Cache getLocalCache();
61 }
62 
63 struct PlatformJobEvent {
64   enum Status {
65     Setup,Process,Terminate
66   };
67   Status status;
68   shared(PlatformJob) job;
69 }
70 /++
71 This represents the state of the framework for an application.
72 The platform handles the resource workspace, loading of plugins and is
73 also a job manager.
74 ++/
75 class DXXPlatform : SyncNotificationSource
76 {
77     static class ThreadLocal :
78         URIResolver,
79         ResourceValidator,
80         ResourceContentProvider
81         //DocumentResourceAdaptor
82     {
83         static WorkflowRunner workflowRunner;
84         //Cache localCache;
85 
86         Resource resolveURI(string uri,ResourceSet owner) {
87             return null;
88         }
89         bool isValid(ResourceSet set) {
90             return true;
91         }
92         bool isValidResource(Resource res) {
93             return true;
94         }
95         void* getContent(Resource) {
96             return null;
97         }
98         override ubyte[] getContent(Resource) {
99             return [];
100         }
101         override void putContent(ubyte[],Resource) {
102         }
103         DocumentType getDocType(FileResource) {
104             return null;
105         }
106 
107         WorkflowRunner getWorkflowRunner() {
108             if(workflowRunner is null) {
109                 workflowRunner = new WorkflowRunner;
110             }
111             return workflowRunner;
112         }
113         /*Cache getLocalCache() {
114           if(localCache is null) {
115             localCache =  CacheFectory.create();
116           }
117           return localCache;
118         }*/
119     }
120     static ThreadLocal _local;
121 
122     static auto getLocals() {
123         if(_local is null) {
124             _local = new ThreadLocal;
125         }
126         return _local;
127     }
128 
129     static __gshared DXXPlatform INSTANCE;
130 
131     static
132     auto getInstance() {
133         static bool instantiated = false;
134         if(!instantiated) {
135             synchronized(DXXPlatform.classinfo) {
136                 if(!INSTANCE) {
137                     INSTANCE=new DXXPlatform;
138                 }
139             }
140             instantiated = true;
141         }
142         return INSTANCE;
143     }
144 
145     static Workspace getDefaultWorkspace() {
146         return resolveInjector!(Workspace)("app.workspace");
147     }
148     /* static Workbench getDefaultWorkbench() {
149         return resolveInjector!(Workbench)("app.workbench");
150     } */
151 
152     ExtensionsManager extensionsManager;
153 
154     private this() {
155         extensionsManager = new _ExtensionsManager;
156     }
157 
158     _PluginLoader[string] plugins;
159 
160     class _PluginLoader : PluginLoader {
161       override void load(string path) {
162           super.load(path);
163           plugins[desc.id] = this;
164       }
165     }
166     PluginLoader newPluginLoader() {
167       return new _PluginLoader();
168     }
169 
170     static nothrow
171     void sendJobEvent(
172         PlatformJobEvent.Status status)
173         (shared(PlatformJob) j)
174     {
175         try {
176           PlatformJobEvent event = PlatformJobEvent(status,j);
177           auto p = cast(shared(DXXPlatform))getInstance;
178           p.send!PlatformJobEvent(&event);
179         } catch(Exception e) {
180           MsgLog.warning(e.message);
181         }
182     }
183     static void executeJob(shared(Job) job) {
184       //auto j = cast(shared(Job))job;
185       job.execute;
186     }
187 
188     static void clearLocalCache() {
189       //destroy(getLocals.localCache);
190     }
191 }
192 
193 /++
194 Job that sends events to the DXXPlatform listeners.
195 ++/
196 interface PlatformJob : Job {
197     T getProperty(T)(string id);
198     void setProperty(T)(T t,string id);
199 }
200 
201 abstract class PlatformJobBase : JobBase,PlatformJob {
202     shared(Workbench) workbench;
203     Variant[string] _props;
204 
205      this(Workbench w = resolveInjector!(Workbench)("app.workbench")) shared {
206         //super();
207         workbench = cast(shared(Workbench))w;
208     }
209     this() shared {
210         //super();
211     }
212 
213     override
214     void setup() shared {
215       DXXPlatform.sendJobEvent!(PlatformJobEvent.Status.Setup)(this);
216     }
217     override
218     void terminate() shared {
219       DXXPlatform.sendJobEvent!(PlatformJobEvent.Status.Terminate)(this);
220     }
221 
222     override
223     void process() shared {
224         DXXPlatform.sendJobEvent!(PlatformJobEvent.Status.Process)(this);
225         processPlatformJob();
226     }
227 
228     abstract
229     void processPlatformJob() shared;
230 
231     //override
232     T getProperty(T)(string id) {
233         return _props[id].get!T;
234     }
235     //override
236     void setProperty(T)(T t,string id) {
237       _props[id] = Variant(t);
238     }
239 }
240 
241 struct PluginDef {
242     public string name;
243     public string pluginVersion;
244     public string path;
245     //public string[string] properties;
246 }
247 
248 struct PlatformParam {
249   PluginDef[] plugins;
250 }
251 
252 alias DXXParam = Tuple!(
253   PlatformParam,"dxx"
254 );
255 
256 /++
257 Default runtime module that exposes components for use by the injector.
258 
259 
260 So, for example, to access a PluginLoader:
261 `
262     PluginLoader loader = resolveInjector!PluginLoader;
263 `
264 ++/
265 @component
266 class PlatformRuntime(Param...) :
267             RuntimeComponents!(Param,PlatformParam),
268             PlatformComponents {
269 
270     @component
271     override URIResolver getURIResolver() {
272         return DXXPlatform.getLocals();
273     }
274 
275     @component
276     override ResourceValidator getResourceValidator() {
277         return DXXPlatform.getLocals;
278     }
279 
280     @component
281     override ResourceContentProvider getResourceContentProvider() {
282         return DXXPlatform.getLocals;
283     }
284 
285     //@component
286     //override DocumentResourceAdaptor getDocumentResourceAdaptor() {
287     //    return Platform.getInstance();
288     //}
289 
290     @component
291     override PluginLoader getPluginLoader() {
292         return DXXPlatform.getInstance.newPluginLoader;
293     }
294 
295     @component
296     public ExtensionsManager getExtensionsManager() {
297         return DXXPlatform.getInstance.extensionsManager;
298     }
299 
300     @component
301     public WorkflowRunner getWorkflowRunner() {
302         return DXXPlatform.getLocals.getWorkflowRunner;
303     }
304     /*@component
305     override Cache getLocalCache() {
306         return DXXPlatform.getLocals.getLocalCache;
307     }*/
308 
309     void registerPlatformDependencies(InjectionContainer injector) {
310       WorkspaceManager w = new WorkspaceManager;
311       Workspace ws = w.workspace;
312       injector.register!(Workspace)(ws,"app.workspace");
313     }
314 
315     override void registerAppDependencies(InjectionContainer injector) {
316         super.registerAppDependencies(injector);
317         registerPlatformDependencies(injector);
318     }
319     version(unittest) {
320         alias UTParam = Tuple!(
321            string,"name",
322            uing,"age"
323           );
324         mixin registerComponent!(PlatformRuntime!UTParam);
325     }
326 }
327 unittest {
328   WorkflowRunner runner = resolveInjector!WorkflowRunner;
329   assert(runner !is null);
330   PluginLoader loader = resolveInjector!PluginLoader;
331   assert(loader !is null);
332 }