Showing posts with label Siebel. Show all posts
Showing posts with label Siebel. Show all posts

Sunday, November 11, 2012

Browser Scripts–‘this’ is a problem

 

One issue I have faced numerous times with Siebel’s browser scripts is that the ‘this’ reference is not recognized when invoked in a separate function.

This code works fine when written directly in the PreInvoke section of the applet:

function Applet_PreInvokeMethod(name, inputPropSet)
{
    if (name == "CustomMethod")
    {
        alert(this.Name());
        return ("CancelOperation");
    }
    return ("ContinueOperation");
}

 

But if you decide to move the code into a separate function of its own:

function Demo()
{
    alert(this.Name());
}

function Applet_PreInvokeMethod(name, inputPropSet)
{
    if (name == "CustomMethod")
    {
        Demo();
        return ("CancelOperation");
    }
    return ("ContinueOperation");
}

..the system will start giving errors saying method not defined.  This really gets in the way when there is not of field access and manipulation required in the function. One way out is to pass the this reference directly as an argument into the function.

function Demo(applet)
{
    alert(applet.Name());
}

function Applet_PreInvokeMethod(name, inputPropSet)
{
    if (name == "CustomMethod")
    {
        Demo(this);
        return ("CancelOperation");
    }
    return ("ContinueOperation");
}

 

Another way I have seen recently is to use a global variable for the applet and use that instead of the this. The variable has to be initialized in Applet_Load event

declarations()
{
    var g_oApplet;
}
function Applet_Load()
{
    g_oApplet = this;
}
function Demo()
{
    alert(g_oApplet.Name());
}
function Applet_PreInvokeMethod(name, inputPropSet)
{
    if (name == "CustomMethod")
    {
        Demo();
        return ("CancelOperation");
    }
    return ("ContinueOperation");
}

Sunday, September 23, 2012

FINS CAP Buscomp Handler’s empty query problem

 

Currently I am working on a Siebel Financial Applications project using a lot of Business Rules Processor (BRPs) . The BRP way of working with Business Components is by using the various methods available under the  FINS CAP Buscomp Handler Business Service.

FINS CAP Buscomp Handler Business Service provides the following five methods:

  • Query
  • NextRecord
  • GetFieldValue
  • SetFieldValue
  • InsertRecord

The BS works without a Business Object context, ie while specifying the Business Component on which to operate, the Business Object name is not provided. It is the only BS I know in Siebel which operates directly on business components without taking the BO context. But as we realized, this is not always the best way of operating. As the amount of data grew, we found the BRPs going slower and performance degradation.

On spooling out the SQL when the BRPs were running, we found that null queries being run in the tables, without a search criteria. When the InsertRecord method of the BS is used to insert a record into say..Opportunity BC which is based on S_OPTY table, the BS was running this query first.

