Context-aware Tasks

Posted in ActionScript on March 13th, 2011 by Mattes – 9 Comments

This article shows an useful way how to combine the Spicelib Task Framework with Parsley. This way you can access everything from the context during the execution of a Task:

“The Task Framework is a general abstraction for asynchronous operations. It allows nesting / grouping of Tasks in TaskGroup instances for concurrent or sequential execution” [source: Parsley Documentation]

One way to access the Context from within a Task would be to define it during the Parsley Configuration (Context). But this would mean, that the Task will not be removed until the context gets destroyed. Because a Task is only active during a limited time, this doesn’t make much sense.

Another approach would be, not to define the Task in the Context but passing in all the necessary dependencies within the constructor. Depending on the amount of required dependencies, the constructor can become quite big. Also Parsley features like Messaging are not directly supported anymore.

Solution

That’s why this solution utilizes the Dynamic Object feature of Parsley. It allows to add any instance to the Context during runtime and also removing it again, if not required anymore. For a Task this means that it needs to be added before the start() is called, and removed after the complete() has been triggered.

This adding/removing happens through the Context interface of Parsley. It should happen automatically in the Task to reduce the amount of code to write. In order to not have to pass the Context to each Task it could just be set once in the parent TaskGroup. The child Task then accesses it via the parent getter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class SequentialContextTaskGroup extends
    SequentialTaskGroup implements IContextProvider
{
    private var _context:Context;

    public function SequentialContextTaskGroup(context:Context,
        name:String = null)
    {
        _context = context;
       
        super(name);
    }

    public function get context():Context
    {
        return _context;
    }
}

And this is how the IContextProvider interface looks like:

1
2
3
4
public interface IContextProvider
{
    function get context():Context;
}

The following AbstractContextTask is then responsible for adding itself to the Context as soon as it is started. It also removes itself as soon as the complete(), cancel() or skip() has been called. Furthermore it provides a doStartContext() method (read more in the next paragraph).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class AbstractContextTask extends Task
{
    private var _dynamicObject:DynamicObject;
   
    protected override function doStart():void
    {
        _dynamicObject = IContextProvider(parent)
            .context.addDynamicObject(this);

        doStartContext();
        super.doStart();
    }

    protected function doStartContext():void
    {
        /* base implementation does nothing */
    }

    protected override function doCancel():void
    {
        cleanContext();
        super.doCancel();
    }

    protected override function doSkip():void
    {
        cleanContext();
        super.doSkip();
    }

    protected override function complete():Boolean
    {
        cleanContext();
        return super.complete();
    }

    private function cleanContext():void
    {
        _dynamicObject.remove();
    }
}

The following class is a concrete implementation of AbstractContextTask. That’s why it gets the HintComponent injected (line 4). Please also note that this Task overrides the method doStartContext() (line 13). This way we ensure that the class already has been added to the Context.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ShowHintTask extends AbstractContextTask
{
    [Inject]
    public var hint:HintComponent;
   
    private var type:HintType;

    public function ShowHintTask(type:HintType)
    {
        this.type = type;
    }
       
    protected override function doStartContext():void
    {
        hint.showHint(type);
       
        complete();
    }
}

The following code shows how everything can be glued together. Note, that you don’t have to pass the Context to each task.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class TaskController
{
    [Inject]
    public var context:Context;
   
    [Init]
    public function initialize():void
    {
        var taskGroup:SequentialContextTaskGroup
            = new SequentialContextTaskGroup(context);

        taskGroup.addTask(new ShowHintTask(HintType.ATTENTION));
        taskGroup.addTask(new PointToTask(new Point(3, 5)));
        // add more tasks here...

        taskGroup.start();
    }
}

Summary

This approach of Context-aware Tasks ensures that you don’t have a lot of Tasks at the same time in the Context. The adding and removing from the Context happens in an encapsulated class. The Task itself can directly access injected objects during execution time.

Links

Label validation with FlexUnit

Posted in ActionScript on January 18th, 2011 by Mattes – 2 Comments

While working in interdisciplinary teams where graphics are produced by artists and the code comes from the developers, a solid designer-developer work-flow is crucial. At my current project team at wooga we already established a very good work-flow. The artists can produce graphics and see them in the running application after committing them. Therefore we use SVN and the Hudson integration server.

The problem

In our project we use SWC asset libraries to have a compile time check and strong typed access to all our graphics. To add logic to MovieClip frames you could either put the code directly on the timeline or the artist defines labels which are then utilized from the code. In order to keep the view separated from the code you should always use the label approach. But this is also risky if the artist accidentally deletes or renames a label. The code would then behave unexpectedly without knowing it. The only way to see the problem is to start the application and test all the MovieClip logic.

The first approach

To protect the labels from unintended changes, our first approach was to check their existence wherever we used them in code. This means we had to provide a separate Vector that contained all the expected labels.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private static var labels:Vector.<String> = new Vector.<String>();
private var view:IconView;

public function IconMediator(view:IconView):void
{
    initializeLabels();
    assertLabelsExist(view);
}

private function initializeLabels():void
{
    if (labels.length == 0)
        labels.push(IconState.ON, IconState.OFF);
}

private function assertLabelsExist(view:ButtonRounded):void
{
    var requiredMatchesRemaining:int = labels.length;
   
    for each (var requiredLabel:String in labels)
    {
        for each (var label:FrameLabel in view.currentLabels)
        {
            if (requiredLabel == label.name)
                requiredMatchesRemaining--;
        }
    }
   
    if (requiredMatchesRemaining != 0)
        throw new IllegalArgumentError(
            'IconView requires all labels: ' + labels);
}

Beside this we defined the labels itself in an enumeration class to provide strong typed access.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class IconState
{
    public static const ON:IconState = new IconState("on");
    public static const OFF:IconState = new IconState("off");
   
    private var type:String;

    public function IconState(type:String)
    {
        this.type = type;
    }

    public function toString():String
    {
        return type;
    }
}

This approach leads to three main problems:

  1. Depending on when the validation is executed in code, it could still happen that you don’t see the problems immediately
  2. We create a lot of code that is only necessary for validation but not for the application itself
  3. We create redundancy because we have to maintain the Vector of expected labels and the enumeration class (IconState). When changing labels it is very likely that you forget to update the Vector.

The solution

Thats why we came up with a different approach. We moved the validation into the unit tests. Now the code is separated but still executed because of our integration server (Hudson with FlexUnit support). The normal application code is now much slimmer and better readable. The artists/developers are automatically notified by mail if their changes break the tests.

To solve point 3 I wrote an assertion method that can reflect on enumeration classes and check all the defined labels on a certain MovieClip.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public function assertLabelEnum(target:MovieClip,
    enumClass:Class):void
{
    var classInfo:ClassInfo = ClassInfo.forClass(enumClass);
    var properties:Array = classInfo.getStaticProperties();
    var expectedLabel : String;
    var type:*;
    var labelCounter:int = 0;
       
    for each (var property : Property in properties)
    {
        type = property.getValue(enumClass);
               
        if (type is String)
            expectedLabel = String(type);
        else if (type is enumClass)
            type["toString"]();
        else
            continue;
           
        labelCounter++;
        expectedLabel = type["toString"]();
           
        assertLabel(expectedLabel, target);
    }
       
    assertEquals("Amount of expected labels differs from the
        amount of existing labels"
, labelCounter,
        target.currentLabels.length);
}

This method internally calls another assertion method assertLabel(). This method can also be used independently for testing specific labels without using enumeration classes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public function assertLabel(target:MovieClip,
    expectedLabel:String):void
{
    var found:Boolean = false;

    for each (var label:FrameLabel in target.currentLabels)
    {
        if (expectedLabel == label.name)
        {
            found = true;
            break;
        }
    }

    if (!found)
        fail("Expected label [" + expectedLabel + "] not
            found in "
+ target);
}

Note: I used the reflection library from spicelib to retrieve all the static members of the enumeration class. You can download the library here.

And this is how the test method would look like:

1
2
3
4
5
[Test]
public function test_icon_frame_labels():void
{
    assertLabelEnum(new IconView(), IconState);
}

Summary

We made very good experiences with this approach because unintended changes on the labels no longer lead to awkward behavior in the application itself. And of course the application code can focus on the main logic and is therefor better readable.

Strong typed constants

Posted in ActionScript on January 2nd, 2011 by Mattes – 7 Comments

Constants are commonly occurring in the ActionScript core classes. Typical examples are events (Event.COMPLETE) or general configurations (StageAlign.TOP_LEFT). These constants are typically of type String and grouped in one class.

If you want to set the align property of the Stage for example you have to know where to look up the different possible constants. This can be done by looking up the documentation or by guessing the potential class name (StageAlign). IDEs like FDT provide support for these constants by suggesting them in the auto completion.

However, the programmer is never enforced to use the existing constants and can assign any other string. This is error prone because the string is eventually misspelled. It is also annoying if you have to look up the documentation because your IDE doesn’t suggest them. If you use your own constants in an application or library then you are completely on your own.

Other programming languages like Java provide a special syntax for this problem: enum

1
public enum Direction {LEFT, RIGHT}

This enumerations can then be used strong typed in code. For example a function can define this as type in the signature. Assigning something else than one of the predefined constants (LEFT or RIGHT) would cause a compiler error:

1
2
3
public void applyDirection(Direction direction) {
    // use the enum here
}

The ActionScript language itself has no support for enumerations. But there is a solution: Instead of using constants of type String just use the type of the constants class itself.

1
2
3
4
5
public class Direction
{
    public static const LEFT:Direction = new Direction();
    public static const RIGHT:Direction = new Direction();
}

A function can then look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public function applyDirection(direction:Direction):void
{
    switch (direction)
    {
        case Direction.LEFT:
            // use direction here...
            break;
        case Direction.RIGHT:
            // use direction here...
            break;
        default:
            throw new IllegalOperationError(
                "Unsupported direction " + direction);
    }
}
1
applyDirection(Direction.LEFT);

You would still be able to create new instances of Direction and assign them. But the implementation of applyDirection() relies on the predefined constants. An error would be thrown if another instance would be assigned. Furthermore the user can see the different possible constants because he knows which specific type is required.

If you want to trace the Direction or if you want to store more information this is no problem, too:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Direction
{
    public static const LEFT:Direction = new Direction("left");
    public static const RIGHT:Direction = new Direction("right");
   
    private var direction:String;
   
    public function Direction(direction:String)
    {
        this.direction = direction;
    }

    public function toString():String
    {
        return direction;
    }
}

Right now, this approach is the only way to provide type save enumerations in ActionScript. You should always use them if you write third party libraries. Also in projects with multiple developers this makes sense.

Update 2011/03/13: In order to to restrict the enum to the predefined constants you could combine the declaration with a singleton enforcing approach. Just expect an instance of a nested class in the constructor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package
{
    public class Direction
    {
        public static const LEFT:Direction = new Direction(
            new EnumEnforcer(), "left");
        public static const RIGHT:Direction = new Direction(
            new EnumEnforcer(), "right");

        private var direction:String;
   
        public function Direction(enumEnforcer:EnumEnforcer,
            direction:String)
        {
            this.direction = direction;
        }

        public function toString():String
        {
            return direction;
        }
    }
}

class EnumEnforcer
{
}

Of course this is still not 100% save because you could just pass in null. In this case an error could be thrown. But this would happen at runtime only then.

Thanks to Thijs for pointing out this problem in the comments and Peter Höche for suggesting this solution.

Review: Logging with Trazzle

Posted in Libraries on November 14th, 2010 by Mattes – 1 Comment

A few weeks ago I discovered an ActionScript 3.0 Logger called Trazzle.

It’s available for Mac only and provides a well-arranged, beautiful logging output, a performance monitor, bitmap logging and much more. In order to use this logger, you need to install the Logger Client and include the SWC files within your project.

All source files are available on GitHub as well as a simple example.

Usage

I assume the author tried to build a logger that is very easy to use. Therefor he provides package level functions which allow fast access to the core features. The logger classes behind can also be used. But this should not be part of this post.

The first step is to initialize to logging framework:

1
zz_init(stage, "Logger app title");

Please note: The logging only works if you import the class TrazzleLogger. The reason why the demo application works: the StatusBar class holds a reference to TrazzleLogger. But normal logging will retrieve the reference only dynamically at runtime, so you have to take care of importing it on your own.

After initialization you can trigger the log messages. By default they will be displayed as plain white text. To make use of the different log levels you have to prepend one of the following characters:

1
2
3
4
5
6
7
8
log("normal");
log("d debug");
log("i info");
log("n notice");
log("w warning");
log("e error");
log("c critical");
log("f fatal");

This syntax is one of the main differences to other logging frameworks. Because of this convention it es very fast to use. You don’t have to retrieve a logger instance and define a strong typed log level. Unfortunately the drawback is, you have to know the convention and you are responsible to use it correctly as there is no compile time check.

You can also use the classical printf behavior which allows to define a string with placeholders that will be replaced at runtime. Again, in order to use this feature you have to make sure that the method printf is compiled into the application.

1
logf("There is a difference between %s and %s", "good", "evil");

Furthermore with the function zz_inspect(object) you should be able to see all the fields and values of an instance. For some reason I didn’t get it to work. Please comment below if you found a solution.

Filtering

In contrast to other logging frameworks it is not possible to configure the logging visibility for certain packages and log levels from within the flash client. Instead the configuration will completely take place in the Trazzle application by using the filters window. Here you can define and combine different rules. Excluding specific packages is not possible. You can save each filter set for later usage.

Performance Monitor

The performance monitor gives you a chronological sequence of the memory consumption and the frames per second (fps). It worked for me but I have not really tested it.

Conclusion

Using the trazzle logging framework will force you to use the Trazzle application which is available for OS X only. So if you work in larger teams you have to take into consideration that you can not exchange the logging appender easily.

What I think is a bit strange, is that you have to manually import the TrazzleLogger in order to use it via the package level functions. This makes it difficult to enable/disable the logging on different environments like on debug and release stages. Reading traces is also very exhausting because you have to read small grey text on a black background. And if you copy the text into another editor it is broken by the line numbers. The other log messages are better readable (see first image).

Apart from this cons you get an easy to use logger which has useful additional features like bitmap data output. With this feature I was able to easily find a bitmap that accidentally prevented clicks. What I especially like is the StackTrace which you can see for each log entry. Because the logger is very easy and fast to use you can eventually use him for some special cases only.

One final note: To see the line numbers you have to compile with the compiler flag “-verbose-stacktraces”.

Short-lived Commands with Parsley

Posted in ActionScript on October 31st, 2010 by Mattes – 4 Comments

This week we had to decide on a MVC Framework for our next game at Wooga. In the end we had to decide between Robotlegs and Parsley. Both of them had pros and cons which I will maybe explain at a later time.

One aspect we came across was the support of Short-lived Command Objects. These Commands hold no state and will be garbage collected after execution. In Robotlegs they are supported via the ICommandMap interface. Parsley also provides an implementation of this pattern called DynamicCommand. In contrast to Robotlegs, Parsley provides 4 different ways to build and configure a context:

  • MXML: DynamicCommand Tag. Only for Flex projects.
  • XML: DynamicCommand Node. No compiler check on types possible.
  • ActionScript: No way to configure dynamic Commands.
  • Configuration DSL: Programmatic configuration of Dynamic Commands.

Because our game should not use the Flex framework, the last option is our only choice if we want to have strongly typed Command mappings like in Robotlegs.

DynamicCommands via Configuration DSL

Because a documentation is not available for this case it was a bit tricky to find the solution (thanks for the hint, Jens). This was the first result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var contextBuilder:ContextBuilder = ContextBuilder.newSetup()
    .viewRoot(this)
    .newBuilder();

