Category Archives: Flex

Flapper: An extension library for AOP with Parsley

I’ve just thrown a quick project up on Google Code for allowing simple AOP style programming with Parsley:

Flapper

The project aims to allow simple registration of AOP interceptors by registering a metatag with an interceptor.

It uses the awesome as3-commons bytecode library for proxy generation

Configuration

The aim is to have simple configuration.  You activate Flapper by simply declaring  AspectSupport in your parsley context:

        <parsley:ContextBuilder>
            <parsley:FlexConfig type="{ParsleyConfig}" />
            <tag:AspectSupport>
                <tag:MetatagAspectDefinition metatag="Log" aspect="{new LoggingAspect()}" />
            </tag:AspectSupport>
        </parsley:ContextBuilder>

In this example, I’m registering the Log metatag with my LoggingAspect.

Now, any class which has a method annotated with Log will be proxied, and the LoggingAspect will get invoked before the actual method itself.

Eg:

    public class Calculator
    {
        [Log]
        public function add(a:int,b:int):int
        {
            return a + b;
        }

    }

The aspects themselves are also extremely simple, implementing an Aspect interface.

Here’s my LoggingAspect:


    public class LoggingAspect implements Aspect
    {
        public function intercept(pointCut:ProceedingJoinPoint):void
        {
            trace(pointCut.targetMember.localName + " called with params: " + pointCut.arguments.join(","));
            pointCut.proceed();
            var returnValueString:String = pointCut.returnValue ? pointCut.returnValue.toString() : "null";
            trace(pointCut.targetMember.localName + " returned " + returnValueString );
        }
    }

This simply traces out the method name that was called, and the arguments that were passed in.

Usage

That’s all the configuration that’s required.  Now, any time I call calculator.add(), the aspect will trace out the call to the console window.

Note – classes that will be proxied must be decalred using Parsley’s Object tag, rather than as an instance.

Eg:

    <fx:Declarations>
        <!-- Don't do this -- it won't work -->
        <sample:Calculator />

        <!-- Instead, decalre using the Object tag -->
        <parsley:Object type="{Calculator}" />
    </fx:Declarations>

Usage from here is no different than with any other injected class.

Example:

            [Inject]
            public var calculator:Calculator;

            private function addNumbers():void
            {
                 // Results in a message being traced out "Called add with arguments: 2,3"
                calculator.add(2,3)
            }

The project and a demo are available to be checked out here. It’s still fairly early days, and the project hasn’t really been tested – but feel free to grab it and have a play.

Important Credit

This whole project took 2 nights to write.  The main reason it was so quick and simple  is because all the hard work has already been done by two awesome existing projects.

The as3-commons team have done an amazing job on the project, but also in providing thorough clear documentation.

Equally so, Jens Halm has done an outstanding job on Parsley, making the framework so easy to extend, with a solid API, and killer docs.  Not to mention he’s extremely responsive in the forums.  Both these projects rock.

Update:

I’ve updated this blog post to reflect the move to the Aspect interface, where previously I was using the ascommons-bytecode IInterceptor.  This has made chaining Aspects easier.  Note – I’m still using ascommons-bytecode underneath, but it’s now abstracted away a little more.

Tagged , ,

Batch Loading Proxies in dpHibernate

I want to share a new feature of dpHibernate I’ve just committed to the codebase – batch loading.

The default behaviour of dpHibernate in the Flex Client is to lazy load any property that is required, as soon as it is first asked for.

This is all well and good, but in some cases, can generate a very high load on your webserver, and in turn – your database.

Take for example the following screenshot of an upcoming dpHibernate demo project:

For every question shown, there’s a list of associated tags.  This list is lazy loaded, so dpHibernate will fetch it as soon as it’s requested.  However, in the above screenshot, that generates a server request for each of the 21 displayed tags.  Hardly efficient.

dpHibernate now supports batching of requests for proxies.  It works as follows:

  • When a request is made to load a proxy from the flex client, dpHibernate postpones sending the request for a short time (the default is 50 milliseconds)
  • If another request is received during this delay, we extend the delay another 50 milliseconds, up to a maximum delay threshold (the default is 350 milliseconds)
  • Once either no more requests are made, or the maximum delay threshold is exceeded, send a request to load all the batches in a single server request.
  • On the server, make a single trip to the database to load all the entities
  • Return the loaded entites to the client