SELECT
      T1.CONFLICT_ID,
      T1.LAST_UPD,
      T1.CREATED,
      T1.LAST_UPD_BY,
      T1.CREATED_BY,
      T1.MODIFICATION_NUM,
      T1.ROW_ID,
      T14.USAGE,
      T8.TRDIN_EXPIRE_DAYS,
      T7.NAME,
      T1.PR_DEPT_OU_ID,
      T7.INTEGRATION_ID,
      T7.LOC,
      T7.OU_NUM,
      T10.NAME,
      T7.CURR_PRI_LST_ID,
      T7.PR_BL_ADDR_ID,
      T7.PR_BL_PER_ID,
      T7.PR_SHIP_ADDR_ID,
      T7.PR_SHIP_PER_ID,
      T1.CONSUMER_OPTY_FLG,
      T13.BL_ACCNT_ID,
      T13.BL_CON_ID,
      T1.CHANNEL_TYPE_CD,
      T1.CURCY_CD,
      T1.CUST_ACCNT_ID,
      T14.PROJ_STAT_CD,
      T1.CLOSED_FLG,
      T13.GROUP_TYPE_CD,
      T13.DEPARTURE_DT,
      T13.ARRIVAL_DT,
      T4.STATUS_INBND_CD,
      T7.ROW_ID,
      T1.PR_CON_ID,
      T1.NAME,
      T1.NEW_LOAN_FLG,
      T13.OPTY_MARKET_CD,
      T12.STAGE_STATUS_CD,
      T13.OPTY_SEGMENT_CD,
      T4.STATUS_CD,
      T1.APPL_OWNER_TYPE_CD,
      T1.PAR_OPTY_ID,
      T5.NAME,
      T9.PAR_POSTN_ID,
      T5.PROJ_PRPTY_ID,
      T1.ALIAS_NAME,
      T1.PR_OU_INDUST_ID,
      T1.PR_OU_ADDR_ID,
      T1.PR_REP_DNRM_FLG,
      T1.PR_REP_MANL_FLG,
      T1.PR_REP_SYS_FLG,
      T1.PR_CMPT_OU_ID,
      T6.COUNTRY,
      T9.PR_EMP_ID,
      T1.PR_OPTYORG_ID,
      T1.PR_OPTYPRD_ID,
      T1.BU_ID,
      T1.PR_PRTNR_ID,
      T1.PR_POSTN_ID,
      T1.SUM_REVN_AMT,
      T1.SUM_CLASS_CD,
      T1.SUM_EFFECTIVE_DT,
      T1.SUM_COMMIT_FLG,
      T1.SUM_COST_AMT,
      T1.SUM_DOWNSIDE_AMT,
      T1.SUM_REVN_ITEM_ID,
      T1.SUM_MARGIN_AMT,
      T1.SUM_TYPE_CD,
      T1.SUM_UPSIDE_AMT,
      T1.SUM_WIN_PROB,
      T11.LOGIN,
      T1.PR_SRC_ID,
      T6.STATE,
      T1.PR_TERR_ID,
      T1.PROG_NAME,
      T1.PROJ_PRPTY_ID,
      T13.REL_TYPE_CD,
      T1.SALES_METHOD_ID,
      T12.NAME,
      T1.STG_START_DT,
      T1.CURR_STG_ID,
      T12.STG_ORDER,
      T1.SECURE_FLG,
      T1.OPTY_CD,
      T1.PGROUP_PUBLIC_FLG,
      T1.BU_ID,
      T2.FCST_CLS_DT,
      T2.FCST_REVN_CURCY_CD,
      T16.LOGIN,
      T17.EFFECTIVE_DT,
      T17.COST_AMT,
      T17.DOWNSIDE_AMT,
      T17.MARGIN_AMT,
      T17.WIN_PROB,
      T17.REVN_AMT,
      T17.ACCNT_ID,
      T17.CLASS_CD,
      T17.REVN_AMT_CURCY_CD,
      T17.QTY,
      T17.CRDT_POSTN_ID,
      T17.TYPE_CD,
      T17.UPSIDE_AMT,
      T19.FST_NAME,
      T19.LAST_NAME,
      T20.SRC_CD,
      T13.ROW_ID,
      T13.PAR_ROW_ID,
      T13.MODIFICATION_NUM,
      T13.CREATED_BY,
      T13.LAST_UPD_BY,
      T13.CREATED,
      T13.LAST_UPD,
      T13.CONFLICT_ID,
      T13.PAR_ROW_ID,
      T14.ROW_ID,
      T14.PAR_ROW_ID,
      T14.MODIFICATION_NUM,
      T14.CREATED_BY,
      T14.LAST_UPD_BY,
      T14.CREATED,
      T14.LAST_UPD,
      T14.CONFLICT_ID,
      T14.PAR_ROW_ID,
      T2.ROW_ID,
      T3.ROW_ID,
      T17.ROW_ID,
      T18.ROW_ID,
      T20.ROW_ID
   FROM
       SIEBEL.S_OPTY T1
          INNER JOIN SIEBEL.S_OPTY_POSTN T2 ON T1.PR_POSTN_ID = T2.POSITION_ID AND T1.ROW_ID = T2.OPTY_ID
          INNER JOIN SIEBEL.S_PARTY T3 ON T2.POSITION_ID = T3.ROW_ID
          LEFT OUTER JOIN SIEBEL.S_SYS_KEYMAP T4 ON T1.ROW_ID = T4.SIEBEL_SYS_KEY
          LEFT OUTER JOIN SIEBEL.S_OPTY T5 ON T1.PAR_OPTY_ID = T5.ROW_ID
          LEFT OUTER JOIN SIEBEL.S_ADDR_PER T6 ON T1.PR_OU_ADDR_ID = T6.ROW_ID
          LEFT OUTER JOIN SIEBEL.S_ORG_EXT T7 ON T1.PR_DEPT_OU_ID = T7.PAR_ROW_ID
          LEFT OUTER JOIN SIEBEL.S_ORG_EXT_ATX T8 ON T1.BU_ID = T8.PAR_ROW_ID
          LEFT OUTER JOIN SIEBEL.S_POSTN T9 ON T1.PR_POSTN_ID = T9.PAR_ROW_ID
          LEFT OUTER JOIN SIEBEL.S_PRI_LST T10 ON T7.CURR_PRI_LST_ID = T10.ROW_ID
          LEFT OUTER JOIN SIEBEL.S_USER T11 ON T9.PR_EMP_ID = T11.PAR_ROW_ID
          LEFT OUTER JOIN SIEBEL.S_STG T12 ON T1.CURR_STG_ID = T12.ROW_ID
          LEFT OUTER JOIN SIEBEL.S_OPTY_TNTX T13 ON T1.ROW_ID = T13.PAR_ROW_ID
          LEFT OUTER JOIN SIEBEL.S_OPTY_DSGN_REG T14 ON T1.ROW_ID = T14.PAR_ROW_ID
          LEFT OUTER JOIN SIEBEL.S_POSTN T15 ON T2.POSITION_ID = T15.PAR_ROW_ID
         LEFT OUTER JOIN SIEBEL.S_USER T16 ON T15.PR_EMP_ID = T16.PAR_ROW_ID
          LEFT OUTER JOIN SIEBEL.S_REVN T17 ON T1.SUM_REVN_ITEM_ID = T17.ROW_ID
          LEFT OUTER JOIN SIEBEL.S_PARTY T18 ON T1.PR_CON_ID = T18.ROW_ID
          LEFT OUTER JOIN SIEBEL.S_CONTACT T19 ON T1.PR_CON_ID = T19.PAR_ROW_ID
          LEFT OUTER JOIN SIEBEL.S_SRC T20 ON T1.PR_SRC_ID = T20.ROW_ID
   ORDER BY
      T17.EFFECTIVE_DT DESC.

If you analyze the last part of the SQL, there is no “WHERE” clause with a search specification , nor are there and bind variables. This query will simply return all records present in the Opportunity Business Component. That’s right, its an empty query on the S_OPTY table and all other tables left joined. And this is fired every time the InsertRecord method is fired. I think Siebel tries to see if the record going to be inserted is not a duplicate of an existing record in the system, and it does this by first firing and empty query and then comparing the result with what we are trying to insert. But as the number of records in the tables grow, the performance degrades. And this is a vanilla/OOTB business service.

