FDT Template – Builder Pattern Helper

This FDT template is pretty much invaluable when it comes writing a Class that follows the Builder Pattern (for example, a Builder for a Fluent Constructor).

public function ${value}(value : ${type}) : ${enclosing_type}
{
	_${value} = value;
	return this;
}

Now you can hammer out all the public setter methods in a fraction of the time – if only we could hook into the QuickFix menu (CTRL+1) to create them straight from the fields! (hint, hint!)

Update I’ve opened a JIRA ticket requesting for a hook into the QuickFix menu; fingers crossed, eh? :)

Posted in ActionScript 3 | Leave a comment

ANT: This compilation unit did not have a factoryClass

A coworker of mine just asked me how to deal with this MXMLC error which was being thrown during her ANT script when using the FLEX 4 SDK.

This compilation unit did not have a factoryClass specified in Frame metadata to load the configured runtime shared libraries. To compile without runtime shared libraries either set the -static-link-runtime-shared-libraries option

This issue is caused by the new default settings of the flex-config settings that ship with the FLEX 4 SDK.  Luckily the solution is fairly simple, you just need to add the following line to your mxmlc target in your ANT build script:

<mxmlc>
    <mxmlc file="src/Main.as" output="bin/main.swf">
    <source-path path-element="src" />
    <external-library-path file="libs" append="true" />
 
    <!-- Here's the magic line that you need to add! -->
    <static-link-runtime-shared-libraries>true</static-link-runtime-shared-libraries>
 
</mxmlc>

Hope that helps :)

Posted in ActionScript 3 | Leave a comment

Flash / Flex Development on Windows – Tips and Tricks

This post is a brain dump of the various applications and tricks which make Flash / Flex development quicker and easier on a Windows based system in the hope that some of the them will be new to the people that find this :)

Console 2http://sourceforge.net/projects/console

Console 2 is an excellent replacement for the rather limited Windows Command Prompt.  It offers a lot of nice features which make it almost comparable to a Unix terminal such as a tabbed interface, TAB auto-completion and dynamic window resizing.  One thing you will probably want to do is configure the Mouse shortcuts to enable left click selection and right click pasting.

SilkSVNhttp://www.sliksvn.com/en/download

SilkSVN offer Windows x32 and x64 binaries of the Subversion command line tool.  Once you’ve downloaded, installed and added this tool to your Windows’ PATH environment variable, you will be able to perform all your svn duties from the command line just like you would on linux.

Apache ANT http://ant.apache.org/bindownload.cgi

If you build your Flash project with ANT then you will probably want to grab the ANT Windows binaries so you can invoke your build from the command line.  Download the zip archive from the site above, extract the “bin” folder from the archive somewhere useful (I go for C:Program FilesApacheAnt) and then add it to your Windows’ PATH environment variable.  You can then invoke ant -diagnostics to check it’s working.

PSCPhttp://www.chiark.greenend.org.uk/~sgtatham/putty/download.html

Everyone knows about PuTTY (right?!) but I don’t think everyone knows that you can also grab the PSCP binary from the same site.  PSCP allows you to perform SCP transfers from you local Windows machine to another system which offers SSH access (eg: your deployment server).  Download the EXE and then add it to your Windows PATH environment variable and you can easily invoke it from the command line via pscp -v.

BareTailhttp://www.baremetalsoft.com/baretail/

Ahh, the first bit of commercial software on the list (although they do offer a free version!)  BareTail provides a GUI for the classic unix tail command which is perfect for monitoring your flashlog file.

Posted in Windows | Leave a comment

MySQL Dump / Backup Batch Script for Windows

This is a small Windows Batch Script which I’ve created for dumping out all tables from a local MySQL Service; all the data gets dumped as a plain SQL file which is then archived using 7Zip.  This script will also attempt to start (and then stop) the MySQL Service on your local machine if it is not already running.

@echo off
REM MySQL Dump / Backup Script for Windows NT Systems.
REM
REM This Script will dump all tables from your MySQL Instance to a 7zip archive; it will
REM Also take care of starting and stopping the MySQL Service on the machine.
REM
REM @author Jonny Reeves – http://www.jonnyreeves.co.uk/
 
