Wednesday, May 28, 2008

MAX 2008 registration is now open

MAX 2008 registration is now open. Check out more information at the MAX web site here.

MAX is the descendant of the Allaire ColdFusion Developers Conference, which turned in to the Macromedia DevCon, which morphed in to Macromedia MAX and is now Adobe MAX. This year it is going to be in San Francisco, which will be great. Not as great as MAX 2006 in Las Vegas IMHO, but SF is a fun place to visit. :-)

I will be giving a session on Livecycle Data Services and BlazeDS deployment, probably with a slant toward integrating with ColdFusion. But anyone who is interested in learning more about Data Services, BlazeDS and how they can leverage the power of these technologies in to their web applications using Flex should get a lot out of it.

Tuesday, May 20, 2008

Offline sync sample application

Christophe has posted another great LCDS sample application that uses the offline synchronization feature of Data Services to good effect. This is one of the features that I worked on for the upcoming LiveCycle Data Services 2.6 release, which is in beta right now up on Adobe Labs. Check it out here.

Friday, May 09, 2008

New blog on FlexBuilder 4 features

Scott Evans, a lead engineer on the FlexBulder team, has started a new blog - Getting and Setting that will be for public discussion of new FlexBuilder 4 IDE features. I am really excited by some of the "IDE Maturity" features that I've seen on the drawing boards for the next FlexBuilder. As an avid InteilliJ IDEA user for my Java development, my tumultuous affair with builder has been a tough ride. I am drooling over most of the improvements that I see coming.

He starts out with his lead post asking about how you use Actionscript "getters" and "setters". Do you use a special prefix for your class member variables? Do you create functions as a matter of course? Or only when you actually need them? Post a comment and let Scott know.

I also encourage you to check out Tim Buntel's $100 test posting asking for feedback on what feature you think are worth investing our resources in. He has recently posted an update on the results, which, I pointed out to Scott, valued the getter/setter generation very high on the list. Of course improving the MXML compiler speed was at the top of many folks lists.

Tuesday, May 06, 2008

Conflict bug in ColdFusion Extensions for Eclipse

If you are trying to use ColdFusion as the back end to a LiveCycle Data Services Data Management application, you should know about the extensions to Eclipse/FlexBuilder that ship with ColdFusion 8 (and 7.0.2). You can download them from the CF download page here.

One of the great features of these extensions is the ability to use the RDS Dataview window to generate CFCs and Actionscript classes from your database tables, saving you lots of tedious typing. To do this go to Window -> Show View -> Other... -> ColdFusion -> RDS Dataview. This will open the panel that allows you to browse your data sources via RDS. Right click on the panel and select "RDS Configuation" to open the settings dialog and configure your RDS server. For instance I have my local CF server configured as:
Description: localhost
Host Name: 127.0.0.1
Port Number: 8500

I am using the built in web server (port 8500) and the stand alone configuration, so there is no context root. You must have RDS turned on in your installation (see technote here for details) .

Once you have the panel open and have access to your ColdFusion data sources, you can open up a DSN, open the "Tables" folder and right-click on a table name. You can show the contents of the table or open up the Query Viewer (on Windows) and run an arbitrary query. At the bottom of the context menu you should see "ColdFusion Wizards". Select that and the sub menu is "Create CFC".

This gives you a dialog that allows you to create CFCs that correspond to this table in your database. Not only that, it will create either "Active Record" or "Bean/DAO" style CFCs that know how to create, read, update and delete (CRUD) themselves! This is pretty cool in an of itself, but if you are using LCDS to write a Data Management application, this wizard can also write the Assembler CFC (the component that has the required methods for LCDS) for you. This selection is named "LiveCycle Data Services Assembler CFC's". It will generate the Bean CFC (representing 1 row of data), the Data Access Object (DAO) CFC, which has read/write/update/delete methods and the Assembler CFC itself, which uses the Bean and the DAO CFCs to do its work.

Neat, huh?

You can even create the Actionscript class that is used in the Flex application to represent your data when it gets to the client.

This code will work right out of the gate if you have a simple single table application. You can use it as a jump start for more complex applications that have multiple assemblers and a more complex data dependencies.

Unfortunately, there is a bug in the generated code when it comes to conflict detection. As part of the "sync" method, there are private functions which perform the create, update and delete operations (named doCreate, doUpdate and doDelete respectively). If you examine the doUpdate and doDelete methods, you will see a cfcatch clause with type="conflict". This calls the ChangeObject's conflict() function. This function takes as its argument the server's version of the object we are trying to update or delete, so the client application will have all three versions of the data - old, new and the server version:

<!--- If there was a conflict, mark the change object.
Include the current version of the record --->
<cfcatch type="conflict">
<cfset variables.dao.read(id=new.getARTISTID()))>
</cfcatch>


The problem is that the code is using the DAO read() method to get the server's version of the object. If you take a look at the DAO code, the return type is defined to be this:
<cffunction name="read" output="false" access="public" returntype="src.com.ARTISTS[]">

This is an array, which is not what we want to put in the ChangeObject for LCDS. What we really want to put in this object is a single record and to do this, we have to unwrap the array returned by read():

<cfcatch type="conflict">
<cfset readresult = variables.dao.read(id=new.getARTISTID())>
<cfset serverversion = readResult[1]>
<cfset co.conflict(serverVersion)>
</cfcatch>

You may want to include some error checking code in here to verify that the call to read() has returned exactly one result (it should as in the case ARTISTID is the primary key in the table). You also may want to "var" the readResult and serverVersion variables at the top of the function to keep them local (yes, this is annoying, yes we need to fix that).

An alternative approach is to invoke the get() method on the Assembler itself, which will take care of unwrapping the array and throwing errors if there is a problem. In order to do this you would need to create a Struct that contained "ARTISTID" as the get() function takes a map of name/value pairs to support the possibility of multiple primary keys. So this fix would look like this:

<cfcatch type="conflict">
<cfset uid = {ARTISTID=new.getARTISTID()}>
<cfset serverVersion = read(uid)>
<cfset co.conflict(serverVersion)>
</cfcatch>


Notice the use of the new ColdFusion 8 structure initialization!

I can't believe we (specifically I) didn't notice this problem before, but as it turns out my conflict functions did not make use of the server version of the records in all of the applications I have written so I (and I guess our QA folks) didn't notice the problem until just recently. On the bright side, this should be an easy thing to fix (and hopefully we will fix it in future releases of the Eclipse extensions) and gives me an opportunity to talk about this really helpful feature of the Extensions.