Doug McCune on Flex and Enterprise Development

Posted in Jon Rose on March 30th, 2009 by jonr

Today, I posted an interview I did with Doug McCune on InfoQ.com. His personality and passion for development came through in his encouragement for developers to build “cool shit.” I love the sentiment, as I so often get trapped in trying to bring business value and forget that sometimes software development should just be a creative endeavor. However, as cool as that sounds, it can be challenging to bring that sort of mindset into the enterprise. With that in mind, Doug had some really interesting comments on UX within business applications:

Enterprise software is almost uniformly horrible, but there’s no reason for that. We’re seeing a “UX revolution” in RIA design, and for all the buzzword nonsense surrounding “user experience, ” there’s something real happening in terms of the overall quality of the experience delivered by RIAs. We’ve seen some really great and innovative work in consumer RIAs, with a trend toward simple and intuitive interfaces. And yet in enterprise software this trend has barely even begun, it’s all still complex. I want to see enterprise applications treated like consumer apps, with the same attention to the user experience and with a consistent drive to simplify and make everything more intuitive. Complex systems don’t have to be presented with confusing software. But it takes more work to figure out the simple, elegant solution. It’s far cheaper and faster to make bad complex software than good simple software.

I also think there’s a business intelligence breakthrough afoot that will bring these same concepts of intuitive software specifically to the BI arena. Business intelligence is just a fancy way of saying that you’re extracting value from raw data in some way. This is typically limited to your mundane set of charts, gauges, and all the other normal dashboard UI elements that are the current standard. But I think thinking about BI problems from a fresh perspective, from the perspective of someone outside the enterprise space, will lead to the invention of new visualization methods. Maybe sales performance isn’t something best shown using a silly looking speedometer gauge. Maybe there’s an intuitive way to extract more value from that heap of raw data sitting on enterprise servers. But I don’t think enterprise developers have been willing enough to experiment with new concepts. People need to start inventing.

I have to agree that enterprise software is generally poor, particularly in the user interfaces.  In addition, his comments on working toward the simple, elegant solution makes me want to scream, “Yes!”  I think the only place I differ with him on is where the blame belongs for the overall low quality of enterprise systems.  Developers do deserve some of the blame, but I think generally the challenges come from the organizations, project owners, and managers who do not understand what is now possible, or even worse never understood how to build software to begin with.

In years gone by, the platforms really limited the ability of developers to build cool user interfaces that still made sense on the budget.  I was originally drawn to Flex because it can do things that simply weren’t possible on the web only a few short years ago.  This probably factors into the decisions that even smart, experienced managers are still making today, as many of them have previous attempts at doing cool things that led to ballooned budgets and jeopardized projects.

So, there is the obvious onus on developers to sell their ideas and educate their organizations on what is possible now that the platforms have capabilities way beyond getting data in and out of the database.  However, with that said, the real limitation of enterprise software will always be that the teams building most systems are part of companies that do not exist to build software, and often just don’t understand the processes, the platforms, the code, the users, etc.  In those cases, it is unlikely that they will be able to overcome their limitations to build cool, highly usable systems.  So, while I am optimistic that the advances that have come with the RIA revolution will trickle into the enterprise, it is unlikely that they will have the same impact on business applications as we are seeing in consumer applications built by companies that exist solely to build quality software.

If you enjoyed Doug in writing, check him out in this recent Flasher Magazine video interview. Also, look for him in a future DrunkOnSoftware.com interview.

Dynamically modifying the HTML space allocated to a Flex Application

Posted in Glen Whitbeck on March 28th, 2009 by admin

If you need to integrate a Flex application into an existing web page, you will probably want control over the amount of space that the Flex application uses on the web page. If the Flex application size never changes, you can simply set the height and width of the Flex application in the HTML code (in the Object and Embed tags). However, if the Flex application size is dynamic based upon user interaction, you will may want the HTML space allocated to the Flex application to change as the Flex application size changes. The purpose of this post is to show how this can be done.

The following Flex application has an “Add Fields” button. If you click that button, two things will happen. First, the “Add Fields” button will be removed. Second, a TextArea and another button (“Remove Fields”) will be added. This behavior will cause the height of the Flex application to grow. The Flex application will make a JavaScript call to the containing page to dynamically change the space allocated to the Flex application.

Similarly, if the “Remove Fields” button is clicked the height of the Flex application will shrink. So, again, the Flex application will make a JavaScript call to the containing page to dynamically change the space allocated to the Flex application.

In order to accomplish this, we first need to insert our Flex application into the containing HTML page:

<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
	codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab
#version=6,0,40,0"
	WIDTH="1" HEIGHT="1" id="mySwf" scrolling="no">
	<PARAM NAME=movie VALUE="FlexibleGorilla.swf">
	<PARAM NAME=quality VALUE=high>
	<EMBED src="FlexibleGorilla.swf"
		quality=high
		scrolling="no"
		WIDTH="1"
		HEIGHT="1"
		NAME="mySwf" ALIGN="" TYPE="application/x-shockwave-flash"
		PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer">
	</EMBED>
</OBJECT>

Next, we will add the following JavaScript function to the containing HTML page:

function updateSwfSize(myHeight, myWidth) {
	var flexibleGorillaSwf = document.getElementById("mySwf");
	flexibleGorillaSwf.height = myHeight;
	flexibleGorillaSwf.width = myWidth;
}