setlocal
set mysql_username="root"
set mysql_password="YOUR-MYSQL-ROOT-USER-PASSWORD"
set output_path="%HOMEDRIVE%%HOMEPATH%Desktopmysql_dumps"
set mysql_service="wampmysqld"
set mysql_path="C:Program Files (x86)WAMPbinmysqlmysql5.5.8bin"
set zip_path="C:Program Files7-Zip"
 
 
REM Start of Script.
IF NOT EXIST %output_path% (mkdir %output_path%)
 
REM Check to see if the MySQL Service is running
for /f "tokens=*" %%a IN ('sc query "%mysql_service%" ^| find "RUNNING"') do set servicerunning=%%a
if "X%servicerunning%%" == "X" (goto service_stopped) ELSE (goto service_running)
 
 
:service_stopped
	echo Starting MySQL Service: %mysql_service%
	net start %mysql_service%
	call :dump_and_zip
	echo Stopping MySQL Service: %mysql_service%
	net stop %mysql_service%
	goto end
 
:service_running
	echo MySQL Service is already running.
	call :dump_and_zip
	goto end
 
:dump_and_zip:
	REM Dump out the MySQL Database to a timestamped .sql file
	for /f "tokens=1,2,3 delims=/ " %%a in ('DATE /T') do set date=%%c-%%b-%%a
	for /f "tokens=1,2 delims=:" %%a in ('TIME /T') do set time=%%a-%%b
	%mysql_path%mysqldump.exe --user %mysql_username% --password=%mysql_password% --all-databases --opt > "%output_path%%date%_%time%.sql"
 
	REM Check for Errors.
	if %ERRORLEVEL% NEQ 0 (goto error)
 
	REM Zip it up and remove the temp file.
	%zip_path%7z.exe a -t7z %output_path%%date%_%time%.7z %output_path%%date%_%time%.sql
	del "%output_path%%date%_%time%.sql"
	goto :EOF
 
:error
	echo An error occured.
	EXIT /B 42
 
:end
	endlocal

You can download a copy of the above script here. Please note that in order to start and stop your MySQL Service, this still will need the appropriate privileges when executed.

Posted in Misc. | Leave a comment

Fluent Builder for TweenLite

After my previous post about Fluent Builders, I have been having a play with a quick example I knocked up for Jack Doyle’s excellent TweenLite, currently, it’s looking a bit like this:

TweenLite syntax:

TweenLite.to(box, 1.5, { x: 200, y: 200, onComplete: onTweenComplete, onCompleteParams: [ "someVar"], ease: Quad.easeOut, onUpdate: onTweenUpdate, onUpdateParams: [ "anotherVar" ]})

TweenLiteBuilder syntax:

new TweenBuilder(box, 1.5, { x: 200, y: 200 })
		.onComplete(onTweenComplete, [ "someVar" ])
		.onUpdate(onTweenUpdate, [ "anotherVar" ])
		.ease(Quad.easeOut)
		.tween();

I fee the TweenLiteBuilder syntax offers a couple of advantages, with main one being that there is a clear speration between the properties which will be tweened on the target (in the above case, x and y) and the TweenLite framework specific bits (ease, onComplete and onUpdate). Your IDE can now provide both code hinting for these framework methods as well as ASDoc, another nice feature is that methods such as onComplete have their callback params in the same function block which makes them much easier to recall.

A side effect of using the Builder Pattern like this is that the actual call to TweenLite is hidden away inside the builder, this means you could switch Tweening engines and only have to modify the Builder itself.

I’ve dropped Jack an email to see what he thinks.

Posted in ActionScript 3 | Leave a comment

Builder Pattern in ActionScript – Fluent Constructors

How many times have you come across a class which looks like this:

package nutrition.model {
	public class NutritionFacts {
		private var _servingSize : uint;	// (mL) required            
		private var _servings : uint;		// (per container) required 
		private var _calories : uint;		// optional                 
		private var _fat : uint;		// (g) optional             
		private var _salt : uint;		// (mg) optional            
		private var _carbohydrate : uint;	// (g)  optional
 
		public function NutritionFacts(servingSize : uint, servings : uint, calories : uint = 0, fat : uint = 0, salt : uint = 0, carbohydrate : uint = 0)  {
			_servingSize = servingSize;
			_servings = servings;
			_calories = calories;
			_fat = fat;
			_salt = salt;
			_carbohydrate = carbohydrate;
		}     		
	}
}

