Quick GenBScript By fkirill

Recently, I was contacted by Siebel Master Kirill Frolov, who shared with me his new Browser Script generation tool. What I found impressive about this tool, is that it can generate browser scripts in under 5 seconds!.

This is really exciting, and I’m sure you guys/gals will think so too. The following article was written by Master Frolov, to explain the design of his program.

-----------------------------------------------

Brief Introduction

All of us, those who deal with Siebel customization in local machines, know that GenBScript generates browser scripts by parsing SRF fie and puts them into a special folder and this folder is names uniquely based on some not very obvious rules. The process itself takes (depending mostly on CPU) from 1 to 3 minutes.

If you have automatic SRF compilation during the night, you have to use GenBScript every morning when you replace the SRF.

Additionally if you have several environments (prod, prod copy for support, upcoming release test, integration test, load test etc. to name a few) and you have to switch from one environment to another throughout the day, time consumed by GenBScript may reach up to 1 – 1.5 hours.

Though incremental compilation of an applet with browser script puts browser scripts in the right directory (if you managed to set up the corresponding options in Tools), the are still a lot of cases when you need to run GenBScript by hand.

The proposed method allows quick and painless method of producing the same result as GenBScript but using slightly different approach to gain performance improvement.

Our tests show that in most cases it gives less than 10 seconds per run (mostly around 5).


Idea behind the proposal

My goal was to reproduce the result of GenBScript as close as possible so first of all I prepared the list of questions needed to be solved for that purpose:

1. How to determine the folder name to which GenBScript result is placed?

2. What’s the difference between the script sources in editor and the resulting scripts in *.js files?

The idea behind the method is to use script sources from database instead of SRF file to produce result as close as possible to original GenBScript and do it as quickly as possible.

To answer both of these questions we need to perform some analysis.

Firstly about the folder name. The folder name is constructed using two parts:

srfXXXXXXXX_YYY. For those of you who are familiar with unix or java, it should be familiar that the time is measured by counting seconds (or milliseconds) from 1st of Jan, 1970. So after some research I realized that XXXXXXXX – is the number of seconds passed from 1st of Jan 1970 when then last full or incremental compilation took place. The seconds part YYY seems to be dependent of whether the SRF is a full compile or an incremental compile.

The problem here is that XXXXXXXX not a creation or modification date of SRF file itself, but a part of an internal record in SRF file.

To approach this issue we need to remember that some time ago there was an article in one of Siebel-related forums stating that SRF file is no more than bare OLE document (which is also used by older versions of Microsoft office system) which is essentially a container format which has its own internal file system. By the way you can easily prove that opening SRF file in 7-zip archive manager which supports this format.

So after some effort I found out that the number of seconds from 1st of Jan 1970 is stored in one of two records which named… surprise-surprise… “Full Compile” and “Last Incr. Compile” respectively and are stored in the root of internal file system. Both of those records have 384 bytes in length and the seconds value is stored in bytes 4-5-6-7 (in reverse order).

So we need to parse SRF records to find one of the entries named “Full Compile” or “Last Incr. Compile”. If latter is found then we have an incremental SRF otherwise full-compiled. The second part YYY as I already mentioned depends solely on whether SRF in question is incremental or full compile. Respectively you need to use 612 for incremental and 599 for full compile.

The second question. How to organize script source code (which we have in repository database) into a bunch of script files. Well, I found out that there are quite a few changes between source code in repository and resulting script files.

1. Scripts are aggregated to parent object. This means that there is one script file per Applet/Business Service/Business Component/Application (with some minor exception for an Applet objects)

2. Names of pre-defined functions are prefixed with escaped name of a parent object

3. Applets have two script files one for controls and one for all the other functions.

I will omit all the details here, this is not really complex. You can look up source code if you wish to find them out yourself.

The implementation

The program is written in Java as single Java-file which contains numerous child subclasses.

To parse OLE file format I used apache POI library which has convenient methods to parse office documents (the funny thing is that file format is called HPSF which stands for Horrible Property Set Format :-) ).

To perform database operations I used jdbcType4 Oracle driver (jdbc6,jar from jdbc/lib folder of Oracle installation home).

Note about supported databases: in theory program should work in any database used in develpoment environment (I mean Sybase (through ODBC), MSSQL (through ODBC) and Oracle (native type 4 (thin), native type3 (TNS) or ODBC). I don’t have any idea about more exotic DB2 but I assume they are not used in development very frequently anyway. I tested only for Oracle but kept in mind other databases during development.

Testing method I used is standard text-compare. The only issue I ran into is that there is no specific order of methods in repository for browser script as they present for server scripts. This make impossible to make binary compare between GenBScript and QuickGenBScript. No other script text differences were identified.

The program was written in one working day, it is fairly small (around 700+ LoC). I and two of my colleagues use it permanently for several week already, no issues found so far.

Installation/Configuration
The program itself is run without any input parameters. This is done intentionally to promote ease of use. Based on my experience, it is easier to spend some time for initial set up than to enter some parameters each time you need to run it.

So the configuration is done through editing two text files (db.properties for database parameters and srf.properties for srf parameters). The program looks for these files in working directory (may not be the same as program directory). If you need to run QuickGenBScript for several environments it is worth doing several folder (each folder for single environment) and place both of db.properties and srf.properties in each of those folder. Then setup environment parameters for each environment and bat-files to run QuickGenBScript in those folders. Alternatively you can set up several installations of QuickGenBScript since it is quite small anyway.

What to configure.

db.properties
ConnectURL - url to database according to syntax for a given driver. Example: jdbc:odbc: for ODBC driver, jdbc:oracle:thin:@:: for Oracle thin driver.

DriverClassName - fully-qualified database driver class name. For example, sub.jdbc.odbc.JdbcOdbcDriver for an ODBC driver and oracle.jdbc.OracleDriver for oracle database driver

Login - database user login

Password - database user password

UseSchema - valid values are “true” and “false”. Whether to prefix table names with schema name (required for oracle when user name is different from siebel system user name)

SchemaName - the prefix to use for database table names. Schemas and table names are separated by dot (“.”)

RepositoryName - the name of Siebel repository to use as a source of browser script data. Normally this should be “Siebel Repository”

ShowSQL - whether to show SQL generated and some more debug output. Normally should be “false”

srf.properties
PathToSRF - path to SRF for which you need to generate browser scripts. It is used to find out the folder name where resulting scripts will be stored.

IMPORTANT: in *.properties files back-slach (“\”) must be DOUBLED. For example c:\Siebel\Client\PUBLIC\ENU\Siebel_SIA.srf transforms to c:\\Siebel\\Client\\PUBLIC\\ENU\\Siebel_SIA.srf

FullCompileSuffix=599. You need to run original GenBScript againts a full-compile SRF file and find out which is the suffix for directory where it puts generated files. In version 8.0 this is 599.

IncrementCompileSuffix=612. The same for increment SRF.

TargetDir - the root public\enu directory where generated files should be stored.

IMPORTANT: IMPORTANT: in *.properties files back-slach (“\”) must be DOUBLED. c:\Siebel\Client\PUBLIC\ENU turns to c:\\Siebel\\Client\\PUBLIC\\ENU

TargetEncoding=utf-8. Target encoding for generated scripts. Leave it as it is.

How to run
Prerequisites: JRE or JDK version 1.6. I assume java.exe can be found in PATH, so no java path is present in run.bat

run.bat contains a single line code which essentially includes apache POI, database library (jdbc6.jar in distributive) and QuickGenBScript.jar which contains all the class.files from QuickGenBScripts (quite a few).

Unfortunately initial implementation requires quite a lot of RAM to run (300M is enough). This is due to the fact that SRF file contains > 70 000 entries (in our case) which need to be parsed.

Additionally I published Eclipse project containing all that is required to run and debug QuickGenBScript in Eclipse environment.

PS: Sorry guys. almost no comments in source code, I’m just really very busy nowadays with my full-time job. I’m a bit ashamed to produce code without comments, but... That’s life. Besides, I’m willing too much to share this interesting research project with you.

Screenshots
With option ShowSQL=true


With option ShowSQL=false


References:
SourceForge download page:
https://sourceforge.net/projects/quickgenbscript/files/

Source code can be obtained via SVN
svn co https://quickgenbscript.svn.sourceforge.net/svnroot/quickgenbscript quickgenbscript

Official notice: QuickGenBScript is purely for development tool, use it on your own risk. Though it’s working, it is experimental and completely unsupported by Oracle. NEVER USE IT IN PRODUCTION ENVIRONMENT!!! Nevertheless, I believe many of you will like it.
-----------------------------------------------

Thanks to Kirill, for providing the community with greater insight into the inner workings of Siebel, and improving the lives of all Developers.

I think there is one aspect that would really top this off. How do we automatically discover the suffix code for Full and Incremental compiles? I think the answer is in the SRF, consider it a challenge =).

