Showing posts with label Framework. Show all posts
Showing posts with label Framework. Show all posts

A Better XML Logger

This article is Part 3 of Siebel Error Handling Approach

Introduction

Last time we looked at an XML logger implementation using the vanilla "EAI XML Queuing Service", and ran through its shortfalls. This time we go through the design of a better XML logger, and introduce a new XML tagging feature.

The keys to building a better XML Logger comes back to understanding how the EAI XML Queueing Service works. The Queueing service takes a SiebelMessage, converts it from a PropertySet to an XML document, and saves it to a file attachment BC, all of which are standard Siebel operations. So we can use this design as the basis of our own EAI XML Queueing service implementation.

High Level Design

1. Create an IO around the EAI Queue/Item BC
2. EAI Queue Item will store References to our Error table, and XML Tagging information
3. Implement an XML query capability to extract information from the message
4. Dynamically Generate a Siebel Message around the EAI Queue structure, with our XML message as an attachment
5. Use EAI Siebel Adaptor to insert the XML message
6. Put a view on top of the above components to allow association to the error table, and to support querying through the UI

Build Steps

1. Create a new WF: "A Better XML Queuing Process"

This workflow has to support logging of either a SiebelMessage, XML document, or any other type of interface message Eg. If a SiebelMessage is provided, this has to be converted to XML Doc.

2. Generating the EAI Queue SiebelMessage

This WF step generates a SiebelMessage that contains the above interface message as an attachment.

There are 3 mains method for creating an instance of this IO

1. XSLT
2. PRM ANI Utility Service
3. Scripting

PRM ANI Utility will easily generate a SiebelMessage structure which is 90% of your work, but it will not generate the File Attachment IC, so it has to be complemented with some scripting, or go for the declarative option using XSLT, which will allow us to generate a message complete with the Attachment IC without resorting to scripting.

3. Populating the SiebelMessage

This WF step populates the SiebelMEssage with actual data and will require some sort of transformation, so you have the following options

1. Data Mapper
2. XSLT
3. Scripting

Once you have your SiebelMessage, using Data Mapper with inputs should be straight forward, however, using the XSLT method requires a little more work, because you will need a source document that contains all your source values, plus the XML payload. This can be achieved by using an empty SiebelMessage, and using dot notation to inject all your variables, including the XML payload, into the SiebelMessage header as attributes. These attributes would then be available in your source document to complete the transformation.

The following, is a list of the attributes required to produce an IO with attachment

XML Payload
Comments
Queued Timestamp
Reference Id
Reference Val2
Reference Val3
Sequence Number
Status
Queue Name
AttachmentIsTextData
Extension
MsgFileAutoUpdFlg
MsgFileDate
MsgFileDeferFlg
MsgFileDockReqFlg
MsgFileDockStatFlg
MsgFileExt
MsgFileSrcType
MsgFileName

The vanilla EAI XML Queueing Service produces attachments with a rigid format similar to this

s_eai_queue_itm_1-62O6DB.txt

The file type is hard coded to txt, and the filename cannot be controlled

The "MsgFileName" is of particular interest to us, as it allows us to produce a more meaningful filename.

4. Insert SiebelMessage

At this point, the populated SiebelMessage is ready to be Inserted via EAI Siebel Adaptor.

5. Build a nice UI to retrieve these XML logs, in association to its Error log.

Our XML files are saved to the Siebel file system, allowing users to retrieve the XMLs without going through file system permissions.

Message Tagging

Message Tagging provides the ability for a project to peek inside the XML message while in transport, and log certain elements/attributes for searching. This was one of the downfalls of EAI Queueing Service, as key details of the message were hidden, until you opened each message individually. This capability is important because Siebel zips the files stored in its attachment folder, and the contents become unsearchable, unless we tag it.

The following XML is a sample of an image notification message. The key pieces of information to be tagged from this message are the Id, PartyType, SourceSystem, and NewImageFlag.
<?xml version="1.0" encoding="UTF-8"?>
<PartyUpdate>
   <PartyIdList>
       <PartyIdDetails>
           <Id>1-XXXX</Id>
           <Type>Siebel</Type>
       </PartyIdDetails>
   </PartyIdList>
   <PartyType>PERSON</PartyType>
   <EventSource>ESB</EventSource>
   <SourceSystem>Imagr</SourceSystem>
   <NewImageFlag>true</NewImageFlag>
</PartyUpdate>
The schema would obviously allow for other types of notifications, and the Message Tagging capability would need to be flexible enough to cater for these other schema options. Message Tagging can be implemented with different kinds of tools, but at the heart of it, we need to query data from the XML.

A few Siebel favourites which can be used for deep hierarchy extraction are

1. FINS Industry XML Query Service
- Allows XPathish notation to be used

2. PRM ANI Utility Service.GetProperty
- Supply the IC name, and property to be extracted

3. WF Alias
- Similiar to Dot notation, but without the 75 character limitation

To be honest, none of the above options are particularly flexible, especially for dealing with namespaces, repeating groups, filtering, getting the nth child, dynamic querying etc. There isn't any vanilla querying capability, that meets this particular requirement.

So for your more ambitious Error handling needs, I would go for a Java based solution, that implements the full XPath standard, allowing all of the previous problems to be addressed. This would be implemented in a JBS, which accepts two arguments the XML, the XPath expression, and returns the XPath result.

To follow our theme of flexibility, the system shouldn't be hard coded to look for certain elements, the design should allow the customer to configure XPath statements, and associate them with an Interface, and maybe more specifically an Interface direction. Going down this path, takes us down a level of abstraction that is not available out of the box, which is a good thing, except for the poor designer who has to materialise this concept!

Conclusion

In this series on Error Handling in Siebel, we've taken a look into the key features of an Error Handling framework. We also delved into the complex error handling requirements of an EAI professional, dissected EAI Queueing Service, and provided the map for framework designers to build a better XML Logger. For an alternative approach, fellow Siebel expert Mik, also provides a different design that readers should also consider.

The capability to capture an XML message, along with its associated error detail, should be a core part of every projects toolset and there should be no doubt, on the importance of this feature. Error Handling Frameworks are not new to Siebel, but they are only available behind closed doors, so the comments are open to readers.

Do you have classy Error Handling ideas that you would like to share with the rest of the world?

Siebel Error Handling Approach

Introduction

Error Handling or Exception Handling, is an essential part of any Siebel project, but where does it come from?. Unlike other commercial development environments, Siebel dosnt provide a standard error handling framework out of the box, or even as a third party add on. Surprising as it sounds, It is left up to each project to implement their own specific error handling capability.

Importance of Error Handling

"Jason, can you help me, my Tools is corrupt, the WF designer discards every one of the error branches that I try to create!"

"I see the problem, you are not providing the Error branch with a name"


The above is a real life scenario of a senior consultant not knowing how to handle errors in Workflow. While Error Handling is important, it seems not everyone knows how to implement it. Its an issue that plagues many developers, because the first step in development is to ensure our build is working first, before we can really understand the circumstances around how it could fail. It requires experience and forethought, to build to components with robust guards in place.

Not everyone gets it right the first time, but that's okay, because robustness is improved over time, but more alarmingly, not every developer designs with Error Handling in mind, nor goes back and puts error handling in place after the build is unit tested.

Error Handling Standards and Features

Error Handling is more than just using TheApplication().Trace at key points in your program, and it is not limited to scripting. Error Handling frameworks vary from project to project, but the fundamentals should remain the same.

Here is a list of ideas, which I've separated into 5 categories, that you could incorporate into your Error Handling Approach.

Scripting
★ Ensure call functions are wrapped in try/catch/finally
★ Put return statement after the finally block
★ Errors should be bubbled up, and handled at the place of invocation
★ Capture stack trace
★ Capture state of variables

WF
★ All major steps should have unhandled exception branches and error checks
★ Unhandled Exceptions should capture as much context around the error as possible
★ Sub processes should return an error property to the parent WF where the error is handled
★ Parent WFs should utilise the Error Process Property or route Errors to a standard project Error Handling Sub Process

