Current section

86 Versions

Jump to

Compare versions

6 files changed
+92 additions
-9 deletions
  @@ -1,6 +1,6 @@
1 1 {<<"links">>,[{<<"GitHub">>,<<"https://github.com/CharlesIrvineKC/mozart">>}]}.
2 2 {<<"name">>,<<"mozart">>}.
3 - {<<"version">>,<<"0.3.5">>}.
3 + {<<"version">>,<<"0.3.6">>}.
4 4 {<<"description">>,
5 5 <<"Mozart is a BPM platform written in Elixir. It is currently in active development,\nbut it has sufficient functionality for the development of BPM POCs.">>}.
6 6 {<<"elixir">>,<<"~> 1.16">>}.
  @@ -61,5 +61,6 @@
61 61 <<"lib/mozart/data/process_model.ex">>,
62 62 <<"lib/mozart/data/process_state.ex">>,<<"lib/mozart/event">>,
63 63 <<"lib/mozart/event/task_exit.ex">>,<<"lib/mozart/user_service.ex">>,
64 - <<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE-2.0">>]}.
64 + <<"priv">>,<<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,
65 + <<"LICENSE-2.0">>]}.
65 66 {<<"build_tools">>,[<<"mix">>]}.
  @@ -23,6 +23,7 @@ defmodule Mozart.BpmProcess do
23 23 alias Mozart.Task.Timer
24 24 alias Mozart.Task.Prototype
25 25 alias Mozart.Task.Repeat
26 + alias Mozart.Event.TaskExit
26 27 alias Mozart.Data.ProcessModel
27 28
28 29 defmacro __using__(_opts) do
  @@ -34,6 +35,9 @@ defmodule Mozart.BpmProcess do
34 35 @capture_subtasks false
35 36 @subtasks []
36 37 @subtask_sets []
38 + @events %{}
39 + @event_tasks []
40 + @event_task_process_map %{}
37 41 @before_compile Mozart.BpmProcess
38 42 end
39 43 end
  @@ -67,6 +71,41 @@ defmodule Mozart.BpmProcess do
67 71 end
68 72 end
69 73
74 + @doc """
75 + Used to implement a business process event. Arguments are:
76 + * the name of the event
77 + * **process**: the name of the process that the event will act upon
78 + * **exit_task**: the name of the task to be exited
79 + * **selector**: a function that matches on the target event
80 + * **do**: one or more tasks to be executed when the target task is exited.
81 + ```
82 + defevent "exit loan decision 1",
83 + process: "exit a user task 1",
84 + exit_task: "user task 1",
85 + selector: &BpmAppWithEvent.event_selector/1 do
86 + prototype_task("event 1 prototype task 1")
87 + prototype_task("event 1 prototype task 2")
88 + end
89 + ```
90 + """
91 + defmacro defevent(name, opts, do: tasks) do
92 + quote do
93 + [process: process, exit_task: exit_task, selector: selector] = unquote(opts)
94 + event = %TaskExit{name: unquote(name), exit_task: exit_task, selector: selector}
95 + @capture_subtasks true
96 + unquote(tasks)
97 + @subtasks set_next_tasks(@subtasks)
98 + first = hd(@subtasks)
99 + event = Map.put(event, :next, Map.get(hd(@subtasks), :name))
100 + @event_task_process_map Map.put(@event_task_process_map, process, @subtasks)
101 + @events Map.put(@events, process, event)
102 + @tasks []
103 + @subtasks []
104 + @subtask_sets []
105 + @capture_subtasks false
106 + end
107 + end
108 +
70 109 @doc false
71 110 def check_for_duplicates(type, tasks) do
72 111 task_names = Enum.map(tasks, fn t -> t.name end)
  @@ -376,7 +415,7 @@ defmodule Mozart.BpmProcess do
376 415 """
377 416 defmacro receive_task(name, selector: function) do
378 417 quote do
379 - task = %Receive{name: unquote(name), message_selector: unquote(function)}
418 + task = %Receive{name: unquote(name), selector: unquote(function)}
380 419
381 420 insert_new_task(task)
382 421 end
  @@ -411,11 +450,53 @@ defmodule Mozart.BpmProcess do
411 450 end
412 451 end
413 452
453 + @doc false
454 + def merge_event_tasks_to_process(event_task_process_map, processes) do
455 + process_name_task_list = Map.to_list(event_task_process_map)
456 + merge_recursive(process_name_task_list, processes)
457 + end
458 +
459 + @doc false
460 + def merge_recursive([], processes), do: processes
461 + def merge_recursive([{process_name, tasks} | rest], processes) do
462 + merge_recursive(rest,
463 + Enum.map(processes,
464 + fn p ->
465 + if process_name == p.name do
466 + tasks = p.tasks ++ tasks
467 + Map.put(p, :tasks, tasks)
468 + else
469 + p
470 + end
471 + end
472 + )
473 + )
474 + end
475 +
476 + @doc false
477 + def assign_events_to_processes([], processes), do: processes
478 + def assign_events_to_processes([{pname, event} | rest], processes) do
479 + assign_events_to_processes(rest, Enum.map(processes, fn p ->
480 + if pname == p.name do
481 + events = [event | p.events]
482 + Map.put(p, :events, events)
483 + else
484 + p
485 + end
486 + end))
487 + end
488 +
414 489 defmacro __before_compile__(_env) do
415 490 quote do
491 + if @event_task_process_map != %{} do
492 + @processes merge_event_tasks_to_process(@event_task_process_map, @processes)
493 + @processes assign_events_to_processes(Map.to_list(@events), @processes)
494 + end
416 495 def get_processes, do: Enum.reverse(@processes)
417 496 def get_process(name), do: Enum.find(@processes, fn p -> p.name == name end)
418 497
498 + def get_events, do: Map.to_list(@events)
499 +
419 500 def load_processes do
420 501 process_names = Enum.map(@processes, fn p -> p.name end)
421 502 end
  @@ -3,7 +3,7 @@ defmodule Mozart.Event.TaskExit do
3 3 defstruct [
4 4 :name,
5 5 :function,
6 - :message_selector,
6 + :selector,
7 7 :exit_task,
8 8 :next,
9 9 type: :task_exit
  @@ -277,7 +277,7 @@ defmodule Mozart.ProcessEngine do
277 277
278 278 def handle_info({:event, payload}, state) do
279 279 model = PS.get_process_model(state.model_name)
280 - event = Enum.find(model.events, fn e -> e.message_selector.(payload) end)
280 + event = Enum.find(model.events, fn e -> e.selector.(payload) end)
281 281 state = if event, do: exit_task(event, state), else: state
282 282 {:noreply, state}
283 283 end
  @@ -288,7 +288,7 @@ defmodule Mozart.ProcessEngine do
288 288 task = Map.put(task, :complete, :exit_on_task_event)
289 289
290 290 if task.type == :subprocess do
291 - complete_on_task_exit_event(task.sub_process_pid)
291 + complete_on_task_exit_event(task.subprocess_pid)
292 292 end
293 293
294 294 # Todo: Code exit repeat task
  @@ -311,7 +311,7 @@ defmodule Mozart.ProcessEngine do
311 311 ## callback utilities
312 312
313 313 defp update_receive_event_task(s_task, payload) do
314 - select_result = s_task.message_selector.(payload)
314 + select_result = s_task.selector.(payload)
315 315
316 316 if select_result do
317 317 Map.put(s_task, :data, select_result)
  @@ -397,6 +397,7 @@ defmodule Mozart.ProcessEngine do
397 397 start_process(new_task.model, data, state.process_key, self())
398 398
399 399 execute(process_pid)
400 + state
400 401 end
401 402
402 403 defp do_new_task_side_effects(_, _, state), do: state
  @@ -5,7 +5,7 @@ defmodule Mozart.Task.Receive do
5 5 :function,
6 6 :next,
7 7 :uid,
8 - :message_selector,
8 + :selector,
9 9 :start_time,
10 10 :finish_time,
11 11 :duration,
Loading more files…