Showing posts with label siebel-tech. Show all posts
Showing posts with label siebel-tech. Show all posts

05 February 2011

Siebel: Prototype in eScript - Part 3

In earlier posts, we have seen using prototypes to extend OOB objects. In other posts we have also dealt with user defined objects and scripts libraries. Time for seeing all three in action you say? And I hear you, we shall see how user defined object can be prototyped, and used across the application.
Problem: I need a function to lookup the description of a LOV provided its type and value
Solution: We address the problem in two steps:
  1. Define a user object and make sure it is available for the session. One of the common ways of doing this is in Application object
  2. Use the custom object to define a prototype for useful function(s) - in our case 'LookupDesc'
 Now, the how..
  • Define a variable in the application script, for example: Siebel Life Sciences
[Application: Siebel Life Sciences, (declarations)]
var MyApp;
And, call a business service where MyApp is initialized. This is just to keep the application object, it works just fine within the application itself.
[Application: Siebel Life Sciences, Method: Application_Start]
function Application_Start (CommandLine)
{
 var bsStarter = TheApplication().GetService("COG Test Proto");
 bsStarter.Init();
}

  • Write the custom business service 'COG Test Proto'
[Service: COG Test Proto, Method: Init]
 function Init ()
 {
    TheApplication().MyApp = new MyAppFun;
    MyAppFun.prototype.LookupDesc = LookupDescFun;
 }

[Service: COG Test Proto, Method: MyAppFun]

       function MyAppFun()
       {
 // this is a dummy, but funny function.
       }


  [Service: COG Test Proto, Method: MyAppFun]
function LookupDescFun (Type, Value)
 {
 try {
  var sDesc = "";
  var boLOV = TheApplication().GetBusObject("List Of Values");
  var bcLOV = boLOV.GetBusComp("List Of Values");
  with (bcLOV) {
     ClearToQuery();
     SetViewMode(AllView);
     ActivateField("Description");
     SetSearchExpr("[Type]='" + Type + "' AND [Value] = '" + Value + "'");
     ExecuteQuery(ForwardOnly);
     if (FirstRecord()) sDesc = GetFieldValue("Description");
  } //with
  return(sDesc);
 }
 catch(e) {
  throw(e);
 }
 finally {
  bcLOV = null;
  boLOV = null;
 }
 }


 That's about it, now MyApp is ready to have some fun. Again, a quick service to test how things work.

[Service: COG Test Proto Call, Method: Service_PreInvokeMethod]
 function Service_PreInvokeMethod (MethodName, Inputs, Outputs)
 {
    Outputs.SetProperty("out", TheApplication().MyApp.LookupDesc("blah", "blah"));
 }

A bit of theory on how it works:
  1. MyApp is defined as a variable in Application, the same is initialized in a business service. It does not matter what the function [MyAppFun] contains, we will not be using that anyway
  2. The prototype LookupDesc is defined as an extension of MyAppFun. Any object based on MyAppFun will have access to the LookupDesc functionality
  3. We invoke LookupDesc as an extension of the variable in the application object. There are other blogs out there who just use TheApplication = MyApp, but that practice is not encouraged as I understand
  4. When TheApplication().MyApp.LookupDesc is invoked, Siebel will look for the LookupDesc function for MyApp object. Since the functionality does not exist OOB, the prototype is consulted and in turn LookupDescFun function is executed.

If you are thinking this is an overkill, you may be right if this is all you want to do. Keep in mind that this coding practice will be more scalable, and ensures reusability.

02 February 2011

Siebel: Prototype in eScript - Part 2

The last example in prototypes dealt with extending a OOB data type, but that extension was done within the business service itself. Although the prototype can be defined only once and used multiple times, it is not really demonstrated well since the entire thing is handled within the same code. Here, let me take an opportunity to show how the prototype definition itself can be handled elsewhere.

Problem
Check whether the given string is a valid email address

Solution
Define the prototype to extend the OOB string object, and use it as many times as needed. To achieve this we define the prototype in the Application object.

Go to "Server Scripts" of 'Siebel Life Sciences' or similar, and define prototype.

(declarations)

String.prototype.IsEmail = CheckValidEmail;

Add a function 'CheckValidEmail' to the same application object.

function CheckValidEmail()

{

var rEmailPat = /^\w+[\w-\.]*\@\w+((-\w+)(\w*))\.[a-z]{2,3}$/;

return rEmailPat.test(this);

}

That's about it! Any string can now be tested for a valid email. We will quickly build a test function to demonstrate how this is used:

Service: COG Test Email

Method: Service_PreInvokeMethod

function Service_PreInvokeMethod (MethodName, Inputs, Outputs)

{

var sEmail = Inputs.GetProperty("Email");

Outputs.SetProperty("Valid", sEmail.IsEmail());

return (CancelOperation);

}

