Compound Theory

v2.0

Categories

  1. Transfer
  2. ColdFusion
  3. JRuby
  4. Java
  5. ColdSpring
  6. Squabble
  7. JavaLoader
  8. ColdDoc
  9. 2ddu
  10. AsyncHTTP
  11. OO Analysis and Design
  12. Flex
  13. Railo
  14. XML / XSL
  15. Hibernate
  16. ColdFusion Builder
  17. Fall
  18. Ubuntu
  19. XHTML / CSS
  20. Eclipse
  21. Git
  22. Oracle Database
  23. Usability / UI Design
  24. webDU
  25. cf.Objective()
  26. LWJGL
  27. cf.Objective(ANZ)
  28. Captcha
  29. MAX
  30. Melbourne CFUG
  31. Martial Arts
  32. Random Things
  33. Conduit

Recent Posts

Projects

Recent Comments

30 August 2011 10:02 AM 1 Comment

Registration Open for cf.Objective(ANZ) + Flex

In case you missed the hullabaloo, registration recently opened for cf.Objective(ANZ) + Flex.

I'm really excited about this years speaker line up, and honestly think that the sessions we have this year are the best we've ever had. We got awesome content on testing, frameworks, continuous integration, version control, and more. Basically, if it's used in enterprise software development, I think we've just about got it covered.

We've also got four pre-conference workshops also lined up as well, so there is an extra opportunity there to get some extra learning in, on top of the pretty incredible line up of speakers we have as well.

It should be noted that there will be no extensions on the early bird for cf.Objective(ANZ) + Flex, so make sure to get your registration in early!

As you can tell, I'm really excited about this year's conference, so I look forward to seeing you all there!

cf.Objective(ANZ) + Flex - Call for Speakers

In case you missed it, cf.Objective(ANZ) opened up it's call for speakers the other week .
 
So if you are interested in speaking on ColdFusion, Flex, or just generally anything enterprisey and/or software development related, make sure to have a look, and put in an entry.
 
Conference speaking is always an awesome and incredibly rewarding experience, and a great opportunity to learn, and also impart your knowledge to others. While it may be extremely nerve wracking to get up in front of an audience, the rewards are well worth it, let me assure you!
 
Either way, I look forward to seeing you all there!

cf.Objective(ANZ) is Back Again - This Time with More Flex

cf.Objective(ANZ)  is back again for another year, with it's usual two tracks of amazing enterprise ColdFusion goodness, as well as a whole new dedicated Flex and Flash track.

No where else in Australia and New Zealand will you be able to get this type of delicious ColdFusion learning, combined with a sumptuous feast of front end Flex and Flash content, so make sure to mark your calendars now!

Check the cf.Objective(ANZ) website  for details including dates and venue.

Also - if you are interested in sponsoring, download the sponsorship guide, which can be found on the sponsors page

 

14 January 2009 05:03 PM 5 Comments

Improving on ColdFusion Remoting with Conduit

Since I've been working with Conduit, there have been several 'enhancements' to the Flex Remoting that I've implemented, above and beyond what ColdFusion provides out of the box.

These are mostly little things, but since Conduit is Open Source, we are able to incorporate them into how Conduit works, and give us some new tools to use when we set up Remoting.

One of the first enhancements I made, was around the fact that every time Flex invokes a CFC through Remoting, it gets created on every request.  Quite often, this is simply not necessary, as the CFC in question has no state, or maybe you want the CFC to maintain state, but you have to jump through some hoops to get that to happen.

In Conduit, you can now set a:

<cfcomponent remoteScope="application" >...</cfcomponent>

...and the CFC will be stored inside the specified shared scope.

For example, here is a CFC that gets stored in the session scope when invoked, and keeps a simple incrementing number each time its remote method gets called:

<cfcomponent hint="proxy stored in a share scope" output="false" remoteScope="session">

<cfscript>
    instance.value = 1;
</cfscript>

<cffunction name="getIncrementingValue" hint="returns a value, and increments it by 1" access="remote" returntype="numeric" output="false">
    <cfreturn instance.value++ />
</cffunction>

</cfcomponent>


So you can see here how we are able to maintain state between calls, within a single CFC.

