Robotlegs with LoaderMax’s XMLLoader

This is a quick modification of hubflanger’s useful Robotlegs AS3.0 Site tutorial. I’m expanding her service class to use a content loading library called LoaderMax.

Since she built hers via an interface, there’s no need to refactor the existing class. Instead use her ISiteDataService interface and create a similar class called LoaderMaxDataService, like so:

package com.hubflanger.robotlegsdemo.service
{
	import com.hubflanger.robotlegsdemo.model.vo.SectionVO;
	import com.hubflanger.robotlegsdemo.model.SiteModel;
	import com.hubflanger.robotlegsdemo.events.SystemEvent;
	
	import com.greensock.events.LoaderEvent;
	import com.greensock.loading.LoaderMax;
	import com.greensock.loading.XMLLoader;
	
	import flash.events.Event;
	import flash.net.*;
	
	import org.robotlegs.mvcs.Actor;
		
	/**
	 * A Service class that handles loading and parsing of the site's xml data.
	 */	
	public class LoaderMaxDataService extends Actor implements ISiteDataService
	{
		/**
		 * Inject the <code>SiteModel</code> Singleton.
		 */		
		[Inject]
		public var model				:SiteModel; 
		
		//private var queue				:LoaderMax; 		

		public function LoaderMaxDataService()
		{ 			
			LoaderMax.activate([XMLLoader]);					
		}
				
		public function loadData():void 
		{			
			var xml:XMLLoader = new XMLLoader("assets/data.xml", 
											  {name:"mainXML", 
											  onComplete:loadCompleteHandler, 
											  estimatedBytes:4000});
			xml.load();						
		}
		
		/**
		 * Handler for the XMLLoader's onComplete.
		 * <p>
		 * Parses the xml data and stores the <code>SectionVO</code> objects in 
		 * the <code>SiteModel</code> Singleton.
		 * <p>
		 * Dispatches a <code>SystemEvent.INIT_VIEW</code> event.
		 * 
		 * @param event
		 */		
		private function loadCompleteHandler(e:LoaderEvent):void 
		{			
			var xml:XMLLoader = e.target as XMLLoader; 
			
			model.header = xml.content.header.text(); 
			var sections:XMLList = xml.content.sections.section; 
			
			for each (var section:XML in sections) 
			{
				var sectionVO:SectionVO = new SectionVO(section.@id,
														section.label.toString(),
														section.content.toString());				
				
				model.sectionsList.push(sectionVO);
				model.sectionsHash[sectionVO.id] = sectionVO;
			}			
			
			model.defaultSection = model.sectionsList[0].id;
			
			dispatch(new SystemEvent(SystemEvent.INIT_VIEW, false));					
		}
	}
}

Update 1 line in the ApplicationContext from this:

 
injector.mapClass(ISiteDataService, SiteDataService);

to this:

 
injector.mapClass(ISiteDataService, LoaderMaxDataService);

There’s no need to update the LoadDataCommand to use LoaderMaxDataService, instead of SiteDataService. hubflanger & Robotlegs’ (ISiteDataService) use of polymorphism allows this to continue working unaltered:

package com.hubflanger.robotlegsdemo.controller
{
	import com.hubflanger.robotlegsdemo.service.ISiteDataService;
	
	import org.robotlegs.mvcs.Command;
	
	/**
	 * Responds to the <code>ContextEvent.STARTUP_COMPLETE</code> framework event.
	 */	
	public class LoadDataCommand extends Command
	{
		/**
		 * Creates an instance of SiteDataService via dependency injection.
		 */		
		[Inject]
		public var siteDataService:ISiteDataService;
		
		/**
		 * Calls the loadData() method of the SiteDataService instance.
		 */		
		override public function execute():void
		{
			siteDataService.loadData();
		}
	}
}

AS3.0 Signals example juxtaposed with native version

AS3.0 Signals is an event handling framework from Robert Penner that’s gaining popularity lately. There’s a good video tutorial by John Lindquist and tutorials here.