When you run this in the simulator, this should either return a 'true' or 'false' value depending on whether the supplied string is a valid email address. Now, a bit about how it works.

  1. First we define the prototype for the data type string with the statement String.prototype.IsEmail = CheckValidEmail'. This statement is executed when the application starts up.
  2. The above prototype points to a custom function 'CheckValidEmail'. This function uses a simple regular expression to test the validity of the entered string. It returns a 'true' when the string has the specified regex pattern, false otherwise
  3. None of the above has any effect until we actually invoke the 'IsEmail' function. When this function is used against the string object, Siebel checks the prototype since no such function exists OOB
  4. Return value from the function denotes whether the string 'sEmail' is a valid email address

Watch this space for one more example!

31 January 2011

Siebel: Script Libraries

Siebel 8 (or ST engine to be more specific) has a elegant way of calling business service methods. Script libraries provide the ability to call functions on a business service directly, no more is the need for building property sets and setting the parameters!

If you have not already used script libraries, do take a look. The reduced coding implies lesser mistakes, debugging time and easier maintenance! The simple demo below illustrates the usage.

Step 1:
Create the target business service 'COG Test Script Lib'. A custom function 'Echo' is defined here.

Service_PreInvokeMethod:

function Service_PreInvokeMethod (MethodName, Inputs, Outputs)

{

return (CancelOperation);

}

Echo:
function Echo (MyString)

{

return "Echoed: " + MyString;

}



Step 2:
Create the caller service 'COG Test Script Lib Call'. There is only one method here - 'Service_PreInvokeMethod', and the following code has to be input:

function Service_PreInvokeMethod (MethodName, Inputs, Outputs) {

var bsTest = TheApplication().GetService("COG Test Script Lib");

Outputs.SetProperty("Output", bsTest.Echo("abc"));

bsTest = null;

return (CancelOperation);

}



Compare this to the approach in earlier versions. In most probability you will be coding something like:

function Service_PreInvokeMethod (MethodName, Inputs, Outputs)

{

var bsTest = TheApplication().GetService("COG Test Script Lib");

var psIn = TheApplication().NewPropertySet();

var psOut = TheApplication().NewPropertySet();

psIn.SetProperty("MyString", "abc");

bsTest.InvokeMethod(psIn, psOut);

Outputs.SetProperty("Output", psOut.GetProperty("ReturnString"));

psOut = null;

psIn = null;

bsTest = null;

return (CancelOperation);

}


And, don't forget to add a line or two in the target service 'COG Test Script Lib' to set required properties in the output propertyset. Now, a simple 'bsTest.Echo("abc")' does the job. Isn't life simpler?

24 January 2011

Siebel: Prototype in eScript

I had mentioned about using prototypes in one of the previous posts, here's a drilldown into how things work.
Tucked away in a remote corner in the eScript reference of the Siebel Bookshelf is a single paragraph referring to prototypes. Common to javascript developers, prototype is not something that we bother about too often. Prototypes provide a highly reusable way of extending out of the box objects, with an optimal memory usage as a bonus.

How do we use Prototypes?
The best way to understand will be through an example. Let us consider a problem where we need to add x days to the given date and get the next working day (!= Saturday or Sunday).
We go about this problem by extending the Date object to support a new functionality - add x days and retrieve the next working day. For simplicity sake we keep the definition of prototype and the actual call together, however they may be located in different objects as well.
To demo the prototype define custom business service 'COG Get Working Day' in Siebel Tools or Client. Paste the following code in relevant sections:
(declarations)


Date.prototype.AddDaysToGetWrkDay = AddDaysToGetWrkDay;

AddDaysToGetWrkDay


function AddDaysToGetWrkDay(iDays, Outputs)

{

var iDateNew; var iOneDay = 24 * 60 * 60 * 1000; // day in milliseconds -
(hrs/day * min * sec * ms)
this.setMilliseconds(iDays * iOneDay);
if
(this.getDay() == 0 this.getDay() == 6) { // if sunday or saturday

this.AddDaysToGetWrkDay(1); // add one more day and check whether that falls
on working day

}

return this;

}

Service_PreInvokeMethod
function Service_PreInvokeMethod (MethodName, Inputs, Outputs)
{
try {
var dSomeDate = new Date("1/28/2011");
dSomeDate.AddDaysToGetWrkDay(1);
Outputs.SetProperty("New Date", dSomeDate);
return (CancelOperation);
}
catch(e){
throw(e);
}
finally {
dSomeDate = null;
}
}


When executed through simulator (or a call from placed from another service), the service returns the next working day - in the above example 31-Jan-2011. Read on to find out how.


Code Explanation

  1. 'Date.prototype.AddDaysToGetWrkDay = AddDaysToGetWrkDay' is the statement that tells the execution engine that there is a new prototype for Date object, and the extended functionality is provided by the function (or object) called 'AddDaysToGetWrkDay'. This is not synonymous with calling a function since there is no actual execution at this point. It is equivalent to a declaration.
  2. Next, define the function 'AddDaysToGetWrkDay'. This will act on the provided date object, which is referenced using 'this'. All it does is to add the given number of days to the date, check whether the new date falls on a Saturday or Sunday, continue adding more days if that is the case, and return the final date. Recursion is used to keep on adding days until it is not required.
  3. 'Service_PreInvokeMethod' just calls the extended function 'AddDaysToGetWrkDay' against the date object. When the actual call is made, the scripting engine looks at the Date object itself to check whether such a method is present, and then consults the prototype. Since such a prototype exists and points to a function, the function is executed to return the result

