Archive for the 'Tutorial' Category

Consuming webservices in Flash 8

Monday, May 5th, 2008

During a partial refactoring process of the Behrloo client system, one of the items on my list was the backend webservice result processing. Without going into a lot of detail how these services are wrapped, it suffices to say that somewhere in the application a couple of webservices are being initialized and utilized through the macromedia webservice classes.

You might be familiar with them, they come in several flavours, for example the WebServiceConnector and the Webservice class. Personally I don’t like to use the WebServiceConnector, mostly since the Webservice class is simple enough to use and tends to give you more control over what is happening.

Basic example

As a simple example of using this Webservice class, paste the following code onto the first frame of the timeline in a new fla document (on a sidenote, REAL applications are not written on a timeline, but for example purposes/quick proof of concepts, this will do just fine):

//example 1
import mx.services.*;

var lLog:Log = new Log (Log.VERBOSE, "myLog");
var lWebService:WebService =
     new WebService ("http://www.flash-mx.com/mm/tips/tips.cfc?wsdl", lLog);

You’ll note some log information passing by in your output window, showing you the progress during the initialization process and such. Somewhere at the end you’ll see a line like:

4/23 13:14:32 [INFO] myLog: Made SOAPCall for operation getTipByProduct

This means the webservice supports an operation called getTipByProduct. Other than that you don’t really know much about it. This is the first step in handling webservices, getting a grip on what your dealing with. Although there are different methods for doing so, I’ll mention two:
1. the webservice panel in flash, this allows you to enter a webservice url, and check the methods including the required parameters and expected return types in flash.
2. WebServiceStudio, a neat little tool. You might need to disable your proxy if it is giving you the same headaches as ours, but other than that, this tool will let you open, inspect and interrogate webservices.

Looking through Flash’s helpfiles you’ll find an example where the getTipByProduct is called with a string argument of “Flash”, so let’s try that one by extending our example.

Webservices are asynchronous

First thing to realize is that, just like most things in flash, a webservice is asynchronous, meaning that code following the instantiation of a webservice will execute before the webservice is actually instantiated. An example that demonstrates this fact extends the previous example:

//example 1
import mx.services.*;

var lLog:Log = new Log (Log.VERBOSE, "myLog");
var lWebService:WebService =
    new WebService ("http://www.flash-mx.com/mm/tips/tips.cfc?wsdl", lLog);

//example 2 addition
trace ("*** You'll see me before the log output has completed ***");

This ofcourse means that if you try to call a method on the webservice before it has been instantiated the call will fail. In other words: we will have to wait till it has been successfully instantiated. Without too much further explanation, we’ll just show the complete process of calling a method on the webservice and showing the results and then continue to the result processing part, since the process itself is explained in enough detail in the Flash Manual:

//example 1
import mx.services.*;

var lLog:Log = new Log (Log.VERBOSE, "myLog");
var lWebService:WebService = new WebService ("http://www.flash-mx.com/mm/tips/tips.cfc?wsdl", lLog);

//example 2 addition
trace ("*** You'll see me before the log output has completed ***");

//example 3 addition
import mx.utils.Delegate;

lWebService.onFault = function () { trace ("WHOOPS!"); }
lWebService.onLoad = Delegate.create (this, _performExampleCall);

function _performExampleCall() {
   trace("\n\nPerforming example call...");
   var lPendingCall:PendingCall = lWebService.getTipByProduct("Flash");
   lPendingCall.onResult = Delegate.create (this, _parseResult);
}

function _parseResult (pResults:Object) {
   trace ("\n\nResults:\n"+pResults);
}

Decoding webservices results

The thing to note in this example is that the result is a simple string. However, and that is were we get to the interesting part of this post: that is not always the case. The result could be an array, a predefined class, or some other complex object. This is were a couple of other settings/flags come into play:

- doDecoding
- doLazyDecoding

The Flash manual has this to say with respect to these two flags:

SOAPCall.doDecoding-description:
Turns decoding of the XML response on (true) or off (false). By default, the XML response is converted (decoded) into ActionScript objects. If you want just the XML, set SOAPCall.doDecoding to false.