Anyway, we had to do away with “FINS CAP Buscomp Handler:InsertRecord” and replaced it with another vanilla BS: “Inbound E-mail Database Operations” Business Service and its “InsertRecord” method. The syntax is not exactly same, some modifications are required. But after using this BS, we found a tremendous improvement in speed in the system.

Saturday, July 7, 2012

Tools of the trade


Five years of Siebel EAI development, and I am still learning every day. One thing I quickly realized was that the Siebel Tools and Application system is not like the contemporary Integrated Development Environment (IDE) used in Java and .NET development. Sure, Tools can solve most of your problems, but every Siebel developer will eventually face a problem which has to be solved using some other tool/utility/script which may have to be written from scratch. Today, I thought I’d share what’s in my arsenal of tools.

Siebel Development

  1. A good text editor is essential for any development need. For years I have been relying on window’s default notepad utility, which is good enough. But it is seriously lacking in features, and hangs when you try to open huge files. I use Notepad2 , Notepad++ and EditPlus. Each has first class CR/LF support, ANSI to Unicode switching, whitespace and line ending graphics and Mouse Wheel Zooming. EditPlus even has ability search and replace special characters (\n,\t) and works nicely with huuge files.
  2. If you work deals with XMLs/XSLs, you will need a good XML/XSLT/WSDL editor. XmlSpy  has been my number one choice, followed by Oxygen. Though I have noticed that there are some minor differences in the XMLSpy XPATH engine between older and newer versions. The XPATH engine in Spy version 6 is similar to Siebel’s own EAI XSLT service. Some of the fine working XSLTs were throwing validation errors in the newer version of Spy, but they worked perfect in Siebel.
  3. SOAP UI. This one deserves a special mention. Not only is it free, it has support for secure webservices , proxies and many other protocols. Its so easy to set up a stub/mockservices, and these have saved my life more than once.
  4. Fiddler. I first used this way back in college, when I wanted to intercept and see the http messages being sent from my system for a project. It’s a free utility from Microsoft, and comes in handy in diagnosing web service related issues. Its got a scripting system, and can be used as mockservice too.
  5. Network tools like PuTTy, WinSCP and FileZilla come here. I also use PuTTY to setup ssh tunnels when I want to route a request via another server.
  6. UnixUtils. A unix developer swears by the huge number of commands at his disposal. Sadly, windows does not provide that many commands, and I thank the geeks for porting these awesome Unix commands over to Win32. These allow me to build bat files and scripts to solve recurring issues.
  7. Although UnixUtils has windows port of grep and tail commands, the UI of BareGrep and BareTail and much more developer friendly.
  8. Oracle SQLDeveloper, TOra and my old favorite, TOAD. You can’t be a Siebel developer without knowing SQL !
  9. I’m sure all you Siebel developers have been in this situation: You have list of data you need to query in Siebel :
val1
val2
val3

The searchspec you need to build is : “val OR val2 OR val3” . Well, that’s all that Orit does. Frankly, I don’t know who developed this utility, but it is something developed by a Siebel developer. All it does is simply concatenate column wise data with ‘OR’ in between.

Other Siebel Things I found on the net

Its sad that Siebel does not provide an Out-of-box documentation feature, which can be used during and development. This is just one of the many problems I have faced.Nice thing is others have faced the same problem, and developed their own solutions for the problem.
  1. The good folks at the Only Siebel blog have released Excel Macro tools which can pull config data for documentation.
  2. Oli has graciously released a lot of his tools for free download. There are script analysers, data loaders and Tracer Tools.
  3. Some useful utilities at the website of Sea Marvel Tech Solutions
  4. Wait…one more utility for Siebel Documentation here.
  5. Here is my own attempt at making an SQL Tracer.
  6. Siebel provides dbisqlc to connect and run SQL statements on your localdb. But I find it painful when there are too many columns in the output, I have to scroll to see the data, and export. Sel2XL is a nice excel macro which does the same thing, and it allows excel formatting.
  7. Sometimes, the easiest way out is direct SQL into the the database. There are SQLs for siebel issues, EIM Mappings, for UI mappings, and so many other issues.

General Use

  1. Window’s default search feature can get irritatingly slow, specially if you need to search across drives and have to run complex search patters. Everything is an awesome ,high speed ,instant search utility for the NTFS file system. You have to try it to see the magic. And did I mention it is free ?
  2. Teracopy is the default copy utility on my systems. Sure, the latest multicopy feature on Windows 7 & 8 are cool, but I still feel Teracopy’s interface is better.
  3. Free Download Manager. For all those loong downloads.
  4. Microsft’s Virtual PC. I use this to setup virtual machines for my Siebel POCs. Its free and no fuss to setup and use. This new version of Windows Virtual PC lets you run Windows XP applications next to your Windows 7 apps for the ultimate in backward-compatibility.
  5. I have been using Liberkey suite since they came out some years ago. They have a free utility for all your day to day needs. NirSoft Utilities Collection is also a good choice.
  6. Autohotkey, DoItAgain. Ultimate Windows Automation.

Sunday, March 11, 2012

Siebel 8 Script Libraries

 

Quick question; will the following code snippet work ?

Business Service : BS1, contains only this code

function function1 ()
{
TheApplication().RaiseErrorText("function1  triggered");
}

There is no code in any other event/function of this BS. And now, the attempt is to trigger this BS via the following code:

var bs = TheApplication().GetService("BS1");
bs.function1();