So, where previously this would’ve taken 21 server calls & 21 database trips, we’ve reduced it down to 1.  Not bad, eh?

Configuration

This option is disabled by default.

To enable it, set the operationBufferFactory property of the HibernateRemoteObject to an instance of a LoadDPProxyOperationBufferFactory.  (Terrible names, I know, but naming is hard.)  Here’s an example:

<?xml version="1.0" encoding="utf-8"?>
<fx:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
           xmlns:s="library://ns.adobe.com/flex/spark"
           xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:digitalprimates="http://www.digitalprimates.net/2007/mxml">
    <fx:Declarations>
        <digitalprimates:HibernateRemoteObject id="dataAccessService" destination="dataAccessService" operationBufferFactory="{bufferFactory}"  />
    </fx:Declarations>
    <fx:Script>
        <![CDATA[
            import net.digitalprimates.persistence.hibernate.rpc.LoadDPProxyOperationBufferFactory;
            [Bindable]
            public var bufferFactory:LoadDPProxyOperationBufferFactory = new LoadDPProxyOperationBufferFactory();
        ]]>
    </fx:Script>
</fx:Group>

On the server, you need something to handle the load requests.  This isn’t trivial, and historically we’ve left writing server side implementations up to individual projects.  However, there’s now a default DataAccessService which provides support for all dpHibernate features out-of-the-box.  I’ll write more about this later, but if you can’t wait, head over and grab the latest source, or browse the class directly.  (Note, there’s an implementation geared towards Spring environments too here).

Tagged

Entity Persistence with dpHibernate – Overview

dpHibernate is an open source project that facilitates lazy loading of hibernate entities with BlazeDS and Flex.

Note:  If you’re not familiar with the dpHibernate project, it may to have a read of this overview post

The topic discussed here is currently only available on the changeMessaging branch of dpHibernate.  The code is available here:

http://dphibernate.googlecode.com/svn/branches/changemessaging

Recently I committed some changes to a new branch of the source which now allows persistence operations (Create, Update, Delete) on entities, using a few lines of code.

Eg:

public class SomePM {
    public void doSomeWork(author:Author) {
        author.name = “Josh Bloch”;
        author.age = 30;
        author.publisher = publishers.findByName(“AddisonLee”);
        author.save();
    }
    public function createNewAuthor():void {
        var newAuthor : Author = new Author();
        newAuthor.name = “Sondhiem”;
        newAuthor.age = 55;
        newAuthor.save();
    }
    public function deleteAuthor(author:Author):void
    {
        author.deleteRecord();
    }
}

This is similar to the entity persistence provided by LCDS, but without the exorbitant licensing fee!

The save() and deleteRecord() methods are made available through the new IUpdatableHibernateProxy interface. Generally, these would delegate work back to the HibernateUpdater class. Examples of this implementation are shown later.

This approach saves the process of having to write individual update services for each entity (which, often requires several methods for each field. Painful!)

Eg:

// Actionscript:
[Managed]
public class Author extends BaseEntity {
    public var id : int;
    public var name : String;
    public var age : int;
}
public class BaseEntity extends HibernateBean {
    public function save(responder:IResponder = null) : AsyncToken
    {
        return HibernateUpdater.save(this,responder);
    }
    public function deleteRecord(responder:IResponder=null) : AsyncToken
    {
        return HibernateUpdater.deleteRecord(this);
    }
}

From this, Author, and all other subclasses of BaseEntity inherit a save method (which handles both creates and updates of entities) and delete method.

Note, that should you wish to keep persistence methods out of your entity classes, the following is also valid:

[Managed]
public class Author implements IHibernateProxy {
    public var id : int;
    public var name : String;
    public var age : int;
    // IHibernateProxy impl. Excluded...
}

public class SomePM {
    public function updateAuthor(author:Author):void
    {
        HibernateUpdater.update(author);
    }
    // Or, for that matter...
    public function updateAnyEntity(entity:IHibernateProxy):void
    {
        HibernateUpdater.update(entity);
    }
}