The other enhancements I made, revolve around passing null values back and forth from AS3 Objects, and ColdFusion.

As we all know, there is no null as such in ColdFusion, which can make dealing with null values from Flex slightly problematic.

I've added two new enhancements to <cfproperty> for Value Objects to help with this issue - nullvalue and nullmethod.

nullvalue provides a value for a given property to be used when a null value is found in a Flex AS3 object coming down to ColdFusion.  This is particularly applicable when using getter/setters for your properties on your ColdFusion Value Objects.

For example:

<cfcomponent output="false" alias="tests.cfml.cfc.model.Basic">

<cfproperty name="date" type="date" nullvalue="1-1-1900">

<cffunction name="getDate" access="public" returntype="date" output="false">
    <cfreturn instance.date />
</cffunction>

<cffunction name="setDate" access="public" returntype="void" output="false">
    <cfargument name="date" type="date" required="true">
    <cfset instance.date = arguments.date />
</cffunction>

</cfcomponent>

...will set 'Date' to the 1-1-1900 if the AS3 Object's 'date' property is null.  Also, if sending data back up to Flex from CF, the 'date' property is set to null on the Flex side, if the date value is 1-1-1900.  This gives you a type safe way of dealing with null values coming down from Flex.

The nullMethod option for dealing with null values becomes more useful when dealing with object composition in Value Objects.

The nullmethod attribute specifies a method on the CFC to be fired, when encountering a null value for the specified method, e.g.

<cfcomponent output="false" alias="tests.cfml.cfc.model.Basic">

<cfproperty name="simple" type="tests.cfml.cfc.model.Simple" nullmethod="removeSimple">

<cffunction name="setSimple" access="public" returntype="void" output="false">
    <cfargument name="Simple" type="Simple" required="true">
    <cfset instance.Simple = arguments.Simple />
</cffunction>

<cffunction name="removeSimple" hint="remove simple" access="public" returntype="void" output="false">
    <cfset StructDelete(instance, "Simple") />
</cffunction>

</cfcomponent>

So in this case, whenever the property 'Simple' comes back from Flex as null, the method 'removeSimple' is called instead of attempting to set the property.

Now you can start to see what we can do with Conduit, since we can control all aspects of the Remoting process.  So the question is - if you could change any aspect of ColdFusion <=> Flex Remoting, what would it be?  Let me know, and we can see if we can incorporate it into Conduit!

If you want to read more, check out Differences between Conduit and ColdFusion remoting, in the Conduit documentation.
14 December 2008 09:58 AM 6 Comments

Conduit: The ColdFusion Adapter for BlazeDS

This project started with writing the translation layer for doing Transfer to Flex communication, I ran into a pretty nasty bug in ColdFusion's remoting implementation, and then ended up in a place that solves all these problems, and is incredibly flexible and powerful to boot!  Quite the round trip, but well worth it in the end.

Conduit requires that you set up BlazeDS on your machine, as well as install the conduit.jar file, and some CFCs as well.  I'm not going to go into too much details here, as you can read about in the Library Installation section of the documentation.

To configure Conduit, we open up our remoting-config.xml, and we add the Conduit adapter to the <adapters> section:

<adapter-definition id="conduit" class="com.compoundtheory.conduit.adapters.ColdFusionAdapter"/>

And now we continue by adding a new Destination to our remoting-config.xml, which we will then call from Flex via RemoteObject (examples of the configuration are provided in the downloads).

<destination id="Conduit">
    <channels>
        <channel ref="my-cfamf" />
    </channels>
    <adapter ref="conduit" />
    <properties>
        <source>*</source>
        <cfcs>
            <!--
            Whether or not reload the CFCs below on each request.
            Useful for debugging when building new invokers,serialisers
            or deserialisers
            -->

            <reloadcfcs>false</reloadcfcs>
            <!--
            The CFC that invokes the remote method call
             -->

            <invoker>conduit.core.CFCInvoker</invoker>
            <!--
            Translates CF=>AS3
             -->

            <serialiser>conduit.core.CFSerialiser</serialiser>
            <!--
            Translates AS3=>CF
             -->

            <deserialiser>conduit.core.CFDeserialiser</deserialiser>
        </cfcs>
    </properties>
