Client
Project Name
eScripting Standards
Version 1.0
Date: 1 October 2001
Document Identification
Client Name / British American Tobacco AustralasiaProject Name
Document Name / Configuration Standards Phase 3.doc
Version / Version 1.0
Issue Date / 31 August 2001
eServices Phase 3 ProjectPage 1
Siebel Enabled Process Model – Accounts Mega Process
Table of Contents
1Introduction......
2Overview......
2.1Use of Script......
2.1.1Configurators......
2.1.2EAI Developers......
2.2Compiling......
3Variables......
3.1Declaring......
3.2Naming......
4Constants......
4.1Siebel literal constants......
4.2User defined constants......
5Functions......
5.1Usage......
5.2Naming......
5.3Returning Objects......
5.4PreInvokeMethod......
6Layout......
7Comments......
7.1Functions......
7.2Code blocks (within functions)......
8Memory Management......
9Thin Client Limitations......
9.1Use of User Interface Methods......
9.2Use of “Active” Methods......
9.3Message Boxes......
9.4Applet Scripts......
10Global Variables......
11Profile Attributes......
12Additional Guidelines......
12.1Activating Fields......
12.2ExecuteQuery(): Use of......
12.2.1Cursor Mode for ExecuteQuery()......
12.2.2Check for existence of Records......
12.2.3Use of Base Components in ExecuteQuery()......
12.3Existence of Objects - Presumed ParentHood & miscellaneous Orphans......
12.3.1BusComp.ParentBusComp()......
12.3.2Business Object Name Check......
12.4Tracing......
13Appendix – Example Code......
13.1Example 2 (more complex)......
1Introduction
This document outlines the guidelines and recommended standards for [Project Name] eScripting. It is not intended to be a step by step instruction manual on how to script.
It is intended to ensure that any eScripting performed is accurate, easy to read and maintainable. While intended for eScript, the reasons documented hereon is also applicable to use for VB script, taking into account the syntax and construction differences (eg, try…catch versus On Error Goto).
This document is intended for members of the Configuration and EAI teams only.
Note: Examples given in this document may not necessarily be case correct due to Word's auto-corrects
2Overview
2.1Use of Script
2.1.1Configurators
The use of script should be a last resort only if the one of the following does not satisfy the requirements:
Predefault/postdefault on fields
Business Component user properties
Business Component field user properties
Calculated fields
Links etc
2.1.2EAI Developers
The use of script should be minimized and limited to the following:
Manipulation of transaction responses to generate the required hierarchies
Setting of user keys for integration components
Queries to obtain Siebel keys for data
Generation of requests
Where possible, script should not be used for:
Mapping response fields to storage fields
Setting field values due to an update in another field
Predefaults/postdefaults
Translations (eg display value to code).
The above should be achieved through configuration of the relevant EAI business components, unless it cannot be achieved simply through this method.
2.2Compiling
Before checking in projects with modified script:
Ensure that scripts compile by using the Debug->Check Syntax menu option
Ensure that scripts are tested by running the application. If an error in the script prevents a user from accessing a view, it should not be checked in.
3Variables
3.1Declaring
All variables used in the script should be declared as the first code block after the script comments. This avoids scope problems and not declaring variables when you though you had!
The exception is the error object (usually e) in a try…catch statement.
3.2Naming
The following naming convention should be followed for the various variable types:
string - strXXXX
integer – iXXXX
array – aXXXX
date - dXXXX
boolean - bXXX
property set– psXXX
business component– bcXXX
business object – boXXX
business service – bsXXX
application object - app
where XXX is the name you give your variable.
Variable names should be meaningful, ie, do not use a, temp, myvar etc unless it makes sense to. The idea is that you should not have to decipher variables as you read the code.
Capitalise the first letter of each word in your variable - eg strStreetName . It makes it that much easier to read.
i, j, k may be used but should be reserved as counters (eg in for loops)
e should be reserved for the try…catch statements.
Examples: iIndex, bcAcct, bcServ, psInputs; psAcctList, strAccNbr
Example 1 (not within guidelines)
var a, b;
var bcPhoneNbr;
// … other code
a = "Smith";
b = "Jones";
bcPhoneNbr = "94590778"
If (condition)
{
var psContact;
psContact = TheApplication().NewPropertySet();
psContact.SetType(“Contact”);
psContact.SetProperty(“FirstName”, b);
psContact.SetProperty(“LastName”, a);
}
else
{
psContact.SetProperty("FullName", b + a)
}
// … other code
Example 2 (within guidelines)
var strFirstName, strLastName;
var strPhoneNbr;
var psContact;
// … other code
strLastName = "Smith";
strFirstName = "Jones";
psContact = TheApplication().NewPropertySet();
If (condition)
{
psContact.SetType(“Contact”);
psContact.SetProperty(“FirstName”, strFirstName);
psContact.SetProperty(“LastName”, strLastName);
}
else
{
psContact.SetProperty("FullName", strFirstName + " " + strLastName)
}
// … other code
4Constants
Literal constants should be used:
where a literal constant is available
where a constant is frequently used
It removes the need to remember what a number stands for!
4.1Siebel literal constants
The following are supplied by Siebel and should be utilised:
CursorMode (for ExecuteQuery() calls on business component objects)
ForwardBackward (0), ForwardOnly(1)
ViewMode (for SetViewMode() calls on the business component objects)
SalesRepView (0), ManagerView(1), PersonalView(2), AllView (3), NoneSetView (4)
NewRecordLocation (for NewRecord() calls on the business component objects)
NewBefore (0), NewAfter(1), NewBeforeCopy (2), NewAfterCopy (3)
4.2User defined constants
Where a constant value is used in multiple places within a module (eg business component or business service), the value should be defined as a literal constant for that module for easy maintenance. User defined constants may be defined in the declarations section as follows:
var ACCT_TYPE_CD_BILL = "Billing";
var ACCT_TYPE_CD_CUST = "Customer";
The use of CAPS is to distinguish the constant from other variables and function calls.
Example 1 (not within guidelines)
// some code
bcAcc.ClearToQuery();
bcAcc.SetViewMode(3);
bcAcc.SetSearchSpec("Integration Id", strAccIntegId);
bcAcc.ExecuteQuery(0);
// some code
Example 2 (within guidelines)
// some code
bcAcc.ClearToQuery();
bcAcc.SetViewMode(AllView);
bcAcc.SetSearchSpec("Integration Id", strAccIntegId);
bcAcc.ExecuteQuery(ForwardBackward);
// some code
5Functions
5.1Usage
Functions should be used to contain logical groupings of script to enable reuse and make your script more readable.
There is a 16K limit to the size of scripts which makes the use of functions imperative!
5.2Naming
The function name should be like a short description for the function, eg MICAToSiebelDate, GetAccountDetails, UpdateAccountDetails, PrepAccountForUpsert,
Capitalise the first letter of each word in the function name
5.3Returning Objects
Functions should only return values of string or number types.
Functions should NOT return object types:
The variable referencing the object to be returned cannot be freed
The calling function might not be assigning the return value, which may cause the object to be allocated and not free-able.
5.4PreInvokeMethod
Minimal script should be written in the PreInvokeMethod event scripts of Business Components and Business Services. Each method should call its own function.
6Layout
Appropriate use of white space should be used to break up blocks of code.
Indentation should be done using the tab key
There should be no code flushed against the left side (it makes the code very difficult to read)
Use line spacing appropriately to break up blocks of code
A line of script should not exceed 80 characters where possible. This is approximately one screen width in tools, where the explorer pane is also visible on the left.
Braces {} should line up with the statement to which they belong. A new line should follow the brace. Eg:
if (condition)
{
statement;
statement;
for (i = 0; i < psInput.GetChildCount(); i++)
{
statement;
statement;
}
…
}
Braces should be used even to contain single statements for consistency and tidiness. Eg:
If (condition)
{
strName = “asdfasef”;
}
else
{
strName = “asdfljk”;
}
Statements which run over more than 1 line should be continued with at least 1 tab indentation on the next line (preferably 2) so that it’s clear it’s a continuation. Eg:
strName = “asd;lfkj ;lkjsdfjk;skdj f;lkjasd f;l;js” + iCount +
“asdfjsldfkjsldfj”
while (i == 0
& (psInputs.GetChildCount() – iNumAssocs + 4) > 0))
{
…
}
Example 1 (not within guidelines)
if (bMoreRec)
{
while (i < iNumChild) {
i++;
strName = bcAcc.GetFieldValue("Name");
}
if (strName != "")
{
//… some statement
}
}
Example 2 (within guidelines)
if (bMoreRec)
{
while (i < iNumChild)
{
i++;
strName = bcAcc.GetFieldValue("Name");
}
if (strName != "")
{
//… some statement
}
}
7Comments
ALL CODE SHOULD BE COMMENTED
Ideally, between 1/5 to 1/3 of lines in your scripts should be comments. Comments should be sufficient to enable someone else to understand your code and also be able to maintain it (eg for debug purposes). It may also help you remember what you did 4 weeks or even a week later!!!
7.1Functions
All functions should be commented with the information in the table below. An example follows the table.
Purpose / Purpose of the function, including a high level statement of the algorithm if appropriate. Eg:Contact to Account associations will be created by:
-identifying existing associations not in the list provided and deleting them
-adding associations in the list that do not already exist
Describe also any relevant preconditions and reference any global variables or profile attributes referenced (note documentation requirements also for globals and profile attributes)
In some cases, this information can be obtained directly from the design documentation.
Inputs / Describe each variable in the input arguments
Outputs / Describe values returned in the function. Also the setting of any properties on input property sets or global variables to indicate the status of the function.
Author / Original author of the script (not the designer)
Date / Date script first created
Change history / Used only for major script changes are after a release, or if functionality has changed substantially from the original design.
function FindChild(psPropSet, strType)
{
/**********************************************************************
* FIND CHILD PROPERTY SET
*
* Purpose:
* Gets the index of the child property set of type specified by
*strType from the property set provided. Searches the first level only.
*
* Inputs:
*psPropSet - the property set to search
* strType - type of the property set to retrieve
*
* Outputs:
* returns the index of the property set required. -1 otherwise.
*
* Author: Nat Chor (eS)
* Date: 16/06/2001
*
* Change History:
*dd/mm/yy - Name (eS)
*
***********************************************************************/
…
…
}
7.2Code blocks (within functions)
Each logical code block should be commented to detail the purpose of the code block, any special conditions, and a high level description of the algorithm if it is considered an explanation is required (eg, if there are complex conditional statements, unusual use of constructs, a particular dependency on data or other code modules, or complex logic). Please see the example code appendix for samples.
8Memory Management
All objects variables which are declared and assigned within a function should be set to null before returning from the function. It is preferred that this be done at the end of the script for clarity. Objects may be:
returned by a function
instantiated using the new constructor
assigned from another object.
No global variables should be assigned to an objectAs there is no point in time in which they can be explicitly freed.
The following are objects that should be freed. Note the importance of naming conventions for variables, as it provides you with an idea of the variables which you will need to free.
Objects / ExampleBusiness Objects / var boAcc;
boAcc = TheApplication().GetBusObject(...);
// some processing
boAcc = null;
Business Components / var bcAcc;
bcAcc = boAcc.GetBusComp();
OR (in a Business Component script)
bcAcc = this.BusObject().GetBusComp(“X”);
// some processing
bcAcc = null;
Business Services / var bsServ;
bsServ = TheApplication().GetBusService(…);
// some processing
bsServ = null;
Property Sets / var psIn;
psIn = TheApplication().NewPropertySet();
OR
psIn = Inputs.GetChild(i);
// some processing
psIn = null;
Arrays / var aNames;
aNames = new Array();
// some processing
aNames = null;
Date / var dFromDate;
var dNextDate;
dFromDate = new Date();
dNextDate = dFromDate;
// some processing
dFromDate = null;
dNextDate = null;
Object which were not declared within the function/script need not and should not be freed. This applies to objects such as Input, Output and this. Freeing these objects may cause you to lose your data.
It should be the practice to clobber all objects before exiting/returning from a function. The convention is not to call the return statement directly from code, but to set a return value which is picked up at the end of the function, and use a goto label. Outer try…catch statements should also be used to handle system exceptions. This is to ensure that the clean up code is executed regardless of whether an error occurred.
Example 1: (not within guidelines)
var psIn;
var psOut;
var iRetVal;
psIn = TheApplication().NewPropertySet
psOut = TheApplication().NewPropertySet;
// Some processing
if (psOut.GetProperty(“ErrCode”) =! SUCCESS)
{
return (CancelOperation)
}
else
{
// some processing
}
psIn = null;
psOut = null;
return (ContinueOperation)
}
Example 2: (within guidelines)
var psIn;
var psOut;
var iRetVal;
iRetVal = ContinueOperation;
try
{
psIn = TheApplication().NewPropertySet
psOut = TheApplication().NewPropertySet;
// Some processing
if (psOut.GetProperty(“ErrCode”) =! SUCCESS)
{
// Log error
iRetVal = CancelOperation;
goto ExitFunctionName;
}
else
{
// More processing
}
}
catch (e)
{
TheApplication().Trace(Clib.rsprintf("BComp CUT Billing " +
Adjustment:Exception: %s\n", e.toString()));
}
finally
{
ExitFunctionName:// labels and try/catches are the only thing which
// should be flush
// against the margin.
// This is the only time you should use a goto
// label. They are to be avoided at all costs at // any other times
// Clean up
// ------
psIn = null;
psOut = null;
return(iRetVal);
}
}
9Thin Client Limitations
9.1Use of User Interface Methods
Generally, any script method which interacts with the user interface is not available for use in thin client. These include:
GotoView
FindControl
9.2Use of “Active” Methods
Methods prefixed by “Active” are not available. This includes:
ActiveView
ActiveBusObject (alternative: this.BusObject() when accessed from business component script)
ActiveBusComp (alternative: “this” reference when accessed from business component script)
9.3Message Boxes
You can’t use them (ie TheApplication().MsgBox())
9.4Applet Scripts
There should be no script on the Applet as this will not execute in thin client. Script associated to a control (eg button) on an applet should be located in the Service_PreInvokeMethod event script of the appropriate business component.
10Global Variables
Global variables should not be used unless absolutely necessary. All variables should be passed as function arguments.
Variables global within a Business Component or Business Service should follow the same naming conventions as normal variables, but prefixed with an "m".
Application global variables should have the following naming convention: gstr[YourVariableName]
Eg: gstrCurrentAccountNumber (no spaces)
Each global variable should be listed and its use specified in the usage matrix of the following file: \\V525c-d07\data\GROUPS\SYSARCH\EService\Architecture\Administration\eS TT Mappings eService Global Vars v0.2.xls
Efforts should be made to reuse existing variables before creating new ones.
Note: global variables are only available as strings.
11Profile Attributes
Profile attributes should be used with care an not be abused.
Profile attributes should have the following naming convention: eS [Your Profile attrib name] eg. eS Current Account Number (spaces in use)
Each profile attribute should be listed and its use specified in the usage matrix of the following file: \\V525c-d07\data\GROUPS\SYSARCH\EService\Architecture\Administration\eS TT Mappings eService Profile Attribs v0.2.xls
Efforts should be made to reuse existing attributes before creating new ones.
12Additional Guidelines
12.1Activating Fields
- Required before doing GetFieldValue and SetFieldValue on a bus comp.
- Fields should be activated before calling the ExecuteQuery() method.
- Is not necessary with:
- Fields where GetFieldValue will not be called (eg used purely for the SearchSpec)
- System fields (eg Id, Created etc)
- Fields with their LinkSpec property set to TRUE
- Fields where Force Active is TRUE
- Fields activated with BusComp.ActviateField(strFldName) are active for the lifetime of the bus comp object variable or until deactivated by calling DeactivateFields().
12.2TheApplication(): Use of
TheApplication() is a function, which introduces an overhead in performance each time it is called. While it may not be noticeable if used once or twice in a script, the cumulative effects over a transaction will add up. The following is suggested to advert any performance impact in a script where TheApplication() is called frequently (eg, more than 4 times):
- Declare a variable app to represent the application
- Set this to the return value of TheApplication()
- Use app as the reference for future calls to application methods
Example:
var app
app = TheApplication()
app.GetSharedGlobal(“gstrEnvironmentType”);
app.Trace(“Bservice eS Account::GetAccount – Start script”)
// more code
app = null;
12.3ExecuteQuery(): Use of
12.3.1Cursor Mode for ExecuteQuery()
- ExecuteQuery() should be performed with the "ForwardOnly" parameter, unless there is a specific need for "ForwardBackward". It cause your query to take twice as long.
- ForwardOnly: Used if you do not need to go backwards through the records returned
- ForwardBackward: Used if you need to go backwards and forwards through your recordset, eg:
- FirstRecord() is used more than once
- PreviousRecord() is used
- FirstRecord() is us after a call to any of NextRecord(), LastRecord() or PreviousRecord();
Example 1 (not within guidelines)
// some code
bcAcc.ExecuteQuery(ForwardBackward);
if (bcAcc.FirstRecord())
{
// do your stuff
while (bcAcc.NextRecord())
{
// do more stuff
}
}
// no more code on bcAcc
Example 2 (within guidelines)
// some code
bcAcc.ExecuteQuery(ForwardOnly);
if (bcAcc.FirstRecord())
{
// do your stuff
while (bcAcc.NextRecord())
{
// do more stuff
}
}
// no more code on bcAcc
12.3.2Check for existence of Records
- A check should be done to determine if a record had been returned after an ExecuteQuery by calling one of the following: FirstRecord(), NextRecord(), LastRecord()
Example 1 (not within guidelines)
// some code
bcAcc.ExecuteQuery(ForwardOnly);
strName = bcAcc.GetFieldValue("Name");
// some code
Example 2 (within guidelines)
// some code
bcAcc.ExecuteQuery(ForwardOnly);
if (bcAcc.FirstRecord())
{
strName = bcAcc.GetFieldValue("Name");
// do your thing
}
else
{
bcAcc.NewRecord(NewAfter);
// more code
}
// some code
12.3.3Use of Base Components in ExecuteQuery()
- Use of execute query on any Business Component should be communicated and verified with an EAI developer before implementation. This is to avoid transactions being inadvertently executed. There is a series of Business Components which mirror the normal Business Components in use for EAI which have the scripts stripped out. Use of these components for query purposes is preferable. Eg. Instead of Account, use eS EAI Account.
12.4Existence of Objects - Presumed ParentHood & miscellaneous Orphans
- A check should be made to ensure that the objects are not null and/or are the ones that you wanted when retrieving associated objects.
12.4.1BusComp.ParentBusComp()
Example 1 (not within guidelines)
// … some code on business component scripts
bcParent = this.ParentBusComp();
strAccNbr = bcParent.GetFieldValue("Account Number");
// … more code
Example 2 (within guidelines)
// … some code on business component scripts
bcParent = this.ParentBusComp();
if (bcParent != null & bcParent.Name() == "Account)