Specifying other temporal operators
For a listener to trigger on an event sequence, the event expression defining what to match against must evaluate to true.
The or operator allows you to specify event expressions where a variety of event sequences could lead to a successful match. It effectively evaluates two event templates (or entire nested event expressions) simultaneously and returns true when either of them become true.
For example,
A or B
means that either A or B need to be detected to match. That is, the occurrence of one of the operand expressions (an A or a B) is enough to satisfy the listener.
The and operator specifies an event sequence that might occur in any temporal order. It evaluates two event templates (or nested event expressions) simultaneously but only returns true when they are both true.
A and B
will seek ‘an A followed by a B’ or ‘a B followed by an A’. Both are valid matching sequences, and the listener will seek both concurrently. However, the first to occur will terminate all monitoring and trigger the listener.
The following example code snippets indicate a few patterns that can be expressed using the three operators presented so far.
Example | Meaning |
A -> (B or C) | Match on an A followed by either a B or a C. |
(A -> B) or C | Match on either the sequence A followed by a B, or just a C on its own. |
A -> ((B -> C) or (C -> D)) | Find an A first, and then seek for either the sequence B followed by a C or C followed by a D. The latter sequences will be looked for concurrently, but the monitor will match upon the first complete sequence that occurs. This is because the or operator treats its operands atomically, i.e. in this case it is looking for the sequences themselves rather than their constituent events. |
(A -> B) and (C -> D) | Find the sequence A followed by a B (A -> B) followed by the sequence C -> D, or else the sequence C -> D followed by the sequence A -> B. The and operator treats its operands atomically—that is, in this case it is looking for the sequences themselves and the order of their occurrence, rather than their constituent events. It does not matter when a sequence starts but it occurs when the last event in it is matched. Therefore {A’,C’,B’,D’} would match the specification, because it contains an A -> B followed by a C -> D. In fact the specification would match against either of the following sequences of event instances; {A’,C’,B’,D’}, {C’,A’,B’,D’}, {A’,B’,C’,D’}, {C’,A’,D’,B’}, {A’,C’,D’,B’}, and {C’,D’,A’,B’}. |
The not operator is unary and acts to invert the truth value of the event expression it is applied to.
A -> B and not C
therefore means that the correlator will match only if it encounters an A followed by a B without a C occurring at any time before the B is encountered.
Note: The not operator can cause an event expression to reach a state where it can never evaluate to true any more, that is, it will become permanently false.
Consider this listener event sequence:
on (A -> B) and not C
The listener will start seeking both A -> B and not C concurrently. If an event matching C is received at any time before one matching B, the C clause will evaluate to true, and hence not C will become false. This will mean that (A -> B) and not C will never be able to evaluate to true, and hence this listener will never trigger. In practice the correlator cleans out these zombie listeners periodically.
Note: It is possible to write an event expression that always evaluates to true immediately, without any events occurring.
Consider this listener:
on (A -> B) or not C
Assuming that A, B, and C represent event templates, their value will start off as being false. However, that means that not C will become true immediately, and hence the whole expression will become true right away. This listener will therefore trigger immediately as soon as it is instantiated. If any of A, B or C were nested event expressions the same logic would apply for their own evaluation.