</destination>

The id of the destination can be whatever you like, but we started with 'Conduit', so we would know what we are calling from Flex.

The <adapter> is specified to use the conduit adapter, rather than the default cf-object adapter.

We then set a series of properties, most important of which are setup within the <cfc> section.  This section controls what CFCs are called upon to perform various duties within the ColdFusion <=> Flex communication process.

Just to emphasise this point - this means that the majority of the heavy lifting done by Conduit is done with ColdFusion code.  This makes it really easy to extend, change, manipulate or debug.  It gives you almost complete control over the AS3<=>CF translation process, without you having to know much about Java at all (I will admit there are some Java classes involved).

We can see from there are three CFCs that the Conduit adapter has configured for it.

The <invoker>
This is the CFC that does the actual method calling.  In the instance of the conduit.core.CFCInvoker that comes with Conduit, all it does is create an instance of the CFC that has been requested in the <RemoteObject>'s source attribute, and calls the passed with method name and any parameters that were passed down from Flex.

The code looks something like this (just to show you how simple it is):

<cffunction name="execute" hint="Creates a cfc, and invokes a methodon it" access="public" returntype="any" output="false">
    <cfargument name="source" hint="the cfc source" type="string" required="Yes">
    <cfargument name="methodName" hint="the name of the method" type="string" required="Yes">
    <cfargument name="params" hint="the parameters to pass in" type="any" required="Yes">
    <cfscript>
        var local = {};
        var object = createObject("component", "#arguments.source#");
    </cfscript>

    <cfinvoke component="#object#" method="#arguments.methodName#"argumentcollection="#arguments.params#"returnvariable="local.return">

    <cfif StructKeyExists(local, "return")>
        <cfreturn local.return />
    </cfif>
</cffunction>

Pretty straight forward, no?

The <serialiser>

The job of this CFC is to take whatever is returned from the <invoker> and translate it into whatever you want to return back to Flex.  Since BlazeDS handles the AMF conversion part of it for us, the conduit.core.CFSerialiser only really needs to convert CFCs in Actionscript objects, set all their properties correct, and we are good to go.

The <deserialiser>

The deserialiser CFC's job it to take the incoming parameters that come down from a Flex RemoteObject call, and translate them into something usable for the <serialiser> CFC.

Again, since BlazeDS does a lot of the heavy lifting, the conduit.core.CFDeseriailser's main job, is to convert Actionscript Objects into their appropriate CFCs, and set all their properties correctly.

Changing how things work
 
While there are plans to put some interesting enhancements for Conduit to provide above and beyond what ColdFusion remoting already does, the real power of Conduit comes from being able to write your own custom Invoker, Serialiser or Deserialiser.

Say for example, when we send information from ColdFusion to Flex, we want to reverse every Simple value (String, date, numeric) that we come across.  Don't ask me why you would want to do this ;o), maybe you just like messing with your co-workers.

First thing we need to do is write our own custom CFSerialiser.cfc.  For this example, I'm going to reuse the conduit folder I would have setup, which already has a /conduit ColdFusion mapping pointing to it, and create a new folder called reverse inside it.

So I create a new component, under /conduit/reverse, and call in CFReverseSerialiser.cfc, and make it extend conduit.core.CFSerialiser.

We will now overwrite the translate method, which handles what data gets converted, and how, depending on its data type.

The code would look something like this:

<cfcomponent output="false" extends="conduit.core.CFSeriaiser" hint="Component for serialising CF=>AS3, in reverse">

