Pages

Tuesday, December 27, 2011

Using Fingerprint Scanner on Ubuntu

I recently acquired a new Lenovo W520 which included a biometric fingerprint scanner and since I generally shun windows in favor of Ubuntu 11.10, I really wanted to be able to use the scanner with Ubuntu.

Open Source Sweetness
Setting up the fingerprint reader on Ubuntu was a piece of cake. I just installed this fingerprint application and within seconds I was recording my index finger and using it to unlock my screen saver. It even works with sudo commands, kudos to the guys that put this together!

I think my only gripe, and this seems to be a popular one, is that the gui could use a little polish. So I decided to pull out my C++ skills of yore and see if I could make a few changes - this is open source after all and anyone brave enough can get the code and compile it.

Not So Easy
As with most open source bundles, I found a readme file with directions on how to build the package. Unfortunately that didn't work for me, I ran into a compile error:
In file included from ../../src/MainWindowImpl.cpp:46:0:
../../src/../include/UserSettings.h:30:20: fatal error: QtCrypto: No such file or directory
compilation terminated.
make[2]: *** [MainWindowImpl.o] Error 1
make[2]: Leaving directory `/home/dsixe/Downloads/fingerprint-gui-1.03/bin/fingerprint-gui'
make[1]: *** [sub-fingerprint-gui-make_default] Error 2
make[1]: Leaving directory `/home/dsixe/Downloads/fingerprint-gui-1.03/bin'
make: *** [sub-bin-make_default] Error 2

Taking a look at the makefile in /fingerprint-gui-1.03/bin/fingerprint-gui I found that a reference to QtCrypto was missing, so I added it:
INCPATH       = -I/usr/share/qt4/mkspecs/linux-g++-64 -I. -I/usr/include/QtCrypto -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtXml -I/usr/include/qt4 -I. -I../../include -I../../upek/include -I. -I.
Note that for some reason QtCrypto doesn't live in qt4 like the other Qt libraries.

Recompile, now I see:
g++ -m64 -Wl,-O1 -o fingerprint-gui DeviceHandler.o PermissionHandler.o AboutImpl.o ExistDialogImpl.o Fingerprint.o FingerprintData.o UpekDevice.o GenericDevice.o FingerprintGUI.o MainWindowImpl.o SavedDialogImpl.o MessageDialogImpl.o PamTester.o xmlwriter.o UserSettings.o UsbDevice.o moc_DeviceHandler.o moc_AboutImpl.o moc_ExistDialogImpl.o moc_Fingerprint.o moc_FingerprintDevice.o moc_FingerprintData.o moc_MainWindowImpl.o moc_SavedDialogImpl.o moc_MessageDialogImpl.o moc_PamTester.o qrc_GUI-res.o qrc_About-res.o    -L/usr/lib/x86_64-linux-gnu -lusb-1.0 -lfprint -lpam -ldl -lpthread -lQtXml -lQtGui -lQtCore
UserSettings.o: In function `UserSettings::UserSettings(char*)':
UserSettings.cpp:(.text+0x1fcc): undefined reference to `QCA::Cipher::~Cipher()'
UserSettings.cpp:(.text+0x1fd4): undefined reference to `QCA::SecureArray::~SecureArray()'
UserSettings.cpp:(.text+0x1fe1): undefined reference to `QCA::SecureArray::~SecureArray()'
It took me a long time to figure out that it was failing to link in the QtCrypto library. Resolved by adding -lqca to the same makefile:
LIBS          = $(SUBLIBS)  -L/usr/lib/x86_64-linux-gnu -lusb-1.0 -lfprint -lpam -ldl -lpthread -lQtXml -lQtGui -lQtCore -lqca
Finally, a clean compile!

Changing the Image
Now that I could compile the code, I went about making a simple change which didn't really involve altering any code. I wanted to change the animated gif file fingerprint-gui-1.03/src/res/Animation.gif to something else, and this required recompiling. For testing purposes I just converted the existing Fingerprint.png file to a gif and renamed it Animation.gif.

Now all I had to do is run make install and it should work. Once again, not so fast, something wasn't working. I finally just reinstalled clean from the repository and manually copied the file myself:
sudo cp fingerprint-gui-1.03/bin/fingerprint-plugin/fingerprint-plugin /usr/lib/fingerprint-gui/fingerprint-plugin
And now this is what I see when prompted to scan my finger:

Thursday, October 20, 2011

Using Environment Entries with WebSphere