Then, in the Flex application, we will call this JavaScript function everytime the Flex application size changes. Here is the Flex code used in the example application:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"
							creationComplete="create()">

	<mx:Script>
		<![CDATA[

			private function create():void {
				updateSwfSize();
			}

			private function addFields():void {
				this.addButton.visible = false;
				this.addButton.includeInLayout = false;

				this.myTextArea.visible = true;
				this.myTextArea.includeInLayout = true;
				this.removeButton.visible = true;
				this.removeButton.includeInLayout = true;

				updateSwfSize();
			}

			private function removeFields():void {
				this.addButton.visible = true;
				this.addButton.includeInLayout = true;

				this.myTextArea.visible = false;
				this.myTextArea.includeInLayout = false;
				this.removeButton.visible = false;
				this.removeButton.includeInLayout = false;

				updateSwfSize();
			}

			private function updateSwfSize():void {
				this.validateNow();

				var newHeight:Number = this.myVBox.height;
				var newWidth:String = "100%";

				if (ExternalInterface.available) {
					ExternalInterface.call("updateSwfSize",
								newHeight,
								newWidth);
				}
			}

		]]>
	</mx:Script>

	<mx:VBox id="myVBox" horizontalAlign="center" width="100%">
		<mx:Label text="Dynamic Sizing Example" />
		<mx:Button id="addButton" label="Add Fields" click="addFields()" />

		<mx:TextArea id="myTextArea" text="FlexibleGorilla.com"
					width="90%" height="100"
					visible="false" includeInLayout="false" />
		<mx:Button id="removeButton" label="Remove Fields"
					click="removeFields()"
					visible="false" includeInLayout="false" />
	</mx:VBox>

</mx:VBox>

Degrafa Button Explorer

Posted in Justin Shacklette on March 27th, 2009 by admin

Recently, I’ve been playing around with Degrafa in preparation for actually using it on an upcoming project at work. For those that aren’t in the know, Degrafa is a badass graphics framework for Flex. One of my favorite parts so far is the amazing leverage it brings to building custom-styled components. It’s terse and powerful, just the way I like it.

Building Buttons

With a very minimal amount of effort, I was able to create a few “web 2.0″ button skins. I just followed one of the millions of glass button photoshop tutorials, but did the work in mxml code using Degrafa’s declarative syntax. Here are my results (view source enabled):

Flash is required. Get it here!
Button Explorer

But then I decided to take it a step further and build out a Degrafa Button Explorer (with a small tip of the hat to the original Flex Style Explorer). The Degrafa Button Explorer allows you to adjust a bunch of properties and colors for all three buttons styles. It goes a step further than the original and provides not only the CSS, but also the full code of the stateful Degrafa-powered button components.

 »  Degrafa Button Explorer

Digging Deeper: I’ve been following the skinning performance issues discovered by the guys at EffectiveUI. The most recent benchmarks appear to show that stateful Degrafa skins (like those produced by the Degrafa Button Explorer) are safe to use.

Flex JavaScript Communication

Posted in Glen Whitbeck on March 26th, 2009 by admin

I was recently developing a Flex application that needed to be integrated into an existing e-Commerce site. As part of the integration, I needed to communicate information between the Flex application and the containing HTML / JavaScript page. I don’t believe I’ve ever seen a web site that put together all of the various scenarios that I wanted in one place. So, I put together an application that contains small examples of each scenario that I was interested in. I thought it might be helpful to post these simple examples for others.

Trinidad Draggable Dialogs

Posted in Bob Hedlund on March 24th, 2009 by admin
Users of Apache Trinidad may have run across the issue of not being able to move the Trinidad dialogs around the page. They always sit right in the center of your screen and of course block you from seeing the information behind. In release 1.02 the authors proposed that the dialogs should be made drag-able, however nothing has been done. The following is a simple solution I used to make the dialogs drag-able. If I had time, I would commit something to the project to handle this - although I believe the reason it has not yet been implemented is because of the amount of cross browser code needed to affect this. The following solution took about 5 hours to come up with and refine.

The trick with making the dialogs drag-able is that that the dialogs are generated after the page loads, use different markup depending on browser type and version, and the markup contains no ids on the DOM elements of interest. I implemented this for Firefox2, 3 and ie7. For other browsers, the dialog is rendered with standard behavior.


So lets get started:

Step 1: Add the mouse drag event script to the Trinidad dialog:

In your xhtml/jsp file that will display behind the dialog , add a trh:script call that is rendered conditionally based on browser. The call will need to wait until the page loads to execute, so I add a timer to delay invokation:

trh:script text="window.setTimeout('attachDraggabilityToDialog()', 500);"
rendered="#{UiUtils.supportsDialogDrag}"

partialTriggers="::pprDialogCallButton "


The text attribute calls the attachDraggabilityToDialog script 500 ms after the page loads ( I place the script at the bottom of the page. )

The rendered attribute calls a backing bean function that specifies whether the browser version is supported for dragging.

The Partial Triggers attribute references Trinidad element id that pops up the dialog - in this case the button.

Step 2. Create the script:

// the frame
var dialog_frameDiv= null;
// the title bar on the frame
var dialog_titleBar=null;
// the object to drag around
var dialog_dragObj = new Object();
var GECKO=0;
var IE=1;
var BR_VER=GECKO;
new Browser();