var targetDef:DynamicObjectDefinition = contextBuilder
    .objectDefinition()
        .forClass(CommandType)
            .asDynamicObject()
                .build();

DynamicCommandBuilder
    .newBuilder(targetDef)
        .builder
            .messageType(MessageType)
            .stateful(false)
        .build();

contextBuilder.config(ActionScriptConfig.forClass(MainConfig));
contextBuilder.build();

Note that you can not use the ActionScriptContexBuilder.build() notation anymore. Instead you have to configure the whole context via the DSL. In line 18, the actual configuration (MainConfig) which contains all object definitions is passed in.

Because this configuration is very hard to read and redundant if you want to map several Commands, I encapsulated the mapping to a separate class CommandMap. Now the configuration looks like this:

1
2
3
4
5
6
7
8
9
10
var contextBuilder:ContextBuilder = ContextBuilder.newSetup()
.viewRoot(this)
.newBuilder();

var commandMap:CommandMap = new CommandMap(contextBuilder);
commandMap.register(LoginCommand, LoginRequest);
commandMap.register(LogoutCommand, LogoutRequest);

contextBuilder.config(ActionScriptConfig.forClass(MainConfig));
contextBuilder.build();

Until now I found no way to map or un-map Commands after the context has been built. The only way would be to destroy the context they are registered in.

To get a better impression how short-lived commands are used in Parsley, I implemented a small example, which you can access on GitHub. The CommandMap class can be found here.

And this is how the login example looks like. Invalid credentials lead to an error pop up. Valid login works with “admin” and password “test“:

Summary

The Robotlegs implementation is very straight forward. Commands can be mapped and un-mapped at any time. This is not possible in Parsley. But you have other features that give maybe similar results (for example MessageInterceptors).

Because Parsley reflects on the types you can pass data directly to the execute method. This way, each concrete execute method can receive strong typed parameters (see line 9). No framework class has to be extended for custom Commands. This is how a command can look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class LogoutCommand
{
    [Inject]
    public var service:ISessionService;
   
    [MessageDispatcher]
    public var dispatcher:Function;
   
    public function execute(message:LogoutRequest) : ServiceRequest
    {
        return service.logout(message.sessionId);
    }
   
    public function result(success:Boolean) : void
    {
        dispatcher(new LogoutSuccess(success));
    }
}

I also like the native support of synchronous and asynchronous Commands in Parsley. No special configuration is necessary, because Parsley reflects on the return type of the execute() method (line 9, ServiceRequest).

Links:

Icon Badge for Windows

Posted in Air Icon Badge, Libraries on March 14th, 2010 by Mattes – 4 Comments

Until now the Air Icon Badge library implementation only supports the OS X dock icon. Nevertheless it is easy to extend the implementation for utilizing it as Windows system tray icon. In this article I will demonstrate how this could be realized.

Demo

Therefore I extended the existing example implementation. Just choose “Window Tray Icon” from the right panel for previewing the new icon.

And this is how it will look like on Windows XP (Windows Vista and 7 will look the same).

Implementation

The first class that I create is the SystemTrayIconBuilder (it must implement IconBuilder interface). This class is responsible for composing the system tray icon. It also sets the general icon size to 16 by 16 pixels.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class SystemTrayIconBuilder extends AbstractIconBuilder
implements IconBuilder
{
public override function createNewIcon(width : int,
height : int) : void
{
super.createNewIcon(16, 16);
}

public override function addBackground(
background : Bitmap) : void
{
background.width = background.height = 16;

container.addChild(background);
}

public override function addBadge(label : String) : void
{
var badge : TrayIconBadge = new TrayIconBadge();
badge.label.text = label;

container.addChild(badge);
}
}

Please note the the TrayIconBadge class used in this example (line 17) is a MovieClip designed and exported (swc) with the Flash IDE. I used a pixel font for better readability. Because of the small icon size the visible letter count is also limited.