Here’s a quick comparison of an old XML processing class written both ways for comparison. For this simple example, Signals was about 10 to 50 milliseconds faster than using regular AS3 events. The results varied a lot each time I compiled.

Using the Signals framework for events:

XML processing class:

package com.timshaya.net
{
	import org.osflash.signals.Signal;
	import org.osflash.signals.natives.NativeSignal;
	
	import flash.events.Event;
	import flash.net.URLLoader;
	import flash.net.URLRequest;	

	public class XmlGrabber 
	{		
		private var loadDone				:NativeSignal;									
		public var dataDone					:Signal;										
		public var cityItems				:Array = [];								

		private var xmlData					:XML;		
		private var loader					:URLLoader;
		private var reqst					:URLRequest;
		private var trgt					:URLLoader;
		
		public function XmlGrabber(pth:String):void 
		{
			loader = new URLLoader(); 
			reqst = new URLRequest(pth);
						
			dataDone = new Signal();	
			loadDone = new NativeSignal(loader, Event.COMPLETE, Event); 
			loadDone.addOnce(loadCompleted);					
			
			loader.load(reqst);	
		}	
		
		public function loadCompleted(e:Event):void 
		{
			var trgt:URLLoader = URLLoader(e.target);
			xmlData = new XML(trgt.data); 
			//trace(xmlData);
			
			if (trgt!=null) 
			{
				for each (var a:XML in xmlData.evnt) 
				{
					cityItems.push(a); 
					//trace("\n cityItems[a]: " + a.@city + "\n"); 
				} 													
			} else trace("error: check your data & datatype");
			
			dataReady();
		}
		
		public function dataReady():void 
		{	
			dataDone.dispatch(); 
		}
	}
}

Test class:

package 
{	
	import org.osflash.signals.Signal;	
	import org.osflash.signals.natives.NativeSignal;
	import com.timshaya.net.XmlGrabber; 	
	
	import flash.display.Sprite;	
	import flash.events.Event;	
	import flash.utils.getTimer;

	[SWF (width="600", height="400", backgroundColor="#FFFFFF", frameRate="30")]	
	public class Test extends Sprite 
	{	
		private var addToStage				:NativeSignal;
		private var xml						:XmlGrabber;		
		private var xmlPth                  :String = "xml/"; 
		private var xmlName  				:String = "events.xml"; 				
		private var timer					:Number;
		
		public function Test():void 		
		{										
			addToStage = new NativeSignal(this, Event.ADDED_TO_STAGE, Event); 
			addToStage.addOnce(initApp);			
		}

		public function initApp(e:Event):void 
		{
			timer = getTimer();
			
			xml = new XmlGrabber(xmlPth + xmlName);
			xml.dataDone.add(createPage); 									
		}

		public function createPage():void 
		{							
			trace("Test::createPage()");		
			trace("\t time elapsed: " + (getTimer() - timer));			
						
			trace("\t xml.cityItems[0].@city = " + xml.cityItems[0].@city); 
			trace("\t xml.cityItems[0].@state = " + xml.cityItems[0].@state);			
		} 				
	}
}

Same code using native AS3 events:

XML processing class:

package com.timshaya.net
{
	import flash.events.Event;
	import flash.net.URLLoader;
	import flash.net.URLRequest;	
	import flash.events.EventDispatcher;

	public class XmlGrabberOld extends EventDispatcher 
	{		
		public var cityItems				:Array = [];		

		private var xmlData					:XML;		
		private var loader					:URLLoader;
		private var reqst					:URLRequest;
		private var trgt					:URLLoader;

		public static var DATA_READY		:String	= "list_ready";
		
		public function XmlGrabberOld(pth:String):void 
		{
			loader = new URLLoader(); 
			reqst = new URLRequest(pth);
			loader.load(reqst);
			loader.addEventListener(Event.COMPLETE, listOnComplete, false, 0, true);	
		}
		
		private function listOnComplete(e:Event):void
		{			
			var trgt:URLLoader = URLLoader(e.target);
			xmlData = new XML(trgt.data);
			//trace(xmlData);
			
			if (trgt!=null) 
			{
				for each (var a:XML in xmlData.evnt) 
				{
					cityItems.push(a); 
					//trace("\n cityItems[a]: " + a.@city + "\n"); 
				} 					
			} else trace("error: check your data & datatype");			

			dataReady();
		}
		
		private function dataReady():void
		{
			dispatchEvent(new Event(XmlGrabberOld.DATA_READY));
		}
		
	}
}

