Find Results Highlight defect

1. Log into the Application through thin client
2. Click the Binoculars
3. Choose a search category
4. Enter a search criteria
5. Click Search

The search results should show the selected record with a highlighted background as shown in the screenshot below. This feature worked in 7.8 and broke when the application was upgraded to 8.1.

Note: This issue only occurs on the thin client and cannot be replicated via the thick client.


The Find pane is rendered in SI, so the row highlighting has to be controlled by CSS and the class tag. To verify what is happening right click on the Find pane, view the source code and identify the section that has the Find results.

We can see that the class tag is missing the class name, this is why the highlighting does not work. Is the server not generating a class or is the swe command for active row highlighting broken? To get to the root cause, we need to go to web templates that is used to render the HTML before it is sent to the browser.

Goto your Web templates folder, locate and open the following file

CCListBodySearchResults.swt

The swe command that is responsible for determining the class is
<tr class="swe:this.RowStyle">

According to the Siebel documentation, this is the correct command, but the Application does not correctly render the class tags.

To work around this feature, we can utilise a swe switch statement to detect the state of the web engine, and the print out the correct class tags for our rows. Heres how its done.
<swe:switch>
<swe:case condition="Web Engine State Properties, IsCurrentRow"><tr id2='JLEOn' class="listRowOn"></swe:case>
<swe:case condition="Web Engine State Properties, IsOddRow"><tr id2='JLEOdd' class="listRowOdd"></swe:case>
<swe:case condition="Web Engine State Properties, IsEvenRow"><tr id2='JLEEven' class="listRowEven"></swe:case>
<swe:case condition="Web Engine State Properties, IsErrorRow"><tr id2='JLEError' class="listRowError"></swe:case>
<swe:default>

</swe:switch>

There are 5 available classes

ListRowOn
ListRowOff
ListRowEven
ListRowOdd
ListRowError

If you want to change the styles of these classes, they can be found in the main.css

Notice that I add a custom id2 attribute to the row tags for testing, this lets verify the change on the thick client, since the original swe command and the new switch statement will generate the exact same output, we need something to tell us that we have modified the correct SWT file.

Enjoy your new old feature again.

Cornelius' Applet Set Focus Challenge

This article continues on from the guest article on Siebel Essentials - Set Focus on an Applet by Cornelius.

When I read the article by Cornelius, and saw the ~85 lines of code, I fainted (possibly due to the heat wave on the day) and when I came to, I wondered if this solution can be made leaner?

Querying the repository is sometimes necessary, when you need to achieve non-standard functionality, but in this case I felt there had to be a better way. Using SWEApplets only works in SI, but in HI, it should be possible to read the DOM and find the first visible applet and pass it to HandleAppletClick.

I did a quick POC using the IE DTB, and got a working solution with 5 lines of code. But 5 lines was too much in my opinion, so with a re-think of the problem, I by passed HandleAppletClick, and got the solution leaner.

The result is 3 lines of code. Heres how I did it.

Before we jump into the solution, ensure you have jQuery installed on your top object. This can be done via the web templates

Insert the following line of code in a common template such as your PageContainer

<script src="<your scripts folder>jquery.min.js"></script>
<script src="<your scripts folder>common_1.00.js"></script>

Next assign the jQuery object to your top object as so in your common JS file
top.$=$;

Now you'll have access to this magic everywhere in your application.

[Solution]

Cornelius separated his solution into two parts

1. Setting focus on the applet using "HandleAppletClick"
2. Using Browser/Server script to retrieve the applet sequence from the repository

This solutions just entails 1 part

1. Goto the DOM behind the current view and click the first applet that we find =)

Line 1:

var iRows = top.$("frameset",top.SWEFindFrame(top,"_sweview").document).attr("rows");

The Siebel thin client has an array of 10 cached view frames, and randomly picks a frame to render the next view upon Application Navigate. This happens behind the scenes and is not exposed or documented. Although the frame reference is random, and the next view frame is not known, we can check to see which of the current 10 frames is visible through the "rows" attribute on the frame container.

The above line just returns a reference to the current frame index.

Line 2:

var fDoc = top.SWEFindFrame(top,"_svf"+top.$.inArray("*",iRows.split(","))).document;

With the frame index, we can grab a hold of the actual frame document, using "top.SWEFindFrame". This is an undocumented Siebel browser framework function, if you are uncomfortable using it, you can roll your own, just write a recursive function that iterates through the frames and match on the frame name or just copy the Siebel function into your own library.

Line 3:

top.$("div[onclick*='HandleAppletClick']",fDoc).first().click();

As Cornelius has discovered, Siebel uses a function called "HandleAppletClick" on the onclick handlers for its applets. My original 5 line solution involved scraping the Applet name from the DOM, and passing it to "HandleAppletClick". In this solution, I just look for the first element that has the onclick handler that fires "HandleAppletClick", and click it programmatically.

[Conclusion]

Although its not necessary to use jQuery, having it makes our solution more concise, and readable. A similiar browser script function could have been implemented, but you would be spending a lot of time performing the low level DOM work.

Applet Toggles, Personalization, and Display Visibility all affect the run time visibility of the Applet. This technique allows us to determine dynamic UI behaviour that is not available when querying the repository.

The solution is lightweight, fast and best of all, we performed a beat down of ~85 lines of browser/server script with 3 lines of "Black Magic Do" (Translation: Way of the black magic). For the non initiated, in martial arts Do, means way or road =)

EAI Phone Format Challenge feat. BRP

Over two years ago, I issued a challenge to the Siebel community, through the EAI Scriptless phone number challenge.

The original challenge was started by a reader from Siebel Essentials's scriptless challenge, which was to find a scriptless solution to strip off the formatting from a DTYPE_PHONE, and leave the raw phone number.

The challenge that I subsequently issued to the community was to find go further and find a solution which applies the format mask to the phone number without any scripting.

At the conclusion of the challenge, I presented a 35 line recursive XSLT template that demonstrated that while it is possible to go to the end of the earth to find a scriptless solution, a 10 liner business service would have between more maintainable, given that most Siebel professionals don't spend their time swimming in stylesheets.