SOAPCall.doLazyDecoding-description:
Turns “lazy decoding” of arrays on (true) or off (false). By default, a “lazy decoding” algorithm is used to delay turning SOAP arrays into ActionScript objects until the last moment; this makes functions execute much more quickly when returning large data sets. This means any arrays you receive from the remote location are ArrayProxy objects. Then when you access a particular index (foo[5]), that element is automatically decoded if necessary. You can turn this behavior off (which causes all arrays to be fully decoded) by setting SOAPCall.doLazyDecoding to false.

Let’s look into doDecoding first:

Although the description is pretty clear, the actual results I got when interpreting webservice results in Behrloo (which uses a .Net webservice backend), were kind of puzzling. When I turned decoding off, I still got an xml object as a result (while I was expecting a large string of some sort), and when I turned decoding on, I got an object which consisted of nodes of type String, Boolean, Array but also of XmlNode (so part of the result was still xml).

In the first implementation of the Behrloo backend, I had decoding turned on, and I dealt with both ‘decoded’ nodes, and xml nodes, which I decoded myself using several xml parsing mechanisms. However triggered by the testresults above, I decided to dive a bit deeper into the WebService class source code, and I found that under the hood the Webservice class is already an XML object to execute any calls to a webservice. This means that WHATEVER you do, the result is always already an XML object. With or without decoding.
With decoding turned on, it goes on to try and decode your object, EXCEPT for the nodes with an xsi:type=”…” attribute, which unfortunately most of my nodes had. I found no way to override this behavior, which means that the default decoding mechanism didn’t do a lot to help me.

Disabling the default decoding

By default, the result is decoded. This takes time, and is kind of useless if you are not using this feature anyway. However disabling the decoding cannot be done on a pendingcall since in order to get a reference to a pendingcall, you need to execute it first, so we disable the decoding through:

_myWebService.getCall ("<operation name here").doDecoding = false;

If you want to do this automatically for all calls defined on a webservice use something like:

for (var lOperationName:String in _myWebService.stub.activePort) {
	myWebService.getCall (lOperationName).doDecoding = false;
}

So what about doLazyDecoding?

LazyDecoding only kicks in if you have doDecoding enabled, after all if we do not decode anything, setting it to lazy has no effect.

Parsing the webservice result with decoding turned off

Well assuming you still want to use webservice and don’t want to switch to something like remoting, we use a simple XmlUtil class that converts XML objects to complete actionscript objects. In our project we need to interpret the complete result from the webservice, so this is feasible (in other words, we don’t spend time decoding object we don’t use anyway).

The source for our XmlUtil can be found here (save as XmlUtil.as in nl/trimm/util):
XmlUtil.as

NSTTWEF !!

Wednesday, January 30th, 2008

Also known as a Non Selectable Transparent Textfield With Embedded Font :).

Some of the V2 Flash Components are less than intuitive now and then. While working on the new trophy tour for Heineken we had to create an application with a transparent textarea with non selectable non editable text using a non standard (embedded) font with Spanish characters (amongst others) ( in Flash 8 ). Oh yeah and the text had to be rendered smoothy using advanced anti-aliasing.

This leaves you with different options. Although I was tempted to simply use a standard textfield, this should be easy to implement using a TextArea component as well, right? Sure. As an easy reference for our own and your convenience, here is a step by step approach.

Creating the test movie

  1. create a new flash movie, size it 300 x 300, and choose a background other than white
  2. drag a TextArea on stage, name it ‘ta_test’ and enter some text for the text parameter in the parameter section
  3. compile the movie, you’ll see a textarea with a border, a white background, whose text is editable and selectable

ActionScript 2, timeline scripting or parameter settings?

You’ll have to decide if you want to approach this using the parameter settings, timeline code or actionscript 2 code. In some cases you can choose, and in some I found timeline code was the easy/only option. This can probably be fixed by waiting a few frames after instantiating the TextArea, but this sounds like a nice exercise for some other time. Let’s keep it simple for now and use whatever works for demonstration purposes.

(more…)

Why you MUST call super

Friday, December 7th, 2007

When implementing super and subclasses, Flash will call the superclass’ constructor automatically unless you call it yourself.

‘Great’, I hear you think. Well… not so much.

Imagine you have the following code:

class Super {
   public function Super () {
       trace ("super called");
   }
}

class Sub extends Super {
}

var myObject:Object = new Sub();

