Thursday, March 12, 2009

Extending eScript Objects

There seemed to be a lot of interest in the post on Siebel Unleashed about the ABS (ATI) Framework for eScript (unrelated to Siebel's Appointment Booking System), which is some company's proprietary tool set used to perform repetitive tasks in eScript - some simple and some complex. A few examples given were: searching for the existence of a particular value in an array; accessing TheApplication() object; getting the field values of a record for which we know the Id. And doing those things in a consistent manner and using fewer keystrokes. What struck me is how well they integrated their framework with Siebel and core eScript objects.

I really believe in tool sets, and I'd like to see some Siebel hackers out there expand on the idea. How this tool set was built is not really obvious, so I'd thought I'd take a stab at it. Respecting the fact that the ATI Framework is proprietary, I won't give a whole lot of detail reverse-engineering the complex API calls I saw in the posts. However, I will show some basic techniques you can use to build your own framework using some simple examples. It would help to know a bit about objects and properties in JavaScript.

To keep the post relatively short, I'm not going to give any examples to validate that this stuff actually works. I'll leave that to you, because it's best to figure some things out yourself. If you're having problems, just know that I have successfully tested these concepts.

Is this value in the array?

Sometimes you have to search an array to see if a particular value exists. Nothing a little "for" loop can't take care of. But if you need to do this with any kind of frequency, why rewrite it every time? Also, what if a developer introduces a bug while trying to reimplement it? Write it once, make it work, and reuse it. Not only will you reduce your exposure to programming errors, but it will make your programs more succinct, and much easier to comprehend.

You can always add an application method that takes a reference to the array and the value you're searching for and returns a true or false, but I always wondered why this method wasn't part of the Array object to begin with. Let's go ahead and make it part of the Array object by modifying the prototype property to include a custom function. I put this in the "(declarations)" section of my application server script (which I chose because it's the first script I know of that's executed when the application starts):

Array.prototype.Exists = function (value)
{
  for (var i = this.length - 1; i >= 0; i--)
    if (this[i] == value) return true;
  return false;
}

Once this sets up you'll be able to see if the value "5 of spades" exists in your aCardDeck array: aCardDeck.Exists("5 of spades");

Accessing the Application Object

Ever get tired of typing TheApplication() every time you need to access an application method? Well those on the ATI Framework don't. It looks like they've reduced the application reference to some sort of global variable "TheApp", accessible from any object.

If I had a business component and wanted to make "TheApp" available from anywhere within that object, I could add a line like "var TheApp = TheApplication();" to the "(declarations)" section of the business component. But that means I'd have to add that line to every business component, which makes me angry. You won't like me when I'm angry. So how can we avoid the maintenance hassle, and me turning into a big green monster?

What if we update the prototype of the business component object to include "TheApp"? That sounds like a good idea. Well unfortunately I haven't been able to figure out what the business component object/constructor is actually called. I'll do the next best thing, which is to add "TheApp" to all custom objects. The business component object must be derived from the Object class. So here's another addition to the application "(declarations)":

Object.prototype.TheApp = this;

Remember, that "this" is the application object, since we're doing this from the application "(declarations)". This approach has the added benefit of enabling "TheApp" reference from all Siebel objects including business services, applets, and, yes, the application object itself. It surprised me that the application object was able to access "TheApp", since the prototype was modified after the application was already instantiated.

Adding a Custom Business Component Method

Let's say, for some reason, you constantly find the need to get business component field values in uppercase characters only. Well here's what I added to the application "(declarations)" this time:

Object.prototype.GetFieldValueUpperCase = function (sFieldName)
{
  return this.GetFieldValue (sFieldName).toUpperCase ();
}

Now if you have some bc "bcFoo", you can get the value for field "Bar" in uppercase characters by doing something like, "bcFoo.GetFieldValueUpperCase("Bar");" When this is called from a business component object, then all the references to "this" refer to that business component.

The unwanted side-effect here is that this method is enabled on all custom objects because we updated the prototype of the Object class. Since GetFieldValue() is only supported on business components, this will fail on any other object. So, if anyone finds the object/constructor names for any Siebel objects, please let that cat out of the bag. In any case,

I think you guys have had enough. Don't forget to let us all know if you find the object/constructor names for any Siebel objects. And if they're any new discoveries or breakthroughs out there, please comment about it. But for now, happy hacking!