I’m not a great fan of this style of object construction, it ends up making massive single lines of code which are confusing to read for example, in the following example, what does the 4th argument actually set, why is it zero?

const colaFacts : NutritionFacts = new NutritionFacts(330, 1, 500, 0, 35, 22)

One soltution to this problem is to only demand the required fields in the constructor and use setters for the other fields, we end up with something similar to this:

package nutrition.model {
	public class NutritionFacts {
		private var _servingSize : uint;	// (mL) required            
		private var _servings : uint;		// (per container) required 
		private var _calories : uint;		// optional                 
		private var _fat : uint;			// (g) optional             
		private var _salt : uint;			// (mg) optional            
		private var _carbohydrate : uint;	// (g)  optional
 
		public function SetterNutritionFacts(servingSize : uint, servings : uint) {
			_servingSize = servingSize;
			_servings = servings;
		}
 
		public function set calories(value : uint) : void {
			_calories = value;
		}
 
		public function set fat(value : uint) : void {
			_fat = value;
		}
 
		public function set salt(value : uint) : void {
			_salt = value;
		}
 
		public function set carbohydrate(value : uint) : void {
			_carbohydrate = value;
		}
	}
}

To create our ColaFacts object using the above we would code:

const colaFacts : NutritionFacts = new NutritionFacts(330, 1);
colaFacts.calories = 500;
colaFacts.salt = 35;
colaFacts.carbohydrate = 22;

In my opinion this approach is preferable, but now it has introduced a different problem, one of design. In the first example where all the arguments were passed in the constructor, the NutritionFacts object was immutable - its values could not be modified once the object had been instantiated. However, with the NutritionFacts object shown above the calories, fat, salt and carbohydrate values can all be modified elsewhere in the code. If we have our purist Object Orientated Developer hat on we would declare this as a violation of encapsulation.

The Builder Pattern offers us a solution, it allows us to create an immutable object (ie: no setters) which doesn’t end up having a massive constructor for all the optional values it can contain. In Effective Java, 2nd Edition, Joshua Bloch covers this under the title of “Consider a Builder when faced with many constructor parameters”. In his book, Josh makes use of an inner class to create the Builder, although we have inner classes in ActionScript, they do not share the same behaviour as those in Java, especially when it comes to the visibility of member properties – this makes implementing Josh’s example in ActionScript difficult, however, by using the internal visibility modifier we can create a close approximation.

First we have the NutritionFactsBuilder, this is based upon the Builder pattern and make use of a fluent interface:

package nutrition.model{
	public class NutritionFactsBuilder {
		internal var servingSize : uint;	            
		internal var servings : uint;		
		internal var calories : uint;		                 
		internal var fat : uint;			             
		internal var salt : uint;			            
		internal var carbohydrate : uint;	
 
		public function NutritionFactsBuilder(servingSize : uint, servings : uint) {
			this.servingSize = servingSize;
			this.servings = servings;
		}
 
		public function withCalories(value : uint) : NutritionFactsBuilder {
			calories = value;
			return this;
		}
 
		public function withFat(value : uint) : NutritionFactsBuilder {
			fat = value;
			return this;
		}
 
		public function withSalt(value : uint) : NutritionFactsBuilder {
			salt = value;
			return this;
		}
 
		public function withCarbohydrate(value : uint) : NutritionFactsBuilder {
			carbohydrate = value;
			return this;
		}
 
		public function build() : NutritionFacts {
			return new NutritionFacts(this);
		}
	}
}

Next up we have the NutritionFacts class, note that now the only argument it expects in the constructor is a NutritionFactsBuilder instance:

package nutrition.model {
	public class NutritionFacts {
		private var _servingSize : uint;	// (mL) required            
		private var _servings : uint;		// (per container) required 
		private var _calories : uint;		// optional                 
		private var _fat : uint;		// (g) optional             
		private var _salt : uint;		// (mg) optional            
		private var _carbohydrate : uint;	// (g)  optional
 
		public function NutritionFacts(builder : NutritionFactsBuilder) {
			_servingSize = builder.servingSize;
			_servings = builder.servings;
			_calories = builder.calories;
			_fat = builder.fat;
			_salt = builder.salt;
			_carbohydrate = builder.carbohydrate;
		}     		
	}
}

We can now employ the builder to create us our NutritionFacts object:

const colaFacts : NutritionFacts = new NutritionFactsBuilder(330, 1)
	.withCalories(500)
	.withSalt(35)
	.withCarbohydrate(22)
	.build();

Note that we are supplying the required servingSize and servings values in the NutritionFactsBuilder() constructor, but all the other optional values can now be supplied via method chaining. When build() is called the NutritionFactsBuilder will return a new instance of NutrionFacts for us; this constructed NutritionFacts object is now immutable and the reader can easily see which properties are going to be set on the instance. Because we have made the properties of the NutritionFactBuilder object internal, they are only visible to classes inside the “nutrition.model” package, as the consumers of models shouldn’t be in the models package they will not be visible (only the public with… methods will be). Another nice benefit is that we have split construction of our object (performed by the NutritionFactsBuilder) out from the actual object (NutrtionFacts) – if NutritionFacts was instead an interface, the Builder could return a different concrete instance to the user without them ever knowing – this may come in handy for making the builder return mock implementations when unit testing, for example (please excuse the hideous code, it’s just as an example!):

package nutrition.model{
	public class NutritionFactsBuilder {
                // The default NutirtionFacts implementation that will be returned by NutritionFactBuilder instances.
                private static var instanceType : Class = NutritionFactsImpl;
 
                // We could call this and request that the Buildern return MockNutritionFact instances instead
                public static function setInstanceType(clazz : Class) : void { 
                	instanceType = clazz;
                }
 
	        // ... other methods omitted.
 
                public function build() : NutritionFacts {
                	return new instanceType(this);
                }
        }
}

By using the Builder Pattern in this fashion we are creating something similar to named parameters as found in other languages – other ActionScript developers have already found their own solutions to this, the most recognisable being Greensock’s excellent TweenLite, where an untyped object is used to optional provide parameters ie:

new TweenLite(target, 0.8, { x: 50, y: 100 });

I think this works well for TweenLite, however, I often find myself having to head on over to greensock.com whenever I need to do something a little bit more complicated (for example, is it onCompleteParams, or onCompleteArgs?), the above Builder Pattern approach could have possibly answered that for us:

new TweenBuilder(target, 0.8)
	.x(50)
	.y(150)
	.onCompleteParams([ "foo" ])
	.tween();
Posted in ActionScript 3 | Tagged , , , , , | 5 Comments

Hudson, MXMLC and Embedding Assets

Quick post to help out anyone in the same headscratching situation that I just found myself in. I was in the process of getting our Flash build up and running on Hudson when I fell foul of the following error:

[java] /foo/diablo-flash/workspace/adoption_ingame/src/com/mindcandy/diablo/adoption_ingame/controller/DropDownConfigManager.as(17): col: 4: Error: unable to resolve 'dropDownConfig.xml' for transcoding
[java] 
[java] 		[Embed(source="dropDownConfig.xml", mimeType="application/octet-stream")]

Strange, I thought to myself, the file is definitnely there:

host:/foo/diablo-flash/workspace/adoption_ingame/src# ls -l
total 100
drwxr-xr-x 4 tomcat6 tomcat6  4096 2010-07-19 15:47 com
-rw-r--r-- 1 tomcat6 tomcat6 12205 2010-07-19 15:47 dropdownConfig.xml

And then the answer struck me – the casing is different – dropDownConfig.xml in the Embed vs. dropdownConfig.xml on disc, sure enough bringing these two back into sync fixed the issue and my build proceeded as planned with Hudson.

I wondered why I had never come across this problem during day-to-day builds and then I remember that Mac OS ships with Case Insensitive filesystem by default…

Posted in ActionScript 3 | Tagged , , , | Leave a comment

FDT and FlexUnit 4.1 Beta

FlexUnit 4 was a massive leap forward for Test Driven ActionScript 3 Development allowing us to make use of metadata annotations, hamcrest and easier asynchronous testing and I was delighted to discover that the flexunit.org team are still busy working away preparing for the next milestone release of FlexUnit 4.1 which boasts some great new features, my favourite being an ANT Task to generate TestSuite’s automatically (something that only Antennae appeared to offer before).