/**
* After the page has loaded, and the popup has been displayed,
* Call this function:
* e.g: window.setTimeout(attachDraggabilityToDialog, 500);
* NOTE _ WORKS IN FF2, 3 AND IE 7
*
*/
function attachDraggabilityToDialog() {
dialog_dragObj = new Object();
dialog_frameDiv= null;
dialog_titleBar=null;

if (BR_VER==GECKO) {
for(var i =0; i <
window.document.body.childNodes.length;i++) {
dialog_frameDiv= window.document.body.childNodes[i];
if(dialog_frameDiv!=null && dialog_frameDiv.nodeName=="DIV" && dialog_frameDiv.style.zIndex==5001) {
dialog_titleBar=dialog_frameDiv.childNodes[0];
break;
}
}
}
else if (BR_VER==IE) {
var _node = document.getElementsByTagName("iframe")[0].parentNode;
if(_node !=null && _node.tagName=="DIV"){
dialog_titleBar= dialog_frameDiv=_node;
}
}

if(dialog_titleBar !=null) {
if (BR_VER==IE) {
dialog_titleBar.attachEvent("onmousedown", callDrag);
dialog_titleBar.attachEvent("onmouseup", endDrag);
}
if (BR_VER==GECKO) {
dialog_titleBar.addEventListener("mousedown", callDrag, true);
dialog_titleBar.addEventListener("mouseup", endDrag, true);
}
}

}



Discussion: Based on browser version, we look through the generated markup in the page once the dialog has appeared and find the element based on attributes or expected location of the node in the tree. While not foolproof, this technique works in the many scenarios in our present application, as Trinidad generates the dialogs in a standard manner per browser and version.

The attachDraggabilityToScript injects event handlers onto the elements to be dragged. The event handlers are below:


function callDrag(event) {

var el;
var x, y;
dialog_dragObj.elNode = dialog_frameDiv;

if (BR_VER==IE) {
x = window.event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;
y = window.event.clientY + document.documentElement.scrollTop+ document.body.scrollTop;
}
if (BR_VER==GECKO) {
x = event.clientX + window.scrollX;
y = event.clientY + window.scrollY;
}


dialog_dragObj.cursorStartX = x;
dialog_dragObj.cursorStartY = y;
dialog_dragObj.elStartLeft = parseInt(dialog_dragObj.elNode.style.left, 10);
dialog_dragObj.elStartTop = parseInt(dialog_dragObj.elNode.style.top, 10);

if (isNaN(dialog_dragObj.elStartLeft)) dialog_dragObj.elStartLeft = 0;
if (isNaN(dialog_dragObj.elStartTop)) dialog_dragObj.elStartTop = 0;

if (BR_VER==IE) {
document.attachEvent("onmousemove", startDrag);
document.attachEvent("onmouseup", endDrag);
window.event.cancelBubble = true;
window.event.returnValue = false;
}
if (BR_VER==GECKO) {
document.addEventListener("mousemove", startDrag, true);
document.addEventListener("mouseup", endDrag, true);
event.preventDefault();
}

}


function startDrag(event) {

var x, y;


if (BR_VER==IE) {
x = window.event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;
y = window.event.clientY + document.documentElement.scrollTop+ document.body.scrollTop;
}
if (BR_VER==GECKO) {
x = event.clientX + window.scrollX;
y = event.clientY + window.scrollY;
}


// Move drag element by the same amount the cursor has moved.

dialog_dragObj.elNode.style.left =(dialog_dragObj.elStartLeft + x - dialog_dragObj.cursorStartX) + "px";
dialog_dragObj.elNode.style.top =(dialog_dragObj.elStartTop + y - dialog_dragObj.cursorStartY) + "px";

if (BR_VER==IE) {
window.event.cancelBubble = true;
window.event.returnValue = false;
}
if (BR_VER==GECKO) ;
event.preventDefault();
}


function endDrag(event) {
if (BR_VER==IE) {
document.detachEvent("onmousemove", startDrag);
document.detachEvent("onmouseup", stopDrag);
}
if (BR_VER==GECKO) {
document.removeEventListener("mousemove", startDrag, true);
document.removeEventListener("mouseup", stopDrag, true);
}
}



Discussion : The above event handlers move the DOM element based on mouse movements after the user mousesdown on the element, and releases once the user mouses up based on browser version.


Finally, I have a simple browser detect , knowing that my script will not be called unless the browser is Firefox2, 3 or IE 7.


function Browser() {
var ua, i;
ua = navigator.userAgent;
if ((i=ua.indexOf("MSIE")) >= 0) {
BR_VER=IE;
}
}


In my backing bean, I have the following browser detection code that conditionally renders the call to the script based on its findings:



/**
* Currently only ff2,3 ie 7
* @return tru if the browser is one of the above.
*/
public boolean getSupportsDialogDrag() {
String ua = UiBaseUtils.getRequest().getHeader("User-Agent");

if(ua ==null)
return false;

if(ua.contains("MSIE 7"))
return true;
if(ua.toUpperCase().contains("GECKO")){
if(ua.contains("Firefox/3."))
return true;
if(ua.contains("Firefox/2."))
return true;
}
return false;

}



That's it.

I believe the correct way to do this would be to donate time and code to the Trinidad Project. I hope to do this , but I needed to come up with a quick solution that worked. I was able to commit this in less than 24 hours after getting the requirement, so please take this solution with this caveat in mind. QA has found no issues, and user feedback has been positive.

Hibernate AliasToBean Transformer

Posted in Bob Hedlund on March 24th, 2009 by admin
Problem: You need to access values from tables that are not hibernate entities, in an aplication that uses hibernate to access the database.

Problem: You want to access a couple columns from any number of tables in your database without bringing back all the associated objects.

Solution: AliasToBean Transformer allows you to retrieve specific information in non entity beans.