Result? Yes indeed, it traces “super called”. The constructor for Sub doesn’t exist, so the default constructor is used, which calls the super class constructor by default.
All’s fine…

Next example:

class Super {
   public function Super (pName:String) {
       trace ("super called with "+pName);
   }
}

class Sub extends Super {
}

var myObject:Object = new Sub();

Result? The super constructor is still called! (To my amazement, but anyway). It is called with no parameters since we didn’t pass any, so I guess that was to be expected. So although this is a little evidence that we should have called the constructor explicitly, it still wouldn’t have prevented us from calling it without parameters.

Ok, next bit of code:

class Super {
   public function Super (pName:String) {
       trace ("super called with "+pName);
   }

   public function mySuperMethod() {
   }
}

class Sub extends Super {
    public function Sub() {
    }
}

var myObject:Object = new Sub();

Result? Yes, the super constructor is still called, since that was the default behavior. Us defining a constructor doesn’t mean we have overridden the superclass constructor.

Ok, let’s move on!

class Super {
   public function Super (pName:String) {
       trace ("super called with "+pName);
   }

   public function mySuperMethod() {
   }
}

class Sub extends Super {
    public function Sub() {
        super.mySuperMethod();
    }
}

var myObject:Object = new Sub();

Result? The super constructor is NO LONGER called. Appearently something is getting messed up by the super. statement. In both the Flash IDE and the MTASC compiler the super constructor fails to run. If we replace super.mySuperMethod(); with mySuperMethod(); the super constructor is called again. Note that super.mySuperMethod is NOT a case of calling the superclass’ constructor, I’m simply calling one of the superclass’ methods.

Conclusions:

  • always called super ( … ) ; explicitly
  • do not use super. to clarify your code, unless you consequently follow the first rule

Inverting the alpha of a bitmap image

Friday, November 30th, 2007

