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.workflow; 24 25 private import std.algorithm; 26 private import std.variant; 27 28 private import dxx.app.platform; 29 private import dxx.app.job; 30 31 interface WorkflowElement { 32 void setup(WorkflowJob job); 33 void process(WorkflowJob job); 34 nothrow void terminate(WorkflowJob job); 35 } 36 37 //abstract class WorkflowElementBase : WorkflowElement { 38 // override void process(WorkflowJob job) { 39 // processElement(job); 40 // } 41 // abstract void processElement(WorkflowJob job); 42 //} 43 44 interface Workflow { 45 @property nothrow 46 ref inout (WorkflowElement[]) 47 workflowElements() inout; 48 49 @property nothrow pure @safe @nogc 50 ref inout(string[]) 51 args() inout; 52 53 @property nothrow pure @safe @nogc 54 ref inout(Variant[string]) 55 param() inout; 56 } 57 58 abstract class WorkflowBase : Workflow { 59 WorkflowElement[] _workflowElements; 60 string[] _args; 61 Variant[string] _param; 62 63 @property nothrow pure @safe @nogc 64 ref inout (WorkflowElement[]) 65 workflowElements() inout { 66 return _workflowElements; 67 } 68 @property nothrow pure @safe @nogc 69 ref inout (string[]) 70 args() inout { 71 return _args; 72 } 73 this(WorkflowElement[] elements,string[] args) { 74 _workflowElements = elements; 75 _args = args; 76 } 77 @property nothrow pure @safe @nogc 78 ref inout (Variant[string]) 79 param() inout { 80 return _param; 81 } 82 } 83 84 final class DefaultWorkflow : WorkflowBase { 85 this(WorkflowElement[] elements,string[] args) { 86 super(elements,args); 87 } 88 } 89 90 final class WorkflowJob : PlatformJobBase { 91 Workflow _workflow; 92 WorkflowRunner _runner; 93 94 this(Workflow wf,WorkflowRunner r) shared { 95 super(); 96 this._workflow = cast(shared(Workflow))wf; 97 this._runner = cast(shared(WorkflowRunner))r; 98 } 99 100 @property nothrow pure @safe @nogc 101 inout(Workflow) workflow() inout { 102 return _workflow; 103 } 104 105 @property nothrow pure @safe @nogc 106 inout(WorkflowRunner) workflowRunner() inout { 107 return _runner; 108 } 109 110 override shared 111 void setup() { 112 super.setup; 113 auto wf = cast(Workflow)_workflow; 114 wf.workflowElements.each!(e=>e.setup(cast(WorkflowJob)this)); 115 } 116 117 override shared 118 void processPlatformJob() { 119 auto wf = cast(Workflow)_workflow; 120 wf.workflowElements.each!(e=>e.process(cast(WorkflowJob)this)); 121 } 122 123 nothrow 124 override shared 125 void terminate() { 126 super.terminate; 127 auto wf = cast(Workflow)_workflow; 128 wf.workflowElements.each!(e=>e.terminate(cast(WorkflowJob)this)); 129 } 130 } 131 132 final class WorkflowRunner { 133 shared(Job) createJob(Workflow wf) { 134 auto job = new shared(WorkflowJob)(wf,this); 135 return job; 136 } 137 shared(Job) createJob(WorkflowElement[] elements,string[] args=[]) { 138 return createJob(new DefaultWorkflow(elements,args)); 139 } 140 } 141 142 class WorkflowElementDelegate(alias D) : WorkflowElement { 143 override void setup(WorkflowJob job) {} 144 override void process(WorkflowJob job) { 145 D(job); 146 } 147 override void terminate(WorkflowJob job) {} 148 } 149 150 unittest { 151 import std.stdio; 152 153 class TestWorkflowElement : WorkflowElement { 154 bool _done = false; 155 override void setup(WorkflowJob job) { 156 //writefln("TestWorkflowElement.setup"); 157 } 158 override void process(WorkflowJob job) { 159 //writefln("TestWorkflowElement.process"); 160 _done = true; 161 } 162 override void terminate(WorkflowJob job) { 163 //writefln("TestWorkflowElement.terminate"); 164 } 165 } 166 string[] arg = [ "arg0","arg1","arg2" ]; 167 168 auto elem = new TestWorkflowElement; 169 WorkflowElement[] e = [ elem ]; 170 auto wf = new DefaultWorkflow(e,arg); 171 auto r = new WorkflowRunner; 172 auto j = r.createJob(wf); 173 j.execute(); 174 assert(j.terminated); 175 assert(j.status == Job.Status.TERMINATED); 176 assert(elem._done); 177 178 } 179 180 unittest { 181 import std.stdio; 182 class TestWorkflowElementException : WorkflowElement { 183 bool terminated = false; 184 override void setup(WorkflowJob job) { 185 /* writeln("TestWorkflowElement.setup"); */ 186 } 187 override void process(WorkflowJob job) { 188 /* writeln("TestWorkflowElementException.process"); */ 189 throw new Exception("workflow unittest"); 190 } 191 override void terminate(WorkflowJob job) { 192 /* writeln("TestWorkflowElement.terminate"); */ 193 terminated = true; 194 } 195 } 196 string[] arg = [ "arg0","arg1","arg2" ]; 197 198 auto elem = new TestWorkflowElementException; 199 WorkflowElement[] e = [ elem ]; 200 auto wf = new DefaultWorkflow(e,arg); 201 auto r = new WorkflowRunner; 202 auto j = r.createJob(wf); 203 j.execute(); 204 assert(j.terminated); 205 writeln("Job status: ",j.status); 206 assert(j.status == Job.Status.THROWN_EXCEPTION); 207 assert(j.thrownException !is null); 208 assert(elem.terminated); 209 }