This hibernate API call will allow you to run sql against your database and populate a list of pojos that are not a hibernate entity. This technique is great when you need specific information or perhaps you want information fom multiple tables.


Your pojo:

Class PlainOldObject {
String s1;
String s2;

public String getS1() {return s1;}
public String getS2() {return s2;}

public void setS1(String s1) {this.s1=s1;}
public void setS2(String s2) {this.s2=s2;}

}

Then in a hibernate dao :

publc List lookupPlainOldObects() {

// the sql with a reference to the s1 and s2 fields in our object
String sql="select tableX.col1 as s1, tableY.colx as s2 where blah blah blah";

List list = getCurrentSession().createSQLQuery(sql)
.addScalar("s1")
.addScalar("s2")
.setResultTransformer(Transformers.aliasToBean(PlainOldObject.class ) )
.setCachMode(CacheMode.GET)
.list();

return list;

}

This avoids your needing to cycle over multiple objects to pull in the information you need. It also alleviates the need to cycle over Object[] s to sort through your results.

A couple notes:

1. Use the set scalar method to convert the variables in your sql to the fields in your pojo.
2. Use CacheMode.GET to keep these ojects out of the hibernate session cache.




Tapping into the GlassFishESB Worklist Manager

Posted in Wayne Adams on March 24th, 2009 by admin
I recently investigated the Worklist Manager in GlassFish ESB and want to share some of the details here.  GlassFish is based on the Java Business Integration (JBI) specification and includes service engines for Java EE, BPEL and so on.  The Worklist Manager is one of these service engines.  It is not based on BPEL4People as far as I know but basically meets the same need -- providing a way to integrate human/workflow tasks into a business-process environment.

Note that there is a Wiki for this service engine at http://wiki.open-esb.java.net/Wiki.jsp?page=WLMSE.  My goal when investigating the WLMSE was to demonstrate accessing it from a web service client external to the GlassFish environment.  The documentation in this area is rather spotty, and hence this post.  I started at the above Wiki and took things from there.

An important consideration here is that there are a number of versions of GlassFishESB, OpenESB, NetBeans, and so on, and the combination makes a difference.  If you peruse enough online tutorials, you'll finally begin wondering what version, exactly, you need to download to see the same functionality as you are seeing in the tutorial.  For example, the latest release, recommended on the  WorkList Manager Service Engine (WLMSE) Wiki, is GlassFish ESB V2.1 Milestone 1.  The download for this release includes NetBeans 6.5.  It does not include the WLMSE, however, which the Wiki recommends obtaining as a separate download.  The only problem with the provided download is that it is only compatible with the latest patch of NetBeans 6.1, and lower.  So you will need an earlier version of NetBeans in order to install the WLMSE!

For reference, I used GlassFish V2 UR2 and NetBeans 6.1 Patch 4.  It does not appear feasible at this time to use V2.1M1 with the WLMSE based on the above issue, so I recommend trying something a little older.  My pre-requisites below send you to the older version that I used to develop this post.

Pre-requisites:
  1. Get NetBeans 6.1 at http://www.netbeans.org/downloads/6.1/index.html, selecting the "All" column, which includes SOA support.
  2. Java SE 6 installed: http://java.sun.com/javase/downloads/index.jsp. Be sure to get the JDK, not the JRE, as there are utilities you will need from the JDK.
  3. Maven 2 installed: http://maven.apache.org/download.html
  4. The following environment variables:
    • JAVA_HOME: top-level Java SE 6 directory
    • M2_HOME: top-level Maven 2 directory
    • M2: $M2_HOME/bin or %M2_HOME%\bin
    • MAVEN_OPTS: -Xms256m -Xms512m (optional)
    • PATH: $JAVA_HOME/bin:$M2:$PATH or %JAVA_HOME%\bin;%M2%;%PATH%
The Java SE JDK, Maven 2 and the environment-variable settings are for the Java-based web-service client we'll be building after we deploy an instance of the Worklist Manager.

Create a Worklist Application

Start NetBeans.  Once the IDE is up, select the Services tab, expand "Servers", then right-click on "GlassFish V2" and select "Start".  Once the GlassFish server has started, select the Projects tab.

From the "File" menu, select "New Project...", then select category "SOA", then select "Worklist Module".  Enter "TutorialWorklistApp" for the project name and click "Finish".

Our worklist application will start with a single operation.  Just as an example, assume this is an ETL system and we want to create a trouble ticket on failure of a file to load.  The creation of the application will be a lot smoother if we first create the XML Schema for the request and response messages, then create the WSDL definition to define the operation, then create the worklist Task itself.

The XML Schema

Right-click on the "WorklistFiles" directory under "TutorialWorklistApp", select "New" -> "XML Schema...".  If "XML Schema..." is not listed, select "Other...", then "XML", then "XML Schema", then "Next".  Name the schema tutorial_worklist (NetBeans will supply an .xsd extension) and click "Finish".  The schema will open in a graphical schema editor.  Provide elements for the request and response messages and base them on complexTypes containing information that might be needed for this application.  An example schema is below:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://xml.netbeans.org/schema/tutorial_worklist"
            xmlns:tw="http://xml.netbeans.org/schema/tutorial_worklist"
            elementFormDefault="qualified">
  <xsd:element name="loadFailureActionRequest" type="tw:LoadFailureActionRequestType"/>
  <xsd:element name="loadFailureActionResponse" type="tw:LoadFailureActionResponseType"/>
  <xsd:complexType name="LoadFailureActionRequestType">
    <xsd:sequence>
      <xsd:element name="feedName" type="xsd:string"/>
      <xsd:element name="fileName" type="xsd:string"/>
      <xsd:element name="timestamp" type="xsd:date"/>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:complexType name="LoadFailureActionResponseType">
    <xsd:sequence>
      <xsd:element name="troubleTicketID" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

