By Acshorten-Oracle on May 20, 2014
One of the features of Oracle Utilities Application Framework V4.x is the ability to audit inquiries from zones and pages. This allows you to track information that is read rather than what is updated (which is the prime focus of the internal audit facility).
This example shown below is a sample only. It just illustrates the process. The Script is invoked upon broadcast (the sample does not include the global context but that can be added as normal).
To use this facility here is the basic design pattern (in order you would perform it):
- Decide where you want to store the inquiry data first. You cannot store the inquiry data in the same audit tables/objects as updates or deletes are recorded as the Audit Object Maintenance Object is read only (as it is only used internally). You have three options here:
- If the Maintenance Object has a child log table then this is ideal for recording when that object is read or viewed by an end user. The advantage of this option is that there is more than likely a user interface for viewing those records.
- If the Maintenance Object does not have a child log table then you can use the generic Business Event Log object (F1-BUSEVTLOG). This can be used to store such audit information. You may want to create a UI to view that information in a format you want to expose as well as adding records to this table. If you use this option, remember to setup a message to hold the audit message you want to display on the screen. This is needed in the Business Object definition. This is in the sample used.
- You can create a custom Maintenance Object to store this information. This is the least desirable as you need to build Java objects to maintain the Maintenance Object but it is still possible. For the rest of this article I will ignore this alternative.
- Create a Business Object with the data you want to store the audit within using the Business Object Maintenance Schema Editor. You can structure the information as you see fit including adding flattened fields for the collections if you wish.
For example, for Business Event Log I created a BO called CM-BusinessAuditLog like below:
<logId mapField="BUS_EVT_LOG_ID"/> <logDateTime mapField="LOG_DTTM" default="%CurrentDateTime"/> <user mapField="USER_ID" default="%CurrentUser"/> <maintenanceObject mapField="MAINT_OBJ_CD" default="F1-BUSEVTLOG"/> <businessObject mapField="BUS_OBJ_CD" default="CM-BusinessAuditLog"/> <primaryKeyValue1 mapField="PK_VALUE1" default="001"/> <messageCategory mapField="MESSAGE_CAT_NBR" default="90000"/> <messageNumber mapField="MESSAGE_NBR" default="1000"/> <version mapField="VERSION" suppress="true"/> <parmUser mapField="MSG_PARM_VAL"> <row mapChild="F1_BUS_EVT_LOG_MSG_PARM"> <PARM_SEQ is="1"/> </row> </parmUser> <parmPortal mapField="MSG_PARM_VAL"> <row mapChild="F1_BUS_EVT_LOG_MSG_PARM"> <PARM_SEQ is="2"/> </row> </parmPortal> <parmZone mapField="MSG_PARM_VAL"> <row mapChild="F1_BUS_EVT_LOG_MSG_PARM"> <PARM_SEQ is="3"/> </row> </parmZone> <parmF1 mapField="MSG_PARM_VAL"> <row mapChild="F1_BUS_EVT_LOG_MSG_PARM"> <PARM_SEQ is="4"/> </row> </parmF1> <parmH1 mapField="MSG_PARM_VAL"> <row mapChild="F1_BUS_EVT_LOG_MSG_PARM"> <PARM_SEQ is="5"/> </row> </parmH1> <parmXML1 mapField="MSG_PARM_VAL"> <row mapChild="F1_BUS_EVT_LOG_MSG_PARM"> <PARM_SEQ is="6"/> </row> </parmXML1> <parmGC1 mapField="MSG_PARM_VAL"> <row mapChild="F1_BUS_EVT_LOG_MSG_PARM"> <PARM_SEQ is="7"/> </row> </parmGC1> <parmF1Label mapField="MSG_PARM_VAL"> <row mapChild="F1_BUS_EVT_LOG_MSG_PARM"> <PARM_SEQ is="8"/> </row> </parmF1Label> <parmH1Label mapField="MSG_PARM_VAL"> <row mapChild="F1_BUS_EVT_LOG_MSG_PARM"> <PARM_SEQ is="9"/> </row> </parmH1Label>
- Note: I set up a basic message (message category 90000 and message number 10000) to hold the desired message
User %1 has read value %6 on Portal %2 within Zone %3
- Create a Service Script (say CM-AuditZone) to populate the fields on the Business Object according to your site standards. Remember to add the Business Object as a Data Area For example:
move "parm/userId" to "CM-BusinessAuditLog/parmUser"; move "parm/portalName" to "CM-BusinessAuditLog/parmPortal"; move "parm/zoneCd" to "CM-BusinessAuditLog/parmZone"; move "parm/pk1" to "CM-BusinessAuditLog/parmXML1";
invokeBO 'CM-BusinessAuditLog' using "CM-BusinessAuditLog" for add;
To reduce performance impact on creating audit records (also to add audit records when the change mode on the prime object is read only) it is recommended to create another Service script (say CM-ZoneAuditing) and use F1-ExecuteScriptInNewSession to execute it in a new thread. Remember to add the script as a Data Area. For example:
move "parm/input" to "CM-AuditZone"; move 'CM-AuditZone' to "F1-ExecuteScriptInNewSession/scriptName"; move "CM-AuditZone" to "F1-ExecuteScriptInNewSession/scriptData";
invokeBS 'F1-ExecuteScriptInNewSession' using "F1-ExecuteScriptInNewSession";
- Add the schema to the script to accept the input from the Zone parameters as per the Help entry for the Audit Service Script. For example:
<input type="group"> <userId/> <zoneCd/> <portalName/> <mo/> <pk1/> <pk2/> <pk3/> <pk4/> <pk5/> </input>
Attach the Audit Service Script (CM-ZoneAuditing). For example:
ss='CM-ZoneAuditing' input=[zone=zone portal=portal user=userId pk1=F1Label pk2=F1 pk3=F3Label pk4=F3]
This example is just a sample with some basic processing. It can be extended to capture additional information. It is recommended to use Log files on the Object if they are available.