Using an Embedded WSDL with Flex’s WebService API

Recently I was helping a customer figure out how to use an embedded WSDL with Flex’s WebService API. One scenario in which this is needed is when the actual WSDL is not available at runtime. In this case the application must contain the WSDL instead of request it at runtime. The Flex WebService API today only supports loading the WSDL over the network at runtime. Beginning in Flash Builder 4 the Service wizard generate code that internally use the WebService API. So no matter how you integrate with a SOAP Web Service in Flex, you need the WSDL accessible via a URL at runtime. This wasn’t possible for the customer I was working with so we figured out a way to actually embed the WSDL into the application. Here is what we did…

I used my Census SOAP Service as a simple service to test this with. In this case, my WSDL is publicly available at: http://www.jamesward.com/census2-tests/services/CensusSOAPService?wsdl

First, I created a new Flex project and saved the WSDL into the src dir of the project. I built a simple test program using the WebService API directly:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark">
 
	<fx:Declarations>
		<s:WebService id="ws" wsdl="http://www.jamesward.com/census2-tests/services/CensusSOAPService?wsdl"/>
	</fx:Declarations>
 
	<s:applicationComplete>
		ws.getElements(0, 50);
	</s:applicationComplete>
 
	<s:DataGrid dataProvider="{ws.getElements.lastResult}" width="100%" height="100%"/>
 
</s:Application>

Then I ran the application in Chrome with the Network view open in the Chrome Developer Tools panel. This indicated that, just as expected, the WSDL is used at runtime:

Next I had a look around the WebService source code (available in <FLEX_SDK>/frameworks/projects/rpc/src/mx/rpc/soap) and discovered there is a loadWSDL method that can be overwritten to handle the embedded loading of the WSDL instead of the default network loading of the WSDL. So I created a new class that extends the base WebService class, embeds the WSDL file, and overrides the loadWSDL method:

package
{
	import mx.core.ByteArrayAsset;
	import mx.core.mx_internal;
	import mx.rpc.events.WSDLLoadEvent;
	import mx.rpc.soap.mxml.WebService;
	import mx.rpc.wsdl.WSDL;
 
	use namespace mx_internal;
 
	public dynamic class MyWebService extends WebService
	{
		[Embed(source="CensusSOAPService.xml", mimeType="application/octet-stream")]
		private static const WSDL_CLASS:Class;
 
		public function MyWebService(destination:String=null)
		{
			super(destination);
			loadWSDL();
		}
 
		override public function loadWSDL(uri:String=null):void
		{
			var thing:Object = new WSDL_CLASS();
			var baa:ByteArrayAsset = (thing as ByteArrayAsset);
			var xml:String = baa.readUTFBytes(baa.length);
 
			deriveHTTPService();
 
			var wsdlLoadEvent:WSDLLoadEvent = WSDLLoadEvent.createEvent(new WSDL(new XML(xml)));
			wsdlHandler(wsdlLoadEvent);
		}
	}
}

In the regular WebService class, setting the wsdl property will trigger the loadWSDL method, but since we are embedding the WSDL, we must manually call the loadWSDL method. I do that in the constructor.

Embedded assets become a class, so first an instance of that class must be instantiated as a ByteArrayAsset (the default type for files embedded with the application/octet-stream mimeType). Then the instance is read into a string. Then the deriveHTTPService method is called to set up the underlying HTTPService‘s channel information. Finally, we create a WSDL object from the XML that was read from the ByteArrayAsset, create a new WSDLLoadEvent with the WSDL, and call the wsdlHandler method, passing it the wsdlLoadEvent. This essentially is doing the same thing as the original WebService class, but now doing it without the network request.

I can now switch my test application to use my extension to WebService instead of the original one:

	<fx:Declarations>
		<local:MyWebService xmlns:local="*" id="ws"/>
	</fx:Declarations>

Now when I run the application and monitor the network activity I no longer see the WSDL being requested at runtime! So everything works when using the WebService API directly. However, the customer I was working with was using the Service wizard in Flash Builder. So we needed to figure out how to get the generated code to use the new WebService extension instead of the original WebService class. I went through the Data Wizards and had it generate the client-side stubs for my Census SOAP Service. This created a CensusSOAPService class that extends the generated _Super_CensusSOAPService class. The CensusSOAPService is intended to give us a place to make modifications to the generated stuff, while the _Super_CensusSOAPService class is not supposed to be modified because it will be overwritten if we refresh the service. Looking in the _Super_CensusSOAPService class I discovered that the WebService instance is being created directly in the constructor:

    public function _Super_CensusSOAPService()
    {
        // initialize service control
        _serviceControl = new mx.rpc.soap.mxml.WebService();
 
        // rest of method omitted
    }