Solution - Mouseover Tooltips (Scriptless) Part 2

This is the final article in our Impossible Tooltips challenge, if you have arrived here by accident, have a read of the precursor articles before going further.

1. Tooltips Challenge
2. Tooltips Solution Part 1
3. Tooltips Solution Part 2 (You are here)

The solution below has been freely available on the Impossible Siebel group for over a month now, and has been available to hundreds of people.

If you havnt already joined, or dont have a friend who is in the group to give you the inside information on our Siebel challenges, join now! There is no non disclosure agreement, take the information and share it.

Originally, I posted this tooltip challenge 6 months ago, but the seed for these articles started over a year ago, does any one remember the first Impossible Siebel poll? Interestingly the tooltip solution finished last on the results.


To quickly refresh your memory, in the last article, we injected artificial browser events into the label caption and used to HTML to display our Tooltips, but that solution had two drawbacks.

1) Unlimited text
2) Dynamic text

The more "important" issue here is the text length, but both these problems can be killed with one stone.

[Scriptless Solution]

The usefulness of the label caption is limited by its text length, but we can cheat by using a calculated field and put it in the position of the label, to act as the 'label' on the form applet.

This can be a little tricky, so we'll start with a basic example on how to implement this.


"<p onmouseover='alert(""Disco Forever"")'>Disco</p>"

Notice that with calculated fields, we need to enclose the expression with double quotes, and also escape any double quotes to become a pair of double quotes. There is no way to quickly simulate calculated fields, so an incorrect attempt at this expression may suggest that the idea dosnt work.

So here is our calculated field expression, with escaped quotes.

"<p onmouseover='var d=document.createElement(""div"");d.id=""t"";d.innerHTML=""Hey"";this.appendChild(d);' onmouseout='var d=document.getElementById(""t"");d.parentNode.removeChild(d);'>Disco</p>"

Create a field control, ensure that the control is set to dontencodedata and HTML Type is set to Plain Text. Map this control to your applet mode, compile these changes, and you'll notice that the real label and the calculated field behaves the same on surface value.

By using calculated fields, we can concatenate several other calculated fields together to get around the character limit, and by the nature of calculated fields, we can also take advantage of the fact that we can pull data dynamically through them. For example, we can retrieve other field values, get profile attributes, and even call business services.

However using calculated fields in this way will become incredibly complicated, especially if you have more than one field. Every field might have multiple concatenations, and the logic for creating and display the tooltips could be duplicated hundreds of times. Imagine having to change the style of the tooltip across the application, this will be quickly become unmaintainable.

This concept is only provided to illustrate that it can be done without scripting, but for practicality writing script in this case is much more sensible.

[Scripting Solution]

We will create two custom global browser script functions called showDiv() and hideDiv(), which will be fired by our artificial onmouseover and onmouseout events. This will offload the creation, as well as the styling of our tooltips, to a central place. Then all we need to do, is pass parameters to these functions, to display the tooltip.

The following example creates a really simple tooltip, but what you can do with it is only limited to your HTML skills.

Eg. you can make it float rather than append, you can add pictures, titles bars, rounded corners, play a sound etc.

Modify the calculated field, or Label to look like this:

"<p onmouseout=top.hideDiv(this) onmouseover=top.showDiv(this,'Hey')>Disco</p>"

In your Application browser script or business service, attach the following functions to your "top" object.

top.showDiv=function(that,m) {
var d=that.document.createElement("div");
d.id="Disco";
d.innerHTML=m;
that.appendChild(d);
}

top.hideDiv=function(that){
var d = that.document.getElementById("Disco");
if (d!=null) d.parentNode.removeChild(d);
}


The "expresssion" in this label caption uses about 80 characters, and still leaves a lot of room to display a useful tooltip without using multiple calculated fields, and if you dont require dynamic text, stick to using the label caption, otherwise the calculated field offers a bit more flexibility at the expense of maintenance.

You still can build some logic in the global showDiv() and hideDiv() functions to enable the label method to be a little dynamic, but it depends on how contexual you want your dynamic labels to be.

If you are one of those control freaks, then you also might want to offload the management of the tooltips text to a central location, rather than hardcoding the text as a parameter, we can hard code a reference to the label and perform a lookup.

A modified solution would look like this, create your calculated field as follows

"<p onmouseout=top.hideDiv(this) onmouseover=top.showDiv(this,'MyApplet.MyLabel')>Disco</p>"

In your Application browser script, change your showDiv function as so

top.showDiv=function(that,lov) {
var m = lookupValue("MY_LABEL_LOV_TYPE",lov);//lookupValue is a custom function that retrieves LOV values from the database.
var d=that.document.createElement("div");
d.id="Disco";
d.innerHTML=m;
that.appendChild(d);
}

This way BAU can change the labels without re-compiling the SRF, and provides clients in regulatory situations to quick adapt to changing needs.

[Floating, Appending, Positioning the tooltip]

The solution that i've provided above, appends the tooltip and positions it underneath the label, the position is always relative to the label. Some readers who i gave out the solution to, modified the solution to use absolute X,Y co-ordinates. I've also seen variations of my solution that have been modified to use <span> tags.

I've found that mouseovers dont work correctly on span tags in Siebel, so if you have problems with the mouseover not triggerring, try changing it to a <p> (paragragh tag).

Should you float or append? For short tooltips, appending is easier, because the solution is a lot less complex. When your text or styling makes the tooltip too big, it will start to push your controls out of alignment. To overcome this issue, you need to implement a floating tooltip, as seen on my screenshots on the original challenge.


[Dealing with the ActiveX]

The floating tooltip will not be effective, unless you deal with the ActiveX problem. Web professionals will know that elements on a web page can be layered, and each control can be set with a layer order to make it appear in front or behind another object.

