Archive for November, 2007

IResponder and Cairngorm

Friday, November 23rd, 2007

My original post on Cairngorm and IResponder had accidentally been deleted while updating my moderations queue, and many of you have contacted me stating that the post is no longer available so I will re-iterate what I mentioned in that post.

For some time now I have been entertaining the notion of abstracting IResponder implementations from Command classes into separate, discreet classes which are intended to handle asynchronous service invocation responses. There has been some talk in the Cairngorm community recently regarding Cairngorm Commands and IResponder implementations so I thought I would share my thoughts on the subject.

Typically most Cairngorm Events are handled by an associated Command. The Command handles the Event by updating a model on the ModelLocator, and / or instantiating a Business Delegate to manage invoking a middle-tier service.

At this point one could argue that the Command has finished doing it’s job - handling the Event. Let’s clarify by taking a look at a formal definition of the Command Pattern:

“The Command pattern is a design pattern in which objects are used to represent actions. A command object encapsulates an action and its parameters.”

From this we can deduce (in the context of a Cairngorm Event) that the Event is the “action” and the Command is the object which encapsulates the handling of the Event (action). The actual handling of the Service response could be considered a separate concern which is outside of the direct concern of the Event and Command, thus requiring an additional object to handle the service response.

However for many developers it is (by design) typical to simply have the Command implement IResponder and also handle the response from the service in addition to the actual Event. This makes sense from a convenience perspective, but not necessarily from a design perspective.

What I have been experimenting with is pretty simple and straightforward. It involves having a completely separate object implement IResponder and handle the service response directly.

Consider the following example in which a specific use-case requires an account log in. The following classes would be required: LoginEvent, LoginCommand, LoginResponder and LoginDelegate. Utilizing a separate class as the responder is very simple and straightforward and would be implemented as follows:

package events
{
  import com.adobe.cairngorm.events.CairngormEvent;
  import vo.LoginVO;

  public class LoginEvent extends CairngormEvent
  {    
    public static const LOGIN_EVENT:String="LoginEvent";
    public var vo:LoginVO;

    public function LoginEvent(vo:LoginVO)
    {
       super ( LOGIN_EVENT );
       this.vo = vo;
    }
  }
}

So far nothing different here, the above Event is just like any other CairngormEvent. Now let’s take a look at the Command implementation.

package commands
{
  import com.adobe.cairngorm.commands.ICommand;
  import com.adobe.cairngorm.events.CairngormEvent;
  import events.LoginEvent;

  public class LoginCommand implements ICommand
  {
    public function execute(event:CairngormEvent)
    {
      var evt:LoginEvent = event as LoginEvent;
      var re:IResponder = new LoginResponder();

      var delegate:LoginDelegate = new LoginDelegate(re);
      delegate.login(evt.vo.username, evt.vo.password);
    }
  }
}

Based on the above example, the only method which must be implemented is execute(), as defined by ICommand. The body of the execute() implementation instantiates an instance of LoginResponder and LoginDelegate, the LoginResponder instance is passed to the LoginDelegate as the IResponder instance.

As can be seen in the following example, the Business Delegate implementation is the same as any other typical Cairngorm Delegate:

package business
{
  import com.adobe.cairngorm.business.ServiceLocator;
  import mx.rpc.AsyncToken;
  import mx.rpc.IResponder;
  import mx.rpc.http.HTTPService;
  import vo.LoginVO;

  public class LoginDelegate
  {
    private var responder:IResponder;
    private var service:HTTPService;

    public function LoginDelegate(responder:IResponder)
    {
      this.responder = responder;
     
      var sl:ServiceLocator = ServiceLocator.getInstance();
      service = sl.getHTTPService( Services.LOGIN_SERVICE );
    }
   
    public function Login(vo:LoginVO) : void
    {
       var call:AsyncToken=service.send(vo.username,vo.password);
       call.addResponder( responder );
    }
  }
}

The IResponder implementation would be as follows:

package responders
{
  import mx.rpc.IResponder;

  public class LoginResponder implements IResponder
  {
    public function result(data:Object)
    {
      // result implementation…
    }

    public function fault(info:Object)
    {
      // fault implementation…
    }
  }
}

That’s pretty much it. Clean, simple, and yes, more code, however this design supports clean separation of concerns and promotes encapsulation and code reusability.

At the end of the day it really comes down to personal preference. For me, I always prefer to have more classes which encapsulate very specific tasks and responsibilities. As long as you have a clear and concise, but most of all, consistent design you usually can’t go wrong.

Cairngen 2.1

Monday, November 19th, 2007

Last week Cairngen 2.0 was released, and judging by my Firestats totals there has been on average, roughly 250 downloads per day.

Based on the feedback I have received so far, the single most requested feature users are asking for is an additional target which will generate multiple Event, Command and Business Delegate classes (Sequences) simultaneously.

Ironically, prior to the Cairngen 2.0 release one of the contributors (I don’t remember who, so if you read this please leave a comment and take credit where it is due) added a few additional tasks which did just this.