I just spent the last few days trying to find an easy way to configure my web services deployed as annotated POJOs and I think I've found it. The idea is to provide an easy mechanism to change values through the administration console and have the java code pick up those changes at run time without redeploying. I thought about using a property file but this is inconvenient because we have a clustered environment and editing files in a deployment directory isn't the best idea.

@Resource Saves the Day
Anybody who used JNDI before the days of annotations knows that old style lookups were a little bit of a pain, but maybe I’m just being difficult. Here’s how I got it working - first thing is to add the proper entries in my web.xml:
<web-app...> ... <env-entry> <env-entry-name>DsixE/SomeParameter</env-entry-name> <env-entry-type>java.lang.String</env-entry-type> <env-entry-value>This really rocks</env-entry-value> </env-entry> ... </web-app>
Next I add an annotation to my code:
    @Resource(name="DsixE/SomeParameter")
    private String someParamter;
I build a WAR, deploy it to WebSphere and notice that I have a new entry in the administration console:


…. which allows me to change the value at any time:


Now the container injects the value defined into member variable someParameter at run time. This is the first time I’ve really used an <env-entry> so I guess this old dog can still learn new tricks.


Tuesday, October 18, 2011

Using Browser Web Services with SSO


A while ago I discussed how web services can be invoked using javascript in a browser, but there was a nagging problem that prevented me from deploying it into a production environment - how do I prevent a hacker from manipulating the user identifier in a request? Suppose we have an application that displays an end user's payroll information. In this case we need web service operation will retrieve information specific to the user's ID. We can't just send the user's identifier in the request because that would allow spoofing the ID of another person resulting in a breach of privacy.

Retrieving the User's Identity from the Container
In a servlet, it is relatively easy to retrieve the user's identity from the request, but this presents a problem if we're using JAX-WS annotated POJOs which have no concept of HTTP or a request object. How the heck do I figure out what the user ID is? I spent many hours looking at WS-Security but I got lost in all the details about policy sets and bindings and I just couldn't get anything to work. Then I found this writeup on developerworks:
http://www.ibm.com/developerworks/websphere/library/techarticles/1001_chung/1001_chung.html?ca=drs-

It is very close to what I wanted to do, but it uses WS-Security and I was dead in the water. Instead, I fell back on servlet security configuration to get the container to use the SSO LTPA token originating from WebSeal. This is the same way I would handle the situation if I was coding a servlet, but again - I'm working with POJOs, so no request object available. The developerworks article revealed the missing piece:
@Resource WebServiceContext wsCtx;

Putting it all Together
I coded a POJO and added JAX-WS annotations to expose it as a web service, then I added an @Resource that tells the container to pass the context:
package com.dsixe;

import javax.annotation.Resource;
import javax.jws.WebService;
import javax.xml.ws.WebServiceContext;

@WebService
public class ContactsService {
    @Resource WebServiceContext wsCtx;

