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

28 January 2009 08:07 AM 0 Comments

ColdDoc 0.2 Released

Not a huge amount to report here, this release fixes a bug in which if there is no 'init' method on a CFC, ColdDoc ends up throwing an error.

You can download ColdDoc 0.2 from here .

26 January 2009 01:11 PM 0 Comments

CFUG Melbourne 2009 Survey

We are conducting a survey to try and tailor CFUG Melbourne to best fit the ColdFusion users in Melbourne, and provide you guys with the best CFUG we can.

Please take 10 minutes to fill out this quick survey on Google Docs, we would greatly appreciate it:
http://spreadsheets.google.com/viewform?key=pJCuG-fQNocTuTRAdDmagGg&hl=en

There are also prizes for filling out the survey! If you write your email at the end of the survey, you will be in the running for:

1st prize: An Adobe Backpack
2nd Prize: A copy of the latest Fusion Authority Quarterly Update (Vol III, Issue 1)
3rd Prize: A Metal Adobe Lunchbox

More details on the user group can be found on the Adobe Groups page .

Thanks for taking the time, and look forward to seeing you all at a CFUG meeting this year.

 

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.
13 January 2009 08:30 AM 9 Comments

Encapsulating Common Exceptions in ColdFusion

When throwing exceptions in ColdFusion, we have the mighty <cfthrow> tag, which allows us to throw exceptions, with given names, and then catch them elsewhere in our application.

For example:

<cftry>
   <cfthrow type="myException" message="This is my custom exception" detail="This is my custom exception detail"/>

   <cfcatch type="myException" />
      <cfset writeOutput("Caught Exception") />
   </cfcatch>
</cftry>

Would output 'Caught Exception' onto the screen, as the cfcatch 'type' matches the name of the Exception being thrown.

This is all very well and good for a 'once off' throwing of an exception, but what happens when an Exception type is used across an code base?  Often I have found myself copy and pasting <cfthrow> statements, just so I can have consistent types, messages and details between Exceptions within a system.

Taking inspiration for the way in which Java has actual Exception objects, which can be implemented and then reused, I came up with the following solution, which I felt was quite elegant, and extensible.

It all starts with a single, lowly Exception.cfc, that looks a little like this:

<cfcomponent name="Exception" hint="Throws a given exception" output="false">

<cffunction name="init" hint="Constructor" access="public" returntype="void" output="false">
    <cfargument name="message" hint="the message to throw" type="string" required="Yes">
    <cfargument name="detail" hint="the detail in which to throw" type="string" required="Yes">

    <cfthrow type="#getMetaData(this).name#" message="#arguments.message#" detail="#detail#">
</cffunction>

</cfcomponent>

..and while this doesn't look like much in and of itself, it becomes quite useful when we start extending it, and using it create our own Exception types, for example, we can rewrite the example above, as myException.cfc:

<cfcomponent name="myException" hint="Throws myException" extends="Exception" output="false">

<cffunction name="init" hint="Constructor" access="public" returntype="void" output="false">
   <cfset super.init("This is my custom exception", "This is my custom exception detail") />
</cffunction>

</cfcomponent>

To then throw myException, I simply do:

<cftry>
  <cfset createObject("component", "myException").init();

   <cfcatch type="myException" />

      <cfset writeOutput("Caught Exception") />
   </cfcatch>
</cftry>


..and the exception will be thrown, with the type 'myException', which comes from the name of the CFC, without me having to write the same message, and detail over and over again.

To get more complicated, and to lift an example directly out of Conduit , this is the exception that gets thrown when Conduit can't find a particular method on a CFC it's making a Flex Remoting call to.

<cfcomponent name="MethodNotFoundException" hint="Exception for method not being found" extends="Exception" output="false">

<cffunction name="init" hint="Constructor" access="public" returntype="void" output="false">
    <cfargument name="component" hint="the component that the method is attempting to be called on" type="any" required="Yes">
    <cfargument name="methodName" hint="the name of the method" type="string" required="Yes">

    <cfscript>
        super.init("The method '#arguments.methodName#' in '#getMetaData(arguments.component).name#' could not be found.",
                    "This method could not be found. Please ensure that it was spelled correctly, and is not private"
                    );
    </cfscript>
</cffunction>

</cfcomponent>


In this case we take a component and a method name as an argument, and can build Exception messages and details, based on those arguments, much like you can with Java Exceptions. However, the actual Exception type in this example will actually end up being 'conduit.exceptions.MethodNotFoundException', as this CFC is found in /conduit/exceptions/MethodNotFoundException.cfc.

Now that your Exceptions are encapsulated inside CFCs, you can use them all over your code base, knowing the Exception type will not change, and you don't have to copy and paste your messages and details every time you want to use them.  There are other ways of doing similar things, but this is one way I found works well for me.