RPC in Flash, AMF

June 3, 2010

1. AMF (Action Message Format):

  1. Zend AMF
  2. Java Server BlazeDC
    • Java AMF Client (enable Java applications talk to AMF compliant servers such as BlazeDS, LCDS, or AMFPHP)

2. Benchmarks:

  1. Census: RIA Data loading Benchmarks
  2. Ajax and Flex Loading Benchmarks ( Read Comments as well !  or Google the name as you’ll need to make your investigation to make your opinion)
  3. WebService-HTTP Service – AMF (test from themidnightcoders)
  4. AMF vs. JSON vs. XML:
    • reply from Java Performance blog :  there are different costs for large amounts of data to be send
    • original post by R.Monsol Haefel ( blogged about the advantages and disadvantages of AMF versus JSON versus XML )
    • 5 1/2 blog post : “Now if you’re developing the back-end services yourself, then please, by all means, use AMF if you’re using Flash, and JSON if you’re using AJAX.”

3. Definitions:

  • AMF3  : a compact binary object serialization protocol.
  • AMF (from midnight coders site):
    is a binary protocol designed by Macromedia/Adobe enabling Flash/Flex clients to communicate with backend services. When a Flex/Flash client performs a remoting invocation, the data about the call is encoded in the AMF format and carried in HTTP request to the server. The message contains information about what method should be invoked, values for the arguments, etc. Since AMF is binary and includes a lot of optimizations to keep the size of the AMF messages small, it becomes very compact in comparison to SOAP/XML used by Web Services
  • WebORB and AMF:
    When a Flex/Flash client sends a Remoting/AMF invocation to the web server, it is an HTTP request with binary payload. Web servers do not have built-in knowledge of how to handle and parse AMF messages. As a result, there must be something plugged into web server to enable processing of the AMF messages. Conceptually that piece of software is commonly referred as ‘Remoting Gateway’. A gateway is responsible for parsing and AMF messages, understanding what method should be invoked, handling method invocation and serializing return value back to the client. WebORB is an example of a remoting gateway. However, the product has evolved to provide significantly more functionality to enable other forms of client-server integration.

4. Notes:

  • Add Gzip option on tests ( apply Gzip to JSON string to compact sending data)

Convert Flash IDE graphics to vector data

June 3, 2010

