Blog

    Happenings and acts of geekery.

PhoneGap, FileTransfer, and ColdFusion

I like PhoneGap. Really. But I bashed my head on this for a while so if this saves you the headache, you're welcome!

The app I am working on uses the Camera API to capture an image and then submits it to a back-end service for inclusion in an online photo gallery. Pretty simple.

When you capture the image, you have two choices for how to handle the data:

Camera.DestinationType.DATA_URL
Camera.DestinationType.FILE_URI

The problem with DATA_URL is that the cameras on mobile devices are getting to be too darn good. That DATA_URL is a Base64 encoded string that can very quickly run you straight out of memory. Therefore, you are strongly encouraged to use FILE_URI instead which is simply a pointer to a file on the device file system.

How do you then get this file moved up to the server? Use the File API's FileTransfer object.

var imageURI = PATH_TO_FILE_AS_GIVEN_BY_CAMERA;

var options = new FileUploadOptions();
options.fileKey="file";
options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType="image/jpeg";
/* ColdFusion barfs if you don't set this */
options.chunkedMode = false;

var params = new Object();
params.formfield1 = 'send other data along for the ride';
   params.formfield2 = 'using more fields like this';

options.params = params;

var ft = new FileTransfer();
ft.upload(imageURI, "http://YOUR_URL_HERE/SOME_FILE.cfm", win, fail, options);
/* don't forget to create functions for win and fail conditions */

The key line here is options.chunkedMode = false;. From what I could tell by reading Ben's blog post , ColdFusion simply can't handle chunked form data. Two hours of searching and evaluating alternatives...and then I noticed this option.

So...lesson learned. Base64 will not only drag your app down but probably crash it as well. FileTransfer (sans chunks) is the way to go.

How I got started with ColdFusion

Steve Bryant had a great idea that the entire ColdFusion community should post about how they got started with ColdFusion on the same day. Count me in!

I started my first job after earning my computer engineering degree as a software test engineer in the summer of 1999. If only I knew how boring that would be! Three months in to that job I went to my boss and asked to be put on a different project - it was that bad!

A couple days later he took me down to the first floor of our building and introduced me to Sam Raimond. Sam was an interesting guy - he had an insatiable curiosity for all new technology. While he wasn't really a programmer, he would mess with just about any new piece of software that came out. In the late 90s, there was an awful lot for him to play with!

Sam was the project manager for the document management system (DDCS) used by a rather large organization up the street from us - NASA. DDCS was a combination of IIS, WebDBC, and Xerox DocuShare running on some ancient Gateway servers - far from sexy, but absolutely mission critical. My boss knew I could build websites, though I hadn't done anything more than HTML and some really basic javascript. Sam didn't seem bothered by that. He handed me the box with ColdFusion 4 server in it, told me he didn't know CFML, and that he was pretty sure nobody else in the company knew it either. My new project: take the four programs that comprised the DDCS system and rewrite them in ColdFusion. Challenge accepted.

The first module took me three months to build. The second, third, and fourth combined took three weeks. Even if we had set out an aggressive rebuild schedule we wouldn't have expected this to come together so quickly. Needless to say, ColdFusion made a lot of people we reported to very, very happy!

I learned how to do this by spending lots of time on the (at the time) Allaire forums and regular attendance at both the DC and Baltimore ColdFusion User Groups. Sam was insistent that we never miss a meeting of either group, even though I was extremely reluctant to go at first. The thing is, once you meet the CF community any reluctance to go as a "newbie" falls away quickly. I remember being immediately put at ease by the friendly people who were there. Some of the stuff people presented was amazing! I'd always come back to work with a whole bunch of ideas and even less time to build them.