Note that the prototype itself may be defined only once, and the functionality is available thereon. Though this example is simple at its best, it does demonstrate how prototypes can be used to extend the objects.

Conclusion

Keep in mind the following:

  • Prototypes share the same memory space. Multiple invocations do not mean multiple copies
  • Prototypes can also be added later. Dynamic invocation can mean that you don't need to do everything in one place and at once
  • A prototype can also be extended further. For example, I can very well define another which says 'AddDaysToGetWrkDay.prototype.ExcludeDay' to selectively exclude certain days. For example, myDate.AddDaysToGetWrkDay(21).ExcludeDay("Tuesday") can return the working day 21 days from the given date, but which is not a Tuesday
  • From the above point you can observe that the methods can be executed in a 'chained' manner, which gives us a scalable solution that is easy to maintain (remember my OO reference in an earlier post?)
  • Use prototypes for reusable functions, that is when they yield better results

So, how do you want to use prototypes in your application?

17 January 2011

Siebel: Custom Functions for TheApplication

If you want to reuse code in Siebel, one of the common practices is to put it away in the business service and invoke those methods. This method, though is invaluable for complex operations, will become a painful process for simple things. When I say painful, it applies in some measure for both developers and the execution engine, reasons outlined below:
  1. Additional business service objects have to be created during execution, this may put some overhead in terms of performance (business service caching kept aside for now)
  2. Invoking most of the business services out there involves creation of property sets and calling them in a "proper" way. With the increased lines of code comes the increased complexity
  3. Developers have to "know" about the business service. This is a big problem in the longer term since code again gets littered everywhere inspite of the same functionality in a service
    There is a way to solve some of the above issues for simple reusable code (at least partially) - custom methods on TheApplication object. This uses a simple fact - all functions written in the application object will be available in any entity and method. Let us illustrate this with an example.

Problem: I need to get the description of a specified LOV. Though developers swear by LookupValue (and other Lookup) functions, there is little one can do about the 30 (or 50) char limit imposed by the data model. It is common to use Description (or some such field) for this purpose, but the code reuse is limited.

Solution: Write a LookupDesc function in the application object. Just edit the 'Siebel Life Sciences' (or any application) that is being used by your object manager. Create a new function called 'LookupDesc' and paste this code:

function LookupDesc(Type, Value)
{
try {
var sDesc = "";
var boLOV = TheApplication().GetBusObject("List Of Values");
var bcLOV = boLOV.GetBusComp("List Of Values");
with (bcLOV) {
ClearToQuery();
SetViewMode(AllView);
ActivateField("Description");
SetSearchExpr("[Type]='" + Type + "' AND [Value] = '" + Value + "'");
ExecuteQuery(ForwardOnly);
if (FirstRecord()) sDesc = GetFieldValue("Description");
} //with
return(sDesc);
}
catch(e) {
throw(e);
}
finally {
bcLOV = null;
boLOV = null;
}
}

Now, invoking the above function is by using a single line in applet, bc or a business service -

TheApplication().LookupDesc("MY_TYPE", "My Value")

This is also available in ScriptAssist against TheApplication, to make others aware of this function ofcourse!
A note of caution though - don't overdo this. I would recommend keeping the code here simple and tight, and to those functions where lot of reuse is foreseen.

30 December 2010

Siebel: User Defined Objects

Ever missed all the OOP goodness in Siebel? Although not used frequently, user defined objects provide you with some degree of control with hiding complexities in scripting. No, this will not help you attain OO nirvana - but you can start doing things with the custom objects and prototyping (another post for another day) to:

  • Hide complexity
  • Provide scalability
  • Save memory while doing the above

Here’s a simple example that demonstrates use of user-defined objects. To test, you simply copy the code in a new client business service and you are all set.
First the Service_PreInvoke method:

function Service_PreInvokeMethod (MethodName, Inputs, Outputs)
{
var qryBC;

qryBC = new GetRecord("Contact", "Contact", "[Id] = '0-1'", "First Name", "Last Name");
Outputs.SetProperty("First Name", qryBC.Values[3]);

Outputs.SetProperty("Last Name", qryBC.Values[4]);

return (CancelOperation);

qryBC = null;
}

Next comes the constructor:

function GetRecord ()
{
try {
var arrValue = new Array();
var iCount;

if (arguments.length < 4) TheApplication().RaiseErrorText("I need minimum four arguments - BO name, BC
name, SearchExpr and at least one field name.");

var bo = TheApplication().GetBusObject(arguments[0]);
var bc = bo.GetBusComp(arguments[1]);
with (bc){
ClearToQuery();
SetViewMode(AllView);

SetSearchExpr(arguments[2]);
for (iCount = 3; iCount < arguments.length; iCount++){
ActivateField(arguments[iCount]);
}
ExecuteQuery(ForwardOnly);
}

if (bc.FirstRecord()) {
for (iCount = 3; iCount < arguments.length; iCount++){
arrValue[iCount] = bc.GetFieldValue(arguments[iCount]);
}
}
this.Values = arrValue;
} // try

catch(e){
throw(e);
}

finally{
arrValue = null;
bc = null;
bo = null;
}
}

Now, the explanation:
Purpose:

Provide ability to query any given BO / BC and retrieve the specified field values

How did we do that:

First, we create an object called “qryBC”, which becomes instance of a class “GetRecord” when the constructor “GetRecord()” is executed. Since this is the very first exposure to the class/object concept, we are letting the constructor do all the work rather than splitting it up. At this time we also pass the arguments to the object, whereby the constructor will query and return you the results. For simplicity in further processing, we return an array with the query results. Note the use of ‘this’ in the constructor and the reference to the set values when retrieving results in PreInvoke method.

Never understood why OO beats procedural programming you say? You need to depend your friend Google to find out what you missed.(cross posted elsewhere)

27 December 2010

Siebel: Importing data from files

I am back after a not-so-brief hiatus, and am back hopefully for good :). Here I am with yet another utility - this time something that will help you to import data from files into Siebel, with zero coding required from your end. ‘COG File Import Service’ as it is known, will hopefully simplify your life a bit.

Contrary to popular (and let me add, buggy) excel macros / VB COM programs that are available to load data to Siebel, this is a business service that can be imported to Tools / Client. But at the same time it does not offer as much flexibility, given below are a few things that make this tool stand apart.

Why another tool?
File import is nothing new to Siebel developers. But why use another tool when there are dime-a-dozen you say? Thus goes the story:

  • The first thing that hits you - most of the tools to load Siebel data have inconsistent interfaces, and may require some amount of ‘getting-used-to’
  • External objects or platforms are required to actually see what is going on, and hopefully to change the behavior. For example, you need Excel or Visual Basic software, or have a dependency on Windows platform to execute the code. And all that can be done, provided you understand what has been written there
  • Customers might have their own restrictions in connecting to production systems using third party software and utilities

The Mechanism


COG Import Service is just a business service that can be applied to Siebel v7.5+, but has only been tested with 7.7 and 8.1. The service works with CSV/delimited files and has two distinct ways to handle them:

  1. Simple Update - This is just a wrapper to the OOB CSV reader service, with a couple of enhancements thrown in
  2. Update - A more sophisticated updater, which can do a few more things than what CSV reader can do

The steps involved in both methods are simple:

  1. Read file (all at once)
  2. Map fields to provided content
  3. Use a data map, if specified
  4. Update

Where they differ is in the way they process files.



When to use which method?


.. Simple Update

  • Uses the 'CSV Reader Business Service', and hence needs an integration object (IO) to be available for the input data
  • When the processing is simple and there is no need for processing more than one component/entity (in other words, entity and its children) at one time
  • Processing should be fast
  • Any errors should roll-back all transactions

.. Update

  • Can be used with or without involving IO
  • Delimited with be comma or something else
  • Process entity and one child with one operation


How to Use?


Import the attached XML into Siebel Tools and compile to SRF, or imported into the Client (Site Map > Business Service Administration). Parameters to the service specify the parameters that are needed for a successful run. The file formats/structure has been documented in the service itself.



License


None, you can use it or throw it away. Use it at your own risk, unintentional bugs are all but risks of the trade.

You can watch this space (at your own risk, of course) for new versions - improvements or bug fixes.

21 March 2010

Siebel: Querying for Distinct Records

Many a time during Siebel configuration, one is left wondering "so near yet so far" - to SQL that is. A recent scenario had this problem - send alerts to the activity's account's team members when it is past the due date. Sending more than one email for one or more pending activity is
not acceptable. One of the common things that we do when confronted with this problem is to just write a workflow or a piece of code somewhere that can:
  1. Query for all activities past the due date

  2. For each activity, get the account and query for the
    account's position team

  3. For each member of the team, get the corresponding primary
    employee

  4. Send notification/alerts and flag him to be ignored in
    future

Looking at this problem from a different angle, the solution
is somewhat more simple - get unique "account team member" - "activity"
combination that will be the potential notification candidate. Siebel
provides a "Distinct" property on business components that helps us to
achieve just this. Note that this property enforces a "DISTINCT" clause
on all fields present in the BC, which may force us to create a clone
when needed. Let us re-look at the solution now:
  1. Create a BC based on S_EVT_ACT and with the following
    fields:
    • Due Date (DUE)
    • Status (EVT_STAT_CD)
    • Account Id (OU_ID)
    • Account Primary Position Id (S_ACCNT_POSTN.POSITION_ID)
      • Join: S_EVT_ACT.OU_ID = S_ACCNT_POSTN.OU_EXT_ID)
    • Account Primary Employee Email (S_CONTACT.EMAIL_ADDR)
      • Join: S_ACCNT_POSTN.POSITION_ID = S_POSTN.PAR_ROW_ID
      • Join: S_POSTN.PR_EMP_ID = S_CONTACT.PAR_ROW_ID

  2. Enable "Distinct" flag on this BC

  3. Create a simple workflow based on a business object which
    has the above BC as primary and which leverages the ""Outbound
    Communications Manager" service

  4. Create a "Repeating Component Request" with the required
    search criteria - "[Due] = Today() AND [Status] = 'Open'"