These are the kinds of things that really make you wish the Flex framework used dependency injection because we need to set _serviceControl from the CensusSOAPService class. So we thought… Alright, this is not ideal but we can just copy the contents of the _Super_CensusSOAPService‘s constructor into CensusSOAPService‘s constructor, replace the line that instantiates the WebService, have it instantiate MyWebService instead, and then just not call super(). We gave it a try and for some reason kept getting _serviceControl set as a WebService not MyWebService. WTF? It made no sense until we found this little gem in the Flex docs:
“If you define the constructor, but omit the call to super(), Flex automatically calls super() at the beginning of your constructor.”
Now it all made sense! Since we didn’t call super(), Flex conveniently inserted a super() call for us! Fun. So we had to figure out a way to convince the Flex compiler that we were going to call super(), but then not call it.

if (0)
{
    super();
}

Voila! Now the CensusSOAPService‘s constructor sets _serviceControl to a new instance of MyWebService and _Super_CensusSOAPService doesn’t get the chance to mess that up.

We tested the new CensusSOAPService and everything worked perfectly!

I hope that helps some of you who are using the Flex WebService API. Let me know if you have any questions.

Integrating Flex and Java EE with JBoss

Flex and Java have always fit together very nicely. Connecting from Flex to a Java back-end is pretty straightforward whether you are using plain old Java beans, Spring beans, or EJB session beans. I’ve created a video and some sample code that shows you how to connect Flex to a Java EE system using BlazeDS. This video walks though a real-time collaborative Whiteboard application that runs in the browser, on the desktop, and on mobile devices. Check out the video and let me know what you think.

Testing Flex Apps with FlexMonkey Reloaded

Whether or not you use a tool to test your Flex apps, you are repeatedly testing your application. Doing this by hand is a pain: start the app, click through some stuff, verify the result is what you expected, makes some changes to your code and then do it all again. The open source FlexMonkey tool automates that process so you don’t have to keep doing those steps manually. FlexMonkey works with Flex applications that run in the browser (Flash Player) as well as on the desktop (Adobe AIR). Jon Rose has just finished a complete overhaul of FlexMonkey that makes automating your Flex testing process uber-simple and much more robust than the previous version.

Jon and I have created some resources to help get you started using FlexMonkey. Start by reading the Introduction to Flex and AIR Testing with FlexMonkey. Then check out a short screencast I did that walks through the FlexMonkey basics:



To continue learning check out a series of videos from Jon that will give you a more in-depth look at each piece of FlexMonkey:

Now enjoy being more productive as you automate the testing process you do hundreds of times a day, leaving more time for Angry Birds! Let me know what you think.

Integrating Flex/Flash with HTML5 APIs

Beyond the media hype about Flash versus HTML5 exists the reality of coexistence and cooperation. This coexistence and cooperation makes the web a better place. When developers combine the strengths of Flash with the strengths of HTML, users get the best possible experiences on the web.

Both HTML and Flash are important foundations that Adobe builds its products on. Here’s a little secret about Adobe’s business model… When new versions of those platforms come out, so do new versions of the tools for building on them. And guess what Adobe makes money on… Tools. So it is true that Adobe loves Flash AND HTML5. :)

In the world of coexistence and cooperation (that is the technical reality) we find some really exciting things. One such thing is Jangaroo an open source project that cross-compiles ActionScript to JavaScript. This means that you can build applications in ActionScript (and eventually MXML) and cross-compile those applications to run in places where Flash doesn’t exist. And you can even use Adobe tools to help you write that ActionScript. :)

Another quick example I whipped up is a proof-of-concept of how you can integrate Flex applications with the new HTML5 session history and navigation APIs (pushState, replaceState, and so on). In a sufficiently modern browser (such as Chrome, Firefox 4, or Safari) open the following demo in a new tab / window:
http://www.jamesward.com/demos/FlexReplaceState/app

As you click on tabs notice that the URL changes without page refresh and without resorting to the use of named anchors / hashes. Also notice that page refresh, back, and forward all work. Check out the source for the demo on github. That is the kind of cooperation and integration we will continue to see more of as HTML5 matures. I’m excited to see the web become a better place as HTML and Flash both mature!

P2P in Desktop, Mobile, and Tablet Flex Apps

Using the open source Flex SDK, developers can easily build desktop, mobile, and tablet applications that use Peer to Peer (P2P) communication. I’ve created a video that walks through demos and code illustrating how to use the P2P APIs in Adobe AIR applications. Check it out:

Grab the code for the demos in the video from github:

Just as the video shows, it’s incredibly easy to use the P2P APIs. Here is a quick walk through. First create a new NetConnection that is connected to “rtmfp:” like so:

localNc = new NetConnection();
localNc.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
localNc.connect("rtmfp:");

In the netStatus event listener wait for the “NetConnection.Connect.Success” event and then set up the NetGroup:

private function netStatus(event:NetStatusEvent):void
{                        
    switch(event.info.code)
    {
        case "NetConnection.Connect.Success":
            setupGroup();
            break;
    }
}
 
private function setupGroup():void
{
    var groupspec:GroupSpecifier = new GroupSpecifier(GROUP_ID);
    groupspec.ipMulticastMemberUpdatesEnabled = true;
    groupspec.multicastEnabled = true;
    groupspec.routingEnabled = true;
    groupspec.postingEnabled = true;
 
    // This is a multicast IP address. More info: http://en.wikipedia.org/wiki/Multicast_address
    groupspec.addIPMulticastAddress("239.254.254.2:30304");
 
    netGroup = new NetGroup(localNc, groupspec.groupspecWithAuthorizations());
    netGroup.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
}

Now handle a “NetGroup.SendTo.Notify” event when a message is received over the P2P connection:

// in the netStatus switch block
case "NetGroup.SendTo.Notify":
    var data:Object = event.info.message;
    break;

And finally to send a P2P message to everyone who is listening simply do:

netGroup.sendToAllNeighbors(objectToSend);

That’s it! Super simple and super fun! :)

Thanks to Tom Krcha for all of his great blogs on how to do this. Also thanks to Mark Dong and James Li (Flash Platform Evangelists in China) for helping me build P2Pong.

Data Paging in Flex 4

I know — you’ve heard it from me before — AMF rocks! With AMF you can load massive amounts of data into your Flex (or JavaScript) apps very quickly. This can often obviate the need for paging data. But what if you have lots, and lots, and lots of data? Well then you should use data paging. And here is how…

There is a new collection wrapper class in Flex 4 called “AsyncListView“. The UI data controls in Flex 4 know how to handle an AsyncListView as a dataProvider. The purpose of the AsyncListView is to give you a callback when the underlying list throws an ItemPendingError. The ItemPendingError indicates that an item that the list thinks it has isn’t really there yet. This allows you to then load the data and update the list. In order to throw an ItemPendingError you need to keep track of which items haven’t been loaded and then, when an item is requested that isn’t really there, throw the ItemPendingError. Here is some code from my PagedList implementation:

public function getItemAt(index:int, prefetch:int = 0):Object
{
    if (fetchedItems[index] == undefined)
    {
      throw new ItemPendingError("itemPending");
    }
 
    return _list.getItemAt(index, prefetch);
}

In my main application I just create a PagedList, set its length (which should really be done by a remote call instead of manually), and then assign the instance of PagedList to the list property on my instance of AsyncListView. With MXML this looks like:

<local:PagedList id="items" length="100000"/>
<s:AsyncListView id="asyncListView" list="{items}"
    createPendingItemFunction="handleCreatePendingItemFunction"/>

When the ItemPendingError is thrown, the handleCreatePendingItemFunction is called. Now I just figure out what page of data is needed, make sure that there isn’t already a pending request for that page, and then make the request. When the response comes back I simply update the underlying collection. Here is the code that does that:

private function handleCreatePendingItemFunction(index:int, ipe:ItemPendingError):Object
{
  var page:uint = Math.floor(index / pageSize);
  if (fetchedPages[page] == undefined)
  {
    var numItemsToFetch:uint = pageSize;
    var startIndex:uint = pageSize * page;
    var endIndex:uint = startIndex + pageSize - 1;
    if (endIndex > items.length)
    {
      numItemsToFetch = items.length - startIndex;
    }
    var asyncToken:AsyncToken = ro.getElements(startIndex, numItemsToFetch);
    asyncToken.addResponder(new AsyncResponder(function result(event:ResultEvent, token:Object = null):void {
      for (var i:uint = 0; i < event.result.length; i++)
      {
        items.setItemAt(event.result[i], token + i);
      }
    }, function fault(event:FaultEvent, token:Object = null):void {
    }, startIndex));
    fetchedPages[page] = true;
  }
  return null;
}

In this example I’m using RemoteObject (AMF) but this could be anything (HTTPService, WebService, etc.) as long as there is a method on the back end that lets me set the starting location and the page size.

Here is a simple demo of data paging using the new Spark DataGrid in Flex Hero. The page size is 100 and there are 100,000 total items.

Fork or view the code for this example on github.com.

Of course another option for doing data paging more automatically is with LiveCycle Data Services. Check out a great example of Data Paging with LCDS in Tour de Flex to learn more about that.

A big thanks to Mike Labriola for helping me figure this out! Please let me know if you have any questions about this.