Now there is something wrong about the second code snippet, right ? This is not the usual way to invoke a Business Service Method.  The practise is to use the InvokeMethod command, passing property sets for input and output.  But here is the output of running these in Siebel 8

image

 

This is an example of Script Libraries feature from Siebel 8 onwards. Developers can write multiple functions in business services, and then these functions get exposed , and the functions can be invoked directly as you would do on C/C++/Java. There is no need of adding code in  Service_PreInvokeMethod  event to expose the functions.

There are limitations though, such a business service’s functions can be invoked only via scripting. They cannot be used in WFs or BRPs. But if your functionality calls for lots of scripting, this feature surely comes in handy.

 

The ever friendly Oli has been posting some really tricky pieces of code for his code challenges. Head over there to learn scripting mistakes that creep up in code.

Happy Scripting !

Friday, March 9, 2012

View Refresh when clicking New Record in a view with Dynamic Toggle

 

Dynamic toggle applets were probably the first piece of automation a Siebel developer gets to work on; switch the applet depending on some field value. No scripting, nothing at the BusComp level, just Applet toggles. But issues crop in when the logged in user tries to create new record on the applet. Sometimes the view jumps or refreshes, specially when there are lots of applets stacked in the view. The user has to manually scroll down back to this target applet.

Oracle has a work around for this ‘defect’ documented here [ID 541100.1] , which involves loads of scripting at the applet and BusComp level. But I tried to come up with something with fewer lines of code.

Resulting solution: add the following code in the WebApplet_PreInvokeMethod section of the base applet as well as its toggle applets:

 

if (MethodName == "NewRecord")
{
this.BusComp().NewRecord(NewBefore);
return (CancelOperation);
}

 

Yep, I know, the code does not make sense at all. But for some reason, it works ! The view does not jump and the new record gets created right there in the applet. At at just 3 lines of code, it beats oracles long and elaborate code version.

Monday, February 6, 2012

eScript–Nested ‘with’ has problems in 8.1.1.5


Recently we had the friendly guys from Oracle come over and review our current project. Over the years, we have had review comments coming from such reviews and now know what to expect. But this time, there was a new entry in the document.
Siebel eScript developers and basically anyone who has worked on ECMA style languages must have used the ‘with’ statement. The with statement assigns a default object to a statement block, so you need to use the object name with its properties and methods. Its makes coding easier when you need to do multiple actions on the same object. But nesting with statements , it seems, is not a good idea if you are planning to upgrade to version 8.1.1.5 which came out last year.
The With statement structure indicates that all methods within its block will be based primarily on the indicated object. When With blocks are nested, it is not immediately obvious which object’s method will be invoked. The code execution may not do what the developer intended.
with(firstbc)
{
ClearToQuery()
ExecuteQuery();
with(secondbc)
{
ClearToQuery()
ExecuteQuery();
}
}
If the script remains unchanged prior to upgrading to 8.1.1.5, there is a known defect where runtime errors will occur. Although this is currently considered a defect and intended to be corrected, nested With blocks are not a recommended scripting practice. All of the methods invoked in the second With block would also work on the object in the first With block. In this script, the developer was actually done using the firstbc object prior to starting the nested With, but simply chose not to close the block.
Now oracle says that :It is not recommended to nest With blocks. The first With block should be close prior to initiating a new With block or the object variables should always be used.
Now we have used countless nested with statements it handle complex business logic, and have never faced an issue. But we are now rewriting the code eliminating nested withs and using the complete object names. This is because we do have plans to upgrade some time in future, and its best to steer clear of rework then.
with(firstbc)
{
ClearToQuery()
ExecuteQuery();
secondbc.ClearToQuery()
secondbc.ExecuteQuery();
}

Update: Oracle SRs are here and here

Monday, October 17, 2011

Alter Session Parameter for Siebel Query

 

For Oracle 10g

alter session set optimizer_mode = first_rows_10
alter session set "_optimizer_sortmerge_join_enabled" = false
alter session set "_optimizer_join_sel_sanity_check" = true

Sunday, June 12, 2011

Java integration to Siebel Webservice

 

A few weeks back we had this requirement to have a Java client connect to our Siebel Webservice and do various operations. In this model, the Siebel side was the backend, and a Java applet was the frontend to the system. I setup the inbound Webservice in Siebel in no time, using ASIs. But the Java folks were having problems in setting up a connection to the system. They even said there were problems in the WSDL and Webservice, and that they were getting various parser errors on their side. Guess they were too dependent on eclipse, and they could not find an import WSDL feature on it !!

Truth is, Java is one of those languages which understands webservices very well, and if properly used, could make the integration work easiest to implement. You don’ have to build the SOAP request by hand (though, that is one option) as is done in some scripting languages. You just have to figure out how to generate the stub file, or the necessary class files into the system.

Now there are two ways to import a WSDL into a  Java system, you would use the WSDLtoJava.bat file if you are using the apache axis framework. This is when a Java servlet on Tomcat/Apache is talking to another server. I preferred the easier way to using the wsimport command as this is a simple client talking to a Siebel server. I will be using the Service Request ASI WSDL from a previous post.

You need to have the Java SDK installed and the paths properly configured on your system. Open up a command prompt window and type in  “java  -version” or “javac” to see if the paths have been added correctly.

Go ahead and import the wsdl using the command wsimport SR_WSDL.wsdl. Here I am running the command from the root of C: drive. You will see the importer at work generating class files.

clip_image002[9]

You can ignore any warnings you see as long as you don’t get any errors. wsimport would have created a nested folder structure with multiple class files. Here the path created is C:\com\siebel\xml\sm_servicerequest.

image