There is a very nice JSFL script “Sel2Draw” (http://debreuil.com/ASDraw/) which converts selected Flash IDE drawings to vector data (as2), line & spline primitives,  see example in Appendix. Read 3D Vectors: From Vector Illustrations Via Sel2draw Into FiVe3d  http://www.motiondraw.com/blog/?p=119

Other links:

1. Converting SVG to FIVE3D, Flash Vector Graphics and Html5 Canvas
2. Shape Export to Objective-C

Appendix.

var drw0 = [
{    fill:[0x3cc00],
origin:[20,70],
records:[[20,49.25,34.6,34.6], [49.25,20,70,20], [90.75,20,105.35,34.6], [120,49.25,120,70], [120,90.75,105.35,105.35], [90.75,120,70,120], [49.25,120,34.6,105.35], [20,90.75,20,70]],
strokes:[[1,0×06600], “-“, “-“, “-“, “-“, “-“, “-“, “-“]
},
{    fill:”stroke”,
origin:[20,10],
records:[[120,10]],
strokes:[[1,0×06600]]
}];
// =====================
//create drawing here:
// =====================
_root.createEmptyMovieClip(“dr0”, 1000);
var img0 = _root[“dr0”];
drawImage(img0, drw0);

var drawImage = function(clip, dat)
{    var prevFill = null;
for(var el = 0; el < dat.length; el++)
{    var element = dat[el];
clip.moveTo(element.origin[0],element.origin[1]);
if(    element.fill == -1 || element.fill == “stroke”)
{    if(prevFill != “stroke”)
{    clip.endFill();
prevFill = element.fill;
}
}else if(element.fill != “donut”)
{    if(element.fill.length != 5)
{    clip.beginFill.apply(clip, element.fill);
}else
{    clip.beginGradientFill.apply(clip, element.fill);
}
prevFill = element.fill;
}
var recs = element.records;
var strokes = element.strokes;
var curStroke = -1;
if(strokes[0] == null)
{    clip.lineStyle();
}else
{    clip.lineStyle.apply(clip, strokes[0]);
}
for(var i = 0; i < recs.length; i++)
{    curStroke = strokes[i];
if(curStroke != “-“)
{    if(curStroke == null)
{    clip.lineStyle();
}else
{    clip.lineStyle(curStroke[0], curStroke[1]);
}
}
var rec = recs[i];
if(rec.length == 4)
{    clip.curveTo(rec[0],rec[1],rec[2],rec[3]);
}
else
{    clip.lineTo(rec[0],rec[1]);
}
}
}    clip.endFill();
return clip;
}

Links: Design Patterns

May 27, 2010
  1. Structural Patterns – Facade Patternhides the complexities of system from the client and provides a simpler interface, see there as well
    (list of patterns as in book “Design Patterns, Elements of Reusable Object Oriented Software” by E.Gamma, R.Helm, R.Johnson, J.Vlissides):

    1. Creational Patterns:
      1. Factory Pattern
      2. Abstract Factory Pattern
      3. Singleton Pattern
      4. Builder Pattern
      5. Prototype Pattern
    2. Structural Patterns:
      1. Adapter Pattern
      2. Bridge Pattern
      3. Composite Pattern
      4. Decorator Pattern
      5. Facade Pattern
      6. Flyweight Pattern
      7. Proxy Pattern
    3. Behavioral Patterns:
      1. Chain of Responsibility Pattern
      2. Command Pattern
      3. Interpreter Pattern
      4. Iterator Pattern
      5. Mediator Pattern
      6. Momento Pattern
      7. Observer Pattern
      8. State Pattern
      9. Strategy Pattern
      10. Template Pattern
      11. Visitor Pattern
  2. Entry-Point Function Definition: Microsoft DLL
  3. QueryInterface retrieves pointers to the supported interfaces on an object

Design Patterns: Singleton

May 21, 2010

1). Implementation from Scott Morgan: (ExternalInterfaceBuffer source code)

package …
public class ExternalInterfaceBuffer{

private static var instance:ExternalInterfaceBuffer = new ExternalInterfaceBuffer();
public function ExternalInterfaceBuffer() {
if( instance ) throw new Error( “Singleton and can only be accessed through Singleton.getInstance()” );
}

public static function getInstance():ExternalInterfaceBuffer {
return instance;
}

2). from Darron Schall: Actionscript 3 Singleton Redux

package …

private static const _instance:Model = new Model( SingletonLock )
public function Model( lock:Class )
{
// Verify that the lock is the correct class reference.
if ( lock != SingletonLock ){
throw new Error( “Invalid Singleton access.  Use Model.instance.” );
}
}

class SingletonLock{} // end class

3). Grant Skinner: AS3 Singleton

4). What if you would like to pass some arguments in constructor?

External Interface

May 21, 2010

ExternalInterfaceBuffer source code by Scott Morgan