One thing I've never forgotten is that it was because of the welcoming, fanatical ColdFusion community *and* the power of the platform that I have been able to enjoy the career that I do. Macromedia recognized the value of the community when they acquired Allaire and Adobe saw it too when they bought Macromedia. No matter the corporate parent the server has seen tremendous improvement from one version to the next with a corresponding jump in the number of things that developers can do easily. I've made a pretty darn good living and a few really great friends thanks to my ColdFusion skills and intend to continue using it as long as the platform keeps evolving (I'll keep the friends regardless).

Interesting footnote: I've known Rob Brooks-Bilson for (omg) 10 years now. Today, thanks to his "How I got started" post, I learned that our first projects were both conversions from WebDBC to ColdFusion. Ironic, indeed.

Fun with Twilio, Part 2 (The Results!)

Last week I wrote up a summary of a project I threw together that leveraged ColdFusion and Twilio to enable the reunion crowd to vote for their favorite performance.

Well, everything went off without a hitch on Saturday! In fact, I spent an hour on Friday night changing how the system worked to cater to both smartphone and "dumbphone" users. I promised a writeup on how it worked and what the results were, so without further delay...

Promotion

We printed up about 1000 stickers - just plain old Avery mailing labels - with two ways to cast your vote. First was via SMS to the number printed on it. The second way was for those "in the know" who understood what a QR code was.

The parade commentators plugged the voting in the warmup before the parade started, between acts and again at the very end. This definitely helped our cause - there was nothing else to pay attention to during those times, so the exclusivity of the promotion really stood out.

We handed out the stickers to as many spectators as we could along with each of the reunion classes while they were lining up for the parade. After a quick explanation of what was at stake (a new award!), some classes eagerly set to work with their phones. They loved that there was something to do while they were waiting for the parade to start.

This was the extent of the promotion. For an app that came together really quickly, there wasn't time to get word out in advance -- and honestly it wasn't necessary. This was a very "event specific" thing that required no prep on the part of the participants.

How It Worked

There are two ways to cast a vote: SMS or using the QR code. The original idea was to use the QR code to launch your text messaging app with the appropriate class year already entered as the body of the message (we'd print unique stickers for each class). You can't do that on iOS - only Android. We then realized that was dumb - if you were going to text, it's easier to just do that rather than fiddle with a barcode reader. There had to be something nicer for the barcode crowd.

So Friday night around 11:30 I sat down with Dreamweaver CS5.5, jQuery Mobile and ColdFusion to toss together a really quick web-based mobile app. One hour later it was skinned, released and running. One hour!

Results

All told, reunion attendance was around 1000 people. There were unregistered spectators and probably some unregistered guests floating around too. Out of this crowd, we collected more than 1200 votes! Roughly a tenth of them were submitted using the mobile app. The URL was not public, so the QR code would be the only (easy) way in. At a couple cents per SMS, this was good, cheap fun - and nothing went wrong.

Lessons Learned

  • PEOPLE LOVE TO PARTICIPATE! Everybody wanted to know the results before they were announced. They were really amused when I pulled out my phone and showed them the graph of results...up to the second
  • QR codes look really scary to people who don't know what they are
  • QR codes CAN be safely dressed up! I took advantage of an excess of error correction code built in to the QR structure and "Fireworks-ed" in the Lehigh shield. It looked less intimidating.
  • Make sure auto refresh was active for your Twilio account (thankfully mine was...though my heart stopped when I got an email in the middle of the parade from them!)
  • The alumni band will, upon finding out they lost, make plans to hack the vote next year. Bring it.
  • Do not send an acknowledgement for every vote - you'll hit a limit pretty quick.
  • Call-to-vote? Entirely possible with Twilio. Might be fun to add it just for fun!

One key enhancement for next time: Screens at the reviewing stand showing the real time voting totals. With ColdFusion, Blaze DS and Flex this is maybe another hour of work.

The Award!

The result was a decisive win for the class of 1976. Their re-enactment of Rocky was entertaining, colorful and energetic...and they certainly weren't shy about voting for themselves!

For their efforts, they were the inaugural winners of the Stephen C. Rittler '99 Reunion Parade Fan Favorite Award!

Fun with Twilio

With the rush to build full-fledged mobile applications for smartphones, sometimes we forget that there are still a lot of people on...shall we say...dumbphones. So what do you do when you want to interact with as many people as possible? You drop down to the lowest common denominator: voice and SMS.

Lehigh University's annual reunion features a parade of classes through the heart of campus. Every class does a performance for a theoretically impartial panel of judges who take the reaction of the crowd into account during their voting. Awards are given, like the "Best Alumni Band Award" (given to the one and only Marching 97 alumni band) and the Petty Flag (for the overall best performance). This year, we wanted to add more crowd interaction to the mix.

The idea was to bang out a quick "vote via SMS" app so everybody watching the parade could vote (as many times as they like) for the class they thought did best. The powers that be have decided to add an award based on the results too.

Enter Twilio! The best part: it's stupid simple to build this kind of app using their REST API. First thing was to sign up for a number - it's only $1/mo. I then set the "SMS request URL" to a page on my server.

Then on the page I pointed it to, I set up code to handle the text that was being sent in. The entire message is passed in in form scope as the "body" attribute with all the other attributes (sender phone number and their account locale information) sent along too.

<cfif structKeyExists(form, "body")>

   <cfset classYear =    reReplace(form.body, "[^0-9.]", '', 'all') />

   <cfif classYear is not "">
      <!--- add to vote total --->
      <cfset v = entityNew('vote') />
      <cfset v.setVote(classYear) />
      <cfset v.setFrom(form.from) />
      <cfset v.setFromCity(form.fromCity) />
      <cfset v.setFromCountry(form.fromCountry) />
      <cfset v.setFromState(form.fromState) />
      <cfset v.setFromZip(form.fromZip) />
      <cfset v.setTimestamp(now()) />
      <cfset entitySave(v) />
</cfif>
</cfif>

Then, I send an acknowledgement message to the sender:

<cfhttp url="https://api.twilio.com/2010-04-01/Accounts/{REALLY_LONG_ACCOUNT_ID}/SMS/Messages" method="post" username="{YOUR_USERNAME_IDENTIFIER}" password="{YOUR_ENCODED_PASSWORD}">
         <cfhttpparam name="From" type="formfield" value="XXXYYYZZZZ" />
         <cfhttpparam name="To" type="formfield" value="#form.from#" />
         <cfhttpparam name="Body" type="formfield" value="The class of #classYear# thanks you! Feel free to vote as many times as you like." />
      </cfhttp>

That's it! Already they're thinking of other uses for this kind of tool. I'll be sure to post again on Monday with the writeup on how it went.

Presentation: Moving from Verity to Solr

I gave a talk at last night's Philly CFUG meeting on making the migration from Verity to Solr in ColdFusion 9. Adobe has made it known that CF9 is the last release of ColdFusion to contain Verity and that Solr is the way forward.

I'm glad that's the case! Solr is amazingly powerful, fast and extensible. What has been exposed in CF9 barely scratches the surface of what it can do. That's not a bad thing - the Adobe team should be commended for making the transition as simple as possible by using the same tags, attributes and data structures. You'll find (as I did) that the migration is relatively straightforward provided your codebase isn't a real mess. 90% of the effort will go in to adjusting any code that builds formatted search criteria in Verity-specific terms into something that's Solr-compatible. Collection maintenance is left essentially untouched.

If you'd like, you can grab the slide deck and simple examples - with one disclaimer: the code is for example purposes only and should not be held up as an example of ideal coding practices :-). Special thanks to Ray Camden and Scott Stroz for their blog posts on Solr - their work was great background for this talk. Also - thanks to Adam Tuttle and the Philly CFUG for inviting me to speak!

CASE Mobile: Our first jQuery Mobile + ColdFusion app

Our first mobile application built with jQuery mobile went "live" today at the annual CASE/NAIS conference in Chicago, IL and by early accounts it's a success!

The purpose of the app is to make relevant conference information available to attendees at all CASE events year-round. Conference attendees will particularly enjoy the ability to submit their session evaluations from their mobile devices right away without having to handle the traditional paper forms. Session information is available as is a venue map. Conference organizers can also send out "alerts" that pop up within the app itself, notifying attendees of upcoming sessions, room changes or other important information. The "app" works on all Apple iOS, Android and Blackberry (OS6 preferred) devices and semi-gracefully degrades for use on older devices -- all with no additional development effort thanks to jQuery mobile.




Built on a tried-and-true combination of Adobe ColdFusion, Mach-ii framework, ColdSpring framework and SQL Server for backend data storage, the app is expected to serve tens of thousands of unique users every year. Taking on jQuery Mobile as our front-end framework was not without some risk; it's still in alpha (we used Alpha 2) but the rapid development and cross-device capabilities of the framework far outweighed the immediate concerns. We'll be keeping a close eye on this and upgrade as new releases are made. Testing was done on a Motorola Droid 2, Blackberry Torch, an iPad and an (ancient!) iPhone 3G without issue.

Want to talk about how we might be able to help you implement a cross-platform mobile application? Email Steve at srittler@countermarch.com.

Take a day off for RIA Unleashed

Pull out your credit card. Yes, yours. This conference is for you. It's only $75! If you don't think spending $75 will make you at least $75 more effective the following week, you're severely undervaluing yourself (so is your employer for that matter).

As for your employer: forget 'em. Take the day off. You'll be so energized and refreshed by the simply amazing content it'll feel like a vacation day anyway. Out of them? Call in sick (I'll vouch for you...just cough a little). Hold your employer accountable for their mission statement of "investing in our employees" and being an "innovative" place to work. That's right...they all say it...make 'em mean it.

Compared to MAX or CFUNITED (r.i.p.) this is an amazingly great value for the money. It's close to home. Yes, even if you're in DC or Philly it's close to home. Anywhere you can get to via Amtrak or in a car within a day is close to home. Regional events need our support too ~ consider this a call to stand up and count yourself among the growing world of CF developers who aren't just 'one trick ponies.'

Content: ColdFusion, Flex, Flash, AIR, Mobile. Plus all the related good stuff presented by people who make you feel smarter just by being in their presence. Just look at this speaker list! You (yes, you) need to be there.

It's a day of training (two if you do the workshops) for far less than a weekend at the beach. Training that will put you that much closer to having your own beach house. Or mountain house. Or Swiss chalet. Whatever floats your boat. Even if that's a boat.

School's back in session. Get to class. See you there!

Mach-II is (still) awesome

Mach-II rocks. It is one of the more "mature" surviving ColdFusion application frameworks, and as such doesn't get nearly the amount of buzz that the new (interesting, different, creative, awesome-in-their-own-way) frameworks get. If you're looking at frameworks, I encourage you to take a look at the amazingly capable Mach-II - we've had fantastic success with it!

Things I really, really like about Mach-II:

Backwards compatibility

Take an old (Mach-II 1.1 app, circa 2006) and update the framework to 1.8 (released 2009). Replace the application.cfm file with application.cfc, comment out everything in index.cfm and *boom*...you're done. I can't really assess how challenging it is for the team to maintain backwards compatibility, but I sure do appreciate how simple it is to upgrade. Instant feature add with zero headaches.

Coldspring integration

<include file="./mach-ii_coldspringProperty.xml" />

and in your listeners:

<cfcomponent name="mpListener" extends="MachII.framework.Listener"

depends="howConfigManager,mpManager,reportManager,notificationManager">

I don't think it gets much easier than that. Instant Coldspring integration for dependency injection (and more), radically simplifying the configuration of all of my listener and model cfcs. Now we've got all the power of Coldspring cleanly available to our Mach-II application.

Faster Fixes

Knowing where to find things is one of the hallmarks of any good framework. Some do it by convention, some by configuration. Mach-II falls into the latter camp but that's perfectly fine by me. Getting back into the mental model of an application months (or years) after deployment is a challenge but by simply cracking open mach-ii.xml I can see what happens where within seconds and bend it to my will. I love this.

Modularity

This wasn't in the framework back in the 1.0 and 1.1 days (when we created some mammoth apps), but by 1.5 (which came out in 2008) the ability to break up large Mach-II applications into separate modules was baked in and oh-so-handy. It's two years later and we've been able to make the easy changes to break those older apps into a collection of modularized sub-apps for much easier maintenance. Perfect example is an extranet: lots of only slightly related apps put under one common umbrella sharing security or UI components. This is easy to implement and support in a well-designed Mach-II application. All of our more recent apps make use of this feature.

The Team

The people who created and have since improved and evolved Mach-II are some of the smartest folks who are or have been involved in the ColdFusion community. Look at this list. Not only have they created something awesome, but they're incredibly responsive on the wiki, development Google group, and framework users Google group. They use this framework at their day jobs so you know that each release has been painstakingly designed, implemented, tested, re-tested, piloted and then released. Plus, they're open to new ideas (even if you personally have no idea how to make them happen!). Code is great, but the people are the best.

The View Loader

This is where some of those "convention-based" concepts have crept in to Mach-II much to the benefit of the users. Back in the "bad old days" your mach-ii.xml file would contain a block that looked sorta like this, except far longer:

<page-views>
      <page-view name="showWelcome"       page="views/showWelcome.cfm" />
      <page-view name="showHome"       page="views/home.cfm" />
      <page-view name="baseTemplate"       page="views/baseTemplate2010.cfm" />
      <page-view name="blankTemplate"    page="views/blankTemplate.cfm" />
      <page-view name="welcomeLanding"    page="views/welcome_landing.cfm" />
      <page-view name="showSendPassword"    page="views/showSendPassword.cfm" />
      <page-view name="showAppHelp"       page="views/showAppHelp.cfm" />
   (and so on)

Each page would have a page-view defined. Someone called shenanigans on it and now we have the PatternViewLoader to replace ALL of it!

<page-views>
   <!-- This would load all views with the pattern of "/views/**/*.cfm" which is the most basic and common pattern -->
<view-loader type="MachII.framework.viewLoaders.PatternViewLoader" />
</page-views>

So, so simple. Love this line of the config file more than any other.

Better apps, faster.

Take Mach-II off the shelf and use it as your "glue." Add Coldspring to manage your model. Use ColdFusion 9's new Hibernate ORM capabilities to cut the lines of code in your model by a huge factor. Redirect some of the saved time into building a better UI using jQuery, improving your cross-browser capabilities with clean CSS and making your client happier by communicating more frequently. Result: a better app, designed to be maintainable and much more in line with your client's spoken and unspoken expectations. How could any craftsman not feel good about that? Mach-II is a key component to that successful formula for us.

Try Mach-II. Need help? Talk to the team on the list. Build great things.

Mobile Apps for Alumni Relations - Cornell Compass

We recently had the privilege of working with Andrew Gossen in Cornell's office of Alumni Affairs on a sweet little mobile project.

The Cornell Compass web application uses geolocation features exposed through mobile browsers to determine the distance and bearing from where you're standing to the center of Cornell's campus. It's fun! It would be way more fun if the orientation of the device was exposed as well (then we could make the compass dynamically spin in real time).

Once your location is determined you have the opportunity to "Check In" and drop a marker on a map with your name and class year (both optional). The map is visible both on the mobile device and via the website (we do some browser sniffing so the content is device-appropriate). All visitors are encouraged to share the link to the site via Facebook and Twitter.

The Compass app is optimized for iPhone, but is functional on both Blackberry and Android devices as well. The backend (which is trivially simple) is ColdFusion with Microsoft SQL Server. The bulk of the front end work was done using jQuery and a few assistive javascript libraries for doing the bearing calculations.

We're working with Cornell to design the next version of this application with more features that make it useful to Cornellians all over the world looking to deepen their relationships with each other. Interested in learning more? Please drop me an email! We're interested in working with other organizations to enhance the usefulness of the app including integration with alumni online communities and CRM systems.

ColdFusion 9 Security Lockdown Guide

Adobe published the work of Pete Freitag today - a 35 page guide to secure installation and configuration of ColdFusion. Even if you feel like your ColdFusion server(s) are tightened up, it's always a good idea to take a moment to do a review.

While the guide does not go into detail on building secure applications, Pete's PDF is a step-by-step tutorial that even someone not familiar with ColdFusion administration could follow. Grab the PDF and spend the 15 minutes to check up on all of your servers (including your local development environment) - it's well worth it.

When you're done with that, check out the Security section of the ColdFusion Developer Center on the Adobe Developer Connection for lots of articles on how to write safe and solid code too!

More Entries

About the blog