ActiveX controls are a little different, because you cannot set the layer order on these type of controls, they just appear on top of everything else on the webpage. So if you try to implement a floating tooltip that lies in the path of a dropdown box or any other Siebel ActiveX control, your tooltip will be hidden by the control.

To get around this, we have to use a really obscure web developer trick, the "iframe technique".

var if=that.document.createElement("iframe");
if.id="iFrameDisco";
if.style.width = your tooltip width
if.style.height = your tooltip height
if.style.top = your tooltip Y position
if.style.left = your tooltip X position
if.style.zIndex='998';
if.style.filter='progid:DXImageTransform.Microsoft.Alpha(opacity=0)';

The above code creates an iframe of the same size as our tooltip, the next step is to create our tooltip to sit above this iframe (it is important that both the iframe and the tooltip are the same size).

This little trick allows our tooltip to float above the ActiveX controls in Siebel and is the same technique, that i've used in the ImposSiebel toolbar to float the AboutView dialog on top of the Siebel ActiveX elements.

[Conclusion]

This solution is unconventional, even if you consider the scriptless option, and depending on what kind of effect you are after, it can become very complex, but when used strategically, your users will be happier than any other siebel user in the world.

Keeping your users happy is very critical, and will be the subject of a series of future articles, but for now, the Siebel community can say that our million dollar system can do Tooltips!

Our regular readers probably saw this coming, but this is where we introduce a disco tune to the audience.



I cant think of a better disco tune than "One way ticket" to compliment this article, wether you like Neil Sedaka, Eruption or Boney M, this is a killer disco track.

Solution - Mouseover Tooltips (Scriptless) Part 1

I've been receiving a lot of requests from Siebel professionals to provide the solution to the tooltips challenge, and though i've provided the solution privately to needing customers, i've realised that implementing it can be tricky, so in this article so i'll provide a walkthrough of the fundamental configuration needed to achieve a basic solution.

[Background]

To provide some perspective on this problem, lets have a look at a real life scenario from a customer on the Oracle forums.

"We have been struggling with a user request:

The users have requested that we change default Siebel Tooltip behavior so that if we hover the mouse over some select fields(In this case a credit code, among others) that the tooltip contain information that can help the user to understand the value. Whether this is the definition of the actual value or a short list of actual values is still up for debate. Alternate approaches like populating the status bar with a value, theoretically the definition of the current value, and providing a help icon with a tooltip or message that contains reference info for the column below, have been discussed, but these are not preferred.

So has anyone ever tried to highjack the tooltip functionality? I'm not going to say that the existing functionality (Displaying the full value of the current field) isn't useful in many cases, but that functionality is useful for the codes that we are looking at(WHich are typically smaller then the existing field) and this would be a far better use of the functionality.
"

source: http://forums.oracle.com/forums/thread.jspa?threadID=577955&tstart=525

[Million dollar system]

The Siebel UI can be quite overwhelming, so its understandable that business want to implement tooltips, to provide its users with visual clues and help the user perform their duties. This is the one requirement that every BA has asked once in their Siebel career.

But when the business ask for a simple feature such as floating tooltips, and we say its not possible. It becomes a little embarasing, when they ask why a system, they've spent millions of dollars on, cant offer tooltips, which have been around since the beginning of the web.

[Workaround]

A primitive technical solution to this, is to utilise the caption override on the label, and hard code text into the alt or title attributes.
<span alt='Disco Forever'>Disco</a>

This dosnt meet the requirement of the impossible challenge, but it also has an annoying side effect, in that the tooltip vanishes too soon. So if you want to provide a few lines of text for the user to read, they'll have roughly 5 seconds to read it all, before it disappears.

Some readers have reasonably guessed that we need to use the onmouseover and onmouseout events in browser script control events to deliver this solution, as it is the most obvious mechanism to create a floating dialog, however the only problem is, these browser events are not available in HI environments, and it also involves scripting.

But read on, and i'll show you how to bypass these obstacles.

[Solution]

To get around the HI browser events limitation, we can inject custom onmouseover and onmouseout events on the label caption as so.
<p onmouseover='<Show our tooltip>' onmouseout='<Hide our tooltip>'>Disco</p>

This lays the foundation for the rest of the challenge, and offers us the launchpad to use some HTML magic to display our tooltips.

Here is the caption override that is needed to display a tooltip.
<p onmouseover='var d=document.createElement("div");d.id="t";d.innerHTML="yeah";this.appendChild(d);' onmouseout='var d = document.getElementById("t");d.parentNode.removeChild(d);'>Disco</p>

What the above syntax does, is creates a DIV element on the fly and injects it underneath the current object, which in this case is our field label object.

Our label now has two custom events that will fire off code to display and hide the tooltip accordingly. The tooltip will hang around as long as the mouse cursor is hovered over the label, and disappear swiftly when the mouse moves away.

But lets not celebrate so soon, because this solution has the following draw backs, the tooltip text is limited by the repository length of the caption field, our creativity with the tooltips is also severely limited by the caption length, and hard coding the text here would make it difficult to maintain.

We can dress it up by adding a little style
<p onmouseover='var d=document.createElement("div");d.id="t";d.innerHTML="yeah";d.style.backgroundColor="red";d.style.borderColor="black";this.appendChild(d);' onmouseout='var d=document.getElementById("t");d.parentNode.removeChild(d);'>Disco</p>

This looks a little better, but uses it up every (255) valuable character, and leaves no room for a useful tooltip.

This is the most "vanilla" result, and is not very useful, but it does provide the basic framework for others wishing to get further with this challenge.

[Until next week]

The most important hurdles have been taken away

1) Mechanism to Display/hide a persistent floating tooltip
2) Achieved by using a caption "expression" and hence Scriptless

But the following aspects of the challenge remain un-met

3) Unlimited text
4) Dynamic text

In the next article, i'll provide the full solution and bust the myth that Siebel cant do tooltips.

Ultra browser script generator 2

A fellow colleague had a chance to test my new Ultra GenB script progress screen enhancement, and the feedback was:

"Every developer should have this"

If you dont know what the excitement is all about, a while ago i presented the Ultra GenB script generator, a free utility to ease the pains of generating browser scripts. This time i've come back with an enhancement to the original program.

The time need to generate browser scripts varies, depending a lot of factors such as the amount of browser scripts you have in your application, the amount of memory/ disk space/CPU utilization currently being used, and Genbscript.exe also runs faster off a fully compiled SRF, compared to incremental compiles, so you could be waiting 1-10 minutes for the program to finish not knowing what Siebel is doing in the background.

My browser script generator fills this user experience gap, by providing a visual cues on the progress of genbscript.exe.

[Features]

All the wonderful features of original +
1) Displays the name of the file currently being generated
2) Displays how many files have been generated so far
3) Turns Red to signal failure or user action
4) Turns Green to signal success





Note: Feature 1, works by polling the file system, so the results are not real time, hence your experience will vary depending on how fast or slow your system is running.

The file and source code can be downloaded freely from my LinkedIn Group: Impossible Siebel

Reader Challenge - Popup Applet "X" button

[Requirement]

"How to show alert to user after closing a Pick Applet from the "X" button [top right corner]. I want to show the alert or confirm(yes/no) box just after closing the pickapplet.

I tried using the window.onunload event in browser script of pickapplet, but it didn't worked.

please help"

Source: Oracle Forums
Link: http://forums.oracle.com/forums/thread.jspa?threadID=924827&tstart=195

