|Reflex - the Customizable Event Correlation System|
This section will need to start with some definitions. First, Policies are the foundation of Reflex. A Policy is the description that the compiler uses to create a custom correlator for a specific purpose. Each Policy contains a number of Patterns. A Pattern represents one particular reaction that Reflex may take, given appropriate input. Each Pattern contains a number of Descriptions, explaining what to look for, when to look for it, and what to do when it has been found.
To step back for a bit, the entire Reflex system is based around a special type of message called an Event. An Event is simply a collection of Attributes that arrive together, and each Event forms one unit of input or output. (Each Attribute is a name/value pair. Reflex allows Attributes of type STL String, integer, double, and bool). Events are fed into the correlator as it runs; and, once it discovers a Pattern, it emits a response, also in the form of an Event.
To make an Event, simply declare one and add attributes to it like this:
What to look for
Now, to get Reflex to recognize this Event, we'll write a description for it. To start, we write the first part of the Description: what to look for. This is similar to an expression in C++: You will be able to operate on Attributes and Constants by using arithmetic operators (+, -, *, /) and relational operators (<, >, ==, !=, <=, >=). Finally, each comparison forms a Boolean value, and these Boolean values can be combined using Boolean operators (&&, ||). Here is 'what to look for':
Notice that "IsValid" can appear by itself as a Boolean. If an Attribute is written into an expression like this, the Boolean value it contains will be used. If the Attribute doesn't have a Boolean value, the result is always false.
When to look
Now that we've described what to look for, let's tell Reflex when to look for it. Reflex has four 'rules' for deciding when to look for an Event. They are called by names: "reset", "always", "ordered", and "unordered".
The "ordered" rule is the simplest. An ordered Description will be looked for in turn - after all ordered descriptions before it and before all ordered Descriptions that follow. Consider this example:
Reflex will start out looking for an Event with an Attribute "Color" which has the string value "brown". (During this time, it will ignore all other Events.) Once found, it will start looking for another Event with Color "red". When this is found, it will look for an Event with Color "green", and once all of these have been found, it will make a reaction (give output) and start looking for brown again.
Note how the descriptions altogether are assigned to the one rule. This makes sense, because the order that they are declared in the set defines which order the system must watch for them. For the complete pattern, there is only one reset set, always set, ordered set, and unordered set - and that is the order that they must be written in the pattern.
What if you are looking for three such Events, but you don't care in which order they appear? Then you make the descriptions "unordered". This description:
will cause Reflex to react each time it sees three Events with colors "brown", "red", and "green" regardless of the order in which they arrive.
How about something more complicated? What if you're looking for "brown", "red", and "green", but if you see "black", you want to start over? In this case, the "black" Event will follow a different rule than the others, the "reset" rule. Here's how to write this:
What if you want to look for something more than once, and keep track of other information, such as how often you saw it? The "always" rule is designed for this, but without knowing about some other features, it won't be useful. This next example will look for "red" then "blue", will start over on "black", and will accept any number of "green" in the middle:
However, this pattern doesn't really need the "always" part, because Reflex will already accept any number of uninteresting events (like "purple") in between each important one. (Furthermore, it will ignore even meaningful events, like "blue", at the wrong time.)
Some additional features will make "always" more useful, starting with actions.
What to do
At this point, you know how to write two parts of a description: What to look for, and when to look for it. There is a third part to descriptions: What to do when it is found. This part is the action. Actions are connected to the end of the expression (within the parenthesis) by a question mark, a little like the ternary operator in C++. Here's an example:
This means, "if you see a ball, increment the BallCount". Actually, there are two new features here. The action, which allows you to do something conditionally, and a stored attribute, enclosed in 's. Stored attributes allow you to save information about the events you have seen as you are constructing a reflex. When Reflex sends out a reaction, the reaction will indicate which pattern has been found, and will also include all stored attributes.
How can you use this? Suppose that you want to count the number of blue Events you see before you see a black one. Here's how:
Notice that both an always and an ordered Description for the blue Event appear in the pattern. That is because an always Description is only looked for if a partial match has already been created. (This also allows the first ordered event to initialize the [count] variable. Otherwise, [count] = [count] + 1 wouldn't work.)
When this reaction is taken (when a black event is seen), Reflex will send out two attributes: the name of the reaction taken, and the count attribute. However, we haven't yet given any of the examples a name. The name does not go with a single Description, but with the whole collection of descriptions that will lead to a reaction, called a Pattern. To name this example, write it like this:
Finally, this is a complete Pattern that Reflex will look for! Also, because a Policy contains one or more Patterns, this is technically a Policy as well. Feed this as input to the compiler, and you will get the code to recognize this Pattern.
Reflex has just a few more features to fill it out. First, Stored Attributes can be used in expressions as well as in actions. (You could use this to keep track of all of the "blue" events headed for a specific person.) Second, we offer a function to determine whether an attribute exists, IsNull(). You can surround any event attribute or stored attribute with isNull to see if it has been defined. Finally, we allow one description to be nested inside the action part of another one. This is also called a Conditional Action, because you can perform another check inside an action to decide what to do.
Let's finish up with an example that uses all of the features of Reflex. This pattern counts animals: Antelopes and Gazelles. But, if it sees a Lion, the count starts over. However, the count could start on an Antelope, or a Gazelle, and we are counting them separately. In order to start the right variable at 1, we have used a conditional action. Also, we use stored attributes in the last description. This pattern counts animals until it sees 2 antelopes, 4 gazelles, or 5 animals, without an intervening lion. Notice that the final description does not look at any Event attributes, only stored ones!
Now that you understand the basics of Reflex Policies, check out the examples, write one of your own, or proceed to the Language Reference section to learn the details.
Copyright © 2001