-
Notifications
You must be signed in to change notification settings - Fork 0
/
catch_event.go
123 lines (110 loc) · 4.52 KB
/
catch_event.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
Copyright 2023 The bpmn Authors
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library;
*/
package logic
import (
"github.com/bits-and-blooms/bitset"
"github.com/olive-io/bpmn/schema"
"github.com/olive-io/bpmn/event"
)
// CatchEventSatisfier is an algorithm that allows to apply events to a schema.CatchEventInterface element
// and obtain a determination whether all conditions were satisfied.
type CatchEventSatisfier struct {
schema.CatchEventInterface
eventDefinitionInstances []event.IDefinitionInstance
len uint
chains []*bitset.BitSet
}
func (satisfier *CatchEventSatisfier) EventDefinitionInstances() *[]event.IDefinitionInstance {
return &satisfier.eventDefinitionInstances
}
func NewCatchEventSatisfier(catchEventElement schema.CatchEventInterface, eventDefinitionInstanceBuilder event.IDefinitionInstanceBuilder) *CatchEventSatisfier {
satisfier := &CatchEventSatisfier{
CatchEventInterface: catchEventElement,
chains: make([]*bitset.BitSet, 0, 1),
len: uint(len(catchEventElement.EventDefinitions())),
}
satisfier.eventDefinitionInstances = make([]event.IDefinitionInstance, len(catchEventElement.EventDefinitions()))
for k := range catchEventElement.EventDefinitions() {
satisfier.eventDefinitionInstances[k], _ = eventDefinitionInstanceBuilder.NewEventDefinitionInstance(catchEventElement.EventDefinitions()[k])
}
return satisfier
}
const EventDidNotMatch = -1
// Satisfy matches an event against event definitions in CatchEvent element,
// if all conditions are satisfied, it'll return true, otherwise, false.
//
// Satisfy also returns the index of the chain operated on. Chain is a partial
// receipt of a parallel multiple event sequence.
//
// - If event didn't match, the value will be equal to EventDidNotMatch
// - If event matched, `chain` will be the matching chain's index
// - If event matched and it was not a parallel multiple catch event, or
// parallel multiple with just one event definition, `chain` will be equal
// to `0`
//
// It is important to mention how chains get re-ordered upon their removal.
// Chain with the largest index (the last one) gets moved to the index of
// the removed chain and the array is shrunk by one element at the end.
// The knowledge of this behavior is important for being able to mirror
// changes if necessary.
//
// Please note that Satisfy is NOT goroutine-safe and if you need to use
// it from multiple goroutines, wrap its usage with appropriate level of
// synchronization.
func (satisfier *CatchEventSatisfier) Satisfy(ev event.IEvent) (matched bool, chain int) {
chain = EventDidNotMatch
for i := range satisfier.eventDefinitionInstances {
if ev.MatchesEventInstance(satisfier.eventDefinitionInstances[i]) {
if !satisfier.ParallelMultiple() || satisfier.len == 1 {
chain = 0
matched = true
return
} else {
// If there are no chains of events,
if len(satisfier.chains) == 0 {
bitSet := bitset.New(satisfier.len)
bitSet.Set(uint(i))
// create the first one
satisfier.chains = append(satisfier.chains, bitSet)
chain = len(satisfier.chains) - 1
} else {
// For every existing chain
for j := range satisfier.chains {
// If it doesn't have this event yet,
if !satisfier.chains[j].Test(uint(i)) {
// Add it to the chain
satisfier.chains[j].Set(uint(i))
// And check if the chain has been fully satisfied
matched = satisfier.chains[j].All()
if matched {
// If it has, remove the chain
satisfier.chains[j] = satisfier.chains[len(satisfier.chains)-1]
satisfier.chains = satisfier.chains[:len(satisfier.chains)-1]
}
chain = j
return
}
}
// If no existing chain had this event not processed, create a new one
bitSet := bitset.New(satisfier.len)
bitSet.Set(uint(i))
satisfier.chains = append(satisfier.chains, bitSet)
chain = len(satisfier.chains) - 1
}
}
break
}
}
return
}