Rules applications can be run in multitier mode. For rules applications that span multiple tiers where rule management is handled in the database, but the action execution for the rules is handled in the application server, the actions for the rules matching an event cannot be invoked from an action callback procedure. Instead, a results view is populated with the information about the events and matching rules; both of which are available for external action execution. The results view can be queried to determine the rules that match an event and their corresponding actions can then be executed.
To handle rules applications with certain rules having their action execution occurring on the application server, you must configure the rule class for external execution (in addition to configuring the action callback procedure). The steps to do this are similar to those described in Chapter2, but are modified as follows:
Create the event structure as an object type in the database (same as Step 1 in Chapter2).
TravelPromotion rule class. Also define the results view, even though you may not use it initially. The results view can be used, for example, to create the TravelPromotion rule class, such that for each rule session (that processes some events for a rule class), the action execution can switch at runtime between either the action callback procedure (calling
dbms_rlmgr.process_rules( ) as shown in Step 5 in Chapter2) or external action execution (calling
dbms_rlmgr.add_event( ), as shown in Step 5 in this section). For this purpose, the rule class is configured with an action callback procedure and a results view, as shown in the following example:
BEGIN dbms_rlmgr.create_rule_class ( rule_class => 'TravelPromotion', event_struct => 'AddFlight', action_cbk => 'PromoAction', rslt_viewnm => 'MatchingPromos', actprf_spec => 'PromoType VARCHAR2(20), OfferedBy VARCHAR2(20)'); END;
Note that this command creates the following
MatchingPromos results view to hold the results from the rule evaluation. This view has a fixed set of columns to list the system generated event identifier (
rlm$eventid), the event instance (
rlm$event for a (simple) primitive event), the rule identifier for the matching rules (
rlm$ruleid), the rule condition (
rlm$rulecond), the rule description (
rlm$ruledesc), and a variable set of columns to represent the action preferences associated with the rules (
OfferedBy columns in this example). For an event matching a set of rules in the rule class, the information about the event and the matched rules can be obtained by querying this view.
VIEW MatchingPromos ( rlm$eventid ROWID, rlm$event AddFlight, rlm$ruleid VARCHAR2(100), PromoType VARCHAR2(20), OfferedBy VARCHAR2(20)), rlm$rulecond VARCHAR2(4000), rlm$ruledesc VARCHAR2(1000); );
The results view in the case of a rule class configured for a composite event is structured to hold the results from evaluating the rules using one or more primitive events. For this purpose, this view is created with separate columns for each primitive event within the composite event. For example, the following results view is created for the rule class defined in Chapter2:
VIEW CompMatchingPromos ( rlm$eventid ROWID, Flt AddFlight, Car AddRentalCar, rlm$ruleid VARCHAR2(100), PromoType VARCHAR2(20), OfferedBy VARCHAR2(20), rlm$rulecond VARCHAR2(4000), rlm$ruledesc VARCHAR2(1000)),
Implement the action callback procedure (same as Step 3 in Chapter2).
Add rules to the rule class (same as Step 4 in Chapter2).
Identify the matching rules for an event. This step replaces the use of the process rules procedure (
dbms_rlmgr.process_rules( )) that identifies the matching rules and executes the corresponding actions with an add event procedure (
dbms_rlmgr.add_event( )) that adds the event to the rule class one at a time and identifies the matching rules for a given event that are later accessed using the
MatchingPromos results view.
BEGIN dbms_rlmgr.add_event ( rule_class => 'TravelPromotion', event_inst => AddFlight.getVarchar(987, 'Abcair', 'Boston', 'Orlando', '01-APR-2003', '08-APR-2003')); END;
Find the matching rules by querying the results view. For example, the following query returns a list of all the events added in the current session and their corresponding matching rules (and their action preferences):
SELECT rlm$eventid, rlm$ruleid, PromoType, OfferedBy FROM MatchingPromos;
The results from this query can be used to execute the appropriate action in the application server. In the case of a rule class defined for a single event structure, this view implicitly has a
rlm$eventid column that returns a system generated event identifier and
rlm$event column to return the actual event as the (primitive event structure's) object instance.
When you need to identify one candidate rule from the result set (conflict resolution), you can use
GROUP BY, and
HAVING clauses. Note that the callback mechanism for action execution can only use
ORDER BY semantics for conflict resolution. See Chapter3 for more information. For example, if the Travel Services application offers only one promotion of each type, the following analytical query can be used to identify the appropriate rules to be fired:
SELECT rlm$eventid, rlm$ruleid, PromoType, OfferedBy FROM (SELECT rlm$eventid, rlm$ruleid, PromoType, OfferedBy, ROW_NUMBER( ) over (PARTITION BY PromoType ORDER BY rlm$ruleid) rnum FROM MatchingPromos) WHERE rnum=1;
In this example, the rule identified as the one to be fired is the first one (
rnum=1) returned from the query of the result set for the set of rules that evaluated to be true, partitioned by the type of promotion and ordered in ascending order by the
rlm$ruleid column value.
The results from a rule evaluation are available until the end of the rule session. By default, the database session (from connect to disconnect) is considered the rule session. Alternatively, the reset session procedure (
dbms_rlmgr.reset_session( )) can be used to end a rule session and start a new session within a database session. Note that at the beginning of a rule session, the results view is empty.
Consume the event that is used in a rule execution. An event can be marked for exclusive or shared execution of rules by specifying the consumption policy for the events. Previously, in Chapter2, if the TravelPromotion rule class was configured for exclusive consumption of events, then an event used for the execution of a rule was immediately deleted from the system and it could not be used for any other (matching) rules. Because the action callback procedure is used, the rule manager automatically handles the consumption of the exclusive events. However, when external action execution is used, the application should explicitly consume the event chosen for an action execution by using the consume event procedure (
dbms_rlmgr.consume_event( )). This procedure ensures that when multiple concurrent sessions try to consume the same event, only one of them succeeds. So, the action for a particular rule should be executed if the event is successfully consumed, as follows:
DECLARE consumed number; BEGIN consumed := dbms_rlmgr.consume_event ( rule_class => 'TravelPromotion', event_ident => :eventIdBind); IF (consumed = 1) THEN OfferPromotion(…); -- offer the promotion only if the event -- consumption is successful END IF; END;
The event identifier is obtained from the value listed in the
rlm$eventid column of the
MatchingPromos results view. If the consumption policy (see Chapter3) for all events is shared, then the
CONSUME_EVENT call always returns 1 and the event is still available. Note that only the events configured for exclusive consumption are consumed and the corresponding rows from the results view are deleted.
A rule-based application designed using Rules Manager has a varying number of steps, depending on its mode of operation. Almost all the steps in both cases, single tier and multitier, are one-time implementations. Once these implementations are in place, the end-user no longer needs to deal with the Rule Manager APIs. The new rules are added using the SQL
INSERT statement against the rule database table and the run-time calls that are embedded in larger applications will automatically process these new rules.
A rule class stored in the database can operate in either of the following two modes:
Single tier mode -- the rule evaluation, identification of the candidate rules or action for execution, execution of action, and optional consumption of events all happen in the database with a single
PROCESS_RULES call (which passes in the event instance). Note that this is the most common case even for applications running outside the database.
Multitier mode -- the rule evaluation happens in the database and the remaining steps described in single-tier mode can be done in any tier with appropriate database calls (with a maximum of four steps, which are described in Chapter5).
The main reasons for a rules application to operate in the multitier mode are:
The action suggested by the rules cannot be implemented as a database function or package (PL/SQL or Java) in the database.
The conflict resolution criterion for the rule class is complex and it cannot be specified using a SQL
ORDER BY clause. In situations when a single event processing a set of rules matches two or more rules, conflict resolution criterion is used to identify a subset of rules or determine an exact order of rules that should be fired, or both. Using a simple SQL
ORDER BY clause is usually sufficient for most applications. However, multitier mode can make use of any SQL operator (including analytical operators) for the conflict resolution criterion.
The four steps to use Rules Manager in the multitier mode are:
Tell the database about the event by calling the
Ask the database which rules apply (query a view, possibly with a complex query with a SQL
ORDER BY clause, and so forth).
Based on the applications conflict-resolution criteria, identify a subset of the matched rules that should be fired and prepare for executing the action by consuming the event with a
dbms_rlmgr.consume_event function call.
Upon success in Step 3, make calls to the (local, middle tier resident) routines that the programmer maps to the actions that are defined.
If the only reason for using the multitier mode is to execute the actions in the application server, then the single tier mode with a few modifications can be used (thereby reducing the number of steps involved to two). The action callback procedure in the single-tier mode can be implemented to enqueue the actions and continue with the rest of the operations (consumption). The application server can subscribe to this action queue and execute the actions. In this configuration a minimum of two database calls are required (
PROCESS_RULES call and
Rules Manager, as a database feature, can be used in multiuser and concurrent session environments. It allows two concurrent sessions to process the same set of rules and call for deletion of a common event that matched the rules and ensures that only one of the sessions succeeds. When the rule application is operating in the single-tier mode, this happens by specifying an
EXCLUSIVE consumption policy for the event type. The
PROCESS_RULE procedure controls the event consumption logic and avoids deadlocks between various sessions. When the rule application is operating in multitier mode, the middle tier application must signal its intent to execute the action of a rule by calling the
CONSUME_EVENT function (because the user application is controlling the conflict resolution criterion). This call returns 0 if any one of the events required by the action has already been consumed by another concurrent session. So, the application should execute the action only if this call returns 1. Note that this step can be skipped if all the events are configured for
SHARED consumption (implying that the events are shared for multiple rule executions).
Because one of the main reasons for using the multitier mode is to implement complex conflict resolution criteria, the results from matching an event with the rules is exposed (to the application) as a relation that can be queried using complex SQL. This view can also be used to specify different resolution criteria based on some external factors (for example, use one conflict-resolution criterion between the times 9AM-5PM and other criterion for the rest of the day).
Rules Manager rule classes can store any form of data (scalar, XML, Raw, BLOB, and so forth) along with the rule definition. This data is returned back to the action-callback procedure or the application when the corresponding rule matches an event.
For example, a rule application may choose to store Simple Object Access Protocol (SOAP) messages in their full form (in an
XMLType column) as actions for each rule. So, when a rule matches an event, this SOAP message is returned to the application. The application in the middle tier could interpret the data accordingly and perform the required action (post the SOAP message). See Appendix G for additional information on action execution.
In another application, the exact call for the action may be fixed, for example using the
OfferDiscount2Customer function. In this case, the rule definitions may just store the percentage of discount that should be offered. When this discount value is returned to the application, it can be bound as an argument to the
OfferDiscount2Customer function call.