This wiki post will show you how to get the FlexUnit 4.1 beta up and running in FDT 3.5 by making use of the FlexUnit ANT tasks.

First up we will download the FlexUnit 4.1 beta; I will be downloading the build for FlexSDK 3.5, AS3 Pure.

Once unzipped, you will want to add the FlexUnit 4.1 libraries to your project’s libs folder; once copied across your project should look something like the screenshot below:

Copying the FlexUnit 4.1 libs into your FDT project

Copying the FlexUnit 4.1 libs into your FDT project

Once you have copied the FlexUnit 4.1 libs into your project you will want to add the FlexUnit core library SWC to your FDT Class Path so you get code completion on FlexUnit methods; this is done by right-clicking on the flexunit-core-4.1.0-beta1.swc file; again see the screnshow below:

Adding the FlexUnit 4.1 Core SWC to your project's Class Path

Adding the FlexUnit 4.1 Core SWC to your project's Class Path

Next up we will add a very simple, sample test to the project, start by adding a new “Source Folder” to your project by selecting File -> New -> Source Folder; name the folder test-src. Now create a new ActionScript Class in the test-src folder and name it TestExample.as.

Because FlexUnit 4 is driven by metadata, there is no need to extend a base class; instead you just need to annotate the methods which represent test with the [Test] metadata tag. Our example test will do nothing, but will at least allow FlexUnit 4.1 to fire up and show some output:

package  
{
	import org.flexunit.asserts.assertTrue;
 
	/**
	 * An example Test Case to get FlexUnit 4.1 Beta up and running.
	 * @author Jonny Reeves
	 */
	public class TestExample 
	{
		[Test]
		public function exampleTest() : void
		{
			// Not much of a test! :)
			assertTrue("FlexUnit 4.1 Beta is running under FDT", true);
		}
	}
}

The final step is to setup the ANT Build File which will automatically create our TestSuite and launch the FlexUnit 4 Visual Test Runner to display the outcome of our test. If you have not used ANT before in FDT then you may need to open the ANT View by selecting Window -> Show View -> Ant.

Create a new file named build.xml in your project; when you open this file for editing FDT should automatically fire up the ANT editor which provides syntax highlighting for you. Start off by creating a barebones ANT file:

<project name="FlexUnit4.1-Example">
</project>

Now drag the build.xml into the ANT View; once added it should appear like the screenshot below:

Creating an ANT BuildFile and adding it to the ANT View

Creating an ANT BuildFile and adding it to the ANT View

Now we want to create a new Build Task which will generate a Test Suite from our test-src folder and then compile a FlexUnit 4.1 SWF which runs those tests.

<project name="FlexUnit4.1-Example">
	<!-- Update this property to point to your FLEX SDK; note there is
			a bug in FlexUnit 4.1 Beta 1 where the FLEX SDK path must
			NOT include any spaces, otherwise you will get an error during
			the MXMLC compilation stage; this has already been fixed in the
			latest Builds of FlexUnit 4.1, see: http://bit.ly/dpHcHT -->
	<property name="FLEX_HOME" location="${eclipse.fdt.flexsdk}" />
 
	<property name="bin.dir" value="${basedir}/bin" />
	<property name="report.dir" value="${basedir}/reports" />
	<property name="lib.dir" value="${basedir}/libs" />
	<property name="test-src.dir" value="${basedir}/test-src" />
 
	<taskdef resource="flexTasks.tasks" classpath="${FLEX_HOME}/ant/lib/flexTasks.jar" />
	<taskdef resource="flexUnitTasks.tasks" classpath="${lib.dir}/flexUnitTasks-4.1.0-beta1.14.jar" />
 
	<!-- Run FlexUnit 4.1 and generate JUnit Output -->
	<target name="test" depends="init" description="Run Unit Tests">
		<flexunit 
			workingDir="${bin.dir}" 
			toDir="${report.dir}" 
			verbose="true" 
			haltonfailure="true"> 
			<testSource dir="${test-src.dir}">
				<include name="**/*Test*.as" />
			</testSource>
			<library dir="${lib.dir}" />
		</flexunit>
 
		<junitreport todir="${report.dir}">
			<fileset dir="${report.dir}">
				<include name="TEST-*.xml" />
			</fileset>
			<report format="frames" todir="${report.dir}/html" />
		</junitreport>
 
	</target>
 
	<!-- Create the required directories and clean out the reports folder -->
	<target name="init">
		<delete dir="${report.dir}" />
		<mkdir dir="${bin.dir}" />
		<mkdir dir="${report.dir}" />
	</target>