Or, if you prefer a more dependency injection friendly implementation:

public class SomePM {
    [Inject] // Actual injection depends on your DI framework of choice.
    public var hibernateUpdater:IHibernateUpdater;

    public function updateAuthor(author:Author):void
    {
        hibernateUpdater.update(author);
    }
}

(Note, this would also work within the Author class itself, should you prefer)

The possibilities for implementation are pretty open, and not overly prescriptive from the dpHibernate framework. The only requirements in terms of your entity classes to facilitate persistence are that they are tagged [Managed] (or implement IManaged), and implement IHibernateProxy.

Nested properties and collections

Both nested properties and changes to collections are supported.

Eg:

Nested properties

public class SomePM {
    public function doSomeWork(book:Book):void
    {
        book.author.name=”newName”;
        book.save();
    }
}

Collections

public class SomePM {
    public function doSomeWork(author:Author,book:Book):void
    {
        author.books.addItem(book);
        author.save();
    }
}

A combination of both

public class SomePM {
    public function doSomeWork(author:Author,book:Book):void
    {
        author.books.addItem(book);
        book.title=”This is the new title”;
        author.save(); // Also persists the change to book.title,
        // as it's part of the author.books collection.
    }
}

Efficient .save()’s

When calling save() on an entity, the actual entity itself is not passed across to the update service. For complex entity trees with collections and nested hierarchies, serialization within the Flash player can be painfully slow.

Eg, consider the following common example:

[Managed]
public class Author extends BaseEntity {
    public var id : int;
    public var name : String;
    public var age : int;
    public var books : ArrayCollection;
}
[Managed]
public class Book extends BaseEntity {
    public var title : String;
    public var author : Author;
}

The Parent entity – Author, contains a list of children entities – books, each of which contains a reference back to it’s parent. These circular references are commonplace, and required in many scenarios by Hibernate.

If we were to use standard AMF serialization for this, the nested tree can get very deep very quickly, depending on the number of Books an Author has written. Additionally, this cost is completely unnecessary if the only thing changed on the Author is it’s name.

Also, given that dpHibernate facilitates lazy loading, it’s quite possible that the property Author.books hasn’t even been populated yet at the time of serialization. Standard AMF serialization would trigger this loading unnecessarily.

Instead, only a list of changes that have occurred to the entity are passed along. This keeps the serialization process light, and quick. Nested properties & collections are handled, and circular references like the one described above are handled efficiently, ensuring that each entity is processed only once.

Essentially, instead of sending through the entire updated entity, dpHibernate sends a collection of changes through to be processed by the server – i.e. :

  • Author record 123 : name changed from “Josh bloch” to “Josh Bloch”
  • Author record 123 : books collection now contains :
    • Book record 123
    • Book record 456
    • A new book record, tentatively identified as ABC
  • Book record 456 : title changed from “effective .net” to “Effective Java”
  • Book record ABC created.

These records are simple objects of primitive types, so serialize very quickly. Once on the server, they are ordered to ensure that dependencies are processed in the appropriate order. Ie, The change record for the creation of Book ABC is processed before it is added to the books collection of Author 123.

Considerations

The entity persistence code of dpHibernate is still new, so typical warnings about bugs apply. That said, dpHibernate is currently being used successfully within a large scale commercial project.

Also, currently these changes to dpHibernate require that your project is using Spring on the Java tier. This dependency will be removed shortly, however for this reason, the entity persistence code is kept separate from the core dpHibernate trunk.

Finally, there are performance implications which you must be careful of. However, these can be easily mitigated through use of new custom metatags, and avoiding state tracking on all entities by default. Fine tuning dpHibernate for performance is discussed in a later blog post.

Tagged

Implementing Paged Collections in dpHibernate

A colleague posted an interesting question regarding lazy loading, and I realized that it’s something that we could be doing better in dpHibernate.

Note:  If you’re not familiar with the dpHibernate project, it may to have a read of this overview post

The topic discussed here is currently only available on the changeMessaging branch of dpHibernate.  The code is available here:

http://dphibernate.googlecode.com/svn/branches/changemessaging

Overview of data paging in flex

The process of paging data is used where a large collection of information is returned to the client.  Instead of sending the entire collection (which can be expensive in terms of broadband and client processing time), data is paged across.