package com.yahoo.webapis.maps.utils {

public class ExternalInterfaceBuffer {

import flash.external.ExternalInterface;
import flash.utils.setInterval;
import flash.utils.clearInterval;

private static var instance:ExternalInterfaceBuffer = new ExternalInterfaceBuffer();
private var methodQueue:Array = new Array();
private var methodCallInterval:Number;

public function ExternalInterfaceBuffer() {
if( instance ) throw new Error( “Singleton and can only be accessed through Singleton.getInstance()” );
}

public static function getInstance():ExternalInterfaceBuffer {
return instance;
}

public function addCall(obj:Object):void {
methodQueue.push(obj);
if (isNaN(methodCallInterval) || methodCallInterval == 0) {
methodCallInterval = setInterval(methodChurn, 50);
}
}

private function methodChurn():void {
if (methodQueue[0].method != undefined && methodQueue[0].method != null) {
ExternalInterface.call(methodQueue[0].method, methodQueue[0].data);
}
methodQueue.shift();
if (methodQueue.length == 0) {
clearInterval(methodCallInterval);
methodCallInterval = undefined;
}
}


Links: Definitions

May 17, 2010
  1. Hash tables (hush function), “to quickly locate a data record (for example, a dictionary definition) given its “search key
    Associative arrays, dynamic sets.
  2. Namespaces: tutorial from Grant Skinner
  3. Matrices in AS3: tutorial from Senocular
  4. Matrix: analog of  “MovieClip.localToGlobal(point)” on Matrix level:

import flash.geom.Matrix;
/**
 * "Global" matrix of nested MovieClip
 * @author Sergei Nikiforovski, 2010
 * note: as2 !
 */
public function getMc_nestedMatrix( mc:MovieClip ):Matrix
 {
 var m0:Matrix = mc.transform.matrix;

 var mc2:MovieClip;
 var m:Matrix = new Matrix();

 for (var s in mc) {
 if ( typeof( mc[s] ) == "movieclip" ) {
 mc2 = mc[s];
 m = getMc_nestedMatrix( mc2 );
 break;
 }
 }

 m.concat( m0 );
 return m;
 }

Links: AS3 code to use

May 17, 2010
  1. Bulk loader – getting started:
    var loader : BulkLoader = new BulkLoader(“main-site”);
    loader.add(“background.jpg”, {id:”bg”});
    loader.add(“/unreliable-web-service.xml”, {maxTries:6});
    loader.addEventListener(BulkLoader.COMPLETE, onAllLoad):
    loader.start();
    Developer guide.
  2. Debugging
    a). as3 hidden treasure in the mm.cfg fiel. Revealing and documenting many Flash secrets,
    – Windows, C:\Documents and Settings\username\mm.cfg
    b). Socket output server: SOS-max
  3. Tween, animations:
    a). Greensock: TweenLite, TweenMax, TweenNan
    b). Caurina tweener
  4. Component’s framework:
    a). AsWing, code download
    b). Minimal comps (BIT-101Peters Keith)  –  Google code
  5. External Interface:
    a). Buffer Source Code,
    b). Adobe example

Links: Flex, AS – PHP

May 17, 2010

1. Back end links:

  • Flex – building remote endpoint by Kevin Scroeder (browse for Zend posts there !), using Zend Framework. Provide data access layer;  ability to use components;  Zend studio, Zend_tool; MVC design pattern. Auto-created Folder’s structure: apps.configs, apps.controllers, apps.models, apps.views, apps/Bootstrap.php, docs, library, public, test; Two classes which extends zend’s Zend_Db_Table_Abstract, Zend_Db_Table_Row_Abstract. Service.php functions: getAll..(), get..ByID(), create..(); gateway.php; bootstrap.php
  • Flex and ZendFramework

Local Connection : Grant Skinner

May 10, 2010

as3 (SWFBridge3.as)  vs  as2 (SWFBridge2.as)  code:

Class variables (both):
baseID:String
myID:String;
extID:String;
lc:LocalConnection;   //used just one lc – that’s nice!
_connected:Boolean=false; //very useful, will dispath
host:Boolean=true; //will auto determine who is host (host the one, came first)
clientObj:Object; //will “redirect” or apply calls to this object (executes methods on the object)

Class:est=
SWFBridgeAS3( p_id:String,p_clientObj:Object)  <-> SWFBridgeAS2(p_id:String,p_clientObj:Object)
as3: SWFBridgeAS3 extends EventDispatcher
as2 (in constructor): EventDispatcher.initialize(this);

Class constructor:
both: lc = new LocalConnection();

as3: lc.client = this;
as2 (redirection to class function,  compare to lc.client = this  in as3 ):
var _this:Object = this;
lc.com_gskinner_utils_SWFBridge_init = function() {
_this.com_gskinner_utils_SWFBridge_init();
}
lc.com_gskinner_utils_SWFBridge_receive = function() {
_this.com_gskinner_utils_SWFBridge_receive.apply(_this,arguments);
}

as2:  host = lc.connect(baseID+”_host”);
as3:
try {
lc.connect(baseID+”_host”);
} catch(e:ArgumentError) {
host = false;
}

both  ( gust will call init() function on host and host will “ping” back, variables this._connected will be send try and connect event fired – brilliant!):
if (!host) {
lc.connect(myID);
lc.send(extID,”com_gskinner_utils_SWFBridge_init”);
}

init :
public function com_gskinner_utils_SWFBridge_init():Void {
trace(“SWFBridge (AS2) connected as “+(host?”host”:”client”));
if (host) {
lc.send(extID,”com_gskinner_utils_SWFBridge_init”);
}
_connected = true;
dispatchEvent({type:”connect”});
}
difference in as3: dispatchEvent(new Event(Event.CONNECT));

Exchanging messages:

1. send():
as3:
public function send(p_method:String,…p_args:Array):void {
if (!_connected) { throw new ArgumentError(“Send failed because the object is not connected.”); }
p_args.unshift(p_method);
p_args.unshift(“com_gskinner_utils_SWFBridge_receive”);
p_args.unshift(extID);
lc.send.apply(lc,p_args);
}
as2:
public function send():Void {
if (!_connected) { return; }
var args:Array = arguments.slice(0);
args.unshift(“com_gskinner_utils_SWFBridge_receive”);
args.unshift(extID);
lc.send.apply(lc,args);
}
note (arguments sent internally): connectionName, nameOfMethodtoCall_onBridgeClass, nameOfMethodtoCall_onClientObjectClass, argumentsOfFinalMethod

2. receive:
as3:
public function com_gskinner_utils_SWFBridge_receive(p_method:String,…p_args:Array):void {
try {
clientObj[p_method].apply(clientObj,p_args);
} catch (e:*) {
trace(“SWFBridge ERROR:  “+e);
}
}
as2:
public function com_gskinner_utils_SWFBridge_receive():Void {
var args:Array = arguments.slice(0);
var method:String = String(args.shift());
clientObj[method].apply(clientObj,args);
}

Other class methods:
public function close():void
public function get id():String
public function get connected():Boolean

Usage:
Could be used for communication as3-as2, as3-as3, as2-as2; browser-projector (check Security Domain guidelines in “LocalConnection” help)

Link: http://www.gskinner.com/blog/archives/2007/07/swfbridge_easie.html

Usage Example:
import com.gskinner.utils.SWFBridgeAS3;

var sb1:SWFBridgeAS3 = new SWFBridgeAS3(“test”,this);

sb1.addEventListener(Event.CONNECT,onConnect);
function onConnect(p_evt:Event) {
out(p_evt);
}

function click1(p_evt:Event) {
out(“click”)
sb1.send(“sbTest”,”sent from”,loaderInfo.url.substr(loaderInfo.url.lastIndexOf(“/”)));
}

Appendix 1, SWFBridgeAS3.as:
/**
* SWFBridgeAS3 by Grant Skinner. March 11, 2007
* Visit http://www.gskinner.com/blog for documentation, updates and more free code.
*
* You may distribute this class freely, provided it is not modified in any way (including
* removing this header or changing the package path).
*
* Please contact info@gskinner.com prior to distributing modified versions of this class.
*/

package com.gskinner.utils {
import flash.net.LocalConnection;
import flash.events.EventDispatcher;
import flash.events.Event;

public class SWFBridgeAS3 extends EventDispatcher {
private var baseID:String;
private var myID:String;
private var extID:String;
private var lc:LocalConnection;
private var _connected:Boolean=false;
private var host:Boolean=true;
private var clientObj:Object;

public function SWFBridgeAS3(p_id:String,p_clientObj:Object) {
baseID = p_id.split(“:”).join(“”);
lc = new LocalConnection();
lc.client = this;
clientObj = p_clientObj;

try {
lc.connect(baseID+”_host”);
} catch(e:ArgumentError) {
host = false;
}

myID = baseID+((host)?”_host”:”_guest”);
extID = baseID+((host)?”_guest”:”_host”);
if (!host) {
lc.connect(myID);
lc.send(extID,”com_gskinner_utils_SWFBridge_init”);
}
}

public function send(p_method:String,…p_args:Array):void {
if (!_connected) { throw new ArgumentError(“Send failed because the object is not connected.”); }
p_args.unshift(p_method);
p_args.unshift(“com_gskinner_utils_SWFBridge_receive”);
p_args.unshift(extID);
lc.send.apply(lc,p_args);
}

public function close():void {
try { lc.close(); } catch (e:*) {}
lc = null;
clientObj = null;
if (!_connected) { throw new ArgumentError(“Close failed because the object is not connected.”); }
_connected = false;
}

public function get id():String {
return baseID;
}

public function get connected():Boolean {
return _connected;
}

public function com_gskinner_utils_SWFBridge_receive(p_method:String,…p_args:Array):void {
try {
clientObj[p_method].apply(clientObj,p_args);
} catch (e:*) {
trace(“SWFBridge ERROR:  “+e);
}
}

public function com_gskinner_utils_SWFBridge_init():void {
trace(“SWFBridge (AS3) connected: “+(host?”host”:”client”));
if (host) {
lc.send(extID,”com_gskinner_utils_SWFBridge_init”);
}
_connected = true;
dispatchEvent(new Event(Event.CONNECT));
}
}
}

