Pages

Wednesday, August 17, 2011

Using soapUI with WebSEAL

In previous posts I explained how it is possible to invoke web services through a browser using javascript, and sometimes the service needs to be debugged using soapUI through WebSEAL.

WebSEAL and Cookies
My current infrastructure uses WebSEAL as a reverse proxy, which means that a session must be established before any of the back end servers can be accessed, including the server hosting my web service. This poses a
problem with soapUI which doesn't provide a mechanism to log into WebSEAL directly, instead I can establish the session using a browser and then copy the cookies into the tool.

Log into the application server and authenticate as usual, then copy the cookies using firebug:












Then paste the
cookies into soapUI:


Now all requests will forward the cookie information which WebSEAL should recognize, allowing it to pass through as authenticated.

Thursday, August 4, 2011

Certification for Web Experience Factory

After 20 years of working in the IT industry, I thought it would be nice to get a certification in something, so I finally took the time to study the new features in WEF 7 and attempt the test.

Hard to Know Everything

Rarely does one have the opportunity to learn all the features of a product, usually a client will focus on a subset of functionality because of the way they do things. One can become an expert with those features, but this produces a false sense that the expertise extends to everything. My case was no exception. Fortunately I worked with WEF on several client engagements which gave me a broader experience.

Why is this relevant? I strongly suggest that anyone who wants to take a certification test attempt a sample test first, which is what I did. It allowed me to evaluate the level of difficulty (it was not easy) and also pointed out the gaps that I needed to focus on.

So there it is, my first certification and a new footnote on my email signature.

Monday, July 25, 2011

Ajax Busy Indicators in WEF

This is my first posting for websphere portlet factory re-branded as web experience factory. I guess I'll have to get used to WEF, at least it sounds like a word now although not very meaningful.

Looking Under the Hood

I often seem to find myself snooping in code, usually when trying to fix a bug or extend some OOTB functionality to my liking. In this case I had a need to display some busy indicators during an unusually long ajax call, which led me to the javascript that enables ajax in WEF.

The file of interest is WebContent\factory\clientjavascript\ajax\ppr.js and inside it, the following code can be found:
// Can overload these to, e.g., show a progress indicator for long operations.
    startLoad: function() { },
    endLoad: function() {  },

Since directly altering this file is not a good idea, we can instead take the advice in the comment and overload the functions in our own script:
dojo.require("dojox.widget.Standby");
   var standby = new dojox.widget.Standby({
         target: "basic2"
   });

wpf_ppr.startLoad = function(){standby.show()};
wpf_ppr.endLoad = function(){standby.hide()};

I've used the dojo standby widget which does a great job communicating to the user that something is taking place while disabling part of the UI, preventing unnecessary repeated requests.

 Done!

Tuesday, June 21, 2011

Building a WPF Project with Ant

Generally speaking, I never endorse deploying an application to a production environment unless it has been built from scratch in a clean environment. This means that building a portlet factory WAR from the eclipse IDE is not the way to do a production build, even though it is really convenient.

Building with Ant

Apache ant has been around for a long while now, is an excellent framework for building WAR files and is the tool that WPF uses to build its own WAR files. In older versions of WPF the build process was somewhat lacking, but the team at IBM has really done a great job with the latest release of the product (I think this improved build may have been available in 6.1.5, but we skipped over that and went straight to 7.0).
Below is an example of how I've taken the sample build.xml provided with the product and modified it to pull code from CVS and allow for project specific settings.

The build.properties is mostly unchanged:
CVSTag=HEAD

# Build source root directory !NOTE! This value must be an absolute path.
buildsrc.location=C:/wsad/GCPS_V7/PF_Build/WPF7/${project.name}

# Build temp location. This is where the temporary project will be created for building purposes
buildtmp.location=${buildsrc.location}/buildtmp

# The root directory for the Portlet Factory files.
wpf.artifacts.dir=C:/wsad/GCPS_V7/PF_Build/WPF7

# The output location for the generated war files.
builddist.location=${buildsrc.location}/dist

# The location of the pbportlet.jar file. This ships with portal
c2a.lib.dir=${wpf.artifacts.dir}/WebSphere Portal

# The name of the project (used for identifiying war files)
project.name=SET PROJECT NAME IN XML BUILD FILE

#-- The following properties should not need to be changed under normal circumstances. --

# The root directory of the temp project. This is used by projectDeploy.xml
project.location=${buildtmp.location}

# The WebContent directory of the project that will be created. This is also used by projectDeploy.xml
webcontent.location=${project.location}/WebContent