Integration
★ All Outbound/Inbound messages should be logged
★ Capability to recognise and handle SOAP Fault and SOAP Warnings accordingly
★ Capability to handle non committed Enterprise transactions
★ Retry capability

BRP
★ Validation errors shouldnt be put into the system error property
★ Errors should be bubbled up, and handled at the place of invocation

General
★ Logging framework to allow debugging
★ Message Lookups
★ Settle on a standard Error Property
★ Provide generic friendly message

Some of the above ideas are standards that need to be enforced through training and technical reviews, while others are capability and tools that needs to be built to support the error handling needs of the project. Some projects take the idea a little further, and provide help desk features such as error assignment, capturing resolution and KPIs.

Show me the details

When an error occurs we want to log as much information as possible, at the point where the error occurred, and depending on the severity, we can make an informed decision on whether to fix the issue straight away or defer it to another release.

Some of the most important error details to log are


★ User Name
★ Error Time
★ Host Name
★ Primary Id
★ Internal Error Code
★ External Error Type
★ External Error Code
★ Error Message
★ Error Category
★ Transaction Time
★ Calling Function/WF
★ Stack Trace
★ XML Logs

Until next time

Imagine that you have an application in production, your users are getting generic error messages that is of no absolute value, and you have to spend hours trying to recreate the issue to get to the bottom of the problem. At this point, you are probably wishing that you had better Error Handling capability, but it is too late, because you know you would have to live with this until the next release, so don't let poor error handling slip by unnoticed.

Having full details of the error, provides you with the confidence to resolve issues, or ignore problems and move on, and defer fixing it in the next iteration of your development. Any reputable System Integrator would have an Error Handling Framework ready, that they would have carried over from past projects, or even if you've got an in-house project, there's nothing stopping you from drawing on the experience of your consultants, or use the above list as fuel, to build your own Error Framework.

Handling errors when working with EAI, requires more specialised capability, and in the follow up to this article, we go through the design process of how to implement the XML logging feature listed above, and in the tradition of Impossible Siebel, bypass a Siebel limitation a long the way.

Part 2 continues here

Funky Town: Non blocking UI

This post is part of the Funky Town series of articles, where we take ridiculous User Centric Design (UCD) requirements and put them into practice.

Imagine that the user

1. Clicks on a button that kicks off a long running report on the server and gets back immediate control of the UI

2. Navigates to another view that fires off several interfaces to get data back

3. As soon as each interface call completes, the screen refreshes with the new data

4. Minutes later the report finishes and the user is presented with a real time browser notification

If the advantages dont jump at you, this list will make it obvious

1. Non blocking UI
2. No nasty polling to maintain
3. Reduced network traffic
4. Less waiting time
5. Real time server to browser notification
6. Parallel processing

This sounds like some modern website, but with a bit of engineering, we can transform Siebel into a more feature rich application.

Basics

Siebel executes code in two modes
1. Synchronous
2. Asynchronous

Synchronous

Server processes invoked by a users session eg. eScript/WFs run synchronously. In other words, you cannot have two pieces of code run in parallel. Synchronous execution freezes the users screen (including any browser side animation) and forces the user to wait until one process has completed before it runs another process.

Asynchronous

Processes can be made to run asynchronously, by dispatching the execution to a background process. This mode provides control back immediately, but a callback is not provided when that process finishes.

However with a little fancy footwork, we can get the best of both worlds. Dispatching code asynchronously with a callback.

Implementation

We will build a button that fires a piece of code that runs on the server for a 10 seconds. The user will be free to do what they choose, and when the server process is complete, a sexy message slides into view, displaying to the user the number of seconds the code took to run.

Ingredients

1. Ajax

Allows us to execute code in the background and get a callback. We will use javascript to launch our background process and listen for the response.

2. Interface

Since the code is triggered client side, we need a browser accessible Siebel interface that allows us to execute code and return some values.

Pick one of the following or come up with your own

A. SWE Querystring
B. XML Command Block
C. SOAP

3. Read Results

I'm going to pick option A. Options B and C will also work, but require dealing with XML payloads and using HTTP POST in javascript, which I'll leave for EAI developers to play with.

The solution entails using Ajax, which dispatches a call to a background process, essentially running synchronous code in a separate session. The user is free to move on and perform other tasks, when the background process finishes, it returns to the browser which registered a callback, the callback function can then notify the user of the results of the process.

4. Proxy

The proxy BS will act as a wrapper to call the intended process, and add the HTTP response headers. These headers are required because invoking a business service using the query string kicks off a server process, which dosnt return a property set to the browser. The proxy business service will convert the outputs into headers that the browser can understand.

5. Session

If we run Ajax calls against our active session, it will still block our UI, so to get around this problem we need a separate Application to offload and invoke our interface. Your second Application can be SI or HI, as long as its different from your active UI session.

The interaction sequence looks like this



There are two key pieces of code that is required for this to work.

1. Ajax Call

The following code is initiated from a button on the browser, and makes a HTTP GET request, using the SWE Querystring API. This querystring calls a Proxy BS, passing in the destination Business Service, Method, and arguments.

It also registers a callback routine to handle the result from the background process. This callback function can take summary data from the server business service and display the results to the users session or it can detect the users view, and refresh data that has been loaded in the background.

var reqUrl = "/Application2/";
reqUrl+="start.swe?SWECmd=ExecuteLogin&SWESetMarkup=XML&SWEDataOnly=1"+
"&ParamBS="+sBS+
"&ParamCallMETH="+sMeth+
"&SWEAC=SWECmd=InvokeMethod&SWEMethod=test&SWEService=MyProxyBS";

var xmlHttp = new XMLHttpRequest();
xmlHttp.open('HEAD', reqUrl, true);
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200 || xmlHttp.status == 204) {

var sResp = ""+
",Status: "+xmlHttp.status+""+
",Result: "+xmlHttp.getResponseHeader("time elapsed");
alert(sResp);
}
}
}


2. Proxy BS

This Proxy BS written in eScript, handles the invokation of the destination Business Service, and creation of the custom HTTP headers. Once this piece of eScript finishes, it returns to the onreadystatechange handler in the code above.

var oBSWeb = TheApplication().GetService("Web Engine HTTP TXN");
oBSWeb.InvokeMethod("GetAllRequestParameters", Inputs, Outputs);

//Get parameters from querystring
var sBSToCall = Outputs.GetProperty("ParamBS");
var sMethToInv = Outputs.GetProperty("ParamCallMETH");          

//Call your BS
//processing time here....
var sElaspedTime="1000";

//set response headers for the browser to read
Inputs.SetProperty("time elapsed",sElaspedTime);
oBSWeb.InvokeMethod("SetResponseHeaders",Inputs,Outputs);


The example above just uses an alert, but an imaginative developer can implement a sexier dialog, or invoke a refresh on the current view

Summary

I've demonstrated usage of the SWE API, but Siebel provides a similar more supportable architecture in the form of an EAI Object manager, making the SOAP interface a more suitable fit.

This is no simple piece of configuration, and it is not recommended that you attempt it without the consultation of your local Siebel Architect. The intention of this article, is to illustrate how Siebel and browser technologies can come together to achieve a solution that was written off as impossible.

This concept was POC'd for client who needed real time notifications for bulk processing, it allowed the user to continue on, and get a fancy notification once the process was completed.

To satisfy our Funky town series, we have to ask ourselves

1. Will it perform well?
Yes, code can be distributed in parallel, and run in the background

2. Is it maintainable?
Yes, if the code is put into a framework, and maintained by an experienced professional

3. Can it be upgraded?
Yes, the solution can be built using a supported architecture, and abstracted through a business services. and

4. Is it sexy?
Yes, its what Siebel Open UI promises to be, except Open UI dosnt do server side callbacks! (Confirmed with Siebel in 4th Qtr 2011)

EAI Phone Format Challenge feat. JL Engine

BRP

Business Rule Processor (BRP) is a diamond in the configurators toolkit, and it should be at the forefront of Oracle's marketing efforts to license more copies of Siebel. If you've never heard of BRP, then you've never lived Siebel, just imagine an Application that is fast, which can be complex and flexible, and at the same time being virtually script free.

Amazing as it is, it has a few flaws, rules cannot be validated, there are UI bugs that make development annoying, rules dont synchronise across multiple OMs, procedures don't support parameters, but the most obvious flaw is the debugging capabilities, every thing is just dumped to the OM logs, no workflow instance monitor, or TBUI like debugger around here, just old fashion log files.

However the design approach of BRP is apparent, the first release of BRP was meant to deliver a fast and stable tool, anything else was second priority, but there is a question that hangs around the future of BRP, with OPA being crowned the rules engine of choice within Oracle. There seems to be a gap in the strategy, OPA is a policy determination engine, while BRP is an eScript replacement, one is business focused, while the other is technically focused, two different things in my opinion.

So what if you dont have BRP on your project? I was engaged by a customer to design solutions to a common problem, getting rid of a sea of code and improving maintainability. All the standard Siebel declarative and non declarative options were considered and weighed up against another. One of the key components of this redesign was a rules engine, and BRP was the primary choice, but due to various factors, including whether BRP could be sourced. I was engaged to build a BRP replacement: a custom rules engine that overcomes some of BRP's limitations that is declarative and fully customisable.

JL Engine

For the sake of identity, the rules engine is conveniently referred to as JL Engine.

Imagine that you could extend the native Siebel Query Language Expressions, and create your own functions, that can be accessed declaratively. This is a powerful feature that allows developers to bypass many of the complexities around implementing rules using the traditional Siebel expressions, and potentially replace a large amount of scripting.

What kind of complexities do you ask? To fire your imagination, how about we solve the EAI Scriptless Phone challenge using this new engine? Previously I demonstrated the power of BRP, and showed how BRP can be used to solve this challenge. It required 15 expressions to complete the task

If you had control over your expressions, you could design convienent utitlities to more effectively solve this challenge, and also re-use these utilities across the application, or you could cheat and design a fancy expression that solves the EAI phone challenge in 1 step, but in consideration of good application design, we are going to design components which are re usable, hence this new rules engine solves the challenge in 8 steps.

Here are some of the new exotic expressions that will aid us in this Challenge

ApplyMask(Mask,MaskCharacter,Value)
//Usage: ApplyMask("$XX.XX","X","1234") = $12.34

AscFromChar(AsciiCode)
//Usage: AscFromChar("65") = A

GetArrayPart(ArrayString,Delimiter,ArrayIndex)
//Usage: GetArrayPart("A,B,C",",","1") = B

CountChar(Value,CharToCount)
//Usage: CountChar("$XX.XX","X") = 4

Solving the EAI Challenge with JL Engine

1. Getting the LF character

This was the original stumbling block to solve this challenge when it was first announced. I presented a solution using XSLT. Impossible Siebel reader Dos, then chimed in with other 2 solutions.

BS: SSSE Address Parser
Method: GetCRLF

This business service returns a CRLF, which is actually two characters chr(10) + chr(13), so the return string has to be post processed to return only chr(10)

SetProfileAttr("LF","\n")

Using SetProfileAttr to set \n, and retrieving it using GetProfileAttr is elegant, but requires two steps. Using our JL Engine expression below allows us to complete this in one step

AscFromChar("10")


2. Separating the Phone and Format from the EAI Phone String

Once we have the LF character, string expressions can be used get our string. In BRP this is done using two expressions Instr is used to find the position of the LF character, then Left/Right is used to chop the string.

"+44123456789LF(00) 00 000 000"

Using our JL Engine expression below allows us to complete this in one step. GetArrayPart splits the string, and returns the desired index.
GetArrayPart("+44123456789LF(00) 00 000 000" ,"LF","0")

3. Applying the Format Mask to the Phone Value

To make things harder, the phone value has the international prefix, which is additional to the number and should not have the format applied to it. BRP and the original XSLT solution solved this by using two cursors, one to track the position of a Mask character, and the other to track the position of phone digit that corresponds to this mask characters, and involved looping and recursion. Using our JL Engine expression below allows us to complete this in one step (three nested expressions)
CountChar("(00) 00 000 000","0")
Counts the number of format characters, which we then use to perform a Left/Right on the phone string to split the prefix and phone Once we have the phone without the international prefix, we use the following Expression to get the formatted number.

ApplyMask("(00) 00 000 000","0","123456789")
The joined expression looks like this

ApplyMask("(00) 00 000 000","0",Right("+44123456789",CountChar("(00) 00 000 000","0")) )
The final step is to concat the Prefix with the result from the above step to get our result

JL Engine solution step by step

The screen shots below provide the step by step detail, of how the solution is physically implemented in the JL Engine.

 1. Create a rule and define all the properties



 2. Create a Main procedure, and create the 8 steps as shown, thats all.



 3. Test the Rule in Business service simulator, or if you are a lucky customer that has SiebUnits on your project, you could write a declarative test case, to test your declarative rules engine.



The test results applet shows the correct output value for our challenge, with the test case passing in 32ms.

Conclusion

This new custom rules engine passes the EAI Phone challenge with flying colors, and manages to do it more nimbly, with less steps of declaration, thanks to its custom inbuilt functions, but is this enough to make it a superior solution than BRP? Both engines are built for different purposes, but share a lot of similiarities.

BRP is a speed demon, and was built for handling complex calculations, which just happened to come with a declarative engine that allows a project to banish casual scripting, but sadly it is not a universal module, and looks likely to be sidelined from future updates.

JL Engine was also designed to remove scripting, comes built with connectors to a custom application framework, it achieves speed by taking shortcuts and also provides a declarative interface for developers, but best of all it is openly extensible, allowing developers to build upon the gaps of BRP with custom requirements.

Want a real time instance monitor that shows step by step execution, condition determination and variable assignment. You got it, JL Engine comes with a rule audit history view to do just this. Want a visulizer that shows the rule composition in a graphical UI? No problem, JL Engine comes with this as well. Want a expression builder that allows developers to build rules faster? Yes Sir, we have that covered.

So how about some performance figures? In the next episode of the EAI Scriptless phone challenge. I will compare all the declarative solutions to this challenge, and provide performance metrics to determine which is the fastest and the best, so be prepared to be blown away.

1. XSLT using Xalan Engine
2. XSLT using Saxon Engine
3. BRP Engine
4. JL Engine

Note 1: While other solutions exist that simply strip away the phone format mask, the above script less solutions apply the format to the phone and have the flexibility to deal with the international prefix. 

Note 2: The JL Engine is not available commercially. The product has a limited audience, and is only available to selected customers.

SiebUnit - Build Inventory

This article is a continuation on SiebUnit - an xUnit implementation, and provides an inventory of the parts needed to construct a SiebUnit framework.

Like the first article, this is aimed at the Technical Architect, who understands the concept, and knows how to put the necessary pieces together to bring this idea to life.


Architecture



The architecture diagram allows us to visualize important concepts at a high level, and can be used to break up big jobs into more manageable pieces.


Rules Engine

You can replace Rules Engine with any Siebel interface that supports receiving Inputs and returning Output PropertySets. SiebUnits will also work against a standard invoked business service, or workflow.

The only caveat is that you cannot have context, that is, you must re-design your BS/WFs to decouple your logic from any specific Application context. This naturally suits the testing of a rules engine, external API such as ESB, internal APIs like custom business object libraries, and scripting utilities.


SiebUnit Framework

A SiebUnit framework can be composed of the following sub components

* Test Case Runner
* Test Case start up routines
* Test Case tear down routines (optional)
* Test case assertion
* Random data generator
* Expression language
* Expression language parser
* Expression Executor
* Expression Builder
* Test history and performance timing
* Script Library
* Business Object (BO) Library
* XML Parser
* SQL/IO Layer


Test Case Runner

This component reads the configuration data from the data store, loads all the test cases in memory, and runs each test case one by one. It records start, stop times, and logs the output, but does not make any determination on the test case result. Errors are captured, and any exceptions are suppressed, allowing the Test Case Runner to continue on until it completes all test cases.


Test Case Startup/TearDown