When a paginated collection is returned to flex, normally an ArrayCollection arrives at the client with the first n items populated, and proxies in place for the remainder of the collection.  By sending proxies in place of the actual collection members, the length of the array collection is still reported correctly, meaning that view components (such as the list & datagrid etc) display scroll bars correctly.

When a call is made to getItemAt() on an ArrayCollection that references a proxied (not yet loaded) item, the following occurs:

  • Trigger a load to a remote service to load the requested item asynchronously
  • Throw an ItemPendingError
  • When the load request completes, replace the proxy in the array collection at the requested index with the newly loaded item.

View components in the flex framework are smart enough to only request the items that need to be displayed.

If a collection of 1000 items is returned to the client and displayed in a list component which is high enough to display 10 items, the first 10 will be retrieved.  As the user scrolls around in the List component, items are loaded non-sequentially as required.  Eg.,  If a user scrolls down to the 200th item, items 200 – 210 are loaded, though items 11 – 199 are skipped, as these are not required to be displayed.

dpHibernate

Previously, dpHibernate had lazy loading of collections, but no support for paging large collections.

If an entity declares a property whose value is a collection, and the value has not yet been loaded from the database at serialization time, it’s sent to the flex client as a collection of uninitialized dpHibernate proxies. This allows that on the flex client when looking at the collection for the first time, the length is reported correctly, even though none of the data has yet been loaded.

When the flex client accesses the property, currently the entire collection is loaded. This works fine for a collection with 10 items, but causes big problems if there’s 1000.

What would be better is to page the data down in the same way that LCDS does it – ie, return the proxies, but only load the members required to show on screen.

Implementation

Let’s step through how this works.

First of all, you need to enable paging. The new paging of collections in dpHibernate is disabled by default. To turn it on, set a page size in the hibernateSerializer bean in the spring config, as follows:

<bean id="hibernateSerializerBean"
class="net.digitalprimates.persistence.translators.hibernate.HibernateSerializer" scope="prototype">
    <property name="pageSize" value="3"/>
</bean>

When a collection is being serialized with paging enabled, the returned collection contains a mixture of the real instances of the collections members, and special lightweight proxies to the remainder of the collections members.

These proxies are instances of the entity class, but with none of it’s properties populated except for the proxyKey, and proxyInitialized set to false.

ArrayCollection and IList

ArrayCollections are one of the few instances of composition within the flex framework. ArrayColellections work by managing an internal IList which contians it’s members. By default, this is an instance of an ArrayList, however we can modify the behaviour by passing in a different implementation – in our case, one that facilitates lazy loading.

ArrayCollection’s methods such as getItemAt() (which is used by the DataGrid, and other components typically associated with lazy loading) are delegated down to the internal IList method. It’s here that the framework expects us to throw the ItemPendingError if the item we’re after isn’t held locally.

In order to get our lazy loading going, we need to augment the behaviour of this list to detect our proxy objects, load the item, and throw the ItemPendingError. DpHibernate uses a class called ManagedArrayList to facilitate this.

When the results of a remote call are returned, they’re examined to see if there’s an array collection there, and – if so – if that array collection has been paged. In that case, we swap out the default ArrayList with an instance of the ManagedArrayList:

private static function manageArrayCollection(collection:ArrayCollection,ro:IHibernateRPC):void
{
    // Trimmed..
    if (isPagedCollection)
    {
        var managedArrayList:ManagedArrayList = new ManagedArrayList(collection.source);
        collection.list = managedArrayList;
    }
}

Now, inside our ManagedArrayList, we need to detect requests for proxied data:

override public function getItemAt(index:int, prefetch:int=0) : Object
{
    var result : Object = super.getItemAt(index,prefetch);
    if (result is IHibernateProxy && IHibernateProxy(result).proxyInitialized == false)
    {
        handleRemoteItem(IHibernateProxy(result),index,prefetch);
    }
    return result;
}
private function handleRemoteItem(proxy:IHibernateProxy,index:int,prefetch:int):void
{
    var remoteService : IHibernateRPC = HibernateManaged.getIHibernateRPCForBean( proxy );
    var token : AsyncToken = remoteService.loadProxy(proxy.proxyKey,proxy);
    token.addResponder(new Responder(onPendingItemLoaded,onFault));
    var itemPendingError : ItemPendingError = new ItemPendingError("Item is pending");
    var pendingItem:PendingItem = new PendingItem(itemPendingError,index);
    pendingItems[token] = pendingItem;
    throw itemPendingError;
}

