Tag Archives: parsley

A new Parsley Extension: The DynamicServices tag

I just pushed a new Parsley extension project to GitHub – support for the <DynamicService /> tag.

Typically in a project, I like to structure my services layers pretty cleanly – for each service I would declare the following:

  • An interface which defines the services contract
  • A concrete implementation of the interface, which abstracts away the RemoteObject
  • A stub implementation of the interface, for testing when the services layer is unavailable

For example, a simple EchoService might look a little something like this:

// IEchoDelegate.as
public interface IEchoDelegate
{
     function echoMessage(source:String):AsyncToken;
}

// EchoDelegate.as
public class EchoDelegate
{
   [Inject]
   public function service:RemoteObject;

   public function echoMessage(source:String):AsyncToken
   {
      return service.echoMessage(source);
   }
}

Here, you can see the concrete delegate is really just boiler-plate code.  It’s pretty repetitive, and while I find lots of value in the pattern, the actual implementation can be a bore.

So, I put together a Parsley extension to generate these delegates on the fly.

Here’s an example:

<?xml version="1.0" encoding="utf-8"?>
<parsley:Objects>
   <fx:Declarations>
      <services:DynamicService type="{IEchoService}" endpoint="http://localhost:8080/testdrive/messagebroker/amf" destination="echoService" />
   </fx:Declarations>
</parsley:Objects>

This definition combines the Interface and the remote object defininition in the context. An implementation of the interface is generated on-the-fly at runtime, and is available to be injected into classes as required.

Eg:

// EchoCommand.as
	public class EchoCommand
	{
		[Inject]
		public var service:IEchoService;

		public function execute(message:EchoMessage):AsyncToken
		{
			return service.echo(message.source);
		}

		public function result(result:String):void
		{
			trace("Received from the server:" + result);
		}
	}

Source

The source for this is available now on github.  There’s also a demo project available here

A word of warning

Under the covers, this extension makes use of the ASCommons-Bytecode library to build an implementation of the interface.

Unfortunately, this dynamic goodness is not free, and incurs a one-off cost at startup when the ByteCode library parses the bytecode of the swf into memory.  As a result, you’ll notice that Parsley takes a little longer to intitialize than you might be used to.  This is a tradeoff that must be considered before using this approach.

Advertisements
Tagged ,

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 , ,