[Challenge]

To clarify, the developer wants to display a confirmation dialog after the applet has been closed, and not to prevent the applet from being closed.

There are a few solutions that come to mind.

1. Put some code on the applet that invokes the popup applet, when focus returns to the first applet, pop up the dialog.

This is ugly because you need to put code on all the base applets across the application that use this popup applet.

2. OnLoad of the pop up applet, create a looping mechanism to check the name of the active applet, when the active applet is no longer the active popup applet, pop up the dialog.

This solution dosnt provide a real time notification, and creates un-neccessary load on the application and browser.

So your challenge is to find an alternative solution, which should be pretty tough ruling out the above possibilities.

To test the water, I seeked opinion from Michael Feng, of scriptless VBC fame, who initially dismissed it as impossible, but when I said, there is a solution.

He came up with a concept and a working solution in a few days. His solution allowed an alert to be displayed in REAL TIME when the X was clicked on a popup applet.

Its been a year since the above requirement was posted to the Oracle forums, if you are the author of the above post, or you are a customer who needs the solution, send me a message on LinkedIn, and i'll gladly fill you in.

To keep you entertained until then, heres a flash back to the 80s, and an introduction to "Joy", the greatest band to come out of Austria.



Joy enjoyed success across Europe and East Asia, with numerous hits such as Touch by touch, Hey Hello, and Valerie.

XSLT 1.0 upper-case() & lower-case()

In the last article, we looked at using XSLT "includes", and along the way, encountered a requirement to convert a string to uppercase in XSLT 1.0.

XSLT 2.0 users have the luxury of upper-case() & lower-case(), but oddly, functions for converting characters to upper and lowercase are not available in XSLT 1.0.

XSLT isnt the mother language of most Siebel professionals, or if you dont use it everyday, youre going to get rusty (i know i am), so this walkthrough should appeal to a lot of readers.

Lets take a look at our XSLT functions file from last time
<!--XSLTfunctions.xslt-->
<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" /> 
    <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" /> 
    <xsl:template name="FORMATBOOLEAN">
        <xsl:param name="BooleanChar"/>
        <xsl:choose>             
            <xsl:when test="translate($BooleanChar, $smallcase, $uppercase)='Y'">true</xsl:when>
            <xsl:when test="translate($BooleanChar, $smallcase, $uppercase)='YES'">true</xsl:when>
            <xsl:when test="translate($BooleanChar, $smallcase, $uppercase)='TRUE'">true</xsl:when>
            <xsl:otherwise>false</xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>


It works by taking a string value, converting it to uppercase and comparing it to 3 static values, but with a little bit of effort, we can optimise it to be more efficient. Instead of calling translate on the same variable 3 times to get the same result. We will engineer it so its only called once.

We start by creating our own custom UPPER and LOWER functions
    <xsl:template name="UPPER">
        <xsl:param name="text"/>
        <xsl:value-of select="translate($text, $smallcase, $uppercase)"/>
    </xsl:template>
    
    <xsl:template name="LOWER">
        <xsl:param name="text"/>
        <xsl:value-of select="translate($text, $uppercase, $smallcase)"/>
    </xsl:template>   


In XSLT we cannot reassign the value of a variable once it is declared, so we create a new variable called $BooleanCharUPPER,and call the UPPER function from inside our FORMATBOOLEAN function and return the result.
    <xsl:template name="FORMATBOOLEAN">
        <xsl:param name="BooleanChar"/>

        <xsl:variable name="BooleanCharUPPER">
            <xsl:call-template name="UPPER">
                <xsl:with-param name="text">
                    <xsl:value-of select="$BooleanChar"/>
                </xsl:with-param>
            </xsl:call-template>
        </xsl:variable>  
  
    </xsl:template>


Finally we evaluate the $BooleanCharUPPER against our static values.
        <xsl:choose>             
            <xsl:when test="$BooleanCharUPPER='Y'">true</xsl:when>
            <xsl:when test="$BooleanCharUPPER='YES'">true</xsl:when>
            <xsl:when test="$BooleanCharUPPER='TRUE'">true</xsl:when>
            <xsl:otherwise>false</xsl:otherwise>
        </xsl:choose>  


We can now use these functions in any XSLT, where we've included them
        <xsl:call-template name="UPPER">
            <xsl:with-param name="text">
                <xsl:text>bad boys blue</xsl:text> 
            </xsl:with-param>
        </xsl:call-template>

Result: BAD BOYS BLUE

        <xsl:call-template name="LOWER">
            <xsl:with-param name="text">
                <xsl:text>BAD BOYS BLUE</xsl:text>
            </xsl:with-param>
        </xsl:call-template>

Result: bad boys blue

Here is the final XSLTFunctions.xsl file.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  
    <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" /> 
    <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" /> 
    
    <xsl:template name="UPPER">
        <xsl:param name="text"/>
        <xsl:value-of select="translate($text, $smallcase, $uppercase)"/>
    </xsl:template>
    
    <xsl:template name="LOWER">
        <xsl:param name="text"/>
        <xsl:value-of select="translate($text, $uppercase, $smallcase)"/>
    </xsl:template>   
    
    <xsl:template name="FORMATBOOLEAN">
        <xsl:param name="BooleanChar"/>
        <xsl:variable name="BooleanCharUPPER">
            <xsl:call-template name="UPPER">
                <xsl:with-param name="text">
                    <xsl:value-of select="$BooleanChar"/>
                </xsl:with-param>
            </xsl:call-template>
        </xsl:variable>        
        <xsl:choose>             
            <xsl:when test="$BooleanCharUPPER='Y'">true</xsl:when>
            <xsl:when test="$BooleanCharUPPER='YES'">true</xsl:when>
            <xsl:when test="$BooleanCharUPPER='TRUE'">true</xsl:when>
            <xsl:otherwise>false</xsl:otherwise>
        </xsl:choose>        
    </xsl:template>
   
</xsl:stylesheet>


Bad Boys Blue, are a eurodance group that came to fame around the same era as Modern Talking and Sandra back in the 80s, and like many of their contemporaries, their music evolved from the more traditional europop to a more upbeat eurodance style. Its hard to pick a favourite BBB track, but check out "You're a woman, i'm a man" for a little taste of their magic.

XSLT 1.0 include

A few years back, I ran a technical session for a client, on how to use XSLT to solve tricky Siebel problems and i came to realise that not every developer is exposed to XSLT.

On some projects XSLT is handled by the middleware team, and Siebel professionals just send across the raw Siebel Message for the external team to perform the transformations.

In a recent discussion with a new client, they wanted to upgrade to XSLT 2.0 to take advantage of include in XSLT to reduce the size of all their XSLTs. I advised them that it was not necessary to upgrade the XSLT engine for this reason, because this feature already exists in XSLT 1.0.

Keen readers of Impossible Siebel would know that the engine behind the EAI XSLT Service, which is used to transform all XML in Siebel, uses XSLT 1.0.

Casual implementors of XSLT might not know about the include statement, but this feature allows you to declare all your XSLT functions in a seperate file, and import it into the current stylesheet.

The following sample shows how to include an external file containing some XLST functions.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:include href="XSLTfunctions.xslt"/>
</xsl:stylesheet>

