Sunday, October 26, 2008

Unit Testing with Fluint

If you like FlexUnit, then you really wanna check out Fluint. It does the basic unit test assert stuff, but my favorite is the sequence testing. This is where it blows FlexUnit out of the water. Great job Mike, Jeff and Mike, you have a new convert !

Saturday, October 25, 2008

Module Not Loading...WT(bleep)

Flex modules are very cool. In the AWS/X days, wrote a whole OSGi-like framework based on modules. So for this new project that I'm working on, I decided to reuse them again. Wrote a simple test case to remind myself how to use them with new Flex Builder, which BTW makes building modular application really easy. No more link reports CLI (well...it does it for you internally :-). So in my smart way (NOT) wrote the following:

public function loadModule() : void
{
const info : IModuleInfo = ModuleManager.getModule( "TestModule.swf");
info.addEventListener( ModuleEvent.READY, readyHandler );
info.load(ApplicationDomain.currentDomain);
}

private function readyHandler( event : ModuleEvent ) : void
{
trace( event.type );
}

Whenever I invoked the loadModule() function at the application creation complete, no trace would appear in my console. WT(bleep). Kept looking at the code, and re-launching the application, assuming that this time it will do it (come on, you've done that too, knowing perfectly well that the outcome will be the same ;-) After a dozen time (yes, I'm that stupid) and blaming the new Flash Player 10, I decided to read the documentation, and came across this:

"Be sure to define the module instance outside of a function, so that it is not in the function's local scope. Otherwise, the object might be garbage collected and the associated event listeners might never be invoked."

Retard !!!

Readjusted the code, as follows:

private var m_info : IModuleInfo;

public function loadModule() : void
{
m_info = ModuleManager.getModule( "TestModule.swf");
m_info.addEventListener( ModuleEvent.READY, readyHandler );
m_info.load(ApplicationDomain.currentDomain);
}

And guess what ? it works! After more reading, found out that the former code was a great way to pre-load modules. Anyway, hope you find this useful and funny. And remember: When all fails, RTFM. Or should it just be RTFM - LOL!

Thursday, October 23, 2008

[ANN] Flex Mapping API

I'm pleased to announce that we just released the Flex API for ArcGIS Server. Check it out here, and make sure to tell us what you think. Good or bad. I'm already on the road preaching the cool stuff you can do with it :-). BTW, it works on Flash Player 10 (though this is not "officially" supported), taking advantage of the speedier JIT and AVM. Check out the samples and the associated source codes to see how it works in MXML and AS3. Happy Mapping All :-)

Sunday, October 12, 2008