Save the schema and check it with the "Validate XML" button.

The WSDL definition

Right-click on the "WorklistFiles" directory under "TutorialWorklistApp", select "New" -> "WSDL Document...".  If "WSDL Document..." is not listed, select "Other...", then "XML", then "WSDL Document", then "Next".  Name the WSDL document "tutorial_worklist"  (NetBeans will supply a .wsdl extension) and click "Finish".   Select "Concrete WSDL Document", then "SOAP" Binding and "Document Literal" for the Type.  Click "Next".

In the "Abstract Configuration" panel, clean up some of the names a little.  Change the port type name to worklistPortType, the operation name to processLoadFailure, then click the ellipses ("...") for the Input and Output messages to select the input and output messages we defined in the XML Schema above (namely, loadFailureActionRequest and loadFailureActionResponse; you will need to scroll up in the dialog to find the definition, and expand the "Elements" node).  Leave the "Generate partnerlinktype automatically" box checked.  Click "Next".

On the "Concrete Configuration" panel, clean up the names a little, using worklistBinding, worklistService, and worklistPort for Binding Name, Service Name, and Port Name, respectively.  Click "Finish".

The Task definition

Right-click on the "WorklistFiles" directory under "TutorialWorklistApp", select "New" -> "Worklist Task Definition...".  If "Worklist Task Definition..." is not listed, select "Other...", then "SOA", then "Worklist Task Definition", then "Next".  Name the file processLoadFailure (no need for an extension), click the ellipsis by the empty Operation name, expand the WSDL definition down to the processLoadFailure operation, and click "OK".  Click "Finish".  The Task definition will now open in a graphical editor.

Build

Right click on the name of the Worklist Application ("TutorialWorklistApp") and select "Build".  You should get a successful build.  This application is now a JBI module which can be deployed to a composite application, which is our next step.


Create a Composite Application

From the "File" menu, select "New Project...", then project category "SOA", then "Composite Application".  Click "Next".  Name the project TutorialCompositeApp.  Click Finish.  The Service Assembly file TutorialCompositeApp.casa will open in a graphical editor containing three sections:
  1. WSDL Ports
  2. JBI Modules
  3. External Modules
Drag the Worklist Application (TutorialWorklistApp) over to the "JBI Modules" section of the service assembly and drop it.  At this point, your service assembly will look as follows:



Right-click on the project name and select "Build". You will see the service-assembly view reload, with the following results:



Note that the processLoadFailure operation has a configured SOAP/HTTP binding, as we expected (we just configured it in some detail), but notice that we also have a TaskCommonPort, with no binding.  This is the Worklist Manager.  We will add a SOAP/HTTP binding for this port so that we will be able to access the items in the Worklist from a simple demonstration Java client.

Create the Worklist Manager binding

From the "WSDL Bindings" section of the Palette, drag and drop a "soap" binding on the "WSDL Ports" section of the service assembly.  You will see an additional binding similar to the one already configured for the Worklist application.  Select the purple (right-pointing) arrow in the binding and drag over to and connect to the TaskCommonPort port.  Now, right-click on this binding and select "Properties".  Change casaPort1 to worklistManagerPort, then click on the ellipsis ("...") by the soap:address Location.  You should see the following:

http://localhost:${HttpDefaultPort}/casaService1/worklistManagerPort

Simplify this a little by changing it to

http://localhost:${HttpDefaultPort}/worklistManager

Note that the URL for the Worklist application is similarly wordy.  If you want to shorten it, you can in similar manner, but you'll have to first right-click on the binding and select "Clone WSDL Port to edit...".  Confirm on the dialog which follows, then right-click and select "Properties" to edit, and change the soap:address Location from

http://localhost:${HttpDefaultPort}/tutorial_worklistService/tutorial_worklistPort

to

http://localhost:${HttpDefaultPort}/worklistApp

then click "Close" to save.  Your service assembly should now look as follows:



Deploy the Composite Application

Before we deploy the application, you're probably wondering what ${HttpDefaultPort} means.  You might guess that it is the default port of the GlassFish web services, but actually each of the binding components in GlassFish has their own unique default port.  This can be a problem if you are trying to access a binding component from outside of GlassFish and don't know the port number, but these can be found in the Admin console.  For more information, see "Understanding the ${HttpDefaultPort} Token" at http://wiki.open-esb.java.net/Wiki.jsp?page=ClusteringSupportForHTTPBindingComponent.  But I will walk you through the process here.