Now its time to start writing your main java file which will make an instance of these class files and trigger the integration to siebel. You will have to know which class represents the webservice, here it is SMServiceRequestWS_Service.class. You can also generate the actual java files to see how the class and methods under them have been defined. Inorder to do this, use the command wsimport –keep.

clip_image002[13]

This time wsimport will create the java files for each class file.

clip_image002[15]

Back to our main java file. Import the generated class files using:

import com.siebel.xml.sm_servicerequest.*;

As can be seen, this string is actually the path of the generated class files. This is what my final Client.java file looked like :

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

import com.siebel.xml.sm_servicerequest.*;

import java.io.Writer;

//the above namespace is from the generated code from the wsdl.

public class Client

{

static SMServiceRequestWS_Service service = new SMServiceRequestWS_Service();

public static void main(String[] args)

{

try

{

Client client = new Client();

client.doTest(args);

}

catch(Exception e)

{

e.printStackTrace();

}

}

public void doTest(String[] args)

{

try

{

SMServiceRequestWS pm = service.getSMServiceRequestWS();

// Building the Request hierachy

QueryPageSRInput req = new QueryPageSRInput();

req.setPageSize("10");

req.setViewMode("All");

req.setStartRowNum("0");

ListOfSmServicerequest list = new ListOfSmServicerequest();

ServiceRequest SR =new ServiceRequest();

list.getServiceRequest().add(SR);

req.setListOfSmServicerequest(list);

// Variable to store Response hierarchy

QueryPageSROutput res = new QueryPageSROutput();

// Invoke the service

System.out.println("Invoking the Webservice ");

res =pm.queryPageSR(req);

System.out.println(res.getLastPage());

for (int i = 0; i < res.getListOfSmServicerequest().getServiceRequest().size(); i++)

{

System.out.print(res.getListOfSmServicerequest().getServiceRequest().get(i).getStatus() + "\t");

System.out.print(res.getListOfSmServicerequest().getServiceRequest().get(i).getSRNumber() + "\t");

System.out.println(res.getListOfSmServicerequest().getServiceRequest().get(i).getOwner());

}

}

catch(Exception e)

{

e.printStackTrace();

}

}

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

All the information you need to build up the request and parse out the response is in the .java files created by wsimport. As can be seen, the final code does not have any variables for the URL,namespace or SOAPAction. These details are taken care of in the .java files.

Time to compile and run the Client.java file. Commands are:

javac Client.java

java Client

The client instance should connect to the Siebel Webservice now :

image

This code runs a  Query and prints out the Service Request Status, RowId and Owner details.

That’s it !! This is all you need to have a java client invoking a Siebel Webservice.

Saturday, May 14, 2011

Scripting and Task Based UIs

Siebel 8's task based user interface (TBUI) is a nifty feature, but it still needs some more polishing though. A really simple looking requirement came up the other day, and I was surprised that there was no out of box feature I knew to support it.

The requirement was to conditionally disable tasks in the Task View pane applet. The Task Groups have to be associated with the triggering views, and when the logged in user enables the tasks by clicking on its button, an applet opens up in the UI on the left side, always showing all the tasks associated with the current opened view.

Now we wanted to conditionally disable certain tasks depending upon the user's position, and there was no way of achieving this. On searching on the bookshelf, I found a way to trigger the task  from script.


if (name == "Test")
{
var inputPropSet;
var outputPropSet;
var taskUIsvc;
inputPropSet = theApplication().NewPropertySet();
outputPropSet = theApplication().NewPropertySet();
taskUIsvc = theApplication().GetService("Task UI Service (SWE)");
inputPropSet.SetProperty("TaskName","Create a Contact");
the outputPropSet is created. outputPropSet is not used to send results back to the task UI--!>
taskUIsvc.InvokeMethod("LaunchTaskFromScript",inputPropSet,outputPropSet);
return ("CancelOperation");
}


So now, instead of showing the tasks in the task pane applet,  we trigger it from scripts behind buttons in the UI. We have buttons for different tasks, and the buttons themselves are enabled/disabled based on positions.

I'm hoping Siebel provides an vanilla way of achieving conditional task enabling/disabling in the UI soon.

Saturday, April 30, 2011

SQL Spools in Siebel and Trace commands

We have all been there; at some point or other, Siebel starts throwing SQL errors, or the application slows down due to some long running SQL statements.

“An error has occurred executing a Sql statement. Please continue or ask your systems administrator to check your application configuration if the problem persists.(SBL-DBC-00105)”

The best way to figure out what went wrong is to spool out the actual SQL statement (could be query or insert/update or delete) which ran in the application.

You could turn on SQL spooling when the client starts using the /s option.
Or you could increase Log levels

Now both these options enables SQL spooling when the client itself starts; and the resulting file will contain every SQL statement which ran up until the error can be reproduced. Is there any way we can turn SQL logging on the fly, to spool up only the SQLs we want and ignore the rest ?

Turns out, there are script commands TraceOn and TraceOff, which can be used the spool out the SQL statements. Documentation can be found here.

We will have to start SQL tracing using script at the beginning of the even,and then stop it after the spooling is done. I found that these commands can also be used in COM controls.

So I have created a simple SQL instant spooler in Excel macros, which will do this for you, without the need for increasing log levels or writing scripts. I have tested it on Siebel 7.8 and Siebel 8.1 local and dedicated clients, and it works fine. All you need to do is

1) Open the Siebel local or dedicated client (does not work on the thin client)
2) Use the start and stop buttons on the sheet to enable SQL tracing.
3) The SQL which was run in Siebel between start and stop will be opened in notepad



