Current section

Files

Jump to
bpe lib bpe gateways.ex
Raw

lib/bpe/gateways.ex

defmodule BPE.Gateways do
require BPE
import BPE
# field positions in the task/gateway tuple (1-based, as used by :erlang.element/2)
# tuple layout: {record_atom, id, name, input, output, prompt, roles, etc, ...}
@id_pos 2
@input_pos 4
@output_pos 5
@roles_pos 7
def def do
r_raw = [
{:r1, :a, :b}, {:r2, :b, :c}, {:r3, :b, :d}, {:r4, :c, :e},
{:r5, :c, :f}, {:r6, :d, :g}, {:r7, :e, :h}, {:r8, :h, :j},
{:r9, :f, :i}, {:r10, :i, :j}, {:r11, :f, :g}, {:r12, :g, :j},
{:r13, :j, :k}
]
{r, n} = get_edges_and_vertices(r_raw)
p = process(name: :Graph, flows: r, tasks: n, beginEvent: :a, endEvent: :k, events: [])
fix_gateways(fix_begin_end_events(p))
end
def vertices(r), do: vertices(Enum.reverse(r), [])
def vertices([], n), do: n
def vertices([sequenceFlow(id: id, source: from, target: to) | rtail], n) do
n1 =
case find_task(from, n) do
false -> [task(name: from, output: [id]) | n]
v -> replace_task(from, n, task(v, output: [id | task(v, :output)]))
end
new_n =
case find_task(to, n1) do
false -> [task(name: to, input: [id]) | n1]
v1 -> replace_task(to, n1, task(v1, input: [id | task(v1, :input)]))
end
vertices(rtail, new_n)
end
def get_edges_and_vertices(edges_raw) do
r = for {id, from, to} <- edges_raw, do: sequenceFlow(name: id, source: from, target: to)
{r, vertices(r)}
end
def set_vertex_type(id, type, vertices) do
case find_task(id, vertices) do
false -> vertices
v ->
new_vertex = gateway(id: task(v, :id), name: task(v, :name),
input: task(v, :input), output: task(v, :output), type: type)
replace_task(id, vertices, new_vertex)
end
end
def fix_begin_end_events(proc) do
tasks = process(proc, :tasks)
[begin_task] = for task(input: []) = t <- tasks, do: t
[end_task] = for task(output: []) = t <- tasks, do: t
begin_event = beginEvent(name: task(begin_task, :name))
end_event = endEvent(name: task(end_task, :name))
process(proc,
tasks: [begin_event, end_event | tasks -- [begin_task, end_task]],
beginEvent: task(begin_task, :name),
endEvent: task(end_task, :name)
)
end
def fix_gateways(process(tasks: tasks) = proc) do
process(proc, tasks: Enum.map(tasks, &convert_if_needed/1))
end
def convert_if_needed(task(name: name, input: in_f, output: out_f) = t)
when length(in_f) > 1 or length(out_f) > 1 do
gateway(name: name, type: :parallel, input: task(t, :input), output: task(t, :output))
end
def convert_if_needed(t), do: t
def action({:request, _, _}, proc), do: {:reply, proc}
# ── helpers ─────────────────────────────────────────────────────────────────
defp find_task(id, list) do
Enum.find(list, fn t -> is_tuple(t) and :erlang.element(@id_pos, t) == id end)
end
defp replace_task(id, list, new_val) do
Enum.map(list, fn t ->
if is_tuple(t) and :erlang.element(@id_pos, t) == id, do: new_val, else: t
end)
end
# Called from BPE.XML.fill_in_out with field positions
def key_push_value(value, value_key_pos, elem_id, list) do
case find_task(elem_id, list) do
nil -> list
false -> list
found ->
if elem(found, 0) == :endEvent do
list
else
new_found = :erlang.setelement(value_key_pos, found,
[value | :erlang.element(value_key_pos, found)])
replace_task(elem_id, list, new_found)
end
end
end
def output_pos, do: @output_pos
def input_pos, do: @input_pos
def roles_pos, do: @roles_pos
def id_pos, do: @id_pos
end