A piece of code and a demo says more than a thousand words :). This code demonstrates inversion of an alpha channel in Flash8/AS2.

  1. /**
  2. * This example demonstrates inverting an alpha channel on an image.
  3. * Since Flash premultiplies the alpha, we need to keep two separate images: one with the color data, and
  4. * one with the alpha data. It demonstrates splitting the alpha from an image, inverting and proves
  5. * premultiplying the alpha destroys color information.
  6. *
  7. * @author J.C. Wichman / Objectpainters.com
  8. */
  9.  
  10. import flash.geom.Rectangle;
  11. import flash.geom.Point;
  12. import flash.display.BitmapData;
  13. import flash.filters.ColorMatrixFilter;
  14.  
  15. //set up some default params for the images
  16. var width:Number = 100;
  17. var height:Number = 100;
  18. var fillColor:Number = 0x000000;
  19.  
  20. /**
  21. * Simple function that checks how many bitmaps have already been shown on stage and
  22. * bases the location for the next one on that information. Never use code like this
  23. * out of context, since its bad programming practice:).
  24. */
  25. function showBitmap (pBitmap:BitmapData, title:String) {
  26. var imageCount:Number = this.getNextHighestDepth();
  27. var row:Number = Math.floor (imageCount/3);
  28. var columns:Number = imageCount%3;
  29.  
  30. var newClip:MovieClip = this.createEmptyMovieClip("image"+imageCount, imageCount);
  31. newClip.attachBitmap(pBitmap, 0);
  32. newClip.createTextField("title", 1, 0, 110, 10,10);
  33. var textClip:TextField = newClip["title"];
  34. textClip.autoSize = true;
  35. textClip.text = "Image "+imageCount+":\n"+title;
  36. var tf:TextFormat = new TextFormat();
  37. tf.font = "Arial";
  38. tf.align ="center";
  39. textClip.setTextFormat(tf);
  40.  
  41. newClip._x = (columns * 150)+10;
  42. newClip._y = (row * 170)+10;
  43. }
  44.  
  45.  
  46. //setting up demo rgb image, this is an image without alpha.
  47. //Since flash uses premultiplied alpha, adding an alpha channel will ruin the image for
  48. //further use when we want to invert the alpha channel, so we keep colours separate from alpha
  49. //(omg pink shirts!)
  50. var colorImage:BitmapData = new BitmapData(width, height, false, fillColor);
  51. for (var x = 0; x < width; x++) {
  52. for (var y = 0; y < height; y++) {
  53. //fiddle with the pixel data to show a dark gradient
  54. colorImage.setPixel( x,y, x<<16|y<<8|x+y);
  55. }
  56. }
  57. showBitmap (colorImage, "Colour w/o alpha");
  58.  
  59. //now we create a demo alpha bitmap. All color info is non existent, only
  60. //alpha data is set. When x<y the alpha value is near opaque, otherwise its near transparent.
  61. //we only use 0xAF and 0x10 instead of 0xFF and 0x00 to show partial alpha values are inverted ok as well
  62. var demoAlpha:BitmapData = new BitmapData(width, height, true, fillColor);
  63. for (var x = 0; x < width; x++) {
  64. for (var y = 0; y < height; y++) {
  65. demoAlpha.setPixel32( x,y, (x<y?0xAF:0x10)<<24);
  66. }
  67. }
  68. showBitmap (demoAlpha, "Alpha only");
  69.  
  70. //now imagine you didnt have a separate alpha bitmap to start with, but a starting image with alpha
  71. //which you needed to extract first:
  72. var alphaSplit:BitmapData = new BitmapData(width, height, true, fillColor);
  73. //copy the alpha channel of one image to another image
  74. alphaSplit.copyChannel(demoAlpha, new Rectangle(0,0, width, height), new Point(0,0), 8,8);
  75. showBitmap (alphaSplit, "Alpha channel copy\n (same as previous)");
  76.  
  77. //now we are going to invert the alpha. This can be done on a pixel by pixel basis, but this might just
  78. //be faster, you'd have to test it
  79. var alphaInvert:BitmapData = alphaSplit.clone();
  80. var matrix:Array = new Array();
  81. matrix = matrix.concat([1, 0, 0, 0, 0]); // red
  82. matrix = matrix.concat([0, 1, 0, 0, 0]); // green
  83. matrix = matrix.concat([0, 0, 1, 0, 0]); // blue
  84. matrix = matrix.concat([0, 0, 0, -1, 0xff]); // alpha, negate the alpha and add 255
  85. alphaInvert.applyFilter(alphaInvert, alphaInvert.rectangle, new Point(0, 0), new ColorMatrixFilter (matrix));
  86. showBitmap (alphaInvert, "Inversion of \nalpha channel");
  87.  
  88. //now the real action, we combine our original color pixels with the inverted alpha channel
  89. var comboImage:BitmapData = new BitmapData(width, height, true, fillColor);
  90. comboImage.copyPixels(colorImage, colorImage.rectangle, new Point(0,0), alphaInvert, new Point(0,0));
  91. showBitmap (comboImage, "Colours + \ninverted alpha");
  92.  
  93. //now to prove premultiplied alpha destroys color information:
  94. var colorImgWithAlpha:BitmapData = new BitmapData(width, height, true, fillColor);
  95. for (var x = 0; x < width; x++) {
  96. for (var y = 0; y < height; y++) {
  97. //fiddle with the pixel data to show a dark gradient
  98. colorImgWithAlpha.setPixel32( x,y, (x<y?0xfe:0x01)<<24|x<<16|y<<8|x+y);
  99. }
  100. }
  101. colorImgWithAlpha.applyFilter(colorImgWithAlpha, colorImgWithAlpha.rectangle, new Point(0, 0), new ColorMatrixFilter (matrix));
  102. showBitmap (colorImgWithAlpha, "Colour with\n premultiplied \n inverted alpha");
  103.  
  104.  
  105.  

Ideas for asset and code separation

Wednesday, November 14th, 2007

I had an idea this afternoon for simple asset from code separation in Flash8/AS2. You might have been in the situation were you wanted to load in your views, or have your views and other assets external from your code. If these assets happened to be V2 Components you were even having a bigger party.

I am usually working on a kind of hybrid projects, I create a fla with assets and code runnable from the IDE, and use the resulting swf as an injection swf in FlashDevelop. The cool thing of working this way is that -seeing the project is hybrid and all- you can either work on the project in the Flash IDE, or crank some code in FlashDevelop. There are a few drawbacks however.

  • you are using an swf which already contains all code as an injection swf. Since we use only intrinsic mx classes, we can’t use the keep flag to remove all classes from the swf, since we lose the mx classes from the swf. However especially refactoring where new superclasses are introduced or interfaces, requires recompilation of the injection swf in the Flash IDE. And in general it’s bad practice, and bloates your swf
  • you need the code to export the swf from the IDE
  • you need the injection swf to run your application from FlashDevelop