When a call is made to getItemAt(), we check to see if it’s an uninitialised IHibernateProxy instance. If so, control is passed off to handleRemoteItem().

Loading data from the server

dpHibernate uses an extension of the RemoteObject class called HibernateRemoteObject.  Objects which arrive on the client as the result of a call to a method on a HibernateRemoteObjectA get “managed”.  Among the tasks performed when “managing” an object, dpHibernate stores a reference to the HibernateRemoteObject instance from which the remote object arrived.  This allows us to get a reference back to the server from the remote object.

A reference to this HibernateRemoteObject is retrieved by calling:

var remoteService : IHibernateRPC = HibernateManaged.getIHibernateRPCForBean( proxy );

Using this reference, a call is issued to the server to load the real value of the proxy, and an ItemPendingError is thrown.

ItemPendingError

The ItemPendingError is not a dpHibernate specific concept – instead, it’s provided by the flex framework for classes to provide support for paginated & remote data.  Some flex framework components already provide support for the ItemPendingError out of the box – such as the List control and the Datagrid control.

You’ll notice that the thrown error is stored along with other details of the call. This is because other classes which catch the ItemPendingError can assign IResponder(s) to get notified when the item has been loaded. By storing the error, we keep reference to this list of responders, and can invoke them accordingly:

private function onPendingItemLoaded(data:Object):void
{
    var resultEvent:ResultEvent = ResultEvent(data);
    var token:AsyncToken = resultEvent.token;
    var pendingItem : PendingItem = pendingItems[token];
    var result:Object = resultEvent.result;
    this.setItemAt(result,pendingItem.index);
    for each ( var responder : IResponder in pendingItem.error.responders )
    {
        responder.result(data);
    }
    delete pendingItems[token]
}

When the item is loaded from the server, the proxy in the list is replaced at the appropriate index. Then, all other responders are invoked so they can take any action necessary.

Tagged

DpHibernate – An Overview

I’m going to start posting a series of articles that discuss some of the work I’ve been doing recently on dpHibernate.

I’m order to prevent repeating the basics of how dpHibernate works in each blog, here’s a little primer on the subject.

Project

dpHibernate is a BlazeDS adapter to provide support for Hibernate entities in actionscript. It’s open source, and the code is available from http://dphibernate.googlecode.com.  Many of the topics discussed on this blog specifically target the “changeMessaging” branch, which at the time of writing has not been merged back into the trunk.  The branch is available for checking out here:

http://dphibernate.googlecode.com/svn/branches/changemessaging

Lazy Loading

dpHibernate’s initial goal was to provide an adapter which handles serialization of a Hibernate object effectively. Eg: Imagine the following structure:

[Managed]
public class Author extends BaseEntity {
    public var id : int;
    public var name : String;
    public var age : int;
    public var publisher : Publisher;
    public var books : ArrayCollection;
}
[Managed]
public class Book extends BaseEntity {
    public var title : String;
    public var author : Author;
}
[Managed]
public class Publisher extends BaseEntity
{
    public var authors : ArrayCollection;
    public var books : ArrayCollection;
}

If a service is written returning a Book object from hibernate to the flex client, it’s possible that a LazyLoading exception is thrown when serializing the author property. This is because the entity is lazily loaded, and has not yet been retrieved from the database.

While one possible solution here is to load the author during serialization, this also requires loading the Author.publisher property, and the Author.books() collection, which in turn will load many more books etc. This approach can quickly becomes too expensive and bandwidth-heavy to use in a real world scenario.

Facilitating Lazy Loading with the IHibernateProxy

Instead of serializing these entities, dpHibernate sends down a proxy in their place. If and when the flex client accesses the property represented by the proxy, then that entity is retrieved from the server. Again, only the primitive values of the returned entity are serialized and sent across to the flex client. Ie., when reading Book.author() for the first time, the Author object is retrieved from the server, however it’s publisher property is represented by a proxy until such time as it is required.