<!--XSLTfunctions.xsl-->
<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" /> 
    <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" /> 
    <xsl:template name="FORMATBOOLEAN">
        <xsl:param name="BooleanChar"/>
        <xsl:choose>             
            <xsl:when test="translate($BooleanChar, $smallcase, $uppercase)='Y'">true</xsl:when>
            <xsl:when test="translate($BooleanChar, $smallcase, $uppercase)='YES'">true</xsl:when>
            <xsl:when test="translate($BooleanChar, $smallcase, $uppercase)='TRUE'">true</xsl:when>
            <xsl:otherwise>false</xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

In the above example, i've presented a function to ensure that booleans are formatted consistently, this can helpful if you have different source systems that have slightly different representations of booleans.

Since XSLT 1.0 dosnt have upper-case() and lower-case() functions, i used the translate function to perform this operation. The use of translate can be further refactored into a seperate function for speed.

Finally, here is how you would call these external included functions from your XSLT.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:include href="XSLTfunctions.xslt"/>
    
    <xsl:template match="/">
    <xsl:call-template name="FORMATBOOLEAN">
        <xsl:with-param name="BooleanChar">
            <xsl:text>y</xsl:text>
        </xsl:with-param>
    </xsl:call-template>
    </xsl:template >
</xsl:stylesheet>


Result: true

Using the "include" allows you to easily maintain all your XSLT functions in one place, it will reduce the size and clutter of your stylesheets, as well make it lighter and hence perform better, and maximise its re-usability.

In the next article, we'll look at how we can optimize the above function to perform better.

Set Tab layout order defect 8.1.1.2

Last year i looked at a Siebel feature that prevented tab orders from being adhered to on Popup Form applets.

This was tested in 8.1.1.1, but under 8.1.1.2, this solution dosnt work anymore. The background on this can be found here.

[Problem]

The root cause this time around, is just as obscure but with our background on this problem in 8.1.1.1, the reason why it is broken in 8.1.1.2, is more easily identified.

If you recall from last time, Siebel generated the HTML Tab index in the browser source code, but failed to provide it with an identifier.

In 8.1.1.2, Siebel dosnt generate the tabIndex property or its value at all, so the solution i'm about to provide is a going to be another UI hack.

Although it is not as elegant as the last solution, it has the advantage of being backwards compatible and should be quite future proof.

[Solution]

Since Siebel dosnt generate the HTML Tab index anymore, we need to find a way to make this information available to the browser. To be thorough, you should turn on all the hidden properties in Tools, by setting this option in your tools configuration.

ClientConfigurationMode = All

After that exercise, i've found that only the Height/Width properties work. So we are going to pick one, and for this example i'm going to use the control height property and ask that developers populate that with the desired HTML sequence.

When Siebel renders the controls on this applet, it will be stretched out of proportion, because we used the control height property as our HTML Sequence indicator.

To get around this problem, we will manipulate the DOM on applet load and inject the tabIndex property, with the height value that we have configured above, and at the same time restore the height to the standard 24 pixel, for all the field controls on the applet, before the user has a chance to see it.

Heres how its done, copy the following code and put it into your browser applet load.

fixTabOrder8112(this,"any valid control name");

function fixTabOrder8112(that,ctrlName)
{
try {
var oControl = that.FindActiveXControl(ctrlName);
oControl.document.body.style.display="none";
var oObject = oControl.document.body.getElementsByTagName("object");
for (var i=0; i < oObject.length; i++){
oObject[i].tabIndex = oObject[i]["height"];
oObject[i].height = "24";
}
   oControl.document.body.style.display="block";
} catch(e){
} finally {
}
}

If you look carefully, you'll notice that i hide the entire contents of the applet, ensuring that all the controls are invisible while the code re-draws all the controls, and re-displays the content when the routine is finished.

You may or may not notice a small moment of flicker as the applet is being worked on, but it should be un-noticable. To get a second opinion, I asked a BA to watch it in action and watch out for the flicker, and when it was over, she stated "I didnt see any flicker!" If you are testing this, try it out on both thin and thick client to see the behaviour.

This will work for the majority of cases, but if you have a Popup form applet with varying control heights such as text areas, then you have to work a bit harder to get this solution to work.

The basic idea, is to append the HTML sequence to the end of the height property, split the values to get your separate properties values and use the above method to alter your HTML source.

The original defect was discovered in 8.1.1.1, and i was told a fix was pushed for 8.1.1.2. We have discovered that it is still outstanding, and 8.1.1.2 has also broken our fix for 8.1.1.1, but customers who are still suffering from this defect, now have a new solution.

Trap submit button in TBUI

In my last article, we encountered a new behaviour in Siebel that allows TBUI to re-use its buttons and dynamically generate different button labels depending on what view the user is on.

For example, you have 5 views in your TBUI task, on the first 4 views, this button would read "Next", but as you navigate to the final view, this button dynamically changes to "Submit", click "Previous" and it turns to "Next" again.

Image of TBUI Playbar


This behaviour is activated by the following control user property.

DynamicLabel Y

If you are curious enough to look at the web template to see how this works, here is the corresponding section with some cues on how to configure it.

<swe:control id="152">
<!-- Next Button -->
<!-- If of "DynamicLabel" is "Y", it shows "Next"/"Submit"/"Finish" based on -->
<!-- <forward button type> in task step -->
<td class="AppletButtons" nowrap>
<swe:this property="FormattedHtml" hintText="Next" hintMapType="Control"/>//Our magic button
</td>
</swe:control>

As magical as it may be, it causes a problem for anyone who wants to trap the event of a click on the "Submit" button, since the "Next", "Submit" buttons are the same physical button, on the same applet, and fire the same methods, so it makes it quite tricky to detect which "buttons" have been clicked.

The key to this problem is reading the button text when the user clicks on the button and then determine the next course of action. This can be done by trapping the PreInvokemethod, and using browser script to read the button label.

The following code shows how this can be done:


function Applet_PreInvokeMethod (name, inputPropSet)
{
if(name=="NavigateNext"){
sCurrentControlName=getControlLabel(this,"ButtonNext");
}
return ("ContinueOperation");
}

function getControlLabel(that, ControlName)
{
var objControl;
var sControlLabel = "";
try{
objControl = that.FindActiveXControl(ControlName);
sControlLabel = objControl.getElementsByTagName("A")[0].innerHTML;
} catch(e){
alert(e.toString());
}
return sControlLabel;

}


To make things a little more interesting, the final button can have other labels such as "Complete", "Done", "Finalize" and other custom values, and you'll also need to consider what happens when the user cancels or Pauses, in your design.

If you need to trap the "Submit" in TBUI for purposes other than this hack, keep in mind the alternative solution of cloning the applets, as mentioned in the previous article, which will allow you to stay away from the dark side.

Close Task Pane Automatically [ID 781860.1]


[Problem]

In Siebel 8, when a Task Based UI (TBUI) session is completed the task pane remains open, displaying the default task (which could be totally unrelated to the current view), even after the user clicks Submit.

This problem has been raised by the customer of Support Document [ID 781860.1] on Metalink. The customer was told that this behaviour is hard coded and to contact Expert Services.

I dont know if there was a solution provided to the customer, because the document was never updated, but this defect would have problems passing User Acceptance Testing (UAT)

[Toggle Solution]

At first glance, an easy solution would be to hijack the method behind the X button, and invoke it from browser script, but since it is not a documented API, it should be a last resort.