You can download the SQL instant spooler here and try it out. You need to have Siebel installed properly and enable the macros on the excel when it is opened.


Cheerios !!

Tuesday, April 26, 2011

Siebel 8.1 menu items not opening in IE 8.

Another issue I ran into in IE 8, regarding the Siebel 8.1 Mobile client. This issue was reproduceable on both debug and non-debug modes.

After the mobile client opened up fine, none of the menu items inside the UI framework would open. The menu items at each applet would not drop down, and even the Help->About View would not open up.

At first I thought the pop-up blockers were playing spoilsport again, but the problem persisted even after pop-up blockers were turned off.


Then , a colleague suggested making a change to the client CFG file. In my case, it was scomms.cfg.

1) Open the client CFG file.

2) Find this line :

               EnableFQDN               = FALSE

3) Change it to :

                EnableFQDN               = TRUE


And that fixed the problem !! I don't know what FQDN has to do with menu items, maybe its something wrong with the UI framework.

Monday, April 25, 2011

Siebel 8 debug mode problem with Internet Explorer 8 ?

The last few months have been some of the worse in my career so far. The hectic project schedule and huge amount of "last minute changes" left me very little time to relax. Hopefully, its all going to change soon.


I am working on Siebel 8.1, and had Internet explorer 7 running, which ran without any issues. After an upgrade to IE 8 (thanks to the IT guys), I found that the Siebel debug mode would no longer open. The IE window would open up and throw a  "page not found" error. But the Siebel client would open fine, when started via its own shortcut.


A little experimenting, and I found that inorder for the Siebel 8.1 debug mode to open up in IE, there should be no other instances of IE running. Just kill all other IE instances, and simulating the workflow should be fine.

Not sure if there is another way to fix this.

Saturday, November 13, 2010

Differentiating New Record & Update Record


There are cases when a particular data validation or Business  Process invocation should only occur when  a new record is being written down to the database, but not when an existing record is being updated. Or it may be the other way around, but the Siebel developer has to figure out what operation is happening.  I have found many ways these can be achieved, here are my favourite three.

1.       Using a Boolean flag in script.  This is how I first implemented such a scenario.  I was new to Siebel and hadn't yet mastered all the scripting events .  Easiest way out seemed to declare a Boolean flag in the declarations section of the Buscomp server script, and giving it a default value of false. Then in NewRecord  event,  this flag should be turned to true. Finally, in the PreWriteRecord or WriteRecord event, the value of this flag could be checked, and new records can be differentiated fromo exisiting records.

2.       RunTime events. This is a No-Scripting approach to the same problem. In Runtime events, if you select the buscomp events supported, it can be seen that Siebel now provides three events for WriteRecord operation :

·         WriteRecord : Triggered everytime after records are committed.

·         WriteRecordNew : Triggered only when new records are committed.

·         WriteRecordUpdated: Triggered only when existing records are updated.

But these events only occur AFTER the records are committed. They can't be used to do validation/invocation before records are committed.

3.       IsNewRecordPending. This is a new specialised Busines Component Method, meant for EBCs, documented here.  But on trying the command out, I found that it works perfectly well in normal business components as well.  This method can be invoked from any other event in BC level, but it only makes sense to invoke it in the PreWriteRecord section.

var isNewRecord = this.InvokeMethod("IsNewRecordPending");

This way new records can be differentiated from old records before they are committed to the system.

Friday, October 15, 2010

Declarative Alternatives to Using Siebel Scripting (Doc ID 477842.1)

Maybe you already know this, but I there is a document on supportweb which documents many alternatives to scripting. Its Doc ID 477842.1 available here:

 

https://supporthtml.oracle.com/ep/faces/secure/km/DocumentDisplay.jspx?id=477842.1

 

It also points to another document which discusses the data validation manager . 478298.1

 

https://supporthtml.oracle.com/ep/faces/secure/km/DocumentDisplay.jspx?id=478298.1

 

 

Wednesday, September 1, 2010

Validating multiple Datamappers


We were facing these strange error during ADM import on target system:


Source component % does not exist.(SBL-EAI-04063)

This was coming when we tried to import the datamappers inot target system.We follow a continous deveopment model with numerous integrations, and the external IOs for them keep on changing. The problem occurred because the new WSDL imported did not contain some IC levels which were developed and mapped earlier. But the problem was complicated because now we did not know which datamapper to check.

Now there is a very useful button which could help us here. On the Datamap administration view, there is a validate button on the top applet. It checks the structure of the mapped IOs with the ones compiled into the SRF and threw up validation errors. For some time now I have been wondering the functionality behind this button.
I found this in the Siebel log files when the button was clicked:

Begin: Business Service 'EAI Data Transformation Engine' invoke method: 'Validate'