Faster JSON Decoder - NOT :-(

I'm looking for a fast JSON decoder in AS3, and I'm really hoping that the next Flash player will have native JSON functions like IE8. The as3 core library has a decoder. Tested it on a one megabyte JSON String and it took almost 4 seconds to decode on my MacBook Pro. Wow ! There has to be a better way. Couple of former life ago, was really into lex/yacc and flex/bison. BTW - I laughed so hard when I read the name of the first link when I googled 'lex yacc' - The generated "C" code was very fast. So one of the "modern" way to write a lexical analyzer/parser is to use ANTLR. ANTLR has an option to target ActionScript. I Found a JSON grammar reference and made simple adjustments for AS3. Ran the ANTLR Tool on the 'g' files and compiled the generated AS files into a test harness. BTW - Had to adjust by hand the generated AS3 code, as it did not compile out-of-the-box :-( I passed a set of test cases for the exception of escaped string content. Now, back to the one megabyte JSON String. It took almost 29 seconds !!!! Wow ! Thinking about it some more. It kinda make sense, as I'm evaluating the string from a generated AST. Anyway, I believe you should "publish" your successes and failures. Like usual, here is the source code.

Friday, October 3, 2008

REST + JSON + AMF

So...I was asked to investigate what will it take to output data in AMF to an existing REST endpoint. The idea is that, with just a path info switch, the endpoint can output XML, JSON or AMF i.e. http://server/rest/service/json, http://server/rest/service/amf. And no, a direct BlazeDS integration is not an option :-( So after looking at the BlazeDS source code (you gotta love open source :-) I homed in on the Java15Amf3Output class. It take an output stream as a property and has a writeObject method. Cool ! So given an Address instance:

package com.esri.webamf;

import java.io.Serializable;

public class Address
implements Serializable
{
private String m_addr;
private String m_city;

public Address()
{
}

public String getAddr()
{
return m_addr;
}

public void setAddr(final String addr)
{
m_addr = addr;
}

public String getCity()
{
return m_city;
}

public void setCity(final String city)
{
m_city = city;
}
}

I can write it to the servlet output stream as follows:

private void writeAMF(
final HttpServletRequest httpServletRequest,
final HttpServletResponse httpServletResponse
) throws IOException
{
final Address address = new Address();
address.setAddr( httpServletRequest.getParameter("addr"));
address.setCity( httpServletRequest.getParameter("city"));
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final Amf3Output amf3Output = new Java15Amf3Output(new SerializationContext());
amf3Output.setOutputStream(baos);
amf3Output.writeObject(address);
amf3Output.writeObjectEnd();
amf3Output.flush();

httpServletResponse.setContentType(MessageIOConstants.AMF_CONTENT_TYPE);
httpServletResponse.setContentLength(baos.size());
baos.writeTo(httpServletResponse.getOutputStream());
}

On the client side, I used a URLStream instance with an AMF3 object encoding to HTTP GET the result as an ActionScript object as follows:

private function load() : void
{
var urlRequest : URLRequest = new URLRequest( "http://localhost:8080/webamf/rest/amf" );
var urlVariables : URLVariables = new URLVariables();
urlVariables.addr = addr.text;
urlVariables.city = city.text;
urlRequest.data = urlVariables;

var urlStream : URLStream = new URLStream();
urlStream.objectEncoding = ObjectEncoding.AMF3;
urlStream.addEventListener(Event.COMPLETE, completeHandler );
urlStream.load( urlRequest );
}
private function completeHandler( event : Event ) : void
{
var urlStream : URLStream = event.target as URLStream;
address = urlStream.readObject() as Address;
}

Where Address is tagged as a remote class aliased to the server side Address class:

package com.esri.webamf
{
[Bindable]
[RemoteClass(alias="com.esri.webamf.Address")]
public class Address
{
public var addr : String;
public var city : String;

public function Address()
{
}
}
}

Cool ?

Thursday, October 2, 2008

Graphic Custom Symbols

We refactored the Symbol class for the next release of the Flex api for ArcGIS Server so it can be easily customized. Here is a simple custom symbol:

package com.esri.symbol
{

import com.esri.ags.Map;
import com.esri.ags.geometry.Geometry;
import com.esri.ags.geometry.MapPoint;
import com.esri.ags.symbol.Symbol;

import flash.display.Sprite;

/**
* Simple custom class with variable color property.
*/
public class CustomSymbol extends Symbol
{
private var m_color : Number;

/**
* Constructor
* @param color optional color. Default 0xFF0000
*/
public function CustomSymbol( color : Number = 0xFF0000 )
{
m_color= color;
}

[Bindable]
/**
* Bindable color property. dispatch Event.CHANGE on change.
* Graphic objects are CHANGE event listeners, and will invalidate their display list
* upon the receipt of the event.
*/
public function get color() : Number
{
return m_color;
}
/**
* @private
*/
public function set color( value : Number ) : void
{
if( value != m_color )
{
m_color = value;
dispatchEventChange();
}
}

/**
* Clear the sprite.
* Recommended that you do this here not in the draw function.
*/
override public function clear( sprite : Sprite ) : void
{
sprite.graphics.clear();
}

/**
* Draw the geometry.
* Here we only render MapPoints.
*/
override public function draw(
sprite : Sprite,
geometry : Geometry,
attributes : Object,
map : Map
) : void
{
if( geometry is MapPoint )
{
drawMapPoint( sprite, MapPoint(geometry), map);
}
}

/**
* Draw the map point.
* Here we position the sprite and use raw flash graphics primitive to draw.
*/
private function drawMapPoint(
sprite : Sprite,
mapPoint : MapPoint,
map : Map
) : void
{
sprite.x = toScreenX( map, mapPoint.x );
sprite.y = toScreenY( map, mapPoint.y );

sprite.graphics.beginFill( m_color, 0.5 );
sprite.graphics.drawCircle( 0, 0, 10 );
sprite.graphics.endFill();
}

}
}

And here is how it is used:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:esri="http://www.esri.com/2008/ags"
xmlns:symbol="com.esri.symbol.*"
layout="vertical"
>
<esri:Map openHandCursorVisible="false">
<esri:ArcGISTiledMapServiceLayer
url="http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer"/>
<esri:GraphicsLayer>
<esri:Graphic toolTip="Hello, World!">
<esri:geometry>
<esri:MapPoint x="45" y="45"/>
</esri:geometry>
<esri:symbol>
<symbol:CustomSymbol color="{colorPicker.selectedColor}"/>
</esri:symbol>
</esri:Graphic>
</esri:GraphicsLayer>
</esri:Map>
<mx:ColorPicker id="colorPicker"/>
</mx:Application>

You can see it in action here.
Here is another example where I'm using Degrafa's drawing capabilities to create a simple pie chart symbol, where the wedges are proportional to the graphic attribute values. And finally, here is another example, where I'm using embedded and downloaded bitmaps. You can download the source code from here.