cfsetting in cfscript

Written by jbriccetti on . Posted in App Dev

Obsessed with converting much (but not all) of my CFML to <cfscript />, I recently discovered there is no <cfscript /> equivalent for the <cfsetting /> tag.  Of course, there is always a way…

CFML

<cfsetting enablecfoutputonly="true" />
<cfsetting requesttimeout="60" />
<cfsetting showdebugoutput="false" />

<cfscript />

<cfscript>
    createObject( "java", "coldfusion.tagext.lang.SettingTag" ).setEnablecfoutputonly(true);
    createObject( "java", "coldfusion.tagext.lang.SettingTag" ).setRequestTimeout(javaCast( "double", 60 ));
    createObject( "java", "coldfusion.tagext.lang.SettingTag" ).setShowdebugoutput(false);
</cfscript>

 

Dealing with Case Sensitivity of Database Table Names at the Persistance Layer with Hibernate

Written by Sean Ryan on . Posted in App Dev, Architecture, Gotchas, Strategy

It’s been a while since my last post so it’s about time I got back to it since I’m backlogged with all sort of awesomeness.

Recently, I took over a pretty big Spring project. Lucky for me, it was written largely in Spring 3.0 so my periodic upgrades to 3.1 haven’t been too difficult. I’m the only developer on the project but it’s not that bad (anymore) and it’s given me a chance to really focus on my Spring skills.

Since I develop locally, I backed up the production database on the server and brought it down to my laptop. Before I could work on it, I needed to run the data through a conversion routine that migrates the database model and its data into the new and improved model for the next release.

The Problem

The problem is that the server is Linux and my computer is a Mac.

Why does this matter? It matters because each OS has different case sensitivity. The conversion routine uses Hibernate as the persistance provider and it’s configured to use the DefaultComponentSafeNamingStrategy which maintains the same case as the managed entities. This is fine except that the application uses a custom naming strategy that converts everything to lower case and acts as a wrapper around the DefaultComponentSafeNamingStrategy. The only time this would ever cause a problem is when the operating system the application is run on is case sensitive. Linux is but Windows is not case sensitive and neither is Mac. I didn’t know this. In fact, I was under the impression Mac was a good OS.

Any of my collegues reading this right now are smiling because I’m constantly listing the ways Windows is terrible and Macs are better as programming tools.

The Effect

This problem wasn’t actually a problem on Windows or Mac. It manifested itself when I moved my converted data up to the server and restored it into the database. When I fired up the application, all the data was gone! Pretty sure a pink slip was in my future, I scrambled to figure out what happened. This was the first time the data was updated since my firm took over the project and they had put their faith in my ability to not blow the database away. I had just blown the database away, or so I thought. It took a while to figure out what happened.

As it turns out, the data was there but with camel casing but since the app uses a lowercase naming strategy, it wasn’t able to find any of the tables.

For example, a table named MyWidgetTable was being looked for under the name mywidgettable.

Finding the Best Solution

This might seem like an easy fix, just update the naming strategy for the conversion routine. It’s true, that’s the best solution and the one I selected but, it’s important to realize why it’s the best solution.

For instance, another option would be to configure the database – in this case, MySQL – to use lowercase naming when creating objects. People do this. You can read more about that here http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html.

Although this is an option, I don’t recommend it.  Doing so will more tightly couple the database implementation to the application and whenever possible we like to make each tier in an architecture as pluggable and removable as possible.  Changing databases has more side effects when you start introducing configurations that directly impact the design of a system.

In general, when you need to deal with filesystem objects, try to choose an implementation that will work across the big players to keep your code as portable as possible even when you think you’re environment won’t change. It will and in this field, crap changes every couple of days! The previous developer knew this and that’s probably why he wrote the custom lower case strategy to begin with.

More Fun with ColdFusion & Spreadsheets

Written by jbriccetti on . Posted in App Dev

I do like spreadsheets. They’re basically glorified csv files and talk about the lowest-common-denominator for data – I’m pretty sure after the nuclear holocaust, the last two things left on earth will be cockroaches and data stored in spreadsheets…

There are many ways to work with spreadsheets, but it’s not uncommon to be pulling data into ColdFusion queries, massaging the data, and then stashing it. This is the sort of utility script work that I get asked to do on client sites like it’s my job. Oh, wait… yeah yeah…