I know that our conservative Siebel readership wont sleep well with the scripted solution, so I've been working hard on an alternate solution that will please all our declarative readers out there, and also impress the eScript Jedi's and hopefully convert them back to the light side.

Here is the challenge outlined again.

"+610212345678[LF](00) 0000 0000"

The system must take the above DTYPE_PHONE value and convert it to (02) 1234 5678 without any scripting.

Note that the DTYPE_PHONE consists of the raw number + a line feed character + a format mask with the zeros representing the position of the number, any non zero characters represent a formatting character that must also be applied to the formatted string.

[Business Rules Processor]

This requirement can be achieved by using Business Rules Processsor (BRP).

BRP was introduced to Siebel as a FINS module around v7.8. It provides a fully declarative means of processing complex business logic.

This is an except from bookshelf about the capabilities of the BRP engine.

"The Business Rule Processor features include:

* Business logic administration through the application user interface.

* Appropriate for complex business logic; supports procedure, loops, if-then-else and switch-case constructs.

* Appropriate for business logic that changes frequently. You can modify business logic without deploying a new SRF.

* Query, read, and write access to business components.

* Error handling.

* Support logging at multiple levels for easy testing and debugging.

* Can potentially replace large amounts of custom scripts."

That list is pretty impressive, but is it up to our challenge?

Here is the psuedo code for rule that we are going to implement.

1. Separate the DTYPE_PHONE into separate PHONE and FORMAT components

2. Start at the last character of the FORMAT component

3. If the character is a Zero, then take the corresponding character in the PHONE component and store it in RESULT

4. If the character is non-Zero then take the current FORMAT character and store it in RESULT

5. Move to the next preceding character and continue processing until no FORMAT characters are left

[Solution]

1. Goto the Business Rule Processor Screen

a. Create a new process called "EAI Phone Format"
b. Create the variables for our rule as shown in the screenshot below


2. Goto the Procedure view

a. Create a procedure called "DeterminePhoneString"
b. Create a procedure called "Main" and set this as the Entry procedure into this rule.
c. Create 4 steps as shown


3. 1st Step - Get CRLF character

Here we call the SSE Address Parser BS to get our CRLF character and assign it to the sCRLFChar property.


4. 2nd Step - Init variables

We initialise and setup all the variables before we start our routine.


5. 3rd Step - Loop through pattern

We define a loop that iterates through the pattern backwards, until our cursor reaches the beginning. On each iteration, it will call "DeterminePhoneString".


6. 4th Step - Set remainder of the string to the final output (Optional)



7. Define the "DeterminePhoneString" procedure

Create a switch statement with the following logic


8. Create a default branch for our switch statement



9. Activate your rule, and test it in BS simulator using "FINS CAP Processor Service"



[Conclusion]

I've only scratched the surface of BRPs features here with this example, but amongst some of the more interesting features, BRP introduces a new property type called 'Vectors" which provides quick access to a hash table like reference, which is populated directly from a BC.

Is BRP the holy grail of declarative configuration?, In my opinion no. When used badly, the problems associated with scripting will only be shifted to a declarative interface. As with scripting, BRP can be the source of duplication and spaghetti procedures.

BRP is also limited by its expressions, and does not support custom functions, so you will still need script to provide a wholistic solution. Eg. Regex is not supported, so performing email validation still requires you to call a business service.

Scripting can be used for good, but too often it falls in the hands of in-experienced developers, which is why I really like BRP. It can be picked up really quickly by beginners, as it utilises the Siebel Query Language, and provides the flexibility of eScript through declarative loops, if/else/switch conditional statements and procedures. It also forces developers to break down their routines to manageble statements that improve readability of the design.

Where BRP really shines, is the capability it provides to developers to implement the majority of requirements with programming constructs but in a declarative interface, and more importantly since the logic is outside the SRF, changes to business logic can be made outside of releases.

Solution - Popup Applet "X" button

This is the long awaited solution to the Popup Applet X button challenge, which was solved by Master configurator Michael Feng.

[Background]

Siebel provides us with two events on popup applets, represented by the buttons "Ok" and "Cancel" which provides the neccessary hooks to capture most business requirements around closing of popup applets.

But the "X" button is an exception case, where the user forced closed the applet without completing the required interaction. In these cases, you might want to rollback any changes that were made since the applet was opened, or popup an alert to educate the user of the consequences of not closing the Applet properly.

[Siebel popup applets]

It is important to understand what happens when we click on the "X" on a popup applet in Siebel. The developer who requested help from the Oracle forums, tried attaching a custom method on window.onunload, which is a native browser event for when the current view has been navigated away from or closed.

This is the right line of thinking, and isnt far off from Michael Fengs solution below. This would normally work for traditional web apps, but Siebel dosnt close the popup applet when you click "X", it just minimizes it and hides it under your taskbar, which is why the window.unload event never fires.

The way to see this in action, is to set your taskbar to auto hide, watch what happens when you click "X" on a popup applet. You'll see it minimized to a short title bar on the bottom left of your screen, underneath where the taskbar would normally sit when displayed.

[Usability]

The reason why Siebel does this is for usability. When you log into your Siebel application, the first time you open any popup applet will always be the slowest, thats because Siebel has to spawn a new instance of an IE window. When you click "X", siebel will minimise and hide the window. The next time when you open another popup applet, Siebel will re-display and re-use this same popup window.

Re-displaying an existing window is in order or magnitudes faster than opening a brand new window, and greatly enhances the user experience in HI applications.

[Solution]

As mentioned in the original post, there are various solutions to this problem. When the popup applet is closed, focus will return back to the control/applet that invoked the popup applet, and you could, pop up a confirmation at this point, but it is ugly, if the popup applet is used in many places then you would have code on a lot of base applets.

Since the Popup applet is never closed, another idea is to set a looping timer to determine the position of the applet, and if it disappears below the taskbar then we know it has been closed. Its not a desirable solution as polling adds overhead. So the ideal solution is to trap the X event on the popup applet itself.

One alternative is to attach a custom function to the window.onmove event of the Popup applet which would give us a real time notification everytime the applet gets moved, and if it moves to the taskbar position, we know the user clicked X.

Or we could do better by detecting when the physical dimensions of the Popup applet has been shrunk by monitoring the window.onresize event.