So after a bit of fine tuning and testing I have added three new targets which are as follows:

  • create-multiple-sequences-include-delegates
    Generates multiple Event, Command and Business Delegate classes simultaneously. To do so simply assign a comma delimited list of Sequence names to the sequence.name property in project.properties.
    (e.g. sequence.name=Login, Logout, RegisterUser, UnregisterUser)
  • create-multiple-sequences-exclude-delegates
    Generates multiple Event and Command classes simultaneously. To do so simply assign a comma delimited list of Sequence names to the sequence.name property in project.properties.
    (e.g. sequence.name=Login, Logout, RegisterUser, UnregisterUser)
  • create-multiple-value-objects
    Generates multiple Value Object classes simultaneously. To do so simply assign a comma delimited list of VO names to the vo.name property in project.properties.
    (e.g. vo.name=Login, Logout, RegisterUser, UnregisterUser)
  • I have also updated the comments in both the project.properties file and the build.xml files, respectively.

    If you have any additional feature requests you would like to see added to Cairngen, or if you have already implemented these features. feel free to leave a comment or send me an email.

    Download Cairngen 2.1

    Cairngen 2.0

    Thursday, November 15th, 2007

    It has been awhile since the release of Cairngen 1.0, and the feedback I have received from the community has been very encouraging. I am happy to have provided a first-of-it’s-kind utility which allows developers to save time when building Flex applications on Adobe Cairngorm. Additionally, many of you have contacted me with some really cool new features that you have added, some of which are now available in this latest release.

    Objective
    The main objective of Cairngen 2.0 was to address 2 issues which were inherent to Cairngen 1.0. The first being that Event / Command mappings were not automated. In Cairngen 1.0 developers had the ability to generate sequences which consisted of an Event, Command and optional Business Delegate. And although this was very useful as it generated all of the required classes, handled upcasting events and instantiating Business Delegates, developers were still required to implement addCommand() in the FrontController manually. The second issue was that Event types were not generated as uppercase. Event types are static constants therefore they should always be uppercase. This is not required, however it is a best practice. Again developers could easily generate the required Event class but they would have to manually modify the event type to make it uppercase.

    These two issues were the main thing preventing Cairngen from full circle code generation and implementation. Cairngen 2.0 addresses these 2 issues by automating the process, thus allowing for even faster development of Cairngorm projects.

    So what’s new in Cairngen 2.0?

  • FrontController addCommand automation
    Event / Command mappings via the FrontController are now automated. When generating a sequence (Event, Command, Business Delegate) the FrontController will be modified to implement an additional addCommand for the Event and Command. This is achieved by a simple //todo comment which is uses as a token and replaced when sequences are generated.
  • Event TYPE
    Event type constants are now generated as upper case. Additionally the value of the event type is set to the fully qualified namespace of the event, thus preventing it from possible collisions with other Events.
  • User prompted before deleting
    You will now be prompted prior to deleting directories in Cairngen 2.0. You can override this by setting the new “prompt.on.delete” property to false
  • Class file copyright header
    Developers can add a specific copyright header for each class file generated. When specified the header will be added before the package definition.
  • Remote class VOs
    The ability to generate and register remote classes with a VO is now available
  • Logging
    Developers can toggle between logging the console output. This can be accomplished by setting the “log.output” property to true or false
  • What’s next?
    I don’t know, you tell me? If you have additional features you would like to see added to Cairngen, or if you have extended Cairngen to provide these features, feel free to leave a comment on this page. I am planning on adding some new features in the near future. One of which will be the ability to detect duplicate addCommands.

    I would like to thank the many developers who have contributed to the development of Cairngen 2.0. I am in the process of compiling a list of contributors, at which point I will update the release notes.

    Cairngen is licensed under the MIT License.

    Ant and Ant-contrib are licensed under The Apache Software License

    Download Cairngen 2.0

    Measuring code performance in ActionScript 3

    Saturday, November 3rd, 2007

    Adobe Flex 3 introduces the much needed, and highly welcomed Flex Profiler which allows Flex and AIR application to be thoroughly examined to measure code performance and determine potential so called “memory leaks” (not that such a thing exists - it’s called a programming error, but that’s a whole other subject in itself). Flex 3.0 provides a new profiling perspective which contains all of the tools one might expect from a high quality profiling utility. I highly recommend taking advantage of the profiler and utilizing it as a powerful addition to your Flex workflow.

    Even with all of the great features available in the Profiler I still find it useful to have the ability to monitor code performance in ActionScript, especially when determining the elapsed duration of service invocations. With this in mind I developed a simple API which allows developers to measure the performance of their code as it executes; such as loops, method invocations, service invocations and so forth.

    The Execution class provides an intuitive API (defined by IExecutable) from which the elapsed time of a code execution, as well as the total duration of a code execution can be measured. This can be accomplished in as little as 2 lines of code. The underlying implementation is simple and the higher level API makes it easy to use.

    Typically developers should utilize the Execution API as a development aid as it is intended for use in dev environments. All references should be removed prior to an actual prod release as there is no need to compile the code into your release swf.

    Below I have provided links to the Execution API resources as well as documentation which contains comprehensive use-case examples.

    Execution API
    IExecutable
    Execution