# The output directory for standalone deployment wars.
build.deployment.war.builddir=${builddist.location}

# The output directory for the portlet wars
wpf.portletwar.location=${builddist.location}

# The shipping version of Portlet Factory
version=7.0.0

Note that I've added a new property CVSTag which is used to identify which label or branch to use with CVS. I've also changed the project.name property to a self descriptive value that will stand out during a build if it is not changed. The intent is that this build.properties file does not contain any project specific values - those will be set elsewhere.

Next, I've taken the sample build.xml and made a few changes to it as well:
<project name="build" default="build4GCPS" basedir=".">

  <!-- define build script properties. -->
  <target name="properties" depends="propertiesOverride">  
    <property file="build.properties" />
  </target>

  <target name="build4GCPS" depends="properties, clean">    

    <!-- create temp directory structure for building -->
    <mkdir dir="${builddist.location}" />
    <mkdir dir="${buildtmp.location}" />  

    <cvs package="${project.name}" cvsroot=":pserver:blduser:XXXX@cvserver1:/usr/cvs/projects" tag="${CVSTag}"/>

    <!-- create temp dir to build on top of -->
    <copy todir="${buildtmp.location}/.deployment">
      <fileset dir="${buildsrc.location}/.deployment"/>
    </copy>    

    <copy todir="${webcontent.location}">
      <fileset dir="${buildsrc.location}/WebContent"/>
    </copy>    

    <!-- optional task to generate the logs folder in the temp location. 
         Specific war generation tasks will log their data to this directory. -->
    <mkdir dir="${buildsrc.location}/WebContent/WEB-INF/logs"/>
    
    <!-- expand factory image into the webcontent.location -->
    <ant antfile="${webcontent.location}/projectDeploy.xml" target="expandFactoryImage" >
      <property name="runtime.image" value="${wpf.artifacts.dir}/Images/factory${version}.zip" />
    </ant>
    
    <antcall target="addPackages"/>
    
    <!-- build source files -->
    <ant antfile="${webcontent.location}/projectDeploy.xml" target="compile" />     
         
    <!-- build 286 portlet war, and give it a new name. -->
    <ant antfile="${webcontent.location}/projectDeploy.xml" target="buildPortletWar" >
      <property name="wpf.portletapi.target" value="build286StandardPortletWar"/>
      <property name="project.name" value="${project.name}"/>
    </ant>               
     
  </target>

  <target name="addPackages">    
      <fail>Your project ant script is missing a target named "addPackages". This is used to add WPF featuresets.</fail>
  </target> 

  <target name="propertiesOverride">    
      <fail>Your project ant script is missing a target named "propertiesOverride".</fail>
  </target> 
 
  <!-- clean the project -->
  <target name="clean" depends="properties">   
    <delete dir="${buildsrc.location}" />
  </target>  
</project>

Noteworthy, from top to bottom:
  • added depends="propertiesOverride" to the properties target.
  • added a call to the ant cvs task. This will retrieve any code that was added to source control.
  • removed the sample antcall to addFeatureSet and replaced it with a call to my own addPackages.
  • finally at the bottom I've added default implementations for the new targets that will cause the build to fail if they're not defined elsewhere.

Now that I've done some prep work, I can build any WPF project with a short bit of xml saved as MyAwesomeWPFProject.xml:
<project name="mainDeployment" default="build4GCPS" basedir=".">
 
    <description>Template script for building a portlet factory WAR for deployment</description>

    <import file="build.xml"/>
     
    <target name="propertiesOverride">  
        <property name="project.name" value="MyAwesomeWPFProject"/>
    </target>

    <target name="addPackages">    
        <ant antfile="${webcontent.location}/projectDeploy.xml" target="addFeatureSet" >
          <property name="pkg" value="${wpf.artifacts.dir}/Packages/Tutorials.pkg" />
        </ant>
    </target>   
    
</project>

The heavy lifting here is done with the import of build.xml, which is just like adding everything in that file to my script, but allowing me to override any targets within it. In this case I've added my own propertiesOverride where I can change values that were defined in build.properties and addPackages where I can add any featuresets that my project requires.

Building my project is now as simple as
ant -f MyAwesomeWPFProject.xml 
and if I need to build a specific version that has been labeled in CVS, I can provide that label like this
ant -f MyAwesomeWPFProject.xml -DCVSTag=MyLabel
which will override the value in build.properties.

Piece of Cake
Prior to this, I had my own homebrew build process that I am now glad to throw away. It served me well for the last three years, but this is more robust and I really like the way I can add featuresets.

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.