From the Director of Evangelism for Aptana

Kevin Hakman

Subscribe to Kevin Hakman: eMailAlertsEmail Alerts
Get Kevin Hakman: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn

Related Topics: RIA Developer's Journal, AJAX World RIA Conference

RIA & Ajax: Article

Real-World AJAX Book Preview: Use of Dummy Data in These Exercises

Real-World AJAX Book Preview: Use of Dummy Data in These Exercises

This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs for the special pre-order price, click here for more information. Aimed at everyone from enterprise developers to self-taught scripters, Real-World AJAX: Secrets of the Masters is the perfect book for anyone who wants to start developing AJAX applications.

Use of Dummy Data in These Exercises
Except for the two GUI components that we'll be configuring in this tutorial, the GUI components have been bound to dummy data sets - a technique useful in mocking up GUIs during GUI design processes.

We'll be using two live services in this tutorial: an XML service and a SOAP service. Be advised that these services return dummy data as well. No matter which parameters you submit, the responses will be the same.

Exercise 1: Find Customer Dialog
First, let's configure the Find Customer Dialog shown in Figure 13.2 so that it can display the results of a call to an XML service that finds customers. This will consist of four steps:

  1. Configure service call to put data in the cache in Common Data Format.
  2. Generate code to call the XML Service and bind an event to invoke it.
  3. Configure list to bind to the data returned from the service call.
  4. Add the event to publish customerSelected.
Suppose that the invocation method for this service is GET with a URL and URI passing three parameters as follows...

...where the response is an XML document that looks like this:

<?xml version="1.0" ?>
     <fullname>Michael Smith</fullname>
     <mainphone>415 545 5555</mainphone>
     <address1>123 Main Street</address1>
     <address2>Apartment 5</address2>
     <city>San Francisco</city>
     <fullname>Jane Smith</fullname>
     <mainphone>415 545 5555</mainphone>
     <address1>123 Main Street</address1>
     <address2>Apartment 5</address2>
     <city>San Francisco</city>

Configure the Service Call to Put Data in the Cache in Common Data Format (CDF)

  1. From the Project Files palette, open the customerFinder.xml file.
  2. Crtl-click on the name textbox to expand the component hierarchy and put focus on that textbox. Note the unique name property of this object, which will help simplify its binding to the Web service.

    Before the next step, you'll need either the .xsd that represents the schema of the response from the customer finder service or you'll need an actual sample response message to use as a template. In general if you have the XSD, that's your best approach. However, in this case, we'll just use a sample XML response. You'll find the sample response in a file we created for you in ../c360/rules/customerFinderResponseTemp.xml.

  3. From the Project Files palette's toolbar select New > Mapping Rule. This will open the visual XML Mapping Utility.
  4. Since this service is not a SOAP service, select the XML/XHTML/Schema option.
  5. Since this service's invocation method is a simple GET statement, there'll be no XML sent to the service as part of the request, so blank out the Outbound Document URL field.
  6. Next, starting with the file button to the right of the Inbound Document URL field, browse to /c360/rules/ and select customerFinderResponseTemp.xml. Press the open button in the dialog to commit the selection and dismiss the file browser dialog.

  7. Press the parse document(s) button.

  8. Set the endpoint URL field to the following URL, which will be useful for testing the service:

    The actual endpoint URL we'll set programmatically later.

  9. Set the Method selector to GET since this service uses a GET invocation method.

    We'll use the next set of steps to create mapping that takes the service output response message and generate, a CDF document from it in the GI data cache.

  10. Select the matches node of the response message.
    a. Click the button in the Mappings area.
    b. From the type selector, choose CDF Document and set the Path/Value field for this mapping to matches_cdf.

    This will generate a cache data document called "matches_cdf" when this mapping rule runs against the response message from the service.

  11. Select the first customer node of the response message.
    a. Click the button in the Mappings area.
    b. From the type selector, choose CDF Record. You can leave the Path/Value blank.

    This generates a CDF <record> node in the cache document for each <customer> node encountered.

  12. Select the customerID node of the response message.
    a. Click the button in the Mappings area.
    b. From the type selector, choose CDF Attribute and set the Path/Value to jsxid.

    This appends a jsxid attribute to the associated <record> node. jsxid is the unique identifier for a <record> node. If no unique identifier is mapped to jsxid, TIBCO General Interface generates and appends unique jsxid values for you.

  13. Repeat step 12 for the fullname and mainphone nodes of the response message, setting the Path/Value field to fullname and mainphone, respectively.
  14. Press the Save button in the XML Mapping Utility toolbar and save this file to /c360/rules/findCustomerMap.xml
  15. To test the configuration, right-click the Operation (Transaction) node and select Execute (Quick Test).

  16. Verify successful configuration by opening the Local Data Cache palette and viewing the matches_cdf document. The matches_cdf document should look like this:

    <data jsxid="jsxroot">
       <record jsxid="jsx_10" customerID="003162883161" fullname="Michael Smith" mainphone="
    415 545 5555"/>
       <record jsxid="jsx_11" customerID="003163649845" fullname="Jane Smith" mainphone="
    415 545 5555"/>

  17. Make sure you've saved your work and dismiss the XML Mapping Utility dialog. Configure List to bind to the data returned from the Service Call.
Next we'll configure a list control to bind to the matches_cdf data.
  1. With the customerFinder.xml component file open, select the list in the component hierarchy palette. You can also ctrl-click on the List onscreen to bring focus to this component.
  2. Open the properties palette and give this object a unique name: listMatches. This will make getting a handle to this GUI object easier later.
  3. Next set the Cache ID property of listMatches to matches_cdf. This binds the list to the CDF document.
  4. Select the colName column in the component hierarchy and set its path property to @fullname. This binds the column data to the fullname attribute on the CDF record. When you commit this setting, you should see data appear in the column.
  5. Repeat step 4 for colID and colPhone, setting the path property to @customerID and @mainphone, respectively.
  6. Save this component file by pressing ctrl-s, right-clicking the component file's tab and selecting save, or selecting save from the project files palette.
Generate Code to Call the XML Service and Bind an Event to Invoke It
Next we'll generate code that will call the service and handle its potential responses.
  1. Reopen the JSXAPPS/c360/rules/findCustomerMap.xml file from the project files palette by double-clicking it.
  2. With the operation (transaction) node selected, press the button in the toolbar. As the alert states this will put some code on your clipboard so that you can paste it into your code. Dismiss the alert and the XML Mapping Utility.
  3. Open the logic.js file from the project files palette.
  4. You'll see one function there already that loads the customerFinder dialog when called. Paste the contents of your clipboard onto the lines after the existing code block. The new code should look like this:


    "eg.service",       //the full name of the package to create
    function(service) {       //name the argument of this function
       //call this method to begin the service call (;) = function() {
         var objService = new"JSXAPPS/c360/rules/findCustomerMap.xml","");

         //set the namespace for the server (change this to run the rule in context of another server)

         //subscribe and call
         objService.subscribe(, service.onSuccess);
         objService.subscribe(, service.onError);
         objService.subscribe(, service.onInvalid);

       service.onSuccess = function(objEvent) {
         //var responseXML =;
         window[].alert("Success","The service call was successful.");

       service.onError = function(objEvent) {
         var myStatus =;
         window[].alert("Error","The service call failed.
    The HTTP Status code is: " + myStatus);

       service.onInvalid = function(objEvent) {
         window[].alert("Invalid","The following message node just failed
         validation:\n\n" + objEvent.message);


    First you'll notice the "package" structure at the top. This code block uses a package concept to provide a unique namespace for the service call and its callback functions. By using a package concept, you can better avoid potential name collisions between JavaScript functions when "mashing up" reusable GUI components and their associated functions. In this case the package name is "eg."

    Next, near the top of the code block, notice the service call referencing the findCustomerMap.xml mapping rules file you created.

  5. Change the generic = function()

    statement to

    service.callFindCustomerMatches = function()

    This way the name of the call will reflect what it actually does. To invoke this call, you'll need to start with the package to which it belongs as shown:


  6. Right-clicking on the logic.js tab select save and reload to save your changes to disk and reload the JavaScript in memory. If there are errors in your code, you should see error information in the system log at the bottom of your GI Builder window. If errors occurred, your files are still saved to disk, but are not loaded into memory.

    In the middle of the code block you'll find three subscriptions to call back events that eg.service. callFindCustomerMatches() may return: Success, Error, Invalid. Success will return a response from the server. Error is any error message from the server (e.g., file not found, timeout, server not found, and other standard HTTP errors). Invalid gets called before a service is invoked if the form of the outbound message doesn't match the schema of the outbound message. (But since we're not using schemas in this case, consider this a handy side note for now.)

  7. Next we need to pass the values of the three form fields in the URI of the call to the service. To do this, insert the code below right after:

    var objService = new"JSXAPPS/c360/rules/findCustomerMap.xml","");

    Now insert this code:

    n = c360.DOM.get('txtName').getValue();
    a = c360.DOM.get('txtName').getValue();
    p = c360.DOM.get('txtName').getValue();
    baseURL += "n="+n+"&a="+a+"&p="+p;


  8. Let's also add a few lines that tell the listMatches component to update its view since its data has arrived in the cache. To do this, comment out the line that displays the "Success" alert and add the lines below it as shown:

    // window[].alert("Success","The service call was successful.");

    // repaint the list to show resulting data c360.DOM.get('listMatches').repaint();

  9. To quickly test the code in the JavaScript Test Utility, press ctrl-e or open the JavaScript Test Utility window from the tools menu of GI Builder.
  10. Enter eg.service.callFindCustomerMatches(); in the code area and press the execute button. A success or error alert should appear, resulting from one of the two callback functions in the code block. Otherwise errors will appear, in the System Log.

    Next we'll bind the function call to the button in customerFinder.xml.

  11. Open or bring forward the customerFinder.xml component file in GI Builder. To bring it forward, click on the customerFinder.xml tab.
  12. Select the button labeled "Find Customer" by ctrl-clicking on it in the WYSIWYG view or expanding the nodes in the component hierarchy palette and selecting it there. Note that ctrl-clicking on the button will also cause it to fire its execute event, which by default is alert('hello');.

  13. Open the events editor palette and replace the default execute event with the following:


    Tip: You can also copy and paste this line from the JavaScript Test Utility where you were running it before.

    Note that the execute handles not only button-click events, but also enter key events when the button has tab focus. In general, behaviors of TIBCO General Interface controls parallel the behaviors of traditional "thick-client" controls. For example, the execute event for a button actually fires when you "mouseup" on the button after "mousingdown" on the button, instead of firing on the "mousedown" event, which is the best practice in more mature GUI systems. Accordingly, native DOM events have been abstracted up into these high-level event concepts. At the same time, GI also lets you bind to the native DOM events if you want to do so.

  14. Save the changes to the customerFinder.xml component file. You'll know the changes are saved when the red filename text of the component file tab turns black.
Congratulations. You've completed the first exercise and connected the Customer Finder Dialog's list to an XML service. Next we'll go one more sophisticated step further, implementing bindings to a SOAP service and using publish-and-subscribe interfaces to send messages between components.

Exercise 2: Update Customer Views
Now that we've made our call to the customer finder service, cached the results, and updated the view, we want to implement what happens when a customer is selected from the list.

Since our architectural strategy is based on the ability to mix-and-match future components that publish-and-subscribe to the GI pub/sub services, we'll implement the following:

  1. Publishing the "customerSelected" message with customerID data when a customer is selected in listMatches
  2. One or more functions that subscribe to the "customerSelected" message, each of which calls to a service, then publish a data-ready event using the cacheID of the data as the subject.
  3. One or more GUI components that listen for a "dataReady" message and update their onscreen views with the fresh customer data.
The following diagram shows the scheme:

Publishing the customerSelected Message
Select the listMatches in the component hierarchy for customerFinder.xml and using the events palette set the execute event to the following code:

objEvent = new Object();
objEvent.subject = "cutomerSelected";
objEvent.customerID = strRECORDID;

Since we mapped the customerID to the unique ID for each record (jsxid), we can easily access it since the strRECORDID context variable resolves to the jsxid for a given CDF <record>.

Save your work.

Subscribing to the customerSelected Event Subject and Publishing the CustomerDataReady Event
We've already created the Mapping Rules file getCustomerAccountsMap.xml that maps to a getCustomerAccounts SOAP service. This file is similar to the one you created earlier except it uses SOAP. Explore the various settings in getCustomerAccountsMap.xml.

Note that the Input message's customerNumber node has a mapping of type "Script" that sets eg.service.customerID to the value of that node. We append customerID to the eg.service package so we can access it as a context variable during the service call scripts below.

Also check out the binding for the "balance" node in the response message that returns a floating point value. This node has a mapping of typescript that converts the incoming float to a two-decimal value more appropriate to the human eye.

Below is the code block generated from the XML Mapping Utility, cleansed of the redundant package definition with the remaining functions, plus a few added lines for publishing an event when the service call is successful. This should be added into the existing eg.service package code block in logic.js.

Take note of the added line that overwrites the actual endpoint URL defined in the WSDL that was used to generate this mapping to the proxy URL we've set up for the service, so the call can be relayed through the sub-domain providing the application.

   //call this method to begin the service call (eg.service.callgetCustomerAccounts();)
   service.callgetCustomerAccounts = function() {
     var objService = new"JSXAPPS/c360/rules/getCustomerAccountsMap.

     //set the namespace for the server (change this to run the rule in context
of another server)
     //by default this service's end point is in a differnt domain
     //therefore, set the endpoint URL to invoke the service through the proxy
gate way
     //subscribe and call
     objService.subscribe(, service.ongetCustomerAc- countsSuccess);
     objService.subscribe(, service.ongetCustomerAc- countsError);
     objService.subscribe(, service.ongetCustomerAc- countsInvalid);

   service.ongetCustomerAccountsSuccess = function(objEvent) {
     //var responseXML =;
     // window[].alert("Success","The service call
was successful.");

     // the following lines publish a message with the subject set dynamically to
the cacheID of the CDF document recently added to the data cache
     objEvent = new Object();
     objEvent.subject = eg.service.cacheID; // this value set in the execution of
the XML Mapping Rules


   service.ongetCustomerAccountsError = function(objEvent) {
     var myStatus =;
     window[].alert("Error","The service call
failed. The HTTP Status code is: " + myStatus);

   service.ongetCustomerAccountsInvalid = function(objEvent) {
     window[].alert("Invalid","The following message
node just failed validation:\n\n" + objEvent.message);

Next, to create the handler for the "customerSelected" message we'll publish later, add the following function at the end of the same eg.service package:

service.listener = function(objEvent) {
service.customerID = objEvent.customerID;

The first line extends the eg.service package with a method called "listener." Using "listener" here is arbitrary. The next line sets a customerID property on the service instance to the customerID value of the published message objEvent that will be passed to this function. The last line calls the function that dispatches the asynchronous call to the SOAP service.

Last, we'll create the subscription for the eg.service.listener() function. Add the following code block to logic.js:

function c360init() {



We'll want to call this init function when the application starts up. Note that appCanvas.xml is set as the first GUI component to load when the project starts. Therefore we can call c360init() from the onAfterDesrialize property of the appCanvas.xml file.

To do this:

  1. Open appCanvas.xml or bring it forward.
  2. View appCanvas.xml's component profile by pressing the component profile button in the lower-right corner of the canvas area.
  3. Set onAfterDeserialize to c360init();
Now c360init() will get called immediately after the components in the appCanvas.xml load.

Save your changes and press the live component button in the lower-right corner of the canvas area to return to the WYSIWYG view.

To recap: we've published a message after selecting a customer from a customer list. We've configured a service call and subscribed it to that message. We've also scripted the service call to publish a message with the cacheID of the CDF data it creates after a successful call. Using these techniques, we could create additional service calls and subscribe them as well.

Subscribing to Data-Ready Message
Next we'll subscribe a GUI component to the cacheID message topic and create a message handler for it that will update the view of the GUI component with the cached data. Like the multiple services that could be invoked based on their subscriptions, multiple GUI components could listen for messages on various topics and execute related scripts.

We've already created the Accounts List component for you.

  1. Open the accountList.xml component file from the project files palette.
  2. View the component profile by pressing the component profile button in the lower-right corner of the canvas area.

The component profile contains an onBeforeDeserialize script area for scripts to run just before this component loads and an onAfterDeserialize script area for scripts to run just after this component loads.

Enter the following in the onAfterDeserizlize script block:

objGUI = c360.DOM.get('listAccounts');

The first line gets a handle to the object just loaded. The second line establishes the subscription to the repaint method of the component just loaded, triggered by a published message with a subject matching the XML cache ID of the component just loaded.

Now when the service call successfully runs, its onSuccess callback function will publish a message with the cacheID for the subject line and notify GUI components subscribing to that subject, that in turn update their views and display the new data.

To round out the solution, you can repeat the service call and subscription process pattern for other GUI components or JavaScript functions subscribed to the data objects.

Where to Go from Here
TIBCO General Interface is a robust professional-grade AJAX rich Internet application product. With features like the WYSIWYG reusable GUI component builder, the visual XML Mapping Utility, the publish/subscribe interface, and the local data cache, TIBCO General Interface speeds the process of authoring more complex corporate projects that take advantage of XML and Web Services. If you didn't notice it, GI Builder is an AJAX RIA implemented using TIBCO General Interface.

Granted it may seem at first to be overhead-heavy compared to the more procedural ways of implementing JavaScript functions and binding directly to DOM events, but the object-oriented Java Script techniques illustrated here have been tested and proven in enterprise deployments as effective ways to build and manage reusable and adaptable components and code.

TIBCO General Interface's object-oriented APIs give you many of the benefits of ECMAScript 2.0, such as class inheritance and packages, even though today's browsers only implement ECMAScript 1.x. If you're not into object-based publish-and-subscribe messaging on the client or the more robust capabilities object-based environments afford, TIBCO General Interface certainly lets you create procedural JavaScript functions and component event bindings. Plenty of examples can be found at the TIBCO General Interface Developer Community.

To learn more about TIBCO General Interface, visit the TIBCO General Interface Developer Community at The community provides software downloads, video tutorials, best practice papers, product documentation, sample projects with downloadable code (including this project), and active discussion forums.

This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs, click here to order.

More Stories By Kevin Hakman

Kevin Hakman is Director of Evangelism for Aptana, Inc., makers of the popular Aptana Studio web development suite. As early as 2001 Kevin was pioneering AJAX web applications via General Interface, a full AJAX development and GUI toolkit which he co-founded, and later sold to TIBCO Software in 2004. Kevin is a contributor to AJAXWorld Magazine, and has spoken at numerous AJAX industry events.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.