Similarly, the property Author.books() is sent as a collection of proxies until such time as they are accessed. Note that because a proxy exists for every entity within the collection, attributes such as the length of the collection are still reported correctly.

In order to facilitate this lazy loading, all entity classes are required to either subclass HibernateBean, or implement IHIbernateProxy, which declares two properties:

public interface IHibernateProxy
{
    function get proxyKey():Object;
    function set proxyKey( value:Object ):void;

    function get proxyInitialized():Boolean;
    function set proxyInitialized( value:Boolean ):void;
}

Normally, the developer doesn’t access or modify these properties directly – instead they are there to facilitate the lazy loading process.

Specifics of how the lazy loading works are beyond the scope of this tutorial, but will be discussed in a later blog post.

Entity Persistence

dpHibernate provides functionality for persisting entities without having to write update services for each entity, through a simple save() method of the IUpdateableHibernateProxy interface:

public interface IUpdatableHibernateProxy extends IHibernateProxy
{
    function save(responder:IResponder=null) : AsyncToken;
    function deleteRecord(responder:IResponder=null) : AsyncToken;
}

dpHibernate provides support for creating, deleting and updating entities, including support for nested entities and collections.

Eg:

public class SomePM {
    public function doSomeWork(book:Book):void
    {
        book.author.name=”newName”;
        book.save();
    }
}

The entity persistence features are discussed in detail in an upcoming blog.

Further reading

That’s the broad overview of dpHibernate.

Other, more detailed blogs cover off:

Tagged

Why I think Silverlight has an edge…

In the Silverlight vs Flex debates, I’ve always been staunchly located on the Flex side of the fence.

But, as much as it pains me to say it, it’s beginning to dawn on me that the dirty ol’ boys in the Microsoft labcoats may just have the leading edge.

And, it’s not about browser penetration, or hi-def video, or 3D capabilities, or swanky new sound API’s.

It’s about language.

If you wanna compare these two frameworks, feature-by-feature, then as it stands, Flex wins out — every time.  But what people tend to miss (IMHO) is that we’re comparing frameworks, and not languages.

Do a comparison of Actionscript to .NET, and it’s a whole different kettle of fish.

Comparatively, shipping a new release of a framework with additional features takes much less time than adding features to your language.

In the time span between Alpha and Beta 1 of Silverlight, MS added a bucket load of features to their (somewhat limited) framework.  Beta 1 to Beta 2 saw lots more of the same.  Add to that the development community who will throw their collective weights behind the platform, and you’ll see real traction.

Does the Silverlight UI framework suck?  Maybe.  But it doesn’t matter.  If it’s really that bad, it won’t take long for the development community to provide one that rocks.

We see the same thing every day in the Flex community.  Hate Cairngorm?  Meet PureMVC / Mate.  Not a fan of <some 3d API>, not a problem — we’ve got 3 or 4 alternatives waiting just around the corner.

But — all of these frameworks share the same lowest common denominator — the Actionscript language.

And, it’s a little embarrassing to tell my .NET mates that mid 2009 the Flex community is getting support for typed arrays.  (Woot!)

I might be wrong, I’ve had limited exposure to Silverlight, but from what I understand the language is boasting some pretty impressive .NET features…

  • Typed Arrays
  • Generics
  • A decent reflection API
  • Dynamic Compilation
  • Abstract classes
  • Threading
  • LINQ / Lamba expressions
  • All sorts of C# 3.0 / 3.5 goodness!

Fire up Silverlight, and you’ll get all these things out of the box.  Today.  Right now.

For that matter, if you don’t like the language, you can write your own!  (IronPython, IronRuby)

And, by the time that Flex 4 and our typed arrays make a release, you can expect that C# 4.0 & VB10 will be boasting some funky new features in early preview.

Sure, Flex is an extremely powerful framework…today….comparatively.

But .NET is an extremely powerful language.  And where there’s a language, there’s developers.  And, where’s the developers, there’s eager minds….filling gaps in markets, plugging holes, and pushing boundaries.

Don’t get me wrong.  I think that Adobe are kicking ass with Flex.  In fact, had they not done such a good job, Silverlight probably wouldn’t be the contender it is.