Well, how is that? Of course both have the same number of steps and the second one actually looks more pronounced. But if you have done a fair bit of coding and solutions to problems such as these you know what to choose.

06 March 2010

Siebel: Batch Script to Compile and Replace SRF

Well, I have been absent - you can't really blame me since I had nothing to say. But I am back and hope that matters at least a bit.

My recent work involved some digging around to compile SRF frequently and was surprised that there was hardly any ready-made way to do that. This is the state even though Siebel has been providing 'command line' syntax to do a number of things using Tools. So the following batch script was born for Microsoft Windows OS. It is not really that difficult to achieve it for other operating systems if you apply your mind a bit. I can no way call this script as my own, it is just putting together of many pieces. A brief explanation follows for the uninitiated.

The complete script can be found at the end of this post. To make it run just open notepad > copy the entire script and save the file as "CompUp.bat". If you just double click the file, there is no log created. It will be mighty helpful for the script to create appropriate logs - this will do it:
"d:\sba81\Compile\CompUp.bat 1>>d:\sb\Compile\CompUp.log 2>>&1"

Let us look at individual sections of the script:

Initiation
Set a few variables which can change across environments.
@set SBL_ROOT=d:\sba81
@set SBL_TOOLS_ROOT=d:\sba81\tools
@set SRF_BACKUP=d:\sba81\Compile\SRFArchive
@set SRF_FOLDER=%SBL_ROOT%\siebsrvr\objects\enu
@set BSCRIPT_FOLDER=%SBL_ROOT%\siebsrvr\webmaster\enu

@set OLD_SRF=siebel_sia.srf
@set NEW_SRF=siebel_sia-%TODAY:~10,4%%TODAY:~4,2%%TODAY:~7,2%%NOW:~0,2%.srf
@set CFG=%SBL_ROOT%\siebsrvr\bin\enu\epharma.cfg

@set SIEBEL_SERVER="my_Siebsrvr"
@set WEB_SERVER="my_Webserver"
Most of it is standard stuff, you might observe that the NEW_SRF is named such that repeated compiles on a single day will not cause any harm - assuming each compile takes at least an hour to complete. Pick any CFG of your choice. Siebel server, web server and gateway parameters are copied from the service names. To view service names go to Windows Start Menu > Run > Type 'services.msc' > Hit OK. In services windows go to 'Properties' of the appropriate service and locate the name - these do not have spaces.

Compile
Next comes the actual compile - use Siebel Tools command line options to initiate compile. When the batch file is being executed, you may actually see Tools open up, compile SRF and close.
@ECHO %DATE% %TIME%: Compile SRF with %SBL_TOOLS_ROOT%\bin\enu\tools.cfg
@%SBL_TOOLS_ROOT%\bin\siebdev.exe /c %SBL_TOOLS_ROOT%\bin\enu\tools.cfg /d ServerDataSrc /u /p /bc "Siebel Repository" %SRF_BACKUP%\%NEW_SRF%
@IF %ERRORLEVEL% NEQ 0 GOTO ERR_HANDLER

One obvious point here is that you need Tools to be installed on the server. If you are using a box that cannot have Tools (or using other operating systems), you may need to write additional statements to telnet (or something similar) to the Tools box, compile SRF and transfer the same to Siebel server machine. If everything runs fine you will have the SRF compiled, hurray! On the other hand, if there is an error the batch execution just stops without executing further statements. These are scattered throughout the script to direct batch execution in case of errors.

Replace SRF
Now, stop the server to enable us to replace SRF.
net stop %SIEBEL_SERVER%
@sleep 120
The sleep is required to wait for the server to actually stop. During execution you may note that 'net stop' command tells us that the service could not be stopped. What really happens is that it waits for too small a time for server to come down. 'sleep' can hold the further execution till defined time (120 seconds) to enable the siebel server to completely shutdown. Next step: replace srf.
move /y %SRF_FOLDER%\%OLD_SRF% %SRF_BACKUP%\%NEW_SRF%_old
move /y %SRF_BACKUP%\%NEW_SRF% %SRF_FOLDER%\%OLD_SRF%
Copy the newly compiled SRF to Siebel server, while rename the old SRF to denote the SRF it was replaced with. Next generate browser script:
%SBL_ROOT%\siebsrvr\bin\genbscript %CFG% %BSCRIPT_FOLDER%
and start Siebel server:
net start %SIEBEL_SERVER%
Just in case you were wondering, we don't need to wait for the Siebel server to actually startup. Restart Web Server service to put the new browser script in action.
@REM net stop %WEB_SERVER%
@REM net start %WEB_SERVER%
As an alternative you can always follow the SWE command route to refresh browser scripts. Well, that was easy wasn't it?

Complete Script
You can download the batch file here.
@REM Compile and Upload Utility - Batch file to compile SRF and 'activate' it on Siebel server
@REM This is the Windows version! Use command "d:\sba81\Compile\CompUp.bat 1>>d:\sb\Compile\CompUp.log 2>>&1" to redirect o/p & error to log
@REM

@set COMPUP_LOG=d:\sba81\Compile\CompUp.log