TBUI can be invoked by Ctrl+Shift+Y , which fires a menu command and invokes a Business service to toggle the task pane.
function closeTBUIPane()
{
var BS = theApplication().GetService("Task UI Service (SWE)");
var inputs = theApplication().NewPropertySet();
var outputs = theApplication().NewPropertySet();
outputs = BS.InvokeMethod("ToggleTaskPane", inputs);
}

This would be the ideal solution.

The business service that we are interested in is "Task UI Service (SWE)", it has the following methods

Open,Close and Toggle

The Open,Toggle methods work fine, but the Close methods seems to be disabled. It seems like when Siebel first designed TBUI, they used seperate methods to open and close the task pane, but in the end Siebel replaced it with the Toggle method.

Although we can use Toggle to close the TBUI after the user clicks Submit, but if, on the chance that the user clicks the X button on the task pane in the middle of the task (therefore closing the pane) when the user reaches the end of the task, clicking the submit button to finish would activate the Toggle method and re-open the pane.

Unless we have someway of detecting if the task pane has been already closed and not perform the toggle, this method may not be acceptable. The only way i know of detecting the state of a pane is to check the existence of the frame by using unsupported browser methods, which takes us back to our first solution.

[X Button Solution]

The following line of browser allows us to tap into the method behind the X button, and invoke it from our TBUI applet.
top.SWEFindFrame(top,"SS_TaskUIPane").TaskObj().HandleClose();


Another problem that we'll face is the Next, and Submit buttons are actually the same physical button that call the same method, TBUI will dynamically change the label of the button depending on what view the task is on, which makes this a little trickier.

There are two solutions to this,

1. Make a clone the TBUI applet and use this clone exclusively for the Submit button and put it in the final view

2. Reuse the vanilla TBUI applet and use browser script to read the button text and decide wether or not to close the task pane

The use of undocumented browser methods is not something i would normally recommend, but until Siebel provides a proper fix, this workaround provides customers with a solution that would not cripple the system if the method becomes deprecated.

The worse that can happen is you revert back to the product defect, the upside is that your application dosnt confuse your users and passes UAT.

Siebel 8.1.1.1 system field bug

This was an interesting find by colleage PW, which will surely affect a lot of developers.

The bug? goto any applet, create a control or column, and try to map it to a system field eg. Id, Created, Created By. You'll find that the field dropdown is now a bounded picklist, and will reject your system field.

I dont remember this feature in 8.1.1 or any prior versions of Siebel, it must be a 8.1.1.1 special. You used to be able to type in any field name you want, and compile the applet with no errors (unless you validated the applet).

If the field didnt exist, all that would happen is the field will appear blank on the UI, which is pretty harmless, so its quite a mystery why Siebel made this bounded.

Here is a simple trick that will allow you to workaround this behaviour, without modifying the tools SRF.

First create your system field in the BC (just supply the name), go back to your applet, map the control/column to your field, which will now appear in the picklist, compile and test your applet, then go back to your BC and delete/inactivate that field.

Escaped!

I recently designed some functionality for a Prison department, and i unwittingly named from one my functions Escape. This raised alarm bells in the system, and a couple of men in black, escorted me to an interview room.

I was questioned whether i put some back door functionality to allow unlawfuls to escape. Luckily, the following explanation got me out of jail (The MIB must of known some Siebel).

The functionality that i was building required me to look up a code, and get back the related description. The concept can be seen from the following example.
function Lookup(sType,sValue) {
var sDesc = "";
var oBO = TheApplication().GetBusObject("PickList Generic");
var oBC = oBO.GetBusComp("PickList Generic");

oBC.ActivateField("Type");
oBC.ActivateField("Value");
oBC.ActivateField("Active");
oBC.ActivateField("Description");

oBC.ClearToQuery();
oBC.SetViewMode(AllView);
oBC.SetSearchSpec("Type", sType);
oBC.SetSearchSpec("Value", sValue);
oBC.SetSearchSpec("Active", "Y");
oBC.ExecuteQuery(ForwardOnly);

if (oBC.FirstRecord())
sDesc = oBC.GetFieldValue("Description");
return sDesc;
}

However the lookup value that i was using contained special key words and values which caused my query to fail.

[Fail Scenarios]
var sValue = "Thomas and Dieter";
var sValue = "Thomas or Dieter";
var sValue = "Dieter's the one with dimples";

Lookup("MY_TYPE",sValue);


To understand whats happening, lets have a look at how Siebel generates the SQL
var sValue = "Thomas and Dieter";

SearchSpec: [Type] = "MY_TYPE" AND [Value] = "Thomas" AND [Value] = "Dieter"

Siebel interprets "Thomas" and "Dieter" as two separate conditions and applies the "AND" operator

var sValue = "Thomas or Dieter";

SearchSpec: [Type] = "MY_TYPE" AND ([Value] = "Thomas" OR [Value] = "Dieter")

In this case, Siebel predictably, takes "Thomas" and "Dieter" and applies the "OR" operator

var sValue = "Dieter's the one with dimples";//Error

This will fail.

I would expect this behaviour for SetSearchExpr, but not SetSearchSpec.

[Escape]

To correct this behaviour, we need to escape our search specs.