And — come to think of it — Adobe are doing one helluva job in including the development community in guiding where the framework is headed.

So maybe it’s out fault.  Hell – maybe, it’s just me.  Maybe the community really does want a better designer / developer workflow over and above the ability to mark a method as abstract.

But I worry that while we’re getting swanky new ways of integrating designers and developers, the Microsoft team are giving their developers ways to achieve more powerful products with less code.

And, if Paris Hilton has taught us anything, it’s that looks can only get you so far in this world!

I just hope I haven’t backed the wrong horse in this race!

Casting string to boolean … A little quirky….

I just stumbled across a little type conversion quirk within Flex. I haven’t tested this in-depth, so I may yet be proven wrong.

However….check this out:

var someVal:string = “true”;
var bool:Boolean;
bool = someVal as Boolean; // bool == false;
bool = someVal; // bool == true;

If you try to explicitly cast a string to Boolean, the casting appears to fail silently, leaving the Boolean with its default value of false.

However, if you leave it to the runtime to convert, the conversion works fine.

Ya learn something new every day!

Mock Webservice in AS3

An important part of a good test suite is repeatability, and independance from external changes. Therefore, if your method loads data from an external source, that’s a real testing no-no.

However, using the features of dynamic classes in AS3 we can whip up a mock webservice which gives us a guaranteed result, every time.

Here’s the class:

package com.martypitt.testing.mockObjects
{
    import flash.utils.Dictionary;
    import flash.utils.flash_proxy;

    import mx.core.Application;
    import mx.core.mx_internal;
    import mx.messaging.messages.AsyncMessage;
    import mx.messaging.messages.IMessage;
    import mx.rpc.AbstractOperation;
    import mx.rpc.AsyncToken;
    import mx.rpc.events.ResultEvent;
    import mx.rpc.soap.WebService;

    use namespace flash_proxy;
    use namespace mx_internal;

    public dynamic class MockWebService extends WebService
    {

        /** The default response is returned if a call is made to a method that has not been explicitly
         * set using setResponse() */
        private var _defaultResult:Object;

        /** Determines bevahiour if a call is made to a method where the response has not been explicity set.
         * If true, an error is thrown.
         * If false (default) the defaultResponse is returned.
         * */
        private var _throwErrorIfResultNotSet:Boolean = false;

        private var _resultDictionary:Dictionary = new Dictionary();

        public function get defaultResult():Object {
            return _defaultResult;
        }
        public function set defaultResult(value:Object):void {
            _defaultResult = value;
        }

        /** responseDictionary holds a list of predefined methods and their associated responses.
         * */
        protected function get resultDictionary():Dictionary {
            return _resultDictionary;
        }
        protected function set resultDictionary(value:Dictionary):void {
            _resultDictionary = value;
        }
        public function get throwErrorIfResultNotSet():Boolean {
            return _throwErrorIfResultNotSet;
        }
        public function set throwErrorIfResultNotSet(value:Boolean):void {
            _throwErrorIfResultNotSet = value;
        }

        public function MockWebService(destination:String=null, rootURL:String=null)
        {
            super(destination, rootURL);
        }

        /** callProperty is called by the Flex / flash framework when something tries to access
         * a method or property of a dynamic object which has not been defined in code.
         * Here we override the default behaviour to return the correct response.
         * */
        override flash_proxy function callProperty(name:*, ... args:Array):*
        {
            var response:Object;
            var methodName:String = getLocalName(name);

            switch (true) {
                case (_resultDictionary[methodName] == null && throwErrorIfResultNotSet) :
                    throw new Error(String(methodName) + " does not have an appropriate result set.");

                case (_resultDictionary[methodName] == null && !throwErrorIfResultNotSet) :
                    response = defaultResult;
                    break;

                case (_resultDictionary[methodName] != null) :
                    response = _resultDictionary[methodName]
                    break;

                default :
                    throw new Error("Unhandled switch case scenario in MockWebService");
            }

            var message:IMessage = new AsyncMessage()
            var token:AsyncToken = new AsyncToken(message)

            // We want to return the Async token now (just like a normal webservice would)
            // but we get the app to dispatch the ResultEvent on the next frame

            // It's important that the result event is dispatched from the operation itself.
            var operation:AbstractOperation = super.getOperation(methodName);
            Application.application.callLater(operation.dispatchEvent,[ResultEvent.createEvent(response,token,message)]);
            return token;
        }

        public function setResult(methodName:String,responseValue:Object):void {
            _resultDictionary[methodName] = responseValue;
        }

    }
}