The next step is to create a custom SystemTrayIconBadge which has to implement the IconBadge interface. To avoid redundancies I extend the DockIconBadge class and override the factory method “createIconBuilder()“.

1
2
3
4
5
6
7
public class SystemTrayIconBadge extends DockIconBadge
{
protected override function createIconBuilder() : IconBuilder
{
return new SystemTrayIconBuilder();
}
}

The last step is to build the CrossPlatformIconBadgeFactory which implements IconBadgeFactory. It is responsible for detecting the users operating system and returning the corresponding IconBadge. Again I extend the existing factory class to avoid redundancies:

1
2
3
4
5
6
7
8
9
10
11
public class CrossPlatformIconBadgeFactory extends
AirIconBadgeFactroy
{
public override function create() : IconBadge
{
if (NativeApplication.supportsSystemTrayIcon)
return new SystemTrayIconBadge();

return super.create();
}
}

Finally for using the new factory it has to be assigned to the AirIconBadge class.

1
2
AirIconBadge.factory = new CrossPlatformIconBadgeFactory();
AirIconBadge.label = "1";

Summary

As you can see, it is very little effort to add the windows system tray icon capability. You are free to (re)use this example. Binaries and sources can be downloaded from the google code project site.

Any comments will be appreciated.

Icon Badge Library for Air

Posted in Air Icon Badge, Libraries on February 8th, 2010 by Mattes – 8 Comments

Introduction

Adobe Air is often used to build feed readers or social media clients. This kind of applications can retrieve new data while they are running in the background. In that case it would be great to inform the user about the amount of new items. With OS X you can use the dock icon for that purpose. The Cocoa Framework allows to display a user defined text consistently on top of the application dock tile (icon). E.g. the screenshot at the right shows 2 unread mails in the inbox.

Native and emulated badge

Unfortunately the Air runtime allows no access to this native functionality. Thats why the idea for this library came up. It tries to emulate the native badge with the possibilities Air provides (see left image). Until now only the OS X badge is supported but a Windows implementation is possible, too. I will demonstrate the extensibility in one of the following blog posts.

Demo

If you have a Mac, you can download this Air application where the badge shows up on the real application icon. Running this application on windows will have no visual effect.

None Mac users can use the following demo that shows a preview of the dock icon:

You can browse the sources for this example on the google code repository.

Usage

To show the badge label you can use the static facade AirIconBadge. Internally it will create an IconBadge appropriate for the current operating system. Note: only one implementation for OS X is provided until now! Windows or Linux users won’t see a badge label.

With the static property label you can assign any string that should be displayed. Thats it.

1
AirIconBadge.label = "1";

If you assign an empty string or null, no badge will be displayed. To remove the current badge label you can also call the method clearLabel().

By default the biggest icon defined within the application descriptor will be loaded and shown. If no icon has been defined or the path is incorrect you must assign a customIcon in order to see the label. You can also assign a customIcon if you want to replace the default icon temporarily. Removing the customIcon will show up the default icon again.

1
AirIconBadge.customIcon = new CustomIconBitmap();

If neither of the icons could be loaded, no badge will be displayed. In this case an error event will be dispatched (UpdateErrorEvent). To get status information about the internals you can register for the InformationEvent. Both events will be dispatched by the IconBadge witch is statically stored within the AirIconBadge.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var iconBadge : IconBadge = AirIconBadge.iconBadge;
iconBadge.addEventListener(UpdateErrorEvent.UPDATE_ERROR,
handleError);
iconBadge.addEventListener(InformationEvent.INFORMATION,
handleInformation);

function handleError(event : UpdateErrorEvent) : void
{
    // do some error handling
}

function handleInformation(event : InformationEvent) : void
{
    trace(event.information.toString());
}

Download

All sources, binaries and examples are available for download under the MIT license.

Whats next

The documentation (especially the ASDocs) will be improved as well as the sources. If you have questions or feature requests, please let my know. The next blog posts will give you a deeper insight in the architecture and extensibility of this library.