Heres how it can be done, the following code is provided by courtesy of Michael Feng.

function Applet_Load () {
var oCon = this.FindActiveXControl("NewQuery");
var obody = oCon.document.body;
var odiv = oCon.document.createElement("script");
odiv.type = "text/javascript";
odiv.language = "javascript";
odiv.text = "window.onresize=UnloadTrigger;function UnloadTrigger(){if(document.body.clientHeight==0&&document.body.clientWidth==0){alert('You close the popup applet');}}";
obody.appendChild(odiv);
}

An interesting question is, what happens to the UnloadTrigger that is attached to our first popup window, when a second popup is called after the first? Does it still linger around, even when if its unwanted on the second window? Siebel re-renders the entire contents of the applet everytime it is "re-used", but keeps a cache of the last applet.

Base applet --> Popup Applet A --> Popup Applet B

Siebel will cache the contents of Popup Applet A when it is opened, Siebel re-uses the popup window, and renders the HTML for Popup applet B when it is opened.

When Popup Applet B is closed, Siebel will reuse the popup window, and restore Popup Applet A from its cache, therefore restoring our UnloadTrigger.

So we have to modify the solution to deal with the fact that popups can spawn other popups.

function Applet_Load () {
var oCon = this.FindActiveXControl("NewQuery");
var obody = oCon.document.body;
var odiv = oCon.document.createElement("script");
odiv.type = "text/javascript";
odiv.language = "javascript";
odiv.text = "window.onresize=UnloadTrigger;function UnloadTrigger(){if(document.body.clientHeight==0&&document.body.clientWidth==0&&!Top().SWEPopupGainFocus()){alert('You close the popup applet');}}";
obody.appendChild(odiv);
}


The above code uses and undocumented function Top().SWEPopupGainFocus() to determine if a popup is in focus or not. We only want to display a message when there is no popup open.

The last piece to this puzzle is to handle the positive events when the user click on "Ok" and "Cancel", in which event we do not want to display our message. You'll need to set profile attributes, or view variables to indicate that the applet was closed properly, and check for these variables in the unload function.

function Applet_Load () {
var oCon = this.FindActiveXControl("NewQuery");
var obody = oCon.document.body;
var odiv = oCon.document.createElement("script");
odiv.type = "text/javascript";
odiv.language = "javascript";
odiv.text = "window.onresize=UnloadTrigger;function UnloadTrigger(){if(document.body.clientHeight==0&&document.body.clientWidth==0&&!Top().SWEPopupGainFocus()&&App().GetProfileAttr('ProperlyClosed')!='Y'){alert('You close the popup applet');}}";
obody.appendChild(odiv);
}

Thanks to Michael for providing this solution, and for helping solve another impossible problem and breaking new grounds on creativity =).

Funky Town: Inline Field Validation

This post is part of the Funky Town series of articles, where we take ridiculous User Centric Design (UCD) requirements and put them into practice.

In this article, I look at another outrageous business requirement - Inline field validation.

Imagine typing in an email address, and as soon as you step off, the field turns red, and a tooltip style message appears, stating that your input does not meet the proper standard for an email address.



Inline field validation provides many benefits

1. Immediate help for the user
2. Affirmation that the user is doing the right thing
3. Assists complex data input requirements
4. Improves user experience
5. No server round trip required
6. Makes Siebel a joy to work with!

This is the sort of thing you see on fancy web forms, and only BA's will dream this requirement up because Siebel is a simple web application right?. Lets see how we can provide this functionality for them.

[Solution]

This solution will only work for form applets, so open up any form applet, and designate a field that will act as your "email address", for this exercise your field dosnt actually be an email field.

1. Put the following code in your email field control OnBlur handler
validateEmail(applet,id);

2. Add the following browser script to your applet
function validateEmail(applet,id){
    try{
        var sValue = applet.FindControl(id).GetValue();
        var oDoc = applet.FindActiveXControl(id).document;
   var oToolTip = oDoc.getElementById("Tooltip");
        if(sValue.length>0&&sValue.indexOf("@")==-1){//insert fancy email validation routine here
       if(!oToolTip){
           var oToolTip=oDoc.createElement("div");
           oToolTip.innerHTML=" Please enter a valid Email address eg. [email protected]";
           oToolTip.id="Tooltip";
           oToolTip.style.backgroundColor="#fff";
           oToolTip.style.color="#000";
           oToolTip.style.padding="10px 40px";
           oToolTip.style.borderStyle="solid";
oToolTip.style.borderColor="#bbb";
oToolTip.style.borderWidth="10px";
           var oHeader = oDoc.getElementById("SectionHeaderId");
           if(oHeader) {
                oHeader.parentNode.parentNode.appendChild(oToolTip);
                applet.FindControl(id).SetProperty("BgColor", "#ff0000");
            }
         }
        }else{
            if(oToolTip){
                oToolTip.parentNode.removeChild(oToolTip);
                applet.FindControl(id).SetProperty("BgColor", "#ffffff");
            }

        }
    }catch(e){
    }

}

3. Create a section header for your form, add the following in the caption override
<span id="SectionHeaderId">My Funky Form</span>

Re-compile your applet, and type in some junk in your email field. As soon as you step off, your field will turn red, and a message will appear to notify of the error.

Suffice to say, the email routine that I used above is not foolproof ^_*, but you get the idea. A more wholistic solution would look at validation from a general perspective, but that is left to the reader to run with.

[Conclusion]

1. Will it perform well?
Yes, there are no server calls.

2. Is it maintainable?
Yes, if the code is made production ready, and all the validation routines are centralised.

3. Can it be upgraded?
Yes, as it does not use any undocumented methods

and

4. Is it sexy?
Yes, its a BA's dream come true

Funky Town: Sexy Salutation

This post is part of the Funky Town series of articles, where we take ridiculous User Centric Design (UCD) requirements and put them into practice.

[Background]

On the Application Home page screen, Siebel provides us with the ability to close individual Applets, and hide them from the home page. Applets can also be hidden by default in the View definition, and users can display the applets again through the Edit Layout view.

This is actually what a home page actually looks like when you hide all the applets.

To the uninitiated, it looks like the data has disappeared or deleted! Surely this cant pass UAT, yes laugh it off, give your users some training and tell them not to party on the weekends and come to work switched off. However you may take an important design principle to heart - Design for the lowest denominator.

How about we give our users a friendly message that reminds them their data is not goneski, its just not visible.

This message will dynamically appear when there are no applets displayed, and slide down smoothly like an accordian, just to give your users that feelgood feeling, and make them wonder why other parts of Siebel is not sexy like this view.

This solutions relies on a Javascript library called jQuery, which allows the developer to easily select and manipulate DOM elements. Never heard of jQuery? You are probably one of those people who are stuck in a web time warp from early 2000s. Circa 2003, there was an explosion of JS frameworks, that provided web developers a new level of abstraction on JS which provided developers with the tools to achieve easy cross browser compatability, stream line their code, and focus on functionality.

Is it production ready? Dont worry, you'll be in good company. Dont hesitate, get it now, and learn it.

Implementation

1. Download jQuery, and include it into your top object

This can be done in application start or a common Page container web template. If you are taking the latter approach back this file up.

2. Identify the web template that your Home Page View is based on

I should now stress that you should not put any javascript logic in your web templates. Any javascript logic should be offloaded into an external file for performance, maintainability and upgrade reasons (In this case the latter is more important than the rest). Plan this out carefully before you attempt to implement this solution.

3. Put the following code in the external file that handles all your home page behaviour

function j(expr){
return top.$(expr,document);//references the top.$ that was loaded in step 1.
}
j(document).ready(function(){//waits for the home page document to finish loading
try{
if(j("[class*='AppletStyle']").length===1){//if the number of applets rendered is 1 (ie Only the Edit Layout Applet is shown), display our fancy message.
var sText = "Your Home Page data is currently on holidays.

"+
"If you would like to see your data, click on the 'Edit Layout' button, then click ";
var sDiv="

";
j("div.Welcome").append(sDiv);//attach a fancy message
j("div#Msg").slideToggle();//use some jQuery magic to make the message animate by sliding down.
}
}catch(e){
}
});

If you loaded jQuery from your Application, you'll have to re-compile, otherwise, if the library is loaded from your web template, you'll just need to re-start your dedicated client, or restart the server, if you are implementing this on the server.

The "beauty" of this solution is that there is no clunky server side co-ordination, and all the logic is performed client side, so it performance translates to a silky smooth experience.

Conclusion

1. Will it perform well?
Yes, no server side components were abused to deliver this functionality

2. Is it maintainable?
Yes, just like web templates, images and other external configuration

3. Can it be upgraded?
Yes. Dont put your code in your templates. Make the effort to offload this to an external file, otherwise dont do it at all.

and

4. Is it sexy?
It is fun and sexy.

Funky Town: Custom UI Extension

This post is part of the Funky Town series of articles, where we take ridiculous User Centric Design (UCD) requirements and put them into practice.

[Background]

I was commissioned to design a custom Integration framework for a client. As part of this framework, the client needed to have a test harness that allows:

1. The developer to generate a pre-populated SOAP request for any predefined Siebel Web Service, with run time data and authentication headers.

2. Allow the developer to send the request and see the SOAP response in real time in the UI

3. They should also be able to modify the SOAP request on the fly and re-submit the message

4. and all of the above for XML over MQ as well

The design needed to load a run time data into the request, but the test data itself was transient and did'nt need to be saved. The size of the payloads are always unknown, especially when dealing with binary encoded data, the response would be massive, so I needed a way of storing unlimited data on the UI.

The closest thing that resembled what i wanted is the Script Editor Applet (Business Service Script Editor Applet2) under Business Service - Administration. Its just an applet with a massive text area, however the field that it maps to has a physical limit.

The idea was to design a custom IE window that could load the request message based on some predefined integration settings, allow the user to modify the request through a text area field, submit it to the transport, read the response and display it on the custom UI window.

This article will focus on how to build a custom window and handle the two way communication between the custom client and Siebel server. Details around integration points in Siebel will be glossed over.

[Design]

This is what the finished product looks like.



1. The chain of events starts when the user clicks on a button called "Launch Harness" which invokes "TestIntegrationCall" to launch our custom window.

a) On WebApplet_PreInvokeMethod of "TestIntegrationCall", we call a process that Generates Request message

In code it would look like this

switch(MethodName){
case "TestIntegrationCall":
//Generate a sample request XML and store it in a Profile Attribute that can be access by the browser
TheApplication().SetProfileAttr("REQUEST_MSG",[Your Request Msg]);
break;
}


b) On Applet_InvokeMethod TestIntegrationCall, we create an IE Window with the following code

//Browser Declarations
var results;

//Applet_InvokeMethod

switch(name){
case "TestIntegrationCall":
results=window.open('','Test Harness','height=600,width=900,scrollbar=yes,resizeable=yes');
var sendButton = "<input type='button' value='Send Request' onclick='opener.sendServerRequest(this)' /><br />";
var requestXML = "<textarea id='request' name='request' rows='30' cols='50'>"+ theApplication().GetProfileAttr("REQUEST_MSG")+"</textarea>";
var responseXML = "<textarea id='response' name='response' rows='30' cols='50'>"+ theApplication().GetProfileAttr("RESPONSE_MSG")+"</textarea>";

var html = "<title>Test Harness</title>"+
"<body style='background-color:#bbbbbb'>"+info+"<table><tr><td>"+requestButton+requestXML+"</td>"+
"<td>"+responseButton+responseXML+"</td></tr></table><br />"+sendButton+"</body>";
results.document.write(html);
results.focus();
results.document.close();
theApplication().SetProfileAttr("REQUEST_MSG","");
theApplication().SetProfileAttr("RESPONSE_MSG","");
break;
}


2. Using the "requestXML" variable in the step above, the Request message is injected into the 1st text area as part of the IE window creation process.

3. Applet_PreInvokeMethod SendRequest
Do nothing.

4. Applet_InvokeMethod SendRequest
Invoke a browser function that will invoke a server method that will initiate the integration call

This is initiated, from the "Send Request" button on our new created UI, which was created in Step 1b.

var sendButton = "<input type='button' value='Send Request' onclick='opener.sendServerRequest(this)' /><br />";

When the user clicks on "Send Request", it will use the "opener" method to lookup the parent window, which is the Form Applet and call the
sendServerRequest
browser function which is defined on the Form Applet as so.

function sendServerRequest(win)
{
var requestXMLStr = win.document.getElementById("request").value;
theApplication().SetProfileAttr("REQUEST_MSG",requestXMLStr);
applet.InvokeMethod("SendRequest");
theApplication().SetProfileAttr("REQUEST_MSG","");
}

Notice that we pass in "this", which is the handle to our custom IE window, this lets us read the values from our custom window.
The first line grabs the XML request from our text area, and calls a server side event.

case "SendRequest":
//Get Request String from our custom IE window
//Convert to correct format and calls the interface

5. The above code will make the interface call and return the results back to our Form Applet, which will convert the Output to a string and store it in a ProfileAttribute which will be accessed by browser script to inject back into our custom IE window as shown in the next step.

6. Get the handle for the IE window, and inject the results into the 2nd text area

case "SendRequest":
var responseXMLStr = theApplication().GetProfileAttr("RESPONSE_MSG");
results.document.getElementById("response").value = responseXMLStr;
theApplication().SetProfileAttr("RESPONSE_MSG", "");
break;


Here are the sequence of events again

Open test harness

1. Browser PreInvoke TestIntegrationCall - Do nothing
2. Server PreInvoke TestIntegrationCall - Generate Request message and convert to string
3. Browser Invoke TestIntegrationCall - Construct IE window and Request message
4. Server Invoke TestIntegrationCall - Do nothing

Send request

1. Browser PreInvoke SendRequest - Do nothing
2. Server PreInvoke SendRequest - Call interface
3. Browser Invoke SendRequest - Injects the response into our Custom IE window
4. Server Invoke SendRequest - Do nothing

[Conclusion]

We have just designed a complex, yet highly unique and functional test harness to assist developers in their day to day jobs, however the concept of a custom UI window can be extended to any part of the application that requires features that are not available out of the box.

Lets look at our criteria again

1. Will it perform well?
N/A. It is a fit for purpose utility

2. Is it maintainable?
Yes, if the code is made production ready

3. Can it be upgraded?
Yes, as it does not use any undocumented methods

and

4. Is it sexy?
It is a no contest, it is like beauty and the beast.

Funky Town: Friendly Siebel Applets

This post is part of the Funky Town series of articles, where we take ridiculous User Centric Design (UCD) requirements and put them into practice.

[Scenario]

The business wanted yet another button on a common applet, but the applet was already crowded with buttons (pictured below). The plan was to consolidate the functionality behind the different buttons, and reduce the clutter on this applet, as it was becoming a real eye sore.



I advised on removing the last two buttons, as they were too specific and its appropriateness was questionable, but i was told that users loved those buttons as they are the two most heavily used buttons in the application! Since the client was paying my wages, who am I to argue?

The second idea was to combine the 3 search buttons into one, since they all perform the same basic functionality "Search"

"Search Client Id"
"Search Client Name"
"Search Client Address"

The problem was, in the current design, the above buttons each invoked a separate VBC Search applet which called an external interface that only allowed mutually exclusive queries by Id, Name or Address, which is why they were designed separately in the beginning.

The agreed design going forward, was to combine all the fields of the above 3 applets into one super search applet, but we needed a way of preventing the user from entering data into different search categories on the same interface call.

The standard approach is to use validation to return an error message when the user hit the "Submit" button. This option achieves the requirement, but it provides a horrible user experience. Imagine the user filling in every section of the form, because it allowed them to, but when they click "Submit", an error pops up, the form is returned to the user, and they have to go through and re-fill the form correctly.

We should aim to design our application to be more intuitive (take inspiration from what Apple did with the Smart phone market =), so the proposed design was to have the fields in the relevant section dynamically became read only or read write as the user typed, this will block out fields that cannot not be filled in.

[Requirement]

a) There are 3 sections, A, B & C on a Search applet.

When the user begins typing in any one section, all the fields in the other two sections should be disabled.



Eg.
If a user types something in a field under section A, all the fields in section B&C would be disabled.

If a user types something in a field under section B, all the fields in section A&C would be disabled.

If a user types something in a field under section C, all the fields in section A&B would be disabled.

b) When the user clears the all field values from any section, all the fields in the entire applet should be re-enabled again.

[Solution]

In HI, there are two control events that are usable on form applets.

onBlur
onFocus

We will use onBlur, because when the user moves from one field to the next, we can implement logic to dynamically enable or disable the rest of the fields on the applet.

Firstly put in our trigger on each control that is editable by the user, put the following code in the onBlur handler

setSectionReadOnly( [section id] );

[section id] is a predefined identifier that you assign to each section in the form. It can be called anything. In our form applet, there are 3 sections, which we'll call a, b, c.

So for all the fields under section "a", you would put the following in each fields onBlur handler

setSectionReadOnly("a");

For every field under section "b", you would put

setSectionReadOnly("b");

and so on.. what this does, is tell our yet to be created function, that every time the user leaves an editable field, send the current field section to our function to determine the UI behaviour.

Now we define the function that is responsible fore enabling/disabling the fields dynamically.

declarations()
var thisApplet = this;

function setSectionReadOnly(sSection)
{
//control object defining allowable applet search sections
var oCTRL = {};
oCTRL.a = ["Id Type","Id Num"];
oCTRL.b = ["Family Name","Given Name"];
oCTRL.c = ["Address Line 1","Address Line 2","Address Line 3", "Address Line 4"];
var bNotEmpty = false;
try {
//check current search section for existence of a search value
for (var i=0;oCTRL[sSection].length>i;i++){
if (thisApplet.FindControl(oCTRL[sSection][i]).GetProperty("ReadOnly")=="true")
return;//abort if active field is RO
if (ctrl.GetValue().length>0){
bNotEmpty=true;//flag first non empty field
break;
}
}

//if current search section has a search value make every other section RO
if (bNotEmpty){
for (var key in oCTRL){
if (sSection!==key){
for (var i=0;oCTRL[key].length>i;i++){
thisApplet.FindControl(oCTRL[key][i]).SetProperty("ReadOnly", "TRUE");
}
}
}
} else {//if current search section is empty then make the whole applet RW
for (var key in oCTRL){
for (var i=0;oCTRL[key].length>i;i++){
thisApplet.FindControl(oCTRL[key][i]).SetProperty("ReadOnly", "FALSE");
}
}
}
}
catch(e) {
//handle error
}
}


Compile your super friendly search applet, and watch your users frustration disappear =). I'm sure you'll agree that dynamically disabling irrelevant fields, and preventing users from entering invalid data is much more friendly, than allowing them to enter invalid data, and complain that the user got it wrong afterwards.

The implementation in this example, was used to illustrate a working concept, there are numerous ways of optimizing this code to perform better, so it should not be copy and pasted across your application.

[Conclusion]

1. Will it perform well?
Yes, there are no server calls, and all the magic happens client side, saving a round trip to the server.

2. Is it maintainable?
Yes, if the logic is made production ready

3. Can it be upgraded?
Yes, as it does not use any undocumented methods

and finally the litmus test

4. Is it sexy?
Yes, and it is also very intuitive

Funky Town

A lot of articles on Impossible Siebel are an exploration of what is possible than what is normally recommended, it is hoped that readers would take these ideas, concepts and techniques (added with some common sense) to solve tricky requirements, within the guidelines of each project.

But what are the consequences when we say no to unconventional business requirements?

[Experience 1]

Recently i walked into a local communications store, to buy a new cell phone. The clerk was training a new starter on how to use the system, and i noticed that they had Siebel eChannel on their monitor, which started grab my interest.

The clerk explained to his apprentice, that they needed to check to see if i am an existing customer, otherwise they will need to create a new account for me.

Because i didn't know whether i had an account with this company or not, they had to first search for my details in their system. This is when the clerk told his apprentice, to switch away from Siebel to this other web based application to perform this search and create my account. The clerk explained to his apprentice that, this other system was easier to use.

-Score-
Siebel: 0
Web based system: 1

[Experience 2]

I had a similiar experience at my local bank, when i met with my banker. I knew the first thing that he was supposed to do, when we sat down was open up his Siebel application, and start a "needs conversation" with me.

A "needs conversation", is process where the banker should go through an interview type transaction, ask me a series of questions relating to my current circumstances, and put this data into Siebel. At the end of the process Siebel would come up with a list of recommended products to offer me.

I knew this, because i knew the team that delivered this functionality. Instead the banker used a java portal to look up my details and get a summary of my data. He wrote everything about our conversation on a piece of paper and made up some recommendations from his head. Interestingly I also knew the other team that developed the java portal, and the UI was so intuitive, that i didn't blame the banker.

-Score-
Siebel : 0
Web based system: 2
Paper based system: 1

[Experience 3]

I walked into a rival bank, and told them i wanted to open a business account. As i sat down with this employee, he used his CRM system to record my conversation, i was quite alert to this, and i asked him to show me his application. He was quite proud to show it to me, because it was a very nice .NET application that was fluid, responsive, the UI was very clean and minimalistic. It was also very sexy, and you can tell the UI was built by a well paid designer, not just some guy in the team that does web design as a hobby.

-Score-
Siebel : 0
Web based system: 3
Paper based system: 1

[User Centric Design]

Custom applications have the advantage over Siebel in user friendlyness, because there are things that you could do with current web technologies that are never "possible" in Siebel,

Lazy loading UI
Async calls with callbacks
Fancy transition animation
Dynamic UIs
Inline field validations
Word completion

etc

But lets not dwell on the negatives too much, because Siebel is a vast product with a lot of technologies that allows us to build a descent and usable interface. If you're lucky enough to work in an organisation that has a good User Centric Design (UCD) team, that hasnt been contaminated by limitations of Vanilla Siebel, get them involved during your solutioning and prototype stage.

Try to mould the application around UCD principals, and avoid designing form applets with 100 fields, with 10 different buttons scattered across the top. The problem is Developers arnt Designers and Designers are often told that Siebel is impossible.

[Go the extra mile]

There is an argument that, the user should learn to live with what the system has to offer, and with proper brainwashing...sorry, i meant training, the user will get to use to its limitations and accept it.

But there is another "school of thought" which says, if the technology is out there, and its supportable, use it and give the client what they want, of course it has to be supported by good architecture, but go the extra mile and make life better for the user, because you don't want the user switching to another application.

The question is, whether we should give the users what they want, knowing that what they ask for will have some future upgrade or maintainance effort, or throw bookshelf at them and say its not possible.

Remember the risks, if we dont give the user what they want, they will use another system or worse, use a piece of paper instead.

Imagine, that a few years down the track, business decides to build a new web 2.0 portal to interface with Siebel as a back end, because it dosnt meet certain usability or accessebility needs. Look further down the track, this sexy portal takes over, and Siebel becomes a legacy system that is too costly to maintain, it is de-comissioned and replaced with newer technology.

Lets take a one last look at the scores again.
Siebel : 0
Web based system: 3
Paper based system: 1

So next time, the business asks you to perform some unconventional configuration, ask yourself these questions

1. Will it perform well?
2. Is it maintainable?
3. Can it be upgraded?

and

4. Is it sexy?

This is the beginning of a series of articles, where i'll introduce a funky requirement, and you guys tell me, if you would go the extra mile to implement it, and along the way we'll tackle some of the impossible limitations above.

Siebel MTOM Attachments

Audience

This article highlights the importance of MTOM in the enterprise, and provides a high level overview of the challenges that I faced bringing the MTOM standard into Siebel. Due to the proprietary nature of the environment, the source code for the implementation cannot be provided, but it is hoped that this article will provide a strategy for system designers/architects out there wishing to achieve the same goal and bring their project forward into the 21st century.

Background

As we slowly move towards the paperless society, handling attachments becomes a crucial part of the Enterprise Messaging landscape. With the popularity of Web service SOA architectures, SOA professionals found themselves with a tricky challenge. How to send binary data in XML?

XML is a textual data format, it has to be well formed and contain legal characters. If you take a binary string and put it between a set of tags, certain characters of the binary string may prematurely escape the tag, or make the XML invalid. In the early days SOA professionals got around this problem by encoding the binary string into Base64 format, which allows binary data to be represented in ACSII format. Although this does solve the problem of transmitting binary using XML, it is not very efficient. A Base64 string is 33% larger than the raw binary, which means more resources are need to handle the larger message, as well as taking longer to transmit.

The next evolution came when SOA professionals realized they can use MIME to send attachments, and thus SOAP with Attachments (SwA) was invented. In short its just an XML message with the binary data tacked at the end of the payload. The attachment is distinctly separate from the payload, which means the message processor has to implement logic to get the URI and retrieve the attachment, another downside is that SwA does not support Web Service Security (WS-S).

MTOM is the next advancement in attachment messaging, which combines the best of SwA and XML with inline attachments. MTOM is based on a slightly modified version SwA, which utilizes an XML Optimized Packaging (XOP) command to logically include the attachment as part of the message, instead of just referencing to the location of the attachment, it also supports WS-S.

That was 2004, today is 2011.

MTOM and Siebel

Siebel does not support MTOM, or even MIME through WS, the only supported method of sending attachments is through Base64 encoding. Base64 works well for small attachments, and is universally accepted, but what happens when Siebel is required to handle large attachments? There is little choice, it is Base64, MIME (non WS), or hire a technical architect that will design a custom MTOM framework for you.

Creating MTOM Messages

There are several approaches to creating MTOM messages in Siebel, here is a high level run down of the options.

Option A

1. Query IO and get a SiebelMessage with Base64 encoded attachments
2. Pass SiebelMessage to JBS, to construct a MTOM message and create the XML payload
3. JBS converts Base64 to Binary stream and appends to the above MTOM message

Adv: Easy to implement, No file management
Con: The Attachment will be converted from Binary to Base64, and back to Binary each way


Option B

1. Query IO and Get a SiebelMessage with Base64 encoded attachments
2. Convert SiebelMessage to MIME Hierarchy in Siebel
3. Parse MIME binary chunk to JBS
4. JBS reconstructs the MIME to MTOM structure, and inserts the proper XML payload

Adv: No file management, good fun for Java programmer
Con: Difficult to implement for a Siebel developer,
The Attachment will be converted from Binary to Base64, and back to Binary each way


Option C

1. Extract file attachments to filesystem
2. Pass file locations to the JBS
3. JBS reads file into memory, creates MTOM message and XML Payload
4. Delete extracted files

Adv: Easy to implement, Attachment is never converted to Base64.
Con: File management. Increased disk IO.


MTOM messages can be created using standard MIME classes, since MTOM is packaged as a multi part MIME message. After the MTOM message has been created, it can be passed back to Siebel or sent to the transport directly from the JBS.

The main theme in these options, is the usage of Java Business Services (JBS). eScript does not have any methods to retrieve binary from a PropertySet, hence it needs to be passed down to a JBS where it can be retrieved, and manipulated.


Importance of MTOM

Dealing with attachments is Business As Usual for many industries. For example, record keeping is a core part of every Government departments DNA, it serves as a means for accountability, and preserves memory for historical purposes. With the proliferation of broadband, hospitals can send X-rays and other medical documents to roaming doctors. Insurance companies can process claims through PDF and automatically store them in the document management system. Integrating with document management systems becomes one of the key programmes of work in the Enterprise, and handling attachments efficiently becomes a key non functional requirement.

The world has moved to MTOM, and for Siebel to remain relevant it must keep apace with new technologies, otherwise it risks becoming a legacy system. There is no immediate risk for Enterprises that deal with small file sizes, as Base64 is still an acceptable technology, as long as your ESB still supports it, but it will not scale well into the future, especially with High Res/HD content becoming mainstream on the horizon.

The problem arises when your Enterprise makes the decision to embrace MTOM, and when the Enterprise architects are deciding which projects will provide the file attachment functionality.

The question they will be asking is your Siebel project MTOM capable and ready?

Browser Script Debugger

One of the joys of working with Siebel is debugging Script, those late nights troubleshooting spaghetti code sure brings back memories. It is even more memorable when you encounter code that has never been unit tested, and wonder how did this ever get into production..

Ah the good times, but where would the fun be without Siebel's debugger. Set a break point where you think the error is occurring, let the application run, and Siebel will halt the execution of the Application at your designated break point, it will display all your current variables, and let you step through the code line by line.

Browser Script on the other hand has always been the poor cousin of eScript, it lacks the interactive debug tools, which has always made it harder to work with. Make a typo in eScript, and you'll probably get a compile error or it will halt your application, but with browser script, a typo will silently fail and halt execution of every other browser script in your application, its quite insidious.

There are a few common methods that developers rely upon to debug Browser Script.

The Alert/SWEAlert box is helpful but annoying and painful when working with loops. I know of people who have implemented browser popups that log information to a separate window, not bad, but dealing with popups is too clunky and slow. Siebel also provides the browser trace files similar to eScript, but a much better tool is the the IE Developer toolbar (IEDTB). It is shipped as part of IE8, but had been available as a separate Add-on for previous versions, if you've used Firebug on Firefox before, then this will be familiar to you.

The IEDTB allows the Siebel developer to

1. debug browser code
2. add breakpoints
3. use log statements
4. watch run-time objects and variables
5. inspect DOM elements
6. run code against the active session
etc, etc

In short, it is pretty badass.

If you are ready to turn to the dark side, press F12 on your keyboard now, otherwise press ALT-F4.



Logging

The IEDTB provides the browser with an object called "Console", with the following methods.

console.log('start function');
console.info('We love disco');
console.warn('warning');
console.error('error');
console.assert((1==2), 'Disco forever);
console.clear();

These methods can be used inside any of your browser script event in Tools, and the results can be inspected in the console window as shown below.



Note. The console must be open at the time when the scripts are run.

Breakpoints

This has always been the holy grail of Browser Script debugging.

Here's how it works. In the script drop down, find the JS script that you want to debug, and select it before navigating to the Siebel screen that actually fires it.

Click the left side of the left pane to set the break point.


Now navigate to the View that contains your browser script, and trigger your function. The IEDTB will stop at the breakpoint, and allow you to step through your code.

The Local window allows you to inspect all your local variables



The Watch window allows you to focus on particular variables and even change the value during run time.





You can also retrieve the values of the profile attributes, and run other browser commands by using the script console.



This is good news for all the Browser Script Jedi's out there, the IEDTB is an in-dispensible tool for debugging browser script, and beats the hell out of plain ol' Alert or SWEAlert

Best practice has it that we implement our logic using declarative means, then go to Script as a last resort, but there is an even finer unspoken distinction. When we have exhausted all declarative means, and all eScript means, you have reached the last resort, of last resorts. Welcome to Browser script town, when you get into this bad end of town remember to bring your IEDTB.

The IEDTB has saved my life more than once, and it will save yours as well.

Searching through UTF-16 files

In a typical day of a Siebel EAI developer, we are required to investigate problems with XML/XSLT files, and unless you know the system inside out, and outside in, you may encounter XML fragments that look unfamiliar.

For example, your ESB team sends you an XML that they claim to have been sent from your system, but from looking at the XML you dont recognise the interface that sent it. However you reason that, if you could search through all the XSLT files in Siebel you could track down the interface that could be generating this file.

The most obvious tool at the developers disposal is Windows Find, this is the defacto method of searching for files or text in files in a Windows OS, but beware because this method will not yield any results when searching through UTF-16 files. Surely Unix users would have more reliable tools in their arsenal. What about Grep?

Grep belongs to the Unix family of tools who's sole purpose is for searching, so how does this command fair with UTF-16 files? Fire up any Grep tool within reach and search for "xml" within your directory of UTF-16 XSLT files.

Here were my results.





FAILPASS
Windows BareGrepX
Mac GrepX
HP Unix GrepX


To understand this behaviour, open a UTF-16 file in a binary editor, you'll see that there is a "00" byte (shown as a space character) between every character, this is how UTF-16 files are physically represented in the file system, but open it in Notepad or your favourite unicode aware editor, and it will magically render the UTF-16 code points into your familiar readable XML.

With that understanding, it becomes clear why text matches will not work in programs that use a non UTF-16 regex engine.

This is a problem for any unsuspecting EAI developer and Siebel project that relies heavily on XSLT for its request/response Integration, but knowing thy enemy is half the battle already won, so here are a few tools to deal with UTF-16 files.

1. Windows findstr
eg. findstr /s /c:"siebelmessage" *.xslt

This command can match strings in UTF-16, and can be used to search directories.

2. Notepad++
3. TextPad

The above two text editors, could search entire directories, and match for text within UTF-16 files.

With this in mind, I'm sure you could easily find other utilities and programs that can scour through UTF-16 files.

It is a little unsettling to discover that you cannot rely on such ubiquitous tools such as Find or Grep for your Integration needs, but hopefully the next time you get that foreign XML in your inbox, you'll already have a hand on a nearby UTF-16 scraper.

Server Confirm dialog (Scriptless)

[Background]

Every Siebel professional knows that its impossible to get input from the user using Server script. The rationale is that server script runs on the server, and theres no way that it can pop something up on the client. Whats more ludicrous is to do it without any script.

Google for "Siebel Confirm" and you'll get a bunch of results stating that this is only possible using Browser Script.

Search in support web and you'll probably end up with these documents

1. How Should You Implement Message and Input Boxes in Siebel 7 and Siebel 8? [ID 476612.1]

2. How Can You Display a Message from a Server Script on the Browser? [ID 477323.1]

The conclusion is the same:

"Interactive dialog boxes are features that belong to the JavaScript language and can only be launched from browser script"

That sounds like solid advice, so would you believe me, if i told you that its possible to invoke a Confirm dialog from the server, using out of the box functionality?

Did i hear someone say "NO"!? Okay, that might have been my sub conscious.

If you are not convinced, let me introduce you to an undocumented business service that does just this.

[Confirm Dialog Business Service]

Business Service: LS Pharma Signature UI Service
Method Name:
ShowConfirmDialog

Open up Siebel and goto your business service simulator, and load up the following values

Inputs:
Cancel Method Name:
MyCustomMethod1
Confirm Text:
Winona, will you marry me?
OK Method Name:MyCustomMethod2

Your view should look like this.



Click run, and VOILA.



This produces an Ok,Cancel dialog that can be used across the application, but best of all, it is scriptless.

Now click either button, and you should get an error.


This happens because we havnt configured the application to handle these custom events, but lets try to invoke methods that we do know exist, and we'll perform some real configuration instead of basing our results off the simulator.

[Configuration]


Find your favourite BC and add the following user property, this will enable a custom method, and call the business service to display our Confirm Dialog.

Named Method

"InvokeAction", "INVOKESVC", "WS Transaction Settings", "LS Pharma Signature UI Service", "ShowConfirmDialog", "'Cancel Method Name'", "'NewRecord'", "'Confirm Text'", "'Hello'", "'OK Method Name'", "'DeleteRecord'"

Next find your favourite applet, and add a new button and set the following property:

Method Invoked: InvokeAction

The Ok and Cancel method definitions, will fire the respective events from the Applet to the BC, and from Browser to the Server, just like normal events, which you can subsequently trap and perform the intended action, based on the user response.

[Results]

NewRecord
This creates a new record in the applet

NewQuery This toggles the applet into Query mode

DeleteRecord
Interestingly, this brings up another confirm dialog. Infact, it looks damn similiar my own confirm dialog, except for the question text.

[Conclusion]


If you look hard enough, you'll find examples of this all over the application, heres another business service that does the same thing, except the message, and return codes are hard coded

Business Service: LS SubjectVisits Service
Method Name: ShowConfirmationDlg

This raises a few questions in my mind

1. Why isnt this documented?
2. Can we have control over how the dialogs are presented?
3. Can we display a message or prompt dialog in the same manner?

Maybe someone from Oracle engineering can answer this, but suffice to say, this is a great little nugget for Impossible Siebel readers.

On a closing note, if you would like more pizazz in your popups, change the buttons or add an icon, have a read of Alex's UMF Series, on Siebel Essentials. It should cover my requirements above.

Siebel Unified Messaging Framework - Part 1

Siebel Unified Messaging Framework - Part 2