@ECHO ====================================================================================================================
@ECHO %DATE% %TIME%: CompUp starting up..
@ECHO %DATE% %TIME%: Set variables

@set TODAY=%Date: =0%
@set NOW=%Time: =0%
@set SBL_ROOT=d:\sba81
@set SBL_TOOLS_ROOT=d:\sba81\tools
@set SRF_BACKUP=d:\sba81\Compile\SRFArchive
@set SRF_FOLDER=%SBL_ROOT%\siebsrvr\objects\enu
@set BSCRIPT_FOLDER=%SBL_ROOT%\siebsrvr\webmaster\enu

@set OLD_SRF=siebel_sia.srf
@set NEW_SRF=siebel_sia-%TODAY:~10,4%%TODAY:~4,2%%TODAY:~7,2%%NOW:~0,2%.srf
@set CFG=%SBL_ROOT%\siebsrvr\bin\enu\epharma.cfg

@set SIEBEL_SERVER="my_Siebsrvr"
@set WEB_SERVER="my_Webserver"

@ECHO %DATE% %TIME%: Compile SRF with %SBL_TOOLS_ROOT%\bin\enu\tools.cfg
@%SBL_TOOLS_ROOT%\bin\siebdev.exe /c %SBL_TOOLS_ROOT%\bin\enu\tools.cfg /d ServerDataSrc /u /p /bc "Siebel Repository" %SRF_BACKUP%\%NEW_SRF%
@IF %ERRORLEVEL% NEQ 0 GOTO ERR_HANDLER

@ECHO %DATE% %TIME%: Stop Siebel server %SIEBEL_SERVER%..
net stop %SIEBEL_SERVER%
@sleep 120
@IF %ERRORLEVEL% NEQ 0 GOTO ERR_HANDLER

@ECHO %DATE% %TIME%: Copy SRF
move /y %SRF_FOLDER%\%OLD_SRF% %SRF_BACKUP%\%NEW_SRF%_old
@IF %ERRORLEVEL% NEQ 0 GOTO ERR_HANDLER
move /y %SRF_BACKUP%\%NEW_SRF% %SRF_FOLDER%\%OLD_SRF%
@IF %ERRORLEVEL% NEQ 0 GOTO ERR_HANDLER

@ECHO %DATE% %TIME%: Generate browser script
%SBL_ROOT%\siebsrvr\bin\genbscript %CFG% %BSCRIPT_FOLDER%

@ECHO %DATE% %TIME%: Start Siebel server %SIEBEL_SERVER%
net start %SIEBEL_SERVER%
@IF %ERRORLEVEL% NEQ 0 GOTO ERR_HANDLER

@REM ECHO %DATE% %TIME%: Restart Webserver %WEB_SERVER%
@REM net stop %WEB_SERVER%
@IF %ERRORLEVEL% NEQ 0 GOTO ERR_HANDLER
@REM net start %WEB_SERVER%
@IF %ERRORLEVEL% NEQ 0 GOTO ERR_HANDLER

@GOTO End

:ERR_HANDLER
@ECHO Job failed! Error Code: %ERRORLEVEL%. Refer log file for further details.

:End
@ECHO %DATE% %TIME%: CompUp end!


16 June 2009

Siebel: Integrating Twitter

If you have not yet seen the demo of Twitter integration with Siebel on Dipock's blog, it is probably a good time to see it. Available there is a demo video that lists out three basic steps to integrate Twitter search in Siebel. For those of you who have a slower internet connection, here are the steps:
  1. Create a calculated field that uses a iFrame to retrieve Twitter search results based on Account name, URL will be something like "http://search.twitter.com/search?q=siebel crm"
  2. Expose the field on a separate applet and display the results in a view

Simple enough to allow the user to search for the account and what not, but how will we make this "actionable"? There comes the use of Siebel's powerful Virtual Business Components (VBC) functionality. Twitter exposes APIs that can fetch search results in atom format. A simple transformation followed by conversion to property set and voila, we have results in a format fit enough to be displayed in any view that you like. The steps you ask?
  1. Create VBC and applet based on VBC
  2. Write supporting script/business service to make sense of the search results, to retrieve Twitter search results using API at http://search.twitter.com/search.atom
  3. Transform and map the values to VBC fields
Not exactly as simple as the previous idea, but the biggest advantage is that you can use this data for subsequent actions - may it be creating a follow-up activity for the Tweet, creating a Service Request to address the complaint raised or just to track the conversation thread for the particular user/tweet.

Although these steps are listed with Twitter in focus, the same will be applicable for any Social media which expose APIs in atom/xml format. The process itself is not entirely different from your regular interface to an enterprise app, but yes, the treatment of how exactly you leverage the Social media effectively certainly is.

23 April 2009

Siebel: URL Tricks