Like most data structures, ColdFusion queries are great for some jobs and stink for others. But then there are things about queries that should work well but they simply don’t. If you have ever tried to generically output a query and you used the “queryname.columnlist” property, you know what I’m talking about. That column list is in alphabetic order, not in the order it appeared in a select statement, or in this case, in the order of the spreadsheet columns. Oh, and its translated to upper case, which is seriously ugly. This is not always a problem, however, when working with spreadsheets, it often is. Spreadsheet users usually put their columns in an order for a reason – and if you are working with a script to read a spreadsheet into a query, do a little dance and then write a new spreadsheet back out, generically (i.e. without hard-coding the column names in your script) – then using that columnlist property for the headers in the output spreadsheet is trouble.

Solution? use the getmetadata function on your query to get an array of structs that describe the columns in the query – and yes, that’s an array, which means ordered, in this case from left-to-right in the spreadsheet. Nice! Also, the case of the values is completely preserved. Extra Nice!

One trick is that you now have an array of structs and what you usually want (for your output to the spreadsheet) is just a common-delimited list of the column names. The column names are all in the key “name” in each structure item in the array. Oh, look what i found (and by found i mean wrote)  http://www.cflib.org/udf/arrayofStructsToList

So, drop that <cffunction /> into a page and sprinkle in some of this sample code:  note, you’ll also need a source xls file

<cfscript>
    fpath = expandPath(".");
    sep = request.vars.sep;
    source = listappend(fpath,"source.xlsx",sep);
    dest = listappend(fpath,"dest.xls",sep);
</cfscript>
<!--- pull the source spreadsheet into a query object --->
<cfspreadsheet action="read" src="#source#" query="q" headerrow="1" rows="2-9999" />

<cfoutput>ugly stuff:#q.columnlist#</cfoutput><br />
<cfoutput>much better:#arrayofStuctsToList(getmetadata(q),'name')#</cfoutput><br />

<!--- image you wanted to modify the data and do some calculations --->
<cfset queryAddColumn(q,"check",[]) />
<cfloop query="q">
    <cfscript>
      isok = "BAD";
        // do whatever you need to do here
        if (true) isok = "OK";
        querySetCell(q,"check",isok,currentrow);
  </cfscript>
</cfloop>

<!--- note the newly created column comes back in both calls. thats good! --->
<cfoutput>ugly stuff:#q.columnlist#</cfoutput><br />
<cfoutput>much better:#arrayofStuctsToList(getmetadata(q),'name')#</cfoutput><br />

<!--- create an output spreadsheet for the new data  --->
<cfset out = spreadsheetNew()>
<!--- Add header --->
<cfset spreadsheetAddRow(out, arrayofStuctsToList(getmetadata(q),"name"))>
<!--- format header if you like --->
<cfset spreadsheetFormatRow(out,{bold=true},1)>
<!--- drop in the data --->
<cfset spreadsheetAddRows(out, q)>
<cfset spreadsheetWrite(out, dest, true)>

Bugs with reading spreadsheets from ram:// disk

Written by jbriccetti on . Posted in App Dev

So this week I had to create a utility to whip together a few spreadsheets, zip them up and provide a download link.There are (2) good reasons (and probably more) to use the RAM disk for storing the files during the processing ISO traditional disk:

  1. Disk bloat: One of the challenges with these sorts of utility apps is orphaned files on the server and after a few months, years, disk space gets scarey. Of course we can clean up the files with a <cfdirectory action=”delete” /> but there are times when you simply can’t rely on that – an error may halt processing, the code to cleanup may not fire and there are those nasty little orphans again! Oh, and then there is the “I’m really lazy” part of programming that, during development, when I’m aborting processing all over the place (for debugging purposes) – well, i just don’t want to see all those files getting orphaned…
  2. Performance: Disk I/O is slow, memory allocation is fast. ’nuff said.

ColdFusion 9 introduced the ram disk – basically, a “virtual”disk drive that CF treats like a regular disk system: You can write, read, delete,  even <cfinclude />. Anyway, use “ram://” as the “drive” specification and create *nix style paths and you are all set.

What are the cons? Well, the ram disk is volatile – if the server reboots it’s all gone. There are some other limitations, like how much ram it will tie-up and the (lack of) restrictions on who can access what (it doesn’t use traditional O/S ACLs). But for what i needed, it was perfect.

And so life was good. I was cranking out the spreadsheets (by copying existing templates) and was able to zip them up and deliver them through <cfcontent /> just fine, and dang fast. Then I went back and tried to actually access the spreadsheets after i copied them, to update some data in them before creating the zip. That’s when I hit this little snafu.

