The following example shows what happens when trigger programs issue
commands that cause events to occur that also have triggers.
This example
involves the business object "Document Checker 0" and a bit of a squabble
between three users, Tom, Dick, and Harry, who fight over ownership.
The default recursion test (name matching) is in use.
Assume that these triggers are in place in the Document type on the
changeowner event:
# Changeowner Event Check Program on Document Type:
mql
code "output 'DocumentChangeOwnerCheck: OBJECT = ${OBJECT} TYPE
= ${TYPE}';
output ' NAME = ${NAME} REVISION = ${REVISION} OWNER =
${OWNER}';
output ' ACCESSFLAG = ${ACCESSFLAG} USER = ${USER}';
output ' CHECKACCESSFLAG = ${CHECKACCESSFLAG}';
output ' TIMESTAMP = ${TIMESTAMP}';
output ' NEWOWNER = ${NEWOWNER}';
tcl;
set status 0
set status $env(RETURN_CHECK_CODE)
exit $status
";
#Changeowner event Override Program on Document #Type:
mql
code "output 'DocumentChangeOwnerOverride: OBJECT = ${OBJECT}
TYPE =${TYPE}';
output ' NAME = ${NAME} REVISION = ${REVISION} OWNER =
${OWNER}';
output ' ACCESSFLAG = ${ACCESSFLAG} USER = ${USER}';
output ' CHECKACCESSFLAG = ${CHECKACCESSFLAG}';
output ' TIMESTAMP = ${TIMESTAMP}';
output ' NEWOWNER = ${NEWOWNER}';
modify bus ${TYPE} ${NAME} ${REVISION} owner Dick;
tcl;
set status 0
set status $env(RETURN_OVERRIDE_CODE)
exit $status
";
Environment variables handle the exit code from the check
and override trigger programs. Their settings are: RETURN_CHECK_CODE=0
and RETURN_OVERRIDE_CODE=1 (which means the check program
will not block and the override program will replace the normal event
handling). Harry is the current owner of the Document object and has
decided to change ownership to Tom. Here is the output:
MQL<7>modify bus Document Checker 0 owner Tom;
DocumentChangeOwnerCheck: OBJECT = Document Checker 0 TYPE =
Document
NAME = Checker REVISION = 0 OWNER = Harry
ACCESSFLAG = True USER = creator
CHECKACCESSFLAG = True
TIMESTAMP = Thu Jan 6, 2010 11:28:03 AM
NEWOWNER = Tom
DocumentChangeOwnerOverride: OBJECT = Document Checker 0 TYPE =
Document
NAME = Checker REVISION = 0 OWNER = Harry
ACCESSFLAG = True USER = creator
CHECKACCESSFLAG = True
TIMESTAMP = Thu Jan 6, 2011 11:28:04 AM
NEWOWNER = Tom
DocumentChangeOwnerCheck: OBJECT = Document Checker 0 TYPE =
Document
NAME = Checker REVISION = 0 OWNER = Harry
ACCESSFLAG = True USER = creator
CHECKACCESSFLAG = True
TIMESTAMP = Thu Jan 6, 2011 11:28:05 AM
NEWOWNER = Dick
The changeowner override program issues its own
modify businessobject Document EventTriggers 0 owner Dick command.
When Harry attempts to change the owner, this command causes a nested
changeowner event to occur, which causes a second set of triggers to
fire. The second override program is a no-op because the first override
program is still running. Since this second override program is a no-op,
the normal event activity (in this case, the first override program)
is guaranteed to take place. This is an important point to keep in mind.
At this point, the owner has been changed to Dick.
After the nested changeowner event transaction commits and the associated
action program, if any, runs, control returns to the original changeowner
event. If the exit code from the override program is non-zero, the normal
event activity is skipped and the owner name continues to be Dick. If
the exit code is zero, the normal activity takes place (overriding the
owner change that took place in the nested event transaction). Now the
owner name is changed to Tom. In either case, the original event transaction
commits and the action program (if any) executes.
Look at the case of the changeowner action program issuing its own
modify businessobject Document Checker 0 owner Harry command.
Assume that RETURN_OVERRIDE_CODE=0 so that the event
is not replaced.
#Changeowner event Action Program on Document Type
mql
code "output 'DocumentChangeOwnerAction: OBJECT = ${OBJECT} TYPE
=${TYPE}';
output ' NAME = ${NAME} REVISION = ${REVISION} OWNER =
${OWNER}';
output ' USER = ${USER}';
output ' TIMESTAMP = ${TIMESTAMP}';
output ' NEWOWNER = ${NEWOWNER}';
modify bus ${TYPE} ${NAME} ${REVISION} owner Harry;
quit;";
In this case, the command causes a new changeowner event
to occur after the initial event transaction has been committed. When
it is time for the action program to be run, the owner has changed to
Tom. As before, recursion occurs and the second action program is a no-op
since the first action program is still running. Note that the second
owner change to Harry, which is caused by the action program, will override
the owner change to Tom that took place as the normal event transaction
before the action program was executed.
Look what happens when both the changeowner override and action programs
generate changeowner events as defined earlier. Assume that RETURN_OVERRIDE_CODE=1
again, so that the event is replaced. In this case, we see the
combined affects of both programs. The question is who now owns the
Document object? The only way to find out is to trace through the changes
in a sequential fashion.
1.0) Original ChangeOwner event transaction is started. Check fires. 2.0) Override changes owner to Dick. 2.1) Nested ChangeOwner transaction is started. Check fires. 2.2) Override is a no-op, since the same Override Program (step 2.0) is still
running. Transaction is committed. 2.3) Nested event's Action changes owner to Harry. 2.3.1) Nested ChangeOwner transaction is started. Check fires. 2.3.2) Override is a no-op, since the same Override Program (step 2.0) is still
running. Transaction is committed. 2.4) Nested Action is a no-op, since the Action (step 2.3) is still running.
Transaction is committed. 3.0) Original ChangeOwner event Action changes owner to Harry. (redundant). |
With the original event transaction now committed, it seems as if
the action program changes will prevail.
3.1) ChangeOwner transaction is started. Check fires. 3.2) Override changes the owner to Dick. 3.2.1) Nested Changeowner transaction is started. Check fires. 3.2.2) Override is a no-op since the Override program (step 3.2) is still
running. Transaction is committed. 3.3.3) Nested Action is a no-op since the Action program (step 3.0) is still
running. Transaction is committed. 3.3) Action is a no-op since the Action program (step 3.0) is still running.
Transaction is committed. |
The proper conclusion is that an override program that replaces normal
event activity will always win out. This example is simplistic because
the check program was not involved, and the override and action programs
issued single commands that generated the same event. Obviously, trigger
programs issue many commands and the events generated by these commands
trigger other programs, and so on. Because of this complexity, consider
graphing the events, showing time on one axis, and the level of nesting
on the other.