Event algebras are a formalism for describing composite events that are groups of other events satisfying specified algebraic constraints. Reaction groups is the mechanism that embeds event algebra into the Prova language.
Prova is well equipped for dealing with reactive behaviour (see Design principles) as it has basic constructs for receving messages that can be used as an event delivery mechanism. The rcvMsg and rcvMult primitives receive either single or multiple messages from within the body of the rules. These primitives are non blocking, and instead store a continuation to the remaining trail of literals, which is activated once the matching message arrives. This message receiving capability is very much like that in Erlang, including the ability to use guards on reactions. However, Prova is quite different from Erlang. For example, Prova does not immediately consume the message but allows it to be accepted by many alternative reactions. There is a way to absorb a message by using the Prova (Prolog) CUT after the reaction.
Let us now talk more concretely about the event algebra in Prova. We need a way to group more than one reaction using a logical operator, for example, AND, requiring that all events matching the reactions belonging to the group arrive (typically, within the specified period of time). This means we need to designate reactions as belonging to a group and a way to indicate somewhere the operator to be used. But there is more: the result of a composite event detection has to be represented somehow, so that it could be captured in the way the composed events are, as well as allow the resulting composite event to be used in other event groups with possibly different operators, creating a recursive operator expression.
An extended example below has all the main ingredients. We start with the code for the server that detects event patterns.
Once the initiator event (a user login) is detected by rcvMult in the rule for server, the Prova code for the predicate server_1 creates five reactions that simultaneously wait for subsequent events. For each new initiator event, more reactions will become active. However, as already mentioned, Prova does not block on any active reactions but instead keeps them in memory ready to match when qualifying inbound messages are detected. Now look closer at the annotations on those five reactions. The first two belong to the group g1, indicated by annotation @group(g1). The third reaction is the result (composite) reaction corresponding to the operator AND (@and(g1)) applied to the first two operands. This means that the whole group will terminate when both composed reactions are detected or timeout expires. Positive detection sends the composite event to the third reaction that is also annotated with @group(g2). The fourth reaction is another (primitive) reaction that belongs to group g2. The fifth reaction indicates the operator OR for the group g2. The variables Events in the third and fifth reactions capture the composite events recorded as the trace of all detected messages resulting in the pattern detection.
Informally, we have something like this: OR(e3,AND(e1,e2)). The third reaction is the result of an AND and the fifth reaction is the result of the enclosing OR. The timeout on the OR-operator is smaller than that for the embedded AND-operator intentionally, to test that the whole group is removed by the timeout correctly, while allowing for the same code to be used in other tests using the following inbound events.
The client code is shown below.
When run, the rulebase prints the following:
Observe how the "update" event results in immediate pattern detection due to OR. Also note that when a full AND is detected, the final composite event includes the actual structural grouping and for the AND sub-event.
To summarize, the event groups are specified using the @group annotations and operators like @and or @or on the reactions corresponding to the composite events. Each composite event may then again be a member of another group and so on, allowing for arbitrary nesting of event groups. Sequences of events are easily captured by reactions following one another, typically with @timeout annotations.