</project>

Once you’re build file is setup you can execute the test ANT task. If the task completes succesfully, FlexUnit will have populated the reports folder with both JUnit style reports and an HTML version which can be opened in a web browser.

SUCCESS! My Test Passed :)

SUCCESS! My Test Passed :)

If the build fails then the Output Console view should provide you with some debugging hints; if you are using FlexUnit 4.1 Beta 1 then make sure your Flex SDK path does not include any spaces (this particular bug will be fixed in beta 2 of FlexUnit 4.1).

Further reading:

Posted in ActionScript 3 | Tagged , , , | 6 Comments

Reducing the size of SWF Files

Over at Moshi HQ, we’ve spent a fair bit of time looking at how to reduce the size of the SWFs we publish; here’s a quick checklist to rattle through to get the most bang for your buck (or in this case, Kb)

1. Joa Ebert’s Apparat.
Joa is an ActionScript hero (infact he won an award to prove it); one of his tools is Apparat; a Scala application which optimises SWFs by tinkering with the compression they use. Apparat is a real quick win as once you’ve integrated it into your build process you will immediately being reaping the rewards.

2. Sothink SWF Decompiler
Yes, number two on my list is a decompiler; this is not a mistake. Sothink SWF Decompiler is an essential part of the optimisation process as it allows you to explore all the assets, ActionScript classes, fonts, bitmaps, etc which are lurking around in your SWF – think of it like a visual Size Report for a SWF.

3. Make use of Run Time Shared Libraries
Flex developers seem very comfortable with Runtime Shared Libraries, but it’s something that most ActionScript dev’s aren’t so hot on. The MXMLC compiler provides a couple of ways to reduce the size of your published SWF by allowing you to automatically exclude duplicated class definitions across SWFs loaded at run time. The problem is a very simple one; you have a Main application which loads in a bunch of child “sub apps” into the same Application Domain; both of the SWFs end up with the same classes compiled into them (for example, you may be using famework elements in both) – because the Main application SWF has already loaded these classes there is no need to include them into the child swf as well.

The simplest MXMLC compiler flag you can use is, runtime-shared-libraries, simply point it at the location of your Main SWF when compiling the subapps and it will do the rest for you. Alternatively, Those of you who worked in AS2 back in the day may recall the old exclude.xml; well it’s still alive and kicking with MXMLC, it just goes under the name of link-report.

The process is pretty straight forward, compile your main application supplying the link-report flag, this will dump out an XML file. Next, compile all your subapps supplying the load-externs flag. Keith Peters goes into more detail on his blog.

4. Check your Compiler Flags
This may seem pretty obvious, but it’s important to check; The MXMLC compiler which ships with the Flex SDK supports a crazy number of switches and options, the following options can impact on the size of the compiled SWF:

  • debug – Pretty obvious, if you set the debug flag to true when compiling, MXMLC will embed a whole bunch of debugging information to your SWF, bloating out the filesize. The main thing to watch out for is that you don’t end up deploying SWFs compiled with the debug flag set to true on your live server. Sames goes for the optimise and verbose-stacktraces flags
  • include-libraries – Make sure that you didn’t mean to use library-path instead! include-libraries will compile the entire contents of a SWC into your final SWF file even if you never actually use any of it! Using library-path, on the other hand, results in only the classes which you import being compiled into the SWF
Posted in ActionScript 3 | Tagged , , , , | 1 Comment

Logging in ActionScript 3

Logging is a fundamental part of any mid to large scale application, your application needs to be able to talk to other developers and Q&A engineers to help diagnose problems and gain insight into what’s going on under the hood. Jesse Warden recently wrote an excellent article on logging, however, my own implementation of logging AS3 apps differs so much that I thought it warranted a blog post.

The Problems