But if you check the definition of this BS in tools, you will not fin the Validate method. But after a little more tweaking, I was able to figure out the input parameters. One thing I found was that if the Datamap is valid, the BS does not return or throw any message, and if there is any validation error, it throws an exception. Hence if multiple datamps need to be validated, the try catch loop must be put inside a loop. I wrote a simple script at client side services which validates multiple datamaps in one go. The search spec can be modified according to your project requirements.


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function Service_PreInvokeMethod (MethodName, Inputs, Outputs)
{
var oBCDataMap = "";
var sMessage= "";
var iCount = 0;
oBCDataMap = TheApplication().GetBusObject("EAI Data Map").GetBusComp("EAI Object Map");
oBCDataMap.ClearToQuery();
oBCDataMap.SetSearchSpec("Source Object Name","*");
oBCDataMap.ExecuteQuery(ForwardOnly);
var oBSDTE = TheApplication().GetService("EAI Data Transformation Engine");
var psInput = TheApplication().NewPropertySet();
var psOutput = TheApplication().NewPropertySet();
var bIsRecord = oBCDataMap.FirstRecord()
while(bIsRecord)
{
psInput.Reset();
psOutput.Reset();
try
{
psInput.SetProperty("MapName",oBCDataMap.GetFieldValue("Name"));
oBSDTE.InvokeMethod("Validate",psInput,psOutput);
}
catch(e)
{
sMessage = sMessage + oBCDataMap.GetFieldValue("Name") + ":" +e.toString() + "\r";
}
iCount = iCount + 1;
bIsRecord = oBCDataMap.NextRecord();
}

sMessage == "" ? TheApplication().RaiseErrorText(iCount + " Datamaps validated successfully.") : TheApplication().RaiseErrorText(sMessage);
return (CancelOperation);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


When the code is execute, it validates all Datamaps using the EAI Data Transformation Engine BS's Validate method, and presents the errors in a message box.





You can hit Ctrl-C now to copy this message, and paste this in notepad.
AMSRefData_ServiceCenter:Parent component map 'q' not found.(SBL-EAI-04061)
AMSRefData_Service_Func:Parent component map 'q' not found.(SBL-EAI-04061)
What'ya think ?

Monday, August 2, 2010

Parent Child Relationships in VBCs - BC User Property : "Populate Child Data"

Virtual Business Components provide for a nice way of presenting data via WebServices. Each time the VBC is loaded/refreshed in the UI, the integration is triggered behind it, and resulting response appears in the UI. But what if there is a parent child relationship in the data being returned and the requirement is to present each set of the hierarchy in a separate applet ? In normal BCs, the data is pulled from the tables, and if links are provided, the child BC gets refreshed when the parent BC is changed. How can we achieve the same in VBCs ? There is a little unknown BC userproperty “Populate Child Data”, which can be used to achieve this nice effect, without scripting, or repeatedly invoking the webservice. Here is what you do.

 

·         Create the two VBCs and the two applets for them. Also created the BO and View based on the BO.

·         Both the VBCs must refer the same IO,either via the BC userpoperty “Outgoing Integration Object Name”, or the IO name gets hardcoded in the WF.

·         The IO should have two ICs, one for parent level and one for child level in response data. The external names must be correctly populated with the BC names created.

·         Link must be created between parent and child BCs. This BC has to be added in the BO.

 

Now if everything is correctly configured, compile everything and fire up the client application. Navigating to the view will bring the data correctly in the two applets, correctly maintaining the parent child relationship between them. Moving to the next record at parent level will refresh the child level data, as the link is in context.

 

Now go ahead and check out the integration logs for this integration. There is a nice tutorial here.

 

You will find that the webservice integration was actually triggered twice, once for each level of hierarchy. The same request goes out and the same response comes back, so it means double the work. Now :

 

·         Go to the child BC you created. Add a new BC userproperty :

·         In the name column, provide : “Populate Child Data”

·         In the value column, provide : “Y”

 

Compile the BC and load the view again. Data still comes as expected in the UI alright, but if you check the integration logs, you will see that the web service was invoked only once.

 

BC user property “Populate Child Data” doesn’t look documented in bookshelf or supportweb. If you are not happy with this approach, there is a scripting alternative suggested on supportweb here.

 

 

 

Tuesday, June 15, 2010

Testing Webservices outside Siebel / Testing Inbound Siebel Webservices - using WGET

I am a Siebel EAI developer. But sometimes I feel that Siebel does not provide the freedom to properly play around with webservice settings, or to test them properly. In most projects, we use a third party tool like SOAP UI or XML SPY to test inbound Siebel webservices. Sometimes when an outbound webservice call from Siebel fails, we try to reproduce the error from SOAP UI to try and find out if there is something wrong in the Siebel configuration. While most developers love the fact that SOAP UI is free and can consume  WSDLS and generate SOAP files, I find it terribly slow. Also, when working on client machines via an RDP/MSTSC connection, I need quick results and cannot wait for SOAP UIs resource hungry interface to load up. Altova XML Spy is faster, but its not free.

 

I set out to find another way to test webservices without using and costly or resource hungry tool. And I found a solution on Unix.

 

Unix developers are well aware of and have been using a command called wget to test http and soap interfaces. Wget is a powerful unix command which can be used to download content, post Http requests, and now even SOAP requests, as I found out. If you have a valid SOAP request, all you need is to send it across to a webservice/url, you can use Wget to do this.  This command has been ported to windows here.I have been using this trick for months now, and it has saved me looaadss of time.

 

Essentially, a SOAP request contains 3 parts

 

·         SOAP Header

·         SOAP Body

·         RAW Parameters / SOAP Parameters

 

The  SOAP Header and Body is as name suggests, contains schema information and data. The SOAP parameters contains additional info as to which url is to be hit and what is the format. Also there is one parameter for length, which contains the length of the soap message (header + body) in char counts. So, the length of the soap message has to be sent.

 

At Siebelunleashed, Neel explains how to trigger outbound webservice from Siebel. I will explain how to do the same thing from outside Siebel.  The example here again uses the GeoIPservice.

 

If you go this link, you will see the actual SOAP request for the service.

 

POST /geoipservice.asmx HTTP/1.1

Host: www.webservicex.net

Content-Type: text/xml; charset=utf-8

Content-Length: length

SOAPAction: "http://www.webservicex.net/GetGeoIP"

 

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

  <soap:Body>

    <GetGeoIP xmlns="http://www.webservicex.net">

      <IPAddress>string</IPAddress>

    </GetGeoIP>

  </soap:Body>

</soap:Envelope>

 

Here, the section in blue is the SOAP/RAW parameter section. And the length highlighted in bold has to contain the length of the soap request. After we frame this entire request, we have to send it across as an HTTP request.

 

Here is what we do.

 

1.     Create a folder on your desktop. Download wget for windows. Don’t worry, its free and safe J

2.     Create three files in your folder

·         Req.xml -  this will contain the soap message

·         url.txt – this will contain the url

·         send.bat – we will automate this in a bat file.

3.     Open up req.xml in notepad and enter this.

 

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

  <soap:Body>

    <GetGeoIP xmlns="http://www.webservicex.net">

      <IPAddress>216.239.51.99</IPAddress>

    </GetGeoIP>

  </soap:Body>

</soap:Envelope>

 

The ip here is that of Google. We shall see where google’s servers are located.

 

4.      Open up url.txt and enter this

 

http://www.webservicex.net/geoipservice.asmx

 

You will get this address from the WSDL. Open up the WSDL and look for a section called http:address

 

<wsdl:port name="GeoIPServiceHttpPost" binding="tns:GeoIPServiceHttpPost">

  <http:address location="http://www.webservicex.net/geoipservice.asmx" />

 

 

5.     Open up the send.bat file in notepad and enter this

wget  --input-file=url.txt   -nv --post-file=req.xml  --output-document=resp.xml   --header="Content-Type: text/xml" --header="SOAPAction: "http://www.webservicex.net/GetGeoIP"

 

notepad resp.xml

 

6.     Your folder should now contain 4 files. Execute send.bat, either by double clicking or from run command.

 

In a moment, the SOAP request will be sent across and the response should open up in notepad.

 

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetGeoIPResponse xmlns="http://www.webservicex.net"><GetGeoIPResult><ReturnCode>1</ReturnCode><IP>216.239.51.99</IP><ReturnCodeDetails>Record Found</ReturnCodeDetails><CountryName>UNITED STATES</CountryName><CountryCode>US</CountryCode></GetGeoIPResult></GetGeoIPResponse></soap:Body></soap:Envelope>

 

 

The response shows us that the 216.239.51.99  is in UNITED STATES.

 

When we run the bat file, wget takes the req.xml file and adds the header parameters we specified.

 

wget  --input-file=url.txt   -nv --post-file=req.xml  --output-document=resp.xml   --header="Content-Type: text/xml" --header="SOAPAction: "http://www.webservicex.net/GetGeoIP"

 

Here the parameters are Content-Type and SOAPAction. Inaddition, WGET also adds the content length required for the request.  WGET provides a debug option to see the complete request going out. Just add –debug in the beginning like this

 

wget  --debug --input-file=url.txt   -nv --post-file=req.xml  --output-document=resp.xml   --header="Content-Type: text/xml" --header="SOAPAction: "http://www.webservicex.net/GetGeoIP"

 

You will see the response with debug information like this.

 

C:\test>wget  --debug --input-file=url.

txt   -nv --post-file=req.xml  --output-document=resp.xml   --header="Content-Ty

pe: text/xml" --header="SOAPAction: "http://www.webservicex.net/GetGeoIP"

Setting --input-file (input) to url.txt

Setting --no (verbose) to 0

Setting --post-file (postfile) to req.xml

Setting --output-document (outputdocument) to resp.xml

Setting --header (header) to Content-Type: text/xml

Setting --header (header) to SOAPAction: http://www.webservicex.net/GetGeoIP

DEBUG output created by Wget 1.11.4 on Windows-MSVC.

 

Loaded url.txt (size 44).

seconds 0.00, Caching www.webservicex.net => 209.162.186.60

seconds 0.00, Created socket 1932.

Releasing 0x00985058 (new refcount 1).

 

---request begin---

POST /geoipservice.asmx HTTP/1.0

User-Agent: Wget/1.11.4

Accept: */*

Host: www.webservicex.net

Connection: Keep-Alive

Content-Type: text/xml

Content-Length: 370

SOAPAction: http://www.webservicex.net/GetGeoIP

 

---request end---

[writing POST file req.xml ... done]

 

---response begin---

HTTP/1.1 200 OK

Connection: keep-alive

Date: Tue, 15 Jun 2010 08:12:10 GMT

Server: Microsoft-IIS/6.0

X-Powered-By: ASP.NET

X-AspNet-Version: 2.0.50727

Cache-Control: private, max-age=0

Content-Type: text/xml; charset=utf-8

Content-Length: 519

 

---response end---

Registered socket 1932 for persistent reuse.

2010-06-15 01:12:10 URL:http://www.webservicex.net/geoipservice.asmx [519/519] -

> "resp.xml" [1]

FINISHED --2010-06-15 01:12:10--

Downloaded: 1 files, 519 in 0s (2320 GB/s)

 

C:\test>notepad resp.xml

           

      Notice the content length (370) added by WGET.

 

 

 

Conclusion : WGET is a powerful tool which can be used to test webservices without using tools like SOAP UI or XML SPY. In fact, this is exactly what SOAP UI does, but in a more fancy way. Similarily, WGET can also be used to test inbound Siebel webservices.

 

 

I discovered WGET it only because I wanted a quick and efficient way to testing webservices on windows as well as unix. Now I can test webservices without installing shareware or when I don’t have admin rights to install them. Hope this helps Siebel and non Siebel developers in their work.

 

 

May the source be with you.