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
GetTheoretically 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.
QueryWithSearchExprThis method is chained of
Get and returns a BC instance with the provided search expression.
GetFieldValueWithIdThis method is chained of
Get and returns a field value, with the provided row id.
debuglog 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..