Appendix 2, SWFBridgeAS2.as:
/**
* SWFBridgeAS2 by Grant Skinner. March 11, 2007
* Visit http://www.gskinner.com/blog for documentation, updates and more free code.
*
* You may distribute this class freely, provided it is not modified in any way (including
* removing this header or changing the package path).
*
* Please contact info@gskinner.com prior to distributing modified versions of this class.
*/

import mx.events.EventDispatcher;

class com.gskinner.utils.SWFBridgeAS2 {
private var baseID:String;
private var myID:String;
private var extID:String;
private var lc:LocalConnection;
private var host:Boolean;
private var clientObj:Object;
private var _connected:Boolean=false;

private var dispatchEvent:Function;
public var addEventListener:Function;
public var removeEventListener:Function;

public function SWFBridgeAS2(p_id:String,p_clientObj:Object) {
EventDispatcher.initialize(this);

baseID = p_id.split(“:”).join(“”);

lc = new LocalConnection();
var _this:Object = this;
lc.com_gskinner_utils_SWFBridge_init = function() {
_this.com_gskinner_utils_SWFBridge_init();
}
lc.com_gskinner_utils_SWFBridge_receive = function() {
_this.com_gskinner_utils_SWFBridge_receive.apply(_this,arguments);
}

clientObj = p_clientObj;

host = lc.connect(baseID+”_host”);

myID = baseID+((host)?”_host”:”_guest”);
extID = baseID+((host)?”_guest”:”_host”);

if (!host) {
lc.connect(myID);
lc.send(extID,”com_gskinner_utils_SWFBridge_init”);
}
}

public function close():Void {
lc.close();
delete(clientObj);
delete(lc);
_connected = false;
}

public function send():Void {
if (!_connected) { return; }
var args:Array = arguments.slice(0);
args.unshift(“com_gskinner_utils_SWFBridge_receive”);
args.unshift(extID);
lc.send.apply(lc,args);
}

public function get id():String {
return baseID;
}

public function get connected():Boolean {
return _connected;
}

public function com_gskinner_utils_SWFBridge_receive():Void {
var args:Array = arguments.slice(0);
var method:String = String(args.shift());
clientObj[method].apply(clientObj,args);
}

public function com_gskinner_utils_SWFBridge_init():Void {
trace(“SWFBridge (AS2) connected as “+(host?”host”:”client”));
if (host) {
lc.send(extID,”com_gskinner_utils_SWFBridge_init”);
}
_connected = true;
dispatchEvent({type:”connect”});
}
}

Appendix 3, SWFBridgeSimpletTest.fla:
import com.gskinner.utils.SWFBridgeAS2;

var sb1 = new SWFBridgeAS2(“test”,this);
var sb2 = new SWFBridgeAS2(“test”,this);

sb2.addEventListener(“connect”,this);

function connect(p_evt) {
trace(“connected”);
}

btn1.onRelease = function() {
_root.click1();
}

function click1() {
trace(“click1”);
sb1.send(“sbTest”,”fun”,”stuff”);
}

btn2.onRelease = function() {
_root.click2();
}

function click2() {
trace(“click2”);
sb2.send(“sbTest”,”sad”,”poo”);
}

function sbTest(p_param1,p_param2) {
trace(“sbTest: “+p_param1+” : “+p_param2);
}

Appendix 4, SWFBridgeTestAS3.as:
import com.gskinner.utils.SWFBridgeAS3;

var loader = new Loader()
loader.load(new URLRequest(“SWFBridgeTestAS2.swf”));
addChild(loader);

var sb1:SWFBridgeAS3 = new SWFBridgeAS3(“test”,this);

