1// This source code comes from http://www.odelia-technologies.com/node/200
2
3package com.odelia.groovy.simpleworkflow
4
5
6class SimpleWorkflowEngine {
7    def workflowMap = [:]
8    def context = [:]
9    def beforeActivityName = 'beforeActivity'
10    def afterActivityName = 'afterActivity'
11
12    SimpleWorkflowEngine(workflow, context = [:]) {
13        this.context = context
14        parseWorkflow(workflow)
15    }
16
17    def parseWorkflow(workflow) {
18        workflowMap = new WorkflowParser().parse(workflow)
19    }
20
21    def getActivityValue(activity) {
22        assert activity instanceof String
23        if (!workflowMap[activity])
24            throw new RuntimeException("$activity activity doesn't exist")
25        workflowMap[activity]
26    }
27
28    def execute(activity, pause) {
29        if (workflowMap[beforeActivityName]) {
30            getActivityValue(beforeActivityName)(context, activity)
31        }
32
33        def activityValue = getActivityValue(activity)
34
35        // Determine the next activity to execute
36        def nextActivity
37        switch (activityValue) {
38            case String: nextActivity = activityValue; break
39            case Closure: nextActivity = activityValue(context); break
40            case Class: nextActivity = activityValue.newInstance()(context)
41        }
42
43        if (workflowMap[afterActivityName]) {
44            getActivityValue(afterActivityName)(context, activity, nextActivity)
45        }
46
47        if (!pause && nextActivity)
48            call(nextActivity)
49        else
50            nextActivity
51    }
52
53    def call(activity) {
54        execute(activity, false)
55    }
56
57    def nextActivity(activity) {
58        execute(activity, true)
59    }
60
61    static void main(String[] args) {
62        if (args.size() != 2) {
63            println 'Usage: com.odelia.groovy.simpleworkflow.SimpleWorkflowEngine <dsl_filename> <activity_name>'
64            return
65        }
66        SimpleWorkflowEngine.newInstance(new File(args[0]))(args[1])
67    }
68
69}
70
71private class WorkflowParser {
72    def map = [:]
73
74    def methodMissing(String name, args) {
75        map[name] = args[0]
76    }
77
78    def parse(Closure wf) {
79        wf.delegate = this
80        wf.resolveStrategy = Closure.DELEGATE_FIRST
81        wf()
82        map
83    }
84
85    def workflow = { it ->
86        it.delegate = this
87        it.resolveStrategy = Closure.DELEGATE_FIRST
88        it()
89    }
90
91    def parse(File workflowDef) {
92        def binding = new Binding([workflow: workflow])
93        def shell = new GroovyShell(binding)
94        shell.evaluate(workflowDef)
95        map
96    }
97}