Annotations and guards are useful for any general purpose rules. Messaging and reaction rules are no exception. rules/reloaded/guard.prova now contains an additional example that shows how annotations and guards can be used to detect sequential event patterns. First, let's look at the client.
:- eval(client()). client() :- % Send all the test messages from a separate thread switch_thread(), sendMsg(XID,task,0,request,login(user1,'10.10.10.10')), % Wait synchronously, could have waited asynchronously instead java.lang.Thread.sleep(500L), sendMsg(XID,task,0,request,login(user2,'30.30.30.30')), java.lang.Thread.sleep(700L), sendMsg(XID,task,0,request,login(user1,'10.10.10.10')), sendMsg(XID,task,0,request,login(user2,'40.40.40.40')). switch_thread() :- sendMsgSync(XID,task,0,switch,[]), rcvMsg(XID,task,From,switch,[]).
The client sends 4 login events on the 'task' loopback protocol, which causes the reactions to run concurrently in no particular order on the 'task' thread pool. Note that there is a 1200 ms gap between the two logins for 'user1' and there is only a 700 ms gap for two logins for 'user2'. For each user, the secon login comes from a different IP address. We want to detect when subsequent logins from the same user are separated by no more than 1 second. Here is the server code.
% Demonstrate a guarded reaction. The server looks for logins for one user from different IP addresses. % The guard on the second reaction filters the expected follow-up message. % This will print: % user2 30.30.30.30 40.40.40.40 :- eval(server()). server() :- % Start detection on each new login rcvMult(XID,Protocol,From,request,login(User,IP)), % Wait for a right follow-up while ignoring anything that does not match @timeout(1000) rcvMsg(XID,Protocol,From,request,login(User,IP2)) [IP2!=IP], % Once the full match has occurred, the above rcvMsg reaction is removed println([User,IP,IP2]," ").
As many event processing languages, Prova has two constructs (called reactions), one (rcvMult) for detecting events repeatedly and one (rcvMsg) for detecting events only once, after which the rcvMsg instance disappears. For example, Esper CEP has a construct 'every' to represent the former case. In Prova, rcvMult stays active for the whole duration of a Prova agent, unless a @timeout annotation is specified. In this example, it is not specified on rcvMult, so the server listens on any logins and initiates a brand new event pattern detection sequence each time a login is detected.
The example uses the @timeout(MILLISECONDS) annotation on the rcvMsg reaction that captures another (second) login following each candidate (first) login. That rcvMsg reaction also uses a guard condition that captures the constraint that the second login should have a different IP address IP2 from the first, IP.
There are 4 instances of event pattern detection sequences created (one for each login). After each of them is accepted by rcvMult, rcvMsg starts waiting for the second login for the same User (observe that using the same variable, User, is equivalent to a JOIN condition in event-processing languages based on SQL). This second reaction rcvMsg can disappear in two ways: (1) if the satisfying event arrives (the one with the same User and different IP address), or (2) if the timeout of 1000 ms is elapsed.