Prova rules are Horn rules with the head literal and a number of body literals. Reactive Messaging in Prova does change this pattern but allows these literals to have special meaning if they are message passing primitives.
Global reaction rules
The simplest form of a reactive rule is one when the head of the rule is a message receiving primitive distinguished by the rcvMsg predicate symbol. Here is an example of such rule:
This rule has a rulebase lifetime scope, i.e., it is active while the rulebase runs in a Prova engine. This global scoping means that the rule is ready to receive any number of messages as they arrive to the agent. We discuss the concurrency issues in Concurrent reactive messaging.
The intended meaning of this construct is to wait messages that match the pattern specified in brackets after rcvMsg and respond to such matching messages with logic reasoning or side-effect causing primitives contained in the body of the rule, in this example, printing the message payload Proposal and processing it in order to generate an Offer (the example does not show what happens with the said Offer).
Note that the message metadata, including conversation-id XID, Protocol, and the sender From, have been left as free variables in the rcvMsg pattern, so that, for example, messages from any senders will be accepted.
Inline reaction rules
These reaction rules are more dynamic and volatile. Their scope can be controlled in a variety of ways, including restricting them to accept just one message, a specified number of messages, or be limited by a timeout. This type of reaction rules is especially useful for workflow and event processing.
The fundamental idea behind inline reaction rules is comparable to closures or continuations that are becoming more and more acceptable even in procedural languages. The reaction is created as part of evaluating the body of a rule when a message receiving primitive rcvMsg is part of that body.
Consider the following example:
What we do here is the following: the spawn primitive initiates a static Java method call to sleep for one second. This sleep occurs in a separate thread in a special task thread pool. Once the task is spawned, the rcvMsg is evaluated. This results in the creation of a closure that contains all the remaining literals in the body of the rule along with a dynamically generated reaction that is waiting for the pattern specified in brackets after rcvMsg. This pattern indicates an interest in a message of pre-defined type return on the internal self protocol. This reaction will fire only once, when the matching message corresponding to a return from a spawned task is received. Note that the conversation-id XID is used for correlation.
The takeaway from this is that rcvMsg inside the body of any Prova rule results in a creation of a temporal reaction that freezes the current state of all the context and body literals following this rcvMsg. The temporal reaction does not consume any thread and is just a pure stored data that gets matched against by the Prova agent each time it perceives a new inbound message on the matching protocol. Once the matching message is received, that stored data is fully destroyed.
Controlling the message reaction multiplicity
The rcvMsg primitive on its own "works" only once. If we want to keep the reaction alive indefinitely, the simplest way to achieve that is to replace it with the rcvMult primitive.
This construct is, for example, useful in event processing applications for specifying a pattern initiator message. The example above waits indefinitely for logins passing the relevant data to further processing in rules for predicate symbol server_1. You may ask a question, why could not we have used a global reaction rule for this prupose and the answer will be yes, we could have, in this particuar instance. What about the case when a multiple reaction is part of the response to another previous inline reaction? This makes the reaction indefinite but specific to the context of the preceding reaction.
The example below shows another way to specify multiple reactions and shows how such reactions can be part of a follow-up for a previous reaction. Let us just add one rule for server_1 from the previous example.
We use an annotation @count with parameter -1 to indicate that the inline rcvMsg reaction will be indefinite. This only works in event processing groups (hence the ise of the @group annotation). The variables XID, User and IP are already concrete data since we are in the context of the previous reaction to login. The guard in square brackets (see Guards in message processing) allows us to specify a constraint on the payload. Guards are executed before the message is accepted by the reaction. This means that if the guard fails, the reaction stays intact even if it is a one-message rcvMsg reaction. Any logical Prova code can go into the guard, not just simple arithmetic constraints, which makes it a very powerful feature.
Explicit termination of inline reactions
To explicitly terminate an inline, particularly multiple, reaction one has to send a specially formatted message to the reaction. The test msg006.prova shows how reaction termination works. Note that that the "Received" is printed from a conversation thread selected based on conversation-id so its order with respect to "Sent"'s is random. However, the termination signal is guaranteed to arrive before the third send is receved by the target conversation thread, so the third reaction never happens.
This example prints: