Pages

Friday, May 20, 2011

Converting a WSDL to Javascript with Web 2.0 Feature Pack

In a previous post I discussed how easy it is to invoke web services from a browser using Websphere web 2.0 feature pack. One of the things I noticed is that it seems to parse the WSDL every time a page is loaded, which isn't necessary if we take a few additional steps.

WSDL2JS
Most developers who work with web services are familiar with a utility which converts a WSDL into generated code for a given language. Something like wsdl2java will generate java, wsdl2perl will generate perl and so on. What about wsdl2js?

As it turns out, the documentation for ibm_soap mentions that the parser holds JSON markup in a variable - all we have to do is grab the contents of that variable (smdString) and save it off to a file. Below is code that will parse a given WSDL and then copy the resulting JSON into a textbox for easy access.

<html>
<head>
<title>DsixE WSDL2JS</title>

<script type="text/javascript" src="dojo/dojo.js" djConfig="isDebug: false, parseOnLoad: true"></script>
<script type="text/javascript" src="ibm_soap/util/WsdlParser.js"></script>
<script type="text/javascript">
  
dojo.require("ibm_soap.widget.SoapService");
dojo.require("dojox.data.dom");
  
function wsdl2js() {
    
    // This is our homebrew wsdl2js. Json code is dumped to a textbox where
    // we can copy/paste it into a file.
    var wsdlParser = new ibm_soap.util.WsdlParser();
    var wsdl = dojo.byId("wsdl").value;
    wsdlParser.parse(wsdl);
       
    dojo.byId("json").value = "var myService=" + wsdlParser.smdString;
}
</script>
</head>

<body>
    <H3>Generate JSON from WSDL (wsdl2js)</H3>
    
    WSDL must not contain externalized schema, all schema must be defined in the WSDL.
    <br>
    
    WSDL URL: <input type="text" id="wsdl" size="80" value="http://"></input>
    <p>
    JSON: <br><textarea id="json" rows="20" cols="80">var myService={}</textarea>
    
    <p>
    <input type="button" id="callServiceButton" value="Create JS from WSDL" onclick="wsdl2js()"/>
</body>
</html>

I wish I could provide a working version on this blog, but I don't have access to a publicly available WAS server. Instead, here's a screenshot of what it looks like:


Now we can include our SOAP service using a script tag instead of parsing a WSDL every time a page loads.

Friday, May 13, 2011

Using Web Services from a Browser

For a long time I wondered why nobody has created a javascript library for web services. There are all kinds of libraries for REST services, but they're not very developer friendly. I much prefer the structure provided by a WSDL, and with tools like wsdl2java creating stubs for my code is a snap.


IBM's Dojo Soap Library

IBMS's Websphere application server offers a set of dojo extensions in their web 2.0 feature pack (FEP) which includes a SOAP library. I decided to take a look at it and found that it is quite easy to use although there aren't many examples to be found on the web. There is a sample provided with the feature pack but it uses the declarative dojo notation which doesn't work for everyone depending on what the goal is.


I opted to take a scripting approach since I already know how to invoke web services on the server side, and I wanted to see how it measures up in ease of use. Below is a simple example which retrieves data from a contacts web service I blogged about a while back.


Setting up the Infrastructure




My setup involved two different boxes - one running the webservice (axisbox) and another which hosted the HTML and the dojo SOAP library (dsixedev1). Due to the cross domain security restriction enforced by the browser, I also had to set up a reverse proxy (lenovobox). Your setup may vary, if everything runs on one box then this part doesn't really matter. Here's what I have in my apache httpd.conf:

ProxyPass /contacts http://lenovobox:8080/axis2
ProxyPassReverse /contacts http://lenovobox:8080/axis2

ProxyPass /was http://dsixedev1:9080
ProxyPassReverse /was http://dsixedev1:9080

The WSDL is loaded using this code:
var wsdlParser = new ibm_soap.util.WsdlParser();
wsdlParser.parse("contacts.wsdl");

Note that I don't load the WSDL directly from the service because it contains a reference to an external schema:
<xsd:schema>
   <xsd:import namespace="http://dsixe.com/blog" schemaLocation="ContactService.ContactInfoPort?xsd=ContactService_schema1.xsd"/>
</xsd:schema>

This reference causes the parser to fail, so I have to manually copy/paste the schema into the WSDL and then save it on the WAS server.

Putting it all Together
Here's a complete listing of the HTML document:
<html>
<head>
<title>DsixE SOAP Sample</title>

<script type="text/javascript" src="dojo/dojo.js" djConfig="isDebug: false, parseOnLoad: true"></script>
<script type="text/javascript">
  
    dojo.require("ibm_soap.widget.SoapService");
    dojo.require("dojox.wire.ml.util");
 
    function init() {
  
        var wsdlParser = new ibm_soap.util.WsdlParser();
        wsdlParser.parse("contacts.wsdl");

        // Create reference to service and set the URL
        var myService = new ibm_soap.rpc.SoapService(wsdlParser.smdObj);
        myService.serviceUrl = "http://lenovobox/contacts/services/ContactService.ContactInfoPort/";

        var params = new dojox.wire.ml.XmlElement("getContact");
        params.setPropertyValue("arg0", "ABC123");
        deferred = myService.getContact(params);
  
        deferred.addCallback(function(xmlData){
            // do something useful with the data here
            console.log(xmlData);
      
            var phone = dojo.query("phone",xmlData)[0].textContent;
            var name = dojo.query("name",xmlData)[0].textContent;
      
            dojo.byId("contact").innerHTML = name + " " + phone;
      
        });
    }

dojo.addOnLoad(init);

</script>
</head>
<body>


<H3> DsixE SOAP Sample - Calling a custom Contacts web service </H3>

This is a pure javascript example of how to invoke a SOAP operation without using declarative dojo markup.
<br><br>

<div id="contact"/>

</body>
</html> 

the SOAP response:
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <dlwmin:getContactResponse xmlns:dlwmin="http://dsixe.com/blog">
            <return>
                <name>Carl</name>
                <phone>678 555-1212</phone>
            </return>
        </dlwmin:getContactResponse>
    </soapenv:Body>
</soapenv:Envelope>

and the output it produces:
DsixE SOAP Sample - Calling a custom Contacts web service
This is a pure javascript example of how to invoke a SOAP operation without using declarative dojo markup.

Carl 678 555-1212

Overall I'm really pleased with the way IBM has done this, I've always been leery of REST services because they lack a structured type definition available in a WSDL, and the SOAP approach makes the code much easier to read.

Friday, April 15, 2011

Using dijit.TooltipDialog with Portlet Factory

WPF contains many useful builders for dojo, but these represent only a subset of what is available from the dojo toolkit. I've recently done work with the dijit.TooltipDialog and was able to integrate with portlet factory without too much fuss.

Retrieve a Page With Ajax Request
The key to integrating the tooltip dialog with WPF is to leverage the href attribute available for the widget. This provides the widget with a mechanism to retrieve the HTML we'd like to display in the dialog, in our case we want the URL to a page. Here's the java that we can use to generate that URL (see this entry for more):

JSPSupport.getActionURL(webAppAccess, webAppAccess.getBackchannelURLMapper(false), "keep_page:lm.page1")

Now let's throw together some HTML for the page builder that will display the dialog:

<html>
    <head><title>Default Test Page</title></head>
    <body>
           <div id="tooltipDialog" dojoType="dijit.TooltipDialog" style="display:none" onBlur='dijit.popup.close(this)'/>
           <div id='dialogTarget' onclick='showOrders()'>Show tooltip here</div>
    </body>
</html>

Note that we're using declarative markup to create the tooltip instead of javascript, and then setting its style to display:none. This is easier because it enables us to use an attribute setter builder to set the href:


Note here the last parameter is the page that we want to display, in my case I'm using a linked model to one of my previous blog entries referenced as lm so I have keep_page:lm.page1.

Finally, we have to add a dojo enable builder that will bring in the required package dijit.TooltipDialog and we'll add a little bit of javascript to display the tooltip when an element is clicked:

function showOrders(){
    var tooltipdialog = dijit.byId('tooltipDialog');
    dijit.popup.open({ popup: tooltipdialog, around: dojo.byId("dialogTarget") });   
}

The result looks like this, and unlike the dojo tooltip builder, we can interact with the contents of the dialog - in this case linked order numbers:

This example provides a good starting point for understanding how easy it is to integrate dojo with WPF.

Monday, April 11, 2011

Adding Custom Snippets to the WPF Picker

Like most websphere software, portlet factory is very customizable and contains several config files which enable the developer to do this. Right now I'm going to focus on the /WEB-INF/config/IndirectJavaExpressions.config file.

Add Your Own Code
I'm busy using dojo with WPF, and one of the things that I know will come up often is the ability to provide a URL to a model so it can display some HTML. I'll probably be using the reference chooser to this:


Now I could just select the replace with java expression item and then type in my code, but that would get tedious and I like things that snap into place (like WPF builders). I can quickly leverage WPF customization by appending some resuable code to the IndirectJavaExpressions.config in my project:

DsixE/AjaxPageURL=JSPSupport.getActionURL(webAppAccess, \
     webAppAccess.getBackchannelURLMapper(false), "keep_page:yourPageHere")

I save the file and go back to my model and now I see this:


I can add any number of shortcuts to this file and deploy to a team, instantly increasing their productivity and the quality of the applications they build.

Tuesday, April 5, 2011

Dynamically Changing dijit.TooltipDialog

I've spent the last week trying to use dijit.TooltipDialog to display widgets programmatically, and although I've found many examples of how to do this, none really addressed my particular case. In this blog entry I will provide a working example of how to manipulate a TooltipDialog using code.

Start Simple
Let's just create a dialog with a textbox on it, along with a simple onclick trigger:

<div onclick="showDialog()">clickme</div>   
<br>
<br>
<div id="dialogTarget">dialog appears here</div> 

<script type="text/javascript">   
    dojo.require("dijit.form.TextBox");        
    dojo.require("dijit.TooltipDialog");        
    
    var dialog;
     
    dojo.addOnLoad(function(){
        var tb = new dijit.form.TextBox({name:"tb1"});
    
        dialog = new dijit.TooltipDialog({
            content: tb,
            onBlur: function() { dijit.popup.close(dialog); }
        });
    });
     
    function showDialog(){
        dijit.popup.open({ popup: dialog, around: dojo.byId("dialogTarget") });
    } 
    
</script>    

A few things to note about this code - the content of a tooltip can be a dijit widget or HTML in quotes, and we can make the toolip appear on any element of our choice using the dijit.popup function. Most examples I could find showed content as HTML and the display of the tooltip triggered by a dijit.form.DropDownButton, neither of which fit my needs.

Change the Content
So what happens if the content of the tooltip dialog needs to be changed at runtime? This can be addressed using the attr() function:
<div onclick="showDialog(false)">clickme</div>   
<div onclick="showDialog(true)">clickme again</div>   
<br>
<br>
<div id="dialogTarget">dialog appears here</div> 

<script type="text/javascript">   
    dojo.require("dijit.form.TextBox");        
    dojo.require("dijit.form.NumberSpinner");        
    dojo.require("dijit.TooltipDialog");        
    
    var dialog;
     
    dojo.addOnLoad(function(){
        var tb = new dijit.form.TextBox({name:"tb1"});
    
        dialog = new dijit.TooltipDialog({
            content: tb,
            onBlur: function() { dijit.popup.close(dialog); }
        });
    });
     
    function showDialog(changeContents){
    
        if (changeContents){
           var mySpinner = new dijit.form.NumberSpinner({
                value: 1000,
                smallDelta: 10,
                constraints: {
                    min: 9,
                    max: 1550,
                    places: 0
                },
                style: "width:100px"
            });
    
            dialog.attr("content", mySpinner);
        }
           
        dijit.popup.open({ popup: dialog, around: dojo.byId("dialogTarget") });
    } 
</script>    
In this code I've made a few changes to support two options - clicking on one element (clickme) will show the dialog we created in the first example, and another (clickme again) will change the contents of the dialog with a dijit.form.NumberSpinner. The key line of code here is dialog.attr("content", mySpinner).

Try it here.

Loading Sametime Proxy Scripts

More useful insight on integrating sametime dojo widgets into a web application - this entry explains how scripts are loaded.

Why can't I find these scripts?

Inspecting the example HTML provided with the ST proxy, one can identify some scripts such as:

<script type="text/javascript" src="http://<YourServer>:9081/stwebclient/dojo_1.2.3/dojo/dojo.js"></script>
<script type="text/javascript" src="http://<YourServer>:9081/stbaseapi/baseComps.js"></script>
<script type="text/javascript" src="http://<YourServer>:9081/stwebclient/livename.js"></script>

but don't go looking for them in your filesystem because you won't find them. The HTTP requests are intercepted by a servlet that maps the filename in the URL to a physical filename in the stproxyweb.war. For example in the above case the request for livename.js is redirected to the physical file /dojo_1.2.3/sametime/LiveNameAll.js. This little bit of knowledge is very useful when debugging because many of the javascript files are also uncompressed, and loading that version makes life much easier.

So, we can replace our above example with this:

<script type="text/javascript" src="http://<YourServer>:9081/stwebclient/dojo_1.2.3/dojo/dojo.js"></script>
<script type="text/javascript" src="http://<YourServer>:9081/stbaseapi/baseComps.js"></script>
<script type="text/javascript" src="http://<YourServer>:9081/stwebclient/dojo_1.2.3/sametime/LiveNameAll.js.uncompressed.js"></script>

And now we can read the original code in firebug, enabling us to insert appropriate breakpoints.

Servlet mapping list

widgetsPart1.js >> stproxyWidgetsAllFirst.js
widgetsPart2.js >> stproxyWidgetsAllSecond.js
chatPart1.js >> stproxyChatAllFirst.js
chatPart2.js >> stproxyChatAllSecond.js
adderLoader.js >> stproxyAdder.js
meetingLoader.js >> stproxyMeeting.js
announcementLoader.js >> stproxyAnnouncement.js
widgets.js >> stproxyWidgetsAll.js
widgetsLight.js >> stproxyWidgetsAllNoDojo.js
livename.js >> LiveNameAll.js
livenameLight.js >>LiveNameAllNoDojo.js

Wednesday, March 30, 2011

Command Recall on AIX

One of the most frustrating things about working with unix is the lack of a user interface, everything is command line. Try explaining stuff like awk, grep, vi and ls to new users and the complaints start to roll in. What tops the list has to be the lack of command recall using the arrow keys. We've all been conditioned that pressing up-arrow will bring back the previous command so we can make edits instead of typing the whole thing over again.

No more. Below is a short series of commands that can be added to a .profile that will enable the arrow keys to behave in unix like they do in DOS:

set -o emacs
alias __A='^P'
alias __B='^N'
alias __C='^F'
alias __D='^B' 

Note that ^P refers to the keysequence control-p while editing the file using vi, so actually typing in the characters probably won't work.