Most of us use the URL to the Siebel application as just that - an address to reach Siebel functionality. But there are a few tricks that could make life easy for a few developers. I don't know of many, but will certainly start out with a couple of them I have used extensively in the past. Do you use any other instructions that may ease everyone's life?

  • Refresh browser script on the webserver: There are a lot of jittery admins out there who will not give you rights to restart the web server box. But at the same time, you don't seem to quash the bugs hard enough and you need more than a few SRF replacements. What do you do? Type this in the browser: http://host:port/application/start.swe?SWECmd=UpdateWebImages&SWEPassword=WebUpdateProtectionKey where: host & port = webserver address as in the URL used to access Siebel application; application = Siebel application identifier - sales_enu, media_enu etc); WebUpdateProtectionKey = Unencrypted web update protection key - defined in eapps.cfg using WebUpdatePassword parameter
  • Execute a few commands for quick and dirty debugging. For example: javascript:alert(theApplication().GetProfileAttr("ApplicationName"));
  • Test your HTTP post/get interface by directly providing the input XML in the address bar. For example: http://host:port/eai_enu/start.swe?SWEExtSource=myService&SWEExtCmd=Execute&UserName=&Password=&SWEExtData=<url encoded request XML>

26 October 2008

Siebel: Sensitizing Case Insensitive Queries

There was a time in the not too distant past - whenever users ask for certain fields to be case insensitive, developers had an answer - "look it's not like we can't or won't do it - it is just that the performance takes a beating". Now things look a lot easier.

The Problem

Siebel applications are case sensitive by default. Although we would certainly like to see them as another Google search - enterprise search was never really a Siebel forte (hold, I did not come to Siebel 8.0 improvements and Oracle Secure Search!). Now, searching for accounts or contacts would require the users to have a general idea or adhere to a framework of naming convention. An "ABC Company" here and "Abc Company" there, albeit a typo, result in frustration for the users. If you can have your whole application case insensitive you just turn on a switch and you lead a peaceful life. But unfortunately, not many of us are blessed with small databases or user-base and the kind of queries that requires users to take coffee-breaks are not encouraged.

Tackling case-insensitive queries assumed monstrous proportions in some implementations. Users have to get their work done. So there were a few work-arounds:
  • Force case sensitive queries for desired fields by prefixing the queries with "~". Might have user-training problems, users are not happy with the extra typing (you have to really search for the damn character). Again, this might lead to the coffee-break problem, although in a much smaller scale
  • Force a single case (like all caps) for certain fields like account or contact names. Again, not a beautiful solution, requires lot of user discipline

Then, there were developers - they have to maintain a certain level of user-satisfaction in the interest of their jobs and so were more work-arounds:
  • Tell users to use ~ in their queries. Create indexes (like functional indexes) to manage performance loads
  • Make selected fields case insensitive and manage performance through indexes
  • Force case on fields and enforce user discipline
  • And another interesting solution, which is now mainstream - enabling case-insensitivity through a redirection approach (you have to go through the entire article)

How Siebel Helps?

Enter CIAI (Case Insensitive and Accent Insensitive) wizard in Siebel 8.0. In there, we have a more streamlined way of dealing with enabling case-insensitive queries for specific fields.

What you do, as a developer, is pretty straight-forward:
  • Select columns of interest
  • Invoke CIAI wizard
    • Select all indexes that need tuning
  • Let wizard do it's thing

What you do, as a user, is more simple:
  • You use the enabled fields to query - no case, no nonsense

What CIAI wizard does is not so simple:
  • Change default insensitivity property to "DB Case & Accent" for the specified columns
  • Optionally, create child columns that are same as parent (or previoulsy specified) columns except for the force-case part. In the background, all values are stored in one case
  • Optionally, delete index including parent columns and recreate indexes for the child columns
Now, the object manager reroutes the queries on specified columns to the case-insensitive columns that in-turn use the case-insensitive indexes to return results that are case-insensitive. I bet you don't want to hear the term case-insensitive again (there you go!).

We can run CIAI wizard multiple times and even turn off the changes made in prior executions. Note that there are a bunch of prerequisites. More important ones - only certain table types like Data (Public/Private/Intersection), Extension etc. are supported and only char, varchar and CLOB data types can be configured for CIAI queries.

Interested to learn more? - Head to "Configuring Siebel Business Applications" in Bookshelf.

20 September 2008

Find Search

Siebel applications provided a search functionality since ages, called "Find". This functionality is valuable in providing a better user experience and controlling user search conditions.

In the application, you will find Siebel Find at the top right corner - a binocular that opens up Find dialog when clicked. User can choose any component they want to search, fill in the appropriate fields and hit go. Search results are displayed in the same applet, that are drilled-down to reach out to the details. Easy to use and also easy to configure. Siebel Tools provides a Find object, which can be used to specify the search components & fields and drill-down target views.