Heres how we do it.
function Escape(v)
{
return "'" + v.replace(/'/g, "''") + "'";
}

The above function escapes any single quotes in the expression, wraps the entire search spec in single quotes, and also implicitly converts it to a string (This makes a good candidate for an eScript framework function)

So when you apply the above function to the sValue variable, Siebel will take the literal expression.

Unfortunately for me, i put this into a class called terrorist, and created a pointer to function called Escape.
terrorist.Escape

In retrospect, i admit that does look suspicious, I'll think of better class names/function name combinations in future.

The real difference between SWEAlert and alert

[TheApplication().SWEAlert Vs alert]

Veteran Siebel developers will know the textbook difference between theApplication().SWEAlert and alert

Here is the usage description from Siebel Help.

"Use SWEAlert() instead of alert(). With alert(), pop-up applets such as MVG and pick applets are hidden (sent to the background) when a JavaScript alert() is raised by a Browser-side event. With SWEAlert(), the dialog's parent applet is not sent to the background"


In other words use, SWEAlert() if you want your message box to appear in front when using popup applets, however there is an important omission in the above description.

[About SWEAlert]

The method SWEAlert is part of a client side class that invokes a method on an obscured ActiveX interface, as shown below.


App().ShowMessage("MSGBOX_ALERT", text);


ShowMessage will internally grab the window reference of the popup and create a message box in context of that window, which allows the message to be displayed in front of all other applets and...

It also will encode all the HTML codes in your message.


eg.1
theApplication().SWEAlert("&#169") //(c)



eg.2
theApplication().SWEAlert("&#174") //(r)



eg.3
theApplication().SWEAlert("&#153") //(tm)

This is supposed to show the (tm) trademark symbol, but it dosnt seem to be able to represent this.


Understanding this behaviour can prevent defects in your application; the most common symbol developers should watch out for, is the & (ampersand) representation.

Imagine you've got a label like the following on your applet


If you had script that grabbed the source code of the label, and attempted to use SWEAlert() to show the value of the source code, it would show you the value on the UI, and not the literal value as shown below.

Dieter Bohlen &amp; Thomas Anders


The bottom line is, dont rely on SWEAlert for debugging, using alert is alot quicker, but if you are serious about debugging browser script, using a javascript logger will save you the frustration.

So what if you want to use SWEAlert to show the unencoded value?

To force SWEAlert to display "&amp;", we need to encode the first character of the encoding as so:

theApplication().SWEAlert("&amp;amp;");


There is one more slight difference.

Siebel could have re-used the standard alert command in javascript, and run it against the modal window to get it to appear in front, but it choose to implement its own message box, why?

The msgbox title.

The standard alert title displays "Message from webpage" which cannot be changed, if you look at the title for SWEAlert, it has "Siebel" as its title.

Note: German readers will pick up on the references to Euro pop in this article, but if you're not so lucky to have grown up with these guys, Thomas Anders, was a famous singer from the 80s and Dieter Bohlen is probably the most successful music producer out of Germany and Axel Breitung would be a close second.

Reader Challenge - Mouseover Tooltips (Scriptless)

[Requirement]

Display a floating tool tip with dynamic text, when a user hovers over a form applet label or image in High Interactivity.



[The challenge]

Our earliest followers will remember this requirement as one of the Impossible tasks on our first poll (which was won by the Scriptless VBC).

I'm sure veteran configuraters, get asked this requirement all the time from green BAs.

Does it sound impossible? It should, because mouseover interactions are not supported in HI, and to make this more interesting, lets add a condition to make this a scriptless challenge. We havnt had a scriptless challege since the "EAI Phone format challenge"

By scriptless, i'm going to borrow @lex's definition:

"I define 'scripting' as the attempt to solve requirements such as automation, validation or integration in Siebel CRM by inserting custom code into the event handlers exposed by the Siebel application.

As we all know, Siebel CRM has four object types that expose event handlers:

* Applet
* Application
* Business Component
* Business Service
"


I should also mention that, there should be no scripting or CSS changes to the Siebel browser framework, everything should be configured inside of tools.

The following screenshot shows an example of an advanced tooltip, that i configured earlier.



[Update]

This tooltip should not dissapear after 5 seconds. ie, if there is paragraph of text, it should allow the user ample time to read the tooltip!

Have fun.

Java Business Service (JBS) Tutorial

As promised in the last article, this is a tutorial for Siebel professionals wanting to implement a JBS.

The full source code is available from my LinkedIn Group:Impossible Siebel, for those who want to start running quickly without the usual fiddling around with a new area of configuration.

The Siebel documentation provides some good high level information on the basics of a JBS, but there is no step by step details on how to implement it.

There are a lot of missing pieces that you just have to figure out yourself, and to make things harder, there is little chance we can get it running without Java knowledge.

This is illustrated by one customer who raised the following SR (ID: 490022.1), and asked all the right questions, but the explanation still didnt connect the dots, the author was obviously on a high plane, co-incidently the author who replied to this SR, is one of my favourite engineers on Support Web, Mr Pascal Kitaeff.

Complement of information about Java Business Service [ID 490022.1]

[JBS for Dummies]

Assuming that Siebel professionals dont speak Java, i'll attempt to translate.

Firstly why use a JBS? Using a JBS allows us to implement features that are not available out of the box. We can leverage all of the open source software that already been built and tested, and just plug and play in Siebel.

[Solution Overview]

1) Setup up the Java Subsystem
2) Implement a specialised eScript BS
3) Build a Java Class
4) Implement the program logic in Java

[Pre-requisites]

1. Download and install the Java SDK from http://developers.sun.com/downloads

Dont install this for fun, otherwise it will eat up valuable profile space on space restricted enterprise connected machines.

2. Download and install a JAVA IDE

Eclipse seems to be the most popular www.eclipse.org

or Netbeans, if you want to go for the Sun product
www.netbeans.org


[Setup up the Java Subsystem]

This is the easiest part. Go to your Client CFG file and create the following section
[JAVA]
DLL = <Program path>\jvm.dll
CLASSPATH = <Siebel Tools path>\CLASSES\Siebel.jar;<Siebel Tools path>\CLASSES\ImposSiebelXSLT.jar
VMOPTIONS = -Xrs -Djava.compiler=NONE


This can also be implemented as a Server profile configuration, see bookshelf for more information, but most developers will want to try this out on the local machine.

[eScript BS]

1. Create a BS based on the class: "CSSJavaBusinessService"
2. Call it "ImposSiebelXSLT Business Service"
3. Create a BS user property with the following values

Name: @class
Value: ImposSiebelXSLT

This BS will be barebones and just pass the method down into the Java class, where the real work will happen.

[Java Class]

If you havn't already done so, you need to have your SDK and IDE installed at this point.

1. Create a new project of type "Java Class Library" called "ImposSiebelXSLT"
2. Link the Siebel.jar file to your project libraries
3. Create a new class called "ImposSiebelXSLT"
4. Add the following code to import the required Clases

import com.siebel.data.SiebelPropertySet;
import com.siebel.eai.SiebelBusinessServiceException;
import java.io.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.*;


5. Add the following code to inherit from the Siebel Business Service class