In order to test certain scenarios, prerequisite test data may need to be setup before the rules can be tested. This component constructs the initial test data before the test suite runs. Optionally, there can be a Tear Down component, which cleans up after all test cases.


Test Case Assertion

Assert is a computer science term used to ensure a condition is true/false to enforces application integrity. The assertion component performs the same role, it checks the outputs of each test case, and validates it against the expected result for that test case, logging the result to a history data store.


XML Parser

This component converts XML into a structured object and back. This can be used to send dynamic outbound messages, and validate inbound responses, for integration testing.

SQL/IO Layer

This component retrieves the related data from an entity for validation purposes. It is used by the Test Case Assertion component.


Random Data Generator

Even within predefined test boundaries, we can allow the generation of random data to simulate dynamic conditions.

Eg. Generate a bunch of expense activities of random type, and amount, and test it against a business rule for assignment or approval logic.

The random data generator can be used by the Setup component, or the individual test case to randomize inputs into a rule.


Expression Language

To make SiebUnits declarative, we need a way of allowing the developer to construct data, supply dynamic inputs, and validate the results of the test cases, without writing a line of code. This can be done via an Expression Language, similar to calculated field expressions in Siebel.


Expression Language Parser

This component is responsible for translating the above expressions into a form which is understandable by the Siebel eScript compiler or external engine, that will in-turn run the instructions.

The expression parser needs to differentiate between a literal and expression. This is done via 4 ways, as illustrated throughout Siebel.

1. Field Pre/Post Default

Expressions need to be prefixed with "Expr: " or a key word such as "System", "Field" etc. Anything else is considered a literal.

If you wanted to pre default another field via the square bracket notation "[Id]" this will actually result in a literal value

2. Calculated Field

A calculation is always expected to be an expression, unless it is surrounded by quotes. So the square bracket notation "[Id]" is treated as an expression in this context.

3. Field Type

This example can be seen in WFs in the Output argument of some steps. There is another field that indicates the type. Eg: Literal vs Expression.

4. Dot Notation

WFs also have another interesting expression, with the dot notation to reference child elements within property sets. This dosnt really fit into either of the above 3 categories. As it can easily be interpreted as a literal, and does not have any prefixes to indicate that it is an expression.

You have to make a call on which method you will use, and your expression parser has to recognise the above patterns if you mix the scenarios.

Eg 1. For an eScript implementation, the expression

"GetProfileAttr('Me.Id')"

Should translate this to an eScript call like this

TheApplication().GetProfileAttr("Me.Id")

The parser has to recognise that this is an expression with a literal argument.


Eg 2. The next expression provides a dynamic input.

"GetProfileAttr([&Property])"

This follows Siebels WF standard, of referencing WF properties via the ampersand prefix inside square bracket notation, requires a bit more work because you have to deal with the nesting of expressions.

This is where you can draw the line, and define styles for your expressions and have another expression to deal with that scenario

"GetProfileAttrByProperty('Property')"

Now the literal references a property that holds the value to this method. You will have to plan out your expression language in advance, and know how your parser will deal with each scenario.


Expression Executor

After you've translated the expression into the native language, it needs to be executed, and the result returned. The method that you execute the expression, will impact on the style of your expressions, and how complex your parser needs to be.

Consider implementing a short circuiting mechanism so that, if part of a condition expression is met, you can abort executing the rest of the expression.


Expression Builder

This component allows the developer to choose from a defined set of expressions, this aids in learning, reduces mistakes, and as well as documenting all the supported functions of SiebUnit. Ideally It has to integrate with the Siebel UI session, and apply the expression to the list/control.


Test History and Performance timing

This data is produced by the Assert component which validates the test case runners run history with the expected outputs, it also extracts performance timings for analysis.

Inputs and Outputs of the run are also included in the run history to help debugging. Having the results in the UI is consistent of the expectations of a declarative tool. Take note BRP engineers!

Test history and performance data can be transient, and the user can export the results, if a base line needs to be established.

Script Library and BO Library

It is important to differentiate between the above two components. A script library provides utilities, and prototypes on native objects, while a BO library provides business functions.

A SiebUnit library is tightly integrated with the script library for performing internal operations, and provides proxy functions for invoking the BO library to setup and perform test cases. When creating framework functions you will have to make conscious decisions in which library a function belongs to.


Unit Testing and Regression Testing

SiebUnit does not replace commercial regression testing suites. An important differentiation is that SiebUnits is designed to be used by developers for unit testing code/WFs before it is checked in, and to ensure application integrity is maintained before it reaches the testers.

SiebUnits are also more thorough, as only the developer could understand all the exception paths of a program. SiebUnits test technical functionality, while regression test tools test functionality.

Although SiebUnit can be used to regression test business rules, it does not test UI components. The developer is still expected to ensure that UI rules are unit tested. A badly configured link, can still bring the system down and while writing SiebUnits to create data, and check the data returned from the link could be a valid test case. It was not intended to micro manage every piece of individual configuration.

SiebUnits can offer a great sense of security for the developer, but poorly designed test cases, can also provide a false sense of security. This is normally due to poor test case coverage. Average developers will usually test the positive scenario, good developers test both positive and negative scenarios. SiebUnits require the developer to understand all the possible logic paths and design test cases to thoroughly cover off the scenarios that can result the program to fail.

Conclusion

There are numerous benefits to having SiebUnits on a project. The immediate return on investment, is that your testing period is reduced, and your application will be more robust, but the real payoff of really comes down the track, when you build highly complex systems, where one small change can break another part of the system. SiebUnits can provide your developers with confidence to make that change, without costly regression testing. SiebUnits will keep your Application, and also your sanity in check.

xUnits is a proven concept, and is a staple of any modern development platform. SiebUnit provides an evolution path, so that your developers no longer need to manually unit test. The world has JUnit , jsUnit, CUnit, OCUnit, PHPUnit, PyUnit, SUnit and now we can add SiebUnit to the list.

SiebUnit - an xUnit implementation

Introduction

Over a year ago, I presented a concept of xUnits in Siebel and how they could be used. Because it was only a concept, it was missing implementation details, so there was some doubts to whether Test driven development would work in Siebel, where code is meant to be restricted to fringe cases.

At that time, I ported some code from a back end Java project that I was working on, to automate Siebel interface verification. The idea was to pickup XML templates from a file system, insert randomize data, send it to the ESB, and validate the results.

It was used for several releases, reducing a days worth of effort to verify 50 interface interactions, to about 5 minutes. With the JUnits in place, they could be used to verify an integrated environment instantly on demand, instead of employing highly paid professionals to perform repetitive regression testing.

The tool was written in Java, didnt have a UI, it had access to the eApps SSO hashes, which meant that an evil developer could use it to log onto a server environment, and impersonate anyone they wanted. It was more of a regression testing tool than a unit test tool, and being written in Java, it was inaccessible to most of the Siebel Team.

In the spirit of a true Siebel developer, I thought a real implementation of xUnits in Siebel had to be scriptless.

So "SiebUnit" was designed to be just that, a fully declarative unit testing framework for Siebel developers.

This framework also happens to plug into a rules engine like BRP, OPA, or it could be run against a collection of business services/workflows, as long as you can pass in an Input and get an Output property set, the "SiebUnit" framework handles the rest.

This idea was sold to a Client, who immediately picked it up as a way to get developers to unit test, improve build quality, and reduce dependence on testers, and provide a structured development process.

This article and its followup, takes a step further, providing architectural and implementation concepts. It is aimed at the Technical Architect, who can grasp high level concepts, fill in the low level implementation, possibly innovate on this idea, and introduce SiebUnits into your Siebel project.


What is SiebUnit

If you had to sell the concept of xUnits in Siebel, this slide should sum it up.



This screenshot shows a SiebUnit implementation that was built for a Client.



Features

Notification System for test results

Uses a custom notification system, written in a client side library, to add persistent messages to the current view. The messages can be dismissed, by clicking the X button.


Design and Run Test Cases from the UI

Test Cases are configured, executed and debugged all within a standard Siebel UI. Debugging the rules itself, depend on the capability of the rules engine. Eg. BRP can only be debugged via log files, WFs can be debugged using the instance monitor.