    public String getName() {
        String userID = wsCtx.getUserPrincipal().toString();
        
        if (userID.equals("cdomingue"))
            return "Carl";
        if (userID.equals("csmith"))
            return "Christine";
        
        return "unknown: " + userID;
    }
    
}
Until this point I had never even looked at the web.xml bundled with the annotated POJOs into the WAR that I deployed to Axis2 since there are no servlets in it. I added the following security constraints to the web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>Jax-wsPolicyTest</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>ContactsService</web-resource-name>
      <url-pattern>
        /*
      </url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <description>
        Roles allowed to execute ContactsService
      </description>
      <role-name>AllAuthenticatedUsers</role-name>
    </auth-constraint>
  </security-constraint>
  
  <security-role>
    <description>All Authenticated Users Role</description>
    <role-name>AllAuthenticatedUsers</role-name>
  </security-role>  
</web-app>
I then deployed to the container and mapped the AllAuthenticatedUsers security role just like I would for any servlet. Protecting the resource caused the container to populate the WebServiceContext object and then I could retrieve the user ID.

Done!

EDIT: I was researching attachments with JAX-WS and found this very comprehensive writeup which I though would be good to read in this context.

EDIT: Here's another interesting read on this topic.

Monday, September 12, 2011

Can't Start Sametime

My current engagement uses the Lotus Sametime chat client and I use it on a daily (hourly) basis. Today, for no reason that I can discern, I was unable to start up the application after a computer reboot. The install creates a shortcut to C:\Program Files (x86)\IBM\Lotus\Sametime Connect\rcp\rcplauncher.exe and running that executable would do absolutely nothing.

After several attempts to figure out what was going on - including a failed attempt to reinstall the standard client - I found a lock file:
C:\Users\dsixe\AppData\Roaming\Lotus\Sametime\.rcp.lock
Delete the file, problem solved.

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.

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.

Thursday, March 17, 2011

Debugging Dojo with Firebug

I've spent the last few weeks trying to integrate sametime dojo widgets into a portal theme and I used firebug extensively to debug my code. Dojo is difficult to debug because of the way it injects code using the requires function, everything shows up as an eval.

Firebug Extensions

I didn't know this, but there are quite a few firebug extensions out there, though none really for dojo. IBM has developed a dojo extension for use in their rational developer products, but since I use eclipse I was out of luck. Thankfully IBM has a history of participating in the open source community and appears to have contributed their code to the firebug community.

The code can be found at http://code.google.com/p/fbug/source/browse/#svn%2Fextensions%2Fdojofirebugextension

I downloaded from their SVN server and executed the build.xml, drag/dropped the resulting dojofirebugextension-1.0a6.xpi into firefox and now I have a nice dojo interface for firebug.

Thanks to Patricio Reyna Almandos and Fernando Gomez (IBM Argentina) for putting this together.

Wednesday, March 9, 2011

Vague Error Message with Sametime Proxy

More insight related to my work with the integration of sametime into a portal theme. If anyone runs into this error:

SystemOut.log:[3/7/11 12:41:01:852 EST] 00000022 STLoginServle W com.ibm.rtc.stproxy.servlet.STLoginServlet loginbyToken  CLFRX0055E: unable to retrieve login credentials

the message is a little misleading. Yes, it cannot retrieve the login credentials, but why exactly? The proxy will produce this error if it cannot find at least one of the following in the request:
  • password
  • LtpaToken
  • LtpaToken2
  • SametimeToken
 In my case I was using SSO through a Webseal reverse proxy and I failed to qualify my junction as an LTPA junction. Webseal wasn't sending the token causing the above error.

Wednesday, March 2, 2011

Race Condition with Sametime Proxy Server

I've spent the last few weeks integrating a web based sametime chat client into websphere portal and ran into a curious problem. It seemed that on occasion the buddy list would not populate, all I'd get is a dojo busy indicator, but if I refreshed the page everything would be fine.

Time to open up firebug.

I have to admit that dojo isn't the easiest javascript to debug, they've really stretched the capabilities of the language, but I finally tracked it down to a piece of code during the execution of:

ST_Client = new sametime.WebClient({}, "STClient");

At some point it tests if it should display the buddy list right away or add the task to a queue for later execution, and in this case it was adding to the queue. So who is supposed to deal with the queue, and why wasn't it being done? Turns out that there's some code executed in the login

stproxy.login.loginByPassword()

that iterates through the queue and displays the buddy list. I was running into a race condition because I was trying to log in to the samtime server before showing the buddy list, but in some cases the login was finishing before the call to create the WebClient was done.

The Fix?

Ensure that the code creates the WebClient before it tries to login. Go figure.

Saturday, February 12, 2011

Running WPF Designer with Java 6

Today I encountered a perplexing error in the portlet factory designer:

(com/ibm/workplace/wcm/api/Workspace) bad major version at offset=6
Cannot instantiate Class Name: com.dsixe.wcm.Content - java.lang.UnsupportedClassVersionError: (com/ibm/workplace/wcm/api/Workspace) bad major version at offset=6

Now I've seen this type of error before, all it requires is a tweak to the project properties, change the runtime to the appropriate version - in this case it seemed to be 6. But the error would not go away.

The source of the problem was a linked java object builder pointing to a class which contained a reference to a class requiring java 6. When a classname is defined in the builder, I assume it must attempt to introspect the class to determine its methods, and I guess it was unable to instantiate it. So the problem seemed to be that the designer (eclipse) needed to execute in java 6 environment.

Switching to JRE 6

Eclipse start parameters can be defined in a configuration file named C:\IBM\Portlet Factory\Eclipse\eclipse.ini. One of those parameters tells it which JDK to use, so I added the following to the top of the file

-vm
C:\Program Files (x86)\Java\jre6\bin

Then I restarted eclipse. Problem gone.

EDIT 02/05/2013:

Using IBM's J9 JRE
Developers using the publish to websphere portal feature in the WEF designer will need to run the J9 version of java. This can be downloaded from http://www.ibm.com/developerworks/java/jdk/eclipse/ , ensure that you pick the 32 bit version and unzip (I put it in C:\IBM where WEF is installed). For some reason the install of WEF on windows uses 32 bit version of eclipse. Edit the eclipse.ini to use this:

-vm
C:\IBM\IBM_DevelopmentPackage_for_Eclipse_Win_X86_32_4.0.0\eclipseDevelopmentPackage\ibm_sdk70\jre\bin\javaw.exe


Wednesday, February 2, 2011

JNDI Datasource Names in WPF Designer

A common problem when working with data sources configured in the application server and the sql call builder is tying the two together. The builder provides a dropdown list of JNDI names that it thinks are
defined, but sometimes the name that you're looking for isn't there.


Ensure that your project is deployed

A typical scenario is starting a new project which contains a service provider model that retrieves data from a data source. You figure you've done this before so you know what you're doing, but somehow the JNDI name just isn't there.

Here's the problem - the designer needs to communicate with the server to retrieve the list of JNDI names, and it does this by issuing an http call to a model on the server from within the eclipse tool. So if the project hasn't been deployed or the server is not running, then the names cannot be retrieved.


Digging deeper

So you're sure that the project has been deployed and the server is running because you successfully executed another model in your project, but still no JNDI name. Here's where we can open up the hood and take a look at what's really going on. Navigate to \WebContent\WEB-INF\models\factory\core\db_utils.model, don't look for it in the \model folder because it's been hidden from view by the designer. Open the model and find a method builder called getDataSourceNames:


The coordinator for the sql call builder attempts to invoke this model at design time to retrieve the JNDI names, so any debugging is easily pinpointed here. It appears that the developers of WPF were kind enough to add some debugging logic in their code, try changing the debug value to true and watch for output in the server's system out log.

Thursday, January 27, 2011

Using VNCServer with SSH

This blog entry isn't directly related to WPF, but there are cases where a WPF project is deployed to a unix environment and there is a need to work with xwindows.

I've been successfully using vcnserver for many years with various flavors of unix, but I've always been stumped by something - when I ssh into another machine, my xwindows display stops working. As long as I stay on the original machine that is running vncserver, everything is fine but if I move to a different box I get the following error:

pdvboxb:/home/dsixe>xcalc
Xlib: connection to "pdvboxa:1.0" refused by server
Xlib: Client is not authorized to connect to Server
Error: Can't open display: pdvboxa:1.0

Well today I was in need to run an application that required xwindows and I decided to buckle down and find a solution to this nagging situation. Since my memory isn't what it once was, I'm going to record it on this blog so the next time I run into it I'll be able to trace my solution and maybe someone else will find it useful as well.

Here's the scenario, there are two machines - pdvboxa and pdvboxb. I log into pdvboxa using something like putty and fire up vncserver, then I log out and go back in using vnc viewer client to pdvboxa:1. Xcalc works fine here but not when I ssh to pdvboxb.

Several sites recommend using xhost + which seems to open up connections to anyone, but that would be bad. Besides, in my scenario it didn't work anyways.


Using xauth

A better solution is to use xauth to copy the magic cookie created by vncserver (I'm pretty sure vncserver created it) to the second machine pdvboxb.

On pdvboxa  run the command xauth list which returns something like:
pdvboxa:1  MIT-MAGIC-COOKIE-1  f73147c509311da56b94ba84597fa41b
pdvboxa/unix:1  MIT-MAGIC-COOKIE-1  f73147c509311da56b94ba84597fa41b

Now go to pdvboxb and run the command xauth add using the first magic cookie:
xauth add pdvboxa:1  MIT-MAGIC-COOKIE-1  f73147c509311da56b94ba84597fa41b

Ensure the display var is set correctly:
export DISPLAY=pdvboxa:1.0

Test by running xcalc and you should be good to go.

Thursday, January 13, 2011

Variables and Schemas in Portlet Factory

Anyone who has played with portlet factory will quickly learn that it depends heavily on xml defined by a schema. Putting some thought into this I realized that a schema is really a way to define a type and a WPF variable is an instance of that type. For example there is a close correlation between a java type definition such as:

public class Contact{
   public String name;
   public String phone;
}
...
public class Data{
   public List<Contact> dsixe;
}

and an xml representation of the same information as

<dsixe>
    <contact>
        <name/>
        <phone/>
    </contact>
</dsixe>

with a schema that looks like this

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:dsixe="http://dsixe.com/contact" targetNamespace="http://dsixe.com/contact">
   <xsd:element name="dsixe">
      <xsd:complexType>
         <xsd:sequence>
            <xsd:element ref="dsixe:contact" minOccurs="1" maxOccurs="unbounded" />
         </xsd:sequence>
      </xsd:complexType>
   </xsd:element>
   <xsd:element name="contact">
      <xsd:complexType>
         <xsd:sequence>
            <xsd:element ref="dsixe:name" minOccurs="1" maxOccurs="1" />
            <xsd:element ref="dsixe:phone" minOccurs="1" maxOccurs="1" />
         </xsd:sequence>
      </xsd:complexType>
   </xsd:element>
   <xsd:element name="name" type="xsd:string" />
   <xsd:element name="phone" type="xsd:string" />
</xsd:schema>

Combining the variable builder with the schema builder

Portlet factory provides separate builders to define a schema and a variable, but sometimes it would be nice to combine both into one when I need a quick and dirty variable and I don't want to create a standalone schema file. If I know what my xml structure looks like then I want WPF to just figure out what the schema is based on some sample data in one motion.
To that end I created a custom builder that combines elements from the variable builder with those of a schema builder:


The builder creates a schema in the model with a suffix _xsd and a variable with a suffix _var:

The builder can be downloaded and installed as a WPF package under Optional Libraries feature set.

Adding Help Feature to Custom Builders

Portlet factory has a great feature which allows creation of custom builders, fantastic for extending the already rich set of builders provided by the tool. Sometimes these custom builders are used to encapsulate business specific functionality to be shared across an organization and providing some help documents can accelerate their adoption.
Adding custom help files that integrate with the designer is quite easy, just take a look at the builder definition file and you'll find a HelpFile element:

  <HelpFile>WEB-INF/builders/com/dsixe/builders/doc/schemagen_builder.htm</HelpFile>

The developer can specify a location for html help that will be tied to the help button on the builder. I like to follow the same look and feel of the stock builder help, so I usually start with an existing file which can be found in {WPF_INSTALL}\Designer\eclipse\plugins\com.bowstreet.designer.doc_*\designer and copy it to my local project.
Using this approach I can put together some really professional looking documentation to support the hard work I put into creating the builders.

An example builder definition file can be found in the attachment for my previous post Variables and Schemas in Portlet Factory.

Wednesday, January 5, 2011

Adding a Custom Toolbar Item to Dojo Rich Text Edit

As mentioned in a previous blog post, dojo's rich text editor includes a plugin mechanism to add custom toolbar items. In this post I will explore how I accomplished this, details of how to integrate into WPF can be found here.

My goal is to be able to click on a toolbar button and have a modal dialog box with a lightbox effect appear. The contents of the dialog is a custom search result where individual result items can be selected, causing the dialog to close and inserting a link to that item in the rich text edit.

Create a New Plugin

Since writing code from scratch is tedious (I am impatient) I always prefer to start with something that works and then modify it to meet my needs. In this case I've taken the plugin named factory\dojo\dijit\_editor\plugins\ToggleDir.js since it's nice and short, and re-purposed it to create a modal popup window when clicked. I'm going to copy it into a new file named SearchPopup.js.

dojo.provide("dijit._editor.plugins.SearchPopup");
dojo.require("dijit._editor._Plugin");
dojo.declare("dijit._editor.plugins.SearchPopup",
    dijit._editor._Plugin,
    {
        // summary:
        //        This plugin provides a popup window to search and select content
        //
        // description:
        //        The commands provided by this plugin are:

    _initButton: function(){
        // summary:
        // This is the button that will appear on the toolbar
        this.button = new dijit.form.Button({
            label: "Search and add content",
            showLabel: false,
            iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "CreateLink",
            tabIndex: "-1",
            onClick: dojo.hitch(this, function(){popupSearch()})
        });
        }
        
    }
);

// Register this plugin.
dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
    if(o.plugin){ return; }
    switch(o.args.name){
    case "searchPopup": 
        o.plugin = new dijit._editor.plugins.SearchPopup();
    }
});


This is probably the most basic plugin that can be created. All it does is invoke a javascript function named popupSearch() when the button is clicked:
onClick: dojo.hitch(this, function(){popupSearch()})

The code to pick an icon is a little tricky, it refers to factory\dojo\dijit\themes\tundra\images\editor.gif which is an image containing a long strip of icons like this:

and finally the iconClass can be tracked down in factory\dojo\dijit\themes\tundra\Editor.css:
Code:
iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "CreateLink",

Matching CSS:
.tundra .dijitEditorIconCreateLink { background-position: -90px; }

If I wanted to use my own icon I'd have to edit the icon strip and add a new image, but since I can't draw to save my life I decided to just reuse the one for creating a link. The rest of the code is just boilerplate, and we can add our newly minted plugin to the toolbar with some javascript:
dojo.addOnLoad(function(){
 dojo.require("dijit._editor.plugins.SearchPopup");
 var widget = dijit.byId(gcps.assessmentWidget);
 widget.addPlugin('searchPopup');
});

EDIT 2/14/2012: I found a pretty good developerworks article on this topic. Check it out.