public class ImposSiebelXSLT extends com.siebel.eai.SiebelBusinessService {
    public void doInvokeMethod(String methodName, SiebelPropertySet input, 
                SiebelPropertySet output) throws SiebelBusinessServiceException {


6. Add the following code to perform the XSLT transformation

            StreamSource xmlSource      = new StreamSource(new StringReader(input.getValue()));
            StreamSource xsltSource     = new StreamSource(new StringReader(input.getProperty("XSLTBuffer")));
            Writer outWriter            = new StringWriter();
            StreamResult result         = new StreamResult( outWriter );
            TransformerFactory transFact = TransformerFactory.newInstance();
            javax.xml.transform.Transformer trans;
            trans = transFact.newTransformer(xsltSource);
            trans.transform(xmlSource, result);
            output.setValue(result.getWriter().toString());
            output.setProperty("ErrorMessage", ErrMsg);


7. Compile and place the Jar file into your classpath as defined in your configuration file above.

[Usage]

Now we can call the JBS like any other eScript business service, by passing in input and output property sets.

BS: ImposSiebelXSLT Business Service

[Input Property]
<Value>: XML String
XSLTBuffer: XSLT String

[Output Property]
<Value>: Transformed XML String

[Final thoughts]

Taking the the leap into JBS and using a entirely new XSLT parser can be a risky undertaking, it means that your entire application needs to be regression tested. This is the same problem Siebel would have to face, if it replace its XSLT engine.

So what should we do?

If you dont have any problems with your "EAI XSLT Service", it is best to leave it alone.

Customers who are affected by the 30 namespace problem have a few options as highlighted in the last article.

JBS's arent the solution to everything, but it provides a door to the open source community.

The Java package for this article can be downloaded from LinkedIn: Impossible Siebel

In the final article in this series, i'll look at implementing XSLT 2.0 in Siebel.

User Question: How to use an OR condition in a WF decision step

[Possible Siebel?]



A reader from Texas, US, asked "How to use an OR condition in Siebel workflow decision point".

[Answer]
By default, every WF condition is binded to the 'AND' operator.

To perform an 'OR' condition, compose a condition using the following values

Compare To: Expression
Operation: <Use the default>
Object: <Blank>
Field: <Blank>
Values: Enter your 'OR' expression in here

Eg.

Ultra browser script generator

This tool hardly needs an introduction; I'm talking about Siebel's "Genbscript.exe", which is a simple command line tool that allows us to generate browser scripts for our application. This is an indespensible tool for every developer and environment specialist.

A generic implementation is shown below

genbscript.exe <your config file> <browser script output directory> <language>

The problem with the above method is if there is an existing directory, genbscript.exe will not run, unless you first delete the existing directory.

When this happens you have to goto the browser script folder..



Find the duplicate folder among all the previous versions of the browser script directory, and delete it, which is more frustrating than it sounds.

Genbscript.exe is a black box command line utility, which has no visible hooks, but never to be one, to settle for standard features, i created some automation that got around the limitations of this tool.

I really had to stretch my batch scripting muscles to its limits for this exercise.

The result is "Ultra GenB", which is an enhanced batch program that will detect wether you've got a previous version of the browser script folder, deletes the folder in question, and, regenerates your browser scripts, all with 1 click.

There are only 3 parameters that you need to set.


::##############################################################################
::CONFIG
::##############################################################################
SET BSCRIPT_EXE=<Siebel folder>\Client\BIN\genbscript.exe
SET CFG_FILE=<Config file>.cfg
SET OUTPUT_DIR=<Siebel folder>\Client\PUBLIC\enu


I spent a whole day, just generating browser scripts over and over, so i guarantee your inner geek will have endless hours of fun with this tool.





The tool is free and is provided without any warranty, and can be downloaded from my LinkedIn Group: Impossible Siebel

Does anyone want to see a progress screen that actually shows you the working progress, and not just a blinking cursor?

EAI XSLT Service namespace limitation

If you've ever tried to use EAI XSLT Service to transform a XML message with more than 30 namespaces, you will get the following dreaded error.

"(xsltransform.cpp (564)) SBL-EAI-04267: XSLT Processing Exception: SAXParseException: An exception occurred! Type:RuntimeException, Message:The buffer manager cannot provide any more buffers"

Googlers will find this information useful, because this error is not documented on Support web, and unless XML is prolific in your Enterprise, you are not likely to run into this problem.

[Root Cause]

Since Siebel is a packaged software, it is not well known that it uses the Xalan 1.5 engine to transform our XML, but this fact can be verified by the existence of xalan-c_1_5_0.dll in the Siebel Tools/BIN folder.

A quick search of the web seem to yield no problems with namespaces with this XSLT engine, so its up to us to dig further into this problem.

If we start by isolating the Xalan component, and see if we perform the XSLT transformation directly using the Xalan DLL, we can test for this namespace limitation and determine if this is a Siebel or Xalan problem.

You can still find the Xalan 1.5 engine on the web; if you want to try it out, go over to the Apache website and download it from the archives.

http://archive.apache.org/dist/xml/xalan-c/binaries/

Finding a Xerces parser compatabile with this engine was more of a challenge, since Xalan 1.5 is obsolete, no archive is kept of the parser.

After 15 minutes of fruitless searching, it occurred to me, that i can use the Xerces DLL from the Siebel directory.

[XSLT transformation with Xalan]

1. Download the Xalan 1.5 binary from Apache.Org
2. Extract the ZIP into any directory
3. Goto your Siebel Tools/BIN folder and copy the xerces-c_2_2_0.dll to the Xalan release folder
4. Supply a XML file with more than 30 namespaces
5. Supply a XSLT file
6. Run the transformation

If you've followed the above steps, you should get the following error.



Bingo!, its the exact same error that we recieved in Siebel.

This is very interesting, so does the problem still occur with the latest version of Xalan?

I used Oxygen 8.2 which comes with the latest Xalan 2.7, and it passed the 30 namespace test.

So we can confirm that this defect is caused by the Xalan 1.5 engine (Oracle engineers take note).

But since this engine is a core part of the product, dont bet on it being upgraded any time soon. Defects in the core Siebel product cannot be easily fixed, so what options does the hapless customer have?

1. [Reduce namespaces in XML]

You can try requesting for your Enterprise to reduce the number of namespaces that is sent to your Application, although this is out of your control, it is worth trying.

2. [Strip out the unused namespaces before transformation]

The idea is that you pass your incomming XML message to a BS utility to strip out the un-needed namespaces, and pass it to the EAI XLST Service for transformation, ensuring that it has less than 30 namespaces.

The above two methods have the following advantages
1. Can be implemented quickly
2. Has very little impact to testing

but it has the following disadvantages.
1. Not scalable
2. Namespaces can change adding to maintenance
3. All namespaces may be needed
4. Different namespaces may be needed for different messages

3. [Use external transformation engine]

An alternative is to replace the default Siebel Xalan engine and use an external transformation engine.

This allows us to bypass the limitations of the standard EAI XSLT Service, and it also provides us access to a more modern XSLT parser.

To achieve this, Siebel provides us with a few mechanisms to extend vanilla functionality by calling on external code.

1. SElib.dynamicLink
2. EAI DLL Transport
3. Java Business Service (JBS)

Although we can use any of the above, methods to call external code. I'll look specifically at using a the JBS option to workaround this product defect, because all the tools and software needed are free and open source.

Using a JBS to call a more modern XSLT parser, will allow our transactions to be more efficient, as well as offering the latest methods available in the XSLT standard.

This is exciting stuff so put that holiday on hold, until this comes out.

Inject browser script in Siebel 8.1.1.2

I dont know how many customers are on 8.1.1.2, but i suspect not many since its only available to the Public Sector vertical. But this could be the beginning of the end for all the browser script hackers out there.

Injecting browser script into the IE address bar has been a favourite trick for developers to Set and Get the value of profile attributes on the fly.

If you've come late to the party, what this trick does is allow us to run browser script against the current siebel session using the following javascript command

javascript: alert(theApplication().GetProfileAttr("Me.Full Name"));


The first signs of problems began in 8.1.1.1 when the Siebel UI rejected my attempts to insert the Impossible Toolbar into the menu frame, which i thought were related to me upgrading to IE8, but in 8.1.1.2 it disabled any injection attempts altogether, as verified by @lex on my Twitter.

I've been secretly playing with a web development trick to inject browser script into Siebel, and reimplementing my tools around this new method.

This is only high level information, but there are a couple ways of running achieving this.

1. Build a browser console

On Application Start, write some code in browser script that opens up an IE window. This IE window exposes a console that runs code in the context of the parent window.

This allows us to hook into the Siebel session, and run our commands in the same fashion that the address bar allowed previously.

You could also modify the Siebel browser script framework files to open up the console, instead of modifying the application, but the downside is neither of these method are very portable.

2. Use a browser debugger

This method affords us the flexibility to inject browser script in any environment, but lacks the flexibility to customize the UI and commands needed to perform a lot of the fancy stuff that the Impossible Siebel toolbar provided.

I am currently looking at a fusion of the above techniques, and have managed to port some essential features of the Impossible Siebel toolbar onto a separate floating console as a POC.

Heres an early prototype that i've hacked onto a log4javascript console.



But, if all you are interested in is Setting and Getting ProfileAttr in Siebel, you can download any debugger (google is your friend), and try it out on your machine, as long as it provides you with a console, you can use it to run Browser Script commands.

Its actually easier than using the address bar, because you dont have to type the "javascript:" prefix in front of all your commands.

Even if you dont have the 8.1.1.2 problem, i recommend you grab one of these tools, it will become indispensible when you need to debug browser script, find the source code of individual frames, or just check profile attributes to test that your config is behaving correctly.