Nothing overly swanky, but all the magic happens courtesy of this line :
override flash_proxy function callProperty(name:*, ... args:Array):*

This method gets invoked whenever you call a method on the class which has not been defined in code. We catch the call, and generate an Async token that makes the caller think that we’re busily off chatting to our webserver.

The other key line is this:
Application.application.callLater(operation.dispatchEvent,[ResultEvent.createEvent(response,token,message)]);

In essence, we’re just dispatching a result event here. But, because our method is called syncronously, and webservices behave asyncronously, it’s important that we dispatch the event on the next frame. Hence Application.application.callLater.

Also, the result event must come from the operation itself, not our mock service, so that whoever has called this method gets notified of the result event, just like they would if it were a normal webservice.

So, with all that done, we simply set up the webservice, and invoke it:


var result:XML = new XML();
var ws:MockWebService = new MockWebService();
ws.setResult("callMyRemoteMethod",result)
someClass.webservice = ws;

It’s important (and good design practice) that you expose the webservice on your class as property that can be modified at runtime.

That’s pretty much it.

Questions and comments welcomed.

Marty

Tagged , ,

Custom Metatags and slicker unit tests in Flex

I’m a fan of unit tests. And, although I probably wouldn’t blazen it across my chest like some, I am sold of the benefits.

However, coming from .NET, I miss quite a bit of the elegance present in NUnit when working with FlexUnit.

Most specifically, the setup of a test suite is kinda clunky.

Normally, you have several classes of unit tests, each which have a static suite() method, returning a test suite comprising the unit tests in that class.

Check out the following example:



 public static function suite():TestSuite {

    	var ts:TestSuite = new TestSuite();	   	ts.addTest( new MyTestClass("testMethodA") );

    	ts.addTest( new MyTestClass("testMethodB") );

    	ts.addTest( new MyTestClass("testMethodC") );

    	ts.addTest( new MyTestClass("testMethodD") );

    	return ts;

 }

As you can appreciate, it doesn’t take long for this to get long and clunky. Also, maintanence is a pain in the butt — adding tests don’t get run if you forget to add it in the Suite method, changing names causes RTE, etc etc etc.

In NUnit (and, presumably JUnit), you just decorate a class with [TestFixture], and a method with [Test], and NUnit takes care of the rest using that groovy cat, Reflection.

Luckily for us, Flex gives us the ability to tell the compiler to retain custom metatags in Flex 3. This means we can achieve similar functionailty — at least at the method level.

The first step is to set the compiler option. In Flex Builder 3, right click your project, hop into Flex Compiler, and add this to the list of compiler options:

-keep-as3-metadata+=Test

Then, using flash.utils.describeType() we can find any methods within a class that are decoared with our [Test] method.

The following method examines a class, and returns a TestSuite which contains a test for each decorated method.

        /**

         * Generates a test suite with all the methods in a class decorated with [Test] metadata

         * @param clazz

         * @return

         *

         */

        public static function fromClass(clazz:Class):TestSuite {

            var suite:TestSuite = new TestSuite();

            var testMethodNames : XMLList = describeType(clazz).method.(metadata.(@name==”Test”)).@name

            for each (var node:XML in testMethods) {

                    var methodName:String = node.value()

                    var test:Test = new clazz(methodName);

                    suite.addTest(test);

            }

            return suite;

        }

Personally, I chose to add this to the TestSuite class in FlexUnit, though you may prefer a seperate util class.

Now, getting all the tests for a class is as simple as:

var suite:TestSuite = TestSuite.forClass(myClass);

Much more readable!

Comments welcomed.

Marty

Update : I modified the disvoery method to use the E4X expression suggested by Theo. I must’ve been having a brain-fart at the time, as I’m a huge fan of the E4X syntax. Nice spotting Theo!

Tagged , ,