All this, you would know and most probably even more. What I propose here and what I have seen in successful implementations is using Find as the only way to search for records. Now, when users have been using Siebel list applets for searching for some time now, they will find it annoying to open another dialog to type in stuff & click "Go". But they do provide certain advantages:
  • The underlying business component that trawls for records based on search criteria may not be the same as the business component on the UI. This makes the search really fast. Searching takes most of the DB time, and reducing search cost is one of the ever tormenting problems in implementations
    • The Find BC itself can be light with very limited and controlled fields that are not "Force Active" or "Link Spec" true
    • Class of Find BC can be something light, like CSSBCBusComp instead of CSSBCOppty or some or the other Order BC classes
  • Search spec on Find applet and BC can provide more controlled filter conditions, completely independent of UI filters
  • Searches can be spanned through components. For example, if for some reason you have segregated Account and Partner at the BC level based on "Partner Flag", users are forced to do the search on two views. A Find component based on S_ORG_EXT (oops.. actually, S_PARTY) and without the filter criteria used in the two BCs, combined with dynamic drill-downs provide different destination views for the search results, will make things a bit easier
  • With additional configuration (script available in Metalink3) Find can be configured to have certain fields as mandatory for search. For example, provide at least one field for search, Account name is required for account search. This can be used as an alternate way to forcefully use good performing indexes on the DB tables!
  • The developers get to decide visibility of the filter conditions. There can be business restrictions to provide "All Accounts Across Organization" views to call center personnel - the fear of data theft (export in List applets work great). All the data may even look intimidating to new users. Using Find and combining with some other component (or the same one) can have developers defined visibility. Users will drill-down to a detail view to see more.

Siebel also enables searching through 3rd party tools (remember Fulcrum search?). In recent versions of Siebel, Oracle provides an enterprise secure search functionality that is separately licensed. These provide users more flexibility and will prove an addictive tool.

10 September 2008

Siebel Client-side Import - Used it yet?

Possible spoiler: Content below may be of academic interest rather than any commercial exploitation!


Most Siebel users will be familiar with "Import" and "Export" options displayed in the applet level menu in list applets. Although export is quite commonly used, import does not find many consumers. Client-side import refers to the functionality using which users, through the UI, can import data into Siebel application from a CSV file, ACT! Application export or any other defined file format.

Although we always "recommend" initiating and storing the CRM data in Siebel, that may be difficult to achieve due to logistic reasons like availability of application, disconnected mode of usage or data coming in from different sources. This gap is commonly addressed as an interface of some kind – submitting files for imports through an enterprise batch process, import using custom COM programs, interacting directly with the third-party enterprise applications etc. There are instances where allowing users to import the data quickly and start working on Siebel application may provide a better experience rather than forcing them through an enterprise EAI process running in a disconnected mode. Instantly uploading data will also enable users to connect closely with the application & assume ownership of the data. ( Hail Jargons! Anymore to add, anyone?)

Siebel out-of-the-box supports import of Contacts (according to an ambiguous statement in bookshelf that says “Siebel applications support contact business components only for client-side imports”). I am not sure how the other 25+ import objects are used, but this feature is certainly will not be on anyone’s priority list. After all, today organizations want immediate access to data from every employee and entering data in one or the other enterprise application is the norm. I did not bother to search in metalink and come out with use-cases, so do notify me if this is a repeat and I will tag this post accordingly.

 

Developers can easily configure components to enable Client-side import. An illustration below is an overview of enabling such an import for “List of Values”.

 

Enabling Client-side Import

 

Pre-build

  • Verify whether the applet to which the import object will be associated has “Insert” permissions for the user (May be irrelevant here – new LOVs can always be inserted right?)
  • Expose “Import Object” in the “Object Explorer” of Siebel Tools

Build - Tools

  1. Create import object in Tools - Create a new “Import Object” based on same BC as the one that you see in UI. You will not see “Import” enabled in the UI if this is not the case
  1. Create “Import Field” for all attributes that need to be imported
  2. Create relevant Import Key Field and Import Aux Field. Import Key Field acts like the “User Key”, those are the fields used to identify uniqueness of the record. Import Aux Field will provide option to re-query if there is a duplicate found
  3. Define “Import Source” to map the type of file that will be imported. This provides options to the user for selecting the type of map at the time of import
  4. For each import source, create field maps. Note that one Siebel field can be mapped to a combination of columns in the import destination 


Use

  1. Navigate to Administration – Data > List of Values. Click on Import from the applet level menu or File (from the application level menu) > Import
  2. Choose file, input format, mapping source and conflict resolution type. All fields hopefully are self-explanatory. Auto mapping allows you to do mapping on the fly, while we have defined mapping rules for predefined mapping. Since we already have created mapping in Tools, we select that without a second thought and hit on ‘Next’
  1. See the magic of mapping and hit ‘Next’ (again). This will trigger the import process. Import runs within the object manager itself (or by siebel.exe, as applicable)
  1. Review import, check log file and sign off. I had introduced a duplicate to test the functionality, which promptly got rejected

Advantages

  • Easy accessibility for the users, immediate response
  • Does not really qualify as an interface :)
  • Functionality can be configured quickly

 

Limitations

  • Client-side import is supported for parent business components only, no complex hierarchies, no importing of parent & children in one stretch
  • Has to be based on the same BC as the applet in UI – no ‘light’ BC concept here
  • Needs ‘debugging’ skills from the users! The error report is not exactly user friendly, except for the summary

 

Final Word

  • Do not forget to “Clear Cache”

 

Components & Version

Components realized on Siebel 8.0. There is nothing worthwhile to share here.


References

Siebel Object Types Reference, Page 199. Bookshelf for Oracle’s Siebel Business Applications Version 8.0 - B40099-02