It appears that when you write a spreadsheet to the ram disk, ColdFusion cannot access it through the spreadsheet functions or the <cfspreadsheet /> tag. I guess I’m not surprised – I’m not sure what (java) utility CF is using under the covers to access the spreadsheets, but i suspect the drivers cannot accept a ram disk file path. Bummer.

Back to using disk and hoping like hell my cleanups do their thing…

here is a sample code you can run to see it yourself:

<cfscript>
sep = createObject("java", "java.lang.System").getProperty("file.separator");
folder = "AF2E3351-1422-52FB-568E3B79A02D455F";
disk = {"dir" = "#expandpath('./')##folder#","list"="","fname"="","spreadsheet"="","err"="no errors"};
ram = {"dir" = "ram://#folder#","list"="","fname"="","spreadsheet"="","err"="no errors"};
if(NOT directoryExists(ram.dir)) directoryCreate(ram.dir);
if(NOT directoryExists(disk.dir)) directoryCreate(disk.dir);
source = listAppend(expandpath("./"),"template.xlsx",sep);
disk.fname = listAppend(disk.dir,"spreadsheet.xlsx",sep);
ram.fname = listAppend(ram.dir,"spreadsheet.xlsx","/");
fileCopy(source,disk.fname);
fileCopy(source,ram.fname);
ram.list = directoryList(ram.dir);
disk.list = directoryList(disk.dir);

try{
	disk.spreadsheet = spreadsheetRead(disk.fname);
}
catch(any e){disk.err = e.message;}

try{
	ram.spreadsheet = spreadsheetRead(ram.fname);
}
catch(any e){ram.err = e.message;}

writedump(disk);
writedump(ram);
</cfscript>

HTML5 & < Video>

Written by jbriccetti on . Posted in App Dev, Misc Ramblings, Mobile, Strategy

Why Now?

At the crossroads of today’s internet experience, we see a convergence of html5, social media, video and a multitude of web enabled devices. The day for all these elements has come  and they are all, equally affecting the web of tomorrow.

The internet has brought us a culture transformation, away from the world of “restrictive” business and social models. Think about real estate & media moguls – giants who monitized information via exclusive rights and limited access – these industries are nothing like they once were. Today, easy discovery, unlimited access and free distribution are the underlying principles of the “inclusive mindset” that closes the gap between content and audience.

HTML5 <video> tag brings a much needed standard to the web. But more importantly it is the opportunity for moving pictures to have it’s heyday on the internet. The benefits?

  • A broader reach: 50%+ of all internet traffic is video; 60%+ of all mobile data is video. 
  • Mega-stickiness: video shows the full range of human emotion and context, the result of which is better communication & faster calls to action.
  • Better content, better context: relatedness via metadata and transparent content density improves the quality of discovery; “Deeper” content, faster and easier.
  • Viral distribution: Social media “pushes” make discovery easier – we no longer have to find content, it find us. Brightcove reports that it’s 2nd biggest referrer of video content is Facebook.

Timing is everything. The success of social media,  the expectations of html5 standards, the proliferation of devices have converged at a time when a new, open mindset creates opportunity like never before. Video is ripe on the vine.

Strategy

Creating and managing optimized video content is critical; Video content production is different than authoring text content. Social media goals are to raise awareness and leverage viral distribution. Core content is for engagement and information distribution. Managing metadata and creating “relatedness” are critical elements of a successful game plan.

Distribution strategy is multifaceted. Viral distribution is powerful yet uncontrollable. Managed syndication via MRSS or syndication partnerships improves reach even further and with more controls. Both vehicles improve inbound links and drive better SEO.

Often overlooked, Analytics is as important as any other part of your strategy. Without metrics for engagement, distribution, content and device support, you have no idea where your successes and failures reside.

Finally, player ubiquity is the most important technical piece of the strategic puzzle. <html5> brings us the hope of a future emerging standards. File formats (codecs) and device support is far from standardized. Much like the browser wars of 2001, 10 years later we are seeing the device wars play out, especially in the video space. Your technical solution must address all devices to fully leverage all that video has to offer.