To determine what the default port is for a binding component (in this case, the HTTP BC):
  1. Open the Admin console (in Netbeans, open Services tab, expand "Servers", right click on Glassfish, select "View Admin Console".  Unless you changed values, the username/password pair is "admin"/"adminadmin".
  2. Under "Common Tasks", expand "JBI", "Components", "sun-http-binding".
  3. Select the "Configuration" tab.
  4. Second entry is "Default HTTP Port Number".  If you did not change this on installation, it will probably be 9080.
If you choose to, you can always select an unused port number and hard-code it into the bindings before you deploy.  If you're like me, all you care about is being able to find out where the service is deployed!

Now, right-click on the composite application name in the "Projects" tab, select "Build", then again right-click on the application name and select "Deploy".  The project should deploy successfully.  

To verify that the two services are correctly deployed, and assuming you used the soap:address Locations I used above, navigate to the following:

http://localhost:9080/worklistManager?wsdl
http://localhost:9080/worklistApp?wsdl

where I have substituted the HTTP default port for my deployment.  Note you may have to view the page source to see the WSDL definition, but you should see both.  Note the worklistApp has a single operation available (processLoadFailure), while the worklistManager has a number of operations related to the processing of tasks, as we might expect.  For example, GetTaskList, RevokeTask, CompleteTask, and so on. We will be calling these operations from the simple Java web-service client which we will create next.

Create a simple Java client

All we'll be doing here is generating the minimal Java client necessary to exercise some operations on the Worklist Manager.  The steps involved are almost identical to those under the heading "Create a client for the web service" at my earlier post Java-SE-Based Web Services .  The only difference will be the URL of the web service, of course.  Because the WSDL definition of the Worklist Manager contains a URL to the TaskCommon.wsdl file (the latter is the abstract WSDL, and the former imports it and contains the necessary information to make the WSDL definition concrete), we will copy both files to a wsdl directory in our client build.

Expand the NetBeans project directory for the composite application and retrieve the following files:
     src/JbiServiceUnits/TutorialCompositeApp.wsdl
     src/JbiServiceUnits/TutorialWorklistApp/TaskCommon.wsdl

Copy these files into the wsdl directory (under your Maven project src directory).  Open the TutorialCompositeApp.wsdl file and change the import path for TaskCommon.wsdl to reflect the fact that it is now in the same directory as TutorialCompositeApp.wsdl:

<import namespace="http://jbi.com.sun/wfse/wsdl/TaskCommon" location="TaskCommon.wsdl">

Also, edit the soap:address, replacing ${HttpDefaultPort} with the actual port number (defaults to 9080, or use whatever value you hard-coded, if any).

Then, instead of configuring a WSDL URL in your pom.xml file, configure a WSDL file as follows:

<configuration>
<wsdlFiles>
<wsdlFile>TutorialCompositeApp.wsdl</wsdlFile>
</wsdlFiles>
<packageName>com.example.webservice.service</packageName>
</configuration>

The client of course instantiates a different service and invokes different operations than in my previous post.  Here is an example Java client that exercises a couple of operations on the Worklist Manager:

package com.example.webservice.client;

import com.example.webservice.service.QueryType;
import com.example.webservice.service.CasaService1;
import com.example.webservice.service.TaskCommonPortType;
import com.example.webservice.service.TaskFaultMsg;
import com.example.webservice.service.TaskListType;
import com.example.webservice.service.TaskType;

public class WLMClient
{
public static void main(String[] args) throws TaskFaultMsg
{
CasaService1 service = new CasaService1();
TaskCommonPortType port = service.getWorklistManagerPort();
System.out.println("Getting Task List:");
QueryType qt = new QueryType();
QueryType.Users users = new QueryType.Users();
users.getUser().add("john");
qt.setUsers(users);
QueryType.Groups groups = new QueryType.Groups();
groups.getGroup().add("CustomerServiceRep");
qt.setGroups(groups);
TaskListType tasks = port.getTaskList(qt, "john", 0, 100);
System.out.println(" Total record count: " + tasks.getTotalRecords());
System.out.println(" Returned record count: " + tasks.getReturnedRecords());
for (TaskType nextTask: tasks.getTask())
{
System.out.println("Task ID: " + nextTask.getTaskId() + "; title: " + nextTask.getTitle() + "; " +
"Claimed by: " + nextTask.getClaimedBy() + "; Assigned to: " + nextTask.getAssignedTo());
}
}
}
Build and run this application and you should see output like the following:

C:\Users\wayne.adams\Blogger\GlassfishWLMJavaClient>java -cp target\glassfishWLMJavaClient.jar com.example.webservice.client.WLMClient
Getting Task List:
Total record count: 0
Returned record count: 0

In this case, there are no tasks, but we can create some by exercising the other service, the worklistApp service. More on that in a subsequent post!

Java-SE-based Web Services

Posted in Wayne Adams on March 24th, 2009 by admin
This isn't exactly late-breaking news, as Java SE6 has been out for a while, but the Standard Edition now includes support for non-trivial web-service development and deployment, no Java-EE application server necessary. The purpose of this very quick introduction is to produce a working web service and a web service client, in as few lines of Java as possible, without relying on heavy infrastructure (namely, an IDE and/or an application server). The output of this post will re-appear in subsequent posts, for example when I need a quick client to kick off a BPEL (Business Process Execution Language) process, or simply to exercise a web service to verify deployment.

Pre-requisites:
  1. Java SE 6 installed: http://java.sun.com/javase/downloads/index.jsp. Be sure to get the JDK, not the JRE, as there are utilities you will need from the JDK.
  2. Maven 2 installed: http://maven.apache.org/download.html
  3. The following environment variables:
    • JAVA_HOME: top-level Java SE 6 directory
    • M2_HOME: top-level Maven 2 directory
    • M2: $M2_HOME/bin or %M2_HOME%\bin
    • MAVEN_OPTS: -Xms256m -Xms512m (optional)
    • PATH: $JAVA_HOME/bin:$M2:$PATH or %JAVA_HOME%\bin;%M2%;%PATH%
Create a Web Service project and launch the service

As you've guessed, I'm using Maven to build this service. Maven will generate the project directory for you, so there's no need to create it first. Just open a command prompt or shell in a development directory and enter the following:

mvn archetype:generate -DgroupId=com.example.webservice -DartifactId=JavaSEWebService

substituting your desired package name for groupId. The artifactId will be the name of the project directory Maven will create in your current working directory. You will be asked for an archetype, where the default is 15, or maven-archetype-quickstart. Select defaults by hitting "Enter" until Maven generates the project.

Next, create a simple web service. Note: I prefer to start with a WSDL definition first, then generate the server and client-side artifacts from it, but for this quick example we'll go in the opposite direction, taking a small piece of business logic and exposing it as a service.

cd to the the groupId-defined package under the source branch (./{artifactId}/src/main/java/...) of the newly-created project. There will be a class called App.java. We will ignore this class and create our own.
  1. Create a directory called service and cd into it.
  2. Create a Java class called Tutorial.java.
  3. Add a couple of methods; one called getHelloWorld that takes no arguments and returns the String "Hello, World!" and a second one called getPersonalizedHelloWorld that takes a String and returns a personalized greeting.
  4. Add a main method, and in it, instantiate a Tutorial and publish it, using the javax.xml.ws.Endpoint class, on your machine. Annotate the class as a WebService and the methods as WebMethods.
An example class is shown here:

package com.example.webservice.service;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;

@WebService
public class Tutorial
{
public static void main( String[] args )
{
Tutorial wsInstance = new Tutorial();
Endpoint.publish("http://localhost:8282/tutorial", wsInstance);
}
@WebMethod
public String getHelloWorld()
{
return "Hello, World!";
}
@WebMethod
public String getPersonalizedHelloWorld(String yourName)
{
return "Hello, " + yourName + "!";
}
}
Next we'll modify the Maven "pom" (Project Object Model) file, first to use Java SE 6 (Maven defaults to 1.3) and secondly to specify the wsgen Maven plugin. wsgen creates all the artifacts necessary to build and deploy the web service. cd into the project directory and open the pom.xml file. Add the following to your pom:

<build>
<finalName>tutorialWebService</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>wsgen</goal>
</goals>
<configuration>
<sei>com.example.webservice.service.Tutorial
</sei>
<genWsdl>true</genWsdl>
<keep>true</keep>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Save and close the file. From the project directory, enter mvn install. You should get a clean build. Note that the name of the produced .jar file is obtained from the finalName element in the pom.xml file. Start the web service from the project-level directory with:

java -cp target/tutorialWebService.jar com.example.webservice.service.Tutorial

and verify that the service is available by retrieving the WSDL description in a browser. Append ?wsdl to the endpoint URL you defined in your Java class, in this case

http://localhost:8282/tutorial?wsdl

Note that depending on the browser you are using, you may need to view the page source to see the WSDL description.

Create a client for the web service

We'll create a new Maven project for the client. Open another command prompt or shell in your development directory (again, no need to create the project directory, as Maven will do this for you), and enter the following:

mvn archetype:generate -DgroupId=com.example.webservice -DartifactId=JavaSEWebServiceClient

substituting your desired package name for groupId. The artifactId will be the name of the project directory Maven will create in your current working directory. As for the web service example, you will be asked for an archetype, where the default is 15, or maven-archetype-quickstart. Select defaults by hitting "Enter" until Maven generates the project.

cd into the project directory, given by the value you supplied for artifactId (for this example, JavaSEWebServiceClient). Open the pom.xml (Maven Project Object Model) file. Add the following to the POM; wsimport is used to generate client stubs for your web service:

  <build>
<finalName>tutorialWebServiceClient</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<wsdlUrls>
<wsdlUrl>http://localhost:8282/tutorial?wsdl</wsdlUrl>
</wsdlUrls>
<packageName>com.example.webservice.service
</packageName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

Save and close the file. Note that you are directing Maven to obtain the WSDL description via the URL we used earlier to verify that the web service was correctly deployed.

Create a simple web service client:
  1. cd to the groupId-defined package under the source branch (./{artifactId}/src/main/java/...) and create a client directory; cd into this directory.
  2. Create a Java class called TutorialWebServiceClient.java.
  3. Create a main method which gets a reference to the tutorial web service and exercises its two operations. For example:

package com.example.webservice.client;

import com.example.webservice.service.Tutorial;
import com.example.webservice.service.TutorialService;

public class TutorialWebServiceClient
{
public static void main(String[] args)
{
TutorialService service = new TutorialService();
Tutorial port = service.getTutorialPort();
System.out.println("Calling getHelloWorld(); returns '" + port.getHelloWorld() + "'");
System.out.println("Calling getPersonalizedHelloWorld(\"Bob\"); returns '" +
port.getPersonalizedHelloWorld("Bob") + "'");
}
}

Note that the wsimport utility will create an interface named TutorialService.java and a class named Tutorial.java. It will do this before the client is compiled, but if you want to see the stub classes before you build the client, just execute mvn install before creating the client.

The web service interface name is obtained by prepending the package name from the POM to the name of the web service portType from the WSDL description, and the name of the service itself is the serviceName from the WSDL description, if you want to reference the classes before they are generated by wsimport.

Also note that the endpoint URL of the web service was embedded into the generated client-side classes by the setup in the Maven POM file, as I mention above.

From the project directory, enter

mvn install

This will generate the client-side stubs you need in your client, followed by the client itself. You can safely ignore the "[INFO] Nothing to do, no WSDL found!" log message; it is misleading and if you get a "BUILD SUCCESSFUL" message, then all is well.

Test the client and the web service with:

java -cp target/tutorialWebServiceClient.jar com.example.webservice.client.TutorialWebServiceClient

You should see output like the following:

Calling getHelloWorld(); returns 'Hello, World!'
Calling getPersonalizedHelloWorld("Bob"); returns 'Hello, Bob!'

You now have a working web-service/client pair, which will come in handy in future entries as we explore Flex web-service clients, BPEL and JBI.

Introductions

Posted in Wayne Adams on March 24th, 2009 by admin
Hello, everyone!

Before I start posting, I should tell you a little about where I'm going.

My main software interest is enterprise Java, and more specifically business process modeling, either on top of Java or a slightly higher level of abstraction.  So I'm really interested in Web Services, Business Process Execution Language (BPEL), Java Business Integration (JBI), and (at this time, to a lesser extent) the Service Component Architecture (SCA).

I'm much more practical than theoretical.  I like to get things working first and ruminate later.  I like tutorials!  I like finding good ones, and I like creating them, especially when it seems there's a hole in the tutorial offerings.  Most of what you see posted here will be in the form of tutorials.  Some of them will be really simple, as they will serve as building blocks for subsequent posts that you'll hopefully find more interesting.  For example, sometimes it's handy to have a 25-line Java-SE-based web service, or an even briefer web service client, to test an application in development (in fact, this will be the topic of my next post).

With that, I hope you enjoy what's forthcoming and that you also find it useful!  Ciao!

Wayne

Testing async services with Fluint

Posted in FlexMonkey, Justin Shacklette on March 22nd, 2009 by admin

We’re pretty big on testing at Gorilla Logic, and in the world of Flex that usually means using FlexMonkey to test the UI and using FlexUnit to test the code. Alas, it is a huge pain in the ass to correctly test the many async objects and services inherent in any Flex app with FlexUnit. Enter Fluint, an superior Flex unit tesing framework by the cool guys at digital primates (no relation). Fluint is the heir apparent to take over the unit testing crown from the venerable FlexUnit. So let’s take Fluint and its enhanced async testing support for a spin.

Service Layer

First, assume we have a nice service layer in Flex that talks asynchronously to our backend. Just something simple to start:

public class MyService {
    public function getSomething(result:Function, fault:Function):AsyncToken {
        //call the backend
        var token:AsyncToken = backend.getSomething();
 
        //wire the callbacks to the result
        token.addResponder(new AsyncResponder(result, fault, token));
 
        return token;
    }
}

In this example, our service only has one method, getSomething() that takes two callback functions. It simply calls the backend method, wires up the callbacks (which get called when the backend method returns a result), and returns the token. It is absolutely critical that our callback-powered service method return the AsyncToken. The reason for this will become apparent.

We might use our service like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
        xmlns:mx="http://www.adobe.com/2006/mxml"
        creationComplete="complete()">
 
    <mx:Script>
    <![CDATA[
        import com.saturnboy.services.MyService;
        private var service:MyService;
 
        private function complete():void {
            service = new MyService();
            service.getSomething(resultHandler, faultHandler);
        }
 
        private function resultHandler(result:Object, token:Object=null):void {
            lbl.text = result.result.name;
        }
 
        public function faultHandler(error:Object, token:Object=null):void {
            lbl.text = 'fault';
        }
    ]]>
    </mx:Script>
 
    <mx:Label id="lbl" text="initial" />
</mx:Application>

We make a call our service, and then use the callbacks to alter the UI however we want depending on the result. In common usage, the fact that our service returns an AsyncToken is worthless, it might as well return void. So, why did I say this is critical? Throw Fluint testing into the mix and it’s “Show em what’s behind door number 2, Johnny!”

Fluint Testing

Fluint provides two different async wrapper methods: asyncHandler and asyncResponder. The first allows a test to be wired to an async method by events, the second allows a test to be wired to an async method by a responder. Since the service method we’re trying to test doesn’t throw any events, we’ll need to use the latter. So inside a Fluint test case, we have our test method:

public function testGetSomething():void {
    //call service with dummy callback
    var token:AsyncToken = service.getSomething(dummyResult, dummyFault);
 
    //create async test responder
    var responder:IResponder = asyncResponder(
            new TestResponder(testHandler, faultHandler), 1000, token);
 
    //wire test responder as 2nd callback
    token.addResponder(responder);
}
private function testHandler(result:Object, passThroughData:Object):void {
    assertEquals('something', result.result.name);
}

The trick is to wire a second callback via Fluint’s asyncResponder helper that actually does the testing, and just give the original service call some dummy callbacks. Note that if the service method didn’t return its AsyncToken there would be no way to wire a second callback. The Fluint async helper do two import operations: they handle the event or call the callback AND they mark the test method as an async method so the result is correctly reported by the test harness. You can read more about Async Testing in Fluint’s wiki. The rest of Fluint is your standard chain of crap borrowed from JUnit: test runner, test suites, and test cases.

Digging Deeper: It is equally critical to use dummy callbacks in the original service method call because in a failure situation they will cause Flash Player to error out instead of being caught by Fluint and reported as a test failure.

Files

The complete code is up on GitHub here: test_fluint_async. The code is MIT licensed and includes a working fluint.swc (see below) plus a mock async backend (so timeouts and faults are easily testable).

Alas, Fluint v1.1.0 was built incorrectly and is missing the TestResponder class (see issue 35). So if you want to try out Fluint in your project, I recommend you grab it from svn and build the swc yourself. Hopefully, this will all be fixed in the next release.

UPDATE: Fluint v1.1.1 was release on May 1, 2009 and fixes this issues and a few others. Download it here.