<cffunction name="translate" hint="translation function for objects,reverses simple values" access="private" returntype="any"output="false">
    <cfargument name="object" hint="the object to serialise" type="any" required="no">
    <cfargument name="cache" hint="local reference cache for cyclic graphs" type="any" required="Yes">
    <cfscript>
        if(isSimpleValue(arguments.object)
        {
            >//if it's simple, then reverse it!
            return reverse(arguments.object);   
        }
        else
        {
            return super.translate(argumentCollection=arguments);
        }
    </cfscript>
</cffunction>
</cfcomponent>

And we can configure a special 'ConduitReverse' destination for anyone who wants reversed Strings in their code:

<destination id="ConduitReverse">
    <channels>
        <channel ref="my-cfamf" />
    </channels>
    <adapter ref="conduit" />
    <properties>
        <source>*</source>
        <cfcs>
            <reloadcfcs>false</reloadcfcs>
            <invoker>conduit.core.CFCInvoker</invoker>
            <serialiser>conduit.reverse.CFReverseSerialiser</serialiser>
            <deserialiser>conduit.core.CFDeserialiser</deserialiser>
        </cfcs>
    </properties>
</destination>


As you can see, we can do almost anything we want to the communication process, simply by extending the core components (or even writing brand new ones) and because its at a low level, its almost completely seamless to those who are writing the ColdFusion and/or Flex code. That being said, its open source, so we can add extra logging and/or debugging as we need.  No more failing silently!

Trying it out

This is still Alpha code, and there is a lot of logging currently in it, but there is enough there for you to start playing.  Code is in SVN, and daily builds are available from the Google Group (saves you having to compile the .jar file).  The documentation is slowly getting fleshed out, but there is enough there to get started.

I am more than happy to get code contributions, and/or ideas for how the to expand on the current ColdFusion remoting feature so send through whatever you have.

I hope you enjoy Conduit!
01 December 2008 08:17 AM 1 Comment

ColdFusion AMF Serialiser inserts 'null' values into a cyclic Object graph... what the?

When writing the Flex <=> Transfer integration, coming across a cyclic object graph is pretty common, as onetomany compositions generate a bi-directional relationship between 2 objects.  I.e. A Parent knows about its children, and children know about their parents.

It is also quite possible for situations to occur, where Object A knows about B, B knows about C, and C knows about A, and therefore having a complete circle.

What confused me no end pretty much all day yesterday, is that when trying to send such an Object data structure up to Flex, theAMF Serialiser, doesn't send it up correctly, instead, it decides to replace one Object value with 'null', in an attempt to break the circle.

To give you an example, I set up a CFC, which had a UUID for identity, and a reference to a child (download the code below to have a look), and an appropriate VO on the Flex side.

I then sent this to Flex, as a cyclic graph of objects, like so:

<cfcomponent output="false">
    <cffunction name="getRecursive" hint="returns a circular CFC structure" access="remote" returntype="flexrecursive.Recursive" output="false">
        <cfscript>
            var a = createObject("component", "flexrecursive.Recursive");
            var b = createObject("component", "flexrecursive.Recursive");
            var c = createObject("component", "flexrecursive.Recursive");

            a.setChild(b);
            b.setChild(c);
            c.setChild(a);

            return a;
        </cfscript>
    </cffunction>
</cfcomponent>

So, like above, A knows about B, B knows about C, and C knows about A.

I then passed this up to Flex, and logged whether or not the children in the collection of Objects was null.

In theory, I should be able to run the following code quite happily, without fear of a NullPointerException:

//rec is the returned objects to Flex
trace(rec.id);
trace(rec.child.id);
trace(rec.child.child.id);
//this should output the same id as the 1st line, as they are the the same object
trace(rec.child.child.child.id);

But what happens when I run my test code is:

* retrieved recursive CFCs, should be 3 items in a recursive graph:
rec.id:
id: F47E1371-C2A7-D498-1F6497AA3F3AEBC8
rec.child.id:
id: F47E1375-A404-D99C-50675EB12C98F9B9
rec.child.child.id:
id: F47E1378-A4AA-57E4-192C2A59D73A9832
rec.child.child.child.id:
This child is null!!!

The Serialiser simply replaces 'null' for the last place in the graph, rather than having a reference to the first Object!

I've run this code through Charles, and have confirmed this is also the structure CF sends in AMF as well.

Looking at the AMF Specification, I read:

'Objects can be sent as a reference to a previously occurring Object by using an index to
the implicit object reference table. Further more, trait information can also be sent as a
reference to a previously occurring set of traits by using an index to the implicit traits
reference table.'


So it should be possibly to handle a cyclic graph of objects, as you could simply insert a reference to a previously serialised object... so what gives ColdFusion? How come this weird and wacky behaviour?

This test was run with ColdFusion 8.01, and Flex 3.2.

If you wish to download my CF and Flex test bed, you can from here.