sb1.addEventListener(Event.CONNECT,onConnect);
function onConnect(p_evt:Event) {
out(p_evt);
}

btn1.addEventListener(“click”,click1)

function click1(p_evt:Event) {
out(“click”)
sb1.send(“sbTest”,”sent from”,loaderInfo.url.substr(loaderInfo.url.lastIndexOf(“/”)));
}

function sbTest(p_param1,p_param2){
out(“sbTest: “+p_param1+” : “+p_param2);
}

function out(p_txt:*) {
trace(p_txt);
outFld.appendText(“\n”+String(p_txt));
}

Appendix 5, SWFBridgeTestAS2.as:
import com.gskinner.utils.SWFBridgeAS2;

var sb1 = new SWFBridgeAS2(“test”,this);
sb1.addEventListener(“connect”,this);

function connect(p_evt) {
out(“connected”);
}

btn1.onRelease = function() {
_root.click1();
}

function click1() {
out(“click1”);
sb1.send(“sbTest”,”sent from”,_url.substr(_url.lastIndexOf(“/”)));
}

function sbTest(p_param1,p_param2) {
out(“sbTest: “+p_param1+” : “+p_param2);
}

function out(p_txt) {
trace(p_txt)
outFld.text += “\n”+p_txt;
}

/**
* SWFBridgeAS2 by Grant Skinner. March 11, 2007
* Visit http://www.gskinner.com/blog for documentation, updates and more free code.
*
* You may distribute this class freely, provided it is not modified in any way (including
* removing this header or changing the package path).
*
* Please contact info@gskinner.com prior to distributing modified versions of this class.
*/import mx.events.EventDispatcher;

class com.gskinner.utils.SWFBridgeAS2 {
private var baseID:String;
private var myID:String;
private var extID:String;
private var lc:LocalConnection;
private var host:Boolean;
private var clientObj:Object;
private var _connected:Boolean=false;

private var dispatchEvent:Function;
public var addEventListener:Function;
public var removeEventListener:Function;

public function SWFBridgeAS2(p_id:String,p_clientObj:Object) {
EventDispatcher.initialize(this);

baseID = p_id.split(“:”).join(“”);

lc = new LocalConnection();
var _this:Object = this;
lc.com_gskinner_utils_SWFBridge_init = function() {
_this.com_gskinner_utils_SWFBridge_init();
}
lc.com_gskinner_utils_SWFBridge_receive = function() {
_this.com_gskinner_utils_SWFBridge_receive.apply(_this,arguments);
}

clientObj = p_clientObj;

host = lc.connect(baseID+”_host”);

myID = baseID+((host)?”_host”:”_guest”);
extID = baseID+((host)?”_guest”:”_host”);

if (!host) {
lc.connect(myID);
lc.send(extID,”com_gskinner_utils_SWFBridge_init”);
}
}

public function close():Void {
lc.close();
delete(clientObj);
delete(lc);
_connected = false;
}

public function send():Void {
if (!_connected) { return; }
var args:Array = arguments.slice(0);
args.unshift(“com_gskinner_utils_SWFBridge_receive”);
args.unshift(extID);
lc.send.apply(lc,args);
}

public function get id():String {
return baseID;
}

public function get connected():Boolean {
return _connected;
}

public function com_gskinner_utils_SWFBridge_receive():Void {
var args:Array = arguments.slice(0);
var method:String = String(args.shift());
clientObj[method].apply(clientObj,args);
}

public function com_gskinner_utils_SWFBridge_init():Void {
trace(“SWFBridge (AS2) connected as “+(host?”host”:”client”));
if (host) {
lc.send(extID,”com_gskinner_utils_SWFBridge_init”);
}
_connected = true;
dispatchEvent({type:”connect”});
}
}

Ant Flex

January 11, 2010

Flex Ant:
0). Google “flex ant tasks”
1). http://livedocs.adobe.com/flex/3/html/help.html?content=anttasks_1.html
2). http://www.adobe.com/devnet/flex/articles/flex_ant_pt1_print.html
3). http://www.adobe.com/devnet/flex/articles/flex_ant_pt1_05.html#where

Data Visualization:
1). Installing Flex 3.3 SDK + Data Visualization 3.3 SWC
2). Compile Flex application