Some interesting statistics:

  • The average web user watched 75% more video in 2010 than in 2008
  • By 30 seconds into an online video up to 33% of viewers have moved on; at 1 minute 44% have left (regardless of the clip’s length) and almost 60% have abandoned by the 2 minute mark. [source]
  • More than 16 Million mobile users in the U.S. watched TV or video on their mobile phone in Q2, 2011
  • Every second, 1 million minutes of video content will cross global IP networks in 2015. That would take a person 5 years to watch. [source]

Myth-busting html5 <video>

 The Promise

  • No fragmentation – higher success factor with scalable, manageable solutions
  • No need for plugins, 3rd party tools or proprietary solutions.
  • Better performance – native functionality
  • More culturally aligned with the web – open & free standards

The Reality

  • The functionality is standardized, the implementation isn’t
  • War of the codec standards
  • Reliance on Plugins (Flash) for fallback

Implementation

  • Make one version of your video in WebM (VP8+Vorbis)
  • Make another version in H.264 +AAC audio in an mp4 container
  • Make a third version in theora + Vorbis in an ogg container
  • <video> embed with a fallback on flash

Why Bother?

  • Devices. If you care at all about reaching the mobile marketplace, html5 video is a must.
  • Lead, don’t follow –  be a part of setting the standard. The sooner you get started, the better off you’ll be when it matures.
  • Potential – html5 <video> is where flash was 10 years ago – on the precipice of explosive growth.
  • It’s worth it – any bumps are outweighed by video’s extended reach.
  • SaaS Solutions – you don’t have to DIY.

Resources:

Example using VideoJS Plugin for wordpress:

All i had to do was add the code like this (it doesn’t matter if you enter it in using visual or html mode, either way the plugin picks it up:

 [ video mp4="http://video-js.zencoder.com/oceans-clip.mp4" ogg="http://video-js.zencoder.com/oceans-clip.ogg" webm="http://video-js.zencoder.com/oceans-clip.webm" poster="http://video-js.zencoder.com/oceans-clip.png" preload="true" width="640" height="264" ]

 

Deploying Beta Test Apps to iPhones+

Written by Anthony DeBonis on . Posted in App Dev, Misc Ramblings, Mobile

After you have developed your mobile application you want to test it out on real devices with real testers, both Android and Apple let you run provisioned ad-hoc version of your application. On Android devices its usually as easy as connection your USB cable and running a command from the command line/terminal or have your tool run a deploy for you.  For iOS devices it can take some extra steps to share your ipa install file around, have your testers drag it into iTunes then trigger synch with the device and this has to happen with each beta release.  We found this workflow cumbersome and looked for a better way.  We found it with testflightapp.com – a free online service that makes distribution of your iOS apps easy and comes with some other helpful features.

Once you have an account you can upload a build, be sure to always update the version number or you will get prompted to make a decision on whether to force an update using the old version number.  The service allows you to enter in release notes which are great for the testers and for general tracking of releases and features.  The system easily tracks multiple project application and test teams for distribution.  With each deploy you can choose which team or user will get a notification of the new application version.  The test end user does need to install the TestFlightApp iOS app from the AppStore or follow the link off the email/website.  It’s a basic app that handles the install of your latest version of the app on the device.  The test users can reply to the test email with comments and those comments will be added to the running comments for that version.  You still have to create a signing certificate and provisioning file with specific devices listed, this is done up on the Apple Developer portal – so you will still need to pay for a developer license. When you invite a tester  to install your beta app you receive notification from their device with its serial number uuid that you will need to create the provisioning file, so there is still some hoops to jump through but this service smoothes it all out nicely with a very clean UI.

Side note – this works with the iPhone, iPad and iPod Touch devices – I wish we could deploy our Android beta versions of our applications this way too…. maybe in a future version of TestFlightApp….

ColdFusion ANT Deployment Scripts – Part One: Versioning

Written by mpacella on . Posted in App Dev

This is the first post of a series in which I will be discussing how I leverage ANT with my ColdFusion applications for various pieces of deployment.  Tentatively, this series will consist of:

  1. Versioning
  2. Generating ColdDoc (javadoc-like CFC documentation)
  3. Automating MXUnit Tests
  4. Deployment (via SSH, FTP, Windows Network)

Note: All files mentioned here should be placed directly in your root project directory.

Step 1 – Create our basic build.xml file

First, we will simply stub out our build file.  For now I simply stub one target, called version.  We will also reference a build.properties file to hold all variables that pertain to the build (we’ll build it later).

<project name="CFAntDemo" default="version" 
    basedir=".">
    <property file="build.properties" />
    <target name="version">
    </target>
</project>