Export/Import test Cases

Allow easy export and import of hierarchical test configuration data between different environments.


Trace Toggling

Toggles developer tracing, for performance testing of rules


Dynamic test data

Uses XML templates, and proxy functions to the BO Library to generate unique test data. Random data can be generated and provided on inputs, or overridden in the case of XML templates.


Expression Builder

A helper utility designed for the developer to construct the test cases declaratively. This is built using HTML, which integrates with the Siebel session.


Other

SiebUnits comes with pre built internal test cases to validate your eScript engine, and profiles ST objects vs non ST objects.

SiebUnits can be configured to run recursively to load test an environment


Case Study - Custom Rules Engine

SiebUnits was used on a project to ensure the integrity of a Rules Engine.

The design of the custom rules engine started off in small components, followed by unit testing, further build and some more unit testing. The components were then integrated, followed by another round of unit testing.

As the design got exponentially more complex, the integration of all these components, made it impractical to regression test all the exception paths, after every change.

SiebUnits was originally built with integration to BRP. So for this project, it was modified to work with this new engine.

A collection of SiebUnits was built to test the following aspects.

Declarative IF conditions
Declarative loops
Declarative procedures
Expression Translation
Expression Results
Business Service Invocations
Property Assignment
Cancel Propagation
Error Messages
Math Operations
Rule inheritance
PropertySet Interactions


Some further internal test cases were also designed to validate the behaviour of the eScript engine. This ensures that if Siebel changes the eScript engine, these internal SiebUnits will pick up on the expected outputs of dependent core functions, and allow the root cause to be addressed.

Once the SiebUnits were designed, and configured, they were used to repeatedly validate the Rules Engine after every change, to ensure previously built functionality still functioned. Changes often broke other unexpected parts of the engine, due to the tight integration and dependency between components, but with the SiebUnits in place, the report of failed test cases helped to quickly pinpoint the cause.

Towards the end of the build, a critical defect was discovered with the eScript engine, that corrupts a core object of the rules engine. This happens during random runs of the test suite, but it was easily reproducible using the load runs.

The problem required a re-design of the core object, which unfortunately touches every function in the engine. Since the new object had a different interface to the old object, it required a re-design of most of the interactions around this object as well.

The affected parts of the program was identified, and a fix was implemented in two hours. The SiebUnits test suite was run afterwards to ensure that the rules engine passed all the test cases. This provided a QA stamp on the product, and was similiar to having a team of regression testers on hand to validate your work at will.

The collection of SiebUnits also allowed load testing of the engine in a real environment. During these load runs, server resources can be monitored to ensure that they run within acceptable standards and allow capacity planning based on expected usage.

It would have been much more difficult if not impossible, to complete such a complex build without SiebUnits in place, and the regression testing and maintenance effort would have been an ongoing burden.


Intermission

Do you have BRP, OPA or a collection of Business Services that you would like to keep in check? The next article will look at the architecture of SiebUnits, and all the components that need to come together to form the framework of SiebUnit.

Note: The term Rules Engine is used broadly in this article. Even though BRP stands for Business Rule Processor, it is actually a declarative eScript replacement engine. OPA is more suited to the term for a Rules Processor, as it takes a bunch of inputs, makes a determination and returns the result. However the Rules Engine interface of Inputs/Outputs is what makes it suited to SiebUnits.

View the next article here

ABS Framework - Business Object Library

The ABS Business Object library is probably the most important feature of ABS, from a benefits realization point of view, and heres why.

ABS can make your project atleast 2x more efficient.

The ABS framework provides a global class of functions that allows developers to write code that is leaner, faster, use less memory and require less time and resources than traditional build methods.

That’s a really big promise, and we should be sceptical when someone makes a claim like that, but in this article I’ll look at how ABS achieves this, and how it can be quantified.

[Abstraction Layer]

The goal of the ABS Business Object library is to build on top of the existing Siebel BO functions, and provide the developer with tools to achieve complex functionality with just a few lines of code.

It’s difficult to talk about abstract concepts, without an example, so heres a scenario that all developers can relate to.

If you wanted to query an Account and get back the primary Address related to this account and return the state and city in an array, how many lines of code would it take?

Here’s the traditional way of writing this logic in standard Siebel eScript.

function GetAccountInfo() {
var aAddressInfo = [];

var oBO_Account = TheApplication().GetBusObject("Account");//1
var oBC_Account = oBO_Account.GetBusComp("Account");//2
var oBC_Address;//3

try {
oBC_Account.ClearToQuery();//4
oBC_Account.SetViewMode(AllView);//5
oBC_Account.ActivateField("City");//6
oBC_Account.ActivateField("State");//7
oBC_Account.SetSearchSpec("Id","1-ABC");//8
oBC_Account.ExecuteQuery(ForwardOnly);//9

if (oBC_Account.FirstRecord()) {//10
oBC_Address = oBO_Account.GetMVGBusComp("Address");//11

if (oBC_Address.FirstRecord()) {//12
aAddressInfo[0] = oBC_Address.GetFieldValue("City");//13
aAddressInfo[1] = oBC_Address.GetFieldValue("State");//14
} //15
}
else {
throw "No Address found in the Account";
}

}
}
catch(e) {
throw (e);
}
finally {
}

return aAddressInfo;
}


That’s over 15 lines of actual logic, not including line spacing, and error handling. So how many lines does it take using the ABS BO Library? Just one.

Here’s how we would write the same logic using ABS.

function GetAccountInfo() {
var bErrRaised=false,aAddressInfo;

try {

aAddressInfo = TheAccount.GetChildFieldValueWithId(“1-ABC”,TheAccount.oBCChild_Address,["City","State"],true))[0];//1

}
catch(e)
throw (e);
}
finally {
if (!bErrRaised) return aAddressInfo;
}
}

Let me explain what is happening here.



















 Legend
TheAccount  This is a predefined ABS BO object that is always available in the Application.

Take it for granted that this exists, and you can use it anywhere, and in the chapter on the ABS Universal Object, I’ll explain how this object comes into existence.
TheAccount.oBCChild_Address  This is another predefined ABS BO object.
GetChildFieldValueWithId  This is a method of the ABS BO Object, which is inherited by all BO instances such as TheAccount. It allows the developer to query a child BC using a row id as a search spec, and return a set of values as an array.


[Inputs]



sId = Row Id

hbChildHandler: Child BC instance

hbChildField: Fields to return

bRaiseErrIfNoRecChild: throw error if not found

sSortSpecChild: Child BC Sort Spec


[Re-Use]

The above example highlights one of the main principles around ABS: Re-use.

Why do we have to write

GetBusObject(), GetBusComp(), ClearToQuery(), ActivateFields(), SetViewMode(), SetSearchExpr(),ExecuteQuery(),FirstRecord()

in every function, in every business component, applet or business service in the application, hundreds of time, over and over again?

We can start to imagine how this kind of code writing can lead to application bloat, adding to application maintenance, reducing the upgradability of a project, and obscuring business logic with un-necessary repetition of technical artifacts.

ABS encapsulates the above logic in a single function, that can be used anywhere in the application.

Writing less code, will definitely add to your efficiency.

[Upgradability]

One of the main arguments for using declarative configuration methods is that it can be easily upgraded. The reasoning is that if all your logic is configured rather than scripted, then the upgrade would be painless and carefree.

Well, that is really not the case. In 7.5 you could have WFs that have steps that were free standing with no connecting lines, 7.5 also allowed WF designers to have multiple start points. This is illegal in 7.7 onwards, and during the upgrade you will have to fix all your WFs.

Experienced people will see that WFs are not foolproof in upgrades, they are just as likely to be obsolete as scripted solutions.

The argument against using traditional eScript, is when you perform an upgrade, Siebel does not touch your script, so every piece of code has to be retested.

How does ABS differ?

The highly modular design of ABS makes it more favourable to upgrades.

For example.

If Siebel decided to make ActivateFields deprecated, and forced developers to use ActivateMultipleFields instead.