One of the most important things in OOP is to ensure that you avoid tight coupling; Jesse’s approach of using a static logger leaves your code scattered with a dependency on it.

Another point that Jesse makes is how important it is to include the name of the enclosing class when writing a log message,

… all log messages start with “ClassName::methodName” where ClassName is the name of the class you are in, and methodName is the current method the log message is in. It seems a major pain at first, but I guarantee you when you start removing them 2 months later, you know EXACTLY where to find it vs. that one trace that stays there for weeks because no one found where the bastard is.

I couldn’t agree more with this, having come from working on a massive application with thousands of log messages, not knowing where a message was originating from would have been a nightmare. However, Jesse’s approach is very manual and relies on your entire team being disciplined; not to mention the fact that as soon as you start refactoring that “ClassName::methodName” identifier is quickly going to get out of sync.

A Commons Solution

I feel that there is a simple solution to both the above problems in the form of the AS3 Commons Logging Framework. The framework provides an abstraction of logging which means your code is not dependant on any one implementation, plus it has the added benefit of automatically adding the name of the Class when writing a log message; winner!

Usage is pretty straight forward, but requires a little more setup than Jesse’s static helper approach; first of all your request a static ILogger instance from the LoggerFactory at the top of your class and then you are free to use it throughout the Class to write log messages, for example:

package uk.co.jonnyreeves
{
	public class MyClass
	{
		// Request an ILogger instance for this Class.
		public static const LOGGER : ILogger = LogFactory.getClassLogger(MyClass);
 
		public function MyClass()
		{
			// Write a log message using the Logger instance.
			LOGGER.info("Created instance of MyClass");
		}
	}
}

Using the TraceLogger implementation which the AS3 Commons Logger will default to, you would receive the following in your Flash TraceLog:

Sun Feb 21 10:33:29 GMT+0000 2010 [INFO]  uk.co.jonnyreeves.MyClass - Created instance of MyClass

The beauty of this approach is that the actual implementation of the ILogger interface is left to the LoggerFactory which means it can be switched at runtime. Another neat benfit is that the name of the Logger is taken from the encolosing Class which created it (via LoggerFactory.getClassLogger()). This mean that is you rename the Class as part of a refactoring effort, all the log messages contained in said class will automatically update.

Getting More Specific

So I’ve mentioned that your can decide the ILogger implementation at runtime, let’s see an example of that in action. My current Logging implementation of choice is the excellent DeMonsters Monster Debugger which reminds me a lot of the AS2 classic, LumnicBox in that it allows you to fully inspect the Object Graph at run time.

The first thing we need is to create an implementation of LogFactory which will return our ILogger instances upon request:

package uk.co.jonnyreeves.logging.util.monsterdebugger 
{
	import nl.demonsters.debugger.MonsterDebugger;
 
	import org.as3commons.logging.ILogger;
	import org.as3commons.logging.ILoggerFactory;
 
	/**
	 * Provides a bridge between the AS3Commons Logging Framework and MonsterDebugger.
	 * 
	 * @author John Reeves
	 */
	public class MonsterDebuggerLoggerFactory implements ILoggerFactory 
	{
 
		/**
		 * Initialises MonsterDebugger
		 * 
		 * @param target		The Base Object you wisht to start graphing from (usually you will supply the
		 * 						Display Root DisplayObject).
		 * 					
		 * @param clearConsole	Clears MonsterDebugger's Trace Console when the initial connection is made.
		 */
		public function MonsterDebuggerLoggerFactory(target : Object, clearConsole : Boolean = true) 
		{
			new MonsterDebugger(target);
			if (clearConsole)
			{
				MonsterDebugger.clearTraces();
			}
		}
 
		/**
		 * Factory Method, used to return an instance of ILogger to the AS3Commons Logging Framework.
		 */
		public function getLogger(name : String) : ILogger
		{
			return new MonsterDebuggerLogger(name);
		}
	}
}

Now all that’s left to do is to create the MonsterDebuggerLogger implementation of the ILogger interface; this will re-write all the LOGGER.info(), etc calls through to MonsterDebugger.

