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

26 November 2012 04:02 AM 1 Comment

Simplify Threaded Processing with FutureThreadedWorker

Having worked with both Groovy, (J)Ruby and, Java and (to a much smaller degree) Clojure, I can pretty easily claim that ColdFusion's threading and distributed processing capabilities.. leave a little to be desired. (Okay, actually a whole lot).

There are solutions though - using a job queuing system like Amazon SQS, IronMQ, or if you are looking for a something more threaded, dig into Marc Esher's awesome cfconcurrent project.

But sometimes you just want to take an array of values and run them through some sort of processing in a threaded manner, without having to jump onto any other projects or infrastructures, and without having to write that nasty <cfthread> create and join pattern for the millionth time.

So I wrote a quick CFC I've called 'FutureThreadedWorker', which does exactly that, without half the code you would otherwise need. (Note: this was written for ColdFusion 9. It would be a bit nicer if I could use closures)

<cfscript>
   //create, passing in an array for the array of structures (which are the arguments passed to the workerMethod)
   //then pass it the worker to call the worker method on
   //tell it how many thread it's should use
   //finally, tell it the name of the method to invoke.
   var future = new services.util.FutureThreadedWorker(queue, this, 5, "doWork");

   //start the running
   future.run();

   //if I want the results, wait for them.
   var results = future.get();

   //if i want to check for errors
   var errors = resuls.getErrors();
</cfscript>

Bam. That's it.  The FutureThreadedWorker now loops around the passed in array, and passed in the arguments to the method specified on the worker without you having to worry about creating threads or joining them back up again. I think you'll find that a lot easier than using <cfthread>.

03 October 2012 08:05 AM 1 Comment

cf.Objective(ANZ) is only a Month Away!

Wow, time flies!

Seems like only yesterday I was doing the closing remarks on the last cf.Objective(ANZ), and now it's already around the corner.

This year is going to be great once again, with lots of top notch speakers and a program that is going to be really interesting as well!

The sessions that I'm personally looking forward to are:

Functional Programming with Clojure & CFML - the best of both worlds?
I'm personally getting more and more into functional programming (or even just writing my OO code with more of a functional style). It's definitely something that is picking up steam all over the place, so I'm keen to see what Kai has to say.

Railo CLI
I'm doing a lot of (J)Ruby work these days, and I'm pretty much living in the console with the great tooling it has in this department. I'm really keen to see what advancements that Railo has made in this area, and see if there are opportunities there for cross pollination.

Building the Olympics
This should have some very interesting war stories of a site that is truly web scale.

Using nginx With ColdFusion
I've always been intrigued by nginx as I've seen it used in many places, but never looked into it itself. I know people that swear by it, so I'll be interested to learn more about nginx.

The Ugly Truth about Frameworks
This is just going to be fun :)

What sessions are you guys looking forward to?

29 May 2012 11:47 AM 1 Comment

ColdFusion 10 with Ubuntu Upstart

Setting up ColdFusion 10 on an Ubuntu Server, and as per usual, the installation option to start up ColdFusion when the server starts does not work on Linux.

So I wondered how hard it would be to set this up using Upstart, and it was surprisingly easy with a few bit of trial and error.

This is what I would eventually came up with:

Unfortunately, I would like this to respawn if it somehow dies, and it doesn't look like this style of setting up will work for that.

Anyone else tried this? What did you come up with?

cf.Objective() 2012 Slide Decks

In case anyone would like access to them, here are my slide decks for the two presentations that I gave at cf.Objective() this year.

The first one is Getting closure on Closures - this can be run directly from ColdFusion 10, as a html slide deck which includes the running code.

The second one, A/B Testing with Squabble can also be found online. I made this pubic because Sean Corfield asked me to, but in all honesty, if you weren't at the presentation, it probably won't make much sense to you. Pictures of Storm Troopers in front of computer screens are not particularly descriptive.

Overall cf.Objective() was a great confidence, yet again, much kudos to those that organised the event!

27 March 2012 07:34 AM 6 Comments

ColdFusion 10 and Closures: The Sesame Library

Writing my presentation for cf.Objective(), Getting closure on Closures, I found I was writing a few common utility functions for use with Closures to use and show in my talk, and as general utilities for coding.

I wanted to bundle these functions into a project, and put it on Github so that we could all share various utility functions that would be useful now that ColdFusion has got Closures available to us. I went looking for an existing project that was already doing this, but since I couldn't find one, I figured I would start one, and see what happens from there!

The project's name is Sesame (much thanks to Ben Koshy for the name), and currently only has a few functions which can be cfincluded into your code, but they were the ones I found most useful when doing some recent work with Groovy, and wanted to have them on hand when doing similar things in ColdFusion.

Here are a few examples:

From the collections include, the _collect functions allows you collect values from one array or struct, by iterating a closure over the passed in collection, and collecting the results returned from that closure.

For example, if I wanted to get all the names from an array of Employees, I could do the following:

var employees = listEmployees();
var names = _collect(employees, function(employee) { return employee.getName(); } );

This would then give me an array of all the employees name in the list.

My other favourite, is _groupBy(), which gives you an easy way to group an array or struct of items into a structure of items that have been grouped by a value returned from a closure.

For example, I could easily group an array of employees by their salary, like so:

var employees = listEmployees();
var grouped = _groupBy(employees, function(employee)
              {
                 if(employee.getSalary() < 100)
                 { return "Less Than 100"; }
                 else if(employee.getSalary() > 100 && employee.getSalary() < 200)
                 { return "Greater than 100, Less than 200"; }
                 else
                 { return "Greater than 200"; }
              });

From there, I can now get at all the employees that earn less than 100, by referenceing them as grouped["Less Than 100"], and so on.

From the numbers include, I really like the _times() function. Simply put, it executes a closure a certain number of times!

_times(6, function() { writeOutput("Write me 6 times!"); });

Nothing too complicated there, but it can be quite useful.

From the concurrency include, there is a function that was directly inspired by the GPars Groovy library (and awesome concurrency library for Groovy). _eachParrallel() will execute the closure for each item in an array or struct, but execute the closure in its own cfthread implementation, allowing for an easy way to parallel process data. When it is done, it joins all the threads back up again, so there is no need for you to do deal with managing the threads yourself.

For example, summing up each item in an array, each in it's own thread:

var values = [1, 2, 3, 4, 5];
var total = 0;
_eachParallel(values, function(it) { total += it; });

Gives us a total of 15.

If you find this interesting, please feel free to download, use and also contribute. I know there are a million more functions that could yet be implemented, and I've already implemented the automatic documentation generator - so as long as your functions have appropriate hinting, it becomes super easy to regenerate the README.md file! So no hard work there.

I'll also be showing this library off as part of my cf.Objective() talk on Closures - so please pop by if you want to see more about closures in ColdFusion 10, or just about closures in general.

17 February 2012 10:06 AM 0 Comments

JavaLoader 1.1, and a Move to GitHub

A couple of new items in this release of JavaLoader:

The new function, swithThreadContextClassLoader() is useful as it is often required when dealing with libraries, such as dom4j, that use the ClassLoader to define singletons or search for implementing classes, and don't allow you to overwrite what ClassLoader they use. Check out the wiki for more details on why this is neccessary, and how easy it is to now do, thanks to our new function!

Also, JavaLoader has been move to GitHub, along with the all the documentation. This should make collaboration much easier moving forward!

Otherwise, make sure to sign up to the mailing list, and enjoy loading your Java.

Speaking at cf.Objective() 2012!

I'm delighted to say that I'm speaking at cf.Objective() again this year!

I've got three sessions I'm presenting this year, two of which on my own, and one in which I'm paired with with Luis Majano.

cf.Objective()

I'll be talking about:

A/B Testing with Squabble

In which I extol the virtue of A/B testing, and why you should be doing it in your business, and introduce people to the A/B testing framework Squabble that we developed to use in the team I work with.

Getting closure on Closures

Where we will look at Closures, which are coming in ColdFusion Zeus. You probably already use these, and don't even know it. I'll explain what closures are, and how you can use them in simple ways, as well as more interesting use cases as well.

AOP Demystified!

This is the session I will be doing with Luis Majano, where we will talk about Aspect Oriented Programming, and give you examples with the two primary AOP frameworks - ColdSpring and Wirebox. Should be good stuff!

All up, it looks like it's shaping up to be a great conference program, so I look forward to seeing everyone there!

19 December 2011 07:41 PM 0 Comments

Custom Schemas in Coldspring 2

One of the most powerful new features in Coldspring 2 is the ability to create custom xml schemas that can be used within your XML configuration.

Rather than go into the details of how to write and configure custom schemas, here is an example of one that comes bundled with CS2 out of the box.

In Coldspring 1.x, if you ever wanted to create a standalone structure inside your XML configuration, you would quite commonly create it through a MapFactoryBean like so:

<bean id="myMap" class="coldspring.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
    <map>
        <entry key="keyA" value="keyA value"/>
        <entry key="keyB" value="keyB value"/>
        <entry key="keyC" value="keyC value"/>
    </map>
</property>
</bean>

This is all well and good, but the issue here is that you specifically need to know the api of the MapFactoryBean.  If you get any part if the configuration of the MapFactoryBean wrong, you tend to get errors that may not be clear, or potentially no error at all, simply a result that is not desirable.

For example, if you misspell the sourceMap property, Coldspring will attempt to set the property, but it doesn't throw an error when it fails.

<bean id="myMap" class="coldspring.beans.factory.config.MapFactoryBean">
<property name="sourcMap">
    <map>
        <entry key="keyA" value="keyA value"/>
        <entry key="keyB" value="keyB value"/>
        <entry key="keyC" value="keyC value"/>
    </map>
</property>
</bean>

Therefore, all you will get back is an empty struct, and quite possibly a headache trying to debug exactly why this is happening in your code.

In ColdSpring 2, there is a nice, convenient util  custom schema, that exists to do things like create arrays, lists and other data structures for you.  It essentially is a simple wrapper around things like the MapFactoryBean, but the custom schema gives you a code completion and hinting when using an XML editor (that support XML Schemas), as well as better error messages when things go wrong.

So, for example, if I wanted to do exactly the same configuration as above, I would add the xml namespace for util in the head of my xml file, like so:

<beans xmlns="http://www.coldspringframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:util="http://www.coldspringframework.org/schema/util"
        xsi:schemaLocation="http://www.coldspringframework.org/schema/beanshttp://coldspringframework.org/schema/coldspring-beans-2.0.xsd
        http://www.coldspringframework.org/schema/utilhttp://coldspringframework.org/schema/coldspring-util-2.0.xsd "
>

Which would enable the <util:> namespace in my XML editor, and I could quickly type out:

<util:map id="myMap">
        <entry key="keyA" value="keyA value"/>
        <entry key="keyB" value="keyB value"/>
        <entry key="keyC" value="keyC value"/>
</util:map>

And we would have the same result as above, but if something went wrong with your syntax, the IDE should show you what it was, and if it didn’t, you would get a nice error from the XML validation letting you know exactly what it was.

Of course, the whole point of this post, is due to the extensible nature of ColdSpring, you can write your own custom XML namespaces, and register them with your XmlBeanFactory, to do things in very concise and easy to use manner inside your IDEs as well.

This is a very simple example of what can be done with Custom xml schemas. You can drastically change the nature of the BeanFactory as well as the contained beans through this mechanism, but this should hopefully give you a little bit of a taste of what can be done with this new functionality.

09 December 2011 08:30 AM 0 Comments

ColdSpring 2 is available on GitHub

This is something I did a while ago, but for whatever reason, totally forgot to announce publicly.

Thanks to the power of distributed version control, there is a copy of the Git repository for ColdSpring 2 on Sourceforge, as well as one on GitHub.

It goes without saying that GitHub really is the best place for Open Source projects to manage and allow for collaboration with other developers, so it makes sense to have a copy of ColdSpring 2 on GitHub as well.

So get your forks ready, and make some pull requests! :)
07 December 2011 11:19 AM 0 Comments

ColdDoc 1.0 Release (and a move to GitHub)

ColdDoc is one of those projects I don’t work without these days. No matter the project, I’ve always got a stack of CFCs in it, and I need a way to document what objects I have, and what methods they have on them. A great example being the ColdSpring 2 project.  I’ve got my local Jenkins install hooked up to generate the ColdDoc documentation on each run, and I usually run it locally often while developing, so I have an up to date reference of what methods are available to me, without having to dig into actual CFC code.

ColdDoc has been ready for 1.0 release for quite a while, but has yet to be formally pushed out into the wild.

With a little push from behind from @vanderwoud, I got my planned migration of ColdDoc to GitHub into gear, and all is now complete.

Now ColdDoc is hosted on GitHub, which is great, because it really is the best place to allow for community contributions, as well as the documentation ported over into the Wiki.

ColdDoc 1.0’s big new ticket item is interface support (although it doesn’t support multiple interface inheritance), as well as lots of little bug fixes.

So if you are ready to get your automated documentation on, grab a copy of ColdDoc, run it against your current code base, and see what comes out!

And if you have any contributions you would like to make to ColdDoc (and I’m sure there are some out in the wild), please issue a pull request against the repository.
25 October 2011 12:38 PM 0 Comments

ColdSpring 2 Documentation Competition - Win a Copy of CFBuilder!

With the rewrite of ColdSpring , a whole load of documentation also needed to be ported, and in some cases, actually written for the first time, for existing functionality as well as new functionality.

Unfortunately it became a real sticking point with getting a release of ColdSpring 2 out of the door.

While the documentation isn’t quite complete, there is enough there to get people started, and it can be fleshed out on a case by case basis.

That being said - to help make the documentation complete as quickly as possible, there is now a competition to win a copy of ColdFusion Builder, and the way to enter is to write documentation for ColdSpring 2.

The rules are very simple: To make this more enticing, and also a whole lot easier, I’m offering each person who wants to enter my Skype and IM details.

Skype: mark_mandel
Gtalk & MSN: mark.mandel@gmail.com

I’m happy to have a 10-15 minute voice chat with potential entrants explaining a feature if they are new to it and/or guiding them in what I had in mind for the documentation page, and give whatever other advice they need via IM and email to help them complete their documentation page.

So not only is this a chance to help out the ColdSpring and ColdFusion community, it’s a chance to win FREE copy of ColdFusion Builder, and also it’s a great opportunity to pick my brain on ColdSpring 2 (which should hopefully be worth something as well  :) ).
25 October 2011 12:35 PM 1 Comment

ColdSpring 2 Alpha 1 Released

After a long 2 years of development, ColdSpring 2, Alpha 1 is ready for release!

It’s been a long road getting here, but with the rewrite of ColdSpring, means that ColdSpring 2 comes with a stack of new functionality that should help you out with all your dependency injection needs, and then some!!!

To give you a quick overview of some of the major new functionality that comes with ColdSpring 2:

XML Schema For ColdSpring

No more needing to guess what XML to write with ColdSpring, or use a not-quite-right-fit Spring.dtd or XSD to give you code completion and hinting with your XML.

Now with a XML editor that supports XML Schemas (Eclipse Web Tools Project jumps to mind) and a quick XML schema declaration at the top of your XML, you now get total code-completion, and built in help with your XML elements. Makes life much easier!

AOP Custom XML Namespace and AOP Expressions

This is one of my favourite features, as it just make Aspect Oriented Programming with ColdSpring and absolute breeze.

Gone are the days of ProxyBeanFactories and NamedMethodAdvisors. Now you have a simple scripting language for defining where you want Aspects to be applied, and what you want them to do.

For example, if I had the following XML:

<beans xmlns="http://www.coldspringframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:aop="http://www.coldspringframework.org/schema/aop"
   xsi:schemaLocation="http://www.coldspringframework.org/schema/beans http://coldspringframework.org/schema/coldspring-beans-2.0.xsd
   http://www.coldspringframework.org/schema/aop http://www.coldspringframework.org/schema/coldspring-aop-2.0.xsd"

   >


   <!-- AOP configuration -->
   <aop:config>
      <aop:aspect ref="timer">
         <aop:around method="timeMethod" pointcut="execution(public * *(..))"/>
      </aop:aspect>
   </aop:config>

   <bean name="timer" class="com.Timer" />

   <bean name="fooService" class="com.FooService" />

</beans>

What this says is, for the given pointcut, execution(public * *(..)), which translates to any method execution, which is public, and returns any variable, with any method name, and any number of arguments (i.e. every method), call the method timeMethod on bean timer around that method.

So when do call fooService.doSomething(). Our Timer Component, will be able to log how long it took, and as you can see, no need for complicated ProxyBeanFactories, target beans or anything of the sort. All nice and clean and concise.

This is by far, just the surface of what is possible with the AOP XML namespace and AOP expressions in ColdSpring. There are more configuration options, and many more different types of expressions that are possible.

ColdFusion 9 ORM Integration

Injecting other objects into your ORM Entities can be a tricky prospect, but ColdSpring 2 comes bundled with a stack of utility objects that make this much easier, as well providing you with additional functionality to help you out with common ORM tasks as well.

ColdSpring 2 comes with a BeanInjectorEventHandler, whose job is to intercept when Entities are loaded, and inject them with whatever dependencies are loaded.

To intercept when new Entities are created, ColdSpring 2 has a SessionWrapper object that provides an interface to the underlying Hibernate Session, from which you can request new Entities, list, save, delete Entites and much more.

The SessionWrapper also enables some more advanced configuration options above and beyond ColdFusion’s basic settings, including being able to set a default Hibernate Session Flush Mode, and implementing a strict transaction mode as well.

This is just a start to the ORM integration, there is plenty more bundled into ColdSpring 2!

Multiple Bean Scope Support

ColdSpring 2 has a totally new and reworked bean creation process, so that not only can it create transient and singleton beans, but it can also tie beans to request and session scopes as well. To do this, it has a new scope attribute which replaces the old singleton attribute on beans.

Therefore to define a bean as a singleton, you not define:
<bean id=fooService class=com.FooService scope=singleton>

To define a  transient bean:
<bean id=fooService class=com.FooService scope=prototype>

To define a request scoped bean:
<bean id=fooService class=com.FooService scope=request>

(And I’m sure you have the pattern by now) To define a session scoped bean:
<bean id=fooService class=com.FooService scope=session>

This gives us even more control over the life-cycle of our beans, to enable some very powerful capabilities in our applications!


There is a lot more to ColdSpring 2 than just the above, but hopefully that will give you enough of a view to entice you to take the framework for spin.

More details can be found in the Release Notes, ColdSpring website, and Trac site.

Also, if you are interested in going into the running for winning a copy of ColdFusion Builder, check out the ColdSpring documentation competition currently running to aid in fleshing out the rest of the documentation for ColdSpring

12 October 2011 07:55 AM 9 Comments

How I Configure ColdFusion ORM and Why

I’ve been reading quite a few mailing list posts on ColdFusion based ORM, and I find that I’m seeing a lot of repeats on what configuration settings people are generally using when setting up ORM in their Applicaiton.cfc, and why they should use certain settings.

I figured it would be useful if I wrote down how I like to have my base configuration of my Application.cfc in regards to ORM, and also take a step by step look through why I set things up the way I do.  Hopefully this will help out a few people when they first start out with ORM, and are looking at all the different options for ORM in ColdFusion.

<cfscript>
   this.datasource = mydatasource;

   //orm settings
   this.ormEnabled = true;
   this.ormSettings.cfclocation = expandPath("/model");

   this.ormSettings.automanageSession = false;
   this.ormSettings.flushatrequestend = false;

   this.ormSettings.useDBForMapping = false;

   this.ormSettings.autogenmap = false;

   if(isDevEnvironment())
   {
      this.ormSettings.dbcreate = "dropcreate";
      this.ormSettings.sqlscript = expandPath("/import.sql");
   }
</cfscript>

So breaking this down line by line.

this.datasource = "mydatasource";

This isn’t specifically an ORM setting, but I love how in CF9, we can set a default datasource across the application in one place. Also like that ORM picks this up too, although it can be overwritten with ormSettings.

this.ormEnabled = true;

Again, nothing special. We turn on ORM. Without this line, nothing happens.

this.ormSettings.cfclocation = expandPath("/model");

When ORM is enabled, by default, ColdFusion will scan from your web root, looking for any CFC’s that are marked as persistent. As a performance enhancement, it’s useful to tell it specifically what folder to look at.  Also, if you have your components stored in a mapped directory, this is the only way it can be done.

I’ve seen this set a few ways (dot notation, relative paths), and seen a fair few people have issues with this. Personally, I’ve never had an issue when using the expandPath(), so I stick with that as the way to go.

this.ormSettings.automanageSession = false;
this.ormSettings.flushatrequestend = false;

I bundle these two together because they are quite related in what they do. They basically control how the Hibernate session works in ColdFusion ORM. This combination of settings does the following:

For me, this is very, very, very important. The default setting of having these both on for ORM makes doing basic things with ORM very easy, but when you start getting into more complex scenarios, in which issues like object validation or concurrency arise, these default settings can throw some fun Hibernate exceptions on your screen super fast.

By setting the above to false, you have complete control over when a session will flush (only when a transaction commits), and you know it will only be cleared when you request it to be. This makes it a lot easier to manage your Hibernate object states in those more tricky scenarios.

(You can use ormFlush() with the above settings, but please don’t do that. Please use transactions. Your database will thank you.)

this.ormSettings.useDBForMapping = false;

This is primarily a performance setting. By turning this off, it stops ColdFusion from going out to your database and looking at what tables and columns you have and attempting to generate it’s object mappings from there. Personally I can’t stand this functionality, as your DB then drives you model (not an ideal scenario), and also because, if you are using annotations / HBMXML config files, there is absolutely no reason to do this (and I’ve read of people on Oracle having crazy issues with having this enabled by default as well).

this.ormSettings.autogenmap = false;

This setting is most definitely a personal preference thing. When I work with ORM I use the HBMXML mapping files, as every time I use the annotations, I find it doesn’t default the way I would expect/want, or I am looking to use some Hibernate functionality that isn’t exposed through annotations. Then I have to go back and move all my configuration from annotations to a HBMXML file. It’s far easier to me to start with a HBMXL file, and never look back. Since I also have a CFBuilder extension to help generate the stub files, it makes it an easy decision.

Setting autogenmap to false, means that even if someone were to come along and use annotations, they wouldn’t work, so it makes sure I don’t have that "Just this once I’ll do annotations..." thought which inevitably leads me back to rewriting annotations into HBMXML again.

this.ormSettings.dbcreate = "dropcreate";
this.ormSettings.sqlscript = expandPath("/import.sql");

This setting is more for greenfield projects. On legacy projects, I find that they tend to frown on having all their development data dropped, for obvious reasons, and it can be a large project to write an import script for it all.  However, when starting from scratch, it’s really nice to have a clean data set on every reload, especially from a unit testing perspective.

There are many more settings that can be used, that are generally more application specific, such as the SQL dialect, or whether or not you enable the second level cache, but this is generally speaking, the base configuration I start most project from.

28 September 2011 09:28 AM 0 Comments

Using ColdFusion Frameworks for Application Development - Recording

If you managed to miss my talk on Using ColdFusion Frameworks for Application Development, you can catch the recording here.

I really enjoyed giving this talk, but it wasn't until I was well into the talk that I realised how much there was to cover (didn't feel like that much during practice!). I'm sure I missed several of people's favourite frameworks, but I attempted to cover the basic set (as I saw it at least), and mention as many other ones as I could to give people a feel for what was out there, and give them a place to start when choosing a single, or set of application frameworks

The whole week featured some really great talks, so if you are looking for the rest of the talks, you can see all the recordings listed here for your enjoyment.

Big thanks to Adobe for hosting the event, and Simon Free for spearheading the efforts!

07 September 2011 10:47 AM 0 Comments

ColdFusion Frameworks for Application Development @ ColdFusion Developer Week

Next week I'm proud to (slightly belatedly) announce that I will be doing a presentation entitled Using ColdFusion Frameworks for Application Development at next weeks online ColdFusion Developer Week.

We will cover a basic introduction to Model-View-Controller, Dependency Injection and Object Relational Mapper concepts, as well as take brief looks at each of the major frameworks that are available for ColdFusion in these areas.

By the end of the presentation, you should (hopefully) have a better idea of what framework options are out there for you as a ColdFusion developer, and give you a sense of which frameworks may suite your particular application, or your development style.

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

 

10 April 2011 08:22 AM 1 Comment

Tip for ColdFusion Builder - Adding a New Server via RDS

Something I (somehow) worked out a while ago for adding a new ColdFusion server in ColdFusion builder, that I'm not sure is widely known.

Adding a new server to ColdFusion Builder can be a bit of a pain, as you have to remember / work out a stack of details about the server, and make sure you get it 100% correct when enterting the details into all the boxes.  This can be even more complicated if you have a JEE install of ColdFusion, and/or are working with remote servers.

There is actually an easier way baked into Builder already!

  1. Go to Windows > Preferences > RDS Configuration (or through any one of the RDS views) and create a RDS connection to the server in question.
  2. Go to the Server View, and click 'Add a Server'. This will now give you the option of importing from an RDS connection. Do that.
  3. You should now have all the fields of the Server pre-populated for you, for a connection.
  4. Add in any extra configuration you like from here - virtual hosts, folders mappings etc.
  5. You are now done.
Isn't that easier?
06 April 2011 04:45 PM 0 Comments

I'm speaking at the cf.Objective() keynote

A little late to the party, but I'm really honoured to announce that I was invited to speak for part of the keynote at cf.Objective() in this year. I'll be joined by such venerable cohorts as Ray Camden, Scott Stroz, Jason Dean and Bob Silverberg, so it should be a great time all around, and we may even learn at thing or too as well.

Don't also forget, there are the Lighting / Pecha Kucha talks at cf.Objective() again this year. These talks are a great way to get your feet wet for presenting at a conference, and can also just be a whole load of fun, so if you are interested, sign up right away.

Either way, I look forward to seeing everyone at cf.Objective(), it's going to be a great time!

14 February 2011 06:26 PM 1 Comment

Speaking at cf.Objective() and Starting a Podcast

Lots of stuff I should have been blogging about, but haven’t managed to find the time.

First of all, I’ve been accepted to speak at cf.Objective() this year, which is a great honour.

I’m doing  talk on AOP For you and Me , which will be an extended version of the talk I did at Adobe MAX and cf.Objective(ANZ) , wherein I will talk not only about what Aspect Oriented Programming is, but also go more in depth into some real world examples.

I will also be presenting ColdSpring 2.0 Alpha 1 - What's New and Improved? In which I will discuss all the new doodads and whoogama-whatsits that come in this new version of ColdSpring , which is currently only 3 tickets away from code completion!




As per usual, I’m really looking forward to this conference. It’s always a fantastic time, and a great learning opportunity.

Also, my good friend, Kai Koenig and I, decided it would be fun to start up a podcast! (Well, he basically bullied me into it, but ssshhhh). We gave it a test run, and it was lots and lots of fun. We’re planning on talking about all sorts of Adobe stuff, ColdFusion, software engineering, and whatever else grabs our fancy.

We set up a website at http://www.2ddu.com/ , and will be posting updates there, and you can also follow the podcast on twitter @2dduPodcast . Our first installment is up there now, and please give us any feedback you have - we would love to have it.
12 October 2010 04:13 PM 3 Comments

Query Caching with Script Based Queries

I could not get query caching to work for me with Query objects, and I couldn't work out why for the longest time.  For example:

<cfscript>
    local.query = new Query(sql="select * from holidays",
                            datasource="myDS",
                            cachedWithin=createTimespan(0, 1, 0, 0));

    local.result = local.query.execute().getResult();
</cfscript>

No matter how many times I refreshed this test script, the SQL result would never cache.

The reasons why didn't click until I kept looking at the query output:

qryname49118 (Datasource=myDS, Time=1ms, Records=8) in /opt/coldfusion9/CustomTags/com/adobe/coldfusion/base.cfc @ 16:19:14.014

select * from holidays

Since I didn't need to set a name for the query, as I had a query object, the Query.cfc was giving the underlying <cfquery> a unique name on each and every call.  Since the name was unique, when ColdFusion went to look to see if the query was cached, it never found anything for that query name.

Changing the above query to:

<cfscript>
    local.query = new Query(name="test",
                            sql="select * from holidays",
                            datasource="myDS",
                            cachedWithin=createTimespan(0, 1, 0, 0));

    local.result = local.query.execute().getResult();
</cfscript>

Suddenly means the query is cached, and all is well again in the world, as the name of the query is explicitly set.

It would be great if the name of the query was a md5 hash of the SQL that is being passed in, and then at least you wouldn't have to bother naming the query something specific if you want to use the query cache. In the mean time, if you run into this issue, you now know how to work around it.

08 September 2010 06:50 AM 9 Comments

Trying the CFML Plug-in on IntelliJ

For a long time I’ve been meaning to try out the the IntelliJ CFML plug-in for two reasons. One of which, I’ve always heard really good things about the IntelliJ platform for editing Java, Groovy and Flex, and also because as a Linux based ColdFusion developer, my CFML IDE options are limited.

So I decided I was going to get some work done on JavaLoader, to move it into a 1.0 Final, and I was going to do it all in IntelliJ with the CFML plugin, and use that as a way of seeing how the CFML plugin was going.

Installation
Installation was the biggest hurdle for me, as I ran into a lot of issues getting the plug-in installed and running.

From what I could see, IntelliJ makes no mention that you need to set a JDK_HOME variable in your environment. Except when you first run it and get an error message. Once that was done however, it fired up with no problems at all.

For whatever reason, after running IntelliJ, the CFML plug-in didn’t show up in the plug-in list.  If it had, I’m sure things may have gone a lot smoother for me.

I then browsed to the plugin page, to download the plug-in manually.  Two things went wrong at this point.
  1. As far as I could see, IntelliJ does not describe anywhere how to install a plug-in manually. This is the only documentation I could find on installing a plug-in, and it was via the plug-in manager (see above), so it was not very helpful. It is very simple, you just unzip it and put it in the /plugins folder.
  2. I downloaded the wrong plug-in for my version on IntelliJ. I downloaded 9.03 Ultimate edition, or if you look in the build.txt file that comes with IntelliJ, that’s Build IU-95.429.  Unbeknownst to me it’s that build number that is used on the plug-in download page (See Since build and Until build ) that define what a plug-in is compatible with. Honestly I am confused as to why they don’t just use the IntelliJ product number, but maybe there is a good reason.
(Apparently this has since been fixed, and you can now install from the plug-in manager again)

Appearance
My first thought when opening IntelliJ was “Wow, this is ugly”. I’m used to working in Eclipse, and the Linux build of Eclipse takes the Ubuntu theme that is currently set very nicely. So much so that people at conferences often ask me how I get my Eclipse to look the way it does.  In IntelliJ, the text wasn’t even anti-aliased.

I quickly found an Appearance setting, and switch the theme over to GTK+, which I expect made IntelliJ use Ubuntu native GTK rendering engine, and suddenly IntelliJ matched my Ubuntu theme, and was much more pleasant to look at.  Eclipse still looks more polished, but maybe that’s just because I’m used to it.

Documentation
This is where things fall down, unfortunately rather hard.  The only documentation for the CFML plug-in is a blog that can be found here and a google group .  This project is in desperate need of a website/wiki/Google doc/anything that has some sort of structure. Skipping through blog posts and searching the google group in an attempt to find that one piece of knowledge you need is frustrating, to say the least.

Creating a Project
I go to create a project, and... there is no ColdFusion Project. Uh oh.  Fire off an email to the group and ask “What do I do now?”. (Update, I just got told to create a Java project. Weird, but it works).

In the mean time, I switch tacks, and import an existing Eclipse Project.  IntelliJ asks me for a JDK, but is happy enough when I skip over it, figuring I wouldn’t need one for a CFML project.  That worked quite well, and I’m now on my way to editing ColdFusion.

Editing Files
Code completion for variables and functions inside a CFM and/or CFC is one of the biggest priorities for me, and in the plug-in, I have to say, this feature works very well.

That being said, one thing that is missing for variable completion for me, is completion for variables such as arguments , application , server , CGI , etc, for which there are already bugs for.  That and CFC resolution is missing, which Builder does for things like createObject() etc, (somewhat).

Interestingly enough there is no “New CFM” or “New CFC”, there is only “New File”, which I didn’t find myself missing, except for when creating CFCs.  The new CFC dialogue in builder is great, and if you’ve ever worked with interfaces, having Builder generate the method stubs for you is pretty cool as well.

Overall, the responsiveness is very snappy, and code completion comes up almost instantly, which is very nice. I prefer the function hinting in IntelliJ to Builder, as it give you the hint per parameter as you are inside the method, where as Builder only tends to give you the tooltip when you first write the method.

While I didn’t get to play with it, there is also support for code completion of Java objects , including when being used with JavaLoader , which is not something ColdFusion Builder can do.

Live Templates
This is more of a IntelliJ thing, but Live Templates blow CF Builder/Eclipse Snippets out of the water. Wow.  I love being able to define a $FOO$ variable in my snippet and declaring that $FOO$ variable to complete(). IntelliJ then intelligently provides all the code completion that would normally show up if I hit ctrl+space at that point. I think I’m only just scratching the surface of what is possible with Live Templates, but this feature is fantastic.

Learning Curve
IntelliJ does some things differently to Eclipse, which takes a little while to get used to.  That being said, you can switch the keyboard commands to Eclipse style with a menu change (I did some extra tweaking above and beyond that), so that is nice.

Price

The CFML plug-in only works on the commercial version of Intellij. Licences for personal use carries a price tag that is fairly similar to ColdFusion Builder. Corporate licences cost a fair amount more.  For the functionality provided by the CFML plug-in at this stage , I would recommend that if you are on Mac/Win, stick with Builder. You will get more bang for your buck.  If you are on Linux, and refuse to move OS’s (like I am), IntelliJ is well worth an evaluation, as the price tag is very reasonable, and if you are looking to do Groovy, Flex or Java work, IntelliJ already has that functionality bundled in.

Overall
I have to say, once I got over the initial hurdles of installation, and documentation, and became more comfortable with IntelliJ as a whole, it because a really nice IDE to work in.  There are plenty of rough spots around the edges, but I think with a few more revisions, this plug-in could easily be a decent contender for ColdFusion Builder (especially if it gets a debugger).

If you are looking to purchase an IDE, I would still say stick with ColdFusion Builder for now if you are on Mac/Windows, but if you are on Linux, and don’t want to move, IntelliJ looks like a dark horse to watch in the ColdFusion IDE space.

Learning More
If this has piqued your interest, the best place to really learn about this plug-in is the google group, so sign up there. The blog is also good for information about new releases and what new features are available.

01 August 2010 04:53 AM 0 Comments

cf.Objective(ANZ) Student Ticket Giveaway

Our wonderful sponsor Fasthit has kindly provided us, not only with a ticket to give away to a student living in Australia or New Zealand, but is also paying for flights and accommodation as well for the lucky winner.

The rules are simple:
  1. You must be an Australian or New Zealand Resident
  2. You have to have a valid student identification.
  3. You must be under 25 years of age.
  4. You need to send an email to contest@cfobjective.com.au, with no more than 200 words stating why you would be the best person to win this competition.
...and that is really about it.

The winner with the best entry will be announced on the 1st of September.

If you are a student, make sure you enter for a chance to win! If you aren't a student, but know someone that is, make sure to pass on the message.

For more details, have a look at this news post.
29 July 2010 11:58 AM 0 Comments

cf.Objective(ANZ) 2010 in Full Swing

There has been so much going on with cf.Objective(ANZ), that I haven't even had time to blog about it!

In case you missed the announcements, the pricing is now online, with the early bird price being lower than last years, at $749.00 including GST, valid until the 31st of August.

There are a series of 1 day workshops the day before the conference as well, covering ColdFusion Performance tuning, Flex 4 and ColdFusion, and Arduino hardware with ColdFusion.  Charlie Arehart, Kai Koenig, and Justin McLean are running these workshops respectively, and you couldn't ask for better instructors.

While each track of the 2 day conference has yet to be finalised, almost all of the sessions that will be available are now online , and we have some fantastic content again this year, with some speakers that I am very excited about.  The usual slew of amazing ANZ dignitaries will be joining us, also with international speakers such as Gert Franz, Mark Drew, Mark Blair, Mike Brunt and Tim Buntel (Or maybe 'semi-international' would be a better fit? Mark Blair moved to San Francisco and then came back, Tim Buntel now lives in Sydney... ;o) ).

I'm really happy with the way this conference is coming together this year, and providing some really unique ColdFusion content for the ANZ region.  We've got some great training, some great speakers, some great sessions, it's looking like it's going to be a fantastic time all around.
13 July 2010 01:15 PM 0 Comments

Adobe MAX Pre-Conference - Getting Started with ColdFusion 9 ORM

Bob Silverberg and I are back at it again, with a one day pre-conference lab at Adobe MAX this year covering an introduction to Object Relational Mapping in ColdFusion 9.

As the description states:
Learn about one of the most compelling new features in Adobe ColdFusion 9 from two seasoned ColdFusion veterans. This release includes the integration of Hibernate, an enterprise-class, Java based ORM. Join us to hear how to get started using ColdFusion 9 ORM features in your next project. Through interactive learning and hands-on labs, we'll start with the basics and work together to add features to an application that takes advantage of the ORM. Then we'll discuss best practices and potential pitfalls, making this an ideal combination of introductory material and tips and tricks.
If you are interested in getting your feet wet with ColdFusion 9 ORM, you can get more information on the MAX pre-conference page .

Hope to see you there!
25 June 2010 01:06 PM 0 Comments

Dzone RefCard - Leveraging ColdFusion 9 Exposed Services from Java

In ColdFusion 9, several Web Services come pre-built with the product, allowing greater interoperability between different technologies and ColdFusion.

The other day saw the release of my Dzone RefCard outlining how you could take advantage of these Web Services from Java, and use ColdFusion's

If you are doing Java development, and are looking to integrate some of ColdFusion's capabilities into your application, you can download the RefCard from here .  It will step you through setting up the Services, generating the required Java code to run the Web Services, and also provides examples of usage to help you get started.

You can also read more about ColdFusion Web Services here .
18 May 2010 08:30 PM 1 Comment

Presenting ColdSpring 2.0 on CFMeetup.com

On 6pm US ET, Wednesday May 19 I will be presenting Dependency Injection Redefined - ColdSpring 2.0 to the CFMeetup Crowd.

For those of us in more southern parts of the world, that is 8:00am, the 20th of May, Australia.

This is the same talk I recently gave at cf.Objective() and WebDU .

Synopsis:
ColdSpring 2.0, codename Narwhal, is a complete rewrite of ColdSpring aiming is to provide a far more extensible architecture and many more features above and beyond what is currently provided with ColdSpring to date. These new features will give developers the capabilities to build and manipulate this Inversion of Control framework in fascinating and very powerful ways, thus saving them even more time when managing their dependencies and utilising functionality such as Aspect Oriented Programming.

In this presentation we will look at the new features of ColdSpring 2.0, both complete and envisioned, including functionality such as extensible schema support, events for bean life-cycles, enhanced AOP support, annotation support, and much more.

More details and rsvp can be found here .

Look forward to seeing you there!
13 May 2010 12:49 PM 11 Comments

Some arguments against "Linux users don't pay for software"

As many people probably know, I'm a huge proponent of Linux operating systems, most specifically Ubuntu, not only because its open source, and free, but mostly because I honestly believe it's the best operating system I've ever come across.

For obvious reasons, I spend a bit of time trying to convince a variety of people that Adobe should take a serious look at bringing Adobe products to Linux, the most notable being ColdFusion Builder.

One argument (and there are a few) against this, I hear over and over is this idea that "Linux Users don't pay for software".

Up until now, the only evidence to the contrary has been anecdotal - i.e. I personally have paid for CrossOver Office, Vmware Workstation, CrashPlan, World of Goo and Caster.  That being said, anecdotal evidence doesn't tend to be very convincing.

Recently, however, the "Humble Indie Bundle", was put up for sale, in which 5 cross platform games (Win, Mac, Linux) were sold together as a group. The real time data for sales and the operating system splits has been shared, providing us with a wonderful aggregate data about the difference between Win, Mac and Linux users, how much they are willing to pay for software, and if they are willing to pay at all.

The fun part of this experiment was that the customer could choose how much they paid for the bundle, which could be as little, or as much as people liked.  It also could be split any way between the developers, charity, or charity and the developers.

Some interesting stats to note (Taken from the real time stats as of this moment):

1) Current intake across Win, Mac, and Linux - $1,173,536 (which is just cool in and of itself)
2) Windows has the largest market share (no surprise there), with 86670 purchases.
3) Linux is the smallest number of purchases, with 21873 purchases, but that is only 8153 purchases, less than the Mac platform - 30026
4) The big news here is that Linux people paid more on average than either Mac, or Windows users.
Win: $8.06,Mac: $10.23, Linux: $14.53
So much so, that the total income from Linux users, outstrips that of Mac, even though Mac had more purchases (Mac: $307172.75, Linux: $317846.61)

I don't think you can ask for a better experiment than this.  If Linux users wouldn't pay for software, then they would be at the bottom of the list in terms of amount paid. Instead that's where Windows users sit.

Details of the Humble Indie Bundle can be seen here:
http://www.wolfire.com/humble

Their realtime JSON feed can be found here as well:
http://www.wolfire.com/humble/stats

(And they are some cool games as well)

On another note, Valve have announced that they are releasing their Steam Source Code client to Linux. This is a huge boon to the Linux community, and while there are no dates yet, obviously Valve thinks there are people in the Linux community who will pay for software, otherwise they wouldn't be putting in the time and effort.

Therefore, you can quite clearly see that Linux users will, and do pay for software, and in fact put a higher cost on software than any other OS's user base.

I claim this myth well and truly busted.
03 May 2010 05:33 PM 2 Comments

ColdSpring Framework on Twitter

Just a note to let everyone know I set up a twitter account for ColdSpring.

It has automated updates for Git commits, and ticket events. It should be a good resource for helping people keep up to date with the going-on's of ColdSpring, and especially ColdSpring 2.0.

Follow coldspring_fw on Twitter!

29 April 2010 11:59 AM 0 Comments

ColdSpring 2.0 - Now On SourceForge

Up until recently, the goings-on of what has been happening in ColdSpring 2.0 has been fairly limited to my twitter account.

At cf.Objective(), I did a presentation entitled Dependency Injection Redefined - ColdSpring 2.0 Narwhal where I outlined what work had been done on ColdSpring 2.0, what was planned for the future, and where you could go for more information. (I'll also be doing this presentation at WebDU in a about a weeks as well).

The first thing to note, is that the code name for this project is Narwhal. Why Narwhal? Basically because they are awesome. They roam the ocean with a huge spike attached to their head, which can be used to impale, seals, penguins, and apparently also koalas. See - awesome. (Who really has reasons for code names?)

The next most interesting thing to note, is that much of ColdSpring's infrastructure is now hosted on Sourceforge, as it provides a large feature set for us to leverage. Here you can find the project page, which gives you access to the Git repository that contains the code for ColdSpring 2.0.  Sourceforge also provides hosting for the Trac install that is being used to host our documentation and tickets and milestones.  We are currently investigating options for integration with the current ColdSpring website.

I'm not going to go into new features in Narwhal, of which there are more than a few (I have to have some incentive for people to come to my my WebDu Talk!), but documentation has started on the Wiki, and will be expanding quickly in the future (If anyone wants to help with that, the more the merrier!).

You may also note that much of the documentation is also being generated automatically, in an attempt to alleviate some of the burden of authoring.  Now that there are XMLschemas being used, HTML documentation is being generated from them, and ColdDoc is also being used to generate API documentation for the underlying architecture.

It's still very early days for ColdSpring 2.0, but a Alpha1 does loom on the horizon. That being said, the Git repository is public, so feel free to pull it down, have a look at what is happening in the Unit Tests, what documentation is available, and feel free to discuss it on the mailing lists.  Just beware - this is still pre-Alpha, so the sand may shift under your feet as new code gets produced, bugs get quashed and new features get developed.  You have been warned!

More details coming soon!

Back from cf.Objective() 2010

I'm back home again from what I would like to say was, one of the best cf.Objective()'s I have ever been to, including the fact that I was incredibly ill for the last day of the conference. I only managed to catch two sessions in the afternoon, and otherwise was holed up in my hotel room either fast asleep, or feeling particularly sorry for myself.

There are many things I would like to prescribe the incredibly high quality of the conference to, but the the high calibre of the session presentations really stands out at the main contributor.  I believe that when the session quality of a conference is so high, the attendees are excited and motivated by new ideas, which directly translates into fantastic and thought inspiring hallway conversations, and everything continues to flow from there.

To make a few particular references to presentations I particularly enjoyed -

Easy and Flexible Validations for Objects - Bob Silverberg
I had not previously taken the time to look at Bob's ValidateThis framework, but let me just say this: It is slick!  I was very impressed by what was possible with very little configuration, and the the flexibility that was available. My hat is off to Bob for his work with this validation framework.

Continuous Integration with MXUnit, Ant and Hudson - Marc Esher
Marc is always a very entertaining presenter, and this presentation was no exception.  I've used Hudson with MXUnit before, but it was still fantastic to see Marc explain this technology in a very clear and easy to understand manner.  He also gets points in my book for using the Hudson Chuck Norris plugin.

Polyglot Programming - Barney Boisvert
If anyone has read Barney's blog, they should already know that he's a super smart fellow.  This presentation only solidified this fact, in which Barney dug deep into the very compelling reasons a developer should potentially look into developing with multiple languages at a time (something as web developers we are doing already).  Barney covered some really interesting points about language design, the intent of programming code and qualifying return on investment in regards to polyglot programming. All great stuff!

Running ColdFusion on the Amazon EC2 Cloud - Chris Peterson
This was a session I really wanted to attend, but unfortunately I slept through due to illness.  I wanted to make note of it, as I was told that Chris had a completely filled room, and I've been told it was a really interesting presentation all around.

Building Advanced Workflows with ColdSpring - Dan Skaggs
I don't believe I have had the opportunity to see Dan speak before this, but this presentation was an eye opener!  I came to this presentation with my 'ColdSpring Lead Developer' hat on to see what interesting things people were doing with ColdSpring, and came away with a new found respect for the framework itself, and the ingenuity that Dan was displaying in his use of it.  Dan walked us through how his company was using ColdSpring to dynamically configure application workflow and processing - which enables it to be both incredibly flexible in its implementation and amazingly easy to maintain. 


Bob Silverberg and I also did a two day Hands on ColdFusion 9 ORM Training before the conference.  Thanks to all our students who attended - we had a great time teaching the program, and we hope you guys got a lot out of it.  If anyone else is ever interested in taking the training course, please provide your contact details on the website so we can contact you at a later date.

All in all, a great conference all around.  See you all again next year!
07 April 2010 09:58 AM 1 Comment

ColdFusion ORM Training + Java Persistance with Hibernate = Awesome!

Like Tyra Banks giving away Vaseline to her entire audience, the attendees of Bob Silverberg's and I's ColdFusion 9 ORM Training, that we are running at cf.Objective(), ever student who attends our training will also get a copy of:

Java Persistence with Hibernate!

You get a book! You get a book! You get a book! Yoouuuuuu get a Booooooooook!!!!

While this is a Java book, and hey, we all write ColdFusion, it is one of the books to read on utilising Hibernate within your applications. Reading this book will give you a huge insight into what ColdFusion is doing under the covers, which will help out a great deal when building applications with ColdFusion 9.

So not only do you get some great training from Bob and I, you also get a fantastic reference to take home with you as well!

If that doesn't push you over the edge to come join us, I don't know what will.

(Ordering now does not provide you with a free set of steak knives, but it will make Bob and I very happy)
23 March 2010 10:12 AM 4 Comments

No more Linux scripts for ColdFusion Builder

A few people have asked me about the ColdFusion Builder scripts for Linux for the new 1.0.

I'm sorry to say that I won't be doing a script for ColdFusion Builder on Linux for the 1.0 release.

I tried this morning to run my usual scripts to get a plugin install out of ColdFusion builder, which ran fine, but after installing and attempting to run it, I was met with a dreaded:

!ENTRY com.adobe.ide.editor.cfml 4 0 2010-03-23 09:39:50.110
!MESSAGE

Whenever I opened a CFML file (which doesn't tell me much about what is going on where).

There is obviously something native built into ColdFusion Builder 1.0, that wasn't present in Beta 3 (I can see some .dll's etc), which is causing this error to occur.  Adobe have also done the right thing, and removed all the debugging so that would be hackers have a hard time working out what is going on where.

If you want to get involved in evangelising ColdFusion Builder on Linux, there are some things you can do:

  1. Vote for the bug!
  2. Vote for the Flash Builder bug too (if they do one, they will have to do the other!)
  3. Bug your evangelists! (But do it in a nice way)  Conference season is coming up, so have a chat with them when you see them around, and let them know that you would buy a copy for Linux.
  4. Run it in VMWare / VirtualBox
  5. Change your OS of choice (ECH!)

At the end of the day, I'm only upset about there being no Linux version, because I think ColdFusion Builder is a great product, and I want it to have as much exposure as it can.  We need to convince Adobe that the Linux market is a viable one, and will have a good return on investment.

If I hear of any changes in the Linux landscape for ColdFusion Builder, I'll be sure to let you know.

cf.Objective() ColdFusion 9 ORM Training

I believe it is time for some shameless self promotion!

If you were looking for more information on the ColdFusion 9 Object Relational Mapping Training that the venerable Bob Silverberg and I are putting on at cf.Objective() next April, we have just fleshed out the content section of our site to include a detailed outline of the topics that we will be covering during the training program.

You'll know Bob from his blogging at http://www.silverwareconsulting.com/, on a variety of all too clever stuff, including CF9 ORM, Git, Unit Testing, and ValidateThis - his own open source validation framework.  He's also an all-around nice guy

You'll see that we cover a variety of topics with ColdFusion 9 ORM that will allow you to hit the ground running once you have completed our training, and it will be taught in a clear, step by step manner that will leave you wondering why you ever thought the term "Object Relational Mapper" sounded so scary and complicated.

So if you are keen on expanding your skill-set with ColdFusion 9, and specifically with its integrated ORM, we think this is the course for you, and we hope to see you at cf.Objective()!

cf.Objective() Preconference Classes
02 March 2010 12:42 PM 2 Comments

ColdDoc 1.0 Alpha Released

When ColdDoc was first born, the original idea was to just output a port of Javadoc.  Looking into it further, I realised that the mechanics where there to generate any sort of documentation, not just a static HTML version of the API.

To that effect, ColdDoc has been refactored so that it is possible to generate documentation based on an arbitrary Template Strategy.  ColdDoc now ships with both a strategy that generates the port of JavaDoc and a strategy that generates UML via the UML2 Tools plugin in Eclipse, and plans are in the works to generate a PDF document strategy as well.

I won't take you through implementation details (there is new documentation for that), but you can still generate the static HTML API documentation based on JavaDoc, for which you can see an example here, but now it is done through the HTMLAPIStrategy. This also includes support for new ColdDoc based annotations, in which, for example, you can specify generic types for return/arguments types like array, struct etc, so you can finally answer that question in your documentation of "Yes, but what does that array contain?".

When working on the ColdSpring 2.0 rewrite (wow, that is long overdue for a blog post), I also really needed a way to generate UML diagrams from the code I was writing, as a basic attempt to be able to roundtrip from UML->CFC and then back again.  Also included within ColdDoc is a strategy to generate the XML that the Eclipse UML2 Tools Plugin uses to create UML diagrams from.  You can see a screenshot of a Class Diagram here that has been created with this combination of tools.

This is very useful, as it becomes very useful for collaboration and software design sessions, even when you have started with UML diagrams, as software designs can shift during implementation phases, and diagrams and documentation often fall by the wayside during these rapid change cycles.

If you are interested in more, or possibly developing your own documentation generation strategies, download a copy of ColdDoc, read the new documentation, and join the conversation on the google group.

Happy automation of documentation!
28 January 2010 08:32 AM 15 Comments

ColdFusion 9 ORM and Transactions - It Does Not Mean What You Think it Means.

In one of my favourite lines from the Princess Bride -

[Vizzini has just cut the rope The Dread Pirate Roberts is climbing up]
Vizzini: HE DIDN'T FALL? INCONCEIVABLE.
Inigo Montoya: You keep using that word. I do not think it means what you think it means.


..and when using Transaction support with ColdFusion 9 ORM and Hibernate Sessions...It did not do what I thought it did. It did something else.

To give some back story: As we have discussed previously, a Hibernate Session is meant to flush at the end of a Hibernate marked Transaction.

So if we are talking to Hibernate natively (for example set up with JavaLoader), and had the following code:
mySession = sessionFactory.openSession();

foo = mySession.get("Foo", 1);
foo.setBar("fooBar");

trans = mySession.beginTransaction();

mySession.save(foo);

trans.commit();

mySession.close();
Which then translates to the following:
  1. Start a Hibernate Session
  2. Retrieve Entity 'Foo', with a key of 1, and assign it to a variable foo
  3. set the property 'Bar' on foo
  4. Start a Hibernate Transaction, which is tied to the Hibernate Session
  5. Tell the Hibernate Session to save() our Entity foo
  6. Commit our Hibernate Transaction, which will flush the Hibernate Session
  7. Close the Hibernate Session

If we attempt to do the same thing in ColdFusion, it may look something like this:

foo = EntityLoad("Foo", 1, true);
foo.setBar("fooBar");

transation {
    EntitySave(foo);
}

Which you would think would work exactly the same as above. Except or one small thing - It Doesn't.

If you read the ColdFusion Documentation on ORM Transactions, it states:

When <cftransaction> begins, any existing ORM session is flushed and closed, and a new ORM session is created. The <cftransaction> can be committed or rolled back using appropriate ColdFusion tags in <cftransaction>. When the transaction ends and has not been committed or rolled back explicitly, it is automatically committed and the ORM session is closed. If there is any error inside the transaction, without any exception handling, the transaction is rolled back.


This means that the above ColdFusion code, will actually perform like so:
  1. Start a Hibernate Session with the ColdFusion Request
  2. Retrieve Entity 'Foo', with a key of 1, and assign it to a variable foo
  3. set the property 'Bar' on foo
  4. Hit the start of the Transaction, flush the current Hibernate Session, close it, and then start another one.  At this point, foo has been persisted to the database, and is now detached (and remember detached is generally bad)
  5. Call EntitySave() on the now detached object foo
  6. Commit the Hibernate Transaction, and flush the Hibernate Session
  7. Flush the Hibernate Session, when the ColdFusion Request Ends

Or if you want to look at it another way, it would be the equivalent of doing the following native communication with Hibernate:
mySession = sessionFactory.openSession();

foo = mySession.get("Foo", 1);
foo.setBar("fooBar");

//foo actually gets persisted to the DB at this point
mySession.flush();
mySession.close();
mySession = sessionFactory.openSession();

trans = mySession.beginTransaction();

//foo is now detached
mySession.save(foo);

trans.commit();

mySession.flush();
mySession.close();

The big question at this point, is of course - Well, why does ColdFusion do it this way then?

There is actually a very good reason, although that reason (imho) is based on a few assumptions. 

The first assumption, is that you are going to write your ORM interactions inside your transaction block, like so:

transation {
    foo = EntityLoad("Foo", 1, true);
    foo.setBar("fooBar");

    EntitySave(foo);
}

The second  assumption is that, as a developer you will leave the ORM setting flushatrequestend set to its default of true, and therefore a split between the Hibernate Sessions is required.

For example, if we had the following code:

transation {
    foo = EntityLoad("Foo", 1, true);
    foo.setBar("fooBar");

    myMethodHereThrowsAnException();

    EntitySave(foo);
}

If we didn't have separate Hibernate Sessions, or at least clearing of the Session after Hibernate Transaction rollback, , the following would occur:
  1. Start a Hibernate Session with the ColdFusion Request
  2. Start the Hibernate Transaction
  3. Retrieve Entity 'Foo', with a key of 1, and assign it to a variable foo
  4. set the property 'Bar' on foo
  5. Throw an exception, which causes the Transaction to rollback
  6. The request ends, the Hibernate Session is flushed, and foo gets saved back to the database, since it is still available in the Hibernate Session.
Which is very much against the nature of a rolled-back transaction.

Instead, what actually happens is:
  1. Start a Hibernate Session with the ColdFusion Request
  2. Start the Hibernate Transaction, which closed the above Session, and starts a new one
  3. Retrieve Entity 'Foo', with a key of 1, and assign it to a variable foo
  4. set the property 'Bar' on foo
  5. Throw an exception, which causes the Transaction to rollback
  6. The Transaction end closes the current Hibernate Session, and creates a new one
  7. The request ends, the Hibernate Session is flushed, and nothing gets saved to the database, as there is nothing in the current Hibernate Session
Given the above assumptions, this is much better, since we want to have the Transaction actually rollback.

That all being said, what happens to those of us that want to work, or have an architecture that inclined towards our previous example:

foo = EntityLoad("Foo", 1, true);
foo.setBar("fooBar");

transation {
    EntitySave(foo);
}

I.e. We want to have our Transaction interact with the current Hibernate Transaction, and not flush at the end of the ColdFusion request, which, I find to be the solution I prefer for when building applications with Hibernate.

What can we do then?

There are two things that need to be done, if we want to do this kinda of approach. The first is, to set the ORM setting flushatrequestend to false.  This means that the Hibernate session won't flush at the end of the ColdFusion request, and we have complete control over when it does flush.

To make sure the Transaction interacts with the current request, we can't use <cftransaction> or a transaction {} block, we have to natively interact with the Hibernate Session directly, which is quite straight forward.

foo = EntityLoad("Foo", 1, true);
foo.setBar("fooBar");

trans = getORMSession().beginTransaction();

try
{
    EntitySave(foo);

    trans.commit();
}
catch(Any exc)
{
    trans.rollback();
    rethrow;
}

We have to do the extra work to manage the commit and/or rollback of the Transaction manually, but this something that could be implemented with a UDF or using Aspect Oriented Programming for reuse.

Now I can use Transactions to demarcate when I want the Hibernate Session to be flushed, and I'm not tied to wrapping my entire Entity operations inside a <cftransaction> block.

This is something I really like about how Adobe implemented the ORM integration.  If I don't particularly like the way an individual aspect has been implemented, I have direct access to the underlying engine, and can therefore interact with it in whatever way that suits the way I develop and thearchitecture of my application.

Now Transactions mean what I think they mean.
 
UPDATE 28/10/01:
I just wanted to add a small conclusion to this post, that sums what I am trying to get across simply.
 
Basically what this all boils down to is: If you are using <cftransaction> or a transaction{} block, make sure you are wrapping them around the entire operation, not just the EntitySave() portion at the end, as otherwise bad things can happen.

If you want to just wrap transactions around the EntitySave() part of your code, you will need to use native Hibernate Transactions like I have done above.
 
Hopefully that boils the large post above into a nice tasty nugget of knowledge that is far easier to swallow.

Presenting and Teaching at cf.Objective() 2010

I'm a little behind the times on this blog post - but I am presenting and also teaching a course at cf.Objective() this year.

I will be presenting 2 sessions at the conference:

Dependency Injection Redefined - ColdSpring 2.0: Narwhal

ColdSpring 2.0, codenamed 'Narwhal', is a project that has been going on a little 'behind the scenes', except for the occasional tweet from either myself, or Chris Scott.

In this presentation, we'll look at some of the motivations behind the complete rewrite of ColdSpring for the 2.0 version, and some of the new features that will be available that should make dependency injection easier, and way more flexible than ever before.

I've had in my to-do list a reminder to write a long blog post on what is going on with Narwhal, which I should write at some point soon, so you have a good idea what to look out for.  That being said, Narwhal is taking shape nicely, and I think is going to be a very powerful addition to the ColdFusion framework landscape.

Advanced Java & ColdFusion Integration with JavaLoader 1.0

This talk will focus on the new features of JavaLoader 1.0, and how you can use them to integrate Java with your ColdFusion platform in some new and exciting ways.  If you are interested in JavaLoader 1.0, check out this previous blog post, it gives you a good run down on the new features it brings to the table.

We will also be investigating some of more common 'gotchas' with Java and ColdFusion integration, especially around ClassLoader issues, which should be useful for all involved.


Bob Silverberg and I are also going to be a teaching a 2 day training course, just before cf.Objective():

Hands-On ColdFusion ORM Training

This will be as very hands on session, where Bob and I will be going through building an application using ColdFuson 9's Object Relational Mapper from beginning to end.  This will include many best practices, discussions as well as theory about how the underlying Hibernate engine works with ColdFusion.  No ORM/Hibernate experience necessary.

More detail on the course can be found on our website, and also on the preconference page, where you can also check out all the other fantastic training content.

Don't forget that the early bird pricing for both conference tickets, and training finishes on the 29th of January, which is coming up soon!

cf.Objective() is looking to be a great conference. Hope to see you there!
20 January 2010 11:48 AM 1 Comment

JavaLoader 1.0 Beta 2 Released

This release of JavaLoader 1.0 includes the following fixes and enhancements:
If you aren't aware of the new functionality in JavaLoader 1.0, you can have a look at my previous blog post , the documentation and/or the presentation I did at MAX for more information.

Credit and thanks to Fred Roeber for his contributions to the NetworkClassLoader in JavaLoader.

If you are interested in hearing more about ColdFusion and Java integration please come to cf.Objective(), where I will be presenting on Advanced Java & ColdFusion with JavaLoader 1.0.

In the mean time, download JavaLoader, and please report any bugs that you find.
18 December 2009 09:56 AM 8 Comments

ColdFusion Builder Beta 3 on Linux

ColdFusion Builder 3 is up on Labs , and available for download, so it's now time to update my scripts for getting it up and running on Linux.

The procedure is as following:
  1. Download the intermediate build *for MAC* (very important! The Windows Adobe Licensing will prevent you from using the Windows version any more, as it uses .dll files, and those don’t work on Linux, but the Mac version works on Linux!)
  2. Download coldfusion_builder_b3.zip .
  3. Unzip coldfusion_builder_b3.zip into a directory
  4. Unzip coldfusionbuilder_b3_install_mac_121709.zip
  5. Unzip /cfbuilder_install.app/Contents/Resources/cfbuilder_install.app/Contents/Resources/Java/Disk1/InstData/Resource1.zip (may be easier to do that into another folder)
  6. From the unzipping of Resource1.zip grab /Z_/dist/_macos_87b1877cbdff_zg_ia_sf.jar and put it in the same folder as where you unzipped coldfusion_builder_b3.zip
  7. Run ’./Rip.py’ from the folder you unzipped it to.
  8. You should now have a ’plugins’ and ’features’ folder with just the bits you need to install into Eclipse.
  9. Enjoy CF Builder in Linux :D

Enjoy!

My Interview on Dzone - ColdFusion and Java Integration

The interview I did with Dzone at the Adobe MAX conference is now online!

In the interview we talk about a variety of topics, mainly centred about how and why to integrate ColdFusion and Java together, but also touching on things like Object Relational Mappers, including ColdFusion 9's integration with Hibernate.

Hope you like it, and please give it a nice 'up' on Dzone.

Code Samples for Rapid OO Development with ColdFusion Frameworks

You can download the full code samples I used in my Rapid OO talk that I gave most recently at cf.Objective(ANZ) , and previously at cf.Objective() .

Before people ask, I don't tend to post slides, as they are generally only pictures, and tend to have no context without me talking next to them.

That being said, I'll have a chat with the CFMeetup crew, and see if they would like me to give the presentation there, so there is a recording for posterities sake, and for those who couldn't make those conferences.

One Week Until cf.Objective(ANZ)

I can't believe it was well over a year ago I was sitting around with the steering committee of cf.Objective() , and the conversation turned to 'What do you think of the idea of doing this conference in Australia?', it feels just like yesterday.

Now we're only one week away from cf.Objective(ANZ)!!!

If you haven't already registered , there are still spots available, so make sure you grab them quick! You don't want to miss out on hanging out with super-top-programmers like Justin McLean , Andrew Muller , Dan Wilson ... oh, and did we mention Ben Forta and Terry Ryan are coming? (like anyone missed that!).

See you all in a week!
26 October 2009 11:11 AM 0 Comments

JavaLoader 1.0 Beta Released

JavaLoader 1.0 is moving from Alpha to Beta with only a few small bug fixes and enhancements.

If you are not familiar with JavaLoader 1.0's functionality, you can have a look at my previous blog post , the documentation and/or the presentation I did at MAX for more information.

The was a logic bug in the way that dynamic compilation was occuring across multiple source directories that has now been resolved, and should also ensure that compilation is much faster than it was in the Alpha.

The other enhancement was to allow for relative paths in the Spring integration.  To explain, in the Alpha, you would often end up having to input your beans similar to this:

<coldfusion:cfc id="message"
        script-source="file://${root.path}/model/Message.cfc"
        script-interfaces="com.IMessage"
        />


Which can be a bit of a pain, as injecting a dynamic value for ${root.path} is not as easy in Spring as it is in ColdSpring.

Now, by default, 'script-source' attributes are relative to the calling page, so you can do your bean definitions like this:

<coldfusion:cfc id="message"
        script-source="file:///model/Message.cfc"
        script-interfaces="com.IMessage"
        />


and the path will be worked out for /model/Message.cfc relative to your application path.

Oh, and don't forget - if you are into integrating Java and ColdFusion development, make sure you sign up for the Google Group !

JavaLoader 1.0 Beta can be downloaded here .

22 October 2009 02:48 PM 5 Comments

MAX Presentation Recording: ColdFusion for Java Developers

I had the wonderful opportunity to present and attend MAX for the first time ever this year, and I can honestly say, it was a fantastic time all around.

MAX is completely unlike any other conference I've ever attended, both in terms of its sheer size, and also in terms of the wide gamut of Adobe community members that are in attendance.  I managed to meet a variety of people that I would never have talk to in my regular travels both in term of physical locations and also technological disciplines.

I also had the pleasure of presenting the last session on the last day, so I was very happy when I had a fairly reasonable turn out for my ColdFusion for Java Developers presentation.  The presentation took the perspective that the attendees were/are already doing Java development, but want to port those tools and codebases that they are already using to a ColdFusion environment, so they could take advantage of ColdFusion services and language.  From there we look at the variety of techniques that you can use to enable ColdFusion->Java communication, as well as Java->ColdFusion.  This includes a aan overview of a lot of the JavaLoader 1.0 feature set in the process.

If you are one of these people, and/or you are doing development in both ColdFusion and Java, you can watch the recording of my presentation on Adobe TV .  You may want to skip the first 5 minutes, as for some reason the recording has me doing all my set-up before I start speaking.
21 October 2009 05:54 PM 8 Comments

ColdFusion Builder Beta 2 on Linux

For those of you who have been running ColdFusion Builder on Linux, you may have noticed that the installer structure has changed since the last public beta, which means that my previous instructions will no longer work.

This means we have to jump through some different hoops to get things to work this time around.

The steps are now the following:

As new versions of ColdFusion Builder become public, I will attempt to keep this script up to date.

 

07 October 2009 02:52 AM 0 Comments

Ben Forta is Coming to cf.Objective(ANZ)!

In case you missed the tweets, I am very pleased to announce that Ben Forta will be joining us in Melbourne, Australia for cf.Objective(ANZ) !

Ben will be joining ColdFusion Evangelist Terry Ryan to represent Adobe ColdFusion here in Australia, and the two of them will be around to chat to all attendees about ColdFusion and the Adobe ecosystem.

Don't forget that the early bird price comes to a close on the 12th of October, which is fast approaching, so please make sure you get yourself registered so you can take advantage of it.

See you all when I get back from MAX.
07 September 2009 09:58 AM 2 Comments

Talking Java and ColdFusion Integration on CFPanel this week!

At a very ANZ friendly time of Wednesday, 10am Melbourne time, I'm going to be joining super-smart guys Brian Kotek and Barney Boisvert on CFPanel to talk about Java Integration with ColdFusion in the CFPanel Connect Room.

This is obviously a topic that is quite near and dear to my heart, but it is also one that I think often doesn't get its 'surface scratched' (so to speak).  In my experience I often see the information presented is more on the 'how to get set up' side, and less on the deeper details on what can actually be done.

I'm really looking forward to getting a chance to share experience with the other CFPanel members, and really get deeper into some interesting Java and ColdFusion integration, in regards to how people are using it, what benefits they are reaping, and also what problems they have encountered.

For more details, and and all the other time zones, check out the CFPanel post.

Hope to see you in the Connect room!
07 September 2009 09:01 AM 0 Comments

Registration Opens for cf.Objective(ANZ)

It's been a bit of a bumpy road getting here, but registration for cf.Objective(ANZ), being held in Melbourne Australia on the 12th and 13th of November is finally open!

The program is full with a stack of really interesting presentations, ranging from JVM Tuning and Optimisation, to ModelGlue 3: Gesture, all the way to Connecting hardware up to ColdFusion!

We have an international cast of speakers, including notable luminaries such as Dan Wilson and Mike Brunt, as well as many talented speakers from the Australia and New Zealand Regions, including Geoff Bowers, Robin Hilliard, Kai Koenig and many, many more.

Helping organising a conference over international borders has been quite the learning experience, however I am very proud to be part of the steering committee that is bringing cf.Objective(ANZ) to the Pacific Region.

If you are looking to learn about enterprise development, and hang out and talk to a slew of like minded developers for two days, register for the conference, and come on down!  It's going to be a great time!
31 August 2009 12:43 PM 2 Comments

JavaLoader 1.0 Alpha is Released!

JavaLoader 1.0 is a project I've been talking about off and on for the past 6 months or so, and I'm very happy to announce that a release version is now complete.

There are several key new features to JavaLoader 1.0,

Dynamic Compilation

Now if you are working with JavaLoader, you don't have to bundle your Java code into a jar to load.  You can simply specify to JavaLoader which directories are your source directories, and JavaLoader will compile and load them on the fly for you!  JavaLoader will also check to see if your source code has changed, and re-compile it as necessary! 

For example, if I wanted to compile and load a HelloWorld.java (that has a simple 'Hello World' method) in my ./src directory, I could do:

javaloader = createObject("component", "javaloader.JavaLoader").init(sourceDirectories=[expandPath('./src')]);

And then create my HelloWord object as per normal:

<cfset helloWorld = javaloader.create("HelloWorld").init()>
<cfoutput>#helloWorld.hello()#</cfoutput>

No more ANT tasks, no more export to .jars, JavaLoader handles the compilation and deployment of your Java code for you.

ColdFusion Component Dynamic Proxy

For those of you who are not aware of what a Dynamic Proxy in Java is, it is essentially an Object that can mimic an object that implements a given set of Interfaces.  The method invocations against that object are intercepted, and you can essentially do whatever you like with them.

In JavaLoader 1.0, I've written a Dynamic Proxy that you are able to wrap around a CFC, and thereby make Java Objects think they are interacting with a native Java object, but are in fact, talking to your CFC.  When a Java Object calls a method on the Dynamic Proxy, it is passed through and invoke directly on the CFC transparent to your Java layer.

For example, the java.lang.Thread Java object can take an instance of the interface java.lang.Runnable in its constructor argument.  Using JavaLoader's Dynamic Proxy, we can pass it what it thinks is an instance of the Runnable Interface, but is in actuality a ColdFusion Component like so:

//give us access to the CFCDynamicProxy
CFCDynamicProxy = javaloaderloader.create("com.compoundtheory.coldfusion.cfc.CFCDynamicProxy");

//create my Runner CFC
myRunner = createObject("component", "MyRunner").init();

//wrap it in a Dynamic Proxy, that implements Runnable
runnerProxy = CFCDynamicProxy.createInstance(myRunner, ["java.lang.Runnable"]);

//pass it to the Thread and call run()
thread = createObject("java", "java.lang.Thread").init(runnerProxy);
thread.run();

...and suddenly we have true seamless communication from Java to ColdFusion components.

This is actually something I wish I had written three years ago.  It would have radically altered how I would have written a lot of software.

Spring Integration

A natural progression from the Dynamic Proxy, was to implement a Custom Schema in Spring, so that you could instantiate and dependency inject your ColdFusion components with your Java Objects inside Spring itself.

Initialising Spring with JavaLoader is covered in the documentation, but to give you a quick taste, once we have Spring running, we can include a CFC in our spring.xml with:

<coldfusion:cfc id="message"
        script-source="file://home/www/model/Message.cfc"
        script-interfaces="com.IMessage"
        />


Where script-source is the absolute path to the CFC you want to instantiate, and script-interfaces are the Java interfaces that your dynamic proxy will implement, and your CFC has mirrored inside it.

This Component then gets treated like a normal Spring bean, so it can be autowired, injected, aop'd and all the usual functionality that a Spring bean has access to.

There are some downsides to implementing Components inside Spring, so be sure to check out the documentation for more details.

Read More

For more details, have a read of the extended documentation, and have a look at the examples provided in the download.

Since this has become a far larger project than its original inception, I've done away with the Riaforge Forum, and have started a new javaloader-dev google group for support and discussion of JavaLoader and Java and ColdFusion integration.

While I'm very confident in the code that I have written for JavaLoader 1.0, I decided to call it an Alpha, simply because it has only really been tested by me and my Unit Tests.  Knowing from experience that users of Open Source Software have a tendency to use and abuse libraries far above and beyond what the author had ever originally dreamed led me to decide to call it Alpha until the community has really had a good change to play with it.

Please download JavaLoader 1.0, take it for a spin, sign up for the mailing list, and if you find any problems please do let me know.
26 August 2009 02:46 PM 3 Comments

Getting UTF-8 and MySQL to work with ColdFusion 9 ORM

A question I've seen show up quite often in Hibernate forums is 'How do I get Hibernate to generate UTF-8 Compliant Tables and/or columns when it generates my database tables when using mySQL?'

It's actually, quite easy to do, but often (myself included), people end up looking deep into Hibernate for some mysterious setting.

In reality, it's just a question of setting up your database correctly.  The first thing you need to do is set your database to use UTF-8 character coding as its default, like so, when creating it:

create database my_new_database default CHARACTER SET = utf8 default COLLATE = utf8_general_ci;

This will ensure all tables that are created by ColdFusion's ORM are created with a UTF-8 character set.

That being said, I have seen issues when data is being sent up to MySQL in UTF-8 form getting corrupted.  To ensure the database drivers use the correct character set as well we add useUnicode=true&characterEncoding=UTF-8 to our MySQL connection string in the ColdFusion Admin under the datasource's Advanced Settings.

There you go! UTF-8 support in mySQL with ColdFusion ORM!

17 August 2009 07:03 PM 7 Comments

Overloading ORM Implicit Get and Set Methods

This is something I just ran into with ColdFusion 9's ORM implementation, that thankfully Rupesh got back to me very fast on, otherwise, I probably would have been confused for quite a while.

I needed to overwrite a get and set value in a CFC I was creating.  We will say for arguments sake I was hashing a password on a User object (even though I was doing something completely different), like so:

component output="false" persistent="true"
{
    property name="userid" fieldtype="id" ormtype="int" generator="identity" hint="primary key";
    property name="name" type="string" notnull="true" length="200" hint="The user's name";
    property name="password" type="string" length="200" hint="The user's password";

    public void function setPassword(String password)
    {
        instance.password = hash(arguments.password);
    }

    public String function getPassword()
    {
        return instance.password;
    }
}

This is how I would usually have written my Components, storing my data in variables.instance, so they wouldn't overlap with any of the data stored in my variables scope.

What I couldn't understand was, my password would keep getting stored in my database as NULL, even though I had explicitly set it.

Thankfully Rupesh explained that when the ColdFusion ORM retrieves and populates data in an ORM managed CFC, it directly accesses the variables scope in the CFC.  So in the above instance, the ORM was finding no data for the password, and interpreting that to mean that I wanted to insert that as NULL into my database.

Therefore,  to get my code to work was to store my data in the variables scope, like so:

component output="false" persistent="true"
{
    property name="userid" fieldtype="id" ormtype="int" generator="identity" hint="primary key";
    property name="name" type="string" notnull="true" length="200" hint="The user's name";
    property name="password" type="string" length="200" hint="The user's password";

    public void function setPassword(String password)
    {
        variables.password = hash(arguments.password);
    }

    public String function getPassword()
    {
        return variables.password;
    }
}

This way the ORM can find exactly what it is looking for, and I can manipulate my data the way I want.

The fact that the ORM integration works this way is actually a very good thing, as it means that my password above doesn't get hash'd over and over again, but it is something we all should be aware of when you want to overwrite the implicit get and set functions that get generated by <cfproperty> declarations.

04 August 2009 07:27 AM 12 Comments

ColdFusion 9 ORM - Explaining Hibernate Object State

In the previous two articles, we started the discussion of Hibernate Sessions and how they related to the ColdFusion 9 ORM.  We noted the fact that a Hibernate Session keeps track of what objects it loads, and can therefore update it when it realises that the object has changed.  The question then posses itself - if a Hibernate Session has closed, which happens at the end of every ColdFusion request, what happens to the objects that it was managing?

Going forward, I'm going to reuse the Musician model I used in the Introducing ORM in Adobe ColdFusion 9 beta Adobe DevNet article, for which the updated code samples can be found here.

The very short version for those who don't wish to look at the code, is a model in which we have a Musician, who has a name, and an age, and he/she also has a many-to-many relationship to an array of Instruments, which they can play.

As far as Hibernate is concerned, there are three different states for any Object that it interacts with.

Transient

An Object/Entity (you could use either word) is Transient, if it has just been created with a createObject() or new operator, but has yet to be saved with the EntitySave() method.

Obviously, if transient objects are not persisted via EntitySave(), then they never get stored in the database, and will eventually be garbage collected.

For example, our musician john below is a transient object:

 

<cfscript>
    import com.*;
   
    //this is transient
    john = new Musician("Transient John");
</cfscript>

Since john is never saved, it will always be transient.

Persistent

A Persistent object is one that has either come from, or has been saved in the database, within the scope of the current Hibernate Session (which is an important point to note).

For example, we can make our musician john below persistent, by:

<cfscript>
    import com.*;
   
    //join is transient
    john = new Musician("Transient John");
    
    john.setAge(47);

    //john is now persistent   
    EntitySave(john);
</cfscript>

Therefore, since john was inserted into the database, he is persistet.

By the same token, if we retrieve an object through the ORM, it is also persistent:

<cfscript>
    //larry's ID is 2

    //larry is also persistent
    larry = EntityLoad("Musician", 2, true);
    
    //As larry is persistent, we can change his age, which will be reflected in the database
    larry.setAge(19);
</cfscript>

Since larry was retrieved from the database, he is also persistent.

Detached

Detached objects are ones that used to be persistent, but the Hibernate Session has closed. Detached objects were one of the biggest things for me to wrap my head around when starting with Hibernate, and can cause a few really tricky errors to occur.

To explain detached a little better, we can go through a scenario that will causes them, as I think this is something that a lot of ColdFusion developers are going to end up running in to.

Let's have a new musician, called Tim, and time is going to have 2 instruments that he plays, the Flute and Piano.

We are going to grab Tim out of the database, and then put him in our ColdFusion Session scope, so we can keep track of him from request to request.

<cfscript>
    tim = EntityLoad("Musician", 2, true);
    
    session.musician = tim;    
</cfscript>

For this request, Tim will be persistent, however, on the next request, Tim is now detached, as the Hibernate Session will have closed at the end of the previous request.

Therefore, if I do this:

<cfscript>
    instruments = session.musician.getInstruments();    
</cfscript>

<cfdump var="#instruments#">

You will see the following (not well written) error:

failed to lazily initialize a collection of role: Musician.instruments, no session or session was closed

If you are running ColdFusion via the console, you will also see something similar to:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: Musician.instruments, no session or session was closed


What does this error even mean? 

First of all, we should remember that the collection of Instruments our Musician can play are lazy loaded. This means they aren't actually loaded from the database into the object until you actually request them.

The important thing to note here, is that lazy loading with Hibernate can only occur if the Hibernate Session that the object was originally loaded from is still open.  To put it another way, if the Hibernate Session has closed, then Hibernate has no record of what the object was doing, and therefore can't do any lazy loading.

In the above example, since the previous ColdFusion request ended, the Hibernate Session has closed, and if you attempt to access a relationship that is set to lazy load, and has yet to be loaded, this error occurs.

Its should be noted that singular properties are not lazy loaded - therefore, if you are just grabbing a property on an object that is detached, no error will be thrown.

What can we do to mitigate this issue? There are a few options, one of which is, to simply retrieve the object all over again, like so:

<cfscript>
    session.musician = EntityLoad("Musician", session.musician.getMusicianID(), true);

    instruments = session.musician.getInstruments();    
</cfscript>

<cfdump var="#instruments#">
Or, like so:
<cfscript>
    session.musician = entityLoadByExample(session.musician, true);

    instruments = session.musician.getInstruments();    
</cfscript>

<cfdump var="#instruments#">

As then the object we are dealing with is considered persistent, as it is attached to the currently open Hibernate Session.  This tends to be the easiest of the options when dealing with detached objects.

Another interesting way of making our detached object persistent is like so:

<cfscript>
    EntitySave(session.musician);

    instruments = session.musician.getInstruments();    
</cfscript>

<cfdump var="#instruments#">

This may look strange, but what is actually happening when you call EntitySave(), is that it calls the Hibernate method saveOrUpdate()

A quick version of what saveOrUpdate() does is -

Therefore in the example above, the data stored in session.musician will be saved again to the database, and since session.musician is now deemed persistent, we can successfully do lazy loading of the instruments.

However, if a situation like this would occur:

<cfscript>
    musicianTwo = EntityLoad("Musician", session.musician.getMusicianID(), true);

    EntitySave(session.musician);
</cfscript>

We get the following error:

a different object with the same identifier value was already associated with the session: [Musician#2]

Since Hibernate deems the persistent object that is currently connected to the Hibernate Session much more important than the detached object, which makes sense, as the persistent object has the most up to date version of the data stored in the database.

Generally speaking, if you at all can, try and avoid having detached objects in your application, as this is generally a Good Thing™, and will allow you to avoid some pretty decent headaches as you develop with CF9 ORM.  Strategies such as storing IDs in the ColdFusion Session and having an API to return a new Object by that ID on request is often a good way to go, rather than storing the Entity itself in the ColdFusion Session.  That being said, if your architecture means that you have to have detached objects this series should be enough to give you a basic grounding the concepts of object state, and how to manage it.

If you want to learn more about managing Hibernate Object States (and there is far more to it than I have written here), you can read more about this in the Hibernate documentation, but this should hopefully have given you a decent enough overview to avoid some possible pitfalls when handling persistence with ColdFusion 9's ORM integration.
31 July 2009 08:10 AM 0 Comments

Speaking at MAX this year - ColdFusion for Java Devlopers

This year it is going to be my absolute pleasure to be attending and presenting for the first time ever at the Adobe MAX conference.

My presentation is entitled ColdFusion For Java Developers and is scheduled for Wednesday, 5:00pm.

Primarily aimed at Java developers, it is going to cover a myriad of ways that you can integrate your already existing Java code base into a ColdFusion application, and also get your Java model talking seamlessly to your ColdFusion code base.

The official synopsis is:
Ever since ColdFusion was re-implemented as a J2EE application, the benefits of combining Java and ColdFusion application development have been easy to see, and widely used across the ColdFusion landscape.

This talk will look at some of the ways we can already take advantage of common Java libraries in ColdFusion, and enable Java developers to leverage the libraries and frameworks that they are already using. We will also be looking at how Java developers can seamlessly leverage the dynamic scripting language of ColdFusion, within their Java code, to easily enable them to take advantage of some of the RAD features that come bundled with ColdFusion.

That being said, if you are a ColdFusion developer who likes to also work with Java, you may wish to come along, as there will be several techniques demonstrated that will be provided by the forthcoming JavaLoader 1.0 release that should (hopefully) interest you greatly.

I look forward to seeing you all at MAX, and also at the ColdFusion Unconference!
28 July 2009 08:41 AM 7 Comments

Updated Sample Code for Introduction to CF9 ORM DevNet Article

My apologies if this is a little belated, but here is an update to the sample code that was posted with my DevNet article Introducing ORM in Adobe ColdFusion 9 beta.

Unfortunately several things changed in CF9 between the time that I wrote the article and when the public beta came out.

The major differences between the sample on Adobe.com and this one are:

I will endeavour to keep this download up to date as new versions of ColdFusion 9 are release.

coldfusion9_orm_sample.zip

 

21 July 2009 08:32 AM 15 Comments

ColdFusion 9 ORM - More on Flushing Hibernate Sessions

Hopefully with my previous article, I've got you understanding how Hibernate Sessions work behind the scenes of ColdFusion.  However, there is one statement I made that requires further clarification before we go any further.

I wrote:
"This means that changes to your objects will also not be persisted to your database, until the end of your ColdFusion request, as that is when the Hibernate Session is closed."

Technically this isn't exactly true, but it was a concept that confused me a lot when first starting with Hibernate, so I wanted to get people thinking in the right direction without complicating things too much.

The Problem

For example, a situation like this made me scratch my head for a long time when I first started working with Hibernate:

We have 5 Musicians in our database, and we want to delete one, and then re-list all of them again.

<cfdump var="#ormExecuteQuery('from Musician')#" label="query">

<p>We are now deleting!</p>
<cfset musician = entityLoad("Musician", 3, true)>
<cfset EntityDelete(musician)>

<cfdump var="#ormExecuteQuery('from Musician')#" label="query">

And we would see a result like:

Tom, Jerry, Ben, Bob, Richard

We are now deleting!

Tom, Jerry, Ben, Bob, Richard

This shows me exactly the same data we before and after my EntityDelete().  Wait... what? Didn't I delete Musician Number 3?

The fact of the matter is, yes, we deleted Musician #3, except since the Hibernate Session hasn't been flushed yet, the data hasn't been persisted to the database.  Therefore, when we run out HQL query, we see all the Musicians!

Hibernate Session Flushing

Before we go directly into how to solve this problem, what does the Hibernate documentation say about when Session Flushing actually occurs?

This process, called flush, occurs by default at the following points:
  1. before some query executions

  2. from org.hibernate.Transaction.commit()

  3. from Session.flush() 
So what does that actually mean in terms of ColdFusion?
  1. Before some query executions - So at some arbitrary points during the Hibernate Session life cycle it may flush.  Obviously not something we can rely upon.
  2. At the end of a Transaction. So if we our code in a <cftransaction> block, it should flush at the end of that transaction, and therefore the changes to our objects will be persisted in the database.
  3. When we call ORMFlush(), or at the end of a Session when it is called implicitly.

Therefore, if we wrap the relevant code in or Transaction, like so:

<cfdump var="#ormExecuteQuery('from Musician')#" label="query">

<cftransaction>
<p>We are now deleting!</p>
<cfset musician = entityLoad("Musician", 3, true)>
<cfset EntityDelete(musician)>

</cftransaction>
<!--- Session should be flushed now --->

<cfdump var="#ormExecuteQuery('from Musician')#" label="query">

We should get a result of:

Tom, Jerry, Ben, Bob, Richard

We are now deleting!

Tom, Jerry, Bob, Richard

Alternatively, we could also do:

<cfdump var="#ormExecuteQuery('from Musician')#" label="query">

<p>We are now deleting!</p>
<cfset musician = entityLoad("Musician", 3, true)>

<cfset ORMFlush()>
<!--- Session should be flushed now --->

<cfdump var="#ormExecuteQuery('from Musician')#" label="query">

And we would also see the same results.

So as you can see it is not exactly true that your object data will only get persisted at the end of you request, as you actually have a lot of control over exactly when the Session gets flushed.

It is important to note that 9/10 times you probably won't care when the Session gets flushed and the changes to your objects actually get persisted in the database.  However, there will be instances in which you will care, and your code depends upon having your data persisted in your database.  You now have the tools to manage your persistence life cycle and know what is going to happen when.

15 July 2009 11:26 AM 5 Comments

ColdFusion 9 ORM - Explaining Hibernate Sessions

Now that ColdFusion 9 is in public beta, I wanted to write some articles explaining how Hibernate is actually working under the hood of the nice ORM integration we now have.  Like all powerful tools, they can do a great many things - but only if you really understand how they work.  Otherwise, they are potential for disaster if you don't know what you are doing.

Hibernate Sessions

The first thing we need to cover is the concept of Hibernate Sessions, which has been nicely hidden away from ColdFusion developers by the Adobe Engineering team, but is still something that you need to really understand to be able to leverage Hibernate in CF9 properly. (At least IMHO).

First things first - don't confuse this with ColdFusion Sessions, or any sort of browser session.  Hibernate is built as a generic solution to ORM, so it has no specific ties to web state. A Hibernate Session is a lightweight object that is used to delineate when Hibernate is meant to start working, and when it is meant to stop, which is often referred to as a unit of work. This may span several transactions and/or INSERT, UPDATE, DELETE and SELECT statements as the Session gets used.

This is very much like the start and stop of a conversation, we say hello at the beginning, and say goodbye at the end, and whatever we need to discuss goes on in between, except we just tell the Session to open() and close(), rather than "hello" and "goodbye".

Actual Hibernate Java code would look something like this:

//open the session from the SessionFactory (which is where sessions come from)
Session session = sessionFactory.openSession();

//get fred, our caveman
Caveman fred = session.get("Caveman", 2);

//change his age to 32
fred.age(32);

//close the session, which will update fred.
session.close();

I'm not going to get into where the SessionFactory comes from, as all you really need to know is: it's where Hibernate Sessions come from.

So what we are doing here is:
  1. opening a Session, i.e. we tell Hibernate 'Hi', which starts our conversation.
  2. Tell Hibernate to retrieve our Caveman fred, through our session.
  3. We change the age of fred to 32.
  4. We close our session, and say 'GoodBye' to Hibernate for now.
There are several things that happen here that are worth noting at this point, even in this relatively simple piece of code.

The first is, by doing session.get("Caveman", 2), we have effectively told our Session to track this object, and make note of any changes that happen to it. 

We have also cached a copy of fred in the Session itself, so that if we were to attempt to retrieve fred again, we would get the same copy.  This is both for performance, and also so that the Hibernate Session only has to deal with one object that represents the data behind fred, which will be a fairly important concept as we continue in this article series.

Since our Session is tracking fred, any change we make to fred will be persisted to the database when we close our Session.  In that way, Hibernate is quite transparent in the way it implements persistence.

It should also be noted at this point: Unless you specify otherwise, Hibernate will only run INSERT, UPDATE and DELETE when the session is closed, generally as a batch.  This is so that, for example, multiple changes happen to fred during the length of our Session, there only needs to be one UPDATE statement when we are finished.  This is an important thing to note, as it is possible to get confused as to why your changes to your objects aren't appearing in your database during your Session, but do appear afterwards. 

Hibernate Sessions and Web Applications

In web applications, it is usual to manage Hibernate Sessions by opening one up at the beginning of a HTTP request, and then closing at the end of the request.  The length of a single HTTP request is a good size to carry on a nice conversation with Hibernate.

Strangely enough, this is exactly what ColdFusion is doing for you behind the scenes.  It starts a Hibernate Session when your request starts, and ties it to that particular request, and then closes it at the end of the request.  (It is quite likely that the Session actually only gets created when first requested, but for the sake of argument it is easier to explain it as it gets opened at the start of the request)

From there, each of the ORM functions, EntityLoad, EntitySave, EntityDelete, etc, all interact with that Session that exists behind the scenes, for that request.

This means that changes to your objects will also not be persisted to your database, until the end of your ColdFusion request, as that is when the Hibernate Session is closed. In later articles, I'm going to cover some ways this can cause some trouble, and how to work around them.

 

You are actually able to flush the Session, which forces it to persist any changes to the database right then and there, and not wait until the end of the request, which can sometimes be very useful. 
To do this in Java, you could go:

session.flush();

But in ColdFusion you write:

ORMFlush();

UPDATE: You can read more about Session Flushing here, which outlines that there are times in which Hibernate will flush a Session in the middle of Session, however, there is often no guarantee except in specific circumstances.

It's also interesting to note you have direct access to the Hibernate Session if you so desire through ORMGetSession(), which gives you access to that request's Hibernate Session object, so you can interact with it directly.

There is much more to Hibernate Sessions and how they relate to the objects that they manage, but this will give us a good start to build upon for now.

You can read more about ColdFusion and Hibernate Sessions in the documentation Hibernate Session Management.

Installing ColdFusion Builder Beta on Linux

UPDATE (21 October 2009): This will no longer work with Beta 2 of ColdFusion builder. If you are looking for a more up to date technique for installing ColdFusion Builder on Linux, please see this post .



So I’ve managed to hack my way to getting Bolt installed on Linux, and it wasn’t quite as painful as I thought it was going to be.  It is essentially a pure plug-in install, but we have to jump though a few hoops to get the plug-in itself.

I would suggest starting with a clean installation of Eclipse 3.4.2, with a clean workspace, just to make sure there are no major issues.

Here are the steps you need to reproduce:

So far, there is only 1 annoying bug I’ve found. 

When using CTRL+J to insert a snippet, it inserts perfectly, however, I find I have to click outside of Eclipse, and then back into Eclipse with my mouse before I can edit again (very weird, I know).  It's annoying, but I can work around it.

Hopefully we can provide enough free testing for ColdFusion Beta on Linux, and prove we have a large enough user base, that we can get supported on Linux.

Make sure any bugs you run into are reported to the ColdFusion Builder Bug Tracker page, so that Adobe is aware of them.
13 July 2009 03:12 PM 2 Comments

ColdFusion 9 Beta Drops, and so does my Devnet ORM Article!

As I'm sure you have all noticed, ColdFusion 9 Public Beta is now available for download.

I am really excited about this release, and think it is going to change the way a lot of people are going to be developing applications going forward.

Some of my favourite new features are:
So if you haven't already, grab a copy of ColdFusion 9 Beta, and ColdFusion Builder Beta, and enjoy!
09 June 2009 09:18 AM 0 Comments

Melbourne Coldfusion 9 and FLEX 4 Usergroup Tour

I just wanted to make sure that everyone was aware of the Melbourne leg of the ColdFusion 9 and Flex 4 Usergroup Tour, on June 17th.

Adobe ColdFusion 9

The Adobe ColdFusion team is hitting the road to discuss Centaur, the next version of ColdFusion, and Bolt - code name for the highly anticipated first ColdFusion IDE from Adobe.  Learn about exciting new features and discover how Centaur and Bolt will accelerate your ColdFusion application development. Visit the tour calendar http://bit.ly/UGTour09 to find a stop near you!

Flex 4 / Flash Catalyst

Come learn about the newest features in the Flex 4 framework, Flex Builder 4 and the newest Adobe product -- Flash Catalyst. See product feature demos, and learn how the new Flex framework powers both Flash Catalyst and Flex Builder to speed the development and testing of rich Internet applications and content.

More details and RSVP can be found here .

Hope to see you there!

 

ColdSpring News, CFConversations RoundTable and other cf.Objective() tidbits

While I am recovering from the Australian WebDU conference, a few days before that started I got off a plane after the end of the wonderful cf.Objective() conference.

I have to say, this year's cfObjective() was the best organised out of all the years I have been to.  As per usual, the content was stellar, the hotel was lovely, and it was an absolute pleasure to catch up with everyone at the conference.  I have to give a big 'congratulations' to Jared, Steven, Jim and the rest of the cf.Objective() crew for putting together such a smooth and professional conference.

I had the pleasure of doing two sessions, Rapid OO Development with ColdFusion Frameworks, which covered a variety of techniques on how to increase your development speed when building OO models, and I was very happy to see that it seemed to have been very well received.  I had one attendee let me know that 'Now I know why I'm using ColdSpring! I was using it before, but now I know why', which is an amazing thing to hear as a presenter, that you've managed to create an 'Aha!' moment for someone.

I also did my Introduction to Building Applications with Transfer ORM, which was a repeat of the session that I did last year.  Unfortunately Ray Camden couldn't make it to do his Transfer session, so I was called in at the last minute to take his place.

The big news that we announced at cf.Objective(), is that I will now be the lead developer on the ColdSpring project.  Since Chris Scott's major focus these days is the Swiz Flex framework, he decided it was time to pass on the reigns, and since I tend to talk to him regularly about Cold/Spring, have contributed code to ColdSpring , and know about running an Open Source project, he seemed to think I would be a good fit.  I'm pretty excited about the opportunity, and have discussed some great ideas with theColdSpring development group, of which Chris is going to stay on as lead architect.  I expect we will start off by building the infrastructure around the project, e.g. a centralised wiki, ticket tracker etc, and then move on to some more interesting items.

The obvious question there is, of course, what does this mean for Transfer? (I think I need to start writing down how many times I've been asked if it's 'Dead'.  Does anyone actually expect a 'yes' for an answer?), and quite frankly, I don't see this impacting on Transfer much at all, simply because this is going to be code that I would have probably ended up writing on ColdSpring anyway, but it is now a more formalised relationship.  When I run into a feature or a bug on an Open Source project, that I want to be implemented, my first natural reaction is to start looking into the code, and writing the feature.  This was first exemplified by my contribution toColdSpring of annotation based pointcuts.  There are several aspects of ColdSpring I wanted to improve on, so it was just a natural reaction for me to end up writing code for it.

As stated, the content at cf.Objective() was brilliant as per usual, with my own personal highlights being, Advanced ColdFusion Server Administration (Adam Lehman), Advanced ColdFusion 9 ORM (Terry Ryan) and ColdFusion Portlets (Adam Haskell).

Thinking about the content, I have a little confession to make, that I realised on the way back from cf.Objective() this year.  I have a tendency to go to the wrong sessions when at a conference. This may sound like a weird thing, but I realised the last few years I tend to go to sessions that I already know a lot about, just to see if they say something a little bit extra that I can add to my knowledge base.  Quite often I end up walking out feeling like I haven't added much to my repertoire.  Really what I should be doing is going (mostly) to sessions in which I know absolutely nothing about, which means I actually get the best return on the my investment in the conference.  While it may not be specifically applicable to what I'm currently doing, at the very least it will inspire me to do some interesting new things, and may give me some knowledge that I can then apply at some point in the future.  This is a philosophy I plan on applying to all future conferences that I attend.

Finally, I also had the opportunity to be part of a CFConversations round-table on the second night of the conference.  Brian Meloche, Andy Powell, Andy Matthews and I had a really good chat about the conference in general, our thoughts on some of Adobe's upcoming products, various other topics relating to ColdFusion.  It was lots of fun to do, and you can download and/or read more about it here.

Again, thanks to all the cf.Objective() crew, and look forward to seeing many of you again at cf.Objective(ANZ).
06 May 2009 04:14 PM 0 Comments

ColdFusion & Flex Data Transformations with Conduit Filters

Previously I discuss a simple mechanism in Conduit to enable you to apply data transformations on outgoing data from ColdFusion to Flex, using a simple inheritance strategy, to overwrite how the CFC=>Flex VO object translation occurred.

The only issue there is, if you need to be able to do different transformations, you end up having to combine separate code-bases into a single CFDeserialiser or CFSerialiser , which is not very portable, or decoupled.

To solve this problem, Conduit has filters that can be applied at different points in the AMF communication life cycle, and manipulate the data that is being passed through.

So, if we take the example we looked at previously, where we reversed every simple value that was travelling from ColdFusion to Flex, we can convert this into a simple filter, which is much easier to apply, and can be combined with other filters to do fairly complex data manipulation.

An example ReverseFilter looks like this:

<cfcomponent hint="filter that reverses all strings" output="false">

<cffunction name="init" hint="Constructor" access="public" returntype="ReverseFilter" output="false">
    <cfargument name="args" hint="the argument ConfigMap" type="struct" required="Yes">
    <cfscript>
        return this;
    </cfscript>
</cffunction>

<cffunction name="doFilter" hint="does the filtering - reverses strings" access="public" returntype="void" output="false">
    <cfargument name="filterData" hint="the data for the filter" type="struct" required="Yes">
    <cfargument name="filterChain" hint="the filter chain" type="conduit.core.filter.FilterChain" required="Yes">

    <cfscript>
        >//we know there will be a 'result', in the after filter
        if(isSimplevalue(arguments.filterData.result))
        {
            arguments.filterData.result = Reverse(arguments.filterData.result);
        }

        >//push on to the next filter
        arguments.filterChain.next();
    </cfscript>
</cffunction>

</cfcomponent>

The doFilter() method is the method that manipulates the incoming data, in this case, looking at the 'result' argument that is being passed in, and if it's a simple value, reversing it.

The Filter is then passed on to any subsequent filters, by calling the next() method on the filterChain.  If we didn't want filtering to continue, we could simply skip that step.

We then configure this ReverseFilter against the CFSerialiser, to convert outgoing data that is going to Flex, like so:

<destination id="Conduit">
     <channels>
        <channel ref="my-cfamf" />
     </channels>
     <adapter ref="conduit" />
     <properties>
         <source>*</source>
         <cfcs>
             <!--- cfc config --->
         </cfcs>         
         <filters>
            <!-- This is an example filter that reverses strings -->        
            <filter>
                <path>conduit.core.filter.example.ReverseFilter</path>
                <apply-after>serialiser</apply-after>
             </filter>
        </filters>
    </properties>
</destination>

The 'apply-after' section, tells Conduit to fire the ReverseFilter after the processing of the CFSerialiser, rather than before, although in this case, it won't make that much difference.

This is just a simple example for the sort of things that can be done with Conduit Filters, but it should give you a good idea on how with a few simple filters, you can drastically change the way data is sent to and from Flex and ColdFusion.

If you want to read more about Conduit, please have a look at the wiki, and daily builds can be downloaded from the google group.

03 April 2009 08:58 AM 0 Comments

cfObjective(ANZ) - Call for speakers

Several days ago, cf.Objective(ANZ) put out a call for speakers.

For those who have missed the announcements, cf.Objective(ANZ), is bringing the famous cf.Objective() conference to Melbourne Australia. 

To steal some of the copy straight from the website:

Topics we're looking for fit into (but are not limited to) the following major categories:

Architecture and Design:
OOP, Design Patterns, Frameworks, Modeling, Refactoring Legacy Apps, Persistence etc.
RIA:
LC DS and CF, Ajax/Flex with CF, BlazeDS and CF etc.
Process and Methodology:
Agile Development, SOA, Managing large CF architectures, Debugging and Metrics etc.
Integration and Testing:
CF and Java, Build and Deployment processes, Server tuning, Unit Testing etc.

Please let us know by April 24 2009 if you're interested by emailing speakers@cfobjective.com.au with a short blurb about yourself and the topics you'd be interested in presenting on.

cf.Objective(ANZ) will provide speaker accommodation for the night of the 12th to the 13th of November 2009 at the conference venue (Renaissance Hotel in Melbourne). At this stage we unfortunately can't provide any further financial assistance with travel cost or other expenses.

So if you wish to speak, or if you wish to hear about a particular topic, please feel free to send an email to the above address to let people know.

If you want to know more, you can check out the website , sign up to the website, and also follow the twitter feed !

Hope to see you all there!

 

Coming to speak at cf.Objective()!

As per usual, I'm late with my announcement that I will speaking at cf.Objective() again this year.  It is actually really interesting to see the schedule contain so many sessions that cover OO concepts, and specifically, how to use common tools and development practices to make OO development in a web application context so much easier, better and faster.


This is obviously a real trend in the ColdFusion thoughtscape, with sessions like:
  • Introduction to OO Modeling and Design - Brian Kotek
  • Taking Code Reuse to a Higher Level - Jeff Chastian
  • Building an Object Oriented Model - Bob Silverberg
  • RAD OO in Code - Peter Bell
  • Atomic Reactor - Mark Drew
  • Leveraging Basic Object Oriented Concepts and Design Patterns in ColdFusion - Phill Nacelli
  • What to do When OO Fails you in ColdFusion - Brian Meloche
  • The Best of Both Worlds: Java Backends with CFML Frontends - Matt Woodward
  • Object Relational Mapping with ColdFusion - Jason Delmore
  • An Object Oriented Approach to Validations - Bob Silverberg
  • Leveraging Enterprise Open-Source Java in ColdFusion - Joe Rinehart
..and of course, my very own Rapid OO Development with ColdFusion Frameworks.

If you are looking to do, or already are doing Object Oriented development in ColdFusion, this is quite obviously the place to be!

In my Rapid OO talk, we are going to take a completely manually written OO model, including persistence to the database, and slowly strip parts of the code away, replacing them with a combination of ColdFusion Frameworks and custom generic code, to give you some new tools in your 'OO Development tool-belt', that you can then go away and play with, and hopefully include in your day to day development practices.

Look forward to seeing you all there!
17 March 2009 03:44 PM 0 Comments

Speaking at WebDU this year!

I'm a little late in posting this, but I had figured I should at least mention that I am speaking at WebDU this year again.

For those who haven't been before, WebDU is a fantastic Adobe/Web technology focused conference that has been happened in Sydney for quite a while now.  This year I'm particularly excited by a lot of the Flex/RIA content that is being presented.

WebDU Banner

I'll be there this year talking about a Conduit , the ColdFusion adapter for Blaze DS, which allows you to all sorts of weird and wacky things with data transfer to and from Flex and ColdFusion.  I'll be showing off some cute and clever data transformations and interesting techniques for data exposure using Conduit, so it should be a interesting presentation for anyone doing ColdFusion and Flex development.

Look forward to seeing you all at WebDU!

cf.Objective() Comes to Melbourne, Australia: cf.Objective(ANZ) is born!

Last year I got the opportunity to have dinner with the steering committee of cf.Objective() in the United States, and the topic of bringing cf.Objective() over the Australia was brought up.  I was instantly excited by the idea as I had always had such a wonderful time at cf.Objective() in the US, and had found it such a marvelous ColdFusion learning experience that I've been back every year since, and am speaking again this year.

Apparently, I've now been given the title of 'cf.Objective() Vice Instigator - Pacific Operations ', for generally just being that annoying guy in the background going 'so what do we do next?', and harassing people on IM to make sure they show up for teleconferences.

Having a stack of focused, ColdFusion specific, Enterprise software development knowledge coming directly into Melbourne is going to be great for local ColdFusion ecosystem, both for Melbourne, and also for the Australia and New Zealand region. 

Speaking from experience, simply having a lot of smart minds that do enterprise ColdFusion development, in the same place, at the same time, talking ColdFusion, means that all sorts of interesting ideas and opportunities get discussed, developed, and often worked on in the halls of the conference.

The conference dates are the 12th and 13th of November, 2009.

We are still in the process of lining up sponsors and speakers, so if you are interested in either, please check out the website for more details and/or sign up for the mailing list, so you can be appraised of further developments. 

If you are interested in coming to cf.Objective(ANZ), please sign up for the mailing list as well, so you can stay abreast of the latest and greatest news for the conference.

Oh, and the hotel is gorgeous, you should check out the online video!

I look forward to seeing you all there!

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

23 November 2008 06:22 PM 0 Comments

CodexWiki goes open Beta!

For a while now, Luis Majano and I have been working on CodexWiki , a ColdBox , Transfer and ColdSpring powered wiki.

The features in it have come together really nicely, including one of the slickest wiki editors I have ever seen, and it has finally gotten to the point where there was no point in keeping it in private beta any longer.

If you are interested in checking out go to http://www.codexwiki.org , and if you wander over to the ColdBox blog , you can see some great screenshots.

Its been great working with Luis, and we have many more ideas for this wiki in the coming future! Watch out :oD

23 November 2008 01:02 PM 8 Comments

ColdDoc 0.1 Released

ColdDoc 0.1 is finally ready as a release version.

ColdDoc is a port of JavaDoc for ColdFusion, and generates static .html files that display API information for a collection of CFCs.

ColdDoc was initially written to output the API documentation for Transfer, which can be seen here .

The benefits of outputting documentation to static html files, rather than doing it dynamically include:

  • Less processing at run time 
  • Documentation can be linked to, without fear of page names and/or anchors changing
  • The ability to generate API details such as Direct known subclasses and Method Overrides information which would be too expensive to determine at run time.

Currently ColdDoc only supports a single root path, and is missing some JavaDoc implementations, such as a Index page, and Interface documentation, and can only run on ColdFusion 8.

ColdDoc can be downloaded from here .

12 November 2008 10:31 AM 0 Comments

Melbourne CFUG - 20th of November

The last Melbourne CFUG for the year!

Location:
NGA.net, Level 2, 17 Raglan St, South Melbourne
Map: http://link.toolbot.com/google.com/73016

When:
November 20, Meeting starts at 7:00, so get there before hand (doors
open at 6:30).
   
Agenda:
Steve Onnis talks about virtualisation

Steve will be presenting on server virtualisation using VMWare.  VMWare allows you to create
virtual operating systems that run independent of your main operating systems giving you the
flexibility to create development environments for testing.

Demonstrating the setup process and vm tools, you will gain an understanding of what virtualisation
is and an insight into what virtualisation can do for you.

If you are going to attend, please RSVP to mark (dot) mandel (at) gmail.com.

Only those that RSVP are eligible for the door prizes, so make sure you apply!

See the CFUG Melbourne Calendar at:
http://www.cfcentral.com.au/Events/index.cfm

Or add to your Google Calendar - search for 'CFUG Melbourne'.

As per usual, we'll grab pizza during the evening, so we have
something to scoff down!

Look forward to seeing you all there.

09 November 2008 04:33 PM 9 Comments

Transfer Survey, and the Results Are In!

I officially closed the Transfer survey a short time ago, as results had slowed to a crawl.  Overall we had 87 respondents, and it was really, really useful to get the feedback.

I can honestly say the feedback from this survey has changed the road-map for the next two releases of Transfer.

Transfer Experience

This was a really interesting set of questions.  41% of respondents say that they use Transfer every day, which is really exciting. Only 1 person responded with What is Transfer?, which hopefully means I'm doing a decent job of getting at least the name 'Transfer' in people's knowledge sphere.

Most people have been using Transfer for only 1-6 months (30%), while coming second place (26%), 6 months to a year, and third 18% for 1-2 years. Only 2 people have been using it for more than 2 years, but since the project has only been around for 3, and the first year, itwasn't all that stable, I'm very happy with these results.

The version of Transfer that people are using totally shocked me! 73% of people where running either 1.1 (which at the time was RC), or the BER release of Transfer. 36% of people were running 1.0. Only 3 people were running 0.6.3, which is a good thing, as it was a really buggy release.  I'm so pleased to see the adoption rate is so high!

Other ORMs people have used

This was another interesting section, in that Reactor scored the highest at 51%, and Hibernate came in second at 21%.  Interestingly enough, 31% of people had never used an ORM before Transfer.

Transfer Enhancements

Not surprisingly, 58% of people that that Performance improvements were most important.  I wasn't surprised by this, and I expect this won't change no matter how fast I make Transfer.  The annoying thing is being constrained quite severely by how fast ColdFusion can createCFCs, which isn't nearly as fast as I would like.

Several comparisons where made between Hibernate (and other Java/Groovy ORMs) and Transfer, and while it is understood that Java will always be faster, they still want comparative speed out of Transfer.  Not sure how I'm going to get that to happen, but I know I will try my best.

To quote a survey taker: '...the whole thing about not really being able to instantiate collections of associated objects with decent performance - therefore you do your head in constantly switching between object-think and query-think.  This is the #1 reason I'd choose Java over CF for a decent-sized domain layer.'

The fact of the matter is, he is right on what he's saying, and I hope its something that Adobe listens to with future versions of ColdFusion.

Interestingly enough, there were several requests specifically to be able to retrieve arrays of Transfer generated Objects.  I had purposely avoided it due to performance concerns, but I think this may be something that will end up being discussed on the Transfer mailing list further, as there were a few people who were interested in this feature.

Integrated Flex support was another hot topic.  I'm currently in the process of learning Flex at the moment, so expect to hear solutions for this common problem around the corner.

DB introspection was a huge draw card, with multiple comments like '...config file generation without using illudium...' and '...non-generative XML can be burdensome in large applications...', which is all true.  In the next few releases we'll be looking at doing property auto-generation from the database, and also providingDDL support for Transfer to generate your database for you.

Inheritance mapping was also a big feature request (far more so than I had originally ever thought it would be, and this is even before the recent spate of ORM articles), and got me thinking about it a whole lot more.  To that effect, expect to see Inheritance mapping as one of the next big features in the next release of Transfer.

Some other interesting requests that came through were:
  • Annotations in Transfer XML data
  • Railo support
  • Generate methods for setting object properties from a struct
  • Query paging / Query limits
  • Bidirectional M2M compositions.
  • TQL aggregates

Support and Documentation

Support seems to be well received, with 46% of people giving Transfer support a 4, and 30% giving it a 5, where 5 was 'Very useful' and 1 was 'Not Useful'.

That being said, ease of learning could be better, as on a scale of 1 (Easy) to 5 (Really hard), the majority, 43%, sat in the middle at, 3, although 34% gave it a 2.

From reading comments, the big element to help Transfer learning, is examples, examples, and when done, some more examples. Comments include: 'Beginner Tutorials, step-by-step type. Maybe even videos...', 'Lack of tutorial type documentation. Especially for advanced topics.', 'The examples on the site are a bit limited...', 'More examples, and more advanced examples...', so the pathways are pretty clear.  I will be contacting members of the Transfer community and contacting people who participated in the survey to help with this.

Conclusion

I'll be finalising the road-maps for the next 2 releases of Transfer based on this feedback, however, I'm looking at moving to Skweegee from Project Tracker, so once I've made a decision in that area, and how to manage previously completed tickets and milestones, I'll get stuck in.

Thanks to all who participated, it was really useful to get the feedback!
23 October 2008 04:23 AM 7 Comments

Adobe eSeminar tomorrow: Transfer ORM Caching Mechanics

Just a reminder that I'm doing an Adobe eSeminar tomorrow at 2pm on Transfer Caching Mechanisms

One of the most powerful features of Transfer is its highly configurable, in-built caching layer that allows for significant performance gains for a given application when configured correctly.

During this eSeminar we'll discuss caching concepts such as 'caching algorithms' and 'memory sensitive caching', so that as a Transfer Developer, you'll have a better understanding of the intricacies of Transfer.

Click here to register

Click here for World Times

20 October 2008 09:45 AM 3 Comments

Managing Selfish Threads in ColdFusion

As per usual, this is something that came out of my work with Transfer, but is something that applies to any ColdFusion application that exists.

So in the context of ColdFusion, what exactly are we referring to when we say Thread?  Generally the first thing we think of is <cfthread>, which executes some code on its own given Thread.  But, we should also remember that the original page that was executing, is its own Thread as well.  If we run a scheduled task, that is also it's own Thread.

Wikipedia defines a Thread very well:

"A thread in computer science is short for a thread of execution. Threads are a way for a program to split itself into two or more simultaneously (or pseudo-simultaneously) running tasks..."

So when looking at Threads, we can consider:
  • Any Coldfusion page execution,
  • Any remote CFC execution
  • Any Scheduled Task execution
  • Any CFThread execution

To be its own Thread, because, it is!

So what defines a Selfish Thread?

A Selfish Thread is a thread that takes up almost all of the CPU's processing, without allowing any other Thread to be able to utilise the CPU at all.

Some code like this, would be a good example of a Thread being selfish -

<cfscript>
    for(counter = 1; counter <= 10000; counter++)
    {
       writeOutPut(counter & "<br/>");

    }
</cfscript>

It's a very tight loop, and there is no waiting, or pausing, or 'room' for any other processing to do anything else while this loop processes.

Now it should be noted, that a Selfish Thread may not necessarily be a bad thing.  In many instances, we want this loop to completed, without waiting for any other Thread to interrupt it.  But in cases when Thread execution can go on for a long time, this can be highly disruptive to an application, as nothing else can be done during that time.

The common CF solution I often see for this, is the scheduled task that runs at 3:00am, so that it doesn't bother any of the users.  This can work perfectly well for many applications, but what if your application is 24 hours? Or is something that has to run every hour, what do you do then?

Before we get into this too much, I want to make note of something - managing Threads is bit black magic, and a bit trial and error.  Since Threads are managed differently per OS, and there are differences per JVM, some of these techniques will work, and some will not, so make sure you test everything thoroughly so you know that it is affective for your OS and JVM configuration.

The other thing to note, is that any Thread that is running, is an actual instance of th Java object java.lang.Thread.  If at any point and time we want access to the actual Thread object that the given process is running we can run:

currentThread = createObject("java", "java.lang.Thread").currentThread();

Will return a reference to the currently executing Thread object, which will be very handy as we move along.

The first thing we should look at, is <cfthread>.  CFThread has a 'priority' attribute that can be set to 'HIGH', 'NORMAL' or 'LOW', which should  control the level of priority that a Thread has.  For example, a HIGH priority thread should have processing precedence over a LOW priority thread.

For example:

<cfthread action="run" name="foo1" priority="LOW">
<!--- do some processing --->
</cfthread>


In reality, I've not seen this actually do much (in my tests), and it does not seem to actually effect a Thread's Thread.getPriority(), which we will talk about later.  That being said, there may be some other mechanism under the hood, and its not going to hurt anything if you choose to use it.

From here, we can look at setting a Threads priority, which can be applied to any CF based Thread (i.e. pages, scheduled tasks, cfthread etc).  A Threads priority goes from 1 to 10, where 1 is the lowest priority, and 10 is the highest.  5 is usually considered 'Normal'.

In theory, a lower priority Thread should give way to a high priority Thread whenever the higher priority Thread requires CPU processing time.  As stated earlier, depending onJVM and OS, this may, or may not happen.

To set the Thread's priority, all you need to do is grab the current thread, like we did above and call:

currentThread.setPriority(2); //set it to a lower priority.
//do some processing...

Since ColdFusion tends to pool Thread (i.e. stores them for reuse), we should reset the Thread's priority after we are done with it, so that it doesn't stay that when it gets used to execute another piece of code. e.g.

priority = currentThread.getPriority();

currentThread.setPriority(2); //set it to a lower priority.

//do some expensive, long running processing...

currentThread.setPriority(priority); //reset it

This way, when the Thread get re-used, the Priority is not set to something that is inappropriate for the processing it is doing.

There are also mechanisms in Java that allow you tell the JVM when a good time is for the current thread to yield to other threads that need to do some processing.

This simply hints to the JVM that 'hey! now would be a really good time for me to pause for a second, if you wanted to do something else'.  The JVM can totally ignore this if it chooses, and depending on OS and JVM, it may well do.

To do this, we call the static method yield(), on java.lang.Thread, like so:

createObject("java", "java.lang.Thread").yield();

So we can now take our very selfish loop above, and do something similar to:

<cfscript>
    for(counter = 1; counter <= 10000; counter++)
    {
       writeOutPut(counter & "<br/>");
       createObject("java", "java.lang.Thread").yield(); //here is a good place to pause
    }
</cfscript>


This is actually a very poor use of yield(), simply because in a display, we would never want the server to pause when displaying some data, but it displays how it works reasonably well.

The interesting thing is, yield() automatically resolves what the current thread it is processing on, and works that way, rather than the setPriority() method we saw above, which required us to use a specific Thread.

Quite probably the least useful, but the most consistent way of managing selfish threads, is by putting the thread to sleep, which will allow other Threads access to the CPU while that thread is asleep.

This is the least useful, as no matter what, the Thread will pause.  Nothing else may be happening on the server, but the Thread will pause anyway, which can mean wasted cycles for whatever it is you are doing.

That being said, this will always work, no matter what JVM or OS you are on, so there is a trade off.

There are three ways we can make the current thread sleep in ColdFusion,

In cfscript:

<cfscript>
    sleep(1000);
</cfscript>


via a Tag

<cfthread action="sleep" duration="1000" />

And via Java,

currentThread = createObject("java", "java.lang.Thread").currentThread();
currentThread.sleep(1000);

Either way, in the above example, the current thread will pause for 1000 milliseconds.

In a real world example, there is no reason we can't combine these techniques.  If we had some processing we wanted to happen asynchronously, but we knew it was going to take a while to complete, we could do something like the following:

<cfthread action="run" name="foo1" priority="LOW">
    c
urrentThread = createObject("java", "java.lang.Thread").currentThread();

    priority = currentThread.getPriority();

    currentThread.setPriority(3); //set it to a lower priority.

    for(counter = 1; counter <= 10000; counter++)
    {
       doSomethingExpensive();
       createObject("java", "java.lang.Thread").yield(); //could pause here
    }

    currentThread.setPriority(priority); //reset it
</cfthread>


Which gives us multiple ways in which to tell Java to make sure that other Threads are able to access the CPU.

Next time you are looking at a long running, expensive process, you now have multiple options about how you want to manage it.

17 October 2008 06:17 AM 2 Comments

Transfer 1.1 Final Released

After a few minor delays, Transfer 1.1 Final is ready for final release.

A few bugs and fixes occured during the release candidate period, so make sure you upgrade to the final release if you are running the release candidate.

For those of you not familiar with the new features of 1.1, some of the highlights of 1.1 are:

Huge Performance Enhancements!

During Testing (on my machine), a 500 Object load has been reduced from an average of 8 seconds down to an average of 6 seconds.   This is a speed increase of around 25%!.  I've even seen Object loads of 500 objects as small at 2 seconds.

Even for the performance alone, it is worth upgrading!

Transfer Object Proxies

This of this like Lazy Loading, but on steroids!

With a simple new setting 'proxied' on onetomany, manytoone and manytomany elements like so:

<onetomany lazy="true" proxied="true">
...
<onetomany>

Objects in the collection will be loaded as Proxies of the real object, and their underlying data will be loaded on an individual basis upon request.

A very handy feature when dealing with large collections.

New Discard Algorithm

Before, if you had a configuration when A -manytoone->B, and B was discarded from the cache, both A and B would have been discarded.

Now in the new algorithm, if B gets discarded, A simply unloads its many to one, and stays resident in the cache.  This ensures there is less unnecessary too-and-fro between the database and Transfer's cache.

Cache Monitoring and Reporting

While there is a new CachMonitor component that allows you to get fine grained reporting on what the cache is doing, to get a re-built cache report, it is as simple as:

<cfimport prefix="report" taglib="/transfer/tags/reports">
<---  Basic Report --->
<report:cacheReport monitor="#application.transferFactory.getTransfer().getCacheMonitor()#">

<---  Detailed Report --->
<report:cacheReport monitor="#application.transferFactory.getTransfer().getCacheMonitor()#" mode="detail" chartsize="300">

TQL Custom Tags

Big thanks to Elliot Sprehn for contributing these TQL custom tags, that make it super easy to do TQL queries, in a <cfquery> style!

For example:

<cfimport prefix="t" taglib="/transfer/tags">

<---  Do list operations --->
<t:query name="result" transfer="#getTransfer()#">
        select
                u.firstName, u.lastName
        from
                user.User as u
        where
                u.email like <t:queryparam value="%example.com" type="string">
</t:query>

<---  Do read operations --->
<---  Get a single record as a TransferObject --->
<t:query name="user" action="read" class="user.User" transfer="#getTransfer()#">
        from
                user.User as u
        where
                u.email = <t:queryparam value="user@foo.com" type="string">
</t:query>

Lots of bug fixes

The usual slew of bug fixes, improvements, and other various adjustments.

If you want more information on what got included in this release, and why to upgrade, I would highly recommend the 'What's new in Transfer 1.0 (and 1.1) ' presentation recordings, and also make sure you check out the Release Notes .

Transfer 1.1 download .

13 October 2008 08:27 AM 0 Comments

Transfer Survey, now open!

I've put together a short Google Forms survey on Transfer to get some consolidated feedback from the community at large on what people are doing with Transfer, what features they want in the future, and what can be done to improve it overall.

It isn't limited to just people who are using Transfer.  If you are not, I also want to hear your reasons why, as hopefully it is something that can be improved upon in the future.

It shouldn't take you much longer than around fifteen minutes to complete, and I would really appreciate the feedback.

Transfer Survey

 

08 October 2008 10:11 AM 2 Comments

Melbourne CFUG - 16th of October

All,

This Month's CFUG is lined up!

Location:
NGA.net, Level 2, 17 Raglan St, South Melbourne
Map: http://link.toolbot.com/google.com/73016

When:
16th of October, Meeting starts at 7:00, so get there before hand (doors
open at 6:30).

Agenda:
Recorded Presentation by Dan Wilson

Refactoring in ColdFusion

If you would like to know how to migrate an existing procedurally programmed application into an object oriented one, grab a chair and sit for a while. We'll discuss some sensible guidelines designed to help you make incremental changes towards OO nirvana. We'll also look at lots of code samples, we all like code samples, right?

If you are going to attend, please RSVP to mark (dot) mandel (at) gmail.com.

Only those that RSVP are eligible for the door prizes, so make sure you apply!

See the CFUG Melbourne Calendar at:
http://www.cfcentral.com.au/Events/index.cfm

Or add to your Google Calendar - search for 'CFUG Melbourne'.

As per usual, we'll grab pizza during the evening, so we have
something to scoff down!

Look forward to seeing you all there.
04 October 2008 12:10 PM 0 Comments

Not been blogging much, where have I been?

I came to the realisation the other day, that my blog has really become almost totally announcement based.  A series of presentation announcements, eSeminars, ColdFusion User Groups, Code Releases and various other 'hey! this is what is going on' posts.

It used to be chock full of weird and interesting things you could do with ColdFusion, and combining with the Java layer that sits underneath it to do even weirder and even more interesting things with that.  Sadly, I've been super busy over the past <insert long time frame>, and I've let things slip.

That being said, I plan on returning to the original theme of this blog, and start publishing some of the new things I've found out about ColdFusion, and what can be done with it.  I've got some interesting ideas on article on ColdFusion and Threading, and also some more on onMissingMethod and method injection and manipulation, so be prepared!

So what has kept me so busy? Quite a lot actually. In no particular order...

Consulting full time.
This has been one of the biggest changes, and adjustments for me to make over the past 6 months or so.  That being said, it is going very well, and I am keeping myself very busy (Almost too busy!).  I love working from home, and love the flexibility working for myself gives me.

I also find it is a really rewarding experience. Working for yourself challenges you in a variety of ways, as you only have yourself to rely on, and you are solely responsible to make it or break it.

While mostly I've been doing Transfer related work, I've also been doing some mentoring and memory leak analysis, all of which have been really interesting.  Coming from a background in which I have tended to work on single projects for months/years at a time, having a variety of undertakings going at once is a nice change.

Speaking at webDU
I didn't even blog about this, which was very remiss of me!  But I went to webDU, which was great fun.  I gave a presentation on TQL, and although I had some projector issues, it seemed to go quite well.

Writing Transfer code
I also got very busy writing Transfer 1.2 in my spare (?) time.  I'm really getting excited about Transfer all over again, and I think I have some really interesting ideas for the future. The next version is almost mapped out in my head... but I will wait until after the Transfer Survey before setting it in stone.

Writing DevNet Frameworks Article
Writing articles always take far longer than you expect them to, but when they finally get published, it feels really great.  From the feedback I've received the Introduction to ColdFusion Frameworks has been well received, and given some people new to frameworks some perspective over the landscape.

Something Super Cool Special
Been spending some time doing something really, really cool, but I can't really talk about it yet...

Don't you hate it when people say that? ;o)

Technical Editing for FAQU
I've also started technical editing for the Fusion Authority Quarterly Update, which one was one of those random opportunities that show up during a conversation I was having with Judith Dinowitz.  Editing other people's articles in an interesting endeavour, but (I find) much easier than writing them in the first place ;o)

Went on Holiday
I actually hadn't had a proper holiday in several years, and it has made a huge difference!  Taking a solid break for a few weeks has meant I've come back with a new passion for writing code, and a variety of other things in my life.  I always forget how much change a holiday can bring.
So that's my life at the moment in a nut shell.  Figured I would let people know what was going on.

An introduction to ColdFusion frameworks - now on Adobe Devnet!

I'm feeling pretty excited, because my first article for Adobe DevNet has finally been published.

An introduction to ColdFusion frameworks

It covers the differences between Model-View-Controller, Dependency Injection, and Persistence frameworks, and also gives a general overview of some of the most popular offerings that are available in ColdFusion right now.

There was a bit of a rush towards the end, and some pieces of it are not as perfect as I would have liked, but I hope that it serves as a way for people to enter into the ColdFusion framework world, gives them enough information so that they understand the differences between framework types, and also allow them to make an informed decision on which one to use based on their personal preferences and needs.

18 September 2008 01:55 PM 0 Comments

CFMEETUP: What's New in Transfer 1.0 (and 1.1)? - Tomorrow!

I'm doing a repeat of the What's new in Transfer 1.0 (and 1.1) Talk at cfmeetup.com tomorrow!

WHEN

Thursday, September 18, 6:00pm US EDT (UTC/GMT-4) (What time is that for you? See http://www.timeanddat... which shows the time as US EDT and you can choose your city from the list offered to see what time that is in your own timezone.)

AGENDA

After a long wait, the Transfer 1.0 release is finally here! This release comes bundled with lots of brand new features, bug fixes and performance improvements.

This presentation will give you a good overview of new functionality the 1.0 release brings to your developer tool kit, providing you with even more ways to implement your ColdFusion applications faster than ever before.

We will also have a sneak peak at some of the 1.1 features, that are currently in release candidate 2.

In case you missed the first talk, you can now catch it again!

23 August 2008 04:25 PM 0 Comments

Transfer 1.1 Release Candidate 2

Release Candidate 2 of Transfer 1.1 is now available for download.

It has several critical bug fixes from the previous Release Candidate.

While I did promise several blog posts about the new features, I simply haven't had time, as I'm been incredibly busy with client work, and working on Transfer.

That being said, the documentation for all the new features has been written in the wiki, and you can also view the latest presentation recording that I did, which covers many of the new features found in Transfer 1.1.

Transfer 1.1 Release Candidate 2 can be downloaded from here.
22 August 2008 06:57 AM 0 Comments

eSeminar Recording: What's new in Transfer 1.0 (and 1.1?)

Just to let you guys know, the recording for the recent eSeminar, What's new in Transfer 1.0 (and 1.1) is available .

You will also find the code examples available to download along with it.

It was a fun presentation to do, so I hope you enjoy it.

21 August 2008 07:02 AM 0 Comments

TransferSync for Transfer Clustering

Tom de Manincor Released yesterday TransferSync , a nice tool that works with Transfer to enable it to be used across a cluster of servers, and maintain its cache.

It's really a nice little piece of software, a huge thanks goes out to Tom for putting this together.  He's expanded on some of the ideas that Sean Corfield had in his original clustering implementation,  and has expanded them nicely.

For more details on TransferSync, check out Tom's blog posts !

18 August 2008 12:15 PM 0 Comments

Melbourne CFUG - 21st of August

Sorry about the late blog post on this! I just realised I hadn't put one up!

Location:
NGA.net, Level 2, 17 Raglan St, South Melbourne
Map:  http://link.toolbot.com/google.com/73016

When:
21st of August, Meeting starts at 7:00, so get there before hand (doors open
at 6:30).

Agenda:
Dale Fraser

Dale Fraser is the Chief Technical Officer at CogState Limited. Working on
varied projects using ColdFusion, Flex and C++, CogState develop Cognitive
Testing Software use mostly in Clinical Trials.

Report Builder (The Hidden Gem)

People may or may not realise that a report builder is included with
ColdFusion since version 7. Along with this report design tool, comes some
additional ColdFusion tags to allow you to incorporate full featured
reporting into your application without additional expense. While Report
Builder is not as rich featured as Crystal Reports or similar, it provides
all the necessary components to create reports, and being part of ColdFusion
the code and syntax used within reports is ColdFusion code that will
familiar to you all.

So if you either don't know about the Report Builder or have never has a
chance to play with it, this introduction will get you started. Things
covered will include

1.    Designing a Report (No Code)

2.    General Reporting Concepts, grouping, totalling etc.

3.    Passing a Query into a Report

4.    Generating a Report silently to a PDF

5.    Printing a Report silently to a local printer.

If you are going to attend, please RSVP to mark (dot) mandel (at) gmail
(dot) com.

Only those that RSVP are eligible for the door prizes, so make sure you
apply!

Or add to your Google Calendar - search for 'CFUG Melbourne'.

As per usual, we'll grab pizza during the evening, so we have something to
scoff down!

Look forward to seeing you all there.

14 August 2008 05:27 AM 1 Comment

eSeminar Tomorrow!: What's new in Transfer 1.0 (and 1.1?)

I'm going to be presenting 'What's new in Transfer 1.0' in Adobe's continuing eSeminar series.

Agenda:
Transfer 1.0 is finally here! This release comes bundled with lots of brand new features, bug fixes and performance improvements. In this eSeminar we'll introduce you to the new Transfer functions and provide more ways to implement ColdFusion applications faster than ever before.

We may also look at the new features that are in 1.1 at the same time as well.

Time and Date:
Melbourne, Australia: 2pm, Friday 15th August
USA - PST: 9pm, Thursday 14th of August
USA - EST: 12am, Thursday/Friday, 14th of August
London, UK: 5am, Friday 15th of August

For more times in your timezone, see: http://snipurl.com/3fk87

To register, go to:
http://www.adobeeseminars.com.au/events/register/18103633

Look forward to seeing you guys!
 

04 August 2008 10:52 PM 0 Comments

Transfer 1.1 Release Candidate

Transfer 1.1 Release Candidate

Hot on the heals of Transfer 1.0, is Transfer 1.1, now with added sugar and spice, and all things nice! :oD

This release has been squarely aimed at large Transfer based systems, in order to give them more control over the caching layer, and provide more performance overall.  (Which is not to say this isn't a release for everyone else as well, because there are lots of good things to share all around).

I'm not going to go into huge detail on each of the new features, but instead will be running a series of blog posts, highlighting each of the new main features and how you would use them over the next coming week or so.

The documentation is still mostly forthcoming (have to get that paying work finished!), but expect it to show up on the wiki in the next few days.  If you want a head start, most of the tickets linked in the release notes have a link to the relevant google group post, or the usage details can be found in the tickets themselves.

To give you a taste, of some of the really interesting new features:
  • A performance upgrade of at least 25% in object loading!
  • Introspection and statistics for the caching layer
  • A new cache discard algorithm, that allows granular control over the cache
  • New cache time-out settings
  • The ability to load manytoone, onetomany and manytomany collections as TransferObject Proxies, giving you a way to manage large object collections.
  • Custom tags for TQL (Big Thanks to Elliot Sprehn!)
  • Plus more!
You can read about all the details on these features in the release notes.

Happy Downloading!
07 July 2008 08:25 AM 11 Comments

How do you test CFML against multiple versions of ColdFusion?

'How do I run ColdFusion 8 and 7 side by side on IIS?' or 'How can I run Railo and Adobe ColdFusion side by side, so I can share the same code base?', is a question I see quite regularly on CF lists.

I figured I would write up a blog post about how I go about solving this problem, since I do this a lot with my Transfer development.

The quick answer is - I don't.  Trying to set up two different Application servers (CF7 vs CF8) on the same Web Server (IIS or Apache), is not something I desire to tackle, and seems way more convoluted than I care to trouble myself with.

The problem is usually broken down into:

  • How do I test the same code on different versions of CF?
  • How do I do so without having to move/sync files between machines?
  • How do I set it up so it is easy to switch between versions of testing?

I solve each of these problems with Virtual Machines , and Shared Folders.

I have actually bought VMware's Workstation product, and I use it every day, but there are several free products out there that will do virtualisation for free.

First thing first, where does my actual CFML code sit? This sits on my primary machine, commonly referred to as the host machine, in VM speak.  This is because the host has guest machines, namely of the Virtual Machine variety.

This means my CFML code is always available if I want to get my hands on it, and I can open it in Eclipse on my host machine as well, so I do all my editing and development with tools on my host machine.

I also do this because I can then share this code between virtual machines, using a mechanism called Shared folders.

So, now that I have my ColdFusion code, I create myself a new virtual machine.  In my case, I use Ubuntu Server, because its lightweight, and I can get one up and running in about half an hour, but you could use XP, or anything that runs CF.

I then configure my virtual machine to share my host folder which contains my CFML, which is a setting I am able to configure within VMWare. This then becomes accessible at /mnt/hgfs/wwwroot in my Ubuntu server on my VM.

From here, I can now install ColdFusion 8 on this VM, and point it to /mnt/hgfs/wwwroot folder to serve cfml from.

I can then create extra virtual machines, one for each version of ColdFusion that I need.

When I need to test against a version of ColdFusion, all I need to do is start up the virtual machine in question, and browse to it.  To switch versions of ColdFusion, I simply power the current one down, and start up another one.

I find this a much easier way to test the same code base between different versions of ColdFusion than trying to run them side by side.

03 July 2008 11:59 AM 0 Comments

Melbourne CFUG - 17th of July

We're back to regular CFUG's, after the break for WebDU, and I think we have a pretty interesting presentation lined up!

Location:
NGA.net, Level 2, 17 Raglan St, South Melbourne
Map: http://link.toolbot.com/google.com/73016

When:
17th of July, Meeting starts at 7:00, so get there before hand (doors open at 6:30).

Agenda:
Elliott Sprehn

Elliott is a software engineer at TeraTech, Inc. and the lead developer for the Conferences department. He has worked on a variety
of projects that include network services, realtime messaging systems, survey processors and most commonly web applications. As a strong advocate of web standards and accessibility he volunteers his free time to help new developers learn standards and best practices. He is also proponent of design patterns and draws his vision about application design from experience with many languages that include ColdFusion, Java, ruby and php.

Internals of the Adobe ColdFusion Server
To many CF developers the ColdFusion server is a block box that just works. This presentation takes a look at how the internals of the engine operate. The presentation covers how variables, scopes, functions, cfcs, custom tags, includes and java objects are implemented and how we can use this knowledge to do things not normally possible with the CF functions.


We'll look at how to implement several features in CF6, CF7 and CF8 like:
- Query Caching with the native CF query cache for queries that use
cfqueryparam.
- Create and execute queries that use cfqueryparam from cfscript.
- Create a function like CF8 to get database info for a datasource.
- Add global mappings by appending to a structure like this.mappings in CF8.
- Call functions and component methods and inspect the local scope
after their execution.
- Access the Application.cfc anywhere in an application.
- Allow passing arrays of values in the url scope instead of lists
when there are duplicate keys.

If you are going to attend, please RSVP to mark (dot) mandel (at) gmail (dot) com.

Only those that RSVP are eligible for the door prizes, so make sure you apply!

See the CFUG Melbourne Calendar at:
http://www.cfcentral.com.au/Events/index.cfm

Or add to your Google Calendar - search for 'CFUG Melbourne'.

As per usual, we'll grab pizza during the evening, so we have something to scoff down!

Look forward to seeing you all there.
19 June 2008 05:19 AM 16 Comments

ColdFusion 9 + Hibernate == Transfer Killer?

So I figured I better head this off at the pass, because I'm already getting questions in my inbox about whether this is the end of the road with Transfer , and what I plan to do with it, and OMGZ! TRANSFER IZ DEADZ!!!.

Let it be known, it couldn't be farther from the truth.

Transfer is not dead, development will still continue way into the future, and I can see a healthy life-cycle for its continuance.

A few points for your consideration:

  1. ColdFusion 9 is not even here yet.  Nobody even knows the exact date it will be shipped.  You want ORM? You can have it right now with Transfer! No waiting around, no fussing.  The documentation is written, the example applications are there, and you already have a large community to integrate with. 
  2. Hibernate integration may not even be implemented with ColdFusion 9.  Yes, we've seen some short demo's, but we've seen demo's of functionality in pre-release at keynotes before, and they didn't make it into production before.  Hibernate and ORM is a pretty complex beast, and especially tying that into CFCs, so any number of things could make it ship late, or not at all.
  3. ColdFusion 9 will cost you $$$ to upgrade.  So you're not getting all this for free.  Transfer can be used right now for $0, and will always be $0.  It is only then up to you whether you want to pay for support, or training, consulting or even new features!
  4. The Transfer release cycle will always be faster than ColdFusion's.  If there is a feature you want in CF's ORM support, you'll have to wait ~18 months.  The Transfer release cycle is around the several month mark, and with the sponsored development program, the features you want in your ORM support can generally be developed in the same week you request them in, in fact the last sponsored development I completed I did in 6 hours! (Yet to be blogged, although in SVN).
  5. We don't know how well the ORM integration in ColdFusion 9 will be developed.  While I love the hard work that Adobe does, we can all remember Flash Forms.  Lots of Shiney, not very useful (maybe that was too low a blow? ;) ).  My point is, there is no point in putting the nail in the coffin until we really know what we are dealing with.
  6. There are plenty of businesses and projects out there using Transfer already, and there is no reason they would suddenly stop using it, and switch (although that is a possibility).  As long as people keep using Transfer, I will keep developing it.
  7. Transfer is a proven technology that has undergone a lot of rigorous testing.  While Hibernate can say the same, we have yet to see how the ColdFusion and CFC integration will perform.
  8. There is no reason why Transfer can't take advantage of some of the ORM integration tools.  For example, if a CFC annotation structure is setup for use with Hibernate, there is no reason Transfer couldn't use the same annotations, so using one tool or another is quite seamless.
  9. All in all, competition is a good thing.  Having competition forces everyone involved to strive to become best in breed.  So this will actually be a good thing, both for Transfer and for ColdFusion.

I don't want to be showering doubt over the ColdFusion 9 integration with Hibernate, it makes sense for them to do it, and I can completely see where it is coming from, and there are a lot of smart people behind it.  But, there is still a lot of unknown factors here, and a lot of reasons to still use Transfer, so don't feel like the project, or the business is going to die, because its not.

I'm really excited by some of the announcements I've been seeing with ColdFusion 9, including the ORM integration, and I think the next few years will be an exciting time for the ColdFusion community.

10 June 2008 05:43 AM 0 Comments

CFMeetup Transfer Introduction Recording

This is just to post a link to the recording of the session of Introduction to Building Applications with Transfer ORM that I did recently on cfmeetup!

To view the recording, you can go here .

This one should hopefully not have the sync issues the previous one did.

08 June 2008 12:20 PM 5 Comments

Transfer 1.0 Goes Gold!

Today is the day in which Transfer finally hits its stable, final, and complete 1.0 status.

The release candidate phase is finally over, and it showed up some critical bugs, which have since been fixed.

Things are moving along speedily, with the recent completion of the support contracts, and sponsored development programs.

I just finished writing a day's training program for webDU, which will soon to be available both on-site, and via Connect.

On the next to-do list, is the rebuilding of the Transfer and Compound Theory websites, with alerts for events, training, and a whole lot more!

I'd like to extend a huge thank you to the community that surrounds Transfer, you guys are fantastic, and without you there is no way Transfer could be where it is now.

Keep expecting good things from Transfer!

You can download the 1.0 Release from here.

For more details, check out the Release Notes.
05 June 2008 03:10 AM 1 Comment

Transfer Presentation Tomorrow on Meetup.com

Tomorrow, I will be presenting my Introduction to Building Applications with Transfer ORM presentation, that I gave at cf.Objective() on coldfusion.meetup.com.

This will happen at:

USA EST:  Thursday, June 5, 2008 at 6:00 PM

USA PST:  Thursday, June 5, 2008 at 3:00 PM

Australia: Friday, June 6, 2008 at 8:00 AM

London: Thursday, June 5, 2008 at 11:00 PM

More details can be found at: http://coldfusion.meetup.com/17/calendar/8035918/

See you all there!

22 May 2008 03:34 PM 4 Comments

Transfer Support Contracts and Sponsored Feature Development

Announcing two new developments for the Professional Open Source Software side of Transfer.

Compound Theory is now offering the following new programs:

Transfer Support Contracts

The basic yearly support package provides you with 20 hours of support, covering:
  • Installation
  • Usage
  • Performance
  • Bug Fixes
Contact through several different channels, including:
  • Email
  • Skype
  • Instant Messenger
Extra support hours can be purchased at any time, and rolled over into subsequent years if required.

Sponsored Feature Development

If there is a feature that has yet to be developed for Transfer that your project could really use, either from the extensive enhancement ticket list, or something that you have thought of, it is possible to sponsor its development.

Full or partial sponsorship is available, and will give the feature you desire priority in its development, and/or the ability to specify the schedule it needs to be developed in.

If you are interested in either of these programs, or want more details, please feel free to contact me for more details through the contact form, mark [at] compoundtheory [dot] com, or through Skype through the account mark_mandel.
19 May 2008 11:49 AM 0 Comments

Transfer 1.0 Release Candidate 2

There have been several bug fixes and performance and memory usage improvements since the initial Release Candidate, so here I present to you Release Candidate 2!

Transfer 1.0 Final is slated for the 8th of June, just a few days before webDU is going to start!

webDU 2008
In case people haven't realised yet, but there will be a full day's training for Transfer at webDU, in which we're going to do a lot of hands on coding, so you can get a really good understanding of the Transfer framework.

The Transfer support contracts I blogged previously should be ready this week, we're just finalising some final details, so please contact me, if you have any interest in this area.

Also, just a quick reminder that Transfer based consulting services are also available right now, so feel free to contact me if you have any needs.

The Transfer 1.0 Release Candidate 2 can be download from here.

Release notes can be found here .


15 May 2008 04:59 AM 5 Comments

JavaLoader 0.6 Released

Not a huge amount to report. This release simply re-orders some of the class loading, so it is child first.

This is important in case you load up a newer (or older) version of a library that ColdFusion already has access to, and you want to make sure you get the library you want, not the library loaded by ColdFusion.

That and I fixed a bug in the JavaProxy.cfc that was sent to me a loooong time ago, that will fix an issue with resolving overloaded Java Methods.

JavaLoader can be downloaded from here.
10 May 2008 07:27 AM 0 Comments

Melbourne CFUG - 15th of May

All,

Another CFUG on the way!

(Apologies for the delay in getting this out, I was in the US!)

Location:

NGA.net, Level 2, 17 Raglan St, South Melbourne
Map: http://link.toolbot.com/google.com/73016

When:
15th of May, Meeting starts at 7:00, so get there before hand (doors open at 6:30).

Agenda:

Richard Herbert, CTO of NGA.NET, Australia's leading e-recruitment company, has been working with ColdFusion since 1997 and version 2.0. With a background in the legal and training industries Richard has developed applications for retail, point of sale, aviation, training, manufacturing, government and of course the HR industry. Also Telstra (but who hasn't?)...

Since 2000 Richard has been building NGA.NET's e-recruitment product and delivering solutions to Top 500 companies and federal government, where NGA.NET have 100% market share.  The application has gone through many evolutionary steps, with a brand new version built on mach-ii/ColdSpring/Transfer architecture in beta for 2008. NGA.NET is in the BRW Fast 100 for 2008 - a list of Australia's top 100 fastest growing companies.

And the presentation...

...will be titled 'Usability for Developers - The Ugly Truth'. I will be seeking to provide the audience with an understanding of what the field of usability covers, how to apply usability methods during the development cycle and the surprising results you can achieve.

Depending on time, Mark Mandel will also take us through some of the CF9 discussion that occurred at the cf.Objective() conference, and give us some insight into what could possibly be coming in CF9.

If you are going to attend, please RSVP to mark -dot- mandel -at- gmail -dot- com.

Only those that RSVP are eligible for the door prizes, so make sure you apply!

See the CFUG Melbourne Calendar at:
http://www.cfcentral.com.au/Events/index.cfm

Or add to your Google Calendar - search for 'CFUG Melbourne'.

As per usual, we'll grab pizza during the evening, so we have something to scoff down!

Look forward to seeing you all there.

cf.Objective(), a review from Down Under

Okay, forgive me one Australia joke ;o).

cf.Objective() was an absolutley fanstastic conference all around, and I had an incredible time.  Not only were the presentations top notch, but it's always an incredible pleasure to meet up with the people that I only tend to see once a year, and I always get a huge burst of inspriation just being around clever people and sharing various ideas over a drink or two.

Presentations

I'm not going to go into all of the presentations, but as per usual, they were all of an incredibly high calibre, and I came out of all of them learning something new.

Highlights of the conference for me were:

Model-Glue 3: Back to its Roots - Joe Rinehart
This was a really interesting presentation, to see what MG3, code named Gesture, had in store for its users.  I really like the innovative approach Joe has taken to enable to framework to generate itself as you develop with it.

Selling Professional Development at a Hostile Shop - Terrence Ryan
I now refer to Terrence as 'the master manipulator' ;o).  He outlined a series of personality types that can often occur when working in an organisation that tends to lean against the utilisation of software development practices such as frameworks, unit testing, or version control, and how to encourage them to accept, and even appreciate, these practices when previously they had shunned them.

His use of images to illustrate each of his points was also particularly clever, I never knew that a photo of Bea Arthur wrestling a velociraptor could ever have any sort of context!

Workshop: ColdSpring 1337 - Chris Scott
Honestly, this was probably my favourite session at cf.Objective().  Chris went through some really interesting way you can use AbstractFactories and AOP to really push what is possible to do within ColdSpring.  He used a Flex / ColdSpring / Transfer/ Yahoo Maps mash-up to show this off, incorporating some nice Transfer powered Flex Remoting, implemented with some very nice ColdSpring Remote Proxy AOP work (Before people ask, yes, this will be finished off and released at some point)

Finally, Chris showed off his new Flex framework, Swiz, and while I don't even do much (any?) Flex development, I looked at and just went 'Well, that is a pretty sweet framework'.  I'm looking to do some Flex work in the near future, and I can see me really getting into Swiz.

Workshop: Advanced Techniques with the ColdBox Framework - Luis Majano
While I didn't attend most of this presentation (I think I was balled up on a couch somewhere trying not to drop off to sleep), I dropped in at the end, so that Luis and I could do a quick announcement of the CodexWiki Open Source Wiki, which is currently powering docs.transfer-orm.com.  We are opening a private beta for Codex, before we do a full release. If you are interested in being involved, feel free to drop me an email.

Transfer

One of my favourite things about the conference was running around giving lots of people Transfer stickers.  It gave me a wonderful opportunity to talk to lots of people about Transfer, and I think I actually managed to get it so that about one in every third person had a Transfer sticker on their laptops (Statistics based on no real analysis)! I passed on a stack of stickers to a few people, so if you weren't fortunate to get any at cf.Objective(), or couldn't attend, you may find some people around who still have some to hand out.

I also did two presentations on Transfer, one of of which was a repeat.  While the first time I presented Introduction to Build Applications with Transfer ORM, didn't quite go according to plan (technical difficulties), people still seemed to get a lot out of it, which I was very happy about.  The Transfer ORM Caching Mechanics and the repeat of the Introduction talk went far more smoothly, and got good reviews from the people that I talked to, which is very pleasing.

ColdFusion 9

The ColdFusion 9 keynote, and BOF was another highlight of the conference for me, although, I must admit, I didn't hear any feature requests that really surprised me.

Adobe is further opening up the ColdFusion development process, promising us a Open Bug Tracker, and setting up an Advisory Committee, which is fantastic.

We got a hinting at a ECMAScript (style?) syntax for ColdFusion components, which I know is something that people, myself included, have wanted to a long time.  From that, there seemed to be a big push to be able to write AS3 on the server side.  Considering that a lot of new CF developers seem to be coming from Flex, I think this would be a really smart move on Adobe's part.  Not only does it streamline the training process for Adobe based Rich Internet Applications, it provides a solid, single language for Adobe products, which can then only be expanded.

That being said, it would be very important that the CFML language also be kept intact, both for backward compatibility, and for the fact that a tag based syntax just makes so much sense on the view layer. (Oh, and let's not forget, some people just like writing CFML ;o) )

People

One of the biggest draw cards for cf.Objective() is the people you get to hang out with.  For me personally, it's the only chance I get per year for me to actually see a lot of the people that I speak to day in, day out on-line.

It also gave me a chance to meet and talk to some of the people I've worked remotely with as well, specifically, the Dinowitzs, who run the great Fusion Authority Quarterly Update, and the really cool Alagad crew. 

Let's also not forget that I won the Wii, which was a big surprise!  It was very amusing watching multiple people try and convince me how it wouldn't work in Australia, and that I should just give it to them, because really 'I didn't need it' ;o).  Let it be known, that a new power cable is on its way in the post, and soon theWii will be up and running smoothly.

Oh yeah.. and I don't care what you lot say, it's cay-shing, not caaashing. ;o)  See you all next year!
28 April 2008 05:30 AM 0 Comments

Transfer 1.0 Release Candidate - Out Now!

Wow.  When I started this project back in 2005 I had no idea it would blossom into what it is now, or that it would take me 3 full years to turn it into an actual 1.0 release.

It's been a crazy, interesting, frustrating and incredibly rewarding ride, and I plan on continuing it well into the future.

So here I present to you the release candidate of Transfer 1.0, ready for your download and consumption !

Some of the major new features include:
  • Composite Key Support
  • Transaction Support
  • Binary Data support
  • Configuration includes
  • Cascading operations e.g. cascadeSave(), cascadeDelete()
  • A huge number of performance improvements
  • Public Bug Tracker
  • Public Wiki

Please see the full release notes for more information.

I want to extend a big thanks to all those people who have helped out with Transfer, with code, testing, documentation, or just giving your ear as I try and work out a n-th level nested recursive threading issue, you all are too many to mention, but you know who you are, and you guys rock!

I'm really happy with the way the Transfer community has grown over the past few years, recently passing 320 members, and big kudos to you all for helping me bring Transfer to this 1.0.

In the coming months, the following is the plan for Transfer -

  1. Transfer Support finalised and advertised. 
    The details of this have been worked out, expect a blog post on this either during, or shortly after cf.Objective() 
  2. Infrastructure
    You will notice there is the new Wiki and Bug Tracker.  There will be a complete rebuild of the Transfer site, to integrate the wiki and the tracker, and provide the community with more ways to learn and interact.
  3. Transfer Training
    This is the next big thing for Transfer, and I will be starting to write the curriculum after I get back from cf.Objective()
  4. Transfer Survey
    Expect to a see a survey in the upcoming months, to get a feeling for how the community is using Transfer, and what sort of enhancements they want for the future.
  5. Transfer 1.1
    Yep, I've already started thinking about a 1.1 release! I think I also know what new features will be in it, but I won't ruin the surprise.
  6. Transfer Developer and Training Certification
    I've had some recent interest in this, and it is still on the roadmap.  Once the training curriculem is finalised, this will be also be developed.

Hopefully that will give you guys something to think about while you play with the 1.0 Release candidate!
28 April 2008 04:41 AM 8 Comments

Transfer Introduction eSeminar Recording

The recording for the recent Transfer eSeminar is now available to be viewed at your discretion.

The same code can also be downloaded from here.

There is a small silent part at the beginning due to the fact my Windows VM crashed, but the rest was relatively smooth sailing.

I hope you enjoy!

This is actually the same presentation I will be giving at cf.Objective() , so you may want to hold off on watching it, and catch it live instead ;o)

Big thanks to the Adobe Pacific eSeminar series for allowing this to happen.  It's worth checking it out to see if there is another eSeminar that is going to interest you!

24 April 2008 04:27 AM 6 Comments

Transfer eSeminar - Tomorrow - 25th of April

Just a quick reminder that I will be doing an eSeminar for Adobe tomorrow, 25th of April, at 2:00pm Melbourne, Australia Time.

Agenda
Introduction to Building Applications with Transfer ORM

When developing an Object Oriented web based application, it is normal to have a database with relational tables and a series of objects that represent that data. Often, the amount of time and effort it takes to manually map these objects back and forth from a database is large, and can be very costly.

Object Relational Mappers (ORM) were developed to cut down the amount of time this process takes, and automate the translation between a relational database and an Object Oriented system.

Transfer ORM's main focus is to automate the repetitive tasks of creating the SQL and custom CFCs that are often required when
developing a ColdFusion application. Through a central configuration file Transfer knows how to generate objects, and how to manage them and their relationships back to the database.

This presentation will outline the basics of what an Object Relational Mapper is, the use case for using one within web application
development, as well as taking a code centric, step by step view of how to install, configure and use the basic functionality of Transfer ORM.

Times
For those Aussie folks - yes, this is Anzac day! (Yeah.... I dunno why I was given a public holiday, go figure) ;o)

For those not in the AU region, the time conversion is:
USA - EST: 12am, 25-26 of April
USA - PST: 9pm, 25th of April
UK - London: 5am, 25th of April.

If you feel like staying up / getting up early, you are more than welcome to join us.

This is the new Introductory presentation I will be giving at cf.Objective() this year, so you can come by and get a preview of what I will be speaking about.

Registration
http://events.adobe.co.uk/cgi-bin/register.cgi?country=pa&eventid=6503&venueid=6858

23 April 2008 05:45 PM 0 Comments

Transfer Documentation Moves to a Wiki

As you may have picked up the occasional teaser, the Transfer documentation has been officially moved to a new Wiki, which can be found at http://docs.transfer-orm.com.

The old URLs now redirect to this link, and the project page links are also pointing here.

This is one of the new faces of the soon to be released Transfer 1.0, a large part of which is project infrastructure. 

In the next few months, you will see more and more being built, to help build the Transfer community, and provide it with the support it needs to help make Transfer into an even better project than it is now.

As per what is CodexWiki? Well, I guess you'll have to come to cf.Objective() to find out...
07 April 2008 09:36 AM 0 Comments

Melbourne CFUG - 17th of April

Another CFUG Meeting for us all,

Location:

NGA.net, Level 2, 17 Raglan St, South Melbourne
Map: http://link.toolbot.com/google.com/73016

When:
17th of April, Meeting starts at 7:00, so get there before hand (doors open at 6:30).

Agenda:

Dale Fraser will be taking us through....

Flex for ColdFusion Developers

This talk will cover the basics of how to get setup on FlexBuilder to start writing Flex applications that will leverage your existing ColdFusion code.

Topics covered will several of the standard flex components and how to return various types of data from ColdFusion to flex. You will be amazed how easy it is.

Specifically:
Returning Simple Values
Returning Structures
Returning Arrays
Returning Queries

And how to bind these to common components in Flex such as

DataGrid
ComboBox
TextInput

We will also cover dymystifying the install and configuration of Flex to ColdFusion, and a simple way to setup the necessary mappings between the two. This is for anyone who loves ColdFusion and wants to start with Flex and for anyone who is trying to decide between Ajax & Flex.


Dale will also announce the launch of a new website on this night that specifically is aimed at the ColdFusion to Flex developers.

If you are going to attend, please RSVP to mark [dot] mandel [at] gmail [dot] com.

Only those that RSVP are eligible for the door prizes, so make sure you apply!

See the CFUG Melbourne Calendar at:
http://www.cfcentral.com.au/Events/index.cfm

Or add to your Google Calendar - search for 'CFUG Melbourne'.

As per usual, we'll grab pizza during the evening, so we have something to scoff down!

Look forward to seeing you all there.

27 March 2008 07:58 AM 0 Comments

Blatant Plug For This Site's ColdFusion Hosting - NovaHost

I just had a really nice experience with NovaHost today, so I felt like sharing the love.

Novahost sponsors the ColdFusion hosting for CompoundTheory, and also for Transfer-orm, and for that I'm always very, very grateful.

Today, I needed some aspects of this hosting changed, so I jut popped them a quick Instant Message via MSN, and was quickly handled, without any problem at all.  I just love it when Customer Serivice just works!

If you are interested in shared ColdFusion hosting in Australia, click the ad on the right hand side of this post.  They're reliable, easy to deal with, and are run by people who understand ColdFusion (which for me is the big selling point).

Okay, I'll stop being gushy now, but seriously, check them out ;)

10 March 2008 11:40 AM 0 Comments

Transfer: Talking and Training at WebDU

I have to say, I'm very excited about this years webDU, the speakers looks fantastic, and the topics seem to be really great as well!  I'm particularly excited by the fact that two of the ColdFusion engineers will be there, and presenting!

 

webDU

 

On the Transfer side of things, I will be providing a full day workshop on Day 0 of webDU, so for those of you who are keen to gets started with Transfer, but haven't before had the chance, or are simply looking to brush up on your Transfer skills, now is the perfect chance.

Otherwise, I will also be presenting Database Queries the Easy Way using Transfer Query Language where I will cover the hows and why of TQL, and some of the ways it can help you write even less SQL.

26 February 2008 12:46 PM 4 Comments

Transfer Transaction Support in SVN

Yes, I know, I broke my own feature freeze... I'm a very naughty developer.  I had a need for Transaction support in the code base I've been writing for the new Transfer documentation, so I figured that I had to simply write it.  That and I thought it was a super cool idea, so I couldn't let it slide ;o)

The Problem

There are two issues I was trying to solve with Transfer Transaction support, so let's look at a common Transfer Transaction scenario and see what the problems are.

Say we have a TransferObject named 'Foo', and we have a Service, named 'FooService'.  We may have some code that looks like:

<cffunction name="saveFoo" hint="saves Foo, and its children" access="public" returntype="void" output="false">
    <cfargument name="foo" hint="The foo" type="Foo" required="Yes">
    <cfset var children = arguments.foo.getFooChildrenArray() />
    <cfset var child = 0 />

    <cftransaction>
        <cfset getTransfer().save(arguments.foo, false) />
        <cfloop array="#children#" index="child">
            <cfset getTransfer().save(child, false) />
        </cfloop>
    </cftransaction>
</cffunction>


In which we save Foo, and its many FooChildren, and we wrap it in a <cftransaction>, so that if anything goes wrong, the whole set of data gets rolled back.

Now, there are two issues with this scenario that need to be addressed:

Nested Transactions
You can't nest the saveFoo() call inside another Transaction block.  i.e. code that looks like:

<cffunction name="saveFooParent" hint="saving a Foo Parent" access="public" returntype="void" output="false">
    <cfargument name="fooParent" hint="The foo" type="FooParent" required="Yes">
    <cftransaction>
        <cfif arguments.fooParent.hasFoo()>
            <cfset saveFoo(arguments.fooParent.getFoo(), false) />
        </cfif>
        <cfset getTransfer().save(arguments.fooParent, false) />
    <cftransaction>
</cffunction>


This will throw an error, as ColdFusion won't allow you to nest <cftransaction> blocks.  We could write something similar to what Transfer already does, and pass a boolean to the save method to tell it whether or not to use an inner transaction, but this is cumbersome, and depending on your application architecture, you may not be in a position to know if a given method is in a transaction.

Cache Synchronisation
Cache synchronisation is a real problem when database data rolls back, and the Transfer cache stays the same.

i.e. If we look at the saveFoo() method above, if the data on Foo has been updated, but something goes wrong when saving the children, then the data for Foo gets rolled back along with everything else, but the cache stays the same, which can be a very bad thing, as your object data is totally out of sync with your database (and not when you want it to be).

The Solution

So what is the solution? The solution is to use the new Transfer Transaction Object!

The Transaction object provides both:

  1. Nested Transaction support.
    If a Transaction wraps another Transaction, the inner transaction just becomes merged with the outer, as if it was just one big Transaction.
  2. Transfer cache synchronisation
    If anything goes wrong in your Transaction, then Transfer will automatically discard any object whose data was modified during that Transaction.

So let's look at how we can use the Transaction object.  First of all, how do we get it? Very simply, it's available from the TransferFactory, so can now go:

<cfscript>
    transaction = application.transferFactory.getTransaction();
</cfscript>


And get access to the Transaction object.  On a side note, the reason it is accessible from the TransferFactory, and not Transfer, is because it is not specifically tied to Transfer.  You can use this Transaction object with anything that requires a <cftransaction> wrapped around it.

There are three different ways you can use the Transaction object, and will look at them all, in regards to the example we gave above.

Direct Execution
The first one is the simplest:

transaction.execute(component, methodName, [arguments])

This simply executes a given method (even private ones!) on a given component, with an optional struct of arguments.

In the instance of above, we would have to change our code to look something like:

<cffunction name="saveFoo" hint="saves Foo, and its children" access="public" returntype="void" output="false">
    <cfargument name="foo" hint="The foo" type="Foo" required="Yes">
    <cfset getTransaction().execute(this, "_saveFoo", arguments)>
</cffunction>

<cffunction name="_saveFoo" hint="saves Foo, and its children" access="public" returntype="void" output="false">
    <cfargument name="foo" hint="The foo" type="Foo" required="Yes">
    <cfset var children = arguments.foo.getFooChildrenArray() />
    <cfset var child = 0 />

    <cfset getTransfer().save(arguments.foo) />
    <cfloop array="#children#" index="child">
        <cfset getTransfer().save(child) />
    </cfloop>

</cffunction>


So the above code would execute the method _saveFoo, wrapped out in our nesting-safe Transaction.  Pretty cool, but a bit cludgy as we have to implement a second method.

Aspect Oriented Programming

I think we can do better, and in fact we can, using the second method.

transaction.advise(component, function)

For those of you who are familiar with Aspect Oriented Programming (AOP), this method takes the component, and the function itself, and wraps a nesting-safe Transaction advise around the function that has been passed in.

If that was a little high level, to give an example, I could change the FooService to be:

<cffunction name="init" hint="saves Foo, and its children" access="public" returntype="void" output="false">
   <cfargument name="transaction" hint="The transaction object"type="transfer.com.sql.transaction.Transaction" required="Yes">

    <cfset arguments.transaction.advise(this, saveFoo) />
</cffunction>


<cffunction name="saveFoo" hint="saves Foo, and its children" access="public" returntype="void" output="false">
    <cfargument name="foo" hint="The foo" type="Foo" required="Yes">
    <cfset var children = arguments.foo.getFooChildrenArray() />
    <cfset var child = 0 />

    <cfset getTransfer().save(arguments.foo) />
    <cfloop array="#children#" index="child">
        <cfset getTransfer().save(child) />
    </cfloop>
</cffunction>


So what happens at init() time, the original saveFoo() is wrapped up in a nesting-safe transaction, and you don't have to write much extra code, except to remove the old <cftransaction> tags, and tell the Transaction object what methods to advise.  Much better than the first way, and it works on both private and public methods.

So the above, is very nice, however, what happens if we have a lot of functions we want to advise()?  Well, the third way of using the Transaction Object is handy for that!

transaction.advise(component, regex, [debug])

With this approach, we can apply the Transaction advise to all methods, both public and private whose name matches the given regular expression.

For example, if we want to apply Transaction advice to every method that starts with 'save' in our FooService, we would just need to have our FooService written like:

<cffunction name="init" hint="saves Foo, and its children" access="public" returntype="void" output="false">
   <cfargument name="transaction" hint="The transaction object"type="transfer.com.sql.transaction.Transaction" required="Yes">

    <cfset arguments.transaction.advise(this, "^save") />
</cffunction>


<cffunction name="saveFoo" hint="saves Foo, and its children" access="public" returntype="void" output="false">
    <cfargument name="foo" hint="The foo" type="Foo" required="Yes">
    <cfset var children = arguments.foo.getFooChildrenArray() />
    <cfset var child = 0 />

    <cfset getTransfer().save(arguments.foo) />
    <cfloop array="#children#" index="child">
        <cfset getTransfer().save(child) />
    </cfloop>
</cffunction>


And we are done.  If we ever add a method that has 'save' at the beginning of its name, such as the saveFooParent() from before,  then it will automatically be wrapped up in a Transaction, even if the method is private.

If the 'debug' argument is set to true, the Transaction object will <cftrace> all the methods that are advised, so you can see if your method is being wrapped up in a Transaction or not.

I don't often say this (in fact, I avoid it whenever possible), but this is the official best practice for doing Transactions with Transfer ORM.  The usage of the optional 'useTransaction' argument is now officially deprecated.

Now I'll get back to this documentation stuff.... this is the last feature! I swear!

Big thanks to Jared Rypka-Hauer for letting me bounce this idea off him as well!

20 February 2008 06:09 AM 0 Comments

Recently on #coldfusion...

This was too clever to pass up (By the way, 'Neuro', or 'Neurotic' is me):

<DanWilson> Neuro doesn't have kids, he generates them
<jamiejackson> hope they don't inherit behavior
<DanWilson> behaviour is mixed in at runtime

Check out more silliness at #coldfusion on Dalnet irc! 

14 February 2008 06:52 AM 0 Comments

Melbourne CFUG - 21st February

The first CFUG of the new year!

Location:

NGA.net, Level 2, 17 Raglan St, South Melbourne
Map: http://link.toolbot.com/google.com/73016

When:
21st February Meeting starts at 7:00, so get there before hand (doors open at 6:30).

Agenda:

Tonight we will be viewing and discussing Sean Corfield's Presentation on Design Patterns:

Come find out what design patterns are really about and how they can make your life easier. (You're probably already using some design
patterns, although you may not know it.) For this session, we have distilled decades of software engineering experience into a well-documented set of blueprints that can be applied to common problems to ensure clean, maintainable code.

Sean Corfield:
Sean is currently a freelance consultant. He has worked in IT for nearly twenty five years, starting out writing database systems and compilers then moving into mobile telecoms and then finally into web development about nine years ago. Along the way, he worked on the ISO and ANSI C++ Standards committees for eight years. Sean is a staunch advocate of software standards and best practice. He wrote C++ coding guidelines for several companies during the 90's and more recently maintaining the Macromedia ColdFusion MX Coding Guidelines and Mach II Development Guide, which are also published for the ColdFusion community. He has also given several seminar talks, both in- house and publicly, on these subjects. Sean has championed and contributed to a number of ColdFusion frameworks.

If you are going to attend, please RSVP to mark [dot] mandel [at] gmail [dot] com.

Only those that RSVP are eligible for the door prizes, so make sure you apply!

See the CFUG Melbourne Calendar at:
http://www.cfcentral.com.au/Events/index.cfm

Or add to your Google Calendar - search for 'CFUG Melbourne'.

As per usual, we'll grab pizza during the evening, so we have something to scoff down!

Look forward to seeing you all there.
21 January 2008 05:22 PM 4 Comments

Transfer Going POSS, Powered by Compound Theory

From the end of February 2008, Transfer will be become Professional Open Source Software.  This means that Compound Theory will start selling services that are based around Transfer, while still retaining its free, Open Source licence.

The idea behind all this is such that I can do more for Transfer than I am currently doing, both in terms of being able to write code, as well giving me more freedom to present, and travel to conferences to physically talk to people.

Not only will Compound Theory be providing a series of services based on Transfer ORM, it will also be offering project based consulting, training, and mentoring.

To that effect, if you are interested in Compound Theory's services, please feel free to contact me directly.

On the Transfer front, understandably, things are moving forward pretty fast. 

Right now, I'm taking Expressions of Interest in the following areas:

  • Transfer Support
    A subscription and/or per incident model for support as pertaining to Transfer installation, use and/or any overall issues.

  • Transfer Training
    A Transfer curriculum that will come in a series of short courses, as well as single/multiple day training programs, covering both on-line training, and in-person training.

  • Transfer Developer Certification
    Much like ColdFusion Developer Certification,a Developer certification give you a listing on the new Transfer site as certified, as well as a spiffy certificate.

  • Transfer Training Certification
    Again, much like ColdFusion Training Certification, this would give you a listing on the Certified Trainers page on the Transfer ORM site, as well as access to the training materials.

If you are interested in any of the above programs and/or services, please send me an email either on my contact form, or via the Transfer Google Group.  Once we have launched these programs, I will be in contact to let you know of the specific details.

If anyone wants any more information on Professional Open Source Software, 'The Beekeeper' article by Pentaho Commercial Open Source Software is one the best descriptions of POSS I have ever read.

So with all that, what are the specific plans for Transfer in the near future?  Lots of things!

First of all, the SVN version of Transfer is currently in feature freeze.  I'm only fixing bug fixes at this stage, to prepare for a Release Candidate of 0.7.

This release candidate will coincide with the new Wiki that will power and house the extended documentation, both for the new features of Transfer, and expansion on current feature sets.  This Wiki is currently under development, and you should be seeing something on it soon.

The Wiki will be a new part of the new Transfer site that I have been promising for a long time.  The design for this has been done, and it looks fantastic.  This will consolidate things like bug tracking, project and knowledge management into a single space, which will be very useful in the long run.

Once that is all up and running, we're going to be moving as quick as we can towards a Transfer 1.0!

I have revised the road map, and pushed out several pieces to be implemented post 1.0:

Included in the 1.0 Roadmap

  • Binary Data Support
    Currently Transfer doesn't support being able to insert or retrieve binary data from the database.

  • Programmatic setting of the data source details through the Configuration Bean
    This will give a developer the ability to programmatically set the details of the data source, which is particularly useful when the datasource name is dynamically generated.

  • Generated methods all have hints on them, for TransferDoc and/or if displaying the object meta data in any way
    Currently some, but not all methods that are generated have a populated hint="" on their <cffunction> definitions. This will be expanded to include all <cffunctions>, to enhance generated documentation

  • Ensure hashing is unique for all changes to the transfer.xml, by ensuring that changes to any parents, flow through to generating new definitions for children.
    There are currently a few rare occurrences where Transfer .transfer files won't be regenerated when a change is made to the XML file.  These rarities will be fixed.

  • Finalise CLOB support across all DBs.
    CLOB support has a few issues across some DBs, specifically Oracle.  This will be resolved so that it is no longer an issue.

  • Cascading insert, updates, delete and saves
    This is what it says it is.

  • Programmatic reloading of the XML file.
    The ability to be able to programatically reload the XML configuration file from within Transfer, to aid in development.

Pushed out to post 1.0 release

  • Soft Deletes
    I have some more flexible ideas on how to go about this, that will provide soft delete functionality, as well as some other far more extensible possibilities.

  • TQL on conditions
    This will allow you to use TQL on <condition> declarations, however, I'm not sure if <conditions> are  necessary any more, as it may be superseded by some other ideas I have

  • Transaction based caching that discards objects inside a transaction if the transaction fails. 
    The way I wanted to implement this was not actually possible with ColdFusion, but I have some other ideas on how to facilitate at least something similar

From here there is also a strong plan to be releasing on a regular and frequent schedule.  I am fully aware of the fact that it's almost been a year since the last release, but for those of you who haven't followed the SVN version of Transfer, will be pleasantly surprised at how much we've managed to fit into this new release.

The goal is to have the 1.0 of Transfer at least at Release Candidate stage by cf.Objective() this year.  Even though it's going to be a lot of hard work, I think that is is truly possible.

All in all, this is a pretty exciting time for Transfer, so I want to thank all those who have participated up until now, we've developed a great community, and 2008 is looking to be a very fun, and exciting year for all involved.
17 January 2008 12:34 PM 11 Comments

I'm an Adobe Community Expert

I was very excited to find out yesterday that I am now an Adobe Community Expert!

Adobe Community Expert

I'm really happy to be selected for the program, and hopefully I'll get my little 'Adobe Community Expert' sticker up on this site soon, when I have two minutes to breathe... ;o)

17 January 2008 04:40 AM 0 Comments

Flex and AIR User Group Pre-release Tour - Melbourne, 29th January

In case people missed this the CFAUSSIE List: 

Flex 3 and AIR are getting close to launch and in preparation, the dobe Platform Evangelist team is travelling around the world, and to elbourne, to show off the great new features and some brand new
demos.

Flex 3 is a feature-packed release, adding new UI components like the advanced datagrid and improved CSS capabilities; powerful tooling additions like refactoring; and extensive testing tools including
memory and performance profiling, plus the addition of the automated testing framework to Flex Builder.

Adobe AIR is game-changing in so many ways, extending rich applications to the desktop, enabling access to the local file system, system tray, notifications and much more. Now you can write desktop applications using the same skills that you've been already using to create great web apps including both Flex and AJAX.

Don't miss out on the opportunity to see and hear about this highly anticipated release of Flex 3 and AIR during this special pre-release tour.  Plus, in addition to giving away some one of a kind Flex/AIR branded goodies, we will also be raffling off a copy of Flex Builder 3 Professional (pending availability) and a full commercial copy of CS3 Web Premium at this event!

Melbourne event details...

Danny Dura is an Adobe Platform Evangelist at Adobe U.S.A, who will be in Melbourne for a special Flex/AIR evening meeting on Tuesday the 29th of January, 2008.

This will be a joint effort/presentation of the Flash UG and the ColdFusion User Group (CFUG), but the venue is still the same.

Many have expressed interest already, and this event will go ahead, but we would still like to get an idea about how many are coming for catering reasons, please express your interest via, if you have not done so already:

Edit ::: 18-Jan-2008 ::: This event is at (or even over) capacity.  You can still apply for interest, but if you do not get an invite, you cannot attend.  We just have too many people wanting to come! :) (which is not a bad thing)

http://www.techevents.com.au/flex/

This event will be catered for and we will be giving away a copy of Adobe Flex 3 (pending availability), as well as Creative Suite 3 Web Premium, all courtesy of Adobe. Please note you must have expressed interest once via the link above to been in for a chance to win the Adobe software.


Meeting time...

7PM, Pizza and refreshments at 6:30PM, doors open 6PM.

Tuesday the 29th of January, 2008.


Meeting location...

Edit ::: 24th of January ::: Due to unforeseen circumstances, there has been a last minute venue change.  Please check your invite emails for the new address.

About Danny Dura...

Danny Dura is an Adobe Platform Evangelist - His main focus is AIR, Flash Player, ActionScript and Flex.

http://www.danieldura.com/

10 January 2008 11:07 AM 1 Comment

Special Flex Event in Melbourne

In case people missed it via the CFUG list, please put down interest ASAP, so we get everything confirmed. 

We are happy to have some potentially very exciting news for our Cold
Fusion User Group for very early in the new year.

Danny Dura is an Adobe Platform Evangelist at Adobe U.S.A will be in
Melbourne in late January so we are making preliminary enquiries to
see if our members would be interested in attending a special
Flex/AIR night meeting.

The planned date would be the evening of Tuesday the 29th of January,
2008. If you don't know much about Flex or AIR, this will be right up
your alley. If you already know about Flex or AIR, this is a great
opportunity to be brought up to speed with Flex 3 and AIR pending
their release this year.

We realise that many of you will be away, given it's still the
holiday season. However, if you'd be interested in coming, please let
us know by simply clicking on the link below.

http://www.techevents.com.au/flex/

If the event goes ahead, it will be catered for and we will be giving
away a copy of Adobe Flex 3 (delivered after release), as well as
Creative Suite 3 Web Premium, all courtesy of Adobe.

About Danny Dura...

Danny Dura is an Adobe Platform Evangelist - His main focus is AIR,
Flash Player, ActionScript and Flex.

http://www.danieldura.com/

06 January 2008 08:21 AM 2 Comments

Paul Marcotte on the Transfer Event Model

Paul Marcotte at Fancy Bread has written a tutorial on the Transfer event model, based on the User password encryption example I gave during my Advanced Transfer ORM Techniques talk.

He does a really good job of breaking down the code example, and provides some extra information above and beyond what I had originally provided in my presentation, including some tips on integrating with ColdSpring.
21 December 2007 07:51 AM 1 Comment

Speaking at cf.Objective()

Yesterday I got notified that I will be speaking at cf.Objective() next year!  I am very excited about coming over again and speaking.  Last year was an amazing experience, and it will be great to catch up with all the people who I only ever get to see face to face once a year.

I'm going to be doing two presentations on Transfer:

'Introduction to Building Applications with Transfer ORM' - A reworking of my original 'intro' talk, that is going to take a very code centric walkthrough of setting up and using Transfer ORM.

Transfer ORM Caching Mechanics' - Where we will look at some overall caching concepts, and have a strong technical discussion on how the caching in Transfer works, as well as all the configuration options, and cache manipulation methods that are available.

I have to say, the speaker line up this year looks absolutely amazing. I'm actually seriously hoping that my speaking schedule doesn't get in the way of me getting to all the sessions I want to get to!

Big Kudos to Jared, Sean, and everyone else who's been working on the cf.Objective() conference, you guys are doing an incredible job.

10 December 2007 08:57 AM 0 Comments

Melbourne CFUG - 20th December

A quick reminder for the last Melbourne CFUG Meeting of the YEAR!

Location:

NGA.net, Level 2, 17 Raglan St, South Melbourne
Map: http://link.toolbot.com/google.com/73016

When:

20TH of December, Meeting starts at 7:00, so get there before hand (doors
open at 6:30).

Agenda:

Dale Fraser will be presenting on CFAJAX!

ColdFusion 8 includes a lot of Ajax features, and if you think Ajax is
complicated, think again. Ajax will make some of the things you do now
easier, and if you can write ColdFusion code, you can easily use Ajax
with ColdFusion Ajax features. So if you have always wanted to do some
Ajax stuff or you want to learn what Ajax is, then this is for you.

Topics covered include:

  • <CFAJAXPROXY to bind to controls and CFC's
  • <CFGRID a DHTML grid with binding and paging
  • <CFINPUT an autosuggest feature using Ajax binding
  • The ColdFusion. javascript methods that come with ColdFusion 8
  • And more

If you are going to attend, please RSVP to mark [dot] mandel [at] gmail [dot] com

Only those that RSVP are eligible for the door prizes, so make sure you apply!

See the CFUG Melbourne Calendar at:
http://www.cfcentral.com.au/Events/index.cfm

Or add to your Google Calendar - search for 'CFUG Melbourne'.

As per usual, we'll grab pizza during the evening, so we have
something to scoff down!

Look forward to seeing you all there.

06 December 2007 04:14 PM 13 Comments

Huge Performance Gain in Moving ColdFusion 8 to Java 1.5

We have a reasonably large application that we have been building for the past 2 years or so, with MachII, ColdSpring and Transfer, and we moved over to ColdFusion 8, pretty much as soon as the Beta came out, and have been developing with it ever since.

To give you an idea of the size of the project, some metrics for you, we have 1064 CFCs, 329 .cfm pages, 161 configured Transfer Objects, 40 MachII frameworks instances (we started this before modules), and 201 Tables.  This actually results in about 22,000 .class files being generated by ColdFusion behind the scenes.

What we began to experience is extremely long start up times when the server was first started up. For example with no class files saved on the server, we have a start time of around 20 minutes before the application was responsive, and if multiple people hit the site at once, we were looking at around 45 minutes before the application would perform usably.

With class files saved, this dropped down to 9 minutes, but we still ran into huge difficulties with multiple users hitting the site at once.  On top of that, whenever we had to upload a change, clearing the template cache so the change would propagate brought the server to it's knees, so we were forced to restart CF with every deployment of code.

So after much haranguing, and talking to a whole slew of people, both Adobe, and non Adobe (you all know who you are, and thank you very much for the time and effort you all put into helping out on this), it eventually got narrowed down to a bottleneck in Java 6 as described here (as also reported by Sean Corfield )

So for those of you not so familiar with Java, what does all that actually mean?  Well, let's look at what ColdFusion does behind the scenes when you run a .cfm or .cfc page:

  1. Checks to see if it has the Java Classes already in memory to do what you have requested - if not,
    1. CF Reads in the file you are executing
    2. Parses the CFML
    3. Converts the parsed CFML data structure, and converts it into Java code
    4. Compiled that Java code down to actual Java .class files
    5. Loads the resulting .class file into memory
  2. Executes the Java code contained in the .class file as necessary.

So probably nothing too revolutionary in there in terms of our understanding of the ColdFusion process, however, there is a big bottle neck in Java 6 where the loading into memory Java classes is really really really slow (maybe I need another really there), so step 1.5 on the above processes takes a very long time to get through - and the problem only gets worse when there are large numbers of very small classes - which in almost any ColdFusion application, and ours in particular, there are.

There are several places in which this issue can cause serious problems -

  1. At System Start Up
    As discussed previously.

  2. Development.
    Obviously during development, files tend to change quite regularly.  During development of our application, it would not be strange for me to be spending several minutes, to the tens of minutes waiting for a small change in either a .cfm or .cfc to come through. This simply slows down the amount of work that you are able to do in any given time frame.

  3. At Run Time
    Since ColdFusion has a finite limit on the number of cached templates (which are just the .class files mentioned earlier stored in memory), it is quite likely that at some point during an application life cycle, part of what is stored in the template cache will get purged so as to make room for other Java classes that have become active.  We hit the same issue as we hit on step 1.5 as above, as the ColdFusion server slows down as it pulls in the required Java classes into memory.  This can result in random slowdowns in the application, which are hard to reproduce.

    This becomes a larger issue on shared host systems, in which a trusted template cache is impossible, and it is quite likely the ColdFusion server is constantly moving the generated Java code in and out of it's template cache, as multiple systems require different ColdFusion code to be executed.

It wasn't until we had one of those head-slap moments when a co-worker turned around to me and said 'well.. why don't we try Java 1.5?'?

Once installed, suddenly everything started working like we wanted it to, performance wise.

Since everyone loves a pretty graph, here are some metrics on server start up, taking a Selenium script through a series of steps through one part of our application, so you can see the considerable difference between the two Java Versions

Average TIme Taken

Total Time Taken

Not only has this made our production systems run incredibly fast, it also means that we are able to upload code to the production server, clear the template cache, clear the application cache, and we are good to go, there is no need to restart ColdFusion for changes.

This also means I can develop without having to take a coffee break in between code changes, which has upped my productivity as well, in fact, I can now develop happily in Machii with the config mode set to constantly reload, and performance is no problem at all.

As far as I am aware, this issue does not exist in the development snapshots of Java 7, and apparently a fix is in the pipeline for 1.6, but Sun hasn't been forthcoming about the date.

Until that time, I would suggest moving your ColdFusion 8 servers over to Java 1.5, and enjoy the speed improvements!!!

Jared Rypka-Hauer on Named Transactions Feature Request

Jared just did a blog post over at Alagad on a feature request for named transactions.  I have to chime in here and say that I really, really, really, want this feature!

The current restriction of having transactions only within a <cftransaction></cftransaction> block is incredibly limiting from a OO perspective.

Something that I had on the radar for Transfer was to be able to control the Transactions at a database level with your code, as well as automatically clearing from cache the relevant objects if something went wrong.

Essentially it would go something like this:

transaction = getTransfer().getTransaction();

try
{
    transaction.begin();
  
    employee = getTransfer().get("employee", 1);
    employee.setUsername(form.username);
    getTransfer().save(employee);

    manager = getTransfer().get("employee", 4);
    manager.addEmployee(employee);
    getTransfer().save(manager);

    transaction.commit();
}
catch(Any exc)
{
    transaction.rollback();
}

With this code, if we got to the 'transaction.rollback()', not only would it roll the DB data back, but it would also intelligently discard the 'employee' and the 'manager' objects from cache - thus ensuring that there was no dirty data.

Currently, with ColdFusion transactions structured the way they are, it's actually impossible for me to do this, as there is no <cftransaction> block, and I have no hook to pick up when something goes wrong.

With a named Transaction block, I could internally handle how transactions where managed inside my Transaction.cfc, and and I could pick up the rollback() or commit() call as appropriate.

This would be an incredibly handy thing, so count me on a big +1 for this feature!
26 November 2007 02:58 PM 0 Comments

Melbourne CFCAMP Wrapup

Melbourne CFCAMP was last week, and I have to say, I think it went really, really well.

We had an attendance of about 50 people, so it made it a good intimate environment, and everyone asked lots of questions from the presenters, which was great to see.

It was also a great chance to catch up for drinks with the likes of Geoff Bowers, Robin Hilliard, and Peter Bell, who may be local to Australia, but rarely are in the same place at the same time.  (Albeit Peter is new to Australia).

We all went out for a few drinks after the CFCAMP events had finished, and the conversation continued over wine and beer, and we had a pretty good discussion about all sorts of things... including Robin's calculations about the Red Bull challenge (which I don't think were ever fully explained)

I'd like to say a big thanks to Mark Blair, and all the Adobe staff that came down to support the event, it was really appreciated, a good time was had by all, and we even learnt a thing or two.

If anyone is still sitting on the fence on whether or not to go to Perth, I would highly recommend it.
19 November 2007 09:24 AM 2 Comments

Melbourne CFCAMP this Week!

Just reminding everyone that the Melbourne CFCAMP is on this Thursday!!!

The agenda has been locked down, and can be seen at http://cfcamp.pbwiki.com/Agenda:+Melbourne and I have to say, it looks really exciting!

We're going to be seeing coverage of topics ranging from ColdFusion 8 (Obviously), Flex integration, AIR Integration, Farcry, Transfer ORM, LiveCycle Data Services and Code Generation, not to mention its going to be a great opportunity to catch up with all the local developers, and see what is going on in the local development community.

If you have yet to register, I would highly recommend that you do! It's going to be a really good day!  And considering its all free, what have you got to lose?
05 November 2007 12:25 PM 1 Comment

Developing Applications With Transfer ORM Recorded Presentation

I recently did a Connect presentation to the IECFUG group, and it went really well!

I recently moved to a new ISP at a higher speed, so this presentation is missing out on all the audio clipping and dropouts of its predecessors, which I am really happy about.

If you haven't managed to catch this presentation, and want to have a listen, the recording can be found here.
05 November 2007 09:43 AM 0 Comments

Advanced Transfer ORM Techniques at CFFrameworks.com

On the 28th of November, 12pm UK time, I will be presenting via Connect my 'Advanced' Transfer ORM talk, covering some of the functionality of Transfer that is above and beyond the usual CRUD stuff.

This includes things like the caching layer, the observable events, Decorators, and Transfer Query Language, which aren't covered in the introductory talk that I often do.

More details on the talk can be found at the cfframeworks site.

I hope you all enjoy it,as I have yet to do this one online yet! So this will be the first!  Should be good!!!
29 October 2007 05:01 PM 0 Comments

Petitioning for Speakers for Melbourne CFCAMP

Melbourne CFCAMP is looming on the 22nd of November and we're in the need for speakers!

Topics can include anything from case studies, to frameworks, to development techniques, to pretty much anything that is related to ColdFusion!

Speaking time is 30 minutes long (although if you need more time, it can be arranged).

So if you have something you can present, or even an idea of something you can present, please write it up on the WIKI page, and share it with the rest of us.

Remember, CFCAMP is for the CF community, so the more your help out, the more your help your community.

If you aren't going to speak, don't forget to register for the event, it should be a great day, and the venerable Ben Forta will be down to join us well!
08 October 2007 01:49 PM 2 Comments

Melbourne CFUG - 18th of October - ColdBox

All,

A reminder for the upcoming Melbourne CFUG!  Still in our new boardroom! No more
tiny cramped room for us!

Location:

NGA.net, Level 2, 17 Raglan St, South Melbourne
Map: http://link.toolbot.com/google.com/73016

When:

18th of October, Meeting starts at 7:00, so get there before hand (doors
open at 6:30).

Agenda:

Luis Majano himself is going to talk to us over Connect about the
ColdBox Framework.

Luis Majano is a Computer Engineer currently employed at ESRI
(Environmental Systems Research Institute) in sunny Redlands,
California. Please Support GIS!!.  He graduated from Florida
International University and holds an Advanced Coldfusion MX 6,7
Developer Certifications. He has over 7 years experience in software
development, networking and system design.  He is also a freelance
engineer and president of Ortus Solutions, Corp.

Coldbox

ColdBox is a proven event-driven CFC based ColdFusion Framework,
specifically designed for high availability web applications. The
purpose behind ColdBox was to create a fast & stable development
methodology that could be shared among several developers. It makes
use of an MVC (Model View Controller) design pattern implemented via
CFC's. It uses event handler CFC's that hold all the code necessary to
prepare views, call model CFC's or a business layer (Soap/ws/xml/J2EE)
and render views (HTML).

If you are going to attend, please RSVP to: mark [dot] mandel [at] gmail [dot] com

Only those that RSVP are eligible for the door prizes, so make sure you apply!

See the CFUG Melbourne Calendar at:
http://www.cfcentral.com.au/Events/index.cfm

Or add to your Google Calendar - search for 'CFUG Melbourne'.

As per usual, we'll grab pizza during the evening, so we have
something to scoff down!

Look forward to seeing you all there.
08 October 2007 09:22 AM 17 Comments

Should I run ColdFusion 8 on Ubuntu Server on my new VPS?

I've been given the opportunity to have my VPS where I am currently hosting, with the free choice of OS, and pretty much any set up I want.

My initial thought was to set it up on Ubuntu server, simply because, since switching to Ubuntu as my primary OS, I am far more familiar with it as a Linux platform than I ever could be on a RedHat based one.

Now, I know that Ubuntu is not a supported platform, however -

1) I've been running CF8 on Ubuntu for development, and had 0 issues, from installation to use.
2) It's my VPS, so I'm happy to have a bit of an experiment.
3) I really don't feel like learning CentOS (Yeah.. I know.. lazy).

What do you guys reckon?  Anyone been running CF8 on a Debian based distro, and faced any issues? Can anyone think of any issues that could trip me up?
02 October 2007 01:01 PM 7 Comments

Javaloader v0.5 Released

Here is the release of JavaLoader, version 0.5.

It pretty much does exactly the same thing that the previous versions did, however, it now works in ColdFusion 8, when the setting 'Disable access to internal ColdFusion Java components' is turned on, as it uses its own JavaProxy CFC, which may often be turned on on shared hosts.

That's really about it, nothing more interesting than that.

Download JavaLoader v0.5 from here.
24 September 2007 12:57 PM 9 Comments

How to tell if code is being run inside a CFTHREAD tag

One restriction I ran into today when doing some ColdFusion8 specific performance enhancements to Transfer with <cfthread> is that you can't make a child thread within an already created <cfthread>, so something like:

<cfthread action="run" name="a">
    <cfthread action="run" name="b">
    </cfthread>
</cfthread>

Will end up with lots of errors in your logs saying things like:
Error","cfthread-1","09/24/07","12:03:42",,"A: Thread B cannot be created. Child threads are not supported."

Which is probably not what you actually want, as you would most likely like for you code to actually execute.

I'm not a huge fan of this limitation, but I can kind of understand where the engineers are coming from - they don't want us CF developers to shoot ourselves in the foot with ridiculously spawning multi threaded applications.

So, in my current situation, I wasn't too fussed if I had a whole, brand new thread, but where my code was being run, I was so far down the stack of method calls, I have no way of knowing if the original call had come from a standard ColdFusion thread, or if it had come from a <cfthread> create thread, and both of which were highly possible.  However, if the execution wasn't coming from a <cfthread> created thread, I wanted to execute my code inside a <cfthread> statement, as I didn't care what the results where, and it would be faster for the end user just to have the code run asynchronously.

If that just made your head hurt, I basically have a series of method calls that look like:

A()
 - makes a <cfthread> call, and calls C()

B()
- Does some work...
- Calls C() from the current thread.

C()
- makes a <cfthread> call, and then does some work

This is an over simplification of the process (mine is far more levels deep), but gives you an idea of the trouble I was facing - the method call could go through A() or through B(), and at the level of C() I wasn't aware of whether or not I had started on the base ColdFusion thread or not.

I could have done this passing a parameter all the way down the method chain to tell it if it should fire asynchronously, but that seemed like a lot of extra work, and would have put a level of complexity within the whole process, and any other process that was related to this, that it didn't seem like the appropriate course of action.

So I thought to myself - there has to be a way to find out if the current thread is a regular, ColdFusion thread, or if it is a <cfthread> invoked thread, and funnily enough, skipping into some Java, there is!

The first thing we have to do, is get access to the java.lang.Thread object:

Thread = createObject("java", "java.lang.Thread");

Now, the Thread object, has a great method 'currentThread()', which returns the current thread that the executing code is on:

currentThread = Thread.currentThread();

What is good to know, is that Threads in Java can exist in ThreadGroups, which is a handy way of grouping Threads together for common operations, and other clever things.  The nice thing here, is that ThreadGroups have a method called 'getName()' which returns the name of the ThreadGroup.

Strangely enough, <cfthread> created threads live inside the ThreadGroup named 'cfthread'! So now we can compare this against the name of the current Thread's ThreadGroup

if(currentThread.getThreadGroup().getName() eq "cfthread")
{
  //do something...
}

We can also wrap this up nicely into a quick little UDF:

<cffunction name="amInCFThread" hint="returns 'true' if the current thread is a cfthread, returns false otherwise" access="public"returntype="boolean" output="false">
    <cfscript>
        var Thread = createObject("java","java.lang.Thread");

        if(Thread.currentThread().getThreadGroup().getName() eq "cfthread")
        {
            return true;
        }

        return false;
    </cfscript>
</cffunction>

This function returns 'true' if the currently executing code is inside a <cfthread>, and 'false' if it is not.

So now, in my function C() I can have:

C()
if(amInCFThread())
{
   // run code
}
else
{
  // make <cfthread> and run code.
}

And continue on my merry way!

Pretty handy if I'm not sure if my <cfthread>'d code will end up being run by other ColdFusion created threads or not.

Writing my own JavaProxy for ColdFusion 8 using onMissingMethod

First of all, you may be wondering 'what on earth is a JavaProxy?', well, to answer that question, it is the Java class that does all the work behind the scenes in ColdFusion to allow you to be able to write all that Java code in-line in your ColdFusion CFCs and CFM pages by taking the Coldfusion invocations you have implemented, and passed them to the native Java objects that you want to use.

To further your understanding, if you are at all interested, you can also read up on the proxy design pattern here.

Now, what some people may or may not realise, is that inside JavaLoader, I create an instance of the coldfusion.runtime.java.JavaProxy class, so it becomes really easy for developers to create and use instances of Java objects that are loaded from external .jar files within their applications.  I have a good blog post on doing this here.

Now just the other day, I became aware of a new setting in ColdFusion 8 entitled 'Disable Access to internal ColdFusion Java components', that really threw me for a bend.

For people who run shared hosts, they probably think of this as a g-d send, in that it will disable access to coldfusion.runtime.ServiceFactory - and for that, I totally understand, however, it completely locks down access to any Java object that sits under the coldfusion.* package space.

What does this mean? It means that JavaLoader, no longer works, along with any other project that also uses JavaLoader could quite potentially not work on some shared hosts providers that have upgraded to ColdFusion 8!

Why did Adobe decided to do this? Not so sure! However, with the power that we have in ColdFusion 8, we are able to implement our own JavaProxy, that should be able to be seamlessly interchanged with the ColdFusion native JavaProxy!

(Disclaimer: This is the first run at this code, and it works in the given tests I have tried on it.  I will be running it against all the unit tests on Transfer, and when they all work perfectly, and Transfer can run with this CF8 restriction in place, I will release the full code as part of a new version of JavaLoader)

There are two things that allow us to do this -
  1. Nothing stopping us from using Java Reflection to dynamically call methods on a Java Class or Instance.
  2. In CF8 we got 'onMissingMethod()' - so we have a hook into every method that is fired on a CFC, regardless of whether or not it has been implemented.
For those of you who aren't that familiar with the term reflection - it essentially means that we are able to introspect a Java Class or Object, determine what methods and/or properties it has, and dynamically call them at run-time.  If you want to read more, the Java site has a whole tutorial on reflection.

So, first of all, let's look at the few different ways you can instantiate and use ColdFusion Java Objects, we'll use an ArrayList as an example, so that we know what we need to support in our own JavaProxy. 
I will use 'createObject' here, but it could also just as easily be JavaLoader.create(className) to create an instance of the JavaProxy.
  1. array = createObject("java", "java.util.ArrayList").init();
    array.add(obj);

    - This would be the most common, and generally the 'best' way of instantiating a Java Object in CF, as it calls the constructor straight away, with the appropriate arguments, and is the closest you will get, in style, to implementing a real constructor.
  2. array = createObject("java", "java.util.ArrayList");
    array.init();
    array.add(obj);

    - I've seen this sort of code before... to me, it seems a bit weird to split out the constructor, but it works, and you always know that the object has been instantiated.
  3. array = createObject("java", "java.util.ArrayList");
    array.add(obj);

    - This is what I feel is the 'worst' way of using Java objects in CF as the no argument default constructor is called implicitly, which means you really have no control, and it can lead to all sorts of weirdness in your application if you don't track what has been actually instantiated and what hasn't.
  4. Collections = createObject("java", "java.util.Collections");
    sortedArray = Collections.sort(array);

    - This case shows where static methods are called, in which case, there is no constructor.
  5. Color = createObject("java", "java.awt.Color");
    black = Color.black;

    - This is where we want to be able to retrieve a static property.
Okay, so we have our work cut out for us! But all this is very much possible!

So, the first decision to make, is that all of our internal methods on the JavaProxy.cfc are going to start with an underscore.  This is so that any method that we write, doesn't interfere with the onMissingMethod's we want to be able to pick up.  Also as we need to implement a special 'init' method, that isn't the constructor for the JavaProxy, but instead is a constructor for the Java object the JavaProxy represents, so we will have a _init(class) method that instantiates the JavaProxy.

I'm not going to show all the code here, just the relevant parts, but don't worry, you will be able to see it in the next version of JavaLoader.

So the _init method will do the following things -
  1. Take a Java Class as an argument, and store it in state
  2. Store some helpful Java Objects in some setters.
  3. Set the Static Fields of the Class the JavaProxy represents to the this scope
  4. Store all the Method objects of the Class in a struct of arrays for easy lookup (more on this later).
First of all, we'll set the Static Fields to the this scope.  It is actually very straight forward -

<cffunction name="_setStaticFields" hint="loops around all the fields andsets the static one to this scope" access="private" returntype="void"output="false">
    <cfscript>
        var fields = _getClass().getFields();
        var counter = 1;
        var len = ArrayLen(fields);
        var field = 0;

        for(; counter <= len; counter++)
        {
            field =fields[counter];
            if(_getModifier().isStatic(field.getModifiers()))
            {
               this[field.getName()] = field.get(JavaCast("null", 0));
            }
        }
    </cfscript>
</cffunction>

For reference
So what are we doing here? Well, we ask the Class for all of it's Fields, then we look around them, and then interrogate into whether or not they are static.

Once we know they are static, we retrieve their value, using field.get(), and set them to the same place in the this scope as they would have been in the Java Object.

We are able to use 'null' on the field.get() because the values are static, and are not tied to any actual instance of the Class.

So, what would be nice now, is to be actually be able to instantiate an object!  So let's look at implementing our own 'init' method, so that we can instantiate the Java Class that the JavaProxy represents.

<cffunction name="init" hint="create an instance of this object"access="public" returntype="any" output="false">
    <cfscript>
        var constructor = 0;
        var instance = 0;

        //make sure we only ever have one instance
        if(_hasClassInstance())
        {
            return _getClassInstance();
        }

        constructor =_resolveMethodByParams("Constructor", _getClass().getConstructors(), arguments);

        instance =constructor.newInstance(_buildArgumentArray(arguments));

        _setClassInstance(instance);

        return _getClassInstance();
    </cfscript>
</cffunction>

For reference
  • _buildArgumentArray() simply takes the argument struct, and turns it into an actual Java Array of the same objects.
So first off, we check to see if we already have created an instance - because we only want one, otherwise weird stuff could happen.  If we do, just give back the Java instance we already have.

The next line, is a little bit more complicated, so we'll break it down.

The _getClass().getConstructors() returns an array of all the possible Constructors that are available for this given class.

The _resolveMethodByParams() method takes a array of Method/Constructor objects, the arguments that have been passed through to the given method, in this case 'init', and find the best match that it can, and returns it.  We'll go into the details of that in a minute.

Once we have the right Constructor object, to get an instance of the Object that our JavaProxy represents, we call 'newInstance' on it, and pass in an array of the objects that make up the arguments that the Constructor needs.

And Preso! We have an instance of our Class! We set it to the state of the Class Instance, and return the newly created instance back out.

Wait! What? Return the new created instance? Why aren't we returning this, that doesn't make sense?  Well actually, if you think about it, it does.

We really would prefer it if ColdFusion did all the heavy lifting when it comes to the bridge between Java and ColdFusion, not only is it more performant, but it also provides a greater deal of consistency across the code base.

So we have code that is:
obj = JavaProxy.init();
obj is actually an instance of the ColdFusion JavaProxy, and then there is a much more seamless line between the new CFC JavaProxy, and the use of the ColdFusion one, which is a very good thing.

That being said, we need to provide support for all the different types of ways that Java Objects can be used and created, so we have to also cater for the other aspects as well.

So without further ado, let's actually fire off some methods!  This is where onMissingMethod really comes into it's power!

<cffunction name="onMissingMethod" access="public" returntype="any"output="false" hint="wires the coldfusion invocation to the JavaObject">
    <cfargument name="missingMethodName" type="string" required="true" />
    <cfargument name="missingMethodArguments" type="struct" required="true" />
    <cfscript>
        var method = _findMethod(arguments.missingMethodName, arguments.missingMethodArguments);

        if(_getModifier().isStatic(method.getModifiers()))
        {
            return method.invoke(JavaCast("null", 0), _buildArgumentArray(arguments.missingMethodArguments));
        }
        else
        {
            if(NOT _hasClassInstance())
            {
                //run the default constructor, just like in normal CF, if there is no instance
                init();
            }

            return method.invoke(_getClassInstance(), _buildArgumentArray(arguments.missingMethodArguments));
        }
    </cfscript>
</cffunction>

Okay, so this is the code that actually takes the methods that are called on the JavaProxy, and passes them to the Java instance or Class as appropriate.

The _findMethod() method, returns the Method that best matches the name of the method that was called, and the arguments that it has.  I will go into detail on that in just a second.

Once we have the correct Method, if it is static, we can then invoke it against 'null', and return it's value.

If it isn't static, then we check to see if we have a instance of the Java Class yet, if not, we create one using the default Constructor, which is the same way that ColdFusion does it.

From here, we are able to invoke the method against the class instance, and return any results that we may get.

Now we can look at the logic that allows us to work out which method matches what in ColdFusion.

Our first step, is to look at the _findMethod method, which is actually pretty simple:

<cffunction name="_findMethod" hint="finds the method thatclosest matches the signature" access="public" returntype="any"output="false">
    <cfargument name="methodName" hint="the name of the method" type="string" required="Yes">
    <cfargument name="methodArgs" hint="the arguments to look for" type="struct" required="Yes">
    <cfscript>
        var decision = 0;

        if(StructKeyExists(_getMethodCollection(), arguments.methodName))
        {
            decision = StructFind(_getMethodCollection(), arguments.methodName);

            //if there is only one option, try it, it's only going to throw a runtime exception if it doesn't work.
            if(ArrayLen(decision) == 1)
            {
                return decision[1];
            }
            else
            {
                return _resolveMethodByParams(arguments.methodName, decision, arguments.methodArgs);
            }
        }

       throw("JavaProxy.MethodNotFoundException", "Could not find thedesignated method", "Could not find the method '#arguments.methodName#'in the class #_getClass().getName()#");
    </cfscript>
</cffunction>

The first thing to know is, that _getMethodCollection() returns a struct of arrays that was set up in our _init(), the key of which is the name of the methods found in the class.  The arrays contained in the struct have all the Methods that have that name, as there may be more than one.

So, the first thing we do, is check to see if the name of the method we need is in the collection of methods we have, if it is we go and grab the array of methods this invocation could possibly be.

You will notice that I have written code that states 'if you only have one option for the method, just return that'.  You may be wondering why, as the parameters of that method may not match what has been passed in.  Well, if that is the case, we will get a runtime error, which is the same as what we would get otherwise, so there is not a huge difference here to just say 'let's give this a shot, if it doesn't work, no big deal', and we save the performance hit of comparing parameters.

If there are more than one option available, then we have to start comparing parameters, and this is where the _resolveMethodByParams() method that we saw earlier does it's hard work.

<cffunction name="_resolveMethodByParams"hint="resolves the method to use by the parameters provided"access="private" returntype="any" output="false">
    <cfargument name="methodName" hint="the name of the method" type="string" required="Yes">
    <cfargument name="decision" hint="the array of methods to decide from" type="array" required="Yes">
    <cfargument name="methodArgs" hint="the arguments to look for" type="struct" required="Yes">
    <cfscript>
        var decisionLen = ArrayLen(arguments.decision);
        var method = 0;
        var counter = 1;
        var argLen = ArrayLen(arguments.methodArgs);
        var paremeters = 0;
        var paramLen = 0;
        var pCounter = 0;
        var param = 0;
        var class = 0;
        var found = true;

        for(; counter <= decisionLen; counter++)
        {
            method = arguments.decision[counter];
            parameters = method.getParameterTypes();
            paramLen = ArrayLen(parameters);

            found = true;

            if(argLen eq paramLen)
            {
                for(pCounter = 1; pCounter <= paramLen AND found; pCounter++)
                {
                    param = parameters[pCounter];
                    class = _getClassMethod().invoke(arguments.methodArgs[pCounter], JavaCast("null", 0));

                    if(param.isAssignableFrom(class))
                    {
                        found = true;
                    }
                    else if(param.isPrimitive()) //if it's a primitive, it can be mapped to object primtive classes
                    {
                        if(param.getName() eq "boolean" AND class.getName() eq "java.lang.Boolean")
                        {
                            found = true;
                        }
                        else if(param.getName() eq "int" AND class.getName() eq "java.lang.Integer")
                        {
                            found = true;
                        }
                        ...
                        else
                        {
                            throw("Ack", "Cannot match this primitive type", "'#param.getName()#' is just not matching");
                        }
                    }
                    else
                    {
                        found = false;
                    }
                }

                if(found)
                {
                    return method;
                }
            }
        }

       throw("JavaProxy.MethodNotFoundException", "Could not find thedesignated method", "Could not find the method '#arguments.methodName#'in the class #_getClass().getName()#");
    </cfscript>
</cffunction>

Woah! That's a lot of crazy code... well, it's not too bad once you break it down.

What we are doing is looping around all the possible methods we have available in the decision array, and trying to see if they match the parameters that we have in our argument struct.

First test says, 'if the number of parameters is different, well, we can't invoke this method', and simply passes it by.

From there, we need to loop around each of the parameters, and see if it can work with the class that the corresponding argument that matches it's place.

You're probably looking at the line that reads '_getClassMethod().invoke(arguments.methodArgs[pCounter], JavaCast("null", 0));' and thinking... what on earth does that do?  Well, it allows us to get to the Class object of that argument.

This is very similar to doing a obj.getClass(), however, I can't do that in all instances.  If an argument is a CFC, then it will try and resolve the method 'getClasss' against the CFC, and most likely throw me an error.  So I have to use reflection!

the _getClassMethod() (this was setup in our _init()) is the actually Method class that represents the 'getClass()' method aforementioned, what I then do is invoke it on the required argument, and this gives me back the Class Object I need for comparison.

Now, a Class object has a great method called 'isAssignableFrom', basically, this says 'If the object is a the same as this Class, or a subclass, or implements this interface, return true'.  This means that if the argument in the method that have been invoked on the CF side isAssignable to the parameter that is required for this method, then this method can be invoked successfully.

The other thing we need to do is map primitive parameters, such as int, char, boolean, etc back to their Object representations.  The nice thing is that Java will map this back and forth at runtime for us, so as long as the values match up, we're good to go.

Once the parameters have all been resolved, we can return the method we have found that works, otherwise, we throw an exception.

That pretty much covers the JavaProxy.CFC.  As I said before, you will be able to see the code in action once I release the new version of JavaLoader, but feel free to ask any questions you may have, I will be happy to answer them.
27 August 2007 02:10 PM 0 Comments

Scaffolding a Generic Admin: Now with Transfer!

Paul Marcotte has written an interesting series on how he is building his own administration scaffolding using his own MVC framework, Dispatcher, and Transfer.

In his latest post, he adds Transfer into the mix and shows some good examples of what can be done when retrieving the Meta Data from Transfer about the Objects that are defined within it.
17 August 2007 05:34 PM 0 Comments

CFFrameworks presentation - Developing Applications with Transfer ORM

Nick Tong bullied me into doing another online presentation of my Developing Applications with Transfer talk ;o) So it's all lined up and ready to go for the 30th of August.

Full details can be seen here: http://www.cfframeworks.com/blog/index.cfm/2007/8/16/Workshop-Mark-Mandel---Developing-Applications-with-Transfer-ORM

This presentation will show off the branding for Transfer, which those of your not at cf.Objective probably haven't had a chance to see (and also since I haven't done the new Transfer site I've been promising for millennium)

Depending on how time goes, you may even get sneak peeks at the new Composite Key functionality I'm about three quarters of the way through.

It should also be worth noting that the following month, I will be doing my Advanced Transfer ORM Techniques presentation, which has not been seen outside of cf.Objective before!
15 August 2007 01:12 PM 22 Comments

Would you come to Melbourne CFCAMP?

I need to know some numbers for if we can run a CFCAMP in Melbourne, how many people would be likely to attend.

If you would be able to attend, please add a comment to this blog post, along with how many people you would be able to bring along with you.

I'm currently trying to see what option we have in terms of venue to incite Adobe to bring CFCAMP down to Melbourne, but if there isn't any interest, better we know now!

Ideally this would shortly thereafter the other state's CFCAMP, so please keep that in mind (short lead time, I know, but what can you do?).

I hope we get a large response! :oD
30 July 2007 09:37 AM 2 Comments

ColdFusion 8 Launch Party - 8th Aug - Melbourne

All! It's a special CF8 Launch party!!!!

Location:

NGA.net, Level 2, 17 Raglan St, South Melbourne
Map: http://link.toolbot.com/google.com/73016

When:

8th of August, Meeting starts at 6:30, so get there before hand -
** Please note, we are starting a little bit early this time, due to the crossover between states.

Agenda:

This is the official ColdFusion 8 Launch Party!

We will have presentations from Ben Forta via Connect, crossovers between the launch parties at all the other CFUGs across Australia and New Zealand, and prizes from Adobe for those people that attend!

Everyone is welcome, and if you haven't attended a single CFUG meeting yet, now is the time to come down!

If you are going to attend, please RSVP to mark [dot] mandel [at] gmail [dot] com.

See the CFUG Melbourne Calendar at:
http://www.cfcentral.com.au/Events/index.cfm

Or add to your Google Calendar - search for 'CFUG Melbourne'.

As per usual, we'll grab pizza during the evening, so we have
something to scoff down!

Look forward to seeing you all there.
23 July 2007 02:47 PM 0 Comments

How to Ask Questions the Smart Way

This is a FAQ that was first written back in 2004, and has been updated ever since, but outlines what I believe to be the best way to ask questions on technical forums.

I think it's important to post it up, every now and again, so that people remember that it exists for a reason ;o)

How to Ask Questions the Smart Way
18 July 2007 10:23 AM 0 Comments

TQL Lexicons for Fusebox


Nick Tong over at Succor has posted a Fusebox lexicon for using TQL !  Pretty neat stuff!

If you like Fusebox, and you like Transfer, I suggest having a look.

I have to say, it's really cool watching all these framework work together... ;o)

OMG! I've sold out!

Yes, it's true, I've finally succumbed, and put ads on my site, and switched out the wishlist for a PayPal donate button.  I have finally turned to the dark side.

Do not fear! There are reasons for this!

First of all, the Amazon wish list, didn't really work out.  I'm sure people thought 'I'll buy Mark something from the wishlist, he'll like that', and then quickly realised it can be up to $30 to send stuff to Australia, and that whole idea quickly went out the window.

Second of all, I really want to get out to more conferences overseas.  Unfortunately, while living in Australia is wonderful, we are about as far away from anyone as can possibly be.  This means that travelling can be really expensive.  So this is to say that any revenue and/or donations that I receive from the ads, or from PayPal, will go directly to funding conference travel costs, and also to general open source development costs.

So if you do like the work that I've provided for you guys, please feel free to click the PayPal donate button, its always appreciated, and allows me to come out to more conferences, and put more resources at your disposal.

Performance Improvements for Transfer

Last week we had Robin Hilliard of Rocketboots into the office to help us get the biggest bang for our buck performance wise with the Transfer / MachII / ColdSpring application, and I have to say it was a great session all around.

Apart from imparting upon us a great many ideas for aspects of our application we could cache, and various other pearls of wisdom, we turned on Report Execution Times, and managed to find several key places in Transfer that were sometimes called over 500 times in one request (we do a fair amount of data movement per request).

For one thing, in all honesty, I had completely forgotten about Report Execution Times.  I had turned it off when it was making my CFC heavy applications go into a slow paced crawl, and had quite literally left it for dust.

However, after turning it on, and just running it over just a few requests, the key areas of Transfer that would provide significant performance increases became very apparent very quickly.

This is where all those small, finicky, performance 'tricks' come to the fore very quick -
  • using else/if statements rather than case statements
  • replacing the use of iterators with for() loops that use a counting numeric index
  • playing with different Java Collections for different operations - i.e. ArrayList vs LinkedList
  • Assigning method results to variables before large looping operations, rather than evaluating them every time.
  • ..and other such things

It should be worth noting, that by doing some of these things, the code ended up looking rather ugly, but with testing, performs faster than before.  So this is not to say that I went through the entire Transfer codebase and switched out everything I could find to being the most efficient I could possibly, in fact that couldn't be further from the truth.  There are many places in Transfer that use case statements, even knowing that else/if statements are faster - simply because I find case statements are more readable, and they are not in places of the system that are called in numerous succession.  By the same token, I make extensive use of Java iterators to loop over my collections in Transfer, as they provide a high degree of abstraction away from what sort of Collection is being used behind the scenes, but those places are now limited.  However, by specifically pin pointing aspects of the system that are critical to the performance of the framework, the necessary tweaks to the framework could be discovered and acted upon.

So say thanks for Robin for the new performance improvements for Transfer that can now be found in SVN.

Brian Rinaldi on Object Composition and Transfer

Brian Rinaldi just finished up a great tutorial on how to handle Object Composition, going from creating CFCs from scratch, through to modelling the entire thing with ColdSpring and Transfer.

He goes into some great detail on how to use his Illudium PU-36 code generator to generate the Transfer templates to make life a lot easier for the outset.

Definitely an interesting read.
13 June 2007 02:13 PM 10 Comments

Installing ColdFusion 7 on Ubuntu Feisty Fawn

I'm not going to say that I'm a hardcore Linux user, but I found that this was the simplest way to install ColdFusion 7 on Ubuntu, with the least amount of fuss.

I've skipped describing any step in which you have your own options which are up to you, or the default specification is fine.

Hope you find it useful.

  1. Download coldfusion-702-lin.bin from www.adobe.com/coldfusion
  2. Install apache2 using
    sudo apt-get install apache2
  3. Make sure you can compile things by installing:
    sudo apt-get install build-essential
  4. Rename the coldfusion-702-lin.bin to coldfusion-702-lin.bak
  5. We run the usual replace command on the binary
    # cat coldfusion-702-lin.bak | sed "s/export LD_ASSUME_KERNEL/#xport LD_ASSUME_KERNEL/" > coldfusion-702-lin.bin
  6. I like to put my help files in /var/www - so, give me permission to do what I want to it:
    sudo chown <your user name> /var/www
  7. Run the newly made installer
    sudo ./coldfusion-702-lin.bin
    1. Choose Server Configuration
    2. Add web server Configuration
      1. Apache
        1. What directory contains your Apache configuration file:
          /etc/apache2
        2. Where is the Apache program binary file?:
          /usr/sbin/apache2
        3. Where is the control file that you use to start and stop the Apache web server?:
          /etc/init.d/apache2
    3. Choose ColdFusion MX Administrator Location:
      /var/www
    4. Enter the name of the runtime user:
      Enter the name of the user that you set to own /var/www
  8. Download the hotfix wsconfig.jar for Apache 2.2 support and install it as per the instructions.
  9. gedit /opt/coldfusionmx7/bin/connectors/apache_connector.sh and change the wsconfig to:
    ../../runtime/bin/wsconfig \
        -server coldfusion \
        -ws apache \
        -dir /etc/apache2 \
        -bin /usr/sbin/apache2 \
        -script /etc/init.d/apache2 \
         -coldfusion

    exit $#
  10. Start ColdFusion
    sudo /opt/coldfusion/bin/coldfusion start
  11. There will be an error about the connector - do not worry about it
  12. Run the apache connector
    cd /opt/coldfusionmx7/bin/connectors/
    sudo ./apache_connector.sh
  13. Browser to: http://localhost/cfide/administrator/index.cfm
  14. Rename cfmx-connectors.sh, so we never see that error message again
    cd /opt/coldfusionmx7/bin
    mv cfmx-connectors.sh cfmx-connectors-run.sh
  15. You are complete!


Now that you've seen all that, it's nice to know that ColdFusion 8 installs seamlessly with Apache 2.2 right out of the box.

Transfer Mailing List: 130 People!!!

I just checked out the mailing list for Transfer, and we're currently at 130 people!

Wow!

When I left for cf.Objective(), we were at 94, and I was hoping we would soon be at 100... I had a peek today, and we're actually at 130! That's an increase of 36 people since cf.Objective() Started!

That's 1.6 people added to the list, per day, since the day cf.Objective() started.

I can only assume that this as a sign that my presentations were well received, and have generated some interest in Transfer, which I am very glad to hear.
(By the way, if anyone has any feedback on those presentations, please feel free to let me know, I actually get very little in the way of feedback, so I'm actually all ears)

I'm currently working on the getting the Composite key functionality off the ground, so things are still moving forward with Transfer, so expect some news on that in the near future.

cf.Objective() Wrap up from Downunder

Now that things have finally settled down getting back to Australia (and I finally have a laptop that I can use again), I can put some of my thoughts down on (virtual) paper on the recent cf.Objective() conference.

First of all, let me just say that this conference was the single best ColdFusion learning experience I have ever had.  I don't think I have learned as much, in such a short period at any other conference, mailing list, chat room, or CFUG meeting.

I have to seriously take my hat off to Jared, Steven and the rest of the crew that put together this event - the facilities were excellent, the speakers were phenomenal, and the food was fantastic (those chocolate cakes!).

When I wasn't busy presenting on Transfer, I actually got to run around and sit in on a whole lot of presentations.  Again, these presentations were a level above and beyond any I have seen elsewhere, so much so, that I can't pick out specific ones in which I would say 'these are were the highlights for me', otherwise, I'd just be listing 90% of the sessions I went to.

For those of you who are still waiting on my presentation slides, please be patient.  I only just got ColdFusion back up and running on my resurrected laptop, so I've got a little ways to go.  Thankfully all the slides where backed up, and I just need to do some work on the example application before I can make it available for download.

Coming from Australia, and actually physically meeting so many of the people that I talk to online, day in, day out, was an absolute pleasure.  A few of you I had met before, but most of you I have only ever talked to via text.  It is always amazing how much more you get out of simply physically sitting in the same room as someone and being able to chat about things, than you can via something like IRC.

While the presentations were incredible, I think I probably took more away from talking to people about ColdFusion at cf.Objective().  The environment and the people that were around really lent itself to creating some really interesting discussions about ColdFusion and various other software development topics.  I often woke up at 5:30am and simply couldn't get to sleep again because I had to get some thoughts down on paper, or I had to actually start writing some code.

The only complaint I had about the conference was the complete lack of sleep I got!  I landed in Minneapolis in time for some dinner, having had about 3 hours sleep, and then promptly got dragged into conversing about ColdFusion until 2am in the morning.  I think I actually worked out, in over 72 hours of being awake, I had only managed around 11 hours sleep.  Of course it was totally not by fault that I was forced to stay up late drinking and talking geeky things. ;D

Honestly, however, regardless of what country you reside in, if you are seriously looking to expand you knowledge of enterprise development, be it beginner, or advances, cf.Objective() is the best learning experience you could have.  Funds non-withstanding, I will definitely be there next year.

Branding for Transfer released at cf.Objective()

This may seem a little behind the times, but between my HD crashing at conference, and trying to physically meet as many people as possible (and have a few drinks too), I didn't blog that at cf.Objective() I released the new logo and branding for Transfer!

Transfer Logo

This was designed by my girlfriend, who, as you can see, can definitely do a far better job than my usual programmer artwork.

As well as this, there is an upcoming www.transfer-orm.com project site for Transfer.  Currently this just points back to the compoundtheory project page, but expect to see a Transfer specific page, with a wiki, coldfusion based trac and all sorts of other interesting things.

I have yet to write up a full blog post on cf.Objective(), as I only got back a couple of days ago, and have still been rebuilding my laptop, so expect that, and presentation slides and example code etc to come soon!

I'm here in Minneapolis!

Phew! over 24 hours of flying, travelling, waiting for bags, standing queues, taking my shoes off, putting my shoes on, walking through scanners, putting bags on conveyor belts, taking bags off conveyor belts.... I'm finally here.

I have to say, the flights weren't all that bad, Qantas's new 'on demand' in flight system was pretty good in that I could pick and choose what TV and movies I wanted to watch for 14 hours.

If you need to reach me, I added myself to the twitter back channel for cf.Objective(), so if you add me as a friend, can chat that way.  I'll most likely be on IM most of the time I am here, and worst comes to worst, call the hotel and ask for me by name - but please no calls before 11am, I'm currently running on about 3 hour sleep.

Other than that, I should be pretty easy to spot around the place, look for the guy that looks like this, with a dragon tattoo around his left bicep.

That being said, if anyone wants to catch up during the day on Thursday, please do get in contact.

See you all at the conference!



29 April 2007 12:23 PM 0 Comments

cf.Objective() Transfer Preview Recording

Yesterday morning (well, it was my morning, most other people's afternoon), I did a short, 20 minute preview of one of the talks I am doing at cf.Objective().

If you managed to miss it, and want to have a listen, or are looking for a real quick overview of Transfer, you can see the recording here.
27 April 2007 04:27 PM 1 Comment

CF.Objective() Preview: Transfer ORM Presentation

I have about three seconds to write this - but I'm doing a preview of my Developing Applications with Transfer ORM presentation for cf.Objective() at 3pm EST, on Friday the 27th of April (my tomorrow). 

Please show up if you are interested, as I'm getting up at 5am to come talk to you lot ;o)

More details can be found at the ColdFusion Meetup Group .

25 April 2007 11:08 AM 0 Comments

Bender goes Alpha - No More Vapourware!

Toby Tremayne has (finally? ;o) ) released an Alpha version of his Flex to Transfer bridge Bender.

Bender looks to be a very interesting project, in that it generates the AS for you that mirrors the generated TransferObjects that come our of Transfer

It also handles passing data back and forth between Transfer and Flex, and back again, without you having to do any of the translation between.

The neat thing about Bender as well, is that you can set up mappings, such that when you call Bender.save() on the AS side, it can either call Transfer directly, or, you can send the save() request to a completely different mapped CFC and/or method!  This gives you complete flexibility over your architecture.

I'm really liking the work that Toby is doing on Bender, and I think it's going to be a real asset to the Transfer library.
17 April 2007 12:39 PM 5 Comments

Transfer 0.6.3 Goes Final!

After a good Release Candidate phase, Transfer 0.6.3 is ready for release.

There is nothing huge to report in the change from RC2 to Final, except for a few small code cleanups and some more documentation, and that is about it.

For the big spiel about what is new in 0.6.3, check out the RC1 release post.

Now it's just a case of seeing what I can manage to fit in before cf.Objective(), which is in two weeks!

Enjoy!
09 April 2007 08:17 PM 1 Comment

Bender - the Flex to Transfer Bridge

Toby Tremayne has started doing some work on developing a bridge between Flex and Transfer called 'Bender', which is meant to automate the process of translating TransferObjects into Actionscript Value Objects and back again within a Flex Application.

We are yet to see any code samples yet, but he tells me that progress on it is running along nicely, and he already has a series of blog posts on the progress he has made already.

I'm really looking forward to seeing the product in action, I think it is going to be really interesting!  Have a read of it here.
09 April 2007 07:14 PM 1 Comment

Setting Up Transfer with Fusebox

This is something that Nick Tong, of cfframeworks.com fame wrote a while ago, but I totally forgot to blog.

Nick wrote up a great little tutorial on how to set up Transfer when using Fusebox with Fusebox Lexicons.

You can have a look at the tutorial here.
09 April 2007 10:52 AM 0 Comments

Transfer v0.6.3 RC2 released

Another release candidate for Transfer.  This one updates some documentation, and implements a workaround for the CFMX memory bug with URLClassLoaders described here.  Other than that, nothing that exciting to report.

Mind you, the new tBlog example application has been updated to instead use TQL to do it's gateway queries, rather than using regular ol' SQL, and a Decorator example is also shown, so it may be worth re-downloading it if you already have it, and take a peek.

Since the last release candidate didn't show up any bugs, assuming I don't hear anything about this one, v0.6.3 final will be ready to go in a week or so.  Which is really great, as no one has discovered any glaring holes in TQL yet.

After that, it's time to start developing Composite Key support. Cool!
09 April 2007 10:50 AM 3 Comments

JavaLoader v0.4 Released

One thing that I always gets complaints about with JavaLoader is that you can't delete or rename a .jar file once it is use by ColdFusion, you either have to restart CF, or name the .jar file something funky like 'myOwnJar-10042007.jar', so it has a unique name.  Now with this version of JavaLoader, that issue is no more!

While the .jar file that JavaLoader uses itself does get locked down (I know.. I can't do anything about that one), but .jar files that you use with JavaLoader no longer are locked by the system!

To note, the JavaLoader cfc has had one of its arguments removed - 'loadedClassPathBias', simply because it was more difficult to implement with the new code base, and there didn't seem to be a case for it.  By default,JavaLoader will load the specified jar files before it loads the parent's, if it has one.  Honestly, I don't think this is going to affect a single person, because I would be shocked if anyone actually ever used the option.

Please note there are some issues with memory and JavaLoader, so make sure you put your JavaLoaders in the Server scope.  See here for more details.

If you find any issues, please post to the forums, or contact me directly.

Enjoy!

Using a Java URLClassLoader in CFMX Can Cause a Memory Leak

This is a bug in ColdFusion that can cause memory leaks when using a java.net.URLClassLoader to load external jar files.  Thus, this can cause memory leaks in JavaLoader, Transfer and any other system that uses this technology.  However there is a workaround for the issue.

To explain the problem, first we need to look at some key issues with a URLClassLoader.  URLClassLoaders are notorious for causing memory leaks, because, for them to be garbage collected, all instances to themselves and the classes that they have created need to be garbage collectible.

This means that if you access a class from a URLClassLoader and hold it somewhere in memory, then the URLClassLoader can never be garbage collected.

This is exactly what happens with ColdFusion.

When ColdFusion does some introspection and resolution of ColdFusion code against a Java object, somewhere, deep inside its hidden internals, it keeps a strong reference to the Class object that refers to that Java object.  This means that when the JVM comes along to garbage collect the instance of the URLClassLoader, it can't do it, because ColdFusion has a reference to a class that it loaded somewhere inside.

So, the memory leak only ever actually happens when an instance of a URLClassLoader is no longer available to ColdFusion, as it is never then garbage collected by the JVM.

How does this translate to using JavaLoader? Well, a perfect example of this is where you put an instance of JavaLoader in the application scope, because generally it is used as a singleton.  JavaLoader (and anything that subsequently uses JavaLoader) has an instance of a URLClassLoader inside it.  However, when the application scope times out, the JavaLoader CFC may well be garbage collected, but the URLClassLoader isn't, which can cause a memory leak.

To note however, in production systems the leak is minimised in situations like this, as it is often very rare that the application scope will ever time out.

So what is the workaround for this issue? To note, I have been pushing at Adobe to get a hotfix out for CFMX to resolve this issue, but we can definitely still use this technique now, without having to worry about memory leaks. 

Essentially, the memory leak only happens when the URLClassLoader is no longer available to CF, i.e. an application scope times out, or something similar - so we just need to make sure that it never, ever, times out.  How can we do that? why, put it in the Server scope of course!

Since variables in the Server scope never time out, we don't need to worry about the URLClassLoader (or JavaLoader) being lost and then recreated, as it always exists.  As long as you put it in the Server scope under a key no one will ever need to utilise (I like a hard coded UUID myself)!  Hence we beat the memory leak monster!

I have just committed a fix for Transfer that automatically puts the JavaLoader it uses into the Server scope, so even if your TransferFactory times out, the JavaLoader never will, which means there is no leak, and the RC2 for 0.6.3 will have this as well.

Hopefully Adobe will put out a hotfix for this issue, but until then, put your JavaLoaders in the Server scope.
27 March 2007 03:46 PM 3 Comments

webDU 2007 Post Mortem

I figured it was about time I made some comments on webDU now that the dust has settled (and I'm finally over the gastro I've had all week, including at the conference).

Overall, I have to say I have an absolute blast, and it was brilliant to put some real faces to people who were just names on a mail list, IM or irc chat room.

There is a huge amount of kudos that needs to go to Geoff, Julie and the rest of the Daemon team for putting on webDU, it was well organised, professional, and not to mention a whole lot of fun.

The only criticism on the conference was that with the Flex heavy presentations, there seemed to be a fair amount of overlap in terms of content covered.  I went to a few Flex presentations, and many of them covered that very beginning level of introduction into Flex.  While I am not a Flex user by any means, I like to keep my eye on the Flex space, and was often looking for something more than just another 'here is how to say 'Hello World' in Flex', especially when the title of the presentation lends itself to make you believe it is something more.

Otherwise, the presentations where very good, and on the whole insightful.  My favourites included the Keynote: Flash Bang, Apollo, FarCry 4.0: The Application Framework, Seeding, Developing and Growing an online Community, and Using the IM gateway in ColdFusion .

I felt that my Transfer presentation went very well, although I'm still not sure how I managed to get through all 39 slides in just over half an hour without someone telling me to speak slower ;o).  I did have to laugh when I got the webDU booklet and my presentation slides took up something like 4 or 5 pages, compared to other presenters usual 2 or 3.

Speaking to people after the session, the feedback was generally positive, and people seemed to have walked away feeling like they had learnt something.  Mind you, if anyone has any extra feedback they wish to give me on the presentation, I'm all ears, so fire away. I'm always looking to do a better job.

Charlie Arehart and I did a BOF: ColdFusion Componentry session together, which, in all honestly, I didn't think anyone would show up to, being 8am after the night of the banquet.  But people did, and we had a good chat about Object Oriented development, from a variety of angles.  I apologise if I wasn't making any sense, as I may have possibly had my fair share of the Microsoft tab at the bar the night before.

Speaking of which, the Banquet was great as well, including the Kath and Kim impersonators.  I think the most enjoyable part was watching the American visitors try and work out who Kath and Kim were. ;o)

The drinks at the bar after the banquet were also lots of fun, but I am wondering where everyone went around 11pm.  It seemed like the place was packed, and then suddenly it was empty.  Go figure.  I did get a definite giggle out of a Microsoft representative asking me why I didn't program in .Net.  All I know is that at around 2am they kicked us out, so I ended up going back to my room to crash.

The definite highlight of the whole thing, I have to say, was the people.  It was such a good opportunity to run around and actually physically talk to a variety of people who worked with Adobe technologies.  (Especially to one guy who couldn't quite believe that I thought manipulating a huge amount of financial data was really cool... I didn't really care about the Flex part).  To those of you I talked to, and there were way to many to mention, was great to chat to you all, and I'm glad to have (finally?) met you.

A brilliant conference, and I hope that those of you who didn't come, will show up next year, and those that I met this year, I will see again.
22 March 2007 08:22 AM 0 Comments

WebDU, Day One

webDU has been off to a great start!  The national Adobe user group meeting was an absolute blast, and I had a great time last night chatting to Jeff Coughlin last night when we went for dinner at 10:30 in the evening.

In case anyone has no idea what I look like - look for the guy in the Black Autobots t-shirt.  You can't miss me ;o) So if you see me, feel free to say Hi!

I'm off to partake in some breakfast.
21 March 2007 12:50 PM 2 Comments

Transfer 0.6.3 RC1 is Released

Wow. I have been pushing like crazy the next release of Transfer finished before I fly out for webDU, and I actually made it.  I leave this afternoon for Sydney at 4:00pm, so I am cutting it fine.

This release has 2 great new features, as well as several critical bug fixes, not to mention a greatly expanded documentation, including a new Overview and FAQ.

Rather than try and explain these features all over again, I'm simply going to show off some of the Overview and FAQ:

From the Overview Section:

Transfer Query Language 

There is also a scripting language that allows you to perform database queries based on the information and naming scheme that you set up in your transfer configuration file called Transfer Query Language (TQL).  TQL is very similar to SQL, however since Transfer already knows about the relationships in your system, you don't have to write as much code to perform complicated queries against your database.

For example,  if we wanted to perform a query to list all Posts in my Blog System, with their Author, and all the Categories they belonged to, ordered by the post date we would write this in TQL:

<cfsavecontent variable="tql">
    from
    post.Post as Post
        join system.Category
            join user.User
    order by
        Post.dateTime desc
</cfsavecontent>

And then we would create a Transfer Query Object by passing the TQL to transfer.createQuery(), and then create the actual query we need by passing the Transfer Query Object to transfer.listByQuery(), as in the example below.

<cfscript>
    query = transfer.createQuery(tql);
    qPosts = transfer.listByQuery(query);
</cfscript>

Since Transfer already has the relationships between the Post, Category and User, it can intelligently create the SQL joins for you!  Saving you even more time!

There's another Database Management Method you can use with TQL besides transfer.listByQuery(), and that's transfer.readByQuery(). readByQuery returns a Transfer Object, whereas listByQuery() returns a query. readByQuery() requires TQL that will return only "one row" - if more than one row is returned, an exception is thrown - and it also requires that you specify the class, like all the otherreadBy* methods.

Basically, readByQuery() is a way to create a Transfer Object when you don't want to use the primary key, but specify some other condition that will return only one record.

For more information on these Transfer methods, see Using The Data Management Methods .

From the FAQ:

How do I inject dependencies into a TransferObject?

To inject dependencies into a TransferObject, the 'afterNew' event must be used.  

To register an Observer for the afterNew event:

observer = createObject("component", "InjectorObserver").init(); 

getTransfer().addAfterNewObserver(observer);

The observer must have a method on it that looks like, which is run when the event is fired:

<cffunction name="actionAfterNewTransferEvent" hint="Do something on the new object" access="public" returntype="void" output="false">
    <cfargument name="event" hint="" type="transfer.com.events.TransferEvent" required="Yes">
    <!--- do stuff here --->
</cffunction>

The event is then fired *after* the TransferObject is init()'d and the configure() method is run.

So if you now want to inject something into a TransferObject, you will need to write a setter/getter on it - and you can do it something like this: 

<cffunction name="actionAfterNewTransferEvent" hint="Do something on the new object" access="public" returntype="void" output="false">
    <cfargument name="event" hint="" type="transfer.com.events.TransferEvent" required="Yes">
    <cfif arguments.event.getTransferObject().getClassName() eq "user.User">
         <cfset arguments.event.getTransferObject().setService(getService()) />
    </cfif>
</cffunction>

A <cfcase> statement could be used instead of an <cfif> depending on your needs.

You could put this event directly on a Factory of some description if you  wanted to, or have it on a specific object whose only task is to inject new
TransferObjects with dependencies, depending on your application design.

Full changelog.

A *HUGE* amount of thanks to Nando, Jaime Metcher, and Aaron Roberson for all the hard work they put into the documentation.  It was greatly appreciated.

You may have also noticed a skip in version numbers.  It's okay, you're not going totally crazy.  That was just a decision that I made, to evenly space out all the major feature releases between 0.6.1 and 0.7.

So now the release road map looks like:

0.6.3 : TQL
0.6.6 : Composite Keys
0.6.9 : Soft Deletes
0.7 : All the other small pieces I wanted to fit into 0.7

It also gives me some wiggle room in case I need/want to do a maintenance release between.

Now, I'm off to webDU, and if you are attending, I hope you come and hear me speak!

You can download Transfer from here.
17 March 2007 05:23 PM 0 Comments

Interview on Transfer, ORMs, and cf.Objective() 2007

I did a quick interview via IM with Judith Dinowitz on travelling over to the USA for cf.Objective() 2007, and the talks I'll be doing on Transfer, and some of the new features that Transfer will have in the next release.  If you want to have a read, check it over here.

Travelling to cf.Objective() this year is going to be so much fun, I can't tell you how excited I am to finally meet a whole heap of people that I've only ever known online, not to mention all the great presentations.  Definitely well worth the over 24 hours of travel that I have to do to get to Minneapolis.
05 March 2007 12:42 PM 0 Comments

Damon Gentry Blogs Transfer

Damon Gentry has started blogging about Transfer over at his website www.dagen.net.

He's done three articles so far as he logs his journey with Transfer, and it is a very interesting read as he learns about the framework.

So, if you are interested in Transfer, or are looking to learn something new, have a look at Dan's blog, it's got some good content.
28 February 2007 11:18 AM 0 Comments

My Presentations Listed at cfObjective.com

If you take a wander over to the cf.Objective() site, you'll see that my two presentations on Transfer are listed on the session page.

I'm going to be doing a general introduction to Transfer, as well as an extended 'Advanced Transfer Techniques' presentation that will go into some of the extra features of Transfer that aid in managing your model, like caching, TQL, Decorators and Observable Events.

The session list is shaping up really nicely, and I've already earmarked several presentations that I definitely want to be at.

So far, my schedule looks tentatively like -
  • Peter Farrell - Head First Mach II
  • Peter Farrell - What's New in Mach II 1.5.0?
  • Sean Corfield - Real World SOA: Building services with ColdSpring and Transfer
  • Sean Corfield - Error Handling in service oriented Architectures
  • Mark Drew - The CFEclipse Project
  • Nicholas Tunney - JVM Server Tuning
Of course, I say this not knowing what times what presentations are, or even if I'm speaking during them. ;o)

cf.Objective() 2007 looks to be an amazing conference, so if you're on the fence about attending, I would highly recommend you come down.
27 February 2007 09:21 PM 7 Comments

Got ColdFusion?

Rey Bango has come up with a fantastic idea for promoting ColdFusion around the web

www.GotCFM.com

First stage of this project is a list of ColdFusion powered websites, that he wants to make sure is up to date, and highly visible.

To help power the site, have a wander over, and put in all the ColdFusion sites that you are aware of. Lets see how big we can make this list.

Apparently this is only step one in Rey's attempt to evangelise ColdFusion on the web, and more power to him.

Keep up the good work Rey, I like what you're doing.

21 February 2007 05:08 PM 5 Comments

CFFrameworks Interview on Transfer ORM

The interview I did with Nick Tong as just been put up on CFFramworks.com .  I'm really happy with how it came out, so I hope you enjoy listening to it.

We had a good chat, mostly about Transfer , but also about frameworks in general.  

Let me know if you have trouble understanding my Australian accent. ;o)
20 February 2007 09:46 AM 2 Comments

I got my Flash Face!

When I was a boy, all I ever wanted was my very own Flash Face .  I can't believe it has finally come true.

 

10 February 2007 06:34 PM 3 Comments

Issue with cfcatch and JavaLoader

This is an issue I came across yesterday while doing some work on Transfer that affects JavaLoader , and generally anything that uses an URLClassLoader to load any external class/jar files.

The issue lies with catching Java exception with <cfcatch>.  The documentation states, that to catch a thrown Java exception you can specify the type in the 'type' attribute of the <cfcatch> tag.  So if we wanted to catch a java.io.IOException, we would do so this way:

<cftry>
   <!--- do some stuff that may throw an exception --->
    <cfcatch type="java.io.IOException">
        <!--- do something with it --->
    </cfcatch>
</cftry>

Now the issue comes when you are using JavaLoader (or anything that utilises any sort of URLClassLoader) and the loaded Java code throws an exception that hasn't been loaded with ColdFusion at start up -

<cfcatch> can't catch the Java Exception by it's specific type!
 
To show you what I mean, I created a simple test bed.

I create a new Java Exception object, 'com.compoundtheory.test.myException', and a class called 'MyThrower' who's sole job was to throw this exception.

Just to note 'jl' is the JavaLoader instance that has loaded my classes.

My test bed looked like this:

<cftry>
    <cfscript>
        myThrower = jl.create("com.compoundtheory.test.MyThrower").init();

        myThrower.myThrow();
    </cfscript>
    <cfcatch type="com.compoundtheory.test.myException">
        full
        <cfdump var="#cfcatch#">
    </cfcatch>
    <cfcatch type="java.lang.Exception">
        java.lang.Exception
        <cfdump var="#cfcatch#">
    </cfcatch>
    <cfcatch type="any">
        any
        <cfdump var="#cfcatch#">
    </cfcatch>
</cftry>

The result that came from this was that 'java.lang.Exception' was output onto the screen.  This means that the ColdFusion <cfcatch> statement bypassed the 'com.compoundtheory.test.myException' type (which is its real type) and caught it at the 'java.lang.Exception' level, which is what 'myException' extends.

This led me to believe that the ColdFusion <cfcatch> can only catch exceptions that are loaded in its class path on start up.  To this effect I had two more test beds.

The first test was to get my JavaLoader loaded class to throw a 'java.io.IOException' - an exception that is native to Java 1.4, which comes with ColdFusion, and is loaded when ColdFusion starts.

The test bed looked like this:

<cftry>
    <cfscript>
        myThrower = jl.create("com.compoundtheory.test.MyThrower").init();

        myThrower.myThrowIOException();
    </cfscript>
    <cfcatch type="java.io.IOException">
        full
        <cfdump var="#cfcatch#">
    </cfcatch>
    <cfcatch type="java.lang.Exception">
        java.lang.Exception
        <cfdump var="#cfcatch#">
    </cfcatch>
    <cfcatch type="any">
        any
        <cfdump var="#cfcatch#">
    </cfcatch>
</cftry>

In this case, 'full' was output, that meaning that the <cfcatch> was able to the exception with the type 'java.lang.IOException', just as it was meant to do.

The final test was when I moved my created classes into the ColdFusion class path, restarted the server, and ran my tests again.

The test bed now looked like this:

<cftry>
    <cfscript>
        myThrower = createObject("java", "com.compoundtheory.test.MyThrower").init();

        myThrower.myThrow();
    </cfscript>
    <cfcatch type="com.compoundtheory.test.myException">
        full
        <cfdump var="#cfcatch#">
    </cfcatch>
    <cfcatch type="java.lang.Exception">
        java.lang.Exception
        <cfdump var="#cfcatch#">
    </cfcatch>
    <cfcatch type="any">
        any
        <cfdump var="#cfcatch#">
    </cfcatch>
</cftry>

In this case, the output was 'full', that meaning that the <cfcatch> could catch the custom exception, as it had been loaded with the ColdFusion library at start up.

So what does this all mean? Does it mean you can't use libraries with custom exceptions in them? No it does not.  But it does mean you need to handle them in a slightly different way when using JavaLoader.

The solution to this problem is to write code that looks like this:

<cfcatch type="java.lang.Exception">
    <cfswitch expression="#cfcatch.Type#">
    <cfcase value="com.compoundtheory.test.myException">
        <!--- do something with it --->
    </cfcase>
    <cfdefaultcase>
        <cfrethrow>
    </cfdefaultcase>
    </cfswitch>
</cfcatch>

The nice thing is that the 'type' attribute on the cfcatch variable will be set properly to the type of the Java Exception, so we can use it as a sort of 'filter' to weed out the Exceptions we wish to handle, and rethrow the ones that we don't.  It's not the prettiest thing in the world, but it works.

I'm not sure if I classify this as a bug in ColdFusion, but it definitely is an issue if you're not sure how to resolve it.
06 February 2007 01:22 PM 1 Comment

Presenting at cf.Objective!

I'm really excited that I am presenting at cf.Objective this year.  It was a bit of a last minute arrangement, but the tickets are almost all booked, and I'm looking forward to a long journey from my home in Australia all the way to Minneapolis in May.

I'm going to be doing a couple of presentations on Transfer , which is going to be good fun, one of which will cover an introduction to Transfer and ORMs in general, and the other will cover some more 'advanced' Transfer development options.

It's also going to be fantastic to finally put some faces to names of people I've met through the community.  I'm really looking forward to it.

See you all there!
24 January 2007 12:16 PM 8 Comments

Cute tricks with Java Static Fields

This is something interesting I came across the other day, when I wanted to dynamically evaluate a static field on a Java class, and I thought it was a clever trick that was worth sharing.

First of all, what is a 'static field'?  Well here is a really good description of a static variable, but the short version is that it something that is available without an instance of a class.  This is functionality that can't be done in ColdFusion, but it is available in Java, and some other languages.

So if we look at a java.lang.Math we can see it has two static fields, one for pi, 'PI' and one for the value of e, 'E'.

In Java, we would be able to access these simply by going:
INT circumference =  java.lang.Math.PI * diameter;

and if we wanted to do that in ColdFusion, we would have to do:

<cfscript>
    Math = createObject("java", "java.lang.Math");
    circumference = Math.PI * diameter;
</cfscript>

Now, what would we do, if we weren't sure if 'PI' existed on the Math class? In Java we'd have to do some reflection , but in ColdFusion, it is really, really easy:

<cfscript>
    hasPI = StructKeyExists(Math, "PI");
</cfscript>

Yes - you can use Struct functions on the Java class to resolve public variables! Interesting, no?

So now, if we wanted to evaluate 'PI', we now have three options:

<cfscript>
    piOne = Math.PI; //as before
    piTwo = Math["PI"]; //dynamically evaluate
    piThree = StructFind(Math, "PI");
</cfscript>

And all three will result in the same value.

This can be very handy when wanting to allow access to Java static fields on Class, but you don't want to be passing around a Java Object - now you can create a Facade to those Java objects, and ask for them dynamically.

I'm sure someone else can come up with a cleverer way to use this trick, but I found it useful.
21 January 2007 04:55 PM 4 Comments

Transfer 0.6.1 Released

After quite a few bug fixes and performance enhancements, it made sense to do a maintenance release of Transfer ORM before moving on to version 0.7.

The major improvements and bug fixes that you will see in this release are:
  • Documentation updates.
    It was noted that some areas of Transfer were not documented as well as they should.  You will now find a brand new 'Getting Started' section, as well as more details in sections such as Caching and Decorators.
  • The caching layer now allows the underlying Java engine to discard TransferObjects as required.
    This means that as the underlying JVM realises that it is requires more memory, it can discard TransferObjects that aren't being used.  This ensures that Transfer won't be a memory leak.
  • ModelGlue folder deleted.
    You will now find the Model Glue : Unity integration code in the MG:U framework.  For more details on how to integrate MG:U will Transfer, go to:
    http://www.firemoss.com/blog/index.cfm?mode=entry&entry=F2BFB7B2-3048-55C9-4329FCB6EE13BAB3
  • Multiple bug fixes and performance enhancements
    Quite a few bug fixes and performance enhancements, mostly to do with the clone() operation, but a few other things as well.
   
For a full list of changes, you can see the changelog .

Download Transfer 0.6.1

For a peek at the future, the major enhancements lined up for 0.7 are:
  • Soft Deletes
    Be able to specify a field in your configuration XML that denotes if a Object is deleted, and have Transfer mange it automatically for you.
  • Composite Key support
    Quite a few of you have asked for it, now you will get it!
  • Transfer Query Language (TQL)
    Another nice way to simplify doing gateway list() queries and read() operations, with a simplified SQL like syntax that follows the configuration XML file.

If you have any questions or comments there is a mailing list , and a forum             .
20 January 2007 10:17 AM 0 Comments

JavaLoader 0.3 - Oops! Missed the Readme.txt

Ooops! For those of you who were wondering where the readme.txt had gone to in JavaLoader, I accidentally left it off!

I just added it back into the zip file, so if you wanted it, you can re-download it. Sorry about that!

17 January 2007 12:44 PM 3 Comments

Changing the Super Scope in a CFC

I'm starting to get a little bored of my blog, all I seem to be posting is releases and updates for open source stuff that I have written.  So I decided in 2007, I would try and regularly blog all the weird and wacky stuff I just happen to try in my 'test' folder on ColdFusion, and what the results where.  Who knows, we may even learn something along the way.

Today's fun and games came from a weird idea I was having with the Decorator pattern, and I thought to myself: 'I wonder what happens if you set another CFC to the SUPER scope within another CFC'.

It's an interesting idea, I mean, at one end of the spectrum it could possibly allow you to dynamically change inheritance at runtime, which could be interesting, at the other end, it could throw a big fat error.

So I decided to write 3 CFCs: Top, Bottom and Super.

Top.cfc sits at the top of the inheritance hierarchy, and looks like this:

<cfcomponent name="Top">

<cffunction name="dothis" hint="" access="public" returntype="string" output="false">
  <cfreturn "top">
</cffunction>

</cfcomponent>

That 'doThis()' function is going to be our basis for seeing what happens.

Bottom.cfc extends Top.cfc and looks like this:
<cfcomponent name="Bottom" extends="Top">

<cffunction name="SuperDoThis" hint="" access="public" returntype="string" output="false">
   <cfreturn super.doThis()>
</cffunction>

<cffunction name="resetSuper" hint="" access="public" returntype="void" output="false">
    <cfset super = createObject("component", "Super")>
</cffunction>

</cfcomponent>

So now we have 2 ways of calling 'doThis()', be can call bottom.doThis() which will go via the usual inheritance mechanism, and bottom.superDoThis(), which will go via super.doThis()

The method resetSuper() will allow us to place a CFC of type Super in the variables scope under the name super.

Super.cfc simply does this:
<cfcomponent name="Super">

<cffunction name="dothis" hint="" access="public" returntype="string" output="false">
    <cfreturn "super">
</cffunction>

</cfcomponent>

Which allows us to see what happens.

So in out test bed, we have:
<cfscript>
    bottom = createObject("component", "Bottom");
</cfscript>

<cfoutput>
    #bottom.doThis()# : #bottom.superDoThis()#
</cfoutput>

And the output from this is:

top : top

So doThis() returns 'top' and superDoThis() return 'top' as well, which is to be expected, as we haven't done anything to change the inheritance structure.

Now, we add this line to it:
<cfscript>
    bottom.resetSuper();
</cfscript>

Which overwrites super with the Super.cfc , and we run the same test code again, and the results come back with:

top : super

So doThis() returns 'top' but superDoThis() return 'super', meaning that the 'doThis' found in Super.cfc is actually run instead.

This means that ColdFusion must resolve the variable 'super' before it actually looks up the inheritance tree, however, you can't dynamically change the inheritance structure of the CFC at run time, which would have been a cute trick.

So what can you actually do with this? Honestly, I'm not entirely sure, but it's interesting to know that you can.

03 January 2007 08:59 PM 23 Comments

Javaloader Version 0.3 Released

I quietly released version 0.3 of JavaLoader today. I'm not sure if anyone actually noticed. Mind you, I didn't actually tell very many people, so I guess I should proclaim a little.

The main purpose of this release is to give greater control over the ClassPath loading behaviour. There are two new optional arguments on the JavaLoader library

loadColdFusionClassPath - this tells JavaLoader whether or not to load the ColdFusion Java libraries.

By default this is set to false.

This is a change from the previous JavaLoader, as it would load all the libraries associated with ColdFusion by default.

loadedClassPathBias - this tells JavaLoader to use a ClassLoader that searches the JAR libraries it has been passed, before it looks to the parent.

This is true by default.

This is also a change from the previous version of the JavaLoader library, which would automatically load the parent's classes before the JavaLoader classes.

This is particularly useful when ColdFusion classes are required, but you need to overload certain libraries that are loaded with ColdFusion.   

More details can be found in the readme.txt file inside the JavaLoader download .

For questions or comments, feel free to email me , fire off a message to the forum , or file a bug report .

11 December 2006 12:35 PM 2 Comments

Speaking at WebDU

Now my name is officially on the list of speakers , I can happily announce that I am talking at the 2007 WebDU conference in Sydney, Australia .

I'm very excited about this, as this is my first time presenting at a conference, and I think this is going to be lots of fun.

Un-surprisingly, I will be presenting on Developing Applictions with Transfer ORM , so please come down and hear me speak, I think you will find it interesting.

But even if you don't hear me speak, come down to the conference.  I've been in previous years, and it's always a great time.

Hope to see you there! 

 WebDU Banner

 

05 December 2006 03:06 PM 2 Comments

Transfer 0.6 Released

After a bit of time in a release candidate, version 0.6 of Transfer is ready to be released.

There is nothing very exciting to report, other than the fact that release candidate saw some critical fixes , so I'm very happy with the choice to do that, and we will see a release pattern much like that in the future.

See the Release Candidate post and full changelog for the new features found in 0.6.

Transfer 0.6 Download

Next on the road map is:
  • Composite Keys
  • Multiple Configuration files
  • Syntax in *where() methods to utilise cfqueryparam
  • ...and some more stuff

Much thanks to all of those that tested out the Release Candidate, it was very much appreciated!!!

Please remember, there is a mailing list , and a forum , so if you have any feedback, please don't hesitate to send it in. 

01 December 2006 04:37 PM 10 Comments

JavaLoader – The Order in which Libraries are Loaded.

I realised something today, I've been telling something about the JavaLoader that isn't true.

By default, JavaLoader loads the ColdFusion class path as its parent when loading in custom Java libraries.

This means that if JavaLoader can't find a class that you are loading through it via the Jars that you have loaded, it will look to what ColdFusion has loaded to see if it can find it there.

I had always assumed that if you loaded something, say for example, the newer version of log4j with JavaLoader, for the Jars loaded with JavaLoader, they would see the newer version, rather than the older version of log4j with ColdFusion.

This is actually, completely and utterly false. I apologise for all the frustration I probably incurred on people for making this statement.

Reading the Java docs it explicitly says : 'When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself.'

So this means that when looking for log4j - the one in ColdFusion actually takes precedence!

This makes sense in the Java world, as it allows for less confusion from the Java engine to be able to resolve classes - but from a ColdFusion perspective it makes life very difficult as we don't have the ability to modify what is loaded at application startup as we would if we had written a Java application from scratch.

A workaround for this is to pass Java null into the JavaLoader as a second variable like so:

loader = createObject("component", "JavaLoader").init(paths, JavaCast("null", ""));

This will create a JavaLoader that is not set with ColdFusion as the parent.

I am currently working on JavaLoader 0.3, that will make the precedence on the loaded classes that will solve this problem all up, as well as some parameters to avoid loading the ColdFusion classpath altogether, but I thought I would give people a heads up now to avoid frustration down the road.

23 November 2006 05:26 PM 0 Comments

Melbourne Contract Position

This just came across my desk...


 

Contract position in Melbourne for a skilled CFMX developer. A good environment and attractive hourly rates beckon for anyone with a good grasp of OO development using the mach-ii framework. We also use ColdSpring and Transfer to sweeten this mix.

A large, industry-leading application is being built and you will be exposed to plenty of ideas and other talented developers to further your career.

Call or email asap for an immediate start. Longer term contract will follow to the right person.

..and there's plenty of beer.

Contact Richard at either:
03 9694 5414
0419 509 900
richard@nga.net.au


08 November 2006 11:08 AM 4 Comments

Transfer Presentation Recording and Sample Application

If you were unable to attend the Connect presentation yesterday that Brian Rinaldi organized for Transfer ORM, you can watch the recording here .

I haven't uploaded the slides, as I figured that the recording is far more valuable than just the slides by themselves. If you want the slides, let me know, and I'd be happy to post them somewhere for download.

I've also uploaded the sample application that I displayed during the presentation, and that can also be downloaded from here .

I have also updated the SVN version of the tBlog sample application (Much thanks to A J Mercer for doing the work on that) so that it works on v0.6 RC1. It still needs the setup SQL for Oracle, but I'm sure this won't be an issue for most people (anyone want to do that for me?).

All in all, I was very happy with the presentation, but if you have any feedback on it at all - from information presented, to presentation style, please feel free to post it in the comments or send me an email directly .

02 November 2006 03:15 PM 4 Comments

Transfer ORM Breeze Presentation thanks to Brian Rinaldi


Thanks to Brian Rinaldi over as RemoteSynthesis.com , I will be presenting via Breeze on Transfer ORM on November 6th, at 4pm EST.

I'm planning on covering the basics of Object Relational Mappers, why they are around, and what problems they solve in developing applications.

From there we will look at Transfer, how it works, and some sample code.

If you have a chance, please come down and attend.

Full details of the talk, including the Breeze URL can be found here .
31 October 2006 02:13 PM 4 Comments

Transfer 0.6RC1 Released

I'm very pleased to announce the Release Candidate of 0.6 of Transfer ORM for ColdFusion.

Since there has been such a huge leap forward in terms of functionality between 0.5 and 0.6, I decided to run a release candidate for a short while, before releasing a final build of 0.6.

Any and all commentary is welcome on this release, not only bugs, and feature requests , but suggestions on documentation, API, and anywhere else you feel the product could be improved.

(Yes, I know the documentation is quite possibly the ugliest thing you have ever seen ;) hopefully before the full release of 0.6 I can try and convince my graphic designer girlfriend to do some branding for me.... But have you tried to explain an Object Relational Mapper to a graphic designer?)

Transfer 0.6RC1 can be downloaded from here.

Now, on to the fun stuff: What is new in this release, well, pretty much everything I talked about recently and a bit more.

  • Oracle Support.
Yes it is true! You can now use Transfer on Oracle!
  • Lazy Loading.
Good for large, complex domains, compositional elements now have a 'lazy' attribute that can be set to true, e.g.

<object name="User">
...
<onetomany name="Permission" lazy="true">
...
</onetomany>
</object>


This means that the Permission objects won't be loaded until they are requested.
  • Nullable properties on objects.
Now properties on objects can be set to a 'Null' value.  A new 'nullable' property attribute adds two new methods: 'setPropertyNameNull()' and 'getPropertyNameIsNull()' which sets the value of the property to a configurable value that is designated to be NULL - be it an empty string, -123456789 or :::!!NULL!!:::
  • Implemented the ability to 'decorate' TransferObjects, to provide greater customisation possibilities.
If you wish to write your own CFCs to be utilised by Transfer, you can.  For example, if I had:

<object name="User" decorator="mysite.security.User">
...
</object>


When you run getTransfer().get("User", 1); you will get an instance of 'mysite.Security.User' which wraps around the original transfer.com.TransferObject and automagically extends all the public methods of that object.

Very handy if you need a high level of customization to your objects.
  • Now able to turn off internal transaction blocks within Transfer with an optional argument on create(), update(), save() and delete() calls.
Now you are able to make calls such as getTransfer().save(user, false); and it will ignore the internal transactions - meaning you can wrap large commitments to the database in their own <cftransaction> blocks, and not have to worry about conflicts with transactions inside of Transfer.
  • Fixed the misspelling of 'objectDefinitions' in the XSD file. Note: This could cause 'object not found' errors if you are updating from a previous version of Transfer. Make sure you validate against the new schema.
It took up until 0.5 to find this spelling mistake!  If you are using a previous version, make sure your configuration file is validated against the schema (a good idea anyway), to ensure you don't get confused by the change.
  • Cached objects will now automatically synchronise data if a non-cached object is saved and/or deleted.
This was a shortcoming of the previous version, in that you could discard objects from the cache, and you could set them to time out, but if an object that wasn't in cache was committed to the database, and there was a cached object in scope - the changes wouldn't be reflected in the cache.  

Now these changes are synchronised with the cached object, so that the data in cache is not out of sync with the database.
  • clone() method on all generated objects. Clone will syncronise with cached objects on getTransfer().save(), getTransfer().update() and getTransfer().delete() calls.
You can now create a deep clone of any Transfer generated object, which is not stored in the Transfer cache.  

However, as we looked at previously, any change made to the cloned version will be synchronised to the cache if it is committed to the database.

This means you can make changes to an object outside of the scope of the cache, if you need to.
  • Put condition on 'onetomany' and 'manytone', allowing for composition filtered by a condition.
You are now also able to setup conditions on which objects are included when having a structure or array of composite objects.

For example, you may wish to -

<manytomany name="Permission" table="lnkPermission">
    ...
    <collection type="array">
        <condition property="isActive" value="1" />
    </collection>
</manytomany>


This will filter only active permissions.
  • find() function on manytomany and onetomany composition.
A new generated 'find' function, which will return back the index of the object you pass in if the collection is an array, or the key it is stored under, if it is a struct.
  • insert-ignore, insert-refresh, update-ignore, update-refresh attributes on properties.
These new property attributes can tell Transfer not to insert or update these property values when committing to the database.

The refresh properties can tell Transfer to go back to the database after a update or insert and get the value of the property, and update the Transfer generated object.

This is particularly handy for setting objects with database default values, or populating objects with values created from database triggers.
  • listByPropertyMap() and readByPropertyMap() to allow for using multiple property values to do reads and lists of objects.
These two new methods allow for listing and reading objects by a combination of property values, simply by passing in a struct of key-value pairs into the function.

For example -

properties = StructNew();
properties.firstName = 'Mark'
properties.lastName = 'Mandel'

user = getTransfer().readByPropertyMap("User", properties);

  • Columns are aliased with property names on list*() operations.
By default, all list*() operations will apply the property name set in the configuration file as aliases to the columns that are returned from a list query.

A new optional 'useAliases' attribute that allows you to turn off column aliasing if you need to.
  • Transfer.getTransferMetaData(className) so that you are able to get the Transfer meta data on an object.
This meta data was exposed for the Model-Glue:Unity integration, but could be used for a variety of purposes.
  • discardByClassAndKey(className, key), discardByClassAndKeyArray(className, keyArray), discardByClassAndKeyQuery(className, keyQuery, keyColumn).
These methods allow you to discard objects from the cache, if they exist.  This is useful for clustered environments and for batch deletions from the database.
  • XML Schema now contains documentation, so you get help with your code hinting.
The XML schema contains all the help documentation, so in your XML editor you should get the documentation to display along with your code hinting.
  • Update to Transferdoc
Incorporated the newest version of wwwObjectDoc into TransferDoc, which now gives us an ordered list of the methods on an object. (Thanks Aaron!)
  • Bug fixes, refactoring and the like...

Also a big thanks to all those who contributed, helped out, gave me bugs, wrote blog posts, and anything else I can't think of right now, it is all very appreciated.

And if you haven't already, please join the mailing list .

23 October 2006 01:05 PM 0 Comments

Transfer moved to RIAForge

Transfer has been officially moved to RIAForge , at http://transfer.riaforge.org/

Barring a few files that are still left on cfopen.org , everything else is running through RIAForge.  Those old files will remain on cfopen, until the 0.6RC1 release, which should hopefully be sometime this week, at which time I'll shut down the old cfopen.org project.

I love RIAForge, and I'm really excited about it.  I think it's a fantastic boon for the community and I'm glad to be moving Transfer on to there.  

Much thanks to those who helped bring this into being, you guys are great!
23 October 2006 10:08 AM 1 Comment

Transfer tutorial over at RemoteSynthesis

Brian Rinaldi over at RemoteSysthesis.com has written up a short tutorial on Transfer , including details on how he integrated it with the ColdSpring .

It's a really nice introduction into using Transfer, so if you are interested in Transfer, please go over and have a look .

Much thanks, Brian!
15 September 2006 04:23 PM 6 Comments

CFQUERY Results: Is it NULL or is it just an Empty String?

One of the annoying things in CF is that when you query a database, all NULL values in the db actually come back as empty strings.  This means that if you actually store an empty string in the database, you have no way of knowing if it was an empty string, or a NULL value.

I hit this the other day when working on a database column where both an empty string and NULL values where valid data values, and had very different meanings.

That's when the light turned on, and I realized 'duh! CF is Java, so if the DB value is NULL, the Java call will return NULL, which we can check for'.

So, knowing that (a) a cfquery resultset is actually a java.sql.ResultSet, and (b) that a cfoutput / cfloop call only iterates through the result set, I can can run .getString(columnName) on it, and if the value it returns is NULL, it will return a Java null value.

So what I ended up with was the following isNull() function, that works a treat, and can tell when a real NULL value is returned, not just an empty string:

<cfquery datasource="db" name="query">
select * from table
</cfquery>

<cfoutput query="query">
    #columnName# : #isNull(query, "columnName")#
    </br>
</cfoutput>

<cffunction name="isNull" hint="is this null" access="public" returntype="boolean" output="false">
    <cfargument name="query" hint="the current query" type="query" required="Yes">
    <cfargument name="column" hint="Column Name" type="string" required="Yes">
    <cfscript>
        var value = arguments.query.getString(arguments.column);

        if(isDefined("value"))
        {
            return false;
        }

        return true;
    </cfscript>
</cffunction>
13 September 2006 12:53 PM 2 Comments

Transfer Updates and News

Things seem to have heated up in the news for Transfer , which has been fantastic.  Huge thanks to Sean Corfield and Matt Woodard for their write-ups on Transfer, they are greatly appreciated.

The most interesting of news is having Sean on board to write a the ORM Adapter for Model-Glue:Unity , so that Transfer can be used in place of Reactor .  This has actually been very interesting, as I have had very little experience with Model Glue, but with some enhancements and changes to Transfer, Sean got it up and running in what seemed to be relative ease.

The reason I haven't been able to do many posts about Transfer as of late, is because I've been attempting to get code out the door in preparation for the 0.6 release, but I figured with all the good press it has been getting lately, I definitely needed to get off my lazy rear end and put hands to the keyboard.

I have to say - there has been a lot of work done on Transfer, and I'm very happy with the new features that are coming out with the next release.

I won't take you through a full change log, but a teaser of some of the major features that are either already implemented in CVS, or will be soon, that you can look forward to:

  • Oracle Support - Got some small bugs working on this right now.
  • Lazy Loading of Composite Objects - About time too!
  • TransferObject 'Decorators' - No more generic 'TransferObjects' if you don't want them.  Decorate generated objects with real CFC's, and extend their functionality as you want.
  • Tell Transfer to not use transaction blocks, during saves and deletes
  • Nullable property values
  • Refresh and/or ignore property values on insert or update
  • Automatic data syncronisation with cached objects
  • Place conditions on composition elements
  • Heaps of bug fixes

The roadmap has also been set for the 1.0 release, seeing Transfer finally move out of its beta state, which I'm finding very exciting.

If you are at all interested in Transfer, I would suggest getting onto the mailing list , and downloading the source from CVS , and having a play with it.

If you have any questions, or problems, please do post them to the mailing list, or hit me via the meebome widget or don't forget there is now a #transfer channel on Dalnet - I'm there almost every day, and am happy to help.  My IRC handle is [Neurotic], so fire me a message if you hop online.

04 September 2006 10:53 AM 0 Comments

AsyncHTTP 0.2 Released

Thanks to a Stefan (sorry, don't know your last name), and Rob Pilic who sent me emails about AsyncHTTP , there have been a couple of small enhancements / bug fixes made to this library.

The first solved a compatibility issue with CFMX 6.1.  This has been changed, and should mean that AsyncHTTP should now work on 6.1. (Cross Fingers)

The second involved some strange scenarios in which basic data was coming out of queries as strange data types, and was causing Java cast exceptions when doing post() requests.

Now the AsyncHTTP will automatically cast everything in the post formData argument to a String, which resolves this issue, and means there doesn't need to be any external JavaCast() calls on weird data.

That's pretty much it.

If anyone finds any other issues, please feel free to send me an email .   
26 July 2006 05:29 PM 2 Comments

Need New CFUG Melbourne Venue

Unfortunately after years of service, the current venue for the Melbourne ColdFusion user group venue is no longer available to us.

If anyone knows a venue in Melbourne that is happy to have some geeks once a month doing presentations on ColdFusion and other related Adobe technologies, please shoot an email to:

Steve AT cfcentral DOT com DOT au

Or you can contact me directly , and I will pass it onto Steve.

Failing any of that, if you are interested in attending the Melbourne CFUG, please stay tuned to the CFAUSSIE mailing list , as announcements will be made to where we will eventually end up.

Please do note, it is really important we find somewhere.  There are some great presentations lined up for the next few months, including Flex development and ColdFusion / Java integration, and without a venue none of this will happen.

User groups are an important part of what keep ColdFusion alive and strong, so any and all suggestions are more than appreciated.
19 July 2006 10:33 AM 6 Comments

AsyncHTTP - Asynchronous HTTP Requests

I don't know how many times I've gone looking to do asynchronous processing in ColdFusion, and come up against the myriad of hacks, workarounds and that general feeling that I want to poke my eyes out with a rusty spoon.

Now that JavaLoader exists, integrating Java with ColdFusion becomes so ridiculously easy, it would have been relative heresy if I hadn't sat down for an afternoon and wrote a library for making asynchronous HTTP GET and POST requests.

To use the asyncHTTP library , you simply have to drop /asyncHTTP/ the folder in your web root, or create a mapping to it.

From here we create an instance of the AsyncHTTP.cfc:

asyncHTTP = createObject("component", "asyncHTTP.AsyncHTTP").init();

Now that we have an instance of the AsynHTTP CFC, to do an asynchronous GET request, we simply call:

asyncHTTP.get("http://www.site.com/mytemplate.cfm?var=value");

If we want to pass form data across, we can also do an asynchronous POST request, like so:

formData = StructNew();
formData.var = "value";
asyncHTTP.post("http://www.site.com/anothertemplate.cfm", formData);


That is it! It is as simple as that.

Please download the library, give is a spin, and any questions, feedback, bugs or general comments, please either reply to this blog post, or shoot me an email .

03 July 2006 04:20 PM 6 Comments

Primary Key Control with Transfer (Transfer Tutorial Part 2)

Previously we looked at doing basic CRUD operations in Transfer, and I was going to look at some of the composition options that are available, but I decided we would look at primary keys instead first.

Primary keys are an integral part of almost any database driven application, and consequently are an integral part of Transfer as well.

When a Business Object is inserted into the database, a primary key value will need to be supplied, either by the database generating the unique value, or by code generating the unique value.
 
A Business Object will need to know the value of its primary key, so that it knows what record it is representing.

Transfer will handle this process for you, and how it does that is configured through the <id> element that is found within the Transfer configuration file .

There are three different ways that Transfer does this:

Retrieves Database Generated Primary Keys

By default, Transfer will attempt to retrieve numeric keys that are generated by the database.  Understandably, this happens differently for each supported database -
  • Microsoft SQL Server:  Generates Identity value
    Example: <id name="IDPost" type="numeric" />
    This will retrieve the last inserted Identity key that was generated by SQL Server.
  • MySQL: Generates 'auto increment' values
    Example: <id name="IDPost" type="numeric" />
    This will retrieve the last inserted auto increment value that was generated by MySQL
  • PostGreSQL: Generates primary key values through sequences
    Example <id name="IDPost" type="numeric" sequence="post_seq" />
    This will retrieve the last sequence value that was by incremented by PostGres.

Transfer can Generate Primary Keys

Transfer can also generate primary key values for you.  There are three different types of primary keys that it can generate -
  • Numeric
    Example: <id name="IDPost" type="numeric"  generate="true" />
    This will generate a unique numeric value for the table
  • UUID
    Example: <id name="IDPost" type="UUID" generate="true" />
    This will generate a UUID value for the primary key
  • GUID
    Example: <id name="IDPost" type="GUID" generate="true" />
    This will generate a GUID value for the primary key


Manually Override Transfer

Last, but not least, you are able to manually override Transfer's primary key controls to insert a record with a primary key value of your choosing.

A Business Object generated by Transfer will have a set() method for its primary key.  If this value is set before the Object is inserted into the database, Transfer will attempt to insert it using this value.

For example,
<cfscript>
    post = transfer.new("post.Post");
    post.setIDPost("george");

    transfer.save(post);
</cfscript>


This will attempt to insert the Post with the primary key value of "george".

With these three options, you should have all the control you need to manage primary keys within the database.

More details on Transfer can be found here .

23 June 2006 01:49 PM 1 Comment

Transfer Presentation Available for Download

For those of you who were at Melbourne CFUG last night, here are the presentation slides for you to download, along with the example application I showed.

For those of who weren't there, (being asleep and half a world away is no excuse) feel free to have a look at the slide presentations, I hope that you will find them useful.

The presentation went very well, albeit over time, and was well received, so I was quite happy over all.

If anyone is interested in me doing this presentation to a CFUG or related, most likely over Breeze as I am in the rear end of the world, please drop me a line , I'd be delighted.

22 June 2006 10:59 AM 3 Comments

JavaLoader 0.2 Released

Huge changes! Massive Changes! The whole thing has been rewritten!

Okay, I'm lying.  The only thing I changed is that if you pass in a path to a JAR or a directory when you init() the JavaLoader, it will throw an Exception if the path doesn't exist.

This is simply a useful addition for debugging purposes, especially if you are wondering why you can't load a particular class, or you are getting the wrong version of a class, if you are trying to overload a class that is loaded into ColdFusion.

Oh yeah, I added a 'getVersion()' method too.

If you have any questions, comments or bugs, please send me an email or respond to this blog post.
16 June 2006 02:29 PM 2 Comments

Transfer Pet Market Example Application

I just uploaded the example Transfer Pet Market application to cfpetmarket .

Besides changing the data management aspects to utilise Transfer, the application has stayed fairly true to its original form, and should hopefully provide a good example of some of the things that Transfer can do.

Some of the new functionality in 0.5 was a result of the issues I faced while developing the pet market application, so it was a good exercise both in providing an example for Transfer, and also testing out what limits it had.

So please wander over to the cfpetmarket , and have a look, and feel free to leave me any feedback or questions that you may have either here , here or here !
13 June 2006 04:30 PM 0 Comments

Melbourne ColdFusion UserGroup - Presenting Transfer

On the 22nd of June I'll be doing a short presentation on Transfer and it's capabilities at the Melbourne ColdFusion Design and Development User Group.

I'll be covering the basics of what an ORM actually is, what Transfer can do, and be showing a small sample application.

If you are at all interested, I would love it if you would come down and listen.

Details can be seen here.

13 June 2006 12:49 PM 2 Comments

Transfer 0.5 Released - Please come test it out!

It has been over a month since I released 0.4 of Transfer, and there has been a lot of work on Transfer been done to get it ready for 0.5.

First of all, I'd like to extend a big thanks to my current employers, NGA.net , who allowed me to open source the development on Transfer that was required for a current project.  You guys are great.

Second of all, I would just like to say - I've put a lot of time and effort into this release, so I would greatly appreciate it if you could take some time to download and give it a good test and general bash around.  If you want to provide feedback there is a mailing list , a forum , a bug tracker , and a feature request tracker , and failing all that, you can send me an email directly! 

I want to hear your feedback, whether it is good, bad, or otherwise.  One of the initial reasons I started writing open source code was as a learning exercise (one of which I recommend quite highly), so your feedback only helps in that process.

With this release, I have written a cfpetmarket application using Transfer.  All I have yet to do on it is write the readme, and bundle it up, so it should be released in day or two.

There is also the tBlog example application that has been updated to use the new code.

On to more important things however - What's new in this release?

  • Postgresql support

    I've implemented PostGres support, and included setup SQL with the tBlog application for it.  I haven't spent much time with PostGres as a database, so anyone who uses it regularly and wants to test out how Transfer handles on it, please do.

  • The ability to control the caching of objects within Transfer, down to an object and scope level.

    While many people will probably never need this functionality, you can now configure the caching of Objects down to numbers, time, as well as pushing the cache to shared scopes like request, session or application.  Very useful if you have multiple copies of Transfer running in a Application, but you want to share caches.

  • Now getIsPersisted() and getIsDirty() methods on TransferObjects to determine if an object has been persisted in the database and/or had it data modified respectively.

    This was more for internal use within Transfer, but it is handy to be able to see if objects have been modified and/or have been created in the database.
  • If Object have not been modified since their last commitment to the database, the Transfer.update() will not fire events, or run the database update.

    This is useful if you are writing cascading save() calls on composite objects.  You can now safely call save() on an object, knowing that it will only hit the database if the data has been changed.

  • TransferDoc

    First off, thanks to much thanks to Aaron J Lynch for allowing me to use and modify his wwwObjectDoc tool for this.  This is a tool for generating documentation on the Business Objects that Transfer creates for you.  I use this a lot when using Transfer, as I can't remember what property of onetomany relationship has created what.

  • If the primary key has been set before inserting, it overrides Transfer's population/retrieval mechanism, and the object is inserted under the set primary key.

    This is something I came across when I was writing cfpetmarket - I needed to override all the primary key handling of Transfer, and manually set it.  So now, if you use the setter for the Primary Key on a TransferObject, Transfer will try and insert the record with that primary key, rather than try and retrieve it from the database, or try and generate it.

  • Some better handling of database 'null' values being turned into values like dates, GUIDs, numbers etc (Not much really you can do to emulate 'null' however).

    This was a bit of a bug.  Transfer didn't handle NULL values coming out of databases very well.  Now NULL values result in default values.

  • onetomany relationships can now removeParent, and hasParent relationships.
  • manytoone relationships now have has, and remove functions.

    I'll lump these two together.  Now you can have compositions that may or may not have objects in them.  If the object is not set, Transfer will attempt to insert/update NULL values into the relevant foreign keys.

  • Removal of the use of a preparedStatement on Selects, and reverted back to CFQUERY, which is much more performant on memory.

    Originally Transfer used a Java preparedStatement to run its SQL queries.  Looking at this again I realised it wasn't necessary, so I moved it back to cfquery, and found a performance increase.

  • Fixed bug where composite objects more than 2 levels deep would fail

    This was a nasty bug, and has now been fixed.   I wrote some code that made no sense.

  • Fixed bug where composite objects with the same named columns would fail

    This was also a nasty bug, as has also been fixed.
There are a few more bits and pieces behind the scenes - but a full change log can be seen here .

On to new and better things - what can you expect in the next release?

  • Oracle Support

    I wanted to get this out in the last release, but I had a need for the caching controls, so that took precedence.  The hooks are in place to write this code, it just needs to be done and tested.

  • Lazy Loading

    I've been bugged and bugged for this functionality, and I've finally realised that this really needs to be in there.  In some ways I wonder if I went the wrong way by not implementing this in the first place, but my software design is proving to be quite flexible, and I have quite a few ideas how to get this ball rolling.

  • Cascading creates, updates and saves.

    This would be really handy, so I'm going to do it.

There are also a few other bits in the wind.  A full todo list can be seen here .  I am also totally open to ideas, so if you think of anything, please put it in the feature request tracker .

Now that this has been released, I can write up the rest of my blog posts on Transfer, and I also have a CFUG presentation on Transfer coming up which I will make the contents of available for download.

And of course - this website runs on Transfer 0.5 right now.

Transfer 0.5 can be downloaded from here .


12 May 2006 04:20 PM 4 Comments

Running Python on ColdFusion

I have no idea why you would actually do this, but the fact that you can is super cool.

1st we download Jython , the Java implementation of Python

2nd we drop the jython.jar file in the same dir as the below code.

3rd we use the JavaLoader.cfc to load up the jar file. 

4th watch Python run in ColdFusion!

This is a CF translation of the Java embedding tutorial at http://www.jython.org/docs/embedding.html

<cfscript>
    //set he path
    paths = ArrayNew(1);
    paths[1] = expandPath("jython.jar");

    //create the loader
    loader = createObject("component", "JavaLoader").init(paths);

    //create the Python Iterpreter
    interp = loader.create("org.python.util.PythonInterpreter").init();
   
    //set standard output and errors out to the screen
    interp.setOut(getPageContext().getResponse().getOutputStream());
    interp.setErr(getPageContext().getResponse().getOutputStream());
   
    //top line
    writeoutput("Hello, brave new world <br/>");

    //do some python   
    interp.exec("import sys");
    interp.exec("print sys");
   
    pyInt = loader.create("org.python.core.PyInteger").init(42);
   
    interp.set("a", pyInt);
   
    //this now prints out to the screen!
    interp.exec("print a");
    interp.exec("x = 2+2");
   
    //get some values back out of python
    x = interp.get("x");
   
    writeoutput("x: " & x & "<br/>");
   
    writeoutput("Goodbye, cruel world <br/>");
</cfscript>

Okay, so I'm just hyped up about using the JavaLoader to do some weird and neat stuff - but hey, it's really cool, allright!

12 May 2006 02:38 PM 4 Comments

JavaLoader.cfc v0.1 Released (Loading Java from ColdFusion part 2)

Well, I *was* going to go to the gym, but noooo, I got pestered by a bunch of people to actually produce a generic version of my JavaLoader that I talked about in a previous blog post .  You people know who you are, and you should be ashamed.  Ashamed that you forced me to produce more open source code. Shame on you indeed.

Now that I've got all that drivel out, I've released a generic version of the Java Class loader for loading external JAR files.  Be they ones you created, an open source library, or a library you created to work with *another* jar library - all is possible with this tool.

The key features of this CFC are:

  • It can load several libraries at once, thereby allowing linking between Java libraries
  • It allows access to ColdFusion core Java files, as well as the Java libraries that are loading with ColdFusion
  • It utilises the coldfusion.runtime.java.JavaProxy, which enables ColdFusion to do Object constructor arguments as you would normally with createObject("java", "javaObject").init(myArg);, as well as being able to give access to static fields on Java objects that cannot be instantiated.

So, how do we use it? Well, there is an example in the download , but I'll give you a run down here.

Say we have a jar file, 'toolbox.jar', and we went and wrote our own code base and stored that in 'ourcode.jar' that referenced objects in toolbox.jar.

First we need to create an Array with the absolute file paths to each of these in it, so we would go:

paths = ArrayNew(1);
paths[1] = expandPath("toolbox.jar");
paths[2] = expandPath("ourcode.jar");

Then we create our JavaLoader, passing in the array, so it knows what to load -

loader = createObject("component", "JavaLoader").init(paths);

So now, we can create a instance of an object from ourcode.jar, say, for example the 'OurCode' class

If we were to just want to create a default (no arguments) instance of OurCode, we could now go:

ourcode = loader.create("OurCode").init();

Just like we would on a createObject("java", "OurCode").init() call, if we had access to the 'OurCode' class.

But say, for example, OurCode also had the option of taking an int and a String as an argument - we could now go:

ourcode = loader.create("OurCode").init(15, "I love Strings");

Again, same as we would on a createObject("java", "OurCode").init(15, "I love Strings") call, if we had access to the 'OurCode' class.

But what if we wanted to get complicated, I mean, we said that ourcode.jar referenced code in toolbox.jar, so maybe OurCode may want to take a ToolBox class instance as an argument - this is all possible.  We have loaded both JARs into the loader, so we can get to both instances, and we use CF to make the constructor work, like so:

toolbox = loader.create("ToolBox").init();
ourcode = loader.create("OurCode").init(toolbox);
 

Again, same as we would on a createObject("java", "OurCode").init(toolbox) call, if we had access to the 'OurCode', 'ToolBox' classes.

Oh, and I almost forgot, what if we want to access static methods, or values? Still the same thing as createObject - we just don't call an init() on the object we get on the create() call, like so -

Utils = loader.create("Utils");
resultFromStaticMethod = Utils.doThisThing("hello");

Again, same as we would on a createObject("java", "Utils") call, if we had access to the 'Utils' class.

That is actually it, in terms of using the JavaLoader, but this opens up a huge area of development where in theory you could actually write most of your object development in Java, and then just have the display tier in CF (I'm not advocating the idea, but you *could* do it), not to mention you now have access to almost every Java lib out there that doesn't require you to install anything J2EE, like a servlet etc - which is a very powerful thing.

Hope you all enjoy. Any questions or comments, either send me an email , or respond to the blog post. 

Details on the project can be found here.  

10 May 2006 11:28 AM 16 Comments

Running your own Java libraries in ColdFusion with style

I've been doing a ridiculous amount of work recently writing up some Java code that I am looking to deploy with Transfer, and in the process have had all sorts of fun running around exploring the internals of ColdFusion.

The issue however was being able to deploy the code with my library.

(As per usual with these posts, you must note that some of these methods are undocumented and liable to change, yadda ya)

I had my JAR file that I wanted to be able to use with my ColdFusion code, but there were several problems

   1. The Java code referenced some ColdFusion, and other related JAR files that were loaded into CF at startup
   2. Some of my objects I wanted to be able to create via CF have constructors that require arguments, which is tricky business.
   3. ColdFusion likes to keep a 'hold' on any Jar it loads up via URLClassLoader, so being able to redeploy/upgrade the code is tricky, as you can't delete the file without resetting the server.

Okay, so we'll start at the beginning - obviously we have the initial aspect of using a URLClassLoader to load in the external series of .class files, or .jar files, as Spike wrote about back in 2004 . (I'm not going to cover that aspect of it here, there is plenty of examples out now on how to use URLClassLoader out on the blogsphere)

This is all fine and dandy, I load in my class, and I try and create an instance, but it will throw an error - you know why? Because the code in my JAR references Java classes that the URLClassLoader doesn't know about.  Namely ColdFusion classes! So it throws a big fat hairy error as it can't see them.

Now, the neat thing is, a URLClassLoader's constructor can take a java.lang.ClassLoader as it's parent - which means it can look to it to try and resolve classes.  So off we run to get the ClassLoader for the ColdFusion context.

There are about half a dozen different ways of doing this, but I did it this way -

cfClassLoader = getClass().getClassLoader();


getClass() gets the java.lang.Class object of the current page or cfc, which is very handy for us, as we can grab the ClassLoader for the CF context, and thereby resolve classes that are loaded by ColdFusion when it starts up.

So now, when we create our URLClassLoader, we can create it like this:

classLoader = createObject("java", "java.net.URLClassLoader").init(URLs, getClass().getClassLoader());

Where URLs is the array of java.net.URL that we need to tell the URLClassLoader what directories and jar files to load in.

Okay, so that's all well and good, but problem number 2 arises.  URLClassLoader allows us to make calls like:

string = urlclassLoader.loadClass("java.lang.String).getInstance();

To create an instance of a Java object.  Which is all fine and dandy if there is a default constructor, BUT so often Java objects like to take arguments when they are instantiated.

I beat my head against this one for a while, as it is a real pain to try and do this through reflection - and then it dawned on me - ColdFusion has already done the hard work for us, why shouldn't we just take advantage?

So I did some digging around and worked out that when you write:

System = createObject("java", "java.lang.System");

The object 'System' is an instance of the coldfusion java object  'coldfusion.runtime.java.JavaProxy'.  The JavaProxy takes a java.lang.Class as an argument in it's constructor, and then handles all the aspects of interpreting CF calls on Java objects.

So now, when we load up a class we want an instance of in ColdFusion, we do this -

class = getClassLoader().loadClass("myPersonalJavaObject");
       
personalObject = createObject("java", "coldfusion.runtime.java.JavaProxy").init(class);

This gives us access to the object as we would normally through a createObject("java", "className"); call.

So now, as we would normally, if we want to create an instance of the object we can call -

instance = personalObject.init();

Just like we would normally.  But if we have arguments

instance = personalObject.init(myarg1, myarg2);

And ColdFusion will handle the aspect of translating the CF to the Java object for you.

Finally, the issue that, when you've made your URLClassLoader to a JAR file, the system often won't let you delete the file, as it still marks it as being 'under use'.  The way I solved that problem was by using ANT to add a datestamp to the name of my jar flie when it creates it.

This does 2 things:

   1. Gives the file a unique name, so I don't have to worry about deleting the previous JAR, and can do so when the server gets reset, or the garbage collector realises that nobody is using the JAR anymore, and releases it.
   2. Lets me know when looking at the dir where I store my JAR files which file was created first.

Since I know which one was created first - as long as I load the most recent JAR file to the URLClassLoader first, it will be the first one queried for the class files that are being requested, and therefore you can use the objects that you want.

It also means you could also write some nifty code to ignore the previous version by tokenizing the name of the file, but I will leave that aspect up to you.

This code has yet to be committed to the Transfer CVS repository, but assuming it all goes ahead as planned, look in the package transfer.com.util for a JavaClassLoader to see these techniques in action.

I hope that all made sense, and makes life easier for you while you write your own Java code to run alongside ColdFusion.

05 May 2006 02:43 PM 2 Comments

Adding a createTimeSpan() to Dates.. who knew?

Really short 'didn't know you could do that' moment.

Playing around with createTimeSpan() today in a little test bed, and gave this a try and it worked -


<cfscript>
    now = now();
   
    dts = createTimeSpan(0,2,0,0);
   
    then = now + dts;
</cfscript>

<cfoutput>
#TimeFormat(Now(), "HH:mm:ss")# : #TimeFormat(then, "HH:mm:ss")#
</cfoutput>
 

And look at that, that just added 2 hours to the time.

Normally I would have done that with a dateAdd(), but this actually quite quick.

27 April 2006 01:37 PM 4 Comments

Doing CRUD Operations in Transfer (Transfer Tutorial Part 1)

I have been slowly working my way through making a Transfer version of cfpetmarket , which has been a great deal of fun.

What I propose to do with this series of articles is to go through some small cases in the cfpetmarket application, as it will eventually be released, and use it as a base to explain some of the functionality of Transfer.

This may end up being a repeat of some of things I've talked about before with Transfer, but I think some small things have changed, so I'm happy to go over them again.

First off all, we'll need to setup Transfer, which is pretty straight forward.  Simply place the 'transfer' directory in the root of your web directory, or you can make a '/transfer' mapping to the directory if you want to keep it off the web root.

From here, we first need to create two XML files.

The first is where we set what our data source definition is, I like to call mine 'datasource.xml', but realistically you can call it whatever you like.

The datasource.xml for cfpetmarket looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<datasource xsi:noNamespaceSchemaLocation="../transfer/resources/xsd/datasource.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <name>petmarket</name>
  <username></username>
  <password></password>
</datasource>


You will notice there is a reference to a datasource.xsd file.  I use Eclipse as an IDE, and when I create my XML file, I refer it to an xml schema file, in this case datasource.xsd, so I get my context suggestion and xml validation.

This should look pretty straight forward, where the 'name' element is the name of the datasource, and the 'username' and 'password' elements are for optional username and password fields for the ColdFusion datasource.

The second file we create is a 'transfer.xml', this defines each of our Transfer Objects in our application.  Again, it doesn't have to be called 'transfer.xml', but since that's the name of the framework, I figured it was appropriate.

Again, we will reference an XSD file, and in this case it will be the 'transfer.xsd' schema.  Normally we would have several 'object' and 'package' elements, but we'll add them in a little bit, so for now, all we'll worry about is:

<?xml version="1.0" encoding="UTF-8"?>
<transfer xsi:noNamespaceSchemaLocation="../transfer/resources/xsd/transfer.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <objectDefinitions/>
</transfer>


Normally we would have our package and object definitions inside the 'objectDefinitions' element, but we'll take a look at the database first.

We have to create a singleton of the TransferFactory, so we can actually use Transfer.  Singleton is just a fancy shmancy way of saying 'there is only of these in the application'.  The easiest way to do this is to create it in the application scope.  

This is probably the least sophisticated way of handling a singleton, but for the purposes of this article (and in cfpetmarket) it will work well for us.

The TransferFactory takes 3 arguments

  1. The relative path to the datasource.xml file
  2. The relative path to the transfer.xml file
  3. The path from root to where Transfer is going generate it's definition files

The first two are relatively straight forward arguments, the third may not be so.

The way Transfer works is by generating ColdFusion code the first time it is run.  Once that code is generated, it is then run and utilised in generating the Transfer Objects that Transfer creates.  Therefore, Transfer needs to know this directory both so it can generate the required files, and also so that it can find them later on.

An example initialisation would look like this:

application.transferFactory = createObject("component", "transfer.TransferFactory").init("/config/datasource.xml",
"/config/transfer.xml",
"/config/definitions");


In this case, we will be creating the definition files in the '/config/defintions' folder off the web root.  The definitions don't have to be created here, but it seemed like a logical place for the files to go.

Now that we have our TransferFactory up and running, we'll look the database.

In this tutorial, as all we are looking at is Create, Read, Update and Delete (CRUD) operations, we'll only be looking at one table in the database, and there are more coming.

The table we are looking at is the 'category' table.  The category table looks like so:

  categoryoid
int 
PK
displayname varchar
  systemname varchar
  color varchar
  locale varchar
  image varchar

It should be noted that we are dealing with a MS SQLServer database, but it is possible to use other databases with Transfer.

It should also be noted, within the actual cfpetmarket application there is no Identity seed on the 'categoryoid' column, but for the sake of this article, we're going to pretend that there is.

So let's go back to our transfer.xml file, and we're going to create a 'package' inside this definition.  Packages are just like regular packages, in that they are a means to organise all our objects into separate areas for ease of use.

We'll create a 'pets' package for our 'Category' to eventually sit under, as it is a Pet Store Category.

Creating a package looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<transfer xsi:noNamespaceSchemaLocation="../transfer/resources/xsd/transfer.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <objectDefinitions>
      <package name="pets">
    </package>
  </objectDefinitions>
</transfer>


Packages can contain packages, so you are not limited to how many levels you are able to go.

Next we have to define an object, and tell it which table it corresponds to.  We're going to call our object 'Category' and point it to the 'category' table

<?xml version="1.0" encoding="UTF-8"?>
<transfer xsi:noNamespaceSchemaLocation="../transfer/resources/xsd/transfer.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <objectDefinitions>
      <package name="pets">
          <object name="Category" table="category">
          </object>
      </package>
  </objectDefinitions>
</transfer>


Next we're going to tell it which column is the primary key on the table -

<?xml version="1.0" encoding="UTF-8"?>
<transfer xsi:noNamespaceSchemaLocation="../transfer/resources/xsd/transfer.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <objectDefinitions>
      <package name="pets">
          <object name="Category" table="category">
              <id name="categoryoid" type="numeric"/>
          </object>
      </package>
  </objectDefinitions>
</transfer>


You will notice that we haven't specified what the column is in the 'id' element.  There is a 'column' attribute to the 'id' element, however it's default value is the value of the 'name' attribute, and in this case, the value of 'categoryoid' is perfect for the name of the 'id' property.

Next we will look at the properties of the 'Category' objects, and strangely enough, these are pretty much exactly the same format as the 'id' element, except that they are 'property' elements.

<?xml version="1.0" encoding="UTF-8"?>
<transfer xsi:noNamespaceSchemaLocation="../transfer/resources/xsd/transfer.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <objectDefinitions>
      <package name="pets">
          <object name="Category" table="category">
                 <id name="categoryoid" type="numeric"/>
              <property name="displayname" type="string"/>
              <property name="systemname" type="string"/>
              <property name="color" type="string"/>
              <property name="categoryLocale" type="string" column="locale"/>
              <property name="image" type="string"/>          
        </object>
      </package>
  </objectDefinitions>
</transfer>


As you can probably see, each 'property' element corresponds with a column on the 'category' table.  On the last item, we've decided we wanted to have a different property name than the name of the column, so in this case, we've called the property name 'categoryLocale' and the column is set to 'locale'.  The reason for this will become clearer later on.

So now, if we reset our initialisation on the TransferFactory, so that it re-reads our new transfer.xml file, we have ability to create, read, update and delete records on the 'category' table.

So from here, if we want a new 'Category' object, we first have to get an instance of Transfer from the TransferFactory -

<cfset transfer = application.transferFactory.getTransfer()>

And then we request the object

<cfset category = transfer.new("pets.Category")>

It should be noted that the class name is case sensitive. So in this case, looking for a class called 'pets.category' will result in an error.

Now we have an object of type 'transfer.com.TransferObject'.  But if you look at the API for a TransferObject, there isn't much to it that allows you to do much with the Object itself.  That is because Transfer adds the required methods to the TransferObject at run time, so that you can manipulate the object.

So for each property and also for the id, there is a get and set method for each of the names of the property.  i.e. There is now a 'setCategoryOID',  'getCategoryOID', 'setDisplayName', 'getDisplayName', 'setColor', 'getColor' etc methods on the object for us to use.

Now you may also be able to see why we created the property named 'categoryLocale' and mapped it back to the column 'locale'.  The reason for this is that 'setLocale' is a ColdFusion native function, and you cannot create a function with the name 'setLocale', otherwise the system will throw an error. Therefore we had to have a different name for the property other than 'Locale', otherwise there would have been a issue.

So if we want to set some properties of the Category before we insert it into the database, we can use the setter functions on the object, like so:

<cfset category.setCategoryName("Fish")>
<cfset category.setImage("fish.jpg")>
<cfset category.setColor("#fc3e41")>

And so on.

Now, the easy bit comes - inserting it into the database:

<cfset transfer.save(category)>

And that is it.  It has now been inserted into the database, and the 'categoryOID" property on the 'category' object has automatically been set to the ID that the database would have created.

Now if we decide we want to change the image on the category, we can now do:

<cfset category. setImage("fish2.jpg")>
<cfset transfer.save(category)>

And the category has been updated in the database.  The 'save' command intelligently calls the appropriate 'INSERT' or 'UPDATE' command in the database, depending on whether or not the object has been committed to the database yet.

If you want to retrieve the category object from the database, you only need to tell Transfer the class that you want, and the id of the category you wish to retrieve, like so:

<cfset category = transfer.get("pets.Category", 1234)>

Again, note that the class name is case sensitive.

And to finally complete the set, if you want to delete a Category -

<cfset transfer.delete(category)>

And the Category has been deleted from the database.  Nothing more than that.

That pretty much covers all the aspects of getting creates, reads, updates and deletes happening on your database with Transfer.

Don't forget more details on Transfer can be found at the home page, as we've only just scratched the surface, and if this interests you, please feel free to join the mailing list.

Next article we'll start looking at composite objects and how they are handled in Transfer.

12 April 2006 03:39 PM 0 Comments

Transfer version 0.4 Released

Its been a long time in coming, but version 0.4 of Transfer has finally been released.

This version sees Transfer finally get some placed on a CVS repository, and also take advantage of its place in cfopen.org

The main new features for this version are:

  • If an object does not exist from transfer.get(); it now returns an empty object, rather than throwing an exception. This is more in line with other ORMs.
  • readByProperty() and readByWhere() methods added to transfer.com.Transfer to retrieve objects by non-primary Key values.
  • list(), listByProperty() and listByWhere() functions added to transfer.com.Transfer to provide simple listing of table values.
  • property[@column] and id[@column] in the config xml now default to the value of the name, which should result in less typing.
  • Added auto generation of GUID's that conform to MS standards, and are performant for indexing.  XSD updated XSD accordingly.
  • Able to set a 'configure' custom function that is run just after the init() function is run.
  • More documentation on new features
The full changelog can be viewed here .

Transfer can be downloaded from here .

The next version is going to focus on getting support working for several more database types, top priorities being postGres and Oracle.

I also plan on doing a series of tutorial articles on this blog to show how to take advantage of Transfer and all its functionality.

It's been great fun getting my hands dirty in Transfer again, so I hope you enjoy the efforts. 

12 April 2006 09:21 AM 4 Comments

Lyla CAPTCHA: Neat!

Peter J. Farrell has taken my open source CAPTCHA component to the next level -

You should check it out 

It's highly configurable (way more than mine is), and comes with a slew of new features. His documentation is also better than mine.

I'm still going to keep my open source captcha on my site, but if you are looking for something a bit above and beyond what i wrote, definitely check out what Peter has done.

04 April 2006 03:37 PM 6 Comments

Array Index of 0 in ColdFusion

Real short post - but something I discovered doing some work on Transfer.

CF Arrays are java.util.Vectors, which means that you can call myNewArray.get(12) on them to get the object at that index.

I kept getting an error saying 'Array 1 index out of bounds', and I couldn't work out why, when I knew I only had one object in the collection.

The thing I totally forgot was, Java arrays are indexed from 0, and ColdFusion arrays are indexed from 1.

So when doing a 'get()' on a Array, you have to remember to refer to your Array as a 0 indexed array, not a normal one like usual... that is if you are brave enough to mess around with Java trickery ;o)

24 March 2006 06:59 PM 1 Comment

Moving On...

Just for a change, it's been a long time since I've updated my blog - but things have finally slowed down enough for me to find 10 minutes to spare!

I had the final day at my recent job today.  It's been 3 years that I've been at this job, and I've learned a lot there, but now it's time to move on to newer things.  I'm really excited about this position - I'm going to be working with a bunch of like minded people, and going to be developing on a mach-ii platform, which will be a first for me.  I'm actually a little bit sad to be leaving the Oracle database behind, I find it a great platform, but I won't be mourning it too much.

I've left Transfer slide a little, but I haven't let it fall totally by the wayside.  In February I also had my first amateur Mixed Martial Arts bout which I was training very hard for. Unfortunately I lost the fight, but it was a great experience all around.  The training for it tended to take up most of my spare time, so Transfer had to shift to a low priority for a little while.  Now that I've finalised my change in job, and my martial arts training isn't as intense, I hope to get some more work done on Transfer in the near future.

So assuming everything goes to plan, hopefully I'll have some releases out soon (ish?). 

20 January 2006 08:01 AM 43 Comments

Open Source CAPTCHA CFC v0.1 Released

Here is the initial release of my Captcha component .

It is a reworking of the code I use on this site to output my Captcha images, into a nice CFC that has two public methods -

  • captchaToFile(...) - This method writes a Captcha image defined by the arguments passed in to the file you tell it to set.
  • captchaToBinary(...) - This returns binary data that can be used by cfcontent to display the generated image on the fly.

The code here is pretty much 'as is'. The CFC should be relatively self explanatory, but I have provided examples in the zip file on how to use the CFC both ways.

If you have any feedback, feel free to send me an email .

17 January 2006 07:47 PM 0 Comments

Transfer ORM version 0.3 Released

Version 0.3 of Transfer ORM is now ready for download .

New things to look for in this release:

  1. The 'generate' attribute on the ID element - now you have to specify if you want Transfer to generate primary keys for you. Otherwise it defaults to the new ability to retrieve database generated primary keys.
  2. Primary keys are now set to default values.
  3. A new method on the Transfer class - save().  This intelligently will either create, or update the transfer object dependent on its current state.
  4. If you are using Transfer to create your primary keys, you no longer need to create the transfer_sequence table.  Transfer now does this behind the scenes.
  5. All the bugs with UUID primary keys have been fixed.
  6. The transfer.xsd has been fixed up so that attributes that should have been set to 'required' are now.

There are a few more pieces, but they are all outlined in the change log and the documentation .

The tBlog example application has also been updated to use the new functionality, and can be downloaded from here.

Please do not forget that there is a mailing list for Transfer, and any and all feedback is appreciated. 

12 January 2006 10:04 AM 6 Comments

Coldfusion + JPEGCodec + response.getOutputStream() = BAD

Time for me to admit I was wrong...

All the time I've been getting ColdFusion errors stating that the server cannot support any more connections... it wasn't the server, it was some code I had written.

I'm still not sure of the why it caused the problems that it did, but it certainly did.

The issue at hand was my Captcha images that i was generating on the fly.

The idea was I would generate a BufferedImage , draw all my stuff on it,  grab the HttpServletResponse OutputStream from the getPageContext() and then use the com.sun.image.codec.jpeg.JPEGCodec to encode said OutputStream to my captcha.

In theory this should all work like a charm.

Except for one very irritating thing. It doesn't. 

Occasionally when multiple requests go for the JpegEncoder, ColdFusion decides to go totally belly up. Not even in a nice error message way, nope, in a 'Oh my G-d, I've totally dropped my &%$#' way.

It even got to the point where it was dropping out the whole server.

The way I have gotten around it now, is by writing the image to a file, and every so often replacing it with a new Captcha image and text.  It seems to be working very nicely, and with some locking, ensures that it should only get hit one at a time.

So, in the future, I highly recommend not encoding the OutputStream of the HttpServletResponse - write it to a file, and access it that way.

29 November 2005 12:55 AM 0 Comments

Transfer ORM version 0.2 Beta

Version 0.2 of Transfer ORM library is now ready for download and there is a whole lot of new things to look at.

It's well past midnight here, so I'll go into full detail about this in coming days, but some details of what I've been working on with this version:

  1. A new area of the site dedicated specifically to Transfer
  2. A lot more documentation
  3. Installation is now easier, with the 'transfer_sequence' table no longer needing you to define it's data - it is now handled by Transfer.
  4. The ability to define your own CFML functions on a Business Object in the Transfer XML configuration file.
  5. A new mailing list for users of Transfer for the discussion and support of Transfer.
  6. Updated the example application to incorporate these new features, and include the latest features and new functionality.

I've also sent off a application to cfopen , and hopefully when that gets approved, I will be moving the codebase into CVS on there, not to mention it will be nice to have a centralised bug tracker.

However,  I am asking of all the people that downloaded Transfer, or plan to soon (yes, I read my web stats, there were a few of you), is to please, join the mailing list, and then have a good go at testing Transfer for me.

While I had a lot of fun testing Transfer out myself, there are always things the developers never think that someone will do with their software, so I figure there has definitley got to be holes out there for someone to poke in this.

If you have some time, please do test Transfer on supported environments, unsupported environments, and anything else that you feel like, and let me know what happens.

28 November 2005 01:53 PM 17 Comments

Scaling JPEG images with ColdFusion

Helping out on #coldfusion on dalnet, the topic of resizing JPEG images without having to install a external Java lib came up.

There are 2 things that make this slightly tricky, but not all together impossible:

  1. Documentation for com.sun.image.codec.jpeg.JPEGCodec can be very difficult to find if you don't know where you are looking
  2. Scaling a BufferedImage produces a Image, which can't be encoded into JPEG, so you need to create a new BufferedImage with the given Image.

So, here is the code I used as a test case to take an image of a Nissan 350z and scale it down by a quarter:

<cfscript>
    //need this to do all the JPEG work
    JpegCodec = createObject("java", "com.sun.image.codec.jpeg.JPEGCodec");
   
    //reading in file
    inputStream = createObject("java", "java.io.FileInputStream").init(expandPath("nissan.jpg"));
   
    //pushing out the file
    outputStream = createObject("java", "java.io.FileOutputStream").init(expandPath("nissan1.jpg"));
   
    //decodes the JPEG
    decoder = jpegCodec.createJPEGDecoder(inputStream);
   
    //give us an image to scale
    image = decoder.decodeAsBufferedImage();
   
    //make it 1/4 the size
    height = round(image.getHeight() /4);
    width = round(image.getWidth() / 4);
   
    //this is java.awt.image.Image, but we need a java.awt.image.BufferedImage!
    scaledImage = image.getScaledInstance(JavaCast("int", width), JavaCast("int", height), image.SCALE_DEFAULT);
   
    //create a new BufferedImage
    newBufferedImage = createObject("java", "java.awt.image.BufferedImage").init(JavaCast("int", width), JavaCast("int", height), image.TYPE_INT_RGB);
   
    //draw the image on the buffered image
    graphics = newBufferedImage.createGraphics();
    graphics.drawImage(scaledImage, 0, 0, Javacast("null", ""));
   
    //encode it
    encoder = jpegCodec.createJPEGEncoder(outputStream);
    encoder.encode(newBufferedImage);
   
    //close off the resources
    outputStream.close();
</cfscript>

So there you have it - JPEG scaling without using an external Java library. Enjoy. 

15 November 2005 03:15 PM 11 Comments

Transfer ORM and Business Object Factory Library - v0.1

Transfer is a library of CFCs for an idea I had a long time ago, and now I am going to pass it out to you for your feedback, and see if what I have developed is sometime useful that should be further developed.  This is the first time I've ever released anything substantial into the wide space of the Internet, so please bear with me.

The thought for Transfer was that to ultimately cut back on development time, it would be very handy to simply be able to create your database, and a corresponding xml file, and from there your Business Objects could be created, updated and deleted all without the writing of another piece of code as well as being managed in persistant scopes.

This is done through 2 processes -

  1. The business object is manufactured within the library, but unlike a code generator, in which you create your code only once, and the CFCs are defined until you run your code generator again, Transfer works by generating only the udfs that are required by each business object, and decorating a generic TransferObject with the required functions at run time when the particular object is requested.  This allows for easier development as the code generation is completely implicit, you don't need to manually fire it off.
  2. The Transfer Library automatically generates all your SQL for CRUD operations, based upon the details specified in the xml config file.  This includes SQL for composite objects.

To show you how it works, I'll take you through some basic Transfer Object definitions, and then we'll get a little bit more complicated with some composite object creation.

This is taken from the provided tBlog example application that is available for download here.

If we want to have a User in the system, first we will set up a table that has the following details:

Name  Data type
IDUser (PK)
numeric
user_Name
varchar(500)
user_Email
varchar(500)

 

Within our transfer configuration file, we want an object of type 'user.User', and we tell it what table it is from.

<objectDefintions>
   <package name="user">
       <object name="User" table="tbl_User">
          </object>
   </package>
</objectDefintions>

We then define the primary key, which will give us a getIDUser() and setIDUser() on the eventual TransferObject

<objectDefintions>
    <package name="user">
        <object name="User" table="tbl_User">
            <id name="IDUser" column="IDUser" type="numeric"/>
        </object>
    </package>
<objectDefintions>

We then set each of the properties on the 'user.User', in this case, name and email, giving us both get & setName() and get & setEmail() on the user.User TransferObject. Each property has a type, and requires that you specify which column that the property refers to.

<objectDefintions>
    <package name="user">
        <object name="User" table="tbl_User">
            <id name="IDUser" column="IDUser" type="numeric"/>
            <property name="Name" type="string" column="user_Name"/>
            <property name="Email" type="string" column="user_Email"/>
        </object>
    </package>
<objectDefintions>


I won't take you into installing the Transfer library, I'll leave that to the (relatively sparse) documentation and the provided example, but we'll assume that the main class transfer.com.Transfer is available to you.

To retrieve a new empty user.User transfer object, all is required is:

<cfscript>
//get a new user
user = transfer.new("user.User");
</cfscript>

To then create the user as a record in the database, we can now:

<cfscript>
//create the user
user.setName("Mark");
user.setEmail("notanemail@email.com");

transfer.create(user);
</cfscript>

To retrieve a record from the database: 

<cfscript>
//get a user
user = transfer.get("user.User", url.IDUser);
</cfscript>

Update and delete 

<cfscript>
//update a user
user.setName("Fred");
transfer.update(user);

//delete
transfer.delete(user);
</cfscript>

A lot of this is relatively straight forward, however where Transfer really comes into it's own is where it starts handling composite objects.

There are 3 different types of ways in which Transfer can handle different composition of objects, but I will show you one example, so you can get a feel for how it works.

Again, from the tBlog example, we'll look at a Post with Comments (in tBlog, a post has Comments, a User, and multiple Categories, but in this case, we will only worry about Comments).

So first we create a 'post.Post' (I won't show the database table, I figure you have a grasp on how it works), and a 'post.Comment' objects:

<package name="post">
    <object name="Post" table="tbl_Post">
        <id name="IDPost" type="string" column="IDPost"/>
        <property name="Title" type="string" column="post_Title"/>
        <property name="Body" type="string" column="post_Body"/>
        <property name="DateTime" type="date" column="post_DateTime"/>
    </object>
    <object name="Comment" table="tbl_Comment">
        <id name="IDComment" type="numeric" column="IDComment"/>
        <property name="Name" type="string" column="comment_Name"/>
        <property name="Value" type="string" column="comment_Value"/>
        <property name="DateTime" type="date" column="comment_DateTime"/>
    </object>
</package>


This provides us with our basic CRUD operations for the tbl_Comment and tbl_Post, however in the database schema, tbl_Comment has a foreign key, lnkIDPost, that provides a one to many relationship between Post and Comment that we still need to define.

Strangely enough, we do it with an element in <object> called 'onetomany', like so:

<package name="post">
    <object name="Post" table="tbl_Post">
        <id name="IDPost" type="string" column="IDPost"/>
        <property name="Title" type="string" column="post_Title"/>
        <property name="Body" type="string" column="post_Body"/>
        <property name="DateTime" type="date" column="post_DateTime"/>
        <onetomany name="Comment">
            <link to="post.Comment" column="lnkIDPost"/>
            <collection type="array"/>
        </onetomany>
    </object>
    <object name="Comment" table="tbl_Comment">
        <id name="IDComment" type="numeric" column="IDComment"/>
        <property name="Name" type="string" column="comment_Name"/>
        <property name="Value" type="string" column="comment_Value"/>
        <property name="DateTime" type="date" column="comment_DateTime"/>
    </object>
</package>


In this, the name of the onetomany relationship is defined, thus giving us methods like 'addComment()', 'getCommentArray()', 'removeComment()' and a few more on the post.Post TransferObject.  The onetomany element also sets a 'setParentParent()' and 'getParentPost()' method on the Comment itself, for controlling what post the comment is for.

If we want to create a new Comment, and add it to a post, all we need to do now is:

<cfscript>
post = transfer.get("post.Post", url.id);

comment = transfer.new("post.Comment");
comment.setName(form.name);
comment.setValue(form.comment);

comment.setParentPost(post);

//no need to sort, or add to the parent, it is done implicitly.
transfer.create(comment);
</cfscript>

And presto, the comment is created, and has implicitly been added to the Post.

If we were to go through the post.getCommentArray() we would find the new Comment in there. 

You will also note that there is a 'type' attribute of 'array' value on the 'collection' element. This states what sort of collection is going to be created on a post.Post.  The other option is 'struct', in which case you must also set a key to be used.

The advantage of having an array however, means we can control the sorting of the Comments, like so:

    <object name="Post" table="tbl_Post">
        <id name="IDPost" type="string" column="IDPost"/>
        <property name="Title" type="string" column="post_Title"/>
        <property name="Body" type="string" column="post_Body"/>
        <property name="DateTime" type="date" column="post_DateTime"/>
        <onetomany name="Comment">
            <link to="post.Comment" column="lnkIDPost"/>
            <collection type="array">
                <order property="DateTime" order="asc"/>
            </collection>
        </onetomany>
    </object>

This does several things - when a post is first retrieved from the database, all its comments will be sorted by their DateTime of entry, however when a new Comment is added, it is automatically software sorted into the correct order.

Therefore, if during development you have decided that sorting shouldn't be on the DateTime property of a post.Comment, but instead on the Name property, all you would need to do is:

 <order property="Name" order="asc"/>

and it the change ordering would be handled the next time the xml file is read by the library.

There is a lot more to Transfer that I haven't looked at here, but if this has piqued your interest, the following is available for download:

I'll also make available the latest documentation as I write it at:

Which will get updated whenever I have a spare moment. 

If you are going to have a look at what I've written, please do drop me a note, either via the comments below or via my contact form, I would greatly appreciate it.  I've learnt a lot writing this library, so hopefully you can get something out of it as well. 

Please note, this is pretty much Alpha code.  While it does run behind the scenes here, it hasn't had nearly as much testing as is reasonable to run on a mission critical system, so in any way you use it, it is at your own risk.

03 November 2005 05:17 PM 7 Comments

Arrays are passed by value, no by reference, no by value...

One thing that ColdFusion has always done in a relatively odd way was, it tended to pass Structs by reference, and arrays by value.

This seems to be a decision that was made back in the hey-day of the product, and has been continued since then to maintain backwards compatibility.

But I started noting something that I was doing inside my CFCs, that lead me to believe (and realise) that arrays are only passed by value sometimes.

This came to pass when I would often have a getter and a setter method for an array inside a CFC, and would often perform operations on it inside the CFC instance like so:

<cfscript>
 ArrayAppend(getThingArray(), newThing);
</cfscript>


and had never really thought anything about it.

However, if you look at it, if getThingArray() (which returns an array), it shouldn't actually change the state of the object if I call ArrayAppend() on it, as it should have returned the array by value.

That being said, it does change the value, so we can see here in this case, it does return the array by reference, not by value.

Some more investigation reveals that an array is passed by reference only when the array is returned inside a ColdFusion native function, such as ArrayAppend() or ArrayDeleteAt().

This has some interesting consequences for encapsulation that you may need to be aware of, for example, doing:

<cfscript>
 obj = createObject("component", "obj").init();
 array = obj.getArray();
 ArrayAppend(array, "george");
</cfscript>


Will only ever result in the external array being changed, the state of 'obj' will never be altered, however if we:

<cfscript>
 obj = createObject("component", "obj").init();
 arrayAppend(obj.getArray(), "fred");
</cfscript>


This will mean that the state of 'obj' will be changed, and 'fred' will be appended to the array stored inside of 'obj'.

Depending on how strong you want your encapsulation to be, this could be an issue for you.  The same would apply for structs as they are always passed on by reference, however it seems to be a little less obvious when applied to arrays.

This was just something I picked up on the other day and thought I would share it, in case it tripped someone up along the way.

15 September 2005 12:13 PM 3 Comments

Options for deploying CFCs on an Application

I've had several conversations with people on various mailing lists about what is the best way to structure your CFCs so that they:

  1. can be typed via 'return' attributes of cffuncion of 'type' attributes of cfargument
  2. can be set in 'extends' attributes of cfcomponent
  3. are very portable - i.e. it is easy to use com.io.FileReader in one project, and you can pick it up and move it to another without having to do a global find and replace to change com.io to com.domain.io.
  4. are able to be used in different applications across a domain - i.e. if you have one application at /myapp1/ and another at /myapp2/ they can both have a com.myCFC that can be named the same, but do differnet things, and they won't intefere with one another.
  5. are easy to maintain.

Unfortunately, I don't believe that there is currently a BEST option out there to cater to all of these things, but I'm going to go through all the options I have found, and describe the pros and cons of each, and you can make your own decisions (For those of you who are on CFCDev, I'll be taking a lot of stuff out of what I wrote there).

Use a CF Mapping
In a lot of cases this can end up being the best option.  It solves all your issues with typing (1, 2), however it does not make the code very portable, in that you may not ever have access to the cfadmin to create the mapping, and/or if the mapping needs to change, you have to edit your code to work with that, so you cannot simply just drag and drop. 

To work around that problem, you could either (a) use the ServiceFactory to check if the mapping already exists, and if not create it in the appropriate place and/or (b) create a mapping that looks like "/com/mynamespace/mystuff/" that will nicely translate into a path like 'com.mynamespace.mystuff'.  The advantages of (a) is that you can make a entry point to your CFC lib (most likely a Factory) setup the mapping as necessary, and therefore you don't need to go to the cfadmin, however, obviously it is a undocumented feature.  The advantages of (b) is that you are almost totally guaranteed that someone hasn't already used that namespace (much like packaged in Java).

The cons of cfmapping (and the ServiceFactory workaround above) have to do with code portability and using the same CFCs across a domain (3,4).  Since a mapping is server wide, if the applications have differing code, it's going to get very messy. You will end up having to set a unique mapping for that application, and therefore break all your return, extends and type attributes in your CFCs.

This would work very well for application specific code, but not code that you wanted to port from one place to another, such as a product or framework (I shudder at the thought of having different versions of framework on the same server that used a mapping...).

 

 

Put all your CFCs in one directory
Placing all your CFCs under a single directory solves most of the above problems, particularly the one with applications spread across a domain (4) and since all the CFCs can see each other typing is not a concern.  The major issues here (I feel it's major) has to do with what happens when you start looking at systems with large amounts of CFCs.  Having anywhere above 20 CFCs in one directory is going to start to get very hard to work with, and could cause some maintenance frustrations in the long run. 

One of the nice things about packages is that they can be relatively self documenting, assuming they are named well, and can help break down an application into manageable 'chunks'.

This would be useful if you have a small amount of CFCs and/or having multiple CFCs across domains with the same name, but different functionality (4) is of utmost importance.

Use relative '/' rather than '.'
I can remember when I first found out about this technique - I thought it was going to be the absolute best thing ever.  However, like all the rest it has its drawbacks.  It handles issues of typing quite well (1,2), but does mean that you can end up with some very odd package design, and more often than not, most of your main CFCs in the same directory anyway. It is very portable (3), but only within a given OS, as '/' must be used on *nix, and '\' must be used on Windows, which pretty much defeats the purpose of portability.  Otherwise you have no problems with multiple apps across a domain (4) as all the mappings are relative.

This would be most useful when you know you aren't going to change OS, and being able to use code across a domain is very important.  This couldn't be used for product development simply because of the OS issue (and it's an undocumented feature).

Don't use typing
This essentially boils down to not using inheritance (because you have to hard code it), and all type and return values are either 'any' or 'web-inf.cftags.component'.  One could argue that since CF won't check things until runtime anyway, this won't make any in terms of how errors are fired on the system. 

To help bring back some sort of typing (1,2) you could do some sort of testing to ensure that a CFC is the CFC you require (via getMetaData), or that it has the given method you wish to call.  This can cause further overhead, especially considering that getMetaData is known to be pretty expensive.  It will also take a little bit longer to develop as you have to write the extra code.

However - this code is very portable (3), and can be used across domains easily (4), but you do lose a lot of the self documentation that typing gives you, and could leave you wondering which CFC you were meant to pass in as an argument.

If you were writing a product to be used it a variety of places, this may be an appropriate place to use this method, but for application specific code, it is probably overkill.

Store them in a directory in the root of your domain
This seems to be the most 'rounded' of solutions for placing your CFCs.  If you notice, Mach-ii, model-glue, Tartan etc all require you to include their install files in a directory in the root of your domain, and since we figure the people who wrote this stuff are a *little* bit clever ;o) so we can assume that there is a reason for this.

This solves issues with typing and portability (1,2,3) and is obviously easy to maintain (4).  The issue comes from where you have multiple applications running across a domain (quite possibly a relatively low percentage of apps?) with different versions of CFCs required on them.

If application /app1/ is running v0.8 of their framework, and /app2/ is using v0.9 and they BOTH have to have their CFCs in the root of the domain - you are either going to run into a mess, or you will need to test app1 all over again to make sure nothing breaks with the new version.

This seems to be the best option for when you are developing a product (particularly frameworks) as it is the most portable version, and it is very unlikely you will not have access to the root of the domain.  If you use this for application specific code is probably dependent on what is being developed on that server.

Of course there is nothing to stop you from chopping and changing different aspects of these approaches into whatever happens to work for you.

I think I managed to cover all the approaches that are possible - but if you have some other way, please let me (us?) know.

07 July 2005 11:10 AM 0 Comments

Coldfusion Bundled with Jakarta Commons Collection

I was requiring a synchronized First in First Out (FIFO) Queue, to store some CFCs for reuse, and I was doing some digging around to see if there was anything already implemented, or if my best bet was to go for just using a synchronized linked list for the Java Collections Framework.

So I did some reasearch, and asked on AJUG, and came across the Jakarta Commons Collection library.

I already knew that ColdFusion had quite a few org.apache libs sitting underneath it (xalan, log4j, axis etc), so I figured I would do some checking and see if the Collections where also there, and strangely enough, they were!

There is a whole lot of very useful collections in here, including Bags, Buffers, MultiMaps, PriorityQueues... all sorts of stuff.

So if you are looking for a collection that you can't seem to find in the regular ol' Java, I suggest checking out the Commons Collection - you should be able to find what you are looking for.

29 June 2005 06:13 PM 3 Comments

CFC Method Injection: Tips of the Trade

I've been playing more with CFC and method injection, and started writing up a CFC to handle it intelligently for me.

After some playing around, I thought it might be nice to document the things I have found about doing method injection, including some very interesting behaviour.

First things first - a UDF is actually it's own class in it's own right, completely seperate from the CFC defintion. It's more like the CFC is simply linked to the UDFs that it is told to, rather than it actually being a solid container. This explains what happens when you type:

<cfoutput>#obj.myMethod#</cfoutput>

rather than

<cfoutput>#obj.myMethod()#</cfoutput>

and you get all that weird stuff like 'cfindex2ecfm1512334719$funcMYMETHOD@1b1dd12'. This is just the output of the toString() function on the UDF itself. It seems to be the generated class name.

So if you do some reflection on the UDF class (udfName.getClass() works just fine), you find that there is a getMetaData() function - so depending on your preference:
myUDF.getMetaData() or getMetaData(myUDF) works - and returns a struct with everything you could ever ask for:

  • name
  • hint
  • access
  • returntype
  • output
  • An array of parameters

This is rather useful if you want to maintain the name of aUDF from one place to another.

Now... method injection in and of itself is very simple:

1) myCFC["methodName"] = myUDF;

Presto, you have created a new public UDF on a CFC.

You can also do the same thing inside a CFC by either doing (but each will make it work differently):

2) this["methodName"] = myUDF;

3) variables["methodName"] = myUDF;

But some things to note:
If you add an access="public" or access="private" UDF directly to a CFC (method 1 or 2), the UDF will be PUBLIC.

BUT, if you add a UDF to the variables struct inside a UDF (method 3), regardless of whether or not it's an access="public" or "private" or "package", it will be a PRIVATE UDF. (How to get it to the variables scope, I will leave up to you ;o) )

The real clincher here however, is that if you add a access="package" UDF directly to a CFC (method 1 or 2), then it will only be accessible from the folder the CFC is in. So obviously there is some runtime checking there that determines if it is being called from inside its own package.

That is pretty much the basics of method injection - hope you find that helpful.

Prototype Based Programming with CFCs

A while ago, I posted an example of creating CFC definitions on the fly using a function I wrote called StructToBean().

It essentially used the concepts of Prototype Based programming to implement the getter and setter methods on a blank CFC, so that the data of the Struct was encapsulated in an object without having to actually write the object itself.

I put that post on here while I was writing a library that was an attempt to cut down on the amount of time I spent writing simple Beans for use as Business Objects.

The basics of the library was such that I had a XML config file that defined each of the Beans that I wanted to be able to use in the system, like so (cut down version):

<compoundObjects>
<package name="Address">
<object name="Street">
<property name="number" type="numeric" />
<property name="name" type="string" />
</object>
</package>
</compoundObjects>


The library would then create a .cfm file on the fly, which would contain all the UDFs required to add the required getters and setters to the blank CFC.

When the specified Bean was called for, the library would create a blank CFC, and insert each of the methods onto the blank CFC at runtime, so it was ready to use.

As personal projects tend to do, this idea fell by the wayside for a while, and now I've been rebuilding compoundtheory, it's come back to me, and I've started to question whether or not it's really something I want to get behind in terms of how I build my CF applications. I'm still pretty much sitting on the fence as to whether or not I'm actually going to rewrite the code (it needs a good refactor), and utilise it in the new version of CT.

While CFCs aren't exactly prototype based, the basic flexibility of being able to utilise slots in the CFC to add and remove methods remains the same, but the question that I am wondering at the moment, is should it be used.

On one side there are alot of interesting things you can do with method injection and removal:

  1. Adding Object functionality on the fly
  2. Create Interfaces on the fly
  3. Faking Base class functionality
  4. Changing protection on methods due on the fly (i.e. remove a init() constructor once it has been called once)
  5. Fix bugs on the fly

But obviously there are cons as well:

  1. Adds a whole level of complexity to an application that is harder to document
  2. Breaks some core OO concepts (which may not be a bad thing, but you have to be happy about it)
  3. Can lead to some awefully spagettied code if not managed correctly

Now, obviously, whether or not you leverage this capability is very dependent on applicaiton requirements, your own personal views on OO Analysis and Design etc, but the usage of this functionality does exist, yet seems to be a topic that is not talked about much in the CF community.

So I ask you guys, as an information gathering excercise:

  1. Have you considered taking a Prototype based approach before?
  2. If you had, did you do it?
  3. If you did, what was it, and why did you do it? (I would love to hear of some places it was used!)
  4. If you didn't, why not?
  5. Would/wouldn't you consider using this approach for something in the future?

That being said, in the next few weeks (as I continue to develop the next version of CT), I'll do a follow up post on whether or not I decided to utilise the prototype based approach to developing the Business Objects for this site, and why I decided to do it, and hopefully this will get some interesting discussion going!

Some more reading on Prototype Based Programming

03 June 2005 08:57 AM 0 Comments

Interesting Caller scope situation...

Hit this one the other day, and thought it was rather cute, because I hadn't even thought of it - even though it makes sense.

If you do a cfmodule call inside a CFC, the caller scope refers to the CFC itself.

This kinda took me aback, because I'm so used to calling a cfmodule from another cfm page, that it was an immediate assumption the caller would be a cfm page.

But if you think about it - the caller scope, just refers to the place that calls the cfmodule - so really it makes alot of sense.

(That and if you look at the underlying code structure, you can see that a cfm page and cfc both extend the same base class, so it's not totally weird).

Just thought it was cute, so I would share.

02 April 2005 01:57 AM 9 Comments

Relative CFC Typing and Extending (CFC WTF Part 2)

So I had my big winge about CFCs being able to create other CFCs relatively, but not being able to extend or use return or cfargument types relatively, and how it totally messes up code being truly reusable.

So I'm chatting to Spike about this issue, and he's looking at my post, and he casually remarks to me: 'Well, why don't you try '\' rather than '.'?  See what happens".

I of course thought to myself, no way is that going to work.. I mean, it's just silly. It doesn't even look like a real class name definition.

Well I'll be damned (and several other loud expletives I echoed at the time), it freakin' works. And to top it off, it works relatively. Spike came up with the good once again.

So to make myself clear through all this muddle - you are perfectly able to:

  • createObject("component", "com\level\Cat")
    - i.e. create Dog.cfc in the folder com\level folder relative to where you are calling it.
  • <cfargument name="Cat" type="com\level\Cat" required="true">
     - i.e The type of the argument is of the Cat.cfc up in the com\level folder relative to the CFC this is in.
  • <cffunction name="getDog" access="private" returntype="com\Dog" output="false">
    - i.e The return type of the function is of the Dog.cfc up in the com\ folder relative to the CFC this is in.
  • <cfcomponent name="Dog" extends="level\extend\Extend">
    - i.e. extend the component Extend.cfc in the relative directory of level\extend to the CFC this is in.

This is really big thing as it means that you can relatively go down a folder tree with your inheritence and typing with CFCs. You can't actually go back up (least I haven't found a way), but you can go down it.  This means, you have much more ability to write really portable code - as long as you are relatively careful (no pun intended) about how you structure your packages.

for example - if I have a directory structure of:

  • \webapp\a.cfc
  • \webapp\one\b.cfc

i can now make a extend b without going back to root and/or a mapping via:
<cfcomponent name="a" extends="one\b">

As well as do similar things with type and return values on cfargument and cffunction.

Here you can download my relative pathing testbed so you can test it out for yourself, and see all the possibilities.

Quite frankly, this has opened up a whole lot of interesting things in terms of how I want to structure my code, and whether or not a cfmapping is even required when doing CFC development.

No cfmapping - how cool is that?

31 March 2005 10:35 AM 21 Comments

CFC typing WTF..... ???

Okay - a bit of a rant... and this has probably been shown before, but this definatley threw me when I saw it..

1st off. I hate having to use a CF mapping when using CFCs. Totally defeats the purpose of portable/reusable code in my mind.

I've been playing alot with trying to keep my code non-mapping required. It's been taking it's toll, but I'm sorta-kinda getting there.

So with that in mind, I started a recent project with all my CFCs in one directory, so they could see each other, with the idea of refactoring into packages last, once I was happy with how it was working.

So I start refactoring, and I run into this fantastic doozie.

Example is:

Directory structure
/webapp/index.cfm
/webapp/Test.cfc
/webapp/com/dog.cfc

Code
--- dog.cfc ---
<cfcomponent name="dog">
</cfcomponent>
-----------------

--- Test.cfc ---
<cfcomponent name="Test">

<cffunction name="init" hint="Constructor" access="public" returntype="Test" output="false">
<cfscript>
var dog = createObject("component", "com.Dog");
setDog(dog);

return this;
</cfscript>
</cffunction>

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

</cfcomponent>
----------------------

 

--- index.cfm ---
<cfscript>
createObject("component", "Test").init();
</cfscript>

--------------------

Problem
So, basically, what happens is: You create a new 'Test', it creats a new 'com.Dog', and then when you go to set it via the setDog(), it tells you:

The argument DOG passed to function setdog() is not of type com.dog.

WTF? Your telling me, that you can work out in relation to the Test.cfc enough information to create a 'com.Dog', but you can't work out the same thing for typing on a cfargument???? Why bother giving us the one, if you can't give us the other?

I just wish that Coldfusion had a way that was either designated, or programtically determ a single root directory for all your CFCs to reside. Much like a J2EE app has /WEB-INF/classes for .class files to reside. That way you COULD have packages much like you can in Java, and not have to worry about portability issues with cfmappings.
(I also wish for the ability to jar up a series of CFCs and import them as a library, again like J2EE... but I think that is asking too much)

As it stands, I think I will experiment with having all my CFCs in one directory, and see what issues arise. It's not an ideal soultion by a long stretch, but it allows me to develop without mappings for now.

-- end rant

26 March 2005 07:22 PM 6 Comments

Using a java.io.BufferedReader in ColdFusion

So I'm parsing through some response text I get from a CFHTTP I'm firing off, and I figure - the easiest way to parse through this thing, is actually going through it line by line.

There are a variety of ways I could have done this particular endevour, but I figured I build myself up a java.io.BufferedReader that I would pass my String into (via a java.io.StringReader), and I could loop around the thing till my heart was content.

Only issue is this - the only way to tell if the BufferedReader is done, is that it returns null from it's readLine() method.

Doh. CF doesn't handle null values all that well.

So I figure - maybe it will return an empty string? Who knows. I'll set it up like I would in Java and see what will happen.

1st round starts like this:

stringReader = createObject("java", "java.io.StringReader").init(response);
bufferedReader = createObject("java", "java.io.BufferedReader").init(stringReader);
while(Len(line = bufferedReader().getLine()))
{
  //do stuff
}


Which unfortunatley doesn't work too well - as CF won't handle the evaluation inside parenthesis, and thinks the = is my mistake for 'eq'. So we switch over to a do ... while loop instead, and get:

do
{
   line = bufferedReader.readLine();
} while(Len(line));


Which works - except it returns back an error: 'line is not defined'.

Which I realise (but fail to understand) is that when Java returned the null value out of the method, it actually removes the line variable from the scope of the method! Woah!

So in the end, this is what I end up with, and it works a treat:

stringReader = createObject("java", "java.io.StringReader").init(response);
bufferedReader = createObject("java", "java.io.BufferedReader").init(stringReader);

do
{
   line = bufferedReader.readLine();
   lineCheck = isDefined("line");
   if(lineCheck)
   {
      //do stuff
   }
} while(lineCheck);


This works perfectly, and now I can use by StringBuffer Happily!

17 March 2005 10:43 AM 0 Comments

Mike Nimer's CF Log Plugin

Yet another reminder I should get off my lazy butt and do some CF/Eclipse work -

Mike Nimer decided to build himself a CFlog viewer and it's pretty neat too.

To copy and paste - it's features include:

  • Supports the ColdFusion log format.
  • Supports multiple Log Folders
  • Keeps a live connection to the log file open, so you can see errors as they happen. Without reloading the log file.
  • Highlights all .cfm files in error message, so you can easily find the bad template.

Nice work Mike!

24 February 2005 01:36 PM 2 Comments

Tim Buntel at Melbourne CFUG

Last night we had Tim Buntel at the Melbourne CFUG for a presentation on ColdFusion MX 7.

I must admit, apon seeing what I had seen on MX7, I walked in thinking I was going to see some neat gadgets, and pretty much walk out of there thinking 'yeah, it's cool... but I could live without it'.

Ultimatley, I was really wrong.  This stuff is cool, and the new stuff could really speed up my productivity. (XML forms for me please!).

So I want to extend a big thank you to Tim for opening my eyes - and it was a pleasure to actually have a good conversation with you this time, as aposed to seeing you from across a conference hall.

Also - Thanks for the pointer to the J2EE Promises white paper. That is definatly going to come in handy in the near future.

07 February 2005 10:54 AM 1 Comment

ColdFusion MX 7 Released

This is probably a repeat of alot of people - but just noticed on MM:

ColdFusion MX 7!!!!

>insert big band music here<

Neato!

27 January 2005 03:41 PM 9 Comments

Best SQL approach for populating composite Business Objects

Well, I didn't get much response out of CFCDev, so I figured I would move the discussion over to my blog.
(So applogies to all this sounds really familiar to)

I always wonder what the best way is to get the results from a database when dealing with composite Business Objects.

Reading Matt Woordards blog post on DAOs and Composition,

He talks about composition, and to quote:
--
We're using composition in our beans, so why not use composition of
sorts (this isn't strictly composition, but bear with me ...) in our
DAO as well? When we instantiate the Person DAO, why not just
instantiate an Address DAO inside the Person DAO so we can call things
that way?
--

Now, in my mind - there are two options for getting the PersonBO information and the AddressBO information.

1) Seperate SQL queries for both BO's - The Address DAO gets the results for a Address, and the PersonDAO gets the results for the
Person BO - there are 2 query hits on the db.
Pros: It's clean, consise and really reusable
Cons: For complex objects, that's alot of database hits - is that a good idea?

2) JOIN between tables - a Gateway object (maybe?) gets a joined result by getting the relevent data form both the Person Table and the
Address Table, and the DAO's intelligently create the BO's that they need from that single query's results
Pros: It's alot more efficient than the above
Cons: It doesn't exactly promote code reuses
It also can get tircky as JOIN can cause duplicate data to display, and you have to avoid creating the same BO twice or more (unless you want to join up data usion UNION or something similar).

Personally I've been running with option (2) for a while, simply from a database performance perspective - but it does leave me with alot of pretty ugly code.  Which makes me lean more these days towards options (1)

But sometimes I write BO's that can be composite of greater than 20 objects (and yes, all are required), so querying the database will 20 small hits I think would take a longer time.

So, which way around do you do it? and why?

20 December 2004 01:43 PM 0 Comments

Crazy Fun with CFCs and Functions: StructToBean()

This totally defeats all purposes of OO encapsulation, and a variety of other principles, but it was a fun time to play around with.

Basically, i wanted to see if I could turn a Struct into a Bean object on the fly. Strangely enough, it was pretty simple considering the flexibility you have with functions and CFCs.

The code works out like follows:

<cfscript>
 //helper functions
 function identityHashCode(object)
 {
  var system = createObject("java", "java.lang.System");
  return system.identityHashCode(arguments.object);
 }

 function setInstance(instance)
 {
  variables.instance = arguments.instance;
 }
</cfscript>

<cffunction name="structToObject" hint="Converts a structure to a object with getters and setters" access="public" returntype="WEB-INF.cftags.component" output="false">
 <cfargument name="inputStruct" hint="Struct to convert" type="struct" required="Yes">

 <cfscript>
  var obj = createObject("component", "WEB-INF.cftags.component");
  var lKeys = StructKeyList(arguments.inputStruct);
  var hash = identityHashCode(arguments.inputStruct);
  var key = "";  var path = GetDirectoryFromPath(CGI.PATH_TRANSLATED);
  var nl = chr(10) & chr(13);
  var buffer = createObject("java", "java.lang.StringBuffer").init("<cfscript>#nl#");

  //move variable scope to inside the CFC
  obj.setInstance = setInstance;
  obj.setInstance(arguments.inputStruct);
  StructDelete(obj, "setInstance");
 </cfscript>

 <cfloop list="#lKeys#" index="key">
  <!--- write out the function to get and set --->
  <cfscript>
   buffer.append("function get#key#() { return instance.#key#; }#nl#");
   buffer.append("function set#key#(#key#) { instance.#key# = arguments.#key#; }#nl#");
  </cfscript>
 </cfloop>
 <cfscript>
  buffer.append("</cfscript>");
 </cfscript>
 
 <!--- make the file - use the hash to ensure uniqueness --->
 <cffile action="write" file="#path##hash#.functions" output="#buffer.toString()#">
 <!--- import the file --->
 <cfinclude template="#hash#.functions"> 
 <!--- delete the file --->  
 <cffile action="delete" file="#path##hash#.functions">
 
 <!---  add it to the object --->
 <cfloop list="#lKeys#" index="key">
  <cfscript>
   obj["get#key#"] = variables["get#key#"];
   obj["set#key#"] = variables["set#key#"];
  </cfscript>
 </cfloop>  
 <cfreturn obj>

</cffunction>

To test this out:

<!--- test code --->

<cfscript>
myStruct = StructNew();
myStruct.fred = "Fred";

obj = structToObject(myStruct);
</cfscript>

<cfoutput>
#obj.getFred()#
<hr>

<cfscript>
obj.setFred("blue");
</cfscript>

#obj.getFred()#
</cfoutput>



Essentially this function:,

  1. Creates a basic CFC (WEB-INF.cftags.component is the base CFC for all CFCs),
  2. Adds the 'setInstance()' function to the CFC, and sets the Struct to the instance data of the CFC with it,
  3. Removes 'setInstance()' function from the CFC,
  4. The function loops through the Struct Keys,
  5. It writes a series of getter and setter functions to an external file,
  6. Imports in the file, placing these functions into the variables scope,
  7. Deletes the file (cleanup!)
  8. Adds all these functions to the CFC,
  9. Returns the CFC.

And look at that, we have created a CFC at run time! Totally defeats some core OO concepts, but it was interesting to note that you can do it.

15 November 2004 09:54 AM 0 Comments

CFEclipse 1.1.17 Released!

The new CFEclipse has been released - with some awesome new features: Ehanced CFC Browser, Bracket Highlighting, Text drag and drop, cold folding, and a whole slew of bug fixes!

More details can be seen at here

Thanks for your work guys!

10 November 2004 05:01 PM 6 Comments

ColdFusion Identity Hash Code

I'm doing some CF R&D (basically I have a little free time, and I was thinking about playing with some things) - and I needed a hash code that would be specific to an object- more often than not a complex object like a Struct or Array.

After a bit of experimentation I found that most of the complex structures that are utilsed in CF (Vectors and Hashtables) return either 0 or 1 as a hashCode(), which is not all that useful.

I finally came along to java.lang.System.identityHashCode() which gives you a specific number that is unique to that object. It is important to note that if the object changes (i.e. you append a value to the array for example) the value of identityHashCode stays the same.

So if you were to compare two identiyHashCodes from different objects, if they were the same, you know them to be exactly the same object.

So of course, i came up with a little UDF for this:

EDIT :::: made a small mistake when I first wrote this UDF as I was walking out the door... fixing it now.

function identityHashCode(object)
{
var system = createObject("java", "java.lang.System");
return system.identityHashCode(arguments.object);
}

Nothing very exciting in the UDF, but an interesting piece of code never the less, if you are trying to muck around with some of the inner workings of Objects in CF.

30 August 2004 03:14 PM 12 Comments

My favourite Java shortcuts for ColdFusion

I just wanted to list some of my favourite Java shortcuts that I like to use when using ColdFusion

java.lang.String.length() - Yes I could do this with Len() from cf, but typing myString.length()seems to be so much easier and faster for me.

java.lang.String.getBytes() - a useful way of working out how many bytes in a string. This can be interesting to use to check approximatley how much memory you are using when storing long strings in a shared scope.

java.lang.reflect.Array - The man when it comes to dealing with Java native arrays.

java.util.Date.before() and .after() - Yes, I can use dateCompare, but I simply find if(myDateOne.after(myDateTwo)) {..} so much easier to read (and all CF date objects are Java date objects).

java.util.Vector.addAll() - Since all CF arrays are vector, this is a easy way of adding an entire array into another without having to manually enter every single item. i.e.

<cfscript>
a = arrayNew(1);
a[1] = "1";
a[2] = "2";
a[3] = "3";

b = ArrayNew(1);

b.addAll(a);
</cfscript>


I think that's all the ones I usually use at the moment - what other Java snippets do you use to save yourself time?

27 August 2004 11:54 AM 7 Comments

CFMX 6.1 Updater Bug - duplicate() and CFINVOKE

Totally kicking myself over this one...

Found a bug in the new updater for CFMX 6.1 (ColdFusion Server Developer 6,1,0,83762 ).
Try the following code:

Hello.cfc

<cfcomponent>

<cffunction name="hello" access="public" returntype="string" output="false">
<cfreturn "hello">
</cffunction>

</cfcomponent>

Test.cfm

<cfscript>
obj = createObject("component", "hello");

dObj = duplicate(obj);
</cfscript>

<cfinvoke component="#dObj#" method="hello" returnvariable="hello">

Error Returned:

The <b>component</b> attribute in <b>cfinvoke</b> tag has invalid value.

The <b>component</b> attribute can either be a string (component name) or a component object

This did not occur prior to the updater being put into place.

Unless there is now a new way to dynamic method invocation, this could provide some real issues.

I have another bug that I have yet to track down that seems to be linked to a similar duplicate issue and inheritence, but I have yet to track that one down fully.

I couldn't find anywhere to submit this as a bug to MM, but I know the guys there read this, so I'm sure one of them will pick it up.

 

What framework do you use?

Frameworks have been a hot topic of discussion around my peers at work of late, and I was wondering what sort of frameworks the wider community was using.

Personally I tend to utilise a custom/personal framework that I have slowly developed over the past few years.  I've tended to shy away from using something standard such as Fusebox or Mach II, not because they are bad products (I've honestly never looked at them properly to give a good evaluation) but simply because (a) I like knowing how the internals of my system work and (b) I find framework development really interesting (and often the most interesting part of application development).

That being said, if I'm doing Java development, I'll tend to use something like Struts or the like, simply because I find I need something like that to get work done in J2EE (being it is rather low level).  That may also just be because I've not had a huge chance to get my hands deep down into the bowels of what really makes J2EE tick, and therefore haven't had the time to make up something of my own.

So, do you use a custom framework? if so, why so? or have you started developing with something like Fusebox or Mach II, and if so, why so?

Mysteries of Business Object

I found these two really nice articles on Business Objects on Java Boutique yesterday, and thought I would share them, considering my previous post on using OO with ColdFusion.

  1. The Mysteries of Business Object - Part 1
  2. The Mysteries of Business Object - Part 2

Business Objects tend to find their way into almost every type of application development that utilises an OO approach, so understanding the concept (and you may already be doing it without knowing it) is a pretty good idea.

The second article goes through a example application, and goes through alot of the considerations to be made when utilising business objects in an application.

Obviously the articles are Java related, but due to the general nature of Business Objects, as well as the myriad of frameworks that support BO's under Java, it tends to stick to pretty vendor non-specific details, so is a good read for ColdFusion developers as well.

OOP and the Evolution of ColdFusion

I hear alot of arguments (particularly of late on the CFAUSSIE mailing list) about ColdFusion and Object Oriented Programming.

It seems that almost even the most tangential conversation that could possibly relate to OOP, degenerates into pointless bickering about how OOP is good, bad or ugly when combined with CF.  It's verging on rediculous.

The facts remain as such - Object Oriented programming has been THE software development paradigm for more years than I have been alive.  There is a REASON why we don't code in procedural code anymore, and a REASON why Object Oriented programming has come into almost every aspect of software development.

Looking solely at Macromedia related products.  CF was procedural, and then came along CFC's.  Flash was... well, Flash... and now you can define classes in Actionscript. Blackstone will further enhance CFC's with Event gateways and the like.

The truth of matter is - the Future for Coldfusion IS OO. You can like it, you can hate it, but quite frankly, if you develop with CF, Object Oriented programming is here to stay, and there is nothing you or anyone else can do about it.  All it's every going to do is infiltrate more and more of the CF development community, as the years go by, and the support for it in future ColdFusion versions grows.

Yet again, I implore you - if you want to develop your software development abilities with ColdFusion go and drop into a Java course.  Not only will it give you the theory you need to stay with the time in ColdFusion, but it also provides you with the ability to combine CF with it's sister language, and give you capabilities with this language you never had before.

Can that really be a bad thing?

27 July 2004 11:15 AM 0 Comments

Unofficial Blackstone Beta Application - Oh Yeah!

Via Ben Forta

An unofficial beta application has been posted at http://www.surveymonkey.com/s.asp?u=1282566342.

Quite frankly I don't care if it's 'official' or not, I'll take any chance to get onto the beta! :o)

Can't wait for BlackStone!

23 July 2004 12:35 PM 7 Comments

Fixing &'s in the URL with getPageContext().forward()

This is a bug that I've been getting on here for a while, and I've been meaning to fix it. Strangely enough today is the day!

The issue comes when either an older browser, or a badly implemented RSS reader picks up my links.

Since both my webpage is and my RSS feed is XML (XHTML), I will turn a link that looks like /?action=displayPost&ID=99 into one that looks like /?action=displayPost&amp;ID=25, as '&' is not a valid XML element.

This is normally no issue, but sometimes I do get requests that still retain the &amp; within the URL, as it hasn't been translated back to the normal ampersand.

My original thought was to fix the issue with a <cflocation>, however I didn't feel that would be seamless enough, and if there was form data going through, that wouldn't work either.

So I used getPageContext().forward() to forward on the request, after I fixed it by replacing all '&amp;' with '&' in the url query string, and because the forward() method simply pushes the java HttpServletRequest and HttpServletResponse objects through to the new request, everything is totally seamless. Form data gets passed through, and the user won't even see a URL change in their browser.

Here is the code below - I have it in a custom tag called 'fixAmp.cfm' that gets called in my Application.cfm

<cfparam name="request.fixAmp" type="boolean" default="false">

<cfif (NOT request.fixAmp) AND (findNoCase("&amp;", cgi.query_string ) gt 0)>

<cfscript>
request.fixAmp = true;
queryString = replace(cgi.query_string, "&amp;", "&", "all");
getPageContext().forward(cgi.script_Name & "?" & queryString);
</cfscript>

<cfabort>

<cfelse>

<cfscript>
//just for cleanup
StructDelete(request, "fixAmp");
</cfscript>

</cfif>

The reason I have the request.fixAmp flag in there is because on some servers, if you forward the request, the CGI data will stay the same. Hence the tag will go into a infinite loop as it never think's it's fixed the ampersand.

And presto, you never have to worry about issues with useing &amp; in your links again!

 

23 July 2004 11:10 AM 3 Comments

New CFEclipse (1.1.15) - Good Stuff, But a Bit Buggy

Opened up my Eclipse, and got notified that there is now a 1.1.15 version of CFEclipse! (I should have known this anyway as I'm on the mailing list, but looks like I missed that one! Ooops!).

Looks good!  Some new features are sweet - particularly that you can now sort CFC methods to alphabetical and back again, in the CFC methods viewer.

The new snippet preview is nice, and the snippet trigger is good - however it is a tad buggy so be careful.

  1. You can't use a trigger that is only a single character - so don't even try. no 'c' or 'f' or 'g'. It has to be at least 2 characters.
  2. When changing your snippet triggers, they may not show up as changed when you look at it again - this is because the plugin doesn't actually delete the old trigger, so it will still be able to be used.  So I suggest choosing wisely before setting your triggers. (That being said, you can manually change triggers via the \eclipse\workspace\.metadata\.plugins\com.rohanclan.cfml\keyCombos.properties file, it's pretty easy, and takes effect straight away)
  3. Supposedly you need a whitespace character before your trigger, otherwise when you hit CTRL+I, it won't work.  I haven't seen this one happen, but keep an eye out for it.

Overall, however, the upgrade is nice, provides some good bug fixes, and these bugs can be worked around.

Oh yeah - and despite the controversy, they are still using my Icon ;o) (Although I'm sure someone will come up with something better eventually).

Enjoy :o)

20 July 2004 11:09 AM 0 Comments

Moving ColdFusion from Windows to Unix

Just moved the development of an app from Windows to a J2EE instance on a Unix server, and quite frankly, not nearly as hard as I thought it was going to be.

Took a little while longer than expected as they had also set up .htm and .js as ColdFusion extensions, and that threw a few bits and pieces out of whack.

Obviously hit the CaSe sEnSItIVitY Issue, but with a few global find and replaces, that soon went away.  That and I also tend to stick to a pretty standard naming convention, so it didn't bite me as hard as it could.

Filepaths got me a little, as Windows will take c:\mydir\/thisplace/file.txt or c:\mydir\\images\image.txt etc as a valid path, whereas Unix only likes the / operator.  But that didn't take long to fix either.

So, all in all migration, pretty easy! :o)

15 July 2004 04:46 PM 7 Comments

ColdFusion Booleans are Short Circuit Booleans

I was never entirely sure as to whether or not ColdFusion booleans where short circuit or not.

(If you are not sure what a short circuit boolean is - check out this article)

I got a tad bored, so I decided to run some tests to see what was what, and lookee here, CF uses short circuit booleans.

I have a feeling in 6.0, this wasn't always the case, but in 6.1 it is definatley the case.

Pretty simple testbed - 2 funtions:

<cffunction name="ftrue">
 <cftrace text="true" inline="true"> 
 <cfreturn true>
</cffunction>

and

<cffunction name="ffalse">
 <cftrace text="false" inline="true"> 
 <cfreturn false>
</cffunction>

and so I ran some tests, and these are the results i came out with (somewhat stripped):

true & false
[CFTRACE] - true 
[CFTRACE] - false 
--------------------------------------------------------------------------------
false & true
[CFTRACE] - false 
--------------------------------------------------------------------------------
true & true
[CFTRACE] - true 
[CFTRACE] - true 
--------------------------------------------------------------------------------
false and false
[CFTRACE] - false 
--------------------------------------------------------------------------------
true or false
[CFTRACE] - true 
--------------------------------------------------------------------------------
false or true
[CFTRACE] - false 
[CFTRACE] - true 
--------------------------------------------------------------------------------
true or true
[CFTRACE] - true 
--------------------------------------------------------------------------------
false or false
[CFTRACE] - false 
[CFTRACE] - false 
--------------------------------------------------------------------------------
(true or false) and true
[CFTRACE] - true 
[CFTRACE] - true 
--------------------------------------------------------------------------------
(false and true) and false
[CFTRACE] - false 

So what does this mean?  Well, for starters - you can do things like this:

if(isDefined("x"))
{
 if(x eq 1)
 {
  x = x + 1;
 }
}

can become

if(isDefined("x") AND (x eq 1))
{
 x = x + 1
}

Without any fear of error, because if the isDefined() fails, the short curcuit doesn't have to check the right hand side, as false and true will always equal false, no matter what.

It's an interesting thing to note when doing your boolean logic, and should open up some interesting ways of making some algorithms just a tad bit faster.

 

14 July 2004 10:54 AM 6 Comments

Making Persistant CFCs Thread Safe

I get bit by the multithreading bug on a regular basis.  This site has had it's fair share (and I think I've managed to remove them all out by now).

Generally I find that multithreading bugs mostly occur when you store CFCs in shared persistant scopes, such as application or server.

So as a rule of thumb to make sure you don't get bit by the dreaded multithreaded bug, here are my tips and tricks:

  1. Use CFMX 6.1. It is possible to do persitatant CFCs with 6.0, but it's really not consistant in it's applications.
  2. var all your local variables within CFC methods.  This is my NUMBER 1 cause of multithreading issues, I forget this all the time.
  3. Use the arguments scope when referring to arguments passed through in the CFC method. (This would be my number 2).
  4. var all your local variables within CFC methods.  This is SO important, I'm going to write it twice.
  5. Refer to instance variables by some sort of scope, beit directly through the variables scope, or if you use an instance struct of some kind, use that.
  6. Use appropriate locking to ensure that data corruption doesn't occur.  As far as I am aware, CF arrays are not thread safe, so write appropriate locking when dealing with them. I find named locks do the job nicely.

    EDIT :::: Actually, I retract this statement.  I did some investigating, and the Java array extends java.util.Vector, which IS thread safe.  To quote from the relevent javadocs "As of the Java 2 platform v1.2, this class has been retrofitted to implement List, so that it becomes a part of Java's collection framework. Unlike the new collection implementations, Vector is synchronized.". I had originally thought that the ColdFusion array extended java.util.ArrayList, which is NOT thread safe, and requires itself to be constructed through java.utils.Collections.synchronizedList() to be thread safe. My bad.

  7. Write an error handler that sends you emails when an error occurs.  Just because you don't see it, doesn't mean it doesn't exist, and multithreaded errors tend to be a sneaky little bunch.  I have a tendency to use a modified version of the DumpVar udf from Cflib that outputs strings with a XMLFormat() on them, and then dump out the error, CGI and Form structs to the email.
  8. Use some sort of stress tool (I've been using the MS Web Application Stress tool) and catch any and all the emails that come out of your above error handler. Fix these bugs. Rinse and Repeat.

That's pretty much it.  That should make your CFCs thread safe.

It seems really simple, but I get caught with it so often (damn being used to declarative programming languages!) I figured I would write up a post.

Let me know if you have any other tips and tricks that help you stave off the dreaded multithreading demon.

08 July 2004 02:34 PM 4 Comments

Second Impression on CFEclipse and Eclipse

I thought I would do a second impression on eclipse and cfeclipse, simply because I've been using it for the last few days, and have really had a chance to get into it.

Quite frankly, I love it.

The new verison (1.1.13) has just come in, with some great bug fixes, and it is so nice to use.

Things I love about cfeclipse:

  1. Snips - These things totally rock my world. The fact you can code in user variables, and have default values such as $${MONTH} and $${CURRENTFILE} provided for you, make things SO easy.  Before I started using these, I missed all the Homesite tag editors, just because of the speed.  Now I just make a small snip with custom elements, and presto, it's pretty much the same. (Keyboard shortcuts for snippets are coming, which is good).
  2. CF Outline view and CFC Method view.  I've been dying for these for a while.  I'm so used to them in Java IDE's, it's great to have them here too.
  3. I do all my editing in a single IDE. I love that, it saves me so much time.
  4. The fact that CFEclipse is has a strong, driven development team.  I love the fact that I can go 'you know, it would be nice if you had void on the code completion for cffuntion', and look, it's there in this release.  Failing that, I'll go write it myself (as soon as I get some time to play with eclipse plugins).

Things I don't like about cfeclipse.

  1. The new icon. I totally understand why you changed it, but UGH! It aint pretty.

Things I use with cfeclipse (half covered with last post)

  1. CSSEditor - works fine with 3.0, hit ctrl+space, and you have some css completion. Perfect for what I need.
  2. JSEditor - The guy who made this has dissapeared, but it's neat, and has code completion too.
  3. XMLBuddy - The free version of this is really good, and I'm seriously contemplating buying a pro version for XSL work. (I can't find a decent XSL editor for Eclipse that is free.)

My contributions

  1. A new icon for CFEclipse. (Right click and save as). Pop it in "/eclipse/plugins/com.rohanclan.cfm{version}\icons\obj16\", and you have a nice pretty blue document.  I had to do this, because I really didn't like the icon.
  2. Comment Header Snip - I used the old comment header extension for Homesite+ alot, so I made a snip that emulated it.  Here you go.  Drop this in your snips directory, and you can use it as you see fit.

There we go. Download Eclipse. Install CFEclipse. Have some fun.

Go on. Do it.

Do it. </bad Starsky and Hutch Reference>

 

05 July 2004 11:51 AM 4 Comments

First impressions of Eclipse and CFEclipse

Well, I've got some UTF-8 Coldfusion development I am working on, so I was forced to ditch Homesite+, and find an editor that I could use that would support Unicode.

There was no way I was going across to Dreamweaver (heh), so I figured it was about time to check out Eclipse and CFEclipse.

I also generally liked the idea of not having to shift between IDEs as I work - no more flitting from Homesite to Topstyle to XmlSpy... etc etc. It would all be contained within the one IDE and it would be wonderful.

Well at least that was the idea.

I grabbed a copy of Eclipse 3.0, primarily (a) because CFEclipse only runs on 3.0 and (b) I love having new things.  The install ran fine, after I moved past a small JRE issue that some Oracle software had pushed via a only JRE 1.3 lying around after my machine without too much trouble.

Then I hit my first issue.  Tigris.org is all in Japanese for me, except for some english.  That made getting cfeclipse a tad tricky.  No idea why it is. Sent the website a email today, so I'll let you know when I get a reply.

Managed to get it down, and installed it - no issue. Sweet.  Open up eclipse, create a new project, yup all looks good.

Find some small issue with CFeclipse, nothing major, but I wanted to report it, or see if it was going to be fixed. (I'm running verison 1.1.9 beta)... oh yeah, can't do that because the site is in Japanese. Sod.  Well I'll subscribe to the mailing list... yeah... can't find it because my Japanese isn't so good.

EDIT ::: Looks like all my winging produced some effects! I can now see the site in English.  That's brilliant, now I'm going to sign up.

Fired off an email to CFAussie, and got subscribed to the mailing list. Going to post up some bugs soon, hopefully I won't be stepping on anyone's toes because I can't find/read the bug tracker.

So now I need a CSS editor... awesome, plugin "CSS Eclipse Plugin" into google, and got the csseditor plugin for eclipse. Allright. Load that in.. and.... now I have some basic CSS validation. It's no topstyle (lite?) but it does the trick... that's cool, it's open source, and it's free, and my css is decent enough (although a colour picker would have been nice.  Maybe I can find a plugin for that in Eclipse).

EDIT ::: I discovered the documentation for the css editor, and of course you can hit 'ctrl + space' and it will get some content assistance - so all in all, a pretty good editor!

So I go hunting a XML editor too, because I do a fair bit of XML work. I found x-men, looks great! nope.. doesn't work with 3.0.. I end up going with XMLbuddy, which looks good, but unless I buy the pro version, isn't going to do all of what I want.

So overall, I'm doing okay - I've started developing with Eclipse, and I'm loving the CFC method view and Outline view of CFEclipse, it's something I've been dying for for ages. So that stuff does rock.

Eclipse and it's range of plugins so far seem to be good but not great.  This is probably a gripe coming from soneone who is used to really mature commercial software, and so there is that bias.  So factoring in what you can get for free out of eclipse it is pretty darn good.  However, to that point, I found the support of 3.0 to be quite lacking by alot of the plugins out there.

So I do want to say that Eclipse (and said plugins) are really good products considering the relative time they have been around, and the fact that they are developed as open source, free products.

I'm going to complete this project with Eclipse before I decide it's a keeper or not, but if you develop with ColdFusion and you don't want to user Dreamweaver, and you are afraid Homesite is going to be a dead end, I highly suggest that you give Eclipse a go.  That and the ability to really extend your IDE yourself is a very powerful feature.

Just bring a monkey wrench in case things go wrong ;o)

30 June 2004 05:17 PM 4 Comments

Connecting CFMX Pro to Oracle

This has been convered in a few places, but people ask this alot, so I figured I would drop my version of the answer somewhere that may be a little easier to find. I've done this a few times here and there.

There are a variety of ways that you can connect Oracle, but most of them provide limited functionality.

JDBC Thin driver

Details can be seen here:
ColdFusion Technote
CFGuru Blog (Yup, that comment at the bottom is me).

Pros - This is by far the most lightweight installation to get Oracle connected with CFMX.

Cons - You cannot get Result Sets to return from Stored Procedures using this driver. (There may be other stored proc issues I may not be aware of, but I hit this one and gave up.)

Oracle ODBC Driver

Pros - You have the full functionality of Oracle (i.e you can get result sets out of stored procs).

Cons - It's a longer and slightly more tricky install process as you have to install the Oracle Client.

Personally, I like the ODBC version the best, simply because getting result sets out of Stored Procs is of high priority to me.

The steps for installing the ODBC version are the following:

  1. Download the Oracle Client (It's big. Be Warned.)
  2. Download the Oracle ODBC driver.
  3. Install the ODBC Client (create an 'Oracle Home' in any dir. Default should be fine).
  4. Install the ODBC drivers (You may have to do this with the Oracle Universal Installer, which comes with the Client).
  5. Open Oracle - oraHome > Configuration and Migration Tools > Net Manager
  6. Click Service Naming in the tree.
  7. Click Edit > Create from the menu at the top. You will get a new window.
  8. Enter the Net Service Name. I tend to use the same name as the Oracle SID/Service Name. Click Next
  9. Leave at TCP/IP and click Next.
  10. Enter the Host Name of the Oracle server (i.e. oracle.mysite.com), and the port number. The default Oracle port is displayed. Click Next.
  11. Enter the SID/Service name of the Oracle database you are connecting to. Leave as Database Default for connection type. Click Next.
  12. Click Test to test the Oracle connection. First test will probably fail, as it will have the wrong login details. Enter the right details and try again.
  13. Once the connection works, click Finish.
  14. Exit the Net Manager and click Save on the dialog.
  15. Goto Control Panel > Administrative Tools > Data Sources.
  16. Click System DSN.
  17. Click Add.
  18. Choose Oracle in OraHomeand click Finish. (Why finish? you're not done!)
  19. Enter the name in DataSource Name. Doesn't really matter what. I tend to stick to the SID / Service Name.
  20. Choose your TNS Service Name from the drop down provided.
  21. Test the connection. The first test will probably fail, as the username and password will be wrong. Enter the correct details until it works.
  22. Click OK.
  23. Now go into the CF Administrator > Data Sources
  24. Add a ODBC Socket datasource.
  25. Choose the Oracle ODBC DSN from the drop down.
  26. Click Show Advanced Settings and enter the username and password (if required).
  27. Click Submit.
  28. The datasource should now validate (if it doesn't, try restarting the machine, as sometimes a restart is required for the new odbc connection to take full effect).

I don't think I've missed anything. Like I said, it's a tad long and convoluted, but it does work in a production environment.

Once it's set up once, adding a new datasource is a 5 minute job.

I hope that solves someone's problem, because it took me a few weeks to work that one out.

 

If you are going to use OOP, study an OOP language

This is something that tends to get my goat a little in some instances, so I apologise if I get a tad ranty.

We had a recent discussion on cfaussie about the this scope in CFCs, and whether or not it was an appropriate place to store data. Regardless of what the outcome of that conversation (and we all have varying opinions on the topic), there was one thing that became very prevelent to me:

There seems to be a bunch of people out there trying to write OOP code, without a full understanding of OOP concepts.

Unfortunatley I think that this is one of the pitfalls of CF - because it is so easy to write code, people can often think that they can just 'work it out on the fly' and they will be just fine.

Sometimes this is true - and sometimes it isn't. I know quite a few proficient coders that have come to many of OO's basic concepts through trial and error, but I don't think it is the most efficient way of doing things.

The simple fact of the matter is - OO concepts have been around for many years, so why would you try and guess them when you can find them out by studying a OOP language?

If you want to do OOP Programming with ColdFusion, go and study an OOP Language, and bring the theory of it back to ColdFusion.

I cannot possibly encourage this enough. Doesn't matter if it's Java, C++, Eiffel, SmallTalk, whatever. What you are looking for is the concepts and theories.

Basic software design concepts and terms such as:

  • Coupling
  • Cohesion
  • Encapsulation
  • Inheritence
  • Polymorphism

I feel should be understood before really useful OOP Coldfusion code can be developed.

By undertaking some Object Oriented training of some kind, I can assure you that many pieces of software design will make so much more sense to you, and will become a far greater ColdFusion coder because of it.

I just want to make clear here as well - I am NOT saying that if you don't understand these terms or concepts, you are a bad coder, or that you write bad software. Far from it. People have different backgrounds, and different skills and come at things in different ways. So I apologise if I have offended anyone.

I just want to make sure that all of us that talk about software (and web development is software development) use the language, terms and vocabulary that have been around for many years.

 

22 June 2004 02:18 PM 2 Comments

Will we ever get an API for ColdFusion's Java Code?

This was one question I was hitting myself for not asking after the recent MXDU in Sydney.

Point: ColdFusion sits on top of a J2EE engine

Point: This is very neat, because it means we have the power of Java at our hands to do low level work we would not otherwise be able to do in CF.

Point: Any time you want to do Java code that integrates with already existing ColdFusion code, there is a whole lot of guesswork and introspection into undocumented features of CF so that we can leverage it's power in ways that we need. (i.e like my post on attempting to add a HttpSessionBindingListener to a CF Session).

Question: Why doesn't CF ship with Javadoc API documentation of the Java classes it is built on? It would make all of our lives a helleva lot easier.

It's not like I'm asking for CF to become open source (which I don't even want), but simply make available the information we can already get through Java Reflection in an easy to use format.

I recently unzipped the cfusion.war archive from the J2EE deployment and made it so I could compile a copy in my Jave IDE (which was a tad trickier than it seemed).  I did this so I could compile some servlets against the already existing codebase, and make sure there were no conflicts.  Admitedly I also did it so that I could grasp a much finer notion of the underpinnings of what ColdFusion really is, and get to put my hands in as many of its internals as I could.  For those of you who do Java/J2EE work as well, I would say try this out, it gives you a whole slew of new ideas in terms of extending ColdFusion.

There is a small part of me (and for the record, I am in no way advocating this) that is tempted to take a decompiler to the codebase of CF, just to see what makes it tick.  Just to be clear on this point - I am quite aware this would be quite illegal, and I have not done so.  That being said, the only reason I would do so, is simply so that I can understand CF at a much lower level, and simply become a better ColdFusion Programmer.  The purpose of this discussion is not for whether or not decompilation is ethically/legally good or bad.

So to end on a positive note - while this does sound like a gripe at heart, really I'm just asking for something that in some ways already exists, and I think would be a very large resource for all the developers who work with ColdFusion today.  It would mean we would all stop grasping at things we think are there in the code base, and can concentrate on really building on what we know is there.

So in case any MM guys happen to read this - Can we have it?

21 June 2004 04:12 PM 2 Comments

J2EE Sessions and OnSessionEnd (HttpSessionBindingListener)

Here I was thinking I was really clever - but I guess I'm not as clever as I had thought.

I wanted to create a way for CF'ers to have a way to determine when a Session had ended - I could do it in J2EE, so I could do it in CF? Right? CF just sits on top of Java, so it should be easy.

So I created a Java class that implemented the HttpSessionBindingListener interface and set it up to call a series of URLs when a session was either timed out, or the user logged off.

I turned on 'Use J2EE Session Variables' within the cfadmin app and wrote the below CF test code:

<cfscript>
 obj = createObject("Java", "com.compoundtheory.URLCallOnSessionUnbind").init();
 
 session.obj = obj;
 
 StructDelete(session, "obj");
</cfscript>

Using this and subsequent test code, I found that neither valuBound() or  valueUnBound() was called on the my Java object.

This led me to believe that CF only implements a mechanism for sharing data between J2EE sessions and itself, and does not actually utilise the actual J2EE session objects themselves.

Apon further examination (thanks to getJavaMetaData), I discovered that the CF session object doesn't even come close to the javax.servlet.http.HttpSession interface, so there was no way this was going to work in the first place.  (It is in face a coldusion.runtime.j2eeSessionScope object).

It's a pity that this hasn't worked, it would have been very handy - and I know how long CF'ers have wanted the capability to know when sessions had ended.

So I guess in conclusion - we now all know, that when it says in the CF admin 'Use J2EE session variables' - it's really not telling the entire truth.

Naughty Naughty. ;o)

Just for fun these guys over at IBM talk about some ways of sharing J2EE and CF session information.  An interesting read never the less.

16 June 2004 12:09 PM 10 Comments

I don't believe URLs anymore

Had an interesting problem float past me the other day, that had me thinking a little outside the CF square.

Situation: We have an existing HTML website, and we are moving it to a CF website.

Problem: We don't want to break any of our existing HTML links. I.e. if you we have http://www.mysite.com/page.html it should stay the same - so no sneaky .cfm extensions.

Interesting Point: It's a standalone CF Instance running on a J2EE server. Hmnnn...

So the obvious starting point is to map the CF Servlet to *.html - much like you could already do within a IIS configuration, nothing all that interesting there.

Obviously there is now some new CF magick, that allows for the pulling in of content (basically through a single CF Custom tag, that does some processing dependent on the URL).

But given the standard CF setup, that would mean we have to create a CF page for every old html page. That is seriously gonna suck, and is a lot of hard work, for not much payoff.

So of course, I got a' thinking and said - 'wait a minute, why can't we use a servlet to fake the html page, and then pass the URL information to a single CF page via the request scope?'

I.e. do something like this:

public class CFForward extends HttpServlet
{

private static final String FORWARD = "forward.cfm";

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{

//grabs the servlet path
String servletPath = request.getServletPath();

/*
Sets the request scope parameter called 'servletpath' that is accessable from the
Coldfusion page. Key must be LOWERCASE!!!
*/

request.setAttribute("servletpath", servletPath);

//forward on to the coldfusion page.
this.getServletContext().getRequestDispatcher(FORWARD).forward(request, response);
}
}

Then add this Servlet mapping to *.html (and get rid of the CF one) - and presto, seamlessly drives all *.html requests over to "forward.cfm", along with the relevent details in it's request scope.

That AND all the URL and FORM scope data is still there as you would need it.

(Note: my version pulls in details from the web.xml, and does some other stuff but I figured I'd keep it simple)

So now you have what looks like a static HTML page, which is really a servlet running a ColdFusion page behind the scenes.

Yup, I don't believe what a URL tells me anymore. Where have the days gone when .html was static, .cgi was perl, and .exe was crazy ;o) You always knew where you stood with a webpage, just by looking at it's extension. Now it's all smoke and mirrors.

The only problem I've hit so far - on the website, the web stats package picks up 404 errors, however, with a servlet mapped to *.html, ANY page with ends with a .html will get picked up by the servlet. If relevent (i.e. no content for that URL), I need to be able to push a 404 error to the Server (getting it to the client isn't hard, you don't even have to use a real 404). Not sure how I'm going to do that yet.

Thought it was a nifty idea just the same.

 

15 June 2004 02:32 PM 28 Comments

Reasons I hate XMLTransform()

Okay, maybe hate is a bit of a strong word, but seriously, having done some (serious?) XSL development under Java, the XMLTransform() of Coldfusion does leave a little to be desired.

Inability to pass in xsl:param values externally
This one is my primary gripe. I don't understand why you can't do this natively in ColdFusion. In Java, when you create your XML transformation via XSL you can pass in values that are defined in the top of the XSL document like so:

<xsl:param name="root"/>

Which means I can use that variable later on in my XSL stylesheet - the primary example being being able to pass in the root URL of your application, so you can build links from it, so regardless of where you run this XSL stylesheet, you know images and links will still be relative to the root. (Admitedly there are other ways to do this, but this is just an example).

Within the current power of CF, you would have to build your XSL at runtime, and add in these elements yourself. Personally I see this as kind of cludgy, as I prefer to keep my XSL files in a flat file somewhere.

XSL Files must be read in to a variable before they can be used
This means that before you use an XSL file, you have to <CFFILE> it in before you use it. 'No big deal' I hear you say, cache it in a scope somewhere and then reuse it later... yes yes, this is all valid, except for one small thing

<xsl:import href="modularXSL.xsl"/>

If you do this - you can no longer do relative XSL imports, which pretty much destroys any chance of doing modular XSL development. Considering that you can't use a <xsl:param> to dynamically pass through the root path, that does mean you are left with developing your XSL at compile time... (which means it's not a file anymore anyway, and can't be used by other xsl stylesheets), or hardcoding your logical path into the XSL stylesheet itself (yuck!).

But what do we do now?
Okay, so I've had my major gripe, and I did have a good winge for a little while about this before I got mad enough to actually look for a solution. There is a solution to one of the issues, there is a xslt() function that can be found at cflib.org.

This runs natively from CF, however does not handle my issue with using native <xsl:import>.

So of course, I didn't get even more mad - I decided to get down and dirty with some Java and came up with my own XSLT() funtion that uses the underlying Java engine (CF uses Xalan it seems under the hood for anyone that cares) that can take either (a) a XML / XSL string, or (b) a file path to a XML / XSL file.

This means it can do BOTH parameters, AND relative xsl importing!

The documentation looks like this:

Syntax:
XSLT(xmlsource, xslsource [, stParameters])

Arguments:
xmlSource - either a valid xml document as a string, or a absolute file path to a XML file.
xslSource - either a valid XSL document as a string, or a absolute file path to a XSL file.
stParameters (optional) - a structure of xsl:param elements to pass through where the key is the name of the param, and the value is the value of the param being passed through. Do note that StructInsert() will need to be used as param names are case sensitive, and otherwise the struct key value will be in uppercase.

Example:
This can be run a variety of ways:

<cfxml variable="xml">
<!--- valid xml doc --->
</cfxml>

<cfxml variable="xsl">
<!--- valid xsl doc --->
</cfxml>

<cfscript>
stParams = StructNew();
StructInsert(stParams, "root", "http://www.mysite.com");
</cfscript>

<cfoutput>#xslt(xml, xsml, stParams)#</cfoutput>

OR

<cfoutput>#xslt("c:\xmlFile.xml", xsl, stParams)#</cfoutput>

OR

<cfoutput>#xslt(xml, "c:\xslFile.xsl", stParams)#</cfoutput>

OR

<cfoutput>#xslt(("c:\xmlFile.xml", "c:\xslFile.xsl", stParams)#</cfoutput>

Code:
<cffunction name="xslt" returntype="string" output="No">
<cfargument name="xmlSource" type="string" required="yes">
<cfargument name="xslSource" type="string" required="yes">
<cfargument name="stParameters" type="struct" default="#StructNew()#" required="No">

<cfscript>
var source = ""; var transformer = ""; var aParamKeys = ""; var pKey = "";
var xmlReader = ""; var xslReader = ""; var pLen = 0;
var xmlWriter = ""; var xmlResult = ""; var pCounter = 0;
var tFactory = createObject("java", "javax.xml.transform.TransformerFactory").newInstance();

//if xml use the StringReader - otherwise, just assume it is a file source.
if(Find("<", arguments.xslSource) neq 0)
{
xslReader = createObject("java", "java.io.StringReader").init(arguments.xslSource);
source = createObject("java", "javax.xml.transform.stream.StreamSource").init(xslReader);
}
else
{
source = createObject("java", "javax.xml.transform.stream.StreamSource").init("file:///#arguments.xslSource#");
}

transformer = tFactory.newTransformer(source);

//if xml use the StringReader - otherwise, just assume it is a file source.
if(Find("<", arguments.xmlSource) neq 0)
{
xmlReader = createObject("java", "java.io.StringReader").init(arguments.xmlSource);
source = createObject("java", "javax.xml.transform.stream.StreamSource").init(xmlReader);
}
else
{
source = createObject("java", "javax.xml.transform.stream.StreamSource").init("file:///#arguments.xmlSource#");
}

//use a StringWriter to allow us to grab the String out after.
xmlWriter = createObject("java", "java.io.StringWriter").init();

xmlResult = createObject("java", "javax.xml.transform.stream.StreamResult").init(xmlWriter);

if(StructCount(arguments.stParameters) gt 0)
{
aParamKeys = structKeyArray(arguments.stParameters);
pLen = ArrayLen(aParamKeys);
for(pCounter = 1; pCounter LTE pLen; pCounter = pCounter + 1)
{
//set params
pKey = aParamKeys[pCounter];
transformer.setParameter(pKey, arguments.stParameters[pKey]);
}
}

transformer.transform(source, xmlResult);

return xmlWriter.toString();
</cfscript>
</cffunction>

There you go - copy paste that funtion, and now you have every all funtionality you could probably ever want when doing an XSL transforamtion.

I will probably shoot this off to cflib.org at some point soon, so you can search for it there as well.

I must say that I am loving the Java integration with CF, it has definately enabled me to do many more interesting things with CF I was previously never able to do before.

If you have any questions / comments / bugs, drop me a line, or post a comment.

12 June 2004 06:40 PM 2 Comments

XHTML and '

It took me about 2 hours to work this one out, but it I ended up getting there at the end.

I had '&apos;' in comments on this blog, and they were written as '&apos;' in the source, yet they didn't want to come up as apostraphes.

So I'm scratching my head, and I'm thinking -

  1. '&apos;' is a valid XML element.
  2. XHTML is valid XML
  3. Hence - '&apos;' should display correctly.

That would all be well and good (according to my deductive reasoning) except for the fact that - &apos; IS NOT VALID HTML.

So - on that note, if you are displaying something on an HTML page - don't use XMLFormat(), as it will escape your apostraphes into a very annoying '&apos;'. Use HTMLEditFormat() instead.

That also being said, if you are pulling in text from XML feeds, you may wish to filter out the '&apos;' and replace them with real apostraphes, as quite obviously they won't display correctly.

Just thought I would share this one.

You can see some more at: XHTML 1.0 - HTML Compatibility Guidelines

EDIT :::
I just discovered, that &apos; actually works as intended in Mozilla based browsers, however not in IE.  I'm not totally surprised mind you.  Just something else to factor into the mix.