Test class:

package 
{		
	import com.timshaya.net.XmlGrabberOld;

	import flash.display.Sprite;	
	import flash.events.Event;	
	import flash.utils.getTimer;

	[SWF (width="600", height="400", backgroundColor="#FFFFFF", frameRate="30")]	
	public class TestOld extends Sprite 
	{	
		private var xml						:XmlGrabberOld;		
		private var xmlPth                  :String = "xml/"; 
		private var xmlName  				:String = "events.xml"; 		
		private var timer					:Number;
		
		public function TestOld():void 		
		{								
			addEventListener(Event.ADDED_TO_STAGE, initApp);		
		}

		public function initApp(e:Event):void 
		{
			timer = getTimer();
		
			xml = new XmlGrabberOld(xmlPth + xmlName);
			xml.addEventListener(XmlGrabberOld.DATA_READY, createPage);											
		}

		public function createPage(e:Event):void 
		{						
			trace("TestOld::createPage()");		
			trace("\t time elapsed: " + (getTimer() - timer));		
			
			trace("\t xml.cityItems[0].@city = " + xml.cityItems[0].@city); 
			trace("\t xml.cityItems[0].@state = " + xml.cityItems[0].@state);						
		} 						
		
	}
}

Sample xml file, events.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<evnts>		
	
	<evnt lnk="test.aspx?c=0" city="Atlantic City" state="New Jersey" />
	<evnt lnk="test.aspx?c=1" city="Clifton" state="New Jersey" />	
	<evnt lnk="test.aspx?c=2" city="Allentown" state="Pennsylvania" />
	<evnt lnk="test.aspx?c=3" city="Akron" state="Ohio" />
	<evnt lnk="test.aspx?c=4" city="Wichita Falls" state="Texas" />
	<evnt lnk="test.aspx?c=5" city="Austin" state="Texas" />
	<evnt lnk="test.aspx?c=6" city="Orlando" state="Florida" />
	<evnt lnk="test.aspx?c=7" city="Atlanta" state="Georgia" />
	<evnt lnk="test.aspx?c=8" city="San Francisco" state="California" />
	<evnt lnk="test.aspx?c=9" city="Los Angeles" state="California" />
	<evnt lnk="test.aspx?c=10" city="San Diego" state="California" />	
	
</evnts>

Checking out a new book for Java EE & Flex 3, published 2009

I  couldn’t find any sort of companion site url. Was I not reading carefully enough or does one not exist on purpose/due to time constraints? 

Trying out the Ch.6: Writing Java Web Applications example…  

On first try, I had a configuration problem trying to install ALL of  Spring IDE 2.2.4 plugin for Eclipse 3.4 for Java EE on OS X 10.4.11.  Here’s the error message:

2

Staying in Eclipse 3.4 I then tried to install only the Spring IDE parts specified on p.33 by doing Help > Software Updates > Available Software > Add Site  (http://springide.org/updatesite)  and the installation worked.

Note
It was quicker and easier to do this Spring MVC tutorial first, before doing Ch.6’s detailed ANT build solution. There was 1 vague area here, in the Adding Libraries section it was unclear which folders contain which .jar file. Also, the file names didn’t contain the version numbers in them. After a little digging inside /mylocalpath/spring-framework-2.5.6/, it was fine. Most were in “dist,” “lib,” or “jakarta-commons.”

Here’s a resource for going beyond the Ch.6 example: Mastering Spring MVC.