package uk.co.jonnyreeves.logging.util.monsterdebugger 
{
	import org.as3commons.logging.util.MessageUtil;
	import nl.demonsters.debugger.MonsterDebugger;
 
	import org.as3commons.logging.LogLevel;
	import org.as3commons.logging.impl.AbstractLogger;
 
	/**
	 * Provides a bridge between the AS3 Commons Logging implementation and Monster Debugger; it's not perfect but it 
	 * works for the most part.
	 * 
	 * The Target of the log message will always be the name of the logger.
	 * 
	 * The Object of the log message will vary depending on the parameters passed.  If the message string is empty
	 * then the params Array will be logged.  If the message string is not empty, the params Array will be used to
	 * tokenise the message string.
	 * 
	 * Usage:
	 * 		LOGGER.debug("Hello World");		// Outputs message: "(String) Hello World"
	 * 		LOGGER.debug("Hello {0} {1}, "Jonny", "Reeves");	// Outputs message: "(String) Hello Jonny Reeves"
	 * 		LOGGER.debug("", [ 1, 2, 3 ]);		// Outputs message: "(Array)..." (which can then be inspected)
	 * 		
	 * Incorrect usage:
	 * 		LOGGER.debug("Some Array", [1, 2, 3]);	// Outputs message: "(String) Some Array" (which can't be inspected)
	 * 
	 * @author John Reeves
	 */
	public class MonsterDebuggerLogger extends AbstractLogger 
	{
		public var level : int = LogLevel.DEBUG;
 
		public function MonsterDebuggerLogger(name : String) 
		{
			super(name);
		}
 
		override protected function log(level : uint, message : String, params : Array) : void
		{
			if (level >= this.level)
			{
				var target : Object = name;
				var object : Object = getLogObject(message, params);
				var colour : uint = getLogMessageColour(level);
				MonsterDebugger.trace(target, object, colour);
			}
		}
 
		private function getLogObject(message : String, params : Array) : Object 
		{
			if (message == "")
			{
				// If the user only supplied a single param to log, we remove the params array which is enclosing it.
				return (params.length == 1) ? params.pop() : params;
			}
			else
			{
				return MessageUtil.toString(message, params);
			}
		}
 
		private function getLogMessageColour(level : int) : uint 
		{
			var colour : int;
			switch (level)
			{
				case LogLevel.FATAL:
				case LogLevel.ERROR:
					colour = MonsterDebugger.COLOR_ERROR;
					break;
 
				case LogLevel.WARN:
					colour = MonsterDebugger.COLOR_WARNING;
					break;
 
				default:
					colour = MonsterDebugger.COLOR_NORMAL;
					break;
			}
			return colour;
		}
 
		override public function get debugEnabled() : Boolean
		{
			return LogLevel.DEBUG >= level;
		}
 
		override public function get errorEnabled() : Boolean
		{
			return LogLevel.ERROR >= level;
		}
 
		override public function get infoEnabled() : Boolean
		{
			return LogLevel.INFO >= level;
		}
 
		override public function get warnEnabled() : Boolean
		{
			return LogLevel.WARN >= level;
		}
 
		override public function get fatalEnabled() : Boolean
		{
			return LogLevel.FATAL >= level;
		}
	}
}

The code here is fairly self documenting with the protected log() method proxying all the logging requests through to MonsterDebugger. Because the creators of the AS3Commons Logging Project specified the message param to have a datatype of String, we are forced to do a little bit of a workaround when we want to dump Objects out to the MonsterDebugger console. There is an open ticket on the AS3Commons project page should you wish to request a change.

The last piece of the puzzle is to swap the AS3Commons LoggingFactory implementation, this is very straight forward and requires a single line of code during your application’s startup routine (preferably before any logging takes place).

package
{
	import uk.co.jonnyreeves.logging.util.MonsterDebuggerLoggerFactory
	import flash.display.Sprite;

	/**
	 * Application Entry Point.
	 * @author John Reeves
	 */
	public class MyApp extends Sprite
	{
		public function MyApp()
		{
			LoggerFactory.loggerFactory = new MonsterDebuggerLoggerFactory(this);
		}
	}
}

Once this is done you are free to start using the LoggingFactory as per the example further up the page. Your log messages should now show up in the MonsterDebugger logging console.

Posted in ActionScript 2, ActionScript 3 | Tagged , , | 3 Comments