You’ll only need to find that one place in the ABS framework, and replace it with the new method. Of course, the unit testing has to be thorough, but once it has been unit tested in this function, the entire application will benefit.

Upgrades can never done by the push of a button, but if you given the choice of upgrading an application with a hoarde of WFs with hundreds of individually defined steps, a massively scripted spaghetti system, or a highly modular but concise scripted system, which one would you choose?

[Improve Efficiency]

Let’s revisit that promise again.

“ABS can make your project atleast 2x more efficient.

…write code that is leaner, faster, use less memory and require less time and resources than traditional build methods. “


Write faster code

If we had two developers with EQUAL knowledge and experience, 1 is skilled in eScript and the other is skilled in ABS.

Which developer would have the advantage? I think the answer is obvious. The eScript developer would have to write 15 times more code than the ABS developer.

That is an unholy advantage. Not only would the ABS developer be faster, but would also have 15x less code to troubleshoot if there was something wrong.

Leaner code

15 lines vs 1 line, need I say more?

The code is not only leaner, but also more representative of the business logic and more readable at the same time.

Use less memory

Business Objects and Business Components are only ever instantiated once, and re-used throughout the lifetime of the user session. This will be explained in more detail in a section for the ABS Universal Object.

Less time/resources

The tangible benefit that the ABS BO library brings to projects is obvious. To run and maintain a large scale project will require less time and resources. This puts project managers in a better bargaining position.

Theoretically, you would have to hire 15 eScript developers to do the same amount of work of 1 master ABS developer.

But realistically, you do not need to hire master ABS developers, you only need to get Siebel developers who have a solid foundation in scripting (preferably ECMA), and who are open minded to the ABS philosophy.

While you cannot hire just anyone that walks in from the street, you’ll only need a few very good people, rather than a brigade of good people.

[Conclusion]

The use of ABS is not widespread, and part of the reason for this is that it needs to be implemented as a total solution, and not in bits and pieces. And the most suitable implementations are the green field projects, or projects which are still young.

Currently there is only one Systems Integrator that is implementing ABS solutions on a grand scale, and the benchmark hasn’t been made public.

A 2x improvement in efficiency sounds controversial, but if we base our conclusion of other ECMA script frameworks, such as jQuery, Scriptaculous and Prototype. We know that scripting frameworks do deliver on efficiency, as well as improving code readability, and application maintenance.

We saw that by using ABS, build and testing times were cut by a factor of 15. Saying that ABS delivers 2x more efficiency is quite conservative, but keeps it realistic.

Code bloat is detrimental to the long term maintenance of the application, and the main culprit is eScript, so its interesting to see a framework like ABS tackle this problem head on with a very radical tactic:

Using ECMA Script to reduce eScript.

Implementing a concise, highly modular, Siebel framework, using ECMA script to lay the foundation, is not something that your average scripting expert can achieve.

People that can pull off this sort of feat, are your architect of architects.

ABS Framework - Prototype Library

[What is a Prototype?]

Using the prototype object is common in web development circles, but it is foreign to most experienced Siebel professionals.

This is the definition of “prototype” object according to Siebel Help
    An object prototype lets you specify a set of default values for an object. When an object property that has not been assigned a value is accessed, the prototype is consulted. If such a property exists in the prototype, its value is used for the object property.

    Object prototypes are useful to be sure that every instance of an object use the same default values and that these instances conserve the amount of memory needed to run a script. Then every instance of the object use the same function instead of each using its own copy of it.


That is quite an abstract description, and although it tries to explain the concept using a generic example, it still feels very disconnected.

In layman terms, using the prototype statement allows developers to add properties and methods to all instances of custom and pre-built objects in eScript/browser script (excluding Siebel Objects).

    So how do we use prototype to solve real world Siebel problems?

[ABS Prototypes]

The ABS framework includes prototypes to reduce the daily scripting chores for Siebel professionals. In this article we look at the some of the most interesting prototypes in ABS, and see how it can make our lives easier and more fun.

The ideas for these prototypes comes from years of experience and tideous hours of work to encapsulate the common routines that Siebel configurators and Integration people can share in one common library.

Array.IsIn

There are a lot of times when we want to compare the current active view, to a list of predetermined views, before performing some action.

Normally we have to write code like this to achieve it

var sViewName = TheApplication().ActiveViewName();

If (sViewName == “View1” || sViewName == “View2” || sViewName == “View3”) {

}

ABS provides us with IsIn() to achieve this same functionality in a more elegant manner.

var aViewName = [“View1”,“View2”,“View3”];
if (aViewName.IsIn(TheApplication().ActiveViewName()) {
}


This function returns a Boolean, indicating whether a value exists or not, but also returns an additional property that points to the index of the matched value.

Date.ToISO

ToISO() is useful for formatting dates to ISO format. This is commonly used to convert dates, so it can be easily sorted alphabetically.

var oDate = new Date(2000,1,1);
oDate.ToISO() = "20000101"


Date.ToDB

ToDB() allows the developer to get the current date and do a setfieldvalue without doing messy conversions.

Date.ToDB() //This returns the current date in MM/DD/YYYY format for setfieldvalue


Date.Compare
Compare() is a really powerful shorthand method of comparing dates or datetime.

A common business requirement is to ensure the currently selected date is greater than the created date, but less than a future date.

Heres how we would normally perform this operation.

//Convert to date object
oCreated = new Date("12/31/1999");
oFutureDate = new Date("1/1/2001");
oCurrentDate = new Date("1/1/2000");

If (oCurrentDate.GetTimeStamp() > oCreated.GetTimeStamp() && oCurrentDate.GetTimeStamp() < oFutureDate. GetTimeStamp ())


ABS does it in one line

Date.Compare("1/1/2000",">","12/31/1999","<","1/1/2001") = true


Heres a couple more examples of how it can be used to quickly compare dates.

//Created for date comparison of date1>date2 or date1>date2>date3
//Example 1:
Date.Compare("12/31/1999",">","1/1/2000") = false

//Example 2:
Date.Compare("12/31/1999","<","1/1/2000",">","") = true
//for the case of open date


Array.PSToStr

PSToStr () converts a Siebel PropertySet to a string for debugging. This is a very common situation for developers to find themselves in.

But it’s the implementation of this function as part of the Array object, which makes it unique. This allows it to be executed from Global scope, anywhere in the application, without using business service script libraries.


var oPS = TheApplication().NewPropertySet();

oPS.SetProperty(“A”,”1”);
[oPS].PSToStr(); //This returns a string representation of the PS


[Reducing code in your application]

Date.Compare() is a really good example of how prototypes can reduce code in your application. This prototype allows a developer to use date strings, to compare dates, without having to manually convert them to date objects.

Converting strings to dates is integral to comparing Dates correctly in Siebel, so instead of having these date conversion routines littered across the application in BCs, Applets and BSs, ABS prototypes this functionality to the Date Object.

ABS Prototypes is a feature purely for coders, but even if you don’t write a lot of script, whatever script you write will be very compact.

What if your project has massive amounts of scripting? We all know these projects exist.

Some projects start off with the noble principle of “exhausting” every declarative means of configuration, before turning to script, but this usually dosnt last, and there are a few common reasons for this.

    * Project cannot say “No” to funky ideas from business
    * Tight deadlines
    * In-experienced developers


Its likely to be a combination, if not all of the above. Its natural that people pick up scripting quicker than using WF, a junior can come in fresh from high school, know a little bit (or a lot) of Javascript, copy a bit of code from here and there, and with a small amount of effort, get a working solution.

Using prototype allows projects to build your own code library, these functions are bound to the standard ECMA objects, and can be re-used across the application without instantiation.

[Reduce memory usage]

I know you didn’t pay much attention to Siebel’s definition of prototype, but its interesting to revisit it (a part of it).

    Object prototypes are useful to be sure that every instance of an object use the same default values and that these instances conserve the amount of memory needed to run a script. Then every instance of the object use the same function instead of each using its own copy of it.


At this stage, we have a little more context of what prototype can do for our projects, and the Siebel definition seems to be more comprehensible.

But for the project managers, and executives out there, the prototype objects ensure that functions are instantiated once and shared across the application, and by taking advantage of prototypes, a project can reduce the memory usage in the application.

With a robust suite of prototypes at the core of your application, you have a more scalable and manageable solution at hand.

[Conclusion]

The ABS Prototype feature, dosnt make people better scripters, but it does reduce the amount of scripting in the application, and provides a repository of common routines, that in-experienced (and experienced) developers can rely on, without re-inventing the wheel.

Benefits of using Prototypes


    1) Reduce the size and clutter in the repository
    2) Reduce redundant code writing
    3) Standardize implementation of common routines
    4) Easier code maintenance
    5) Speed and streamline up code development
    6) Reduce memory usage


