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

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.

30 November 2009 11:04 PM 0 Comments

Sneak Peak: Transfer's new Plug-able Cache

If you've kept and eye on the transfer-dev mailing list, or possibly on Brian Ghidinelli's blog you may well have already seen this, but its an interesting development with the next version of Transfer, so I figured it could use some discussion.

If you have a look in the Transfer SVN repository, you will see there is a new branch:
http://svn.riaforge.org/transfer/transfer/branches/pluggable_cache/

So the aim of Transfer's plug-able cache is to replace the cache that Transfer uses with a extensible plug-in architecture.  By default, Transfer will ship with a EHCache implementation (which has some deployment limitations of CF8+ only, and won't work on some shared hosts, depending on settings), and also a ColdBox Cache implementation (once ColdBox Cache is released), for wider compatibility.  We are also looking at a CacheBox implementation as well.

That being said, the sky is the limit - because the cache is now plug-able and extensible, you can write your own cache providers for Transfer, which can hook into almost anything you desire.

The reason behind this change is twofold. (1) The cache implementation as it currently stood was not very flexible, and it meant that there could only be limited extension to what was possible with that cache and (2) there were certain implementation details within the cache that could have been written a lot better (including a very random, rare, and really hard to reproduce memory leak that only seems to show up sometimes).  So all in all, it simply made a lot of sense to move to an already proven cache implementation, and take the burden off Transfer's shoulders, while opening up caching to the developer community at the same time.

Unfortunately, this means that if you had cache settings set up before, you will now need to rewrite them with the configuration of choice of the cache provider that is selected (or provided by default), which is irritating, however the power provided by this new functionality is worth it.

If you didn't have cache setting set up by default, then Transfer will use EHCache as the default cache provider, with some basic settings configured for you, and no changes will be necessary.

For example, now, a cache configuration will look something like this:

<objectCache>
    <defaultcache provider="transfer.com.cache.provider.EHCacheProvider">
       <setting name="config" value="/test/resources/ehcache.xml"/>
    </defaultcache>
    <cache class="none.Basic" provider="transfer.com.cache.provider.NoCacheProvider"/>
    <cache class="none.Child" provider="transfer.com.cache.provider.NoCacheProvider"/>
</objectCache>

This sets up the default cache provider, as being the EHCache Provider, and passes it a relative path to the ehcache.xml file that will configure the EHCache.

You can also see that there are 2 class definitions for none.Basic and none.Child, that use the NoCacheProvider, which, as you have probably guessed, does no caching at all.

From there, we can configure our ehCache.xml file, which is quite straight forward.

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">

    <defaultCache
        maxElementsInMemory="1000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="600"
        overflowToDisk="false"
        />

    
    <cache name="AutoGenerate"
            eternal="false"
            maxElementsInMemory="10" overflowToDisk="false">
    </cache>
    
</ehcache>
Here you can see that I've set up a defaultCache for all of the objects being used by Transfer, such that it can have 1000 elements in memory, objects can be idle in the cache for 120 seconds, but will be discarded after 600 seconds.

I have also setup a cache specific to my class 'AutoGenerate', which only allows 10 items to exist in memory at any given point in time.

There are many other options available for EHCache configuration, all which are covered in the documentation.

If you are at all interested in writing your own Cache Providers, you will need to extend the AbstractBaseProvider.cfc and implement all the virtual / abstract methods on there.  It is actually pretty straight forward API.

There is something new that is required when bootstrapping Transfer now, which is the 'shutdown()' method.

A lot of cache implementation have 'shutdown()' methods, as they may have to close connections to files, shut down threads, or let go of certain resources before they can be garbage collected properly.

Therefore, for example, if you have Transfer in your application scope, it is important to shut it down when the application ends:

<cffunction name="onApplicationEnd" returnType="void">
   <cfargument name="applicationScope" required=true/>
<cfscript>
    arguments.applicationScope.transferFactory.shutdown();
</cfscript>
</cffunction>

This will call shutdown() on all the cache providers Transfer is using.  In the case of EHCache, this is very important, as without it a native thread will keep running, stopping EHCache from being garbage collected.

If you need more control over your cache's you can access the native cache as it is exposed by the Provider, through the Cache Monitor (whose API has changes slightly from before) methods 'getDefaultCache()' and 'getCache(className)' methods.Please have a play, and let me know how it goes on the transfer-dev list.  I'm waiting on the other ColdFusion caches to become available so everyone has a cache they can work with, before releasing this in a 1.2 release.

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!

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

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:

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

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

 

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 !

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:
You can read about all the details on these features in the release notes.

Happy Downloading!
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:
Contact through several different channels, including:
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 .


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:

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

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:


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


Pushed out to post 1.0 release


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

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

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

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.

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!

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.
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 -
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.
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)
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!
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:
   
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:

If you have any questions or comments there is a mailing list , and a forum             .
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:

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. 

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.

Yes it is true! You can now use Transfer on Oracle!
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.
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!!:::
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 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.
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.
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.
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.
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.
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.
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.
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);

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.
This meta data was exposed for the Model-Glue:Unity integration, but could be used for a variety of purposes.
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.
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.
Incorporated the newest version of wwwObjectDoc into TransferDoc, which now gives us an ordered list of the methods on an object. (Thanks Aaron!)

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!
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:


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.

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 -

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 -


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.

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?

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?


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 .


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:

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. 

11 April 2006 02:02 PM 0 Comments

Finally! CVS For Transfer!

I think to myself today... gee, I haven't checked out my project application on cfopen.org for aaages, I'll log in and see what's going on.

Lo and Behold! The accepted my project back in November 2005, and I had no idea.

Thank you very much to the guys at cfopen, I must have lost the email along the way somewhere!  Guess that shows me that I should be more diligent in paying attention.

So I'm slowly moving my files up to CVS on cfopen - which is a long time in coming for Transfer .  At the moment it's just the core code, but I will also be putting up my test cases, and the example code base shortly.

Version 0.4 is just on the horizon, with me pretty much just left with making some minor edits to some files, and packaging it all up nicely left to go, but I figured I would let you all have a taste a little bit early.

Enjoy the new CVS Repository.

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. 

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.

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.