Especially when working with a designer where the designer (more…)

Flash Frameworks Revisited

Saturday, October 20th, 2007

On my long list of plans for this year was to dive into the world of Flash Frameworks.
Only thing is that it has taken me so long, that the world has moved on to Flex Frameworks, but that’s beside the point.

I wanted to dive into frameworks because I heard all these people talk about how great frameworks are and how they’ve helped people build great applications etc.

A quick recap of my first impressions/experiences: (more…)

Creating your own testserver with a bogus domain

Tuesday, October 16th, 2007

When you are developing a theme for say Joomla, or editing a lot of content, it is easier now and then to do this offline.
However if you DO want to do this offline, you’ll need a testserver.

I’ve been using JSAS, Joomla StandAlone Server for that purpose.
Download it here: http://joomlacode.org/gf/project/jsas/frs/.

Once installed, you’re good to go with apache, php, mysql and joomla.

By default it will give you a local webserver on your localhost, reachable on port 85, in other words, to test it, goto :
http://localhost:85/

Inside the JSAS directory (more…)

Local Flash Content And SSL

Tuesday, August 14th, 2007

We are in the process of migrating one of our largest eLearning systems to SSL and Active Directory. Some of the Learning Objects within this system are pretty complex and I’ve implemented a mechanism which allows you to test them standalone.

However during the migration to SSL these objects stopped working when run locally, from the IDE or from FlashDevelop.

I tried to wrap my head around why this was happening, since I’ve been doing less and less with serverside content and certificates these past few years.

Luckily I found this URL which described the problem quite accurate.

Http:// content cannot always access https:// content it seems, but the invalid security certificate was the biggest issue for us.

Our system admin Roy Olthof quickly jumped in, installed a valid certificate and tadaaaaa. Local content could access https content again. Note that we were accessing https content on our own test server, which didnt have a certificate installed.

In addition the Flash content kept giving me the mixed content (secure and unsecure) warning. After changing all the http://’s in the macromedia/adobe codebases (contained within the object and embed tags) this disappeared as well.

Drawing using controlpoints

Wednesday, July 18th, 2007

There is an old trick which comes down to drawing a fluid line through controlpoints, by using the average of the controlpoints as anchors.

As usual most of my blogging is triggered by post on the flashcoders list, making me want to try things for myself. This has probably been done a million times, but here is my quick and dirty go at it:

You can download the example here.

arguments.callee._name?

Monday, July 16th, 2007

A question on the flashcoders list about an hour ago triggered me to put together a very simple example that I have been wanting to put together for ages now.

How do you get the name of a function?

With function we could refer to:

  • any function
  • a calling function
  • a function being called
  • My reflection package is at the core of my xflas2 logger, but I don’t think a lot of people have been using it. Even though it provides much the same information MTASC can put into a trace statement WITHOUT MTASC (except for the linenumbers). Not that I don’t like MTASC, I absolutely love MTASC and never leave home without it ;-).

    Anyway, the reflection package is perfectly capable of being used standalone without my logger or Xray around (yeah that’s right: osflash.org/xray yeah baby!). It provides two simple classes with an even simpler API: ClassFinder and FunctionFinder.

    Imagine a function:


    private static function runExample3() {
    _print (
    "I am :"+
    FunctionFinder.getFunctionName(arguments.callee)+
    " and I am defined in "+
    ClassFinder.getClassName(
    FunctionFinder.getFunctionClass(arguments.callee)
    )+
    " and OH YEAH I was called by "+
    FunctionFinder.getFunctionName(arguments.caller)
    );
    }

    Note that it’s static, but it doesn’t have to be, I’m just being a lazy git.

    This prints:


    I am :runExample3 and I am defined in SampleClass and OH YEAH I was called by main

    Now, for the small print : you HAVE to call ClassFinder.registerAll() once somewhere at the start of your program.

    For your convenience I’ve put an example together for download, have fun and let me know what you think of it!

    Note:
    I am working on an (xuse da tude but I’ve been very happy with it so far) awesome new version of a reflection package, which doesn’t have the registerAll requirement, but I’m not quite there yet so for now this will have to do :).