Pre-requisites


Prototypes should be implemented by developers with a solid understanding of ECMA script (not eScript). Improper implementation of prototypes can lead to memory leaks and defective behaviour across your application.

This also applies to projects that currently have ABS, and want to enhance the prototype library.

Projects need to ensure that there is a clear owner for the prototype library, and this person or group, have exclusive controls to these library functions, and makes changes on behalf of everyone. This ensures a layer of quality control, and a consistent coding standard is maintained for the project.

ABS Framework - Logging & Tracing Module

Log files are the bread and butter of every developer, so every once in a while it is interesting to meet a developer who has never used Trace() before. So how do these people troubleshoot Siebel? Using debugger, amazing!

Although debugging is useful, it’s not always reliable. In complex scenarios, when you have logic across different objects, the debugger just dies, or jumps around erratically. In these cases it’s just more efficient to dump out all the information to a file and analyse what went wrong.

From the most mundane, to the most critical problem, having informative logs is crucial to solving problems quickly.

For this purpose Siebel provides us with a basic tool.

    TheApplication().Trace()

Good old Trace, what this does is allow us to route key information to a log file during script execution. This same log file is used by the Siebel application for its application logging. So the first frustration developers get is all the information they are trying to dump out, is being buried by all the Siebel internal object allocation and destruction information.

Trace() is used by developers during the build phase and is inserted when a problem is found or in key areas for unit testing, and it is removed before the code is migrated into the test environments and ultimately in production.

Trace()
does the job, and gives developers the basic means to troubleshoot problems. Its function is not flashy, and it’s a little better than popping up an alert box, but we all learn to live with it pretty quickly.

[Paradigm Shift]


With that perspective, anyone that looks at ABS business code, will notice one major contrast to the above logging paradigm.

The ABS tracing module is used as part of the program design, rather than to troubleshoot problems as they arise.

In standard code, we normally trace the start, end and catch of each function, and put lots of comments to explain the code.

In ABS code, tracing is done at the start, end, catch, and is put at key decision points in the program, and this is left in the code, even when it is migrated into production.

The advantage of doing this is two fold.

1. The code is self documenting
    By including descriptions of the program logic in business speak, anyone can turn on tracing, perform the function, and the system will spool the program logic to a log for analysis.

2. On demand function execution information
    Since the tracing code is part of the program design, a developer can go into any environment, look at the ABS logs, or re-run the function, and have access to the details of the function execution details.

Similar to the way Workflow provides a debug mode for developers to see step and variable information of the runtime action. This ABS design feature closes the gap on the advantage that declarative configurations once had.

This is quite powerful, because it allows the developer to debug the problem live in an environment with real data, which can’t always be created on a local environment.

[Logging Levels]

Conforming to the Siebel logging standard, the ABS logging module has 5 levels of logging detail. Setting this value controls the amount of detail that is spooled to the log file. By default it is set to 3, but this can be overridden by the developer in the system preference or in the code.



[ABS Logging & Tracing components ]

    1. MSG object
    2. LOG object
    3. EXCEP object


[MSG Object]

One of the key design principles around the ABS System is re-use. Messages can be categorised and parameterised and re-used across the application.

To display errors or log error messages, we need to create our own message category in the Application, ABS encourages this over hard coding custom errors on the fly.

The ABS System creates a category called ABS Defined Messages.

Instead of using numbers and defined ranges for their use, the ABS Logging module uses identifiers with the following naming standard.



The ABS Defined Messages is only used for the ABS framework for standard error messages, to display more specific error messages, we need to create our own custom message category, and follow the above standard to define our messages.

Although it is not enforced, it is encouraged to follow this standard, because it makes managing error messages, and looking up their relationship to the functional areas easier.

[LOG Object]

This object defines how a function is logged, and does the actual job of tracing the messages to a file.

ABS Log files are generated in the following format, but can be changed according to individual user preferences.































 LOG object Methods
 Begin  Tell the logging module that a new function has begun
 Step  Used to record key milestones in the script and document the process
 StepResult  Used to document the result of a milestone
 End  Tell the the logging module that the function ended without any errors
 Error  Logs the error object



The basic construct must be built like this, for the proper logging and log format indenting to happen.



[EXCEP Object]


In a standard application, when an error is raised, the developer can choose to override this error, to provide a different message that is more suited to the context, or bubble it up the the parent function, but local variables are lost when the function loses scope.

In ABS, when an error occurs, the EXCEP object is thrown, the relevant parameters are captured and stored in the EXCEP object, and the original message is discarded after it is logged, the EXCEP object is then bubbled up in the function chain.

When the error bubbles back to the base function, the parameters are written out along with the error message.

This is very interesting, because it allows us to display a meaningful error message with full context of the parameters at the point when the error occurred.

[Example Error Log]



This is the function calling path from the above example.
    BO_Service -> LOV_Service -> LOV_GetValue -> LOV_GetAnyField -> BO_Query -> SYS_Assert

The error is raised at SYS_Assert, but it has no useful information at this point, so the error is thrown up the chain to BO_Query.

BO_Query is the real reason why the exception was raised, the arguments captured by this function are important, and will not be available once the function finishes, so it is bubbled up further along the function chain, with arguments captured from previous functions, until it reaches BO_Service

BO_Service is where the message is finally displayed. The cause of the error is due to a BC query that returned no results, but you want to override this, and display something more meaningful to the end user, but still log the actual technical reason for the developer.

The result is an informative message that contains details gathered from various parts of the function calling chain.

[Consolidated Server Logs]

The ABS Logging module solves a very fundamental problem with Siebel server logs. If you are in a multi-server environment and have 10 Siebel application servers, each will have its own set of application logs. So what happens when there is an error? We need to find out which server we were logged onto!

Why do we have to hunt for our logs?

ABS allows us to save logs from all our application servers in one central location.


Developers and environment guys a like, will really appreciate this feature. The design of ABS is an evolution of the way Siebel manages its logs.

[Self Documentation]

Traditional documentation and diagrams can be quickly outdated, especially if the rules are complex, and change every release. Script should be easy to read and understandable, the ABS system takes this idea further, and uses the logging objects to document the system.

With the correct usage of these functions, the ABS logging module will allow anyone to go into the system, and generate 100% accurate documentation of the system in business speak.

[Pro-active Error handling]

During the build and test phase, a developer builds a piece of functionality, does the unit testing, and migrates the code for testing. The tester will look at the build and raise defects that will event get re-assigned back to the developer. This process can take days.

The ABS system takes a more proactive approach, when ever an error is raised, it uses a SR style ticketing system, and assigns the error, based on its category to the correct position, in real time. This way a developer can get all the details of an exception, even before the tester has even realised there was an error.

[Conclusion]

The ABS logging & Tracing module provides the following features

    1. Detailed contextual error messages
    2. Step execution and function parameter information
    3. Self documentation mechanism
    4. Problem ticket assignment
    5. Consolidated server logs
    6. Works in WF and Script


Developers will appreciate the level of detail provided by the ABS system.

    1. Point of error
    2. Function calling path
    3. Function inputs and outputs
    4. Name, Value, and Type of arguments used in function

ABS can generate a lot of logs, so its important to keep your eye on disk space. The good news is the design of ABS allows all logs to be saved to one central place, so you only have to monitor one location, unfortunately, we cannot do the same for Siebel logs.

The developer shouldn't have to hunt around the logs for an error, then wonder where it exactly originated, and what were the conditions that caused it to error. All this information should be captured at the point of error.

If we reflect for a moment and compare the ABS logging module to the standard Siebel solution, the TheApplication().Trace() feels somehow inadequate, its like trying to fight fire with a water pistol.

The ABS logging and Tracing modules provides advanced tools for projects to quickly identify problems, turn around a solution and focus on the delivery.

Introduction to the ABS Framework

When considering the solution design for a business requirement, we usually have a few configuration options at our disposal.

One of the cardinal decisions we make, is wether we choose to build our solution using WF or Script, there is a lot of emphasis put on this decision by the Siebel community.

In my opinion, wether we use WF or Script isnt important, what is important, is the result. The ultimate goal should be to ensure that the build, is maintainable, scalable, and upgradable.

In the comming series, and i'm going to look at the ABS framework, and see wether it meets the above goals.

What is the ABS framework?

The ABS framework is a custom Siebel framework that embodies the following principles

  1. Maintainable
  2. Resuable
  3. Scalable

and it is written in eScript!

Its important to note that, the ABS framework is more than just a library of functions, it is an alternative Siebel framework, with features beyond scripting.

What are the features of the ABS framework?

  1. Centralization of all business logic
  2. Reduces scripting
  3. Reduces development time and implementation
  4. Superior Logging and Tracing
  5. Ready made eScript library
  6. Abstraction of Siebel Objects

There is no public documentation on the ABS framework, and what we currently know, are mainly from word of mouth or blogs across the Internet. There are still a lot of questions and speculation about the ABS Framework.

With courtesy from the ATI framework (which is extended from ABS), i have a unique opportunity to explore the framework from the source code level.

In the next series of articles, i will endeavour to reveal its features and discover the answers to all the questions we've been asking.

An interview with the creator of the ABS Framework



I've recently had the pleasure and good fortune, of meeting the creator of the Siebel ABS eScript Framework and what follows will be an interesting journey.

This is a continuation of my first article on the implementation of an eScript Framework.

If you dont know what the ABS Framework is then, this article wont mean much, but for those are keanly following this topic, it will make us re-think the way we develop Siebel and also open a lot of doors that we didnt know existed.

In my first article, i discussed an implementation of a Siebel framework, that solves Mike M. Lin's dilenma of creating a custom Siebel class with proper method chaining.

In the closing of the first article, i hinted on another implementation of the framework, which avoids the horrible problem of attaching methods to the Object constructor.

But my opportunistic meeting with the creator of the ABS Framework (who wishes to remain anonymous), has confirmed this theory, that attaching custom methods to the Object constructor is not the way to go.

I've also discovered, that while our implementation mechanism of the eScript class method chaining is different, our ideas for laying the foundations for a framework and the results are the same.

Our initial conversation covered the architectural design of a framework and the different implementation methods, scripting standards, and the absolute need for such a framework.

We are currently evaluating this framework, and also looking at some potential changes for Siebel 8, but thats as far as we got.

The first and only place, that we've heard about this framework is from the Siebel Unleashed forum, and there is little if any knowledge of this framework, by Oracle or any other independant source, but in conclusion to this article, i can definitely confirm that the ABS Framework exists.

In the next article, i will provide some more information on our eScript framework, so stay tuned...


A Siebel eScript framework



In my inaugural post, i'll attempt to tackle, probably one of the most talked about Siebel challenges around.

If you dont know what the ABS (ATI) Framework is, i highly recommend you have a look at the articles on Siebel Unleashed. One of the key features that it provides, is access to a global Class that provides an abstraction layer on top of eScript which allows you to do things such as:

TheApp.Get("Contact").GetFieldValueWithId("12323","Last Name");

This would normally take atleast 10 lines of code to query the BO, BC, get a value from application and add error handling, but the above abstraction does it in 1 line.

In this article, i'll provide a technique to implement a custom object with method chaining, but the million dollar question is how do we build a eScript Framework in Siebel.

Mike M. Lin showed us how to make a custom object available globally in Siebel, his solution was to reference the Application object and attach it to the Object constructor, like below.


Object.prototype.TheApp = this;

What this does is make TheApp available in every script without declaration. At this stage all we've done is made TheApplication() = TheApp.

Mike M. Lin also offers a custom BC method called GetFieldValueUpperCase(), which is applied to the Object constructor, the side effect of attaching custom functions to the Object constructor and calling Siebel methods on non Siebel objects or objects where the method dosnt exist, is you'll get an error.

The GetFieldValueUpperCase() method can be used on BC based objects such as GetBusComp

var oBC=TheApp.ActiveBusObject("Contact").GetBusComp("Contact");
//retrieve recordset
oBC.GetFieldValueUpperCase("Name");

But the same method is also available on every other object in the scripting engine.

var sDummy = "testing";
sDummy.GetFieldValueUpperCase("Name"); //Error

The problem is obvious, the complete solution needs to implement hirerachical method chaining in a class like fashion. This will allow us control what methods are available on what parent object. Since we do not know the Siebel constructors, we will do the next best thing, which is create our own Siebel class, which is what i think the creators of the ABS (ATI) framework have done.

The following code is a protoype that i've created, to emulate the ABS (ATI) Framework.


Object.prototype.TheApp = function () {
return {

Get: function ( sBC ) {

/***********************************************************************/
// Component Name : JLE eScript Class
// Use : TheApp.Get(BC Name)
// .QueryWithSearchExpr(Search Expression)
// .GetFieldValueWithId(Id, Field)
// : TheApp.debug(String)
// Date Author
// 20/02/2009 Jason Le
/************************************************************************/
TheApp.BC = sBC;
return {
QueryWithSearchExpr: function ( sSS ) {
var oBC = TheApplication().ActiveBusObject().GetBusComp( TheApp.BC );
oBC.ClearToQuery();
oBC.SetViewMode( AllView );
oBC.SetSearchExpr( sSS );
oBC.ExecuteQuery( ForwardOnly );
if ( oBC.FirstRecord() )
return oBC;
},
GetFieldValueWithId: function ( sId, sFldName ) {
var oBC = TheApplication().ActiveBusObject().GetBusComp( TheApp.BC );
oBC.ClearToQuery();
oBC.ActivateField( sFldName );
oBC.SetViewMode( AllView );
oBC.SetSearchSpec( "Id", sId );
oBC.ExecuteQuery( ForwardOnly );
if ( oBC.FirstRecord() )
return oBC.GetFieldValue ( sFldName );
}
}
},
debug : function ( text ) {
var fp = Clib.fopen("C:\\debug.txt", "a");
Clib.fputs(text + "\n", fp);
Clib.fclose(fp);
}
}
}();

TheApp.prototype.BC = "";


This class contains 4 methods
Get
Theoretically this would accept upto two parameters, the name of the BO and the BC, if only one parameter is passed in, we use the Active BO.

QueryWithSearchExpr
This method is chained of Get and returns a BC instance with the provided search expression.

GetFieldValueWithId
This method is chained of Get and returns a field value, with the provided row id.

debug
log to file function.

Examples of use.

var BC = TheApp.Get("Contact").QueryWithSearchExpr("[Id]='1-ABCD'");
TheApp.debug ( BC.GetFieldValue("Id") );

var Field = TheApp.Get("Contact").GetFieldValueWithId("1-ABCD", "Name");
TheApp.debug ( Field );


If you look carefully, you notice that the custom object acts as an interface to the Application() methods instead of referencing this on every Object. This allows us to avoid those errors, when we were using the non hierarchical methods.

A lot of complexity has been left out of this code to make it easier to read, it has been hard coded to work on the ActiveBusObject, there is no error handling, there is no consideration into preventing memory leaks, this point is especially important because if improperly implemented, either nothing will work, or when you go into production, it will bring your environment down.

With that disclaimer aside, this idea of creating a custom object structure allows us to be very creative and create our own eScript Framework on top of Siebel.



I know there are architects out there thinking, are you crazy to attach something to the Object constructor? I'll look into a possible concession with the